diff --git a/apps/hadis/admin/__init__.py b/apps/hadis/admin/__init__.py index 3e6f70c..44d3e7b 100644 --- a/apps/hadis/admin/__init__.py +++ b/apps/hadis/admin/__init__.py @@ -1,4 +1,5 @@ from .category import * from .hadis import * from .transmitter import * -from .reference import * \ No newline at end of file +from .reference import * +from .version import * \ No newline at end of file diff --git a/apps/hadis/admin/version.py b/apps/hadis/admin/version.py new file mode 100644 index 0000000..f33a956 --- /dev/null +++ b/apps/hadis/admin/version.py @@ -0,0 +1,29 @@ +from django.contrib import admin +from django.utils.translation import gettext_lazy as _ +from unfold.admin import ModelAdmin + +from utils.admin import project_admin_site +from ..models import ContentRelease + + +class ContentReleaseAdmin(ModelAdmin): + """Admin for ContentRelease model""" + list_display = ('version_name', 'published_at', 'is_active') + list_filter = ('is_active', 'published_at') + search_fields = ('version_name', 'description') + readonly_fields = ('published_at',) + ordering = ('-published_at',) + + fieldsets = ( + (None, { + 'fields': ('version_name', 'description', 'is_active') + }), + (_('Timestamps'), { + 'fields': ('published_at',), + 'classes': ('collapse',) + }), + ) + + +# Register model with the custom admin site +project_admin_site.register(ContentRelease, ContentReleaseAdmin) diff --git a/apps/hadis/docs.py b/apps/hadis/docs.py index b934b63..fbeffde 100644 --- a/apps/hadis/docs.py +++ b/apps/hadis/docs.py @@ -2400,4 +2400,67 @@ hadis_main_list_swagger = swagger_auto_schema( description="Internal server error occurred while processing the request" ) } -) \ No newline at end of file +) + +# # Swagger documentation for ContentReleaseSyncView +# content_release_sync_swagger = swagger_auto_schema( +# operation_description="Get list of all active content releases for offline mode sync", +# operation_summary="List Content Releases", +# tags=[ +# 'Hadis' +# ], +# responses={ +# status.HTTP_200_OK: openapi.Response( +# description="List of active content releases with pagination info", +# examples={ +# "application/json": { +# "count": 2, +# "results": [ +# { +# "id": 1, +# "version_name": "v1.2 - Muharram Update", +# "published_at": "2024-01-15T10:30:00Z", +# "description": "New hadis content added for Muharram month", +# "is_active": True +# }, +# { +# "id": 2, +# "version_name": "v1.1 - Initial Release", +# "published_at": "2024-01-01T00:00:00Z", +# "description": "Initial release of the hadis database", +# "is_active": True +# } +# ] +# } +# } +# ), +# status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response( +# description="Internal server error" +# ) +# } +# ) + + +# Swagger documentation for ContentReleaseSyncView +content_release_sync_swagger = swagger_auto_schema( + operation_description='Get the latest active content release for offline mode sync', + operation_summary='Get Latest Content Release', + tags=['Hadis'], + responses={ + status.HTTP_200_OK: openapi.Response( + description='Latest active content release object', + examples={ + 'application/json': { + 'id': 1, + 'version_name': 'v1.2 - Muharram Update', + 'published_at': '2024-01-15T10:30:00Z', + 'description': 'New hadis content added for Muharram month', + 'is_active': True + } + } + ), + status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response( + description='Internal server error' + ) + } +) diff --git a/apps/hadis/migrations/0086_alter_opinionstatus_options_and_more.py b/apps/hadis/migrations/0086_alter_opinionstatus_options_and_more.py new file mode 100644 index 0000000..454b9d7 --- /dev/null +++ b/apps/hadis/migrations/0086_alter_opinionstatus_options_and_more.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.27 on 2025-12-27 09:42 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("hadis", "0085_hadistransmitter_hadis_hadis_hadis_i_d04e3a_idx_and_more"), + ] + + operations = [ + migrations.AlterModelOptions( + name="opinionstatus", + options={ + "verbose_name": "Opinion Status", + "verbose_name_plural": "Opinion Statuses", + }, + ), + migrations.AlterModelOptions( + name="transmitterreliability", + options={ + "verbose_name": "Transmitter Reliability", + "verbose_name_plural": "Transmitter Reliabilities", + }, + ), + ] diff --git a/apps/hadis/migrations/0087_contentrelease.py b/apps/hadis/migrations/0087_contentrelease.py new file mode 100644 index 0000000..717ef51 --- /dev/null +++ b/apps/hadis/migrations/0087_contentrelease.py @@ -0,0 +1,44 @@ +# Generated by Django 4.2.27 on 2025-12-27 10:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("hadis", "0086_alter_opinionstatus_options_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="ContentRelease", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "version_name", + models.CharField(max_length=50, verbose_name="Version Name"), + ), + ( + "published_at", + models.DateTimeField( + auto_now_add=True, verbose_name="Published Date" + ), + ), + ( + "description", + models.TextField(blank=True, verbose_name="Release Description"), + ), + ("is_active", models.BooleanField(default=True, verbose_name="Active")), + ], + options={ + "ordering": ["-published_at"], + }, + ), + ] diff --git a/apps/hadis/models/__init__.py b/apps/hadis/models/__init__.py index 3e6f70c..44d3e7b 100644 --- a/apps/hadis/models/__init__.py +++ b/apps/hadis/models/__init__.py @@ -1,4 +1,5 @@ from .category import * from .hadis import * from .transmitter import * -from .reference import * \ No newline at end of file +from .reference import * +from .version import * \ No newline at end of file diff --git a/apps/hadis/models/version.py b/apps/hadis/models/version.py new file mode 100644 index 0000000..09b92c0 --- /dev/null +++ b/apps/hadis/models/version.py @@ -0,0 +1,13 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ + +class ContentRelease(models.Model): + version_name = models.CharField(max_length=50, verbose_name=_('Version Name')) # e.g., "v1.2 - Muharram Update" + published_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Published Date")) + description = models.TextField(blank=True, verbose_name=_("Release Description")) + + # Optional: is_active to easily rollback updates if something breaks + is_active = models.BooleanField(default=True, verbose_name=_("Active")) + + class Meta: + ordering = ['-published_at'] \ No newline at end of file diff --git a/apps/hadis/serializers/__init__.py b/apps/hadis/serializers/__init__.py index eef37be..1f4ec91 100644 --- a/apps/hadis/serializers/__init__.py +++ b/apps/hadis/serializers/__init__.py @@ -1,2 +1,3 @@ from .category import * -from .hadis import * \ No newline at end of file +from .hadis import * +from .version import * \ No newline at end of file diff --git a/apps/hadis/serializers/version.py b/apps/hadis/serializers/version.py new file mode 100644 index 0000000..4eb6036 --- /dev/null +++ b/apps/hadis/serializers/version.py @@ -0,0 +1,16 @@ +from rest_framework import serializers +from ..models import ContentRelease + + +class ContentReleaseSyncSerializer(serializers.ModelSerializer): + """Serializer for syncing content release data for offline mode""" + + class Meta: + model = ContentRelease + fields = [ + 'id', + 'version_name', + 'published_at', + 'description', + 'is_active' + ] diff --git a/apps/hadis/urls.py b/apps/hadis/urls.py index 641572a..111ccdd 100644 --- a/apps/hadis/urls.py +++ b/apps/hadis/urls.py @@ -3,6 +3,7 @@ from .views.category import HadisCategorySectListView, HadisCategoryTreeView, Ca from .views.hadis import HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView,HadisMainListView, HadisFiltersView from .views.transmitter import TransmitterView ,TransmitterDetailView, TransmitterSyncView,TransmitterOpinionView, TransmitterOriginalTextView, TransmitterFiltersView from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView, BookAttributeView +from .views.version import ContentReleaseSyncView from .views.info import HadisInfoView from django.views.decorators.cache import cache_page from django.views.decorators.vary import vary_on_headers @@ -20,6 +21,7 @@ urlpatterns = [ path('sync/hadis/', cached_view(HadisSyncView.as_view()), name='hadis-sync'), path('sync/narrators/', cached_view(TransmitterSyncView.as_view()), name='transmitter-sync'), path('sync/references/', cached_view(BookReferenceSyncView.as_view()), name='reference-sync'), + path('sync/version/', ContentReleaseSyncView.as_view(), name='content-release-sync'), path('info/', cached_view(HadisInfoView.as_view()), name='hadis-info'), # Category paths (more specific first) diff --git a/apps/hadis/views/hadis.py b/apps/hadis/views/hadis.py index 432565d..12bdf75 100644 --- a/apps/hadis/views/hadis.py +++ b/apps/hadis/views/hadis.py @@ -116,6 +116,7 @@ class HadisMainListView(ListAPIView): serializer_class = HadisListSerializer pagination_class = PageNumberPagination + @hadis_main_list_swagger def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) diff --git a/apps/hadis/views/version.py b/apps/hadis/views/version.py new file mode 100644 index 0000000..c8d0dab --- /dev/null +++ b/apps/hadis/views/version.py @@ -0,0 +1,20 @@ +from rest_framework.generics import RetrieveAPIView +from rest_framework.response import Response + +from ..models import ContentRelease +from ..serializers import ContentReleaseSyncSerializer +from ..docs import content_release_sync_swagger + + +class ContentReleaseSyncView(RetrieveAPIView): + """ + API view to get the latest content release for offline mode sync + """ + serializer_class = ContentReleaseSyncSerializer + + @content_release_sync_swagger + def get(self, request, *args, **kwargs): + return self.retrieve(request, *args, **kwargs) + + def get_object(self): + return ContentRelease.objects.filter(is_active=True).order_by('-published_at').first()