From 38bd05867d295fc6b1eaa3ba127cc2104790d8a4 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 19 Feb 2021 17:05:02 +0100 Subject: [PATCH] web: migrate Policy list to web --- .../templates/administration/policy/list.html | 151 ------------------ authentik/admin/urls.py | 1 - authentik/admin/views/policies.py | 28 +--- web/src/api/Policies.ts | 17 +- web/src/interfaces/AdminInterface.ts | 2 +- web/src/pages/policies/PolicyListPage.ts | 108 +++++++++++++ web/src/routes.ts | 22 +-- 7 files changed, 139 insertions(+), 190 deletions(-) delete mode 100644 authentik/admin/templates/administration/policy/list.html create mode 100644 web/src/pages/policies/PolicyListPage.ts diff --git a/authentik/admin/templates/administration/policy/list.html b/authentik/admin/templates/administration/policy/list.html deleted file mode 100644 index 3b4d35a9a..000000000 --- a/authentik/admin/templates/administration/policy/list.html +++ /dev/null @@ -1,151 +0,0 @@ -{% extends "administration/base.html" %} - -{% load i18n %} -{% load authentik_utils %} - -{% block content %} -
-
-

- - {% trans 'Policies' %} -

-

{% trans "Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Stages." %}

-
-
-
-
- {% if object_list %} -
-
- {% include 'partials/toolbar_search.html' %} -
- - - - - -
- {% include 'partials/pagination.html' %} -
-
- - - - - - - - - - {% for policy in object_list %} - - - - - - {% endfor %} - -
{% trans 'Name' %}{% trans 'Type' %}
-
-
{{ policy.name }}
- {% if not policy.bindings.exists and not policy.promptstage_set.exists %} - - {% trans 'Warning: Policy is not assigned.' %} - {% else %} - - {% blocktrans with object_count=policy.bindings.all|length %}Assigned to {{ object_count }} objects.{% endblocktrans %} - {% endif %} -
-
- - {{ policy|verbose_name }} - - - - - {% trans 'Edit' %} - -
-
- - - {% trans 'Test' %} - -
-
- - - {% trans 'Delete' %} - -
-
-
-
- {% include 'partials/pagination.html' %} -
- {% else %} -
-
- {% include 'partials/toolbar_search.html' %} -
-
-
-
- -

- {% trans 'No Policies.' %} -

