web/admin: migrate invitations to web
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
717282b4b7
commit
8a3b1ae29d
|
@ -10,7 +10,6 @@ from authentik.admin.views import (
|
||||||
sources,
|
sources,
|
||||||
stages,
|
stages,
|
||||||
stages_bindings,
|
stages_bindings,
|
||||||
stages_invitations,
|
|
||||||
stages_prompts,
|
stages_prompts,
|
||||||
)
|
)
|
||||||
from authentik.providers.saml.views.metadata import MetadataImportView
|
from authentik.providers.saml.views.metadata import MetadataImportView
|
||||||
|
@ -86,12 +85,6 @@ urlpatterns = [
|
||||||
stages_prompts.PromptUpdateView.as_view(),
|
stages_prompts.PromptUpdateView.as_view(),
|
||||||
name="stage-prompt-update",
|
name="stage-prompt-update",
|
||||||
),
|
),
|
||||||
# Stage Invitations
|
|
||||||
path(
|
|
||||||
"stages/invitations/create/",
|
|
||||||
stages_invitations.InvitationCreateView.as_view(),
|
|
||||||
name="stage-invitation-create",
|
|
||||||
),
|
|
||||||
# Property Mappings
|
# Property Mappings
|
||||||
path(
|
path(
|
||||||
"property-mappings/create/",
|
"property-mappings/create/",
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
"""authentik Invitation 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.http import HttpResponseRedirect
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
|
|
||||||
from authentik.lib.views import CreateAssignPermView
|
|
||||||
from authentik.stages.invitation.forms import InvitationForm
|
|
||||||
from authentik.stages.invitation.models import Invitation
|
|
||||||
|
|
||||||
|
|
||||||
class InvitationCreateView(
|
|
||||||
SuccessMessageMixin,
|
|
||||||
LoginRequiredMixin,
|
|
||||||
DjangoPermissionRequiredMixin,
|
|
||||||
CreateAssignPermView,
|
|
||||||
):
|
|
||||||
"""Create new Invitation"""
|
|
||||||
|
|
||||||
model = Invitation
|
|
||||||
form_class = InvitationForm
|
|
||||||
permission_required = "authentik_stages_invitation.add_invitation"
|
|
||||||
|
|
||||||
template_name = "generic/create.html"
|
|
||||||
success_url = reverse_lazy("authentik_core:if-admin")
|
|
||||||
success_message = _("Successfully created Invitation")
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
obj = form.save(commit=False)
|
|
||||||
obj.created_by = self.request.user
|
|
||||||
obj.save()
|
|
||||||
return HttpResponseRedirect(self.success_url)
|
|
|
@ -49,5 +49,4 @@ class InvitationViewSet(ModelViewSet):
|
||||||
filterset_fields = ["created_by__username", "expires"]
|
filterset_fields = ["created_by__username", "expires"]
|
||||||
|
|
||||||
def perform_create(self, serializer: InvitationSerializer):
|
def perform_create(self, serializer: InvitationSerializer):
|
||||||
serializer.instance.created_by = self.request.user
|
serializer.save(created_by=self.request.user)
|
||||||
return super().perform_create(serializer)
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
"""authentik flows invitation forms"""
|
"""authentik flows invitation forms"""
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from authentik.admin.fields import CodeMirrorWidget, YAMLField
|
from authentik.stages.invitation.models import InvitationStage
|
||||||
from authentik.stages.invitation.models import Invitation, InvitationStage
|
|
||||||
|
|
||||||
|
|
||||||
class InvitationStageForm(forms.ModelForm):
|
class InvitationStageForm(forms.ModelForm):
|
||||||
|
@ -15,14 +14,3 @@ class InvitationStageForm(forms.ModelForm):
|
||||||
widgets = {
|
widgets = {
|
||||||
"name": forms.TextInput(),
|
"name": forms.TextInput(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class InvitationForm(forms.ModelForm):
|
|
||||||
"""InvitationForm"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
|
|
||||||
model = Invitation
|
|
||||||
fields = ["expires", "fixed_data"]
|
|
||||||
widgets = {"fixed_data": CodeMirrorWidget()}
|
|
||||||
field_classes = {"fixed_data": YAMLField}
|
|
||||||
|
|
|
@ -28,10 +28,6 @@ export class AdminURLManager {
|
||||||
return `/administration/stages_prompts/${rest}`;
|
return `/administration/stages_prompts/${rest}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static stageInvitations(rest: string): string {
|
|
||||||
return `/administration/stages/invitations/${rest}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static stageBindings(rest: string): string {
|
static stageBindings(rest: string): string {
|
||||||
return `/administration/stages/bindings/${rest}`;
|
return `/administration/stages/bindings/${rest}`;
|
||||||
}
|
}
|
||||||
|
@ -52,10 +48,6 @@ export class UserURLManager {
|
||||||
return `/-/user/tokens/${rest}`;
|
return `/-/user/tokens/${rest}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static authenticatorWebauthn(rest: string): string {
|
|
||||||
return `/-/user/authenticator/webauthn/${rest}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AppURLManager {
|
export class AppURLManager {
|
||||||
|
|
|
@ -84,6 +84,8 @@ export class Form<T> extends LitElement {
|
||||||
const values = form._serializeElementValues(element);
|
const values = form._serializeElementValues(element);
|
||||||
if (element.tagName.toLowerCase() === "select" && "multiple" in element.attributes) {
|
if (element.tagName.toLowerCase() === "select" && "multiple" in element.attributes) {
|
||||||
json[element.name] = values;
|
json[element.name] = values;
|
||||||
|
} else if (element.tagName.toLowerCase() === "input" && element.type === "date") {
|
||||||
|
json[element.name] = element.valueAsDate;
|
||||||
} else {
|
} else {
|
||||||
for (let v = 0; v < values.length; v++) {
|
for (let v = 0; v < values.length; v++) {
|
||||||
form._addSerializedElement(json, element.name, values[v]);
|
form._addSerializedElement(json, element.name, values[v]);
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { Invitation, 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";
|
||||||
|
import "../../elements/CodeMirror";
|
||||||
|
import YAML from "yaml";
|
||||||
|
|
||||||
|
@customElement("ak-stage-invitation-form")
|
||||||
|
export class InvitationForm extends Form<Invitation> {
|
||||||
|
|
||||||
|
@property({attribute: false})
|
||||||
|
invitation?: Invitation;
|
||||||
|
|
||||||
|
getSuccessMessage(): string {
|
||||||
|
if (this.invitation) {
|
||||||
|
return gettext("Successfully updated invitation.");
|
||||||
|
} else {
|
||||||
|
return gettext("Successfully created invitation.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send = (data: Invitation): Promise<Invitation> => {
|
||||||
|
if (this.invitation) {
|
||||||
|
return new StagesApi(DEFAULT_CONFIG).stagesInvitationInvitationsUpdate({
|
||||||
|
inviteUuid: this.invitation.pk || "",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new StagesApi(DEFAULT_CONFIG).stagesInvitationInvitationsCreate({
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderForm(): TemplateResult {
|
||||||
|
return html`<form class="pf-c-form pf-m-horizontal">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Expires")}
|
||||||
|
?required=${true}
|
||||||
|
name="expires">
|
||||||
|
<input type="date" value="${ifDefined(this.invitation?.expires)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Attributes")}
|
||||||
|
name="fixedData">
|
||||||
|
<ak-codemirror mode="yaml" value="${YAML.stringify(this.invitation?.fixedData)}">
|
||||||
|
</ak-codemirror>
|
||||||
|
<p class="pf-c-form__helper-text">${gettext("Optional data which is loaded into the flow's 'prompt_data' context variable.")}</p>
|
||||||
|
</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 "./InvitationForm";
|
||||||
import { TableColumn } from "../../elements/table/Table";
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
import { PAGE_SIZE } from "../../constants";
|
import { PAGE_SIZE } from "../../constants";
|
||||||
import { Invitation, StagesApi } from "authentik-api";
|
import { Invitation, StagesApi } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
import { AdminURLManager } from "../../api/legacy";
|
|
||||||
|
|
||||||
@customElement("ak-stage-invitation-list")
|
@customElement("ak-stage-invitation-list")
|
||||||
export class InvitationListPage extends TablePage<Invitation> {
|
export class InvitationListPage extends TablePage<Invitation> {
|
||||||
|
@ -71,12 +72,19 @@ export class InvitationListPage extends TablePage<Invitation> {
|
||||||
|
|
||||||
renderToolbar(): TemplateResult {
|
renderToolbar(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ak-modal-button href=${AdminURLManager.stageInvitations("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 Invitation")}
|
||||||
|
</span>
|
||||||
|
<ak-stage-invitation-form slot="form">
|
||||||
|
</ak-stage-invitation-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||||
|
${gettext("Create")}
|
||||||
|
</button>
|
||||||
|
</ak-forms-modal>
|
||||||
${super.renderToolbar()}
|
${super.renderToolbar()}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue