web: add UI for notification triggers
This commit is contained in:
		| @ -5,6 +5,7 @@ from authentik.admin.views import ( | ||||
|     applications, | ||||
|     certificate_key_pair, | ||||
|     events_notifications_transports, | ||||
|     events_notifications_triggers, | ||||
|     flows, | ||||
|     groups, | ||||
|     outposts, | ||||
| @ -369,4 +370,20 @@ urlpatterns = [ | ||||
|         events_notifications_transports.NotificationTransportDeleteView.as_view(), | ||||
|         name="notification-transport-delete", | ||||
|     ), | ||||
|     # Event Notification Triggers | ||||
|     path( | ||||
|         "events/triggers/create/", | ||||
|         events_notifications_triggers.NotificationTriggerCreateView.as_view(), | ||||
|         name="notification-trigger-create", | ||||
|     ), | ||||
|     path( | ||||
|         "events/triggers/<uuid:pk>/update/", | ||||
|         events_notifications_triggers.NotificationTriggerUpdateView.as_view(), | ||||
|         name="notification-trigger-update", | ||||
|     ), | ||||
|     path( | ||||
|         "events/triggers/<uuid:pk>/delete/", | ||||
|         events_notifications_triggers.NotificationTriggerDeleteView.as_view(), | ||||
|         name="notification-trigger-delete", | ||||
|     ), | ||||
| ] | ||||
|  | ||||
							
								
								
									
										64
									
								
								authentik/admin/views/events_notifications_triggers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								authentik/admin/views/events_notifications_triggers.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| """authentik NotificationTrigger administration""" | ||||
| from django.contrib.auth.mixins import LoginRequiredMixin | ||||
| from django.contrib.auth.mixins import ( | ||||
|     PermissionRequiredMixin as DjangoPermissionRequiredMixin, | ||||
| ) | ||||
| from django.contrib.messages.views import SuccessMessageMixin | ||||
| from django.urls import reverse_lazy | ||||
| from django.utils.translation import gettext as _ | ||||
| from django.views.generic import UpdateView | ||||
| from guardian.mixins import PermissionRequiredMixin | ||||
|  | ||||
| from authentik.admin.views.utils import BackSuccessUrlMixin, DeleteMessageView | ||||
| from authentik.events.forms import NotificationTriggerForm | ||||
| from authentik.events.models import NotificationTrigger | ||||
| from authentik.lib.views import CreateAssignPermView | ||||
|  | ||||
|  | ||||
| class NotificationTriggerCreateView( | ||||
|     SuccessMessageMixin, | ||||
|     BackSuccessUrlMixin, | ||||
|     LoginRequiredMixin, | ||||
|     DjangoPermissionRequiredMixin, | ||||
|     CreateAssignPermView, | ||||
| ): | ||||
|     """Create new NotificationTrigger""" | ||||
|  | ||||
|     model = NotificationTrigger | ||||
|     form_class = NotificationTriggerForm | ||||
|     permission_required = "authentik_events.add_notificationtrigger" | ||||
|  | ||||
|     template_name = "generic/create.html" | ||||
|     success_url = reverse_lazy("authentik_core:shell") | ||||
|     success_message = _("Successfully created Notification Trigger") | ||||
|  | ||||
|  | ||||
| class NotificationTriggerUpdateView( | ||||
|     SuccessMessageMixin, | ||||
|     BackSuccessUrlMixin, | ||||
|     LoginRequiredMixin, | ||||
|     PermissionRequiredMixin, | ||||
|     UpdateView, | ||||
| ): | ||||
|     """Update application""" | ||||
|  | ||||
|     model = NotificationTrigger | ||||
|     form_class = NotificationTriggerForm | ||||
|     permission_required = "authentik_events.change_notificationtrigger" | ||||
|  | ||||
|     template_name = "generic/update.html" | ||||
|     success_url = reverse_lazy("authentik_core:shell") | ||||
|     success_message = _("Successfully updated Notification Trigger") | ||||
|  | ||||
|  | ||||
| class NotificationTriggerDeleteView( | ||||
|     LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageView | ||||
| ): | ||||
|     """Delete application""" | ||||
|  | ||||
|     model = NotificationTrigger | ||||
|     permission_required = "authentik_events.delete_notificationtrigger" | ||||
|  | ||||
|     template_name = "generic/delete.html" | ||||
|     success_url = reverse_lazy("authentik_core:shell") | ||||
|     success_message = _("Successfully deleted Notification Trigger") | ||||
| @ -16,6 +16,7 @@ class NotificationTriggerSerializer(ModelSerializer): | ||||
|             "name", | ||||
|             "transports", | ||||
|             "severity", | ||||
|             "group", | ||||
|         ] | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| from django import forms | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
|  | ||||
| from authentik.events.models import NotificationTransport | ||||
| from authentik.events.models import NotificationTransport, NotificationTrigger | ||||
|  | ||||
|  | ||||
| class NotificationTransportForm(forms.ModelForm): | ||||
| @ -25,8 +25,23 @@ class NotificationTransportForm(forms.ModelForm): | ||||
|         } | ||||
|         help_texts = { | ||||
|             "webhook_url": _( | ||||
|                 ( | ||||
|                     "Only required when the Generic or Slack Webhook is used." | ||||
|                 ) | ||||
|                 ("Only required when the Generic or Slack Webhook is used.") | ||||
|             ), | ||||
|         } | ||||
|  | ||||
|  | ||||
| class NotificationTriggerForm(forms.ModelForm): | ||||
|     """NotificationTrigger Form""" | ||||
|  | ||||
|     class Meta: | ||||
|  | ||||
|         model = NotificationTrigger | ||||
|         fields = [ | ||||
|             "name", | ||||
|             "transports", | ||||
|             "severity", | ||||
|             "group", | ||||
|         ] | ||||
|         widgets = { | ||||
|             "name": forms.TextInput(), | ||||
|         } | ||||
|  | ||||
| @ -7720,6 +7720,13 @@ definitions: | ||||
|           - notice | ||||
|           - warning | ||||
|           - alert | ||||
|       group: | ||||
|         title: Group | ||||
|         description: Define which group of users this notification should be sent | ||||
|           and shown to. If left empty, Notification won't ben sent. | ||||
|         type: string | ||||
|         format: uuid | ||||
|         x-nullable: true | ||||
|   Stage: | ||||
|     title: Stage obj | ||||
|     description: Stage Serializer | ||||
|  | ||||
							
								
								
									
										25
									
								
								web/src/api/EventTriggers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								web/src/api/EventTriggers.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| import { DefaultClient, QueryArguments, PBResponse } from "./Client"; | ||||
