Browse Source

Add share link property to various models and update serializers

- Introduced a `share_link` property in the `Article`, `Hadis`, `Book`, `Podcast`, `Video`, and `Transmitter` models to generate shareable links based on their slugs.
- Updated corresponding serializers to include the `share_link` field as read-only.
- Added a management command to refresh share links for existing Hadis models, ensuring all instances have updated slugs and share links.
- Adjusted the `settings` to define `DOVODI_DOMAIN` for consistent link generation across models.
master
Mohsen Taba 3 months ago
parent
commit
5ad95557b7
  1. 7
      apps/article/models.py
  2. 6
      apps/article/serializers.py
  3. 44
      apps/hadis/management/commands/refresh_share_links.py
  4. 28
      apps/hadis/models/hadis.py
  5. 7
      apps/hadis/models/reference.py
  6. 12
      apps/hadis/models/transmitter.py
  7. 6
      apps/hadis/serializers/hadis.py
  8. 7
      apps/hadis/serializers/reference.py
  9. 7
      apps/library/models.py
  10. 3
      apps/library/serializers.py
  11. 7
      apps/podcast/models.py
  12. 6
      apps/podcast/serializers.py
  13. 7
      apps/video/models.py
  14. 6
      apps/video/serializers.py
  15. 3
      config/settings/base.py

7
apps/article/models.py

@ -1,5 +1,6 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from utils import generate_slug_for_model
@ -111,6 +112,12 @@ class Article(models.Model):
def __str__(self):
return self.title
@property
def share_link(self):
if self.slug:
return f"{settings.DOVODI_DOMAIN}/articles/{self.slug}"
return None
def increment_view_count(self):
self.view_count += 1
self.save(update_fields=['view_count'])

6
apps/article/serializers.py

@ -44,10 +44,11 @@ class MiddleArticleCollectionSerializer(serializers.ModelSerializer):
class ArticleListSerializer(serializers.ModelSerializer):
thumbnail = serializers.SerializerMethodField()
categories = ArticleCategoryListSerializer(many=True, read_only=True)
share_link = serializers.CharField(read_only=True)
class Meta:
model = Article
fields = ['id', 'title', 'slug', 'thumbnail', 'description', 'view_count', 'created_at', 'categories']
fields = ['id', 'title', 'slug', 'thumbnail', 'description', 'view_count', 'created_at', 'categories', 'share_link']
def get_thumbnail(self, obj):
return get_thumbs(obj.thumbnail, self.context.get('request'))
@ -78,12 +79,13 @@ class ArticleDetailSerializer(serializers.ModelSerializer):
user_rate = serializers.SerializerMethodField()
average_rate = serializers.SerializerMethodField()
article_content = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = Article
fields = ['id', 'title', 'slug', 'thumbnail', 'description',
'article_file', 'view_count', 'download_count',
'categories', 'created_at', 'user_rate', 'average_rate', 'bookmark', 'article_content']
'categories', 'created_at', 'user_rate', 'average_rate', 'bookmark', 'article_content', 'share_link']
def get_thumbnail(self, obj):
return get_thumbs(obj.thumbnail, self.context.get('request'))

44
apps/hadis/management/commands/refresh_share_links.py

@ -0,0 +1,44 @@
from django.core.management.base import BaseCommand
from django.db import transaction
from apps.hadis.models import Hadis, HadisCorrection, TransmitterOriginalText
class Command(BaseCommand):
help = 'Refreshes slugs and share_links by re-saving all existing instances of Hadis models.'
def handle(self, *args, **options):
models_to_refresh = [
(Hadis, "Hadis"),
(HadisCorrection, "Hadis Correction"),
(TransmitterOriginalText, "Transmitter Original Text"),
]
for model_class, name in models_to_refresh:
self.stdout.write(self.style.WARNING(f'--- Processing {name} ---'))
instances = model_class.objects.all()
count = instances.count()
if count == 0:
self.stdout.write(f"No {name} instances found.")
continue
processed = 0
# Using transaction.atomic to ensure database integrity
with transaction.atomic():
for instance in instances:
try:
# This triggers your updated .save() logic
instance.save()
processed += 1
if processed % 100 == 0:
self.stdout.write(f"Updated {processed}/{count} {name}...")
except Exception as e:
self.stdout.write(self.style.ERROR(
f"Error saving {name} ID {instance.id}: {str(e)}"
))
self.stdout.write(self.style.SUCCESS(f'Successfully refreshed {processed} {name} instances.'))
self.stdout.write(self.style.SUCCESS('--- All models refreshed successfully ---'))

