Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔨 Refactor/types #65

Merged
merged 3 commits into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions django_notification/api/views/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,45 +38,51 @@ class ActivityViewSet(

Features:
- List Activities: Lists all seen notifications for the user. The availability of
this method is controlled by the `api_allow_list` setting.
this method is controlled by settings.
- Retrieve Activity: Retrieve detailed information about a specific notification
by its ID. The availability of this method is controlled by the `api_allow_retrieve` setting.
by its ID. The availability of this method is controlled by settings.
- Clear Activities: Allows users to soft-delete or clear all notifications. This
functionality is controlled by the `include_soft_delete` setting.
functionality is controlled by settings.
- Delete Activities: Admin users can permanently delete notifications. This
feature is controlled by the `include_hard_delete` setting.
feature is controlled by settings.

Customizations:
- Dynamic Serializer: Based on user role and settings, the appropriate serializer
is chosen between `NotificationSerializer` (for detailed information) and
`SimpleNotificationSerializer` (for basic information).
- Conditional Actions: Soft and hard deletion actions are conditionally enabled
based on settings (`include_soft_delete`, `include_hard_delete`) and permissions.
Admins have additional capabilities such as hard-deleting notifications.
based on settings and permissions.
Admins have additional capabilities such as hard-deleting notifications based on settings.
- Filtering and Searching: This view supports filtering, searching, and ordering
of notifications via `DjangoFilterBackend`, `SearchFilter`, and `OrderingFilter`.
- Configuration via Settings: The viewset is dynamically configured using the
`configure_attrs` method, which adjusts method availability and functionality
based on project settings.

Parsers:
- Accepts various content types, such as `application/json` and `multipart/form-data`,
allowing flexibility in handling requests that include file uploads or JSON payloads.

Methods:
- `GET /activities/`: List all seen notifications.
- `GET /activities/<id>/`: Retrieve detailed information about a specific notification.
- `POST /activities/clear/`: Soft-delete or clear all activities (conditionally enabled).
- `POST /activities/clear/<id>/`: Soft-delete a specific notification (conditionally enabled).
- `POST /activities/delete/`: Permanently delete all activities (admin only, conditionally enabled).
- `POST /activities/delete/<id>/`: Permanently delete a specific notification (admin only, conditionally enabled).
- `GET /activities/clear_activities/`: Soft-delete or clear all activities (conditionally enabled).
- `GET /activities/<id>/clear_notification/`: Soft-delete a specific notification (conditionally enabled).
- `GET /activities/delete_activities/`: Permanently delete all activities (admin only, conditionally enabled).
- `GET /activities/<id>/delete_notification`: Permanently delete a specific notification (admin only, conditionally enabled).

Permissions:
- Regular Users: Can list, retrieve, and clear their own notifications.
- Admin Users: Have additional permissions to hard-delete notifications, depending
on the configuration.

Settings:
- The availability of list and retrieve methods is controlled by `api_allow_list`
and `api_allow_retrieve` settings.
- The soft-delete and hard-delete functionalities are controlled by `include_soft_delete`
and `include_hard_delete` settings.
- The availability of list and retrieve methods is controlled by `DJANGO_NOTIFICATION_API_ALLOW_LIST`
and `DJANGO_NOTIFICATION_API_ALLOW_RETRIEVE` settings.
- The soft-delete and hard-delete functionalities are controlled by `DJANGO_NOTIFICATION_API_INCLUDE_SOFT_DELETE`
and `DJANGO_NOTIFICATION_API_INCLUDE_HARD_DELETE` settings.
- The level of notification details returned is based on the user's role and the setting
(`DJANGO_NOTIFICATION_SERIALIZER_INCLUDE_FULL_DETAILS`).

This viewset provides a flexible and configurable API for managing notification activities,
with dynamic behavior driven by user roles and project settings.
Expand Down
8 changes: 4 additions & 4 deletions django_notification/api/views/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ class NotificationViewSet(

Features:
- List Notifications: Retrieves a list of unseen notifications. The availability
of this method is controlled by a setting (`api_allow_list`).
of this method is controlled by settings.
- Retrieve Notification: Fetch detailed information about a specific notification
by its ID. Mark the notification as seen upon retrieval. The availability of this
method is controlled by a setting (`api_allow_retrieve`).
method is controlled by settings.
- Mark All as Seen: Marks all unseen notifications for the user as seen.

Customizations:
Expand Down Expand Up @@ -64,9 +64,9 @@ class NotificationViewSet(

Settings:
- The availability of list and retrieve methods is determined by the configuration
(`api_allow_list`, `api_allow_retrieve`).
(`DJANGO_NOTIFICATION_API_ALLOW_LIST`, `DJANGO_NOTIFICATION_API_ALLOW_RETRIEVE`).
- The level of notification details returned is based on the user's role and the setting
(`include_serializer_full_details`).
(`DJANGO_NOTIFICATION_SERIALIZER_INCLUDE_FULL_DETAILS`).

Parsers and filters are automatically applied based on the request's `Content-Type`
and query parameters, making the viewset flexible and adaptable to various use cases.
Expand Down
18 changes: 18 additions & 0 deletions django_notification/constants/qs_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from typing import List, Optional, Union

from django.contrib.auth.models import Group
from django.db.models import JSONField, Model, Q, QuerySet

from django_notification.utils.user_model import UserModel

# Type Alias for Notification QuerySet
Recipient = Optional[UserModel]
Recipients = Optional[Union[UserModel, QuerySet, List[UserModel]]]
Groups = Optional[Union[Group, QuerySet, List[Group]]]
OptConditions = Optional[Q]
Link = Optional[str]
Actor = Model
Target = Optional[Model]
ActionObject = Optional[Model]
Data = Optional[JSONField]
Description = Optional[str]
96 changes: 53 additions & 43 deletions django_notification/repository/queryset/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,21 @@

from django.contrib.auth.models import Group
from django.db import transaction
from django.db.models import JSONField, Model, Q, QuerySet, Subquery
from django.db.models import Model, Q, QuerySet, Subquery
from rest_framework.generics import get_object_or_404

from django_notification.constants.qs_types import (
ActionObject,
Actor,
Data,
Description,
Groups,
Link,
OptConditions,
Recipient,
Recipients,
Target,
)
from django_notification.models.deleted_notification import DeletedNotification
from django_notification.models.notification_seen import NotificationSeen
from django_notification.utils.user_model import UserModel
Expand All @@ -18,9 +30,7 @@ def with_related(self) -> QuerySet:
"recipient", "group", "group__permissions", "seen_by"
)

def _get_deleted_notifications(
self, deleted_by: Optional[UserModel] = None
) -> QuerySet:
def _get_deleted_notifications(self, deleted_by: Recipient = None) -> QuerySet:
"""Retrieve deleted notifications optionally filtered by user who
delete the notification."""
queryset = DeletedNotification.objects.values("notification")
Expand All @@ -30,9 +40,9 @@ def _get_deleted_notifications(

def _get_notifications_queryset(
self,
exclude_deleted_by: Optional[UserModel] = None,
display_detail: Optional[bool] = False,
conditions: Optional[Q] = None,
exclude_deleted_by: Recipient = None,
display_detail: bool = False,
conditions: OptConditions = None,
) -> Union[QuerySet, Dict]:
"""Return a queryset of notifications based on the given conditions.

Expand Down Expand Up @@ -69,9 +79,9 @@ def _get_notifications_queryset(

def all_notifications(
self,
recipients: Optional[Union[UserModel, QuerySet, List[UserModel]]] = None,
groups: Optional[Union[Group, QuerySet, List[Group]]] = None,
display_detail: Optional[bool] = False,
recipients: Recipients = None,
groups: Groups = None,
display_detail: bool = False,
) -> QuerySet:
"""Return all notifications excluding those that have been deleted.

Expand Down Expand Up @@ -104,11 +114,11 @@ def all_notifications(

def sent(
self,
recipients: Optional[Union[UserModel, QuerySet, List[UserModel]]] = None,
exclude_deleted_by: Optional[UserModel] = None,
groups: Optional[Union[Group, QuerySet, List[Group]]] = None,
display_detail: Optional[bool] = False,
conditions: Optional[Q] = Q(),
recipients: Recipients = None,
exclude_deleted_by: Recipient = None,
groups: Groups = None,
display_detail: bool = False,
conditions: Q = Q(),
) -> QuerySet:
"""Return all sent notifications.

Expand Down Expand Up @@ -151,11 +161,11 @@ def sent(

def unsent(
self,
recipients: Optional[Union[UserModel, QuerySet, List[UserModel]]] = None,
exclude_deleted_by: Optional[UserModel] = None,
groups: Optional[Union[Group, QuerySet, List[Group]]] = None,
display_detail: Optional[bool] = False,
conditions: Optional[Q] = Q(),
recipients: Recipients = None,
exclude_deleted_by: Recipient = None,
groups: Groups = None,
display_detail: bool = False,
conditions: Q = Q(),
) -> QuerySet:
"""Return all unsent notifications.

Expand Down Expand Up @@ -198,10 +208,10 @@ def unsent(
def seen(
self,
seen_by: UserModel,
recipients: Optional[Union[UserModel, QuerySet, List[UserModel]]] = None,
groups: Optional[Union[Group, QuerySet, List[Group]]] = None,
display_detail: Optional[bool] = False,
conditions: Optional[Q] = Q(),
recipients: Recipients = None,
groups: Groups = None,
display_detail: bool = False,
conditions: Q = Q(),
) -> QuerySet:
"""Return all seen notifications by the given user."""
conditions &= Q(seen_by=seen_by)
Expand All @@ -216,10 +226,10 @@ def seen(
def unseen(
self,
unseen_by: UserModel,
recipients: Optional[Union[UserModel, QuerySet, List[UserModel]]] = None,
groups: Optional[Union[Group, QuerySet, List[Group]]] = None,
display_detail: Optional[bool] = False,
conditions: Optional[Q] = Q(),
recipients: Recipients = None,
groups: Groups = None,
display_detail: bool = False,
conditions: Q = Q(),
) -> QuerySet:
"""Return notifications that the given user has not seen."""
return self.sent(
Expand Down Expand Up @@ -251,10 +261,10 @@ def mark_all_as_seen(self, user: UserModel) -> int:
NotificationSeen.objects.bulk_create(notifications_to_mark)
return notifications.count()

def mark_as_sent(
def mark_all_as_sent(
self,
recipients: Optional[Union[UserModel, QuerySet, List[UserModel]]] = None,
groups: Optional[Union[Group, QuerySet, List[Group]]] = None,
recipients: Recipients = None,
groups: Groups = None,
) -> int:
"""Mark notifications as sent.

Expand All @@ -270,7 +280,7 @@ def mark_as_sent(
recipients=recipients, groups=groups, display_detail=True
).update(is_sent=True)

def deleted(self, deleted_by: Optional[UserModel] = None) -> QuerySet:
def deleted(self, deleted_by: Recipient = None) -> QuerySet:
"""Return all deleted notifications optionally filtered by the user who
delete it."""

Expand Down Expand Up @@ -304,17 +314,17 @@ def clear_all(self, user: UserModel) -> None:
def create_notification(
self,
verb: str,
actor: Model,
description: Optional[str] = None,
recipients: Optional[Union[UserModel, QuerySet, List[UserModel]]] = None,
groups: Optional[Union[Group, QuerySet, List[Group]]] = None,
status: Optional[str] = "INFO",
actor: Actor,
description: Description = None,
recipients: Recipients = None,
groups: Groups = None,
status: str = "INFO",
public: bool = True,
target: Optional[Model] = None,
action_object: Optional[Model] = None,
link: Optional[str] = None,
target: Target = None,
action_object: ActionObject = None,
link: Link = None,
is_sent: bool = False,
data: Optional[Dict] = None,
data: Data = None,
):
"""Create a new notification.

Expand Down Expand Up @@ -380,7 +390,7 @@ def update_notification(
notification_id: int,
is_sent: Optional[bool] = None,
public: Optional[bool] = None,
data: Optional[JSONField] = None,
data: Data = None,
):
"""Update the status of a notification selectively.

Expand Down Expand Up @@ -415,7 +425,7 @@ def update_notification(
def delete_notification(
self,
notification_id: int,
recipient: Optional[UserModel] = None,
recipient: Recipient = None,
soft_delete: bool = True,
) -> None:
"""Delete a notification.
Expand Down
2 changes: 1 addition & 1 deletion django_notification/tests/repository/test_queryset.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def test_mark_as_sent(self, notifications: List[Notification]) -> None:
-------
The `mark_as_sent` method is successfully called. (Placeholder assertion)
"""
Notification.queryset.mark_as_sent()
Notification.queryset.mark_all_as_sent()
assert True

def test_deleted(
Expand Down