-
- {% if request.GET.search != "" %} - {% trans "Your search query doesn't match any policies." %} - {% else %} - {% trans 'Currently no policies exist. Click the button below to create one.' %} - {% endif %} -
- - - - -
-
- {% endif %} -
-
-{% endblock %} diff --git a/authentik/admin/urls.py b/authentik/admin/urls.py index c35cdbc90..b0f0aece6 100644 --- a/authentik/admin/urls.py +++ b/authentik/admin/urls.py @@ -73,7 +73,6 @@ urlpatterns = [ name="source-delete", ), # Policies - path("policies/", policies.PolicyListView.as_view(), name="policies"), path("policies/create/", policies.PolicyCreateView.as_view(), name="policy-create"), path( "policies//update/", diff --git a/authentik/admin/views/policies.py b/authentik/admin/views/policies.py index 3a999f3cc..d4491edf2 100644 --- a/authentik/admin/views/policies.py +++ b/authentik/admin/views/policies.py @@ -7,42 +7,22 @@ from django.contrib.auth.mixins import ( ) from django.contrib.messages.views import SuccessMessageMixin from django.http import HttpResponse -from django.urls import reverse_lazy from django.utils.translation import gettext as _ from django.views.generic import FormView from django.views.generic.detail import DetailView -from guardian.mixins import PermissionListMixin, PermissionRequiredMixin +from guardian.mixins import PermissionRequiredMixin from authentik.admin.forms.policies import PolicyTestForm from authentik.admin.views.utils import ( BackSuccessUrlMixin, DeleteMessageView, InheritanceCreateView, - InheritanceListView, InheritanceUpdateView, - SearchListMixin, - UserPaginateListMixin, ) from authentik.policies.models import Policy, PolicyBinding from authentik.policies.process import PolicyProcess, PolicyRequest -class PolicyListView( - LoginRequiredMixin, - PermissionListMixin, - UserPaginateListMixin, - SearchListMixin, - InheritanceListView, -): - """Show list of all policies""" - - model = Policy - permission_required = "authentik_policies.view_policy" - ordering = "name" - template_name = "administration/policy/list.html" - search_fields = ["name"] - - class PolicyCreateView( SuccessMessageMixin, BackSuccessUrlMixin, @@ -56,7 +36,7 @@ class PolicyCreateView( permission_required = "authentik_policies.add_policy" template_name = "generic/create.html" - success_url = reverse_lazy("authentik_admin:policies") + success_url = "/" success_message = _("Successfully created Policy") @@ -73,7 +53,7 @@ class PolicyUpdateView( permission_required = "authentik_policies.change_policy" template_name = "generic/update.html" - success_url = reverse_lazy("authentik_admin:policies") + success_url = "/" success_message = _("Successfully updated Policy") @@ -84,7 +64,7 @@ class PolicyDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessag permission_required = "authentik_policies.delete_policy" template_name = "generic/delete.html" - success_url = reverse_lazy("authentik_admin:policies") + success_url = "/" success_message = _("Successfully deleted Policy") diff --git a/web/src/api/Policies.ts b/web/src/api/Policies.ts index 120c7f839..d720bd559 100644 --- a/web/src/api/Policies.ts +++ b/web/src/api/Policies.ts @@ -1,15 +1,18 @@ import { DefaultClient, BaseInheritanceModel, AKResponse, QueryArguments } from "./Client"; +import { TypeCreate } from "./Providers"; export class Policy implements BaseInheritanceModel { pk: string; name: string; + execution_logging: boolean; + object_type: string; + verbose_name: string; + verbose_name_plural: string; + bound_to: number; constructor() { throw Error(); } - object_type: string; - verbose_name: string; - verbose_name_plural: string; static get(pk: string): Promise { return DefaultClient.fetch(["policies", "all", pk]); @@ -24,4 +27,12 @@ export class Policy implements BaseInheritanceModel { return r.count; }); } + + static getTypes(): Promise { + return DefaultClient.fetch(["policies", "all", "types"]); + } + + static adminUrl(rest: string): string { + return `/administration/policies/${rest}`; + } } diff --git a/web/src/interfaces/AdminInterface.ts b/web/src/interfaces/AdminInterface.ts index 57f3e3329..a34ff9170 100644 --- a/web/src/interfaces/AdminInterface.ts +++ b/web/src/interfaces/AdminInterface.ts @@ -33,7 +33,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [ return User.me().then(u => u.is_superuser); }), new SidebarItem("Customisation").children( - new SidebarItem("Policies", "/administration/policies/"), + new SidebarItem("Policies", "/policies"), new SidebarItem("Property Mappings", "/property-mappings"), ).when((): Promise => { return User.me().then(u => u.is_superuser); diff --git a/web/src/pages/policies/PolicyListPage.ts b/web/src/pages/policies/PolicyListPage.ts new file mode 100644 index 000000000..503e2c660 --- /dev/null +++ b/web/src/pages/policies/PolicyListPage.ts @@ -0,0 +1,108 @@ +import { gettext } from "django"; +import { customElement, html, property, TemplateResult } from "lit-element"; +import { AKResponse } from "../../api/Client"; +import { TablePage } from "../../elements/table/TablePage"; + +import "../../elements/buttons/ModalButton"; +import "../../elements/buttons/Dropdown"; +import "../../elements/buttons/SpinnerButton"; +import { TableColumn } from "../../elements/table/Table"; +import { Policy } from "../../api/Policies"; +import { until } from "lit-html/directives/until"; + +@customElement("ak-policy-list") +export class PolicyListPage extends TablePage { + searchEnabled(): boolean { + return true; + } + pageTitle(): string { + return gettext("Policies"); + } + pageDescription(): string { + return gettext("Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Stages."); + } + pageIcon(): string { + return gettext("pf-icon pf-icon-infrastructure"); + } + + @property() + order = "name"; + + apiEndpoint(page: number): Promise> { + return Policy.list({ + ordering: this.order, + page: page, + search: this.search || "", + }); + } + + columns(): TableColumn[] { + return [ + new TableColumn("Name", "name"), + new TableColumn("Type"), + new TableColumn(""), + ]; + } + + row(item: Policy): TemplateResult[] { + return [ + html`
+
${item.name}
+ ${item.bound_to > 0 ? + html` + + ${gettext(`Assigned to ${item.bound_to} objects.`)} + `: + html` + ${gettext("Warning: Policy is not assigned.")}/small>`} +
`, + html`${item.verbose_name}`, + html` + + + ${gettext("Edit")} + +
+
+ + + ${gettext("Test")} + +
+
+ + + ${gettext("Delete")} + +
+
+ `, + ]; + } + + renderToolbar(): TemplateResult { + return html` + + + + + ${super.renderToolbar()}`; + } + +} diff --git a/web/src/routes.ts b/web/src/routes.ts index 778b7e4d1..63e114b96 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -1,23 +1,24 @@ import { html } from "lit-html"; import { Route, SLUG_REGEX, ID_REGEX, UUID_REGEX } from "./elements/router/Route"; -import "./pages/LibraryPage"; import "./pages/admin-overview/AdminOverviewPage"; import "./pages/applications/ApplicationListPage"; import "./pages/applications/ApplicationViewPage"; -import "./pages/sources/SourcesListPage"; -import "./pages/sources/SourceViewPage"; +import "./pages/crypto/CertificateKeyPairListPage"; +import "./pages/events/EventInfoPage"; +import "./pages/events/EventListPage"; +import "./pages/events/RuleListPage"; +import "./pages/events/TransportListPage"; import "./pages/flows/FlowListPage"; import "./pages/flows/FlowViewPage"; -import "./pages/events/EventListPage"; -import "./pages/events/EventInfoPage"; -import "./pages/events/TransportListPage"; -import "./pages/events/RuleListPage"; +import "./pages/LibraryPage"; +import "./pages/outposts/OutpostListPage"; +import "./pages/policies/PolicyListPage"; +import "./pages/property-mappings/PropertyMappingListPage"; import "./pages/providers/ProviderListPage"; import "./pages/providers/ProviderViewPage"; -import "./pages/property-mappings/PropertyMappingListPage"; -import "./pages/outposts/OutpostListPage"; -import "./pages/crypto/CertificateKeyPairListPage"; +import "./pages/sources/SourcesListPage"; +import "./pages/sources/SourceViewPage"; export const ROUTES: Route[] = [ // Prevent infinite Shell loops @@ -37,6 +38,7 @@ export const ROUTES: Route[] = [ new Route(new RegExp(`^/sources/(?${SLUG_REGEX})$`)).then((args) => { return html``; }), + new Route(new RegExp("^/policies$"), html``), new Route(new RegExp("^/flows$"), html``), new Route(new RegExp(`^/flows/(?${SLUG_REGEX})$`)).then((args) => { return html``;