28
apps/hadis/models/hadis.py

@ -173,13 +173,13 @@ class HadisStatus(models.Model):
GRAY = 'gray', _('Gray')
COLOR_PALETTE = {
'red': {'main': '#E74C3C', 'light': '#FADBD8'},
'green': {'main': '#27AE60', 'light': '#D5F5E3'},
'blue': {'main': '#2980B9', 'light': '#D4E6F1'},
'yellow': {'main': '#F1C40F', 'light': '#FCF3CF'},
'orange': {'main': '#E67E22', 'light': '#FAE5D3'},
'purple': {'main': '#8E44AD', 'light': '#EBDEF0'},
'gray': {'main': '#7F8C8D', 'light': '#E5E8E8'},
'red': {'main': '#D33A3A', 'light': '#FBEBEB'},
'green': {'main': '#1DAC43', 'light': '#E8F7EC'},
'blue': {'main': '#5172E1', 'light': '#FAFBFC'},
'yellow': {'main': '#EDC130', 'light': '#FCF8EA'},
'orange': {'main': '#E67E22', 'light': '#FDF1E6'},
'purple': {'main': '#7C5CC4', 'light': '#F2EDFA'},
'gray': {'main': '#374151', 'light': '#EEEFF2'},
}
title = models.JSONField(default = list , verbose_name=_('Title'))
@ -354,9 +354,10 @@ class Hadis(models.Model):
counter += 1
self.slug = base_slug
# Generate share_link before saving
if not self.share_link and self.slug:
self.share_link = f"{settings.SITE_DOMAIN}/hadis/{self.slug}"
# Generate/update share_link before saving
if self.slug:
category_slug = self.category.slug if self.category and self.category.slug else 'uncategorized'
self.share_link = f"{settings.DOVODI_DOMAIN}/arguments/hadith/{category_slug}/{self.slug}"
super().save(*args, **kwargs)
@ -555,9 +556,10 @@ class HadisCorrection(models.Model):
counter += 1
self.slug = base_slug
# Generate share_link before saving
if not self.share_link and self.slug and self.hadis and self.hadis.slug:
self.share_link = f"{settings.SITE_DOMAIN}/hadis/{self.hadis.slug}/corrections/{self.slug}"
# Generate/update share_link before saving
if self.slug and self.hadis and self.hadis.slug:
category_slug = self.hadis.category.slug if self.hadis.category and self.hadis.category.slug else 'uncategorized'
self.share_link = f"{settings.DOVODI_DOMAIN}/arguments/hadith/{category_slug}/{self.hadis.slug}/corrections/{self.slug}"
super().save(*args, **kwargs)

7
apps/hadis/models/reference.py

@ -1,6 +1,7 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.utils.text import slugify
from django.conf import settings
from typing import Optional
class BookSubjectArea(models.Model):
@ -121,6 +122,12 @@ class BookReference(models.Model):
print(item)
return item.get("text", "") if isinstance(item, dict) else None
@property
def share_link(self):
if self.slug:
return f"{settings.DOVODI_DOMAIN}/arguments/sources/{self.slug}"
return None
def get_title(self,lang):
return self._get_json_field("title" , lang)

12
apps/hadis/models/transmitter.py

@ -296,6 +296,12 @@ class Transmitters(models.Model):
verbose_name_plural = _('Transmitters')
ordering = ('full_name',)
@property
def share_link(self):
if self.slug:
return f"{settings.DOVODI_DOMAIN}/arguments/narrators/{self.slug}"
return None
def save(self, *args, **kwargs):
if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''):
# Try to get text from full_name field with robust error handling
@ -696,9 +702,9 @@ class TransmitterOriginalText(models.Model):
counter += 1
self.slug = base_slug
# Generate share_link before saving
if not self.share_link and self.slug and self.transmitter and self.transmitter.slug:
self.share_link = f"{settings.SITE_DOMAIN}/hadis/narrators/{self.transmitter.slug}/original-texts/{self.slug}"
# Generate/update share_link before saving
if self.slug and self.transmitter and self.transmitter.slug:
self.share_link = f"{settings.DOVODI_DOMAIN}/arguments/narrators/{self.transmitter.slug}/original-texts/{self.slug}"
super().save(*args, **kwargs)

