diff --git a/authentik/events/api/notification.py b/authentik/events/api/notification.py index 2162e021f..17792e8af 100644 --- a/authentik/events/api/notification.py +++ b/authentik/events/api/notification.py @@ -1,8 +1,13 @@ """Notification API Views""" from django_filters.rest_framework import DjangoFilterBackend +from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import OpenApiResponse, extend_schema from rest_framework import mixins +from rest_framework.decorators import action from rest_framework.fields import ReadOnlyField from rest_framework.filters import OrderingFilter, SearchFilter +from rest_framework.request import Request +from rest_framework.response import Response from rest_framework.serializers import ModelSerializer from rest_framework.viewsets import GenericViewSet @@ -53,3 +58,18 @@ class NotificationViewSet( ] permission_classes = [OwnerPermissions] filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] + + @extend_schema( + request=OpenApiTypes.NONE, + responses={ + 204: OpenApiResponse(description="Marked tasks as read successfully."), + }, + ) + @action(detail=False, methods=["post"]) + def mark_all_seen(self, request: Request) -> Response: + """Mark all the user's notifications as seen""" + notifications = Notification.objects.filter(user=request.user) + for notification in notifications: + notification.seen = True + Notification.objects.bulk_update(notifications, ["seen"]) + return Response({}, status=204) diff --git a/authentik/events/tests/test_api.py b/authentik/events/tests/test_api.py index b7b4c15fc..e23bf1157 100644 --- a/authentik/events/tests/test_api.py +++ b/authentik/events/tests/test_api.py @@ -1,18 +1,19 @@ """Event API tests""" +from authentik.events.api.notification import NotificationSerializer from django.urls import reverse from rest_framework.test import APITestCase from authentik.core.models import User -from authentik.events.models import Event, EventAction +from authentik.events.models import Event, EventAction, Notification, NotificationSeverity class TestEventsAPI(APITestCase): """Test Event API""" def setUp(self) -> None: - user = User.objects.get(username="akadmin") - self.client.force_login(user) + self.user = User.objects.get(username="akadmin") + self.client.force_login(self.user) def test_top_n(self): """Test top_per_user""" @@ -30,3 +31,14 @@ class TestEventsAPI(APITestCase): reverse("authentik_api:event-actions"), ) self.assertEqual(response.status_code, 200) + + def test_notifications(self): + """Test notifications""" + notification = Notification.objects.create( + user=self.user, severity=NotificationSeverity.ALERT, body="", seen=False + ) + self.client.post( + reverse("authentik_api:notification-mark-all-seen"), + ) + notification.refresh_from_db() + self.assertTrue(notification.seen) diff --git a/schema.yml b/schema.yml index a626a1bcd..eb0186b91 100644 --- a/schema.yml +++ b/schema.yml @@ -3903,6 +3903,21 @@ paths: $ref: '#/components/schemas/ValidationError' '403': $ref: '#/components/schemas/GenericError' + /events/notifications/mark_all_seen/: + post: + operationId: events_notifications_mark_all_seen_create + description: Mark all the user's notifications as seen + tags: + - events + security: + - authentik: [] + responses: + '204': + description: Marked tasks as read successfully. + '400': + $ref: '#/components/schemas/ValidationError' + '403': + $ref: '#/components/schemas/GenericError' /events/rules/: get: operationId: events_rules_list diff --git a/web/src/elements/notifications/NotificationDrawer.ts b/web/src/elements/notifications/NotificationDrawer.ts index c68e281e0..8d25a1af0 100644 --- a/web/src/elements/notifications/NotificationDrawer.ts +++ b/web/src/elements/notifications/NotificationDrawer.ts @@ -19,6 +19,8 @@ import AKGlobal from "../../authentik.css"; import PFContent from "@patternfly/patternfly/components/Content/content.css"; import { EVENT_NOTIFICATION_DRAWER_TOGGLE } from "../../constants"; import { ActionToLabel } from "../../pages/events/utils"; +import { showMessage } from "../messages/MessageContainer"; +import { MessageLevel } from "../messages/Message"; @customElement("ak-notification-drawer") export class NotificationDrawer extends LitElement { @@ -31,6 +33,12 @@ export class NotificationDrawer extends LitElement { static get styles(): CSSResult[] { return [PFBase, PFButton, PFNotificationDrawer, PFContent, PFDropdown, AKGlobal].concat( css` + .pf-c-drawer__body { + height: 100%; + } + .pf-c-notification-drawer__body { + flex-grow: 1; + } .pf-c-notification-drawer__header { height: 114px; align-items: center; @@ -143,7 +151,7 @@ export class NotificationDrawer extends LitElement { }} class="pf-c-button pf-m-plain" type="button" - aria-label="Close" + aria-label=${t`Close`} > @@ -155,6 +163,25 @@ export class NotificationDrawer extends LitElement { ${this.notifications.results.map((n) => this.renderItem(n))} + `; } diff --git a/web/src/locales/en.po b/web/src/locales/en.po index de5b6cdb1..871e691ca 100644 --- a/web/src/locales/en.po +++ b/web/src/locales/en.po @@ -276,6 +276,7 @@ msgstr "Application(s)" #: src/interfaces/AdminInterface.ts #: src/pages/LibraryPage.ts #: src/pages/applications/ApplicationListPage.ts +#: src/pages/outposts/OutpostForm.ts msgid "Applications" msgstr "Applications" @@ -685,6 +686,11 @@ msgstr "Clear Flow cache" msgid "Clear Policy cache" msgstr "Clear Policy cache" +#: src/elements/notifications/NotificationDrawer.ts +#: src/elements/notifications/NotificationDrawer.ts +msgid "Clear all" +msgstr "Clear all" + #: src/pages/flows/FlowForm.ts msgid "Clear background image" msgstr "Clear background image" @@ -730,6 +736,7 @@ msgstr "Client Secret" msgid "Client type" msgstr "Client type" +#: src/elements/notifications/NotificationDrawer.ts #: src/pages/outposts/OutpostDeploymentModal.ts #: src/pages/users/UserListPage.ts msgid "Close" @@ -3186,7 +3193,6 @@ msgid "Provider(s)" msgstr "Provider(s)" #: src/interfaces/AdminInterface.ts -#: src/pages/outposts/OutpostForm.ts #: src/pages/outposts/OutpostListPage.ts #: src/pages/providers/ProviderListPage.ts msgid "Providers" @@ -3910,6 +3916,10 @@ msgstr "Successful" msgid "Successfully cleared flow cache" msgstr "Successfully cleared flow cache" +#: src/elements/notifications/NotificationDrawer.ts +msgid "Successfully cleared notifications" +msgstr "Successfully cleared notifications" + #: src/pages/policies/PolicyListPage.ts msgid "Successfully cleared policy cache" msgstr "Successfully cleared policy cache" diff --git a/web/src/locales/pseudo-LOCALE.po b/web/src/locales/pseudo-LOCALE.po index bbf0388ee..9b834f3f0 100644 --- a/web/src/locales/pseudo-LOCALE.po +++ b/web/src/locales/pseudo-LOCALE.po @@ -276,6 +276,7 @@ msgstr "" #: src/interfaces/AdminInterface.ts #: src/pages/LibraryPage.ts #: src/pages/applications/ApplicationListPage.ts +#: src/pages/outposts/OutpostForm.ts msgid "Applications" msgstr "" @@ -679,6 +680,11 @@ msgstr "" msgid "Clear Policy cache" msgstr "" +#: src/elements/notifications/NotificationDrawer.ts +#: src/elements/notifications/NotificationDrawer.ts +msgid "Clear all" +msgstr "" + #: src/pages/flows/FlowForm.ts msgid "Clear background image" msgstr "" @@ -724,6 +730,7 @@ msgstr "" msgid "Client type" msgstr "" +#: src/elements/notifications/NotificationDrawer.ts #: src/pages/outposts/OutpostDeploymentModal.ts #: src/pages/users/UserListPage.ts msgid "Close" @@ -3178,7 +3185,6 @@ msgid "Provider(s)" msgstr "" #: src/interfaces/AdminInterface.ts -#: src/pages/outposts/OutpostForm.ts #: src/pages/outposts/OutpostListPage.ts #: src/pages/providers/ProviderListPage.ts msgid "Providers" @@ -3902,6 +3908,10 @@ msgstr "" msgid "Successfully cleared flow cache" msgstr "" +#: src/elements/notifications/NotificationDrawer.ts +msgid "Successfully cleared notifications" +msgstr "" + #: src/pages/policies/PolicyListPage.ts msgid "Successfully cleared policy cache" msgstr ""