Browse Source

notifications added with filtering options

master
Mohsen Taba 2 months ago
parent
commit
4168879bbd
  1. 12
      apps/account/serializers/notification.py
  2. 1
      apps/account/urls.py
  3. 153
      apps/account/views/notification.py

12
apps/account/serializers/notification.py

@ -23,4 +23,14 @@ class NotificationSendSerializer(serializers.Serializer):
data = serializers.DictField(required=False)
account_id = serializers.CharField(required=True)
user_type = serializers.CharField(required=True)
service = serializers.ChoiceField(choices=Notification.ServiceChoices.choices, default=Notification.ServiceChoices.IMAM_JAVAD)
service = serializers.ChoiceField(choices=Notification.ServiceChoices.choices, default=Notification.ServiceChoices.IMAM_JAVAD)
class AdminNotificationSerializer(serializers.ModelSerializer):
user_fullname = serializers.CharField(source='user.fullname', read_only=True)
user_email = serializers.CharField(source='user.email', read_only=True)
user_id = serializers.IntegerField(source='user.id', read_only=True)
class Meta:
model = Notification
fields = ['id', 'title', 'message', 'is_read', 'service', 'created_at', 'updated_at', 'user_fullname', 'user_email', 'user_id']

1
apps/account/urls.py

@ -9,6 +9,7 @@ from apps.geolocation_package.views.region_info import RegionInfoView
admin_router = SimpleRouter()
admin_router.register(r'users', views.AdminUserViewSet, basename='admin-users')
admin_router.register(r'notifications', views.AdminNotificationViewSet, basename='admin-notifications')
urlpatterns = [
path('location-info/', IPGeolocationAPIView.as_view(), name='location-info'),

153
apps/account/views/notification.py

@ -4,10 +4,16 @@ from rest_framework.authentication import TokenAuthentication
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from rest_framework.permissions import IsAuthenticated
from apps.account.serializers import NotificationSerializer, NotificationSendSerializer
from apps.account.serializers import NotificationSerializer, NotificationSendSerializer, AdminNotificationSerializer
from apps.account.models import Notification, User
from apps.account.tasks import send_notification
from utils.pagination import StandardResultsSetPagination
from django.db.models import Q
from rest_framework.viewsets import ModelViewSet
from apps.account.permissions import IsSuperAdmin
import logging
logger = logging.getLogger(__name__)
@ -63,49 +69,22 @@ class NotificationReadAllView(generics.GenericAPIView):
authentication_classes = [TokenAuthentication]
queryset = Notification.objects.all()
@swagger_auto_schema(
operation_description="Mark all notifications as read for the authenticated user or merchant account.",
operation_description="Mark all notifications as read for the authenticated user.",
tags=['Notifications'],
manual_parameters=[
openapi.Parameter(
'service',
openapi.IN_QUERY,
description="Filter notifications to mark as read by service (imam-javad or doboodi)",
type=openapi.TYPE_STRING,
enum=['imam-javad', 'doboodi'],
required=False
)
],
responses={
200: "All notifications marked as read",
}
)
def get(self, request, *args, **kwargs):
user = request.user
service = request.query_params.get('service', None)
# Get base queryset for user's notifications
notifications = Notification.objects.filter(user=user)
# Mark all of the user's notifications as read
Notification.objects.filter(user=user).update(is_read=True)
return Response({'status': 'all notifications marked as read'}, status=status.HTTP_200_OK)
# Apply service filtering based on query parameter
if service == 'doboodi':
# If service is doboodi, only mark doboodi notifications as read
notifications = notifications.filter(service=Notification.ServiceChoices.DOBOODI)
status_message = 'all doboodi notifications marked as read'
else:
# Default: mark all imam-javad notifications as read (exclude doboodi)
notifications = notifications.exclude(service=Notification.ServiceChoices.DOBOODI)
status_message = 'all imam-javad notifications marked as read'
# Update the filtered notifications
notifications.update(is_read=True)
return Response({'status': status_message}, status=status.HTTP_200_OK)
class SendNotificationView(generics.GenericAPIView):
@swagger_auto_schema(
@ -157,3 +136,109 @@ class SendNotificationView(generics.GenericAPIView):
return Response({
'error': str(e)
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class AdminNotificationViewSet(ModelViewSet):
permission_classes = [IsSuperAdmin]
authentication_classes = [TokenAuthentication]
serializer_class = AdminNotificationSerializer
pagination_class = StandardResultsSetPagination
def get_queryset(self):
queryset = Notification.objects.all().select_related('user')
# Filter by service if provided
service = self.request.query_params.get('service', None)
if service:
queryset = queryset.filter(service=service)
# Search by user name or email or notification title/message
search = self.request.query_params.get('search', None)
if search:
queryset = queryset.filter(
Q(title__icontains=search) |
Q(message__icontains=search) |
Q(user__fullname__icontains=search) |
Q(user__email__icontains=search)
)
# Date filtering
date_after = self.request.query_params.get('date_after', None)
if date_after:
queryset = queryset.filter(created_at__date__gte=date_after)
date_before = self.request.query_params.get('date_before', None)
if date_before:
queryset = queryset.filter(created_at__date__lte=date_before)
# User filtering
user_param = self.request.query_params.get('user', None)
if user_param:
queryset = queryset.filter(user_id=user_param)
# Read status filtering (is_read=true/false)
is_read_param = self.request.query_params.get('is_read', None)
if is_read_param is not None:
if is_read_param.lower() == 'true':
queryset = queryset.filter(is_read=True)
elif is_read_param.lower() == 'false':
queryset = queryset.filter(is_read=False)
return queryset.order_by('-created_at')
def create(self, request, *args, **kwargs):
title = request.data.get('title')
message = request.data.get('message')
service = request.data.get('service', 'imam-javad')
send_to_all = request.data.get('send_to_all', False)
user_id = request.data.get('user_id', None)
if not title or not message:
return Response({'error': 'Title and message are required.'}, status=status.HTTP_400_BAD_REQUEST)
if send_to_all:
# Get all active users
users = User.objects.filter(is_active=True)
notifications_to_create = []
for u in users:
notifications_to_create.append(Notification(
title=title,
message=message,
service=service,
user=u
))
Notification.objects.bulk_create(notifications_to_create)
# Send push notifications
fcm_tokens = list(users.exclude(fcm__isnull=True).exclude(fcm='').values_list('fcm', flat=True))
if fcm_tokens:
try:
send_notification(fcm_tokens, title, message, {'service': service})
except Exception as e:
logger.error(f"Failed to send push notifications: {e}")
return Response({'message': f'Notification created for {len(notifications_to_create)} users.'}, status=status.HTTP_201_CREATED)
else:
if not user_id:
return Response({'error': 'user_id is required when send_to_all is false.'}, status=status.HTTP_400_BAD_REQUEST)
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return Response({'error': 'User not found.'}, status=status.HTTP_404_NOT_FOUND)
notif = Notification.objects.create(
title=title,
message=message,
service=service,
user=user
)
# Send push notification
if user.fcm:
try:
send_notification([user.fcm], title, message, {'service': service})
except Exception as e:
logger.error(f"Failed to send push notification: {e}")
serializer = self.get_serializer(notif)
return Response(serializer.data, status=status.HTTP_201_CREATED)
Loading…
Cancel
Save