6
apps/hadis/serializers/hadis.py

@ -269,12 +269,13 @@ class TransmitterSerializer(serializers.ModelSerializer):
known_as = LocalizedField()
nickname = LocalizedField()
reliability = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = Transmitters
fields = [
'id', 'full_name', 'slug','birth_year_hijri', 'death_year_hijri',
"known_as",'nickname','reliability','madhhab','generation'
"known_as",'nickname','reliability','madhhab','generation','share_link'
]
def get_reliability(self, obj):
@ -344,6 +345,7 @@ class TransmitterDetailSerializer(serializers.ModelSerializer):
died_in = LocalizedField()
description = LocalizedField()
reliability = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = Transmitters
@ -352,7 +354,7 @@ class TransmitterDetailSerializer(serializers.ModelSerializer):
'origin','lived_in','died_in','birth_year_hijri',
'death_year_hijri','age_at_death','reliability',
'madhhab',"in_sahih_muslim","in_sahih_bukhari",
"description",'generation'
"description",'generation','share_link'
]
def get_reliability(self, obj):

7
apps/hadis/serializers/reference.py

@ -27,9 +27,10 @@ class BookReferenceSerializer(serializers.ModelSerializer):
title = LocalizedField()
description = LocalizedField()
author = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = BookReference
fields = ['id','title','slug','rate','author','description','image','volume']
fields = ['id','title','slug','rate','author','description','image','volume','share_link']
def get_author(self, obj):
request = self.context.get("request")
# Prefer request.LANGUAGE_CODE if you use LocaleMiddleware
@ -107,9 +108,11 @@ class BookDetailSerializer(serializers.ModelSerializer):
publisher = LocalizedField()
description = LocalizedField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = BookReference
fields = ['id','title','rate','isbn','language','number_page','publisher','description','volume','slug','attribute','author','image','hadis']
fields = ['id','title','rate','isbn','share_link','language','number_page','publisher','description','volume','slug','attribute','author','image','hadis']
def get_hadis(self,obj):
references = obj.hadis_references.all()

7
apps/library/models.py

@ -1,6 +1,7 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from filer.fields.image import FilerImageField
from dj_language.field import LanguageField
@ -139,6 +140,12 @@ class Book(models.Model):
def __str__(self):
return f'<{self.id}>-{self.title}'
@property
def share_link(self):
if self.slug:
return f"{settings.DOVODI_DOMAIN}/library/{self.slug}"
return None
def save(self, *args, **kwargs):
if not self.slug:
self.slug = generate_slug_for_model(Book, self.title)

3
apps/library/serializers.py

@ -52,6 +52,7 @@ class BookSerializer(serializers.ModelSerializer):
bookmark = serializers.SerializerMethodField()
user_rate = serializers.SerializerMethodField()
average_rate = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
def get_thumbnail(self, obj):
if obj.thumbnail:
@ -65,7 +66,7 @@ class BookSerializer(serializers.ModelSerializer):
'status', 'pin', 'view_count', 'download_count', 'publisher', 'year_of_publication', 'author', 'isbn', 'numnber_of_volume',
'language', 'main_themes', 'notable_works',
'file_type', 'book_file', 'created_at', 'bookmark', 'user_rate',
'average_rate'
'average_rate', 'share_link'
)
def get_bookmark(self, obj):

7
apps/podcast/models.py

@ -1,5 +1,6 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from utils import generate_slug_for_model
@ -100,6 +101,12 @@ class Podcast(models.Model):
def __str__(self):
return self.title
@property
def share_link(self):
if self.slug:
return f"{settings.DOVODI_DOMAIN}/podcast/{self.slug}"
return None
def increment_view_count(self):
self.view_count += 1
self.save(update_fields=['view_count'])

