-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
466 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# | ||
# Copyright (c) 2023-present Kaleidos INC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# | ||
# Copyright (c) 2023-present Kaleidos INC | ||
|
||
from typing import Any | ||
|
||
from taiga.base.db import admin | ||
from taiga.base.db.admin.http import HttpRequest | ||
from taiga.notifications.models import Notification | ||
|
||
|
||
@admin.register(Notification) | ||
class NotificationAdmin(admin.ModelAdmin[Notification]): | ||
list_display = ("id", "type", "owner", "created_at", "read_at") | ||
|
||
def has_change_permission(self, request: HttpRequest, obj: Any = None) -> bool: | ||
return False | ||
|
||
def has_add_permission(self, request: HttpRequest, obj: Any = None) -> bool: | ||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# | ||
# Copyright (c) 2023-present Kaleidos INC | ||
|
||
from taiga.base.api import AuthRequest | ||
from taiga.base.api.permissions import check_permissions | ||
from taiga.exceptions.api.errors import ERROR_403 | ||
from taiga.notifications import services as notifications_services | ||
from taiga.notifications.models import Notification | ||
from taiga.notifications.serializers import NotificationCountersSerializer, NotificationSerializer | ||
from taiga.permissions import IsAuthenticated | ||
from taiga.routers import routes | ||
|
||
LIST_MY_NOTIFICATIONS = IsAuthenticated() | ||
COUNT_MY_NOTIFICATIONS = IsAuthenticated() | ||
|
||
########################################################## | ||
# list notifications | ||
########################################################## | ||
|
||
|
||
@routes.notifications.get( | ||
"/my/notifications", | ||
name="my.notifications.list", | ||
summary="List all the user notifications", | ||
responses=ERROR_403, | ||
response_model=list[NotificationSerializer], | ||
) | ||
async def list_my_notifications(request: AuthRequest, is_read: bool | None = None) -> list[Notification]: | ||
""" | ||
List the notifications of the logged user. | ||
""" | ||
await check_permissions(permissions=LIST_MY_NOTIFICATIONS, user=request.user, obj=None) | ||
return await notifications_services.list_user_notifications(user=request.user, is_read=is_read) | ||
|
||
|
||
########################################################## | ||
# count notifications | ||
########################################################## | ||
|
||
|
||
@routes.notifications.get( | ||
"/my/notifications/count", | ||
name="my.notifications.count", | ||
summary="Get user notifications counters", | ||
responses=ERROR_403, | ||
response_model=NotificationCountersSerializer, | ||
) | ||
async def count_my_notifications(request: AuthRequest) -> dict[str, int]: | ||
""" | ||
List the notifications of the logged user. | ||
""" | ||
await check_permissions(permissions=COUNT_MY_NOTIFICATIONS, user=request.user, obj=None) | ||
return await notifications_services.count_user_notifications(user=request.user) |
25 changes: 25 additions & 0 deletions
25
python/apps/taiga/src/taiga/notifications/events/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# | ||
# Copyright (c) 2023-present Kaleidos INC | ||
|
||
from taiga.events import events_manager | ||
from taiga.notifications.events.content import CreateNotificationContent | ||
from taiga.notifications.models import Notification | ||
|
||
CREATE_NOTIFICATION = "notifications.create" | ||
|
||
|
||
async def emit_event_when_notifications_are_created( | ||
notifications: list[Notification], | ||
) -> None: | ||
for notification in notifications: | ||
await events_manager.publish_on_user_channel( | ||
user=notification.owner, | ||
type=CREATE_NOTIFICATION, | ||
content=CreateNotificationContent( | ||
notification=notification, | ||
), | ||
) |
13 changes: 13 additions & 0 deletions
13
python/apps/taiga/src/taiga/notifications/events/content.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# | ||
# Copyright (c) 2023-present Kaleidos INC | ||
|
||
from taiga.base.serializers import BaseModel | ||
from taiga.notifications.serializers import NotificationSerializer | ||
|
||
|
||
class CreateNotificationContent(BaseModel): | ||
notification: NotificationSerializer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# | ||
# Copyright (c) 2023-present Kaleidos INC | ||
|
||
from taiga.base.db import models | ||
from taiga.base.db.mixins import CreatedMetaInfoMixin | ||
|
||
####################################################################### | ||
# Base Notification | ||
###################################################################### | ||
|
||
|
||
class Notification(models.BaseModel, CreatedMetaInfoMixin): | ||
type = models.CharField( | ||
max_length=500, | ||
null=False, | ||
blank=False, | ||
verbose_name="type", | ||
) | ||
owner = models.ForeignKey( | ||
"users.User", | ||
null=False, | ||
blank=False, | ||
on_delete=models.CASCADE, | ||
related_name="notifications", | ||
verbose_name="owner", | ||
) | ||
read_at = models.DateTimeField( | ||
null=True, | ||
blank=True, | ||
verbose_name="read at", | ||
) | ||
content = models.JSONField( | ||
null=False, | ||
blank=False, | ||
default=dict, | ||
verbose_name="content", | ||
) | ||
|
||
class Meta: | ||
verbose_name = "notification" | ||
verbose_name_plural = "notifications" | ||
ordering = ["-created_at"] | ||
indexes = [ | ||
models.Index( | ||
fields=[ | ||
"owner", | ||
] | ||
), | ||
models.Index(fields=["owner", "read_at"]), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# | ||
# Copyright (c) 2023-present Kaleidos INC | ||
|
||
from collections.abc import Iterable | ||
from typing import Any, TypedDict | ||
|
||
from taiga.base.db.models import QuerySet | ||
from taiga.notifications.models import Notification | ||
from taiga.users.models import User | ||
|
||
########################################################## | ||
# filters and querysets | ||
########################################################## | ||
|
||
DEFAULT_QUERYSET = Notification.objects.select_related("created_by").all() | ||
|
||
|
||
class NotificationFilters(TypedDict, total=False): | ||
owner: User | ||
is_read: bool | ||
|
||
|
||
async def _apply_filters_to_queryset( | ||
qs: QuerySet[Notification], | ||
filters: NotificationFilters = {}, | ||
) -> QuerySet[Notification]: | ||
filter_data = dict(filters.copy()) | ||
|
||
if "is_read" in filter_data: | ||
is_read = filter_data.pop("is_read") | ||
filter_data["read_at__isnull"] = not is_read | ||
|
||
return qs.filter(**filter_data) | ||
|
||
|
||
########################################################## | ||
# create notifications | ||
########################################################## | ||
|
||
|
||
async def create_notifications( | ||
owners: Iterable[User], | ||
created_by: User, | ||
notification_type: str, | ||
content: dict[str, Any], | ||
) -> list[Notification]: | ||
notifications = [ | ||
Notification( | ||
owner=owner, | ||
created_by=created_by, | ||
type=notification_type, | ||
content=content, | ||
) | ||
for owner in owners | ||
] | ||
|
||
return await Notification.objects.abulk_create(notifications) | ||
|
||
|
||
########################################################## | ||
# list notifications | ||
########################################################## | ||
|
||
|
||
async def list_notifications( | ||
filters: NotificationFilters = {}, | ||
offset: int | None = None, | ||
limit: int | None = None, | ||
) -> list[Notification]: | ||
qs = await _apply_filters_to_queryset(qs=DEFAULT_QUERYSET, filters=filters) | ||
|
||
if limit is not None and offset is not None: | ||
limit += offset | ||
|
||
return [a async for a in qs[offset:limit]] | ||
|
||
|
||
########################################################## | ||
# misc | ||
########################################################## | ||
|
||
|
||
async def count_notifications( | ||
filters: NotificationFilters = {}, | ||
) -> int: | ||
qs = await _apply_filters_to_queryset(qs=DEFAULT_QUERYSET, filters=filters) | ||
|
||
return await qs.acount() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
# | ||
# Copyright (c) 2023-present Kaleidos INC | ||
|
||
from datetime import datetime | ||
from typing import Any | ||
|
||
from taiga.base.serializers import BaseModel | ||
from taiga.users.serializers.nested import UserNestedSerializer | ||
|
||
|
||
class NotificationSerializer(BaseModel): | ||
created_by: UserNestedSerializer | None | ||
created_at: datetime | ||
read_at: datetime | None | ||
content: dict[str, Any] | ||
|
||
class Config: | ||
orm_mode = True | ||
|
||
|
||
class NotificationCountersSerializer(BaseModel): | ||
read: int | ||
unread: int | ||
total: int |
Oops, something went wrong.