Mohsen Taba 1 week ago
parent
commit
ffed87aaa4
  1. 8
      apps/account/views/user.py
  2. 5
      apps/article/serializers_admin.py
  3. 5
      apps/article/views.py
  4. 17
      apps/hadis/serializers/hadis.py
  5. 19
      apps/hadis/serializers/reference_v2.py
  6. 11
      apps/hadis/serializers/serializers_admin.py
  7. 8
      apps/hadis/urls.py
  8. 3
      apps/hadis/views/category.py
  9. 5
      apps/hadis/views/hadis.py
  10. 5
      apps/library/serializers_admin.py
  11. 5
      apps/library/views.py
  12. 5
      apps/podcast/serializers_admin.py
  13. 5
      apps/podcast/views.py
  14. 5
      apps/video/serializers_admin.py
  15. 5
      apps/video/views.py
  16. 2
      config/__init__.py
  17. 18
      utils/__init__.py

8
apps/account/views/user.py

@ -27,7 +27,7 @@ from apps.account.serializers import UserRegisterSerializer, UserProfileSerializ
from apps.account.serializers.user_web import WebUserRegisterSerializer
from utils.redis import RedisManager
from utils.exceptions import AppAPIException
from utils import send_email, is_valid_email
from utils import send_email, is_valid_email, absolute_https_url
from config.settings import base as settings
from apps.account.permissions import IsActiveUser, IsSuperAdminOrReadOnlyForProfessor
from apps.account.doc import *
@ -431,7 +431,7 @@ class UserLoginView(CreateAPIView):
"email": user.email,
"token": token.key,
"user_type": user.user_type,
"avatar": request.build_absolute_uri(user.avatar.url) if user.avatar else None,
"avatar": absolute_https_url(user.avatar.url, request) if user.avatar else None,
}, status=status.HTTP_201_CREATED)
@ -492,7 +492,7 @@ class UserRecoverPassword(CreateAPIView):
"fullname": user.fullname,
"phone_number": str(user.phone_number) if user.phone_number else None,
"email": user.email if user.email else None,
"avatar": request.build_absolute_uri(user.avatar.url) if user.avatar else None,
"avatar": absolute_https_url(user.avatar.url, request) if user.avatar else None,
"message": "Forgot password code sent"
},
status=status.HTTP_202_ACCEPTED,
@ -633,7 +633,7 @@ class AdminLoginView(CreateAPIView):
"email": user.email,
"token": token.key,
"user_type": effective_user_type,
"avatar": request.build_absolute_uri(user.avatar.url) if user.avatar else None,
"avatar": absolute_https_url(user.avatar.url, request) if user.avatar else None,
}, status=status.HTTP_201_CREATED)

5
apps/article/serializers_admin.py

@ -1,6 +1,7 @@
from rest_framework import serializers
from django.core.files.uploadedfile import SimpleUploadedFile
from utils.image_compression import maybe_compress_uploaded_file
from utils import absolute_https_url
from .models import Article, ArticleCategory, ArticleCollection, ArticleContent, ContentPart, TextSection
@ -23,9 +24,7 @@ class AbsoluteImageField(serializers.ImageField):
return None
request = self.context.get("request")
url = value.url if hasattr(value, "url") else str(value)
if request:
return request.build_absolute_uri(url)
return url
return absolute_https_url(url, request)
class AbsoluteFileField(serializers.FileField):

5
apps/article/views.py

@ -64,8 +64,9 @@ class PinnedArticleCollectionListView(generics.ListAPIView):
def get_queryset(self):
return PinnedArticleCollection.objects.filter(
status=True,
display_position=ArticleCollection.DisplayPosition.PINNED
).order_by('order', '-created_at')
display_position=ArticleCollection.DisplayPosition.PINNED,
articles__status=True
).distinct().order_by('order', '-created_at')
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)

17
apps/hadis/serializers/hadis.py

