web/admin: migrate prompts to web
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
8a3b1ae29d
commit
cb0b5f7146
|
@ -10,7 +10,6 @@ from authentik.admin.views import (
|
||||||
sources,
|
sources,
|
||||||
stages,
|
stages,
|
||||||
stages_bindings,
|
stages_bindings,
|
||||||
stages_prompts,
|
|
||||||
)
|
)
|
||||||
from authentik.providers.saml.views.metadata import MetadataImportView
|
from authentik.providers.saml.views.metadata import MetadataImportView
|
||||||
|
|
||||||
|
@ -74,17 +73,6 @@ urlpatterns = [
|
||||||
stages_bindings.StageBindingUpdateView.as_view(),
|
stages_bindings.StageBindingUpdateView.as_view(),
|
||||||
name="stage-binding-update",
|
name="stage-binding-update",
|
||||||
),
|
),
|
||||||
# Stage Prompts
|
|
||||||
path(
|
|
||||||
"stages_prompts/create/",
|
|
||||||
stages_prompts.PromptCreateView.as_view(),
|
|
||||||
name="stage-prompt-create",
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
"stages_prompts/<uuid:pk>/update/",
|
|
||||||
stages_prompts.PromptUpdateView.as_view(),
|
|
||||||
name="stage-prompt-update",
|
|
||||||
),
|
|
||||||
# Property Mappings
|
# Property Mappings
|
||||||
path(
|
path(
|
||||||
"property-mappings/create/",
|
"property-mappings/create/",
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
"""authentik Prompt 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.lib.views import CreateAssignPermView
|
|
||||||
from authentik.stages.prompt.forms import PromptAdminForm
|
|
||||||
from authentik.stages.prompt.models import Prompt
|
|
||||||
|
|
||||||
|
|
||||||
class PromptCreateView(
|
|
||||||
SuccessMessageMixin,
|
|
||||||
LoginRequiredMixin,
|
|
||||||
DjangoPermissionRequiredMixin,
|
|
||||||
CreateAssignPermView,
|
|
||||||
):
|
|
||||||
"""Create new Prompt"""
|
|
||||||
|
|
||||||
model = Prompt
|
|
||||||
form_class = PromptAdminForm
|
|
||||||
permission_required = "authentik_stages_prompt.add_prompt"
|
|
||||||
|
|
||||||
template_name = "generic/create.html"
|
|
||||||
success_url = reverse_lazy("authentik_core:if-admin")
|
|
||||||
success_message = _("Successfully created Prompt")
|
|
||||||
|
|
||||||
|
|
||||||
class PromptUpdateView(
|
|
||||||
SuccessMessageMixin,
|
|
||||||
LoginRequiredMixin,
|
|
||||||
PermissionRequiredMixin,
|
|
||||||
UpdateView,
|
|
||||||
):
|
|
||||||
"""Update prompt"""
|
|
||||||
|
|
||||||
model = Prompt
|
|
||||||
form_class = PromptAdminForm
|
|
||||||
permission_required = "authentik_stages_prompt.change_prompt"
|
|
||||||
|
|
||||||
template_name = "generic/update.html"
|
|
||||||
success_url = reverse_lazy("authentik_core:if-admin")
|
|
||||||
success_message = _("Successfully updated Prompt")
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Prompt forms"""
|
"""Prompt forms"""
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from authentik.stages.prompt.models import Prompt, PromptStage
|
from authentik.stages.prompt.models import PromptStage
|
||||||
|
|
||||||
|
|
||||||
class PromptStageForm(forms.ModelForm):
|
class PromptStageForm(forms.ModelForm):
|
||||||
|
@ -14,23 +14,3 @@ class PromptStageForm(forms.ModelForm):
|
||||||
widgets = {
|
widgets = {
|
||||||
"name": forms.TextInput(),
|
"name": forms.TextInput(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PromptAdminForm(forms.ModelForm):
|
|
||||||
"""Form to edit Prompt instances for admins"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
model = Prompt
|
|
||||||
fields = [
|
|
||||||
"field_key",
|
|
||||||
"label",
|
|
||||||
"type",
|
|
||||||
"required",
|
|
||||||
"placeholder",
|
|
||||||
"order",
|
|
||||||
]
|
|
||||||
widgets = {
|
|
||||||
"label": forms.TextInput(),
|
|
||||||
"placeholder": forms.TextInput(),
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,10 +24,6 @@ export class AdminURLManager {
|
||||||
return `/administration/stages/${rest}`;
|
return `/administration/stages/${rest}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static stagePrompts(rest: string): string {
|
|
||||||
return `/administration/stages_prompts/${rest}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static stageBindings(rest: string): string {
|
static stageBindings(rest: string): string {
|
||||||
return `/administration/stages/bindings/${rest}`;
|
return `/administration/stages/bindings/${rest}`;
|
||||||
}
|
}
|
||||||
|
|
122
web/src/pages/stages/PromptForm.ts
Normal file
122
web/src/pages/stages/PromptForm.ts
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
import { Prompt, PromptTypeEnum, StagesApi } from "authentik-api";
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, property } from "lit-element";
|
||||||
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
|
import { Form } from "../../elements/forms/Form";
|
||||||
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
import "../../elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
|
@customElement("ak-stage-prompt-form")
|
||||||
|
export class PromptForm extends Form<Prompt> {
|
||||||
|
|
||||||
|
@property({attribute: false})
|
||||||
|
prompt?: Prompt;
|
||||||
|
|
||||||
|
getSuccessMessage(): string {
|
||||||
|
if (this.prompt) {
|
||||||
|
return gettext("Successfully updated prompt.");
|
||||||
|
} else {
|
||||||
|
return gettext("Successfully created prompt.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send = (data: Prompt): Promise<Prompt> => {
|
||||||
|
if (this.prompt) {
|
||||||
|
return new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsUpdate({
|
||||||
|
promptUuid: this.prompt.pk || "",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsCreate({
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTypes(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<option value=${PromptTypeEnum.Text} ?selected=${this.prompt?.type === PromptTypeEnum.Text}>
|
||||||
|
${gettext("Text: Simple Text input")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Username} ?selected=${this.prompt?.type === PromptTypeEnum.Username}>
|
||||||
|
${gettext("Username: Same as Text input, but checks for and prevents duplicate usernames.")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Email} ?selected=${this.prompt?.type === PromptTypeEnum.Email}>
|
||||||
|
${gettext("Email: Text field with Email type.")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Password} ?selected=${this.prompt?.type === PromptTypeEnum.Password}>
|
||||||
|
${gettext("Password: Masked input, password is validated against sources. Policies still have to be applied to this Stage. If two of these are used in the same stage, they are ensured to be identical.")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Number} ?selected=${this.prompt?.type === PromptTypeEnum.Number}>
|
||||||
|
${gettext("Number")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Checkbox} ?selected=${this.prompt?.type === PromptTypeEnum.Checkbox}>
|
||||||
|
${gettext("Checkbox")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Date} ?selected=${this.prompt?.type === PromptTypeEnum.Date}>
|
||||||
|
${gettext("Date")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.DateTime} ?selected=${this.prompt?.type === PromptTypeEnum.DateTime}>
|
||||||
|
${gettext("Date Time")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Separator} ?selected=${this.prompt?.type === PromptTypeEnum.Separator}>
|
||||||
|
${gettext("Separator: Static Separator Line")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Hidden} ?selected=${this.prompt?.type === PromptTypeEnum.Hidden}>
|
||||||
|
${gettext("Hidden: Hidden field, can be used to insert data into form.")}
|
||||||
|
</option>
|
||||||
|
<option value=${PromptTypeEnum.Static} ?selected=${this.prompt?.type === PromptTypeEnum.Static}>
|
||||||
|
${gettext("Static: Static value, displayed as-is.")}
|
||||||
|
</option>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderForm(): TemplateResult {
|
||||||
|
return html`<form class="pf-c-form pf-m-horizontal">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Field Key")}
|
||||||
|
?required=${true}
|
||||||
|
name="fieldKey">
|
||||||
|
<input type="text" value="${ifDefined(this.prompt?.fieldKey)}" class="pf-c-form-control" required>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Name of the form field, also used to store the value.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Label")}
|
||||||
|
?required=${true}
|
||||||
|
name="label">
|
||||||
|
<input type="text" value="${ifDefined(this.prompt?.label)}" class="pf-c-form-control" required>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Label shown next to/above the prompt.")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Type")}
|
||||||
|
?required=${true}
|
||||||
|
name="type">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
${this.renderTypes()}
|
||||||
|
</select>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal name="required">
|
||||||
|
<div class="pf-c-check">
|
||||||
|
<input type="checkbox" class="pf-c-check__input" ?checked=${this.prompt?.required || false}>
|
||||||
|
<label class="pf-c-check__label">
|
||||||
|
${gettext("Required")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Placeholder")}
|
||||||
|
name="placeholder">
|
||||||
|
<input type="text" value="${ifDefined(this.prompt?.placeholder)}" class="pf-c-form-control" required>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Optionally pre-fill the input value")}</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Order")}
|
||||||
|
?required=${true}
|
||||||
|
name="order">
|
||||||
|
<input type="number" value="${ifDefined(this.prompt?.order)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
</form>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,11 +6,12 @@ import { TablePage } from "../../elements/table/TablePage";
|
||||||
import "../../elements/buttons/ModalButton";
|
import "../../elements/buttons/ModalButton";
|
||||||
import "../../elements/buttons/SpinnerButton";
|
import "../../elements/buttons/SpinnerButton";
|
||||||
import "../../elements/forms/DeleteForm";
|
import "../../elements/forms/DeleteForm";
|
||||||
|
import "../../elements/forms/ModalForm";
|
||||||
|
import "./PromptForm";
|
||||||
import { TableColumn } from "../../elements/table/Table";
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
import { PAGE_SIZE } from "../../constants";
|
import { PAGE_SIZE } from "../../constants";
|
||||||
import { Prompt, StagesApi } from "authentik-api";
|
import { Prompt, StagesApi } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
import { AdminURLManager } from "../../api/legacy";
|
|
||||||
|
|
||||||
@customElement("ak-stage-prompt-list")
|
@customElement("ak-stage-prompt-list")
|
||||||
export class PromptListPage extends TablePage<Prompt> {
|
export class PromptListPage extends TablePage<Prompt> {
|
||||||
|
@ -60,12 +61,19 @@ export class PromptListPage extends TablePage<Prompt> {
|
||||||
return html`<li>${stage.name}</li>`;
|
return html`<li>${stage.name}</li>`;
|
||||||
})}`,
|
})}`,
|
||||||
html`
|
html`
|
||||||
<ak-modal-button href="${AdminURLManager.stagePrompts(`${item.pk}/update/`)}">
|
<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
<span slot="submit">
|
||||||
|
${gettext("Update")}
|
||||||
|
</span>
|
||||||
|
<span slot="header">
|
||||||
|
${gettext("Update Prompt")}
|
||||||
|
</span>
|
||||||
|
<ak-stage-prompt-form slot="form" .prompt=${item}>
|
||||||
|
</ak-stage-prompt-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||||
${gettext("Edit")}
|
${gettext("Edit")}
|
||||||
</ak-spinner-button>
|
</button>
|
||||||
<div slot="modal"></div>
|
</ak-forms-modal>
|
||||||
</ak-modal-button>
|
|
||||||
<ak-forms-delete
|
<ak-forms-delete
|
||||||
.obj=${item}
|
.obj=${item}
|
||||||
objectLabel=${gettext("Prompt")}
|
objectLabel=${gettext("Prompt")}
|
||||||
|
@ -83,12 +91,19 @@ export class PromptListPage extends TablePage<Prompt> {
|
||||||
|
|
||||||
renderToolbar(): TemplateResult {
|
renderToolbar(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ak-modal-button href=${AdminURLManager.stagePrompts("create/")}>
|
<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
<span slot="submit">
|
||||||
${gettext("Create")}
|
${gettext("Create")}
|
||||||
</ak-spinner-button>
|
</span>
|
||||||
<div slot="modal"></div>
|
<span slot="header">
|
||||||
</ak-modal-button>
|
${gettext("Create Prompt")}
|
||||||
|
</span>
|
||||||
|
<ak-stage-prompt-form slot="form">
|
||||||
|
</ak-stage-prompt-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||||
|
${gettext("Create")}
|
||||||
|
</button>
|
||||||
|
</ak-forms-modal>
|
||||||
${super.renderToolbar()}
|
${super.renderToolbar()}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue