From 64c1d52f6e5fad82733987a13ae42ff2ff422eb9 Mon Sep 17 00:00:00 2001 From: Ishankoradia Date: Wed, 11 Sep 2024 10:52:52 +0530 Subject: [PATCH 1/5] added new apis to get user notifications and bulk update status of notification --- ddpui/api/notifications_api.py | 45 +++++++++++++- ddpui/core/notifications_service.py | 71 ++++++++++++++++++++-- ddpui/schemas/notifications_api_schemas.py | 7 +++ 3 files changed, 116 insertions(+), 7 deletions(-) diff --git a/ddpui/api/notifications_api.py b/ddpui/api/notifications_api.py index e4d6b620..d93c3740 100644 --- a/ddpui/api/notifications_api.py +++ b/ddpui/api/notifications_api.py @@ -7,6 +7,7 @@ from ddpui.schemas.notifications_api_schemas import ( CreateNotificationPayloadSchema, UpdateReadStatusSchema, + UpdateReadStatusSchemav1, ) from ddpui.models.org_user import OrgUser @@ -73,12 +74,16 @@ def create_notification(request, payload: CreateNotificationPayloadSchema): @notificationsapi.get("/history") -def get_notification_history(request, page: int = 1, limit: int = 10): +def get_notification_history( + request, page: int = 1, limit: int = 10, read_status: int = None +): """ Returns all the notifications including the past and the future scheduled notifications """ - error, result = notifications_service.get_notification_history(page, limit) + error, result = notifications_service.get_notification_history( + page, limit, read_status=None + ) if error is not None: raise HttpError(400, error) @@ -105,7 +110,26 @@ def get_user_notifications(request, page: int = 1, limit: int = 10): which are already sent """ orguser = request.orguser - error, result = notifications_service.get_user_notifications(orguser, page, limit) + error, result = notifications_service.fetch_user_notifications(orguser, page, limit) + if error is not None: + raise HttpError(400, error) + + return result + + +@notificationsapi.get("/v1", auth=auth.CustomAuthMiddleware()) +def get_user_notifications_v1( + request, page: int = 1, limit: int = 10, read_status: int = None +): + """ + Returns all the notifications for a particular user. + It returns only the past notifications,i.e,notifications + which are already sent + """ + orguser = request.orguser + error, result = notifications_service.fetch_user_notifications_v1( + orguser, page, limit, read_status + ) if error is not None: raise HttpError(400, error) @@ -128,6 +152,21 @@ def mark_as_read(request, payload: UpdateReadStatusSchema): return result +@notificationsapi.put("/v1", auth=auth.CustomAuthMiddleware()) +def mark_as_read(request, payload: UpdateReadStatusSchemav1): + """ + Bulk update of read status of notifications + """ + orguser: OrgUser = request.orguser + error, result = notifications_service.mark_notifications_as_read_or_unread( + orguser.id, payload.notification_ids, payload.read_status + ) + if error is not None: + raise HttpError(400, error) + + return result + + @notificationsapi.delete("/") def delete_notification(request, notification_id: int): """ diff --git a/ddpui/core/notifications_service.py b/ddpui/core/notifications_service.py index 2afcf6a3..36a82dde 100644 --- a/ddpui/core/notifications_service.py +++ b/ddpui/core/notifications_service.py @@ -157,13 +157,18 @@ def create_notification( # get notification history def get_notification_history( - page: int, limit: int + page: int, limit: int, read_status: Optional[int] = None ) -> Tuple[Optional[None], Dict[str, Any]]: """returns history of sent notifications""" - notifications = Notification.objects.all().order_by("-timestamp") + notifications = Notification.objects + + if read_status: + notifications = notifications.filter(read_status=(read_status == 1)) + + notifications = notifications.all().order_by("-timestamp") paginator = Paginator(notifications, limit) - paginated_notifications: Notification = paginator.get_page(page) + paginated_notifications: list[Notification] = paginator.get_page(page) notification_history = [ { @@ -214,7 +219,7 @@ def get_notification_recipients( # get notification data -def get_user_notifications( +def fetch_user_notifications( orguser: OrgUser, page: int, limit: int ) -> Tuple[Optional[None], Dict[str, Any]]: """returns all notifications for a specific user""" @@ -256,6 +261,50 @@ def get_user_notifications( } +def fetch_user_notifications_v1( + orguser: OrgUser, page: int, limit: int, read_status: int = None +) -> Tuple[Optional[None], Dict[str, Any]]: + """returns all notifications for a specific user""" + + notifications = ( + NotificationRecipient.objects.filter( + recipient=orguser, + notification__sent_time__isnull=False, + **({"read_status": read_status == 1} if read_status is not None else {}), + ) + .select_related("notification") + .order_by("-notification__timestamp") + ) + + paginator = Paginator(notifications, limit) + paginated_notifications = paginator.get_page(page) + + user_notifications = [] + + for recipient in paginated_notifications: + notification = recipient.notification + user_notifications.append( + { + "id": notification.id, + "author": notification.author, + "message": notification.message, + "timestamp": notification.timestamp, + "urgent": notification.urgent, + "scheduled_time": notification.scheduled_time, + "sent_time": notification.sent_time, + "read_status": recipient.read_status, + } + ) + + return None, { + "success": True, + "res": user_notifications, + "page": paginated_notifications.number, + "total_pages": paginated_notifications.paginator.num_pages, + "total_notifications": paginated_notifications.paginator.count, + } + + # mark notificaiton as read def mark_notification_as_read_or_unread( orguser_id: int, notification_id: int, read_status: bool @@ -272,6 +321,20 @@ def mark_notification_as_read_or_unread( return "Notification not found for the given user", None +def mark_notifications_as_read_or_unread( + orguser_id: int, notification_ids: int, read_status: bool +) -> Tuple[Optional[str], Optional[Dict[str, Any]]]: + """bulk update of the read status of a recipient for notifications""" + try: + NotificationRecipient.objects.filter( + recipient__id=orguser_id, + notification__id__in=notification_ids, + ).update(read_status=read_status) + return None, {"success": True, "message": "Notifications updated successfully"} + except NotificationRecipient.DoesNotExist: + return "Something went wrong updating the notifications", None + + # delete notification def delete_scheduled_notification( notification_id: int, diff --git a/ddpui/schemas/notifications_api_schemas.py b/ddpui/schemas/notifications_api_schemas.py index 844153be..367cc252 100644 --- a/ddpui/schemas/notifications_api_schemas.py +++ b/ddpui/schemas/notifications_api_schemas.py @@ -37,3 +37,10 @@ class UpdateReadStatusSchema(Schema): notification_id: int read_status: bool + + +class UpdateReadStatusSchemav1(Schema): + """Schema for updating the read status of a notification.""" + + notification_ids: list[int] + read_status: bool From b9ebc530f14324103890e7a9aa2dfdae06a860c4 Mon Sep 17 00:00:00 2001 From: Ishankoradia Date: Fri, 13 Sep 2024 12:03:45 +0530 Subject: [PATCH 2/5] deprecate old apis --- ddpui/api/notifications_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddpui/api/notifications_api.py b/ddpui/api/notifications_api.py index d93c3740..2f6eeaff 100644 --- a/ddpui/api/notifications_api.py +++ b/ddpui/api/notifications_api.py @@ -102,7 +102,7 @@ def get_notification_recipients(request, notification_id: int): return result -@notificationsapi.get("/", auth=auth.CustomAuthMiddleware()) +@notificationsapi.get("/", auth=auth.CustomAuthMiddleware(), deprecated=True) def get_user_notifications(request, page: int = 1, limit: int = 10): """ Returns all the notifications for a particular user. @@ -136,7 +136,7 @@ def get_user_notifications_v1( return result -@notificationsapi.put("/", auth=auth.CustomAuthMiddleware()) +@notificationsapi.put("/", auth=auth.CustomAuthMiddleware(), deprecated=True) def mark_as_read(request, payload: UpdateReadStatusSchema): """ Handles the task of updating the read_status From ee8140d8324030d4fd3c03c85fd0b0dfc20afc24 Mon Sep 17 00:00:00 2001 From: Ishankoradia Date: Fri, 13 Sep 2024 12:13:50 +0530 Subject: [PATCH 3/5] minor change --- ddpui/tests/core/test_notifications_service.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ddpui/tests/core/test_notifications_service.py b/ddpui/tests/core/test_notifications_service.py index 5e236e14..d40f6523 100644 --- a/ddpui/tests/core/test_notifications_service.py +++ b/ddpui/tests/core/test_notifications_service.py @@ -16,10 +16,10 @@ create_notification, get_notification_history, get_notification_recipients, - get_user_notifications, + fetch_user_notifications, mark_notification_as_read_or_unread, delete_scheduled_notification, - get_unread_notifications_count + get_unread_notifications_count, ) from ddpui.schemas.notifications_api_schemas import SentToEnum from ddpui.tests.api_tests.test_user_org_api import mock_request, seed_db @@ -248,7 +248,7 @@ def test_get_notification_recipients_not_exist(): def test_get_user_notifications(orguser): - error, result = get_user_notifications(orguser, 1, 10) + error, result = fetch_user_notifications(orguser, 1, 10) assert error is None assert result["success"] is True assert len(result["res"]) >= 0 @@ -290,4 +290,4 @@ def test_count_unread_notifications_success(orguser): error, result = get_unread_notifications_count(orguser) assert error is None assert result["success"] is True - assert result["res"] >= 0 \ No newline at end of file + assert result["res"] >= 0 From 8fae4a1727b44655d99c10c702679e5dbf2d778c Mon Sep 17 00:00:00 2001 From: Ishankoradia Date: Fri, 13 Sep 2024 12:29:57 +0530 Subject: [PATCH 4/5] fix test case --- ddpui/api/notifications_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddpui/api/notifications_api.py b/ddpui/api/notifications_api.py index 2f6eeaff..415b221c 100644 --- a/ddpui/api/notifications_api.py +++ b/ddpui/api/notifications_api.py @@ -153,7 +153,7 @@ def mark_as_read(request, payload: UpdateReadStatusSchema): @notificationsapi.put("/v1", auth=auth.CustomAuthMiddleware()) -def mark_as_read(request, payload: UpdateReadStatusSchemav1): +def mark_as_read_v1(request, payload: UpdateReadStatusSchemav1): """ Bulk update of read status of notifications """ From 2e90c57d2c6fc8a79781a33a9e9afafad5e659d2 Mon Sep 17 00:00:00 2001 From: Ishankoradia Date: Fri, 13 Sep 2024 12:36:52 +0530 Subject: [PATCH 5/5] fix --- ddpui/tests/api_tests/test_notifications_api.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ddpui/tests/api_tests/test_notifications_api.py b/ddpui/tests/api_tests/test_notifications_api.py index feb823ad..5ab1381a 100644 --- a/ddpui/tests/api_tests/test_notifications_api.py +++ b/ddpui/tests/api_tests/test_notifications_api.py @@ -15,7 +15,7 @@ get_user_notifications, delete_notification, mark_as_read, - get_unread_notifications_count + get_unread_notifications_count, ) from ddpui.schemas.notifications_api_schemas import ( CreateNotificationPayloadSchema, @@ -253,7 +253,7 @@ def test_get_notification_history_success(): assert response["success"] is True assert isinstance(response["res"], list) assert all(isinstance(notification, dict) for notification in response["res"]) - mock_get_notification_history.assert_called_once_with(1, 10) + mock_get_notification_history.assert_called_once_with(1, 10, read_status=None) def test_get_notification_recipients_success(): @@ -277,7 +277,7 @@ def test_get_user_notifications_success(orguser): request = MagicMock() request.orguser = orguser with patch( - "ddpui.core.notifications_service.get_user_notifications" + "ddpui.core.notifications_service.fetch_user_notifications" ) as mock_get_user_notifications: mock_get_user_notifications.return_value = (None, {"success": True, "res": []}) response = get_user_notifications(request, 1, 10) @@ -383,6 +383,7 @@ def test_delete_already_sent_notification(): ) mock_delete_notification.assert_called_once_with(1) + def test_get_unread_notifications_count_success(orguser): """tests the success of api endpoint for fetching unread notification count""" request = MagicMock() @@ -399,7 +400,5 @@ def test_get_unread_notifications_count_success(orguser): ) response = get_unread_notifications_count(request) assert response["success"] is True - assert ( - response["res"] == 0 - ) - mock_get_unread_notifications_count.assert_called_once_with(orguser) \ No newline at end of file + assert response["res"] == 0 + mock_get_unread_notifications_count.assert_called_once_with(orguser)