Introduce notifications app and integrate emails
Add a new notifications app (models, serializers, views, admin, tasks, consumers, routing, urls, tests) with Notification.notify for in-app websocket pushes and optional email delivery. Centralize email sending in notifications.tasks.send_email_with_context and re-export it from account.tasks for compatibility. Update account and commerce and advertisement tasks to use Notification.notify/_notify_order and the new email helper; adjust order/notification tasks to consolidate logic. Wire notifications into ASGI routing, settings and URL conf. Misc: handle OSError when importing weasyprint, add tmp/ to .gitignore, add local .claude PowerShell checks, add social.blog skeleton, and remove legacy ews-component test files.
This commit is contained in:
51
backend/notifications/views.py
Normal file
51
backend/notifications/views.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import logging
|
||||
from django.utils import timezone
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
|
||||
from drf_spectacular.utils import extend_schema
|
||||
|
||||
from .models import Notification
|
||||
from .serializers import NotificationSerializer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@extend_schema(tags=["notifications"])
|
||||
class NotificationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||
serializer_class = NotificationSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get_queryset(self):
|
||||
return Notification.objects.filter(user=self.request.user)
|
||||
|
||||
@extend_schema(
|
||||
summary="Unread notification count",
|
||||
responses={200: {"type": "object", "properties": {"unread_count": {"type": "integer"}}}},
|
||||
)
|
||||
@action(detail=False, methods=["get"], url_path="unread-count")
|
||||
def unread_count(self, request):
|
||||
count = self.get_queryset().filter(is_read=False).count()
|
||||
return Response({"unread_count": count})
|
||||
|
||||
@extend_schema(summary="Mark a single notification as read", responses={200: NotificationSerializer})
|
||||
@action(detail=True, methods=["post"], url_path="read")
|
||||
def mark_read(self, request, pk=None):
|
||||
notification = self.get_object()
|
||||
if not notification.is_read:
|
||||
notification.is_read = True
|
||||
notification.read_at = timezone.now()
|
||||
notification.save(update_fields=["is_read", "read_at"])
|
||||
return Response(NotificationSerializer(notification).data)
|
||||
|
||||
@extend_schema(
|
||||
summary="Mark all notifications as read",
|
||||
responses={200: {"type": "object", "properties": {"marked": {"type": "integer"}}}},
|
||||
)
|
||||
@action(detail=False, methods=["post"], url_path="read-all")
|
||||
def mark_all_read(self, request):
|
||||
now = timezone.now()
|
||||
updated = self.get_queryset().filter(is_read=False).update(is_read=True, read_at=now)
|
||||
return Response({"marked": updated})
|
||||
Reference in New Issue
Block a user