From 3124b0f39ce96f9e44ddd36d08340195eabecc80 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 31 Mar 2021 19:10:10 +0200 Subject: [PATCH] web/elements: add support for non-field errors Signed-off-by: Jens Langhammer --- authentik/policies/api/bindings.py | 11 ++++++++--- web/src/elements/forms/Form.ts | 29 ++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/authentik/policies/api/bindings.py b/authentik/policies/api/bindings.py index f00c1bb98..8d08bd5fd 100644 --- a/authentik/policies/api/bindings.py +++ b/authentik/policies/api/bindings.py @@ -1,7 +1,12 @@ """policy binding API Views""" from typing import OrderedDict + from django.core.exceptions import ObjectDoesNotExist -from rest_framework.serializers import ModelSerializer, PrimaryKeyRelatedField, ValidationError +from rest_framework.serializers import ( + ModelSerializer, + PrimaryKeyRelatedField, + ValidationError, +) from rest_framework.viewsets import ModelViewSet from structlog.stdlib import get_logger @@ -77,8 +82,7 @@ class PolicyBindingSerializer(ModelSerializer): def validate(self, data: OrderedDict) -> OrderedDict: """Check that either policy, group or user is set.""" - count = sum([bool(data["policy"]), bool( - data["group"]), bool(data["user"])]) + count = sum([bool(data["policy"]), bool(data["group"]), bool(data["user"])]) invalid = count > 1 empty = count < 1 if invalid: @@ -87,6 +91,7 @@ class PolicyBindingSerializer(ModelSerializer): raise ValidationError("One of 'policy', 'group' or 'user' must be set.") return data + class PolicyBindingViewSet(ModelViewSet): """PolicyBinding Viewset""" diff --git a/web/src/elements/forms/Form.ts b/web/src/elements/forms/Form.ts index 4596053fd..f7b77ea29 100644 --- a/web/src/elements/forms/Form.ts +++ b/web/src/elements/forms/Form.ts @@ -9,6 +9,7 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css"; import AKGlobal from "../../authentik.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; +import PFAlert from "@patternfly/patternfly/components/Alert/alert.css"; import { MessageLevel } from "../messages/Message"; import { IronFormElement } from "@polymer/iron-form/iron-form"; import { camelToSnake } from "../../utils"; @@ -31,8 +32,11 @@ export class Form extends LitElement { @property() send!: (data: T) => Promise; + @property({attribute: false}) + nonFieldErrors?: string[]; + static get styles(): CSSResult[] { - return [PFBase, PFCard, PFButton, PFForm, PFFormControl, AKGlobal, css` + return [PFBase, PFCard, PFButton, PFForm, PFAlert, PFFormControl, AKGlobal, css` select[multiple] { height: 15em; } @@ -116,6 +120,7 @@ export class Form extends LitElement { if (errorMessage instanceof Error) { throw errorMessage; } + // assign all input-related errors to their elements const elements: PaperInputElement[] = ironForm._getSubmittableElements(); elements.forEach((element) => { const elementName = element.name; @@ -125,6 +130,9 @@ export class Form extends LitElement { element.invalid = true; } }); + if ("non_field_errors" in errorMessage) { + this.nonFieldErrors = errorMessage["non_field_errors"]; + } throw new APIError(errorMessage); }); } @@ -136,6 +144,24 @@ export class Form extends LitElement { return html``; } + renderNonFieldErrors(): TemplateResult { + if (!this.nonFieldErrors) { + return html``; + } + return html`
+ ${this.nonFieldErrors.map(err => { + return html`
+
+ +
+

+ ${err} +

+
`; + })} +
`; + } + render(): TemplateResult { const rect = this.getBoundingClientRect(); if (rect.x + rect.y + rect.width + rect.height === 0) { @@ -143,6 +169,7 @@ export class Form extends LitElement { } return html` { this.submit(ev); }}> + ${this.renderNonFieldErrors()} ${this.renderForm()} `; }