diff --git a/apps/dobodbi_calendar/admin.py b/apps/dobodbi_calendar/admin.py index 35165fd..aef89f6 100644 --- a/apps/dobodbi_calendar/admin.py +++ b/apps/dobodbi_calendar/admin.py @@ -1,6 +1,10 @@ import json from django.contrib import admin from django.db import models +from django.http import JsonResponse +from django.shortcuts import get_object_or_404 +from django.urls import path +from django.utils.dateformat import format as date_format from django.utils.translation import gettext_lazy as _ from django.utils.safestring import mark_safe from django.utils.html import format_html @@ -46,6 +50,7 @@ class CalendarOccasionsForm(forms.ModelForm): class CalendarOccasionsAdmin(ModelAdmin): form = CalendarOccasionsForm + change_list_template = "admin/dobodbi_calendar/calendar_event_list.html" ordering = ('-id',) list_display = [ "title", @@ -119,6 +124,84 @@ class CalendarOccasionsAdmin(ModelAdmin): from django.utils.html import format_html return "\n".join([f"{i['month']}/{i['day']}" for i in obj.dates]) + def get_urls(self): + urls = super().get_urls() + custom_urls = [ + path( + "manage/create/", + self.admin_site.admin_view(self.create_event_view), + name="dobodbi_calendar_calendaroccasions_create", + ), + path( + "manage//update/", + self.admin_site.admin_view(self.update_event_view), + name="dobodbi_calendar_calendaroccasions_update", + ), + ] + return custom_urls + urls + + def changelist_view(self, request, extra_context=None): + events = CalendarOccasions.objects.all().order_by("-updated_at", "-id") + event_rows = [ + { + "id": event.id, + "title": event.title, + "occasion_type": event.occasion_type, + "occasion_type_label": event.get_occasion_type_display(), + "event_type": event.event_type or "", + "event_type_label": event.get_event_type_display() if event.event_type else "-", + "is_global": event.is_global, + "is_yearly": event.is_yearly, + "dates": event.dates or [], + "dates_preview": ", ".join( + [ + f"{date_item.get('year', '')}/{date_item.get('month', '')}/{date_item.get('day', '')}".strip("/") + for date_item in (event.dates or []) + ] + ), + "updated_at": date_format(event.updated_at, "Y-m-d H:i"), + "created_at": date_format(event.created_at, "Y-m-d H:i"), + } + for event in events + ] + + extra_context = extra_context or {} + extra_context.update( + { + "calendar_events": event_rows, + "calendar_event_type_choices": [ + {"value": value, "label": label} + for value, label in CalendarOccasions.EventType.choices + ], + "calendar_occasion_type_choices": [ + {"value": value, "label": label} + for value, label in CalendarOccasions.OccasionType.choices + ], + } + ) + return super().changelist_view(request, extra_context=extra_context) + + def create_event_view(self, request): + if request.method != "POST": + return JsonResponse({"ok": False, "error": "Method not allowed."}, status=405) + + form = CalendarOccasionsForm(request.POST) + if form.is_valid(): + event = form.save() + return JsonResponse({"ok": True, "id": event.id}) + return JsonResponse({"ok": False, "errors": form.errors.get_json_data()}, status=400) + + def update_event_view(self, request, event_id): + if request.method != "POST": + return JsonResponse({"ok": False, "error": "Method not allowed."}, status=405) + + event = get_object_or_404(CalendarOccasions, pk=event_id) + form = CalendarOccasionsForm(request.POST, instance=event) + if form.is_valid(): + form.save() + return JsonResponse({"ok": True, "id": event.id}) + return JsonResponse({"ok": False, "errors": form.errors.get_json_data()}, status=400) + def get_search_results(self, request, queryset, search_term): queryset, use_distinct = super().get_search_results(request, queryset, search_term) diff --git a/apps/dobodbi_calendar/serializers_admin.py b/apps/dobodbi_calendar/serializers_admin.py new file mode 100644 index 0000000..6f0461e --- /dev/null +++ b/apps/dobodbi_calendar/serializers_admin.py @@ -0,0 +1,41 @@ +from rest_framework import serializers + +from apps.dobodbi_calendar.models import CalendarOccasions + + +class CalendarOccasionAdminSerializer(serializers.ModelSerializer): + dates = serializers.ListField(child=serializers.DictField(), allow_empty=False) + + class Meta: + model = CalendarOccasions + fields = [ + "id", + "title", + "is_global", + "occasion_type", + "dates", + "is_yearly", + "event_type", + "updated_at", + "created_at", + ] + read_only_fields = ["id", "updated_at", "created_at"] + + def validate_dates(self, value): + cleaned_dates = [] + + for index, item in enumerate(value): + day = str(item.get("day", "")).strip() + month = str(item.get("month", "")).strip() + year = str(item.get("year", "")).strip() + + if not day or not month: + raise serializers.ValidationError(f"Date row {index + 1} must include day and month.") + + cleaned_dates.append({ + "day": day, + "month": month, + "year": year, + }) + + return cleaned_dates diff --git a/apps/dobodbi_calendar/urls.py b/apps/dobodbi_calendar/urls.py index 1fb196f..ae660e6 100644 --- a/apps/dobodbi_calendar/urls.py +++ b/apps/dobodbi_calendar/urls.py @@ -1,8 +1,14 @@ -from django.urls import path +from django.urls import include, path +from rest_framework.routers import SimpleRouter from apps.dobodbi_calendar.views import CalendarList, AdjustmentConfigView, OccasionsList +from apps.dobodbi_calendar.views_admin import AdminCalendarOccasionViewSet + +admin_router = SimpleRouter() +admin_router.register(r'occasions', AdminCalendarOccasionViewSet, basename='admin-calendar-occasions') urlpatterns = [ + path('admin/', include(admin_router.urls)), path('sync-occasions/', CalendarList.as_view()), path('adjustemnts/', AdjustmentConfigView.as_view()), path('occasions/', OccasionsList.as_view()), diff --git a/apps/dobodbi_calendar/views_admin.py b/apps/dobodbi_calendar/views_admin.py new file mode 100644 index 0000000..e1c57e3 --- /dev/null +++ b/apps/dobodbi_calendar/views_admin.py @@ -0,0 +1,44 @@ +from django.db.models import Q +from rest_framework.authentication import TokenAuthentication +from rest_framework.permissions import IsAuthenticated +from rest_framework.viewsets import ModelViewSet + +from apps.account.permissions import IsSuperAdmin +from apps.dobodbi_calendar.models import CalendarOccasions +from apps.dobodbi_calendar.serializers_admin import CalendarOccasionAdminSerializer + + +class AdminCalendarOccasionViewSet(ModelViewSet): + serializer_class = CalendarOccasionAdminSerializer + permission_classes = [IsAuthenticated, IsSuperAdmin] + authentication_classes = [TokenAuthentication] + pagination_class = None + + def get_queryset(self): + queryset = CalendarOccasions.objects.all() + search_query = self.request.query_params.get("search") + + if search_query: + queryset = queryset.filter( + Q(title__icontains=search_query) + | Q(event_type__icontains=search_query) + | Q(occasion_type__icontains=search_query) + ) + + event_type = self.request.query_params.get("event_type") + if event_type and event_type != "all": + queryset = queryset.filter(event_type=event_type) + + occasion_type = self.request.query_params.get("occasion_type") + if occasion_type and occasion_type != "all": + queryset = queryset.filter(occasion_type=occasion_type) + + yearly = self.request.query_params.get("is_yearly") + if yearly in {"true", "false"}: + queryset = queryset.filter(is_yearly=yearly == "true") + + global_filter = self.request.query_params.get("is_global") + if global_filter in {"true", "false"}: + queryset = queryset.filter(is_global=global_filter == "true") + + return queryset.order_by("-updated_at", "-id")