diff --git a/Mapapi/migrations/0009_user_activity_seen_at.py b/Mapapi/migrations/0009_user_activity_seen_at.py new file mode 100644 index 0000000..91b6ee0 --- /dev/null +++ b/Mapapi/migrations/0009_user_activity_seen_at.py @@ -0,0 +1,19 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + """Ajoute User.activity_seen_at : horodatage de dernière consultation du flux + d'activité, pour exposer des compteurs vues / non-vues (comme lu/non-lu des + notifications).""" + + dependencies = [ + ('Mapapi', '0008_unaccent_extension'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='activity_seen_at', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/Mapapi/models.py b/Mapapi/models.py index 79fe761..6bf31e6 100644 --- a/Mapapi/models.py +++ b/Mapapi/models.py @@ -425,6 +425,9 @@ class User(AbstractBaseUser, PermissionsMixin): is_verified = models.BooleanField(default=False) otp = models.CharField(max_length=6, blank=True, null=True) otp_expiration = models.DateTimeField(blank=True, null=True) + # Dernière consultation du flux d'activité (vues/non-vues) : tout élément du + # flux postérieur à cette date est considéré « non vu » par l'utilisateur. + activity_seen_at = models.DateTimeField(blank=True, null=True) objects = UserManager() USERNAME_FIELD = 'email' diff --git a/Mapapi/urls.py b/Mapapi/urls.py index 51bf3bd..c617b61 100644 --- a/Mapapi/urls.py +++ b/Mapapi/urls.py @@ -189,6 +189,7 @@ path('notifications/mark-all-read/', NotificationViewSet.as_view({'post': 'mark_all_read'}), name="notification-mark-all-read"), path('notifications//', NotificationViewSet.as_view({'get': 'retrieve', 'patch': 'partial_update'}), name="notification-detail"), path('activity-feed/', ActivityFeedView.as_view(), name="activity-feed"), + path('activity-feed/mark-seen/', ActivityFeedMarkSeenView.as_view(), name="activity-feed-mark-seen"), path('agents/stats/', AgentStatsView.as_view(), name="agents-stats"), path('agents/', AgentListView.as_view(), name="agents-list"), path('hadleIncident/', HandleIncidentView.as_view(), name="handle"), diff --git a/Mapapi/views/notification.py b/Mapapi/views/notification.py index 705a431..846e8cf 100644 --- a/Mapapi/views/notification.py +++ b/Mapapi/views/notification.py @@ -1,5 +1,6 @@ """Notification & user-action endpoints.""" from rest_framework import viewsets, generics, status +from rest_framework.views import APIView from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -150,8 +151,40 @@ def get_queryset(self): return qs # tri par défaut depuis Meta (-created_at, -timeStamp) def list(self, request, *args, **kwargs): - """Liste paginée + `total_count` (nombre total d'activités du flux).""" + """Liste paginée + compteurs total / vues / non-vues du flux. + + `unseen_count` = éléments du flux postérieurs à la dernière consultation + (`user.activity_seen_at`) ; tout est « non vu » si l'utilisateur n'a jamais + consulté le flux. `POST /activity-feed/mark-seen/` met l'horodatage à jour. + """ response = super().list(request, *args, **kwargs) if isinstance(response.data, dict): - response.data['total_count'] = self.get_queryset().count() + qs = self.get_queryset() + total = qs.count() + seen_at = getattr(request.user, 'activity_seen_at', None) + unseen = qs.filter(created_at__gt=seen_at).count() if seen_at else total + response.data['total_count'] = total + response.data['unseen_count'] = unseen + response.data['seen_count'] = total - unseen return response + + +@extend_schema( + tags=['Notifications'], + operation_id='activity_feed_mark_seen', + summary="Marquer le flux d'activité comme vu", + description="Met à jour la date de dernière consultation du flux d'activité " + "de l'utilisateur connecté → `unseen_count` repasse à 0. Auth requise.", + request=None, + responses={200: OpenApiTypes.OBJECT}, +) +class ActivityFeedMarkSeenView(APIView): + """POST /activity-feed/mark-seen/ — marque le flux d'activité comme vu.""" + permission_classes = [IsAuthenticated] + + def post(self, request, *args, **kwargs): + from django.utils import timezone + request.user.activity_seen_at = timezone.now() + request.user.save(update_fields=['activity_seen_at']) + return Response({'activity_seen_at': request.user.activity_seen_at}, + status=status.HTTP_200_OK)