6
apps/podcast/serializers.py

@ -19,11 +19,12 @@ class PodcastListSerializer(serializers.ModelSerializer):
thumbnail = serializers.SerializerMethodField()
audio_file = serializers.SerializerMethodField()
in_user_playlist = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = Podcast
fields = ['id', 'title', 'slug', 'thumbnail', 'description', 'audio_file',
'audio_time', 'view_count', 'created_at', 'in_user_playlist']
'audio_time', 'view_count', 'created_at', 'in_user_playlist', 'share_link']
def get_thumbnail(self, obj):
return get_thumbs(obj.thumbnail, self.context.get('request'))
@ -60,13 +61,14 @@ class PodcastDetailSerializer(serializers.ModelSerializer):
is_in_playlist = serializers.SerializerMethodField()
playlist_podcasts = serializers.SerializerMethodField()
in_user_playlist = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = Podcast
fields = ['id', 'title', 'slug', 'thumbnail', 'description',
'audio_file', 'audio_time', 'view_count', 'download_count',
'categories', 'created_at', 'user_rate', 'average_rate', 'bookmark',
'is_in_playlist', 'playlist_podcasts', 'in_user_playlist']
'is_in_playlist', 'playlist_podcasts', 'in_user_playlist', 'share_link']
def get_thumbnail(self, obj):
return get_thumbs(obj.thumbnail, self.context.get('request'))

7
apps/video/models.py

@ -1,5 +1,6 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from filer.fields.image import FilerImageField
from utils import generate_slug_for_model
@ -103,6 +104,12 @@ class Video(models.Model):
def __str__(self):
return self.title
@property
def share_link(self):
if self.slug:
return f"{settings.DOVODI_DOMAIN}/videos/{self.slug}"
return None
def increment_view_count(self):
"""Increment the view count for this video"""
self.view_count += 1

6
apps/video/serializers.py

@ -18,11 +18,12 @@ class VideoCategoryListSerializer(serializers.ModelSerializer):
class VideoListSerializer(serializers.ModelSerializer):
thumbnail = serializers.SerializerMethodField()
video_file = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = Video
fields = ['id', 'title', 'slug', 'thumbnail', 'description', 'video_type',
'video_file', 'video_url', 'video_time', 'view_count', 'created_at']
'video_file', 'video_url', 'video_time', 'view_count', 'created_at', 'share_link']
def get_thumbnail(self, obj):
return get_thumbs(obj.thumbnail, self.context.get('request'))
@ -154,13 +155,14 @@ class VideoDetailSerializer(serializers.ModelSerializer):
average_rate = serializers.SerializerMethodField()
is_in_playlist = serializers.SerializerMethodField()
playlist_videos = serializers.SerializerMethodField()
share_link = serializers.CharField(read_only=True)
class Meta:
model = Video
fields = ['id', 'title', 'slug', 'thumbnail', 'description', 'video_type',
'video_file', 'video_url', 'video_time', 'view_count',
'categories', 'created_at', 'user_rate', 'average_rate', 'bookmark',
'is_in_playlist', 'playlist_videos']
'is_in_playlist', 'playlist_videos', 'share_link']
def get_thumbnail(self, obj):
return get_thumbs(obj.thumbnail, self.context.get('request'))

3
config/settings/base.py

@ -278,7 +278,8 @@ FILER_ENABLE_LOGGING = True
FILER_DEBUG = True
ADMIN_TITLE = 'Imam Javad App'
ADMIN_INDEX_TITLE = 'Imam Javad Administration'
SITE_DOMAIN = "https://imamjavad.nwhco.ir"
SITE_DOMAIN = "https://imamjavad.newhorizonco.uk"
DOVODI_DOMAIN = "https://dovodi.newhorizonco.uk"
ONLINE_CLASS_FRONTEND_DOMAIN = env('ONLINE_CLASS_FRONTEND_DOMAIN', default=SITE_DOMAIN)
ONLINE_CLASS_TOKEN_TTL = env.int('ONLINE_CLASS_TOKEN_TTL', default=3000)
PLUGNMEET_SERVER_URL ='https://meet.newhorizonco.uk'

Loading…
Cancel
Save