@ -8,6 +8,7 @@ from .category import LocalizedField, ArabicLocalizedField
from .category import get_localized_text, get_arabic_localized_text
from .category import get_localized_text
from apps.bookmark.serializers.bookmark import BookmarkStatusSerializer
from utils import absolute_https_url
from ..models import (
Hadis, HadisStatus, HadisTag, HadisTransmitter,
@ -58,8 +59,8 @@ class PinnedHadisCollectionSerializer(serializers.ModelSerializer):
if obj.thumbnail:
request = self.context.get('request')
if request:
return request.build_absolute_uri(obj.thumbnail.url)
return obj.thumbnail.url
return absolute_https_url(obj.thumbnail.url, request)
return absolute_https_url(obj.thumbnail.url)
return None
class HadisCollectionListSerializer(serializers.ModelSerializer):
@ -75,8 +76,8 @@ class HadisCollectionListSerializer(serializers.ModelSerializer):
if obj.thumbnail:
request = self.context.get('request')
if request:
return request.build_absolute_uri(obj.thumbnail.url)
return obj.thumbnail.url
return absolute_https_url(obj.thumbnail.url, request)
return absolute_https_url(obj.thumbnail.url)
return None
@ -142,7 +143,7 @@ class HadisSyncSerializer(serializers.ModelSerializer):
for img in reference.images.all():
thumb_url = None
if img.thumbnail:
thumb_url = request.build_absolute_uri(img.thumbnail.url) if request else img.thumbnail.url
thumb_url = absolute_https_url(img.thumbnail.url, request)
reference_images_block.append({
'id': img.id,
'thumbnail': thumb_url,
@ -770,8 +771,8 @@ class ReferenceImageSerializer(serializers.ModelSerializer):
if obj.thumbnail:
request = self.context.get('request')
if request:
return request.build_absolute_uri(obj.thumbnail.url)
return obj.thumbnail.url
return absolute_https_url(obj.thumbnail.url, request)
return absolute_https_url(obj.thumbnail.url)
return None
@ -1220,4 +1221,4 @@ class TransmitterOriginalTextDetailSerializer(serializers.ModelSerializer):
"id": obj.transmitter.id,
"slug": obj.transmitter.slug,
"name": get_localized_text(obj.transmitter.full_name, self.context.get('request'))
}
}

19
apps/hadis/serializers/reference_v2.py

@ -5,6 +5,7 @@ from .category import get_localized_text
from apps.hadis.serializers import HadisListSerializer, HadisShortSerializer
from ..serializers.category import LocalizedField
from ..serializers.reference import BookAttributeSerializer, BookReferenceImageSerializer
from utils import absolute_https_url
class BookTagV2Serializer(serializers.ModelSerializer):
title = LocalizedField()
@ -58,8 +59,8 @@ class BookReferenceV2ListSerializer(serializers.ModelSerializer):
if first_image and first_image.image:
request = self.context.get('request')
if request:
return request.build_absolute_uri(first_image.image.url)
return first_image.image.url
return absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url)
return None
class BookEditionV2Serializer(serializers.ModelSerializer):
@ -99,8 +100,8 @@ class BookVolumeV2Serializer(serializers.ModelSerializer):
if first_image and first_image.image:
request = self.context.get('request')
if request:
return request.build_absolute_uri(first_image.image.url)
return first_image.image.url
return absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url)
return None
class BookReferenceV2DetailSerializer(serializers.ModelSerializer):
@ -128,8 +129,8 @@ class BookReferenceV2DetailSerializer(serializers.ModelSerializer):
if first_image and first_image.image:
request = self.context.get('request')
if request:
return request.build_absolute_uri(first_image.image.url)
return first_image.image.url
return absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url)
return None
def get_information(self, obj):
@ -305,8 +306,8 @@ class AuthorBookReferenceSerializer(serializers.ModelSerializer):
if first_image and first_image.image:
request = self.context.get('request')
if request:
return request.build_absolute_uri(first_image.image.url)
return first_image.image.url
return absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url)
return None
# یک سریالایزر مینیمال برای کتاب‌ها داخل سینک
@ -350,4 +351,4 @@ class BookAuthorSyncSerializer(serializers.ModelSerializer):
'death_year_miladi',
'books', # 👈 لیست کتاب‌های هر نویسنده
'related_narrator_slug'
]
]

11
apps/hadis/serializers/serializers_admin.py

