From d595e80763e4dd8a3e250f1e7052b10374979151 Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Wed, 3 Jun 2026 11:52:14 +0330 Subject: [PATCH] working hours added and dynamic prefrences api updated --- config/urls.py | 65 +++++++++++++++++-- .../dynamic_preferences_registry.py | 3 +- dynamic_preferences/serializers.py | 46 +++++++------ dynamic_preferences/views.py | 61 ++++++++++++++--- 4 files changed, 141 insertions(+), 34 deletions(-) diff --git a/config/urls.py b/config/urls.py index f22b709..9fbdd54 100644 --- a/config/urls.py +++ b/config/urls.py @@ -124,10 +124,65 @@ swagger_urlpatterns = [ ] if settings.DEBUG: - urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - - - - + import os + import re + import mimetypes + from django.http import StreamingHttpResponse, HttpResponse, Http404 + from django.views.static import serve as django_static_serve + + def ranged_static_serve(request, path, document_root=None, **kwargs): + fullpath = os.path.join(document_root, path) + if not os.path.exists(fullpath) or os.path.isdir(fullpath): + raise Http404("File not found") + + range_header = request.META.get('HTTP_RANGE', '').strip() + if not range_header: + return django_static_serve(request, path, document_root=document_root, **kwargs) + + size = os.path.getsize(fullpath) + content_type, encoding = mimetypes.guess_type(fullpath) + content_type = content_type or 'application/octet-stream' + + match = re.match(r'bytes=(\d+)-(\d*)', range_header) + if not match: + return HttpResponse("Invalid Range Header", status=400) + + first_byte, last_byte = match.groups() + first_byte = int(first_byte) if first_byte else 0 + last_byte = int(last_byte) if last_byte else size - 1 + + if first_byte >= size: + return HttpResponse("Requested Range Not Satisfiable", status=416) + + if last_byte >= size: + last_byte = size - 1 + + length = last_byte - first_byte + 1 + + def file_iterator(file_path, offset, bytes_to_read, chunk_size=8192): + with open(file_path, 'rb') as f: + f.seek(offset) + remaining = bytes_to_read + while remaining > 0: + to_read = min(chunk_size, remaining) + data = f.read(to_read) + if not data: + break + yield data + remaining -= len(data) + + response = StreamingHttpResponse( + file_iterator(fullpath, first_byte, length), + status=206, + content_type=content_type + ) + response['Content-Range'] = f'bytes {first_byte}-{last_byte}/{size}' + response['Content-Length'] = str(length) + response['Accept-Ranges'] = 'bytes' + return response + + urlpatterns += [ + re_path(r'^%s(?P.*)$' % re.escape(settings.MEDIA_URL.lstrip('/')), ranged_static_serve, {'document_root': settings.MEDIA_ROOT}), + ] # Force reload trigger diff --git a/dynamic_preferences/dynamic_preferences_registry.py b/dynamic_preferences/dynamic_preferences_registry.py index 11617fc..0d3dbf2 100644 --- a/dynamic_preferences/dynamic_preferences_registry.py +++ b/dynamic_preferences/dynamic_preferences_registry.py @@ -129,10 +129,11 @@ support_fields = { "format": "table", "title": "", "required_by_default": 1, - "required": ['telegram_number', "whatsapp_number"], + "required": ['telegram_number', "whatsapp_number", "office_hours"], "properties": { "telegram_number": {"type": "string", "title": "Telegram Number"}, "whatsapp_number": {"type": "string", "title": "Whatsapp Number"}, + "office_hours": {"type": "string", "title": "Office Hours"}, } } diff --git a/dynamic_preferences/serializers.py b/dynamic_preferences/serializers.py index 5132b56..1b1016c 100644 --- a/dynamic_preferences/serializers.py +++ b/dynamic_preferences/serializers.py @@ -28,28 +28,36 @@ from django.db.models.fields.files import FieldFile from rest_framework import serializers -class AboutUsSerializer(serializers.Serializer): - content = serializers.CharField(allow_blank=True) - -class AboutUsDobodiSerializer(serializers.Serializer): - arabic_text = serializers.CharField(allow_blank=True) - translated_text = serializers.CharField(allow_blank=True) - title = serializers.CharField(allow_blank=True) - content = serializers.CharField(allow_blank=True) - +class BaseSettingsSerializer(serializers.Serializer): + def to_representation(self, instance): + ret = super().to_representation(instance) + for key, value in ret.items(): + if value is None: + ret[key] = "" + return ret + +class AboutUsSerializer(BaseSettingsSerializer): + content = serializers.CharField(required=False, allow_blank=True, default="") + +class AboutUsDobodiSerializer(BaseSettingsSerializer): + arabic_text = serializers.CharField(required=False, allow_blank=True, default="") + translated_text = serializers.CharField(required=False, allow_blank=True, default="") + title = serializers.CharField(required=False, allow_blank=True, default="") + content = serializers.CharField(required=False, allow_blank=True, default="") -class FAQItemSerializer(serializers.Serializer): - question = serializers.CharField() - answer = serializers.CharField() +class FAQItemSerializer(BaseSettingsSerializer): + question = serializers.CharField(required=False, allow_blank=True, default="") + answer = serializers.CharField(required=False, allow_blank=True, default="") -class SupportSerializer(serializers.Serializer): - telegram_number = serializers.CharField() - whatsapp_number = serializers.CharField() +class SupportSerializer(BaseSettingsSerializer): + telegram_number = serializers.CharField(required=False, allow_blank=True, default="") + whatsapp_number = serializers.CharField(required=False, allow_blank=True, default="") + office_hours = serializers.CharField(required=False, allow_blank=True, default="") -class CardSerializer(serializers.Serializer): - card_number = serializers.CharField() - card_name = serializers.CharField() - whatsapp_number = serializers.CharField() +class CardSerializer(BaseSettingsSerializer): + card_number = serializers.CharField(required=False, allow_blank=True, default="") + card_name = serializers.CharField(required=False, allow_blank=True, default="") + whatsapp_number = serializers.CharField(required=False, allow_blank=True, default="") class UnsetValue(object): diff --git a/dynamic_preferences/views.py b/dynamic_preferences/views.py index 05bc81b..9ad04e7 100644 --- a/dynamic_preferences/views.py +++ b/dynamic_preferences/views.py @@ -12,14 +12,30 @@ from .serializers import ( AboutUsDobodiSerializer ) +from rest_framework.authentication import TokenAuthentication +from apps.account.permissions import IsSuperAdmin + class AboutUsAPIView(GenericAPIView): serializer_class = AboutUsSerializer + authentication_classes = [TokenAuthentication] + + def get_permissions(self): + if self.request.method in ['PUT', 'POST', 'PATCH']: + return [IsSuperAdmin()] + return [] def get(self, request, *args, **kwargs): preferences = global_preferences_registry.manager() about_us = preferences.get('aboutus__aboutus', '') - serializer = self.get_serializer(data={'content': about_us}) + serializer = self.get_serializer({'content': about_us}) + return Response(serializer.data) + + def put(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) + content = serializer.validated_data.get('content', '') + preferences = global_preferences_registry.manager() + preferences['aboutus__aboutus'] = content return Response(serializer.data) class FAQCourseAPIView(GenericAPIView): @@ -28,8 +44,7 @@ class FAQCourseAPIView(GenericAPIView): def get(self, request, *args, **kwargs): preferences = global_preferences_registry.manager() faq_course = preferences.get('FAQ_Course__FAQ_Course', []) - serializer = self.get_serializer(data=faq_course, many=True) - serializer.is_valid(raise_exception=True) + serializer = self.get_serializer(faq_course, many=True) return Response(serializer.data) class FAQGeneralAPIView(GenericAPIView): @@ -38,28 +53,55 @@ class FAQGeneralAPIView(GenericAPIView): def get(self, request, *args, **kwargs): preferences = global_preferences_registry.manager() faq_general = preferences.get('FAQ_General__FAQ_General', []) - serializer = self.get_serializer(data=faq_general, many=True) - serializer.is_valid(raise_exception=True) + serializer = self.get_serializer(faq_general, many=True) return Response(serializer.data) class SupportAPIView(GenericAPIView): serializer_class = SupportSerializer + authentication_classes = [TokenAuthentication] + + def get_permissions(self): + if self.request.method in ['PUT', 'POST', 'PATCH']: + return [IsSuperAdmin()] + return [] def get(self, request, *args, **kwargs): preferences = global_preferences_registry.manager() support = preferences.get('support__support', {}) - serializer = self.get_serializer(data=support) + if not isinstance(support, dict): + support = {} + serializer = self.get_serializer(support) + return Response(serializer.data) + + def put(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) + preferences = global_preferences_registry.manager() + preferences['support__support'] = serializer.validated_data return Response(serializer.data) class CardAPIView(GenericAPIView): serializer_class = CardSerializer + authentication_classes = [TokenAuthentication] + + def get_permissions(self): + if self.request.method in ['PUT', 'POST', 'PATCH']: + return [IsSuperAdmin()] + return [] def get(self, request, *args, **kwargs): preferences = global_preferences_registry.manager() card = preferences.get('card__card', {}) - serializer = self.get_serializer(data=card) + if not isinstance(card, dict): + card = {} + serializer = self.get_serializer(card) + return Response(serializer.data) + + def put(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) + preferences = global_preferences_registry.manager() + preferences['card__card'] = serializer.validated_data return Response(serializer.data) class AboutUsDobodiAPIView(GenericAPIView): @@ -68,8 +110,9 @@ class AboutUsDobodiAPIView(GenericAPIView): def get(self, request, *args, **kwargs): preferences = global_preferences_registry.manager() about_us_dobodi = preferences.get('about_us_dobodi__about_us_dobodi', {}) - serializer = self.get_serializer(data=about_us_dobodi) - serializer.is_valid(raise_exception=True) + if not isinstance(about_us_dobodi, dict): + about_us_dobodi = {} + serializer = self.get_serializer(about_us_dobodi) return Response(serializer.data)