Skip to content

Commit

Permalink
Merge pull request #855 from DalgoT4D/notifications-system-changes
Browse files Browse the repository at this point in the history
added new apis to get user notifications and bulk update status
  • Loading branch information
fatchat authored Sep 13, 2024
2 parents b07abb1 + 2e90c57 commit ef19849
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 20 deletions.
49 changes: 44 additions & 5 deletions ddpui/api/notifications_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ddpui.schemas.notifications_api_schemas import (
CreateNotificationPayloadSchema,
UpdateReadStatusSchema,
UpdateReadStatusSchemav1,
)
from ddpui.models.org_user import OrgUser

Expand Down Expand Up @@ -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)

Expand All @@ -97,22 +102,41 @@ 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.
It returns only the past notifications,i.e,notifications
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)

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
Expand All @@ -128,6 +152,21 @@ def mark_as_read(request, payload: UpdateReadStatusSchema):
return result


@notificationsapi.put("/v1", auth=auth.CustomAuthMiddleware())
def mark_as_read_v1(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):
"""
Expand Down
71 changes: 67 additions & 4 deletions ddpui/core/notifications_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
{
Expand Down Expand Up @@ -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"""
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions ddpui/schemas/notifications_api_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 6 additions & 7 deletions ddpui/tests/api_tests/test_notifications_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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():
Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand All @@ -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)
assert response["res"] == 0
mock_get_unread_notifications_count.assert_called_once_with(orguser)
8 changes: 4 additions & 4 deletions ddpui/tests/core/test_notifications_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
assert result["res"] >= 0

0 comments on commit ef19849

Please sign in to comment.