@ -2,6 +2,7 @@ from rest_framework import serializers
from django.core.files.uploadedfile import SimpleUploadedFile
from utils.image_compression import maybe_compress_uploaded_file
from utils import absolute_https_url
from ..models import (
Hadis, HadisCategory, HadisStatus, HadisTag, HadisCorrection, HadisInterpretation, HadisCollection, HadisSect, HadisInCollection, HadisTransmitter, HadisReference,
BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookEdition, BookVolume, BookResearcher, BookEditor,
@ -33,9 +34,7 @@ class AbsoluteImageField(serializers.ImageField):
return None
request = self.context.get("request")
url = value.url if hasattr(value, "url") else str(value)
if request:
return request.build_absolute_uri(url)
return url
return absolute_https_url(url, request)
class AdminHadisCategorySerializer(serializers.ModelSerializer):
@ -415,7 +414,7 @@ class AdminHadisCorrectionSerializer(serializers.ModelSerializer):
ret["images"] = [
{
"id": img.id,
"image": request.build_absolute_uri(img.image.url) if request and img.image else img.image.url
"image": absolute_https_url(img.image.url, request) if request and img.image else absolute_https_url(img.image.url)
}
for img in images
]
@ -534,7 +533,7 @@ class AdminHadisInterpretationSerializer(serializers.ModelSerializer):
ret["images"] = [
{
"id": img.id,
"image": request.build_absolute_uri(img.image.url) if request and img.image else img.image.url
"image": absolute_https_url(img.image.url, request) if request and img.image else absolute_https_url(img.image.url)
}
for img in images
]
@ -1198,7 +1197,7 @@ class AdminTransmitterOriginalTextSerializer(serializers.ModelSerializer):
ret["images"] = [
{
"id": img.id,
"image": request.build_absolute_uri(img.image.url) if request and img.image else img.image.url
"image": absolute_https_url(img.image.url, request) if request and img.image else absolute_https_url(img.image.url)
}
for img in (ref.images.all() if ref else [])
]

8
apps/hadis/urls.py

@ -104,10 +104,10 @@ urlpatterns = [
# Narrator paths
path('narrators/<str:narrator_slug>/teachers/', NarratorTeachersView.as_view(), name='narrator-teachers'),
path('narrators/<str:narrator_slug>/students/', NarratorStudentsView.as_view(), name='narrator-students'),
path('narrators/<str:narrator_slug>/arguments', NarratorArgumentsListView.as_view(), name='narrator-arguments'),
path('narrators/<str:narrator_slug>/opinions', TransmitterOpinionView.as_view(), name='narrator-opinions'),
path('narrators/<str:narrator_slug>/original_texts', TransmitterOriginalTextView.as_view(), name='narrator-original-texts'),
path('narrators/<str:narrator_slug>', TransmitterDetailView.as_view(), name='narrator-detail'),
path('narrators/<str:narrator_slug>/arguments/', NarratorArgumentsListView.as_view(), name='narrator-arguments'),
path('narrators/<str:narrator_slug>/opinions/', TransmitterOpinionView.as_view(), name='narrator-opinions'),
path('narrators/<str:narrator_slug>/original_texts/', TransmitterOriginalTextView.as_view(), name='narrator-original-texts'),
path('narrators/<str:narrator_slug>/', TransmitterDetailView.as_view(), name='narrator-detail'),
path('narrators/filters/', TransmitterFiltersView.as_view(), name='narrator-filters'),
path('narrators/', TransmitterView.as_view(), name='narrators'),

3
apps/hadis/views/category.py

@ -5,6 +5,7 @@ from utils.pagination import NoPagination
from django.db.models import Q
from collections import defaultdict
from utils.pagination import StandardResultsSetPagination
from utils import absolute_https_url
from ..models import HadisSect, HadisCategory,Hadis
from apps.bookmark.serializers.bookmark import BookmarkStatusSerializer
from ..serializers import (
@ -218,7 +219,7 @@ class HadisCategoryTreeView(ListAPIView):
def _get_thumbnail_url(self, category, request):
"""Get absolute thumbnail URL"""
if hasattr(category, 'thumbnail') and category.thumbnail:
return request.build_absolute_uri(category.thumbnail.url) if request else category.thumbnail.url
return absolute_https_url(category.thumbnail.url, request)
return None
def _get_xmind_url(self, category, request):

5
apps/hadis/views/hadis.py

@ -33,8 +33,9 @@ class PinnedHadisCollectionListView(ListAPIView):
def get_queryset(self):
return HadisCollection.objects.filter(
status=True,
display_position=HadisCollection.DisplayPosition.PINNED
).order_by('order', '-created_at')
display_position=HadisCollection.DisplayPosition.PINNED,
hadis_items__hadis__status=True
).distinct().order_by('order', '-created_at')
def list(self, request, *args, **kwargs):
# 1. گرفتن خروجی استاندارد لیست مجموعه‌ها

5
apps/library/serializers_admin.py

@ -1,6 +1,7 @@
from rest_framework import serializers
from django.core.files.uploadedfile import SimpleUploadedFile
from utils.image_compression import maybe_compress_uploaded_file
from utils import absolute_https_url
from .models import Author, Book, BookCollection, Category
@ -23,9 +24,7 @@ class AbsoluteImageField(serializers.ImageField):
return None
request = self.context.get("request")
url = value.url if hasattr(value, "url") else str(value)
if request:
return request.build_absolute_uri(url)
return url
return absolute_https_url(url, request)
class AbsoluteFileField(serializers.FileField):

5
apps/library/views.py

@ -67,8 +67,9 @@ class PinnedBookCollectionListView(ListAPIView):
def get_queryset(self):
return BookCollection.objects.filter(
status=True,
display_position=BookCollection.DisplayPosition.PINNED
).order_by('order', '-created_at')
display_position=BookCollection.DisplayPosition.PINNED,
books__status=True
).distinct().order_by('order', '-created_at')
def list(self, request, *args, **kwargs):

5
apps/podcast/serializers_admin.py

@ -1,6 +1,7 @@
from rest_framework import serializers
from django.core.files.uploadedfile import SimpleUploadedFile
from utils.image_compression import maybe_compress_uploaded_file
from utils import absolute_https_url
from .models import PlaylistItem, Podcast, PodcastCategory, PodcastCollection, PodcastPlaylist
@ -23,9 +24,7 @@ class AbsoluteImageField(serializers.ImageField):
return None
request = self.context.get("request")
url = value.url if hasattr(value, "url") else str(value)
if request:
return request.build_absolute_uri(url)
return url
return absolute_https_url(url, request)
class AbsoluteFileField(serializers.FileField):

5
apps/podcast/views.py

@ -71,8 +71,9 @@ class PinnedPodcastCollectionListView(generics.ListAPIView):
def get_queryset(self):
return PinnedPodcastCollection.objects.filter(
status=True,
display_position=PodcastCollection.DisplayPosition.PINNED
).order_by('order', '-created_at')
display_position=PodcastCollection.DisplayPosition.PINNED,
podcasts__status=True
).distinct().order_by('order', '-created_at')
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)

5
apps/video/serializers_admin.py

@ -1,6 +1,7 @@
from rest_framework import serializers
from django.core.files.uploadedfile import SimpleUploadedFile
from utils.image_compression import maybe_compress_uploaded_file
from utils import absolute_https_url
from .models import PlaylistItem, Video, VideoCategory, VideoCollection, VideoPlaylist
@ -23,9 +24,7 @@ class AbsoluteImageField(serializers.ImageField):
return None
request = self.context.get("request")
url = value.url if hasattr(value, "url") else str(value)
if request:
return request.build_absolute_uri(url)
return url
return absolute_https_url(url, request)
class AbsoluteFileField(serializers.FileField):

5
apps/video/views.py

@ -84,8 +84,9 @@ class PinnedVideoCollectionListView(generics.ListAPIView):
def get_queryset(self):
queryset = PinnedVideoCollection.objects.filter(
status=True,
display_position=VideoCollection.DisplayPosition.PINNED
).order_by('order', '-created_at')
display_position=VideoCollection.DisplayPosition.PINNED,
related_playlists__status=True
).distinct().order_by('order', '-created_at')
# Filter by bookmarks if requested
is_bookmark = self.request.query_params.get('is_bookmark', '').lower()

2
config/__init__.py

@ -5,4 +5,4 @@ from __future__ import absolute_import, unicode_literals
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ('celery_app',)
__all__ = ('celery_app',)

18
utils/__init__.py

@ -36,6 +36,17 @@ from utils.image_compression import maybe_compress_uploaded_file
logger = logging.getLogger(__name__)
def absolute_https_url(url, request=None):
"""Build an absolute URL and always expose it over HTTPS."""
if request:
url = request.build_absolute_uri(url)
if isinstance(url, str) and url.startswith('http://'):
return f'https://{url[7:]}'
return url
# Moved filer imports to avoid circular imports
# These will be imported when needed in functions
@ -63,12 +74,7 @@ def get_thumbs(obj, request: HttpRequest = None) -> dict:
# برای هر سه سایز، همان URL اصلی را برگردان
for size in sizes:
if request:
url = request.build_absolute_uri(original_url)
else:
url = original_url
thumbnail_object[size] = url
thumbnail_object[size] = absolute_https_url(original_url, request)
return thumbnail_object

Loading…
Cancel
Save