Repository: Lazarus-org/dj-notification-api

Issue:
Missing types constant file for type annotations
## Overview
The `django_notification` package currently has type annotations embedded within its methods, which can lead to redundancy and decreased maintainability. Centralizing these types into a dedicated constants file will streamline the code and improve clarity.

## Problem
- Type annotations are scattered across various methods, making it difficult to track and manage.
- This approach can lead to inconsistencies if the same type needs to be modified in multiple locations.
- It hinders the ability to quickly reference and update types as needed.

## Suggested Solution
Create a dedicated file for type constants in the `django_notification` package, consolidating the existing type annotations. This file could include:
- `Recipient`: Optional user model for notifications.
- `Recipients`: Union type representing a single user, queryset, or list of users.
- `Groups`: Union type for groups.
- Additional types for conditions, links, actors, targets, action objects, data, and descriptions.

## Benefits
- Promotes a cleaner, more organized codebase.
- Enhances maintainability by reducing redundancy and potential for errors.
- Facilitates easier updates to types in a single location, improving overall development efficiency.


Discussion:

Patch:
diff --git a/django_notification/api/views/activity.py b/django_notification/api/views/activity.py
index dc99c66..f94b3e4 100644
--- a/django_notification/api/views/activity.py
+++ b/django_notification/api/views/activity.py
@@ -38,34 +38,38 @@ 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.
@@ -73,10 +77,12 @@ class ActivityViewSet(
       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.
diff --git a/django_notification/api/views/notification.py b/django_notification/api/views/notification.py
index 35cc949..5d44520 100644
--- a/django_notification/api/views/notification.py
+++ b/django_notification/api/views/notification.py
@@ -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:
@@ -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.
diff --git a/django_notification/constants/qs_types.py b/django_notification/constants/qs_types.py
new file mode 100644
index 0000000..a440647
--- /dev/null
+++ b/django_notification/constants/qs_types.py
@@ -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]
diff --git a/django_notification/repository/queryset/notification.py b/django_notification/repository/queryset/notification.py
index 170b888..17e5774 100644
--- a/django_notification/repository/queryset/notification.py
+++ b/django_notification/repository/queryset/notification.py
@@ -2,9 +2,21 @@ from typing import Dict, List, Optional, Union
 
 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
@@ -18,9 +30,7 @@ class NotificationQuerySet(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")
@@ -30,9 +40,9 @@ class NotificationQuerySet(QuerySet):
 
     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.
 
@@ -69,9 +79,9 @@ class NotificationQuerySet(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.
 
@@ -104,11 +114,11 @@ class NotificationQuerySet(QuerySet):
 
     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.
 
@@ -151,11 +161,11 @@ class NotificationQuerySet(QuerySet):
 
     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.
 
@@ -198,10 +208,10 @@ class NotificationQuerySet(QuerySet):
     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)
@@ -216,10 +226,10 @@ class NotificationQuerySet(QuerySet):
     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(
@@ -251,10 +261,10 @@ class NotificationQuerySet(QuerySet):
         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.
 
@@ -270,7 +280,7 @@ class NotificationQuerySet(QuerySet):
             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."""
 
@@ -304,17 +314,17 @@ class NotificationQuerySet(QuerySet):
     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.
 
@@ -380,7 +390,7 @@ class NotificationQuerySet(QuerySet):
         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.
 
@@ -415,7 +425,7 @@ class NotificationQuerySet(QuerySet):
     def delete_notification(
         self,
         notification_id: int,
-        recipient: Optional[UserModel] = None,
+        recipient: Recipient = None,
         soft_delete: bool = True,
     ) -> None:
         """Delete a notification.


Test patch:
diff --git a/django_notification/tests/repository/test_queryset.py b/django_notification/tests/repository/test_queryset.py
index 4754155..d6f0523 100644
--- a/django_notification/tests/repository/test_queryset.py
+++ b/django_notification/tests/repository/test_queryset.py
@@ -171,7 +171,7 @@ class TestNotificationQuerySet:
         -------
             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(