|  | ||||
| export class Trigger { | ||||
|     pk: string; | ||||
|     name: string; | ||||
|     transports: string[]; | ||||
|     severity: string; | ||||
|     group?: string; | ||||
|  | ||||
|     constructor() { | ||||
|         throw Error(); | ||||
|     } | ||||
|  | ||||
|     static get(pk: string): Promise<Trigger> { | ||||
|         return DefaultClient.fetch<Trigger>(["events", "triggers", pk]); | ||||
|     } | ||||
|  | ||||
|     static list(filter?: QueryArguments): Promise<PBResponse<Trigger>> { | ||||
|         return DefaultClient.fetch<PBResponse<Trigger>>(["events", "triggers"], filter); | ||||
|     } | ||||
|  | ||||
|     static adminUrl(rest: string): string { | ||||
|         return `/administration/events/triggers/${rest}`; | ||||
|     } | ||||
| } | ||||
| @ -44,7 +44,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> { | ||||
|                     Edit | ||||
|                 </ak-spinner-button> | ||||
|                 <div slot="modal"></div> | ||||
|             </ak-modal-button> | ||||
|             </ak-modal-button>  | ||||
|             <ak-modal-button href="${PolicyBinding.adminUrl(`${item.pk}/delete/`)}"> | ||||
|                 <ak-spinner-button slot="trigger" class="pf-m-danger"> | ||||
|                     Delete | ||||
|  | ||||
| @ -14,7 +14,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [ | ||||
|     }), | ||||
|     new SidebarItem("Events").children( | ||||
|         new SidebarItem("Log", "/events/log"), | ||||
|         new SidebarItem("Notification Triggers", "/administration/tasks/"), | ||||
|         new SidebarItem("Notification Triggers", "/events/triggers"), | ||||
|         new SidebarItem("Notification Transports", "/events/transports"), | ||||
|     ).when((): Promise<boolean> => { | ||||
|         return User.me().then(u => u.is_superuser); | ||||
|  | ||||
| @ -3,6 +3,7 @@ import { customElement, html, property, TemplateResult } from "lit-element"; | ||||
| import { DefaultClient, PBResponse } from "../../api/Client"; | ||||
| import { TablePage } from "../../elements/table/TablePage"; | ||||
|  | ||||
| import "../../elements/buttons/ActionButton"; | ||||
| import "../../elements/buttons/ModalButton"; | ||||
| import "../../elements/buttons/SpinnerButton"; | ||||
| import { TableColumn } from "../../elements/table/Table"; | ||||
|  | ||||
							
								
								
									
										94
									
								
								web/src/pages/events/TriggerListPage.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								web/src/pages/events/TriggerListPage.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| import { gettext } from "django"; | ||||
| import { customElement, html, property, TemplateResult } from "lit-element"; | ||||
| import { PBResponse } from "../../api/Client"; | ||||
| import { TablePage } from "../../elements/table/TablePage"; | ||||
|  | ||||
| import "../../elements/policies/BoundPoliciesList"; | ||||
| import "../../elements/buttons/ModalButton"; | ||||
| import "../../elements/buttons/SpinnerButton"; | ||||
| import { TableColumn } from "../../elements/table/Table"; | ||||
| import { Trigger } from "../../api/EventTriggers"; | ||||
|  | ||||
| @customElement("ak-event-trigger-list") | ||||
| export class TriggerListPage extends TablePage<Trigger> { | ||||
|     expandable = true; | ||||
|  | ||||
|     searchEnabled(): boolean { | ||||
|         return true; | ||||
|     } | ||||
|     pageTitle(): string { | ||||
|         return gettext("Notification Triggers"); | ||||
|     } | ||||
|     pageDescription(): string { | ||||
|         return gettext("Send notifications on whenever a specific Event is created and matched by policies."); | ||||
|     } | ||||
|     pageIcon(): string { | ||||
|         return gettext("pf-icon pf-icon-attention-bell"); | ||||
|     } | ||||
|  | ||||
|     @property() | ||||
|     order = "name"; | ||||
|  | ||||
|     apiEndpoint(page: number): Promise<PBResponse<Trigger>> { | ||||
|         return Trigger.list({ | ||||
|             ordering: this.order, | ||||
|             page: page, | ||||
|             search: this.search || "", | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     columns(): TableColumn[] { | ||||
|         return [ | ||||
|             new TableColumn("Name", "name"), | ||||
|             new TableColumn("Severity", "severity"), | ||||
|             new TableColumn("Sent to group", "group"), | ||||
|             new TableColumn(""), | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     row(item: Trigger): TemplateResult[] { | ||||
|         return [ | ||||
|             html`${item.name}`, | ||||
|             html`${item.severity}`, | ||||
|             html`${item.group || gettext("None (trigger disabled)")}`, | ||||
|             html` | ||||
|             <ak-modal-button href="${Trigger.adminUrl(`${item.pk}/update/`)}"> | ||||
|                 <ak-spinner-button slot="trigger" class="pf-m-secondary"> | ||||
|                     ${gettext("Edit")} | ||||
|                 </ak-spinner-button> | ||||
|                 <div slot="modal"></div> | ||||
|             </ak-modal-button>  | ||||
|             <ak-modal-button href="${Trigger.adminUrl(`${item.pk}/delete/`)}"> | ||||
|                 <ak-spinner-button slot="trigger" class="pf-m-danger"> | ||||
|                     ${gettext("Delete")} | ||||
|                 </ak-spinner-button> | ||||
|                 <div slot="modal"></div> | ||||
|             </ak-modal-button> | ||||
|             `, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     renderToolbar(): TemplateResult { | ||||
|         return html` | ||||
|         <ak-modal-button href=${Trigger.adminUrl("create/")}> | ||||
|             <ak-spinner-button slot="trigger" class="pf-m-primary"> | ||||
|                 ${gettext("Create")} | ||||
|             </ak-spinner-button> | ||||
|             <div slot="modal"></div> | ||||
|         </ak-modal-button> | ||||
|         ${super.renderToolbar()} | ||||
|         `; | ||||
|     } | ||||
|  | ||||
|     renderExpanded(item: Trigger): TemplateResult { | ||||
|         return html` | ||||
|         <td role="cell" colspan="4"> | ||||
|             <div class="pf-c-table__expandable-row-content"> | ||||
|                 <ak-bound-policies-list .target=${item.pk}> | ||||
|                 </ak-bound-policies-list> | ||||
|             </div> | ||||
|         </td> | ||||
|         <td></td> | ||||
|         <td></td>`; | ||||
|     } | ||||
| } | ||||
| @ -9,6 +9,7 @@ import "./pages/sources/SourceViewPage"; | ||||
| import "./pages/flows/FlowViewPage"; | ||||
| import "./pages/events/EventListPage"; | ||||
| import "./pages/events/TransportListPage"; | ||||
| import "./pages/events/TriggerListPage"; | ||||
|  | ||||
| export const ROUTES: Route[] = [ | ||||
|     // Prevent infinite Shell loops | ||||
| @ -28,4 +29,5 @@ export const ROUTES: Route[] = [ | ||||
|     }), | ||||
|     new Route(new RegExp("^/events/log$"), html`<ak-event-list></ak-event-list>`), | ||||
|     new Route(new RegExp("^/events/transports$"), html`<ak-event-transport-list></ak-event-transport-list>`), | ||||
|     new Route(new RegExp("^/events/triggers$"), html`<ak-event-trigger-list></ak-event-trigger-list>`), | ||||
| ]; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer