stages/invitation: add invitation name

closes #2583

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2022-03-26 18:32:45 +01:00
parent 933919c647
commit c7a83e6182
18 changed files with 220 additions and 16 deletions

View file

@ -54,6 +54,7 @@ class InvitationSerializer(ModelSerializer):
model = Invitation model = Invitation
fields = [ fields = [
"pk", "pk",
"name",
"expires", "expires",
"fixed_data", "fixed_data",
"created_by", "created_by",
@ -67,8 +68,8 @@ class InvitationViewSet(UsedByMixin, ModelViewSet):
queryset = Invitation.objects.all() queryset = Invitation.objects.all()
serializer_class = InvitationSerializer serializer_class = InvitationSerializer
ordering = ["-expires"] ordering = ["-expires"]
search_fields = ["created_by__username", "expires"] search_fields = ["name", "created_by__username", "expires"]
filterset_fields = ["created_by__username", "expires"] filterset_fields = ["name", "created_by__username", "expires"]
def perform_create(self, serializer: InvitationSerializer): def perform_create(self, serializer: InvitationSerializer):
serializer.save(created_by=self.request.user) serializer.save(created_by=self.request.user)

View file

@ -0,0 +1,122 @@
# Generated by Django 4.0.3 on 2022-03-26 17:24
import uuid
import django.db.models.deletion
from django.apps.registry import Apps
from django.conf import settings
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
import authentik.core.models
def migrate_add_name(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Invitation = apps.get_model("authentik_stages_invitation", "invitation")
for invite in Invitation.objects.using(db_alias).all():
invite.name = invite.pk.hex
invite.save()
class Migration(migrations.Migration):
replaces = [
("authentik_stages_invitation", "0001_initial"),
("authentik_stages_invitation", "0002_auto_20201225_2143"),
("authentik_stages_invitation", "0003_auto_20201227_1210"),
("authentik_stages_invitation", "0004_invitation_single_use"),
("authentik_stages_invitation", "0005_auto_20210901_1211"),
("authentik_stages_invitation", "0006_invitation_name"),
]
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("authentik_flows", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="InvitationStage",
fields=[
(
"stage_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_flows.stage",
),
),
(
"continue_flow_without_invitation",
models.BooleanField(
default=False,
help_text="If this flag is set, this Stage will jump to the next Stage when no Invitation is given. By default this Stage will cancel the Flow when no invitation is given.",
),
),
],
options={
"verbose_name": "Invitation Stage",
"verbose_name_plural": "Invitation Stages",
},
bases=("authentik_flows.stage",),
),
migrations.CreateModel(
name="Invitation",
fields=[
(
"invite_uuid",
models.UUIDField(
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
),
),
(
"expires",
models.DateTimeField(default=authentik.core.models.default_token_duration),
),
(
"fixed_data",
models.JSONField(
blank=True,
default=dict,
help_text="Optional fixed data to enforce on user enrollment.",
),
),
(
"created_by",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
(
"single_use",
models.BooleanField(
default=False,
help_text="When enabled, the invitation will be deleted after usage.",
),
),
("expiring", models.BooleanField(default=True)),
("name", models.SlugField(default="")),
],
options={
"verbose_name": "Invitation",
"verbose_name_plural": "Invitations",
},
),
migrations.RunPython(
code=migrate_add_name,
),
migrations.AlterField(
model_name="invitation",
name="name",
field=models.SlugField(),
preserve_default=False,
),
]

View file

@ -0,0 +1,38 @@
# Generated by Django 4.0.3 on 2022-03-26 17:22
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def migrate_add_name(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Invitation = apps.get_model("authentik_stages_invitation", "invitation")
for invite in Invitation.objects.using(db_alias).all():
invite.name = invite.pk.hex
invite.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_stages_invitation", "0005_auto_20210901_1211"),
]
operations = [
migrations.AddField(
model_name="invitation",
name="name",
field=models.SlugField(default=""),
preserve_default=False,
),
migrations.RunPython(migrate_add_name),
migrations.AlterField(
model_name="invitation",
name="name",
field=models.SlugField(),
preserve_default=False,
),
]

View file

@ -52,6 +52,8 @@ class Invitation(ExpiringModel):
invite_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) invite_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
name = models.SlugField()
single_use = models.BooleanField( single_use = models.BooleanField(
default=False, default=False,
help_text=_("When enabled, the invitation will be deleted after usage."), help_text=_("When enabled, the invitation will be deleted after usage."),

View file

@ -16924,6 +16924,10 @@ paths:
schema: schema:
type: string type: string
format: date-time format: date-time
- in: query
name: name
schema:
type: string
- name: ordering - name: ordering
required: false required: false
in: query in: query
@ -16973,6 +16977,7 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/InvitationRequest' $ref: '#/components/schemas/InvitationRequest'
required: true
security: security:
- authentik: [] - authentik: []
responses: responses:
@ -17031,6 +17036,7 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/InvitationRequest' $ref: '#/components/schemas/InvitationRequest'
required: true
security: security:
- authentik: [] - authentik: []
responses: responses:
@ -22105,6 +22111,10 @@ components:
format: uuid format: uuid
readOnly: true readOnly: true
title: Invite uuid title: Invite uuid
name:
type: string
maxLength: 50
pattern: ^[-a-zA-Z0-9_]+$
expires: expires:
type: string type: string
format: date-time format: date-time
@ -22120,11 +22130,17 @@ components:
description: When enabled, the invitation will be deleted after usage. description: When enabled, the invitation will be deleted after usage.
required: required:
- created_by - created_by
- name
- pk - pk
InvitationRequest: InvitationRequest:
type: object type: object
description: Invitation Serializer description: Invitation Serializer
properties: properties:
name:
type: string
minLength: 1
maxLength: 50
pattern: ^[-a-zA-Z0-9_]+$
expires: expires:
type: string type: string
format: date-time format: date-time
@ -22134,6 +22150,8 @@ components:
single_use: single_use:
type: boolean type: boolean
description: When enabled, the invitation will be deleted after usage. description: When enabled, the invitation will be deleted after usage.
required:
- name
InvitationStage: InvitationStage:
type: object type: object
description: InvitationStage Serializer description: InvitationStage Serializer
@ -27141,6 +27159,11 @@ components:
type: object type: object
description: Invitation Serializer description: Invitation Serializer
properties: properties:
name:
type: string
minLength: 1
maxLength: 50
pattern: ^[-a-zA-Z0-9_]+$
expires: expires:
type: string type: string
format: date-time format: date-time

View file

@ -2350,7 +2350,6 @@ msgid "How to connect"
msgstr "So verbinden Sie sich" msgstr "So verbinden Sie sich"
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3048,6 +3047,8 @@ msgstr "Meine Anwendungen"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2383,7 +2383,6 @@ msgid "How to connect"
msgstr "How to connect" msgstr "How to connect"
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3093,6 +3092,8 @@ msgstr "My applications"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2341,7 +2341,6 @@ msgid "How to connect"
msgstr "Cómo conectarse" msgstr "Cómo conectarse"
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3041,6 +3040,8 @@ msgstr "Mis solicitudes"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2367,7 +2367,6 @@ msgid "How to connect"
msgstr "" msgstr ""
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3072,6 +3071,8 @@ msgstr "Mes applications"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2338,7 +2338,6 @@ msgid "How to connect"
msgstr "Jak się połączyć" msgstr "Jak się połączyć"
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3038,6 +3037,8 @@ msgstr "Moje aplikacje"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2375,7 +2375,6 @@ msgid "How to connect"
msgstr "" msgstr ""
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3083,6 +3082,8 @@ msgstr ""
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2341,7 +2341,6 @@ msgid "How to connect"
msgstr "Nasıl bağlanır" msgstr "Nasıl bağlanır"
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3042,6 +3041,8 @@ msgstr "Uygulamalarım"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2338,7 +2338,6 @@ msgid "How to connect"
msgstr "如何连接" msgstr "如何连接"
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3037,6 +3036,8 @@ msgstr "我的应用"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2338,7 +2338,6 @@ msgid "How to connect"
msgstr "如何连接" msgstr "如何连接"
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3037,6 +3036,8 @@ msgstr "我的应用"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -2338,7 +2338,6 @@ msgid "How to connect"
msgstr "如何连接" msgstr "如何连接"
#: src/elements/forms/DeleteBulkForm.ts #: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/RelatedUserList.ts #: src/pages/users/RelatedUserList.ts
#: src/pages/users/UserListPage.ts #: src/pages/users/UserListPage.ts
msgid "ID" msgid "ID"
@ -3037,6 +3036,8 @@ msgstr "我的应用"
#: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/dummy/DummyStageForm.ts
#: src/pages/stages/email/EmailStageForm.ts #: src/pages/stages/email/EmailStageForm.ts
#: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/stages/invitation/InvitationForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/stages/invitation/InvitationStageForm.ts #: src/pages/stages/invitation/InvitationStageForm.ts
#: src/pages/stages/password/PasswordStageForm.ts #: src/pages/stages/password/PasswordStageForm.ts
#: src/pages/stages/prompt/PromptStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts

View file

@ -44,6 +44,15 @@ export class InvitationForm extends ModelForm<Invitation, string> {
renderForm(): TemplateResult { renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal"> return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
<input
type="text"
value="${this.instance?.name || ""}"
class="pf-c-form-control"
required
data-ak-slug="true"
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Expires`} ?required=${true} name="expires"> <ak-form-element-horizontal label=${t`Expires`} ?required=${true} name="expires">
<input <input
type="datetime-local" type="datetime-local"

View file

@ -65,7 +65,7 @@ export class InvitationListPage extends TablePage<Invitation> {
columns(): TableColumn[] { columns(): TableColumn[] {
return [ return [
new TableColumn(t`ID`, "pk"), new TableColumn(t`Name`, "name"),
new TableColumn(t`Created by`, "created_by"), new TableColumn(t`Created by`, "created_by"),
new TableColumn(t`Expiry`), new TableColumn(t`Expiry`),
new TableColumn(t`Actions`), new TableColumn(t`Actions`),
@ -96,7 +96,7 @@ export class InvitationListPage extends TablePage<Invitation> {
row(item: Invitation): TemplateResult[] { row(item: Invitation): TemplateResult[] {
return [ return [
html`${item.pk}`, html`${item.name}`,
html`${item.createdBy?.username}`, html`${item.createdBy?.username}`,
html`${item.expires?.toLocaleString() || t`-`}`, html`${item.expires?.toLocaleString() || t`-`}`,
html` <ak-forms-modal> html` <ak-forms-modal>

View file

@ -2,7 +2,6 @@ import { t } from "@lingui/macro";
import { TemplateResult, html } from "lit"; import { TemplateResult, html } from "lit";
import { customElement } from "lit/decorators.js"; import { customElement } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { InvitationStage, StagesApi } from "@goauthentik/api"; import { InvitationStage, StagesApi } from "@goauthentik/api";
@ -49,7 +48,7 @@ export class InvitationStageForm extends ModelForm<InvitationStage, string> {
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name"> <ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
<input <input
type="text" type="text"
value="${ifDefined(this.instance?.name || "")}" value="${this.instance?.name || ""}"
class="pf-c-form-control" class="pf-c-form-control"
required required
/> />