diff --git a/authentik/stages/invitation/api.py b/authentik/stages/invitation/api.py index 9132504b9..789ba69de 100644 --- a/authentik/stages/invitation/api.py +++ b/authentik/stages/invitation/api.py @@ -54,6 +54,7 @@ class InvitationSerializer(ModelSerializer): model = Invitation fields = [ "pk", + "name", "expires", "fixed_data", "created_by", @@ -67,8 +68,8 @@ class InvitationViewSet(UsedByMixin, ModelViewSet): queryset = Invitation.objects.all() serializer_class = InvitationSerializer ordering = ["-expires"] - search_fields = ["created_by__username", "expires"] - filterset_fields = ["created_by__username", "expires"] + search_fields = ["name", "created_by__username", "expires"] + filterset_fields = ["name", "created_by__username", "expires"] def perform_create(self, serializer: InvitationSerializer): serializer.save(created_by=self.request.user) diff --git a/authentik/stages/invitation/migrations/0001_squashed_0006_invitation_name.py b/authentik/stages/invitation/migrations/0001_squashed_0006_invitation_name.py new file mode 100644 index 000000000..7802cbe60 --- /dev/null +++ b/authentik/stages/invitation/migrations/0001_squashed_0006_invitation_name.py @@ -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, + ), + ] diff --git a/authentik/stages/invitation/migrations/0006_invitation_name.py b/authentik/stages/invitation/migrations/0006_invitation_name.py new file mode 100644 index 000000000..acbeb5a3b --- /dev/null +++ b/authentik/stages/invitation/migrations/0006_invitation_name.py @@ -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, + ), + ] diff --git a/authentik/stages/invitation/models.py b/authentik/stages/invitation/models.py index 4ed9ef0ea..2805334e5 100644 --- a/authentik/stages/invitation/models.py +++ b/authentik/stages/invitation/models.py @@ -52,6 +52,8 @@ class Invitation(ExpiringModel): invite_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) + name = models.SlugField() + single_use = models.BooleanField( default=False, help_text=_("When enabled, the invitation will be deleted after usage."), diff --git a/schema.yml b/schema.yml index 0b67dcb2b..3b1416e1d 100644 --- a/schema.yml +++ b/schema.yml @@ -16924,6 +16924,10 @@ paths: schema: type: string format: date-time + - in: query + name: name + schema: + type: string - name: ordering required: false in: query @@ -16973,6 +16977,7 @@ paths: application/json: schema: $ref: '#/components/schemas/InvitationRequest' + required: true security: - authentik: [] responses: @@ -17031,6 +17036,7 @@ paths: application/json: schema: $ref: '#/components/schemas/InvitationRequest' + required: true security: - authentik: [] responses: @@ -22105,6 +22111,10 @@ components: format: uuid readOnly: true title: Invite uuid + name: + type: string + maxLength: 50 + pattern: ^[-a-zA-Z0-9_]+$ expires: type: string format: date-time @@ -22120,11 +22130,17 @@ components: description: When enabled, the invitation will be deleted after usage. required: - created_by + - name - pk InvitationRequest: type: object description: Invitation Serializer properties: + name: + type: string + minLength: 1 + maxLength: 50 + pattern: ^[-a-zA-Z0-9_]+$ expires: type: string format: date-time @@ -22134,6 +22150,8 @@ components: single_use: type: boolean description: When enabled, the invitation will be deleted after usage. + required: + - name InvitationStage: type: object description: InvitationStage Serializer @@ -27141,6 +27159,11 @@ components: type: object description: Invitation Serializer properties: + name: + type: string + minLength: 1 + maxLength: 50 + pattern: ^[-a-zA-Z0-9_]+$ expires: type: string format: date-time diff --git a/web/src/locales/de.po b/web/src/locales/de.po index 58fcc6339..e9474da12 100644 --- a/web/src/locales/de.po +++ b/web/src/locales/de.po @@ -2350,7 +2350,6 @@ msgid "How to connect" msgstr "So verbinden Sie sich" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3048,6 +3047,8 @@ msgstr "Meine Anwendungen" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/en.po b/web/src/locales/en.po index 6d26ae5fe..9b7930227 100644 --- a/web/src/locales/en.po +++ b/web/src/locales/en.po @@ -2383,7 +2383,6 @@ msgid "How to connect" msgstr "How to connect" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3093,6 +3092,8 @@ msgstr "My applications" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/es.po b/web/src/locales/es.po index 35a75b872..bcdc84d9d 100644 --- a/web/src/locales/es.po +++ b/web/src/locales/es.po @@ -2341,7 +2341,6 @@ msgid "How to connect" msgstr "Cómo conectarse" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3041,6 +3040,8 @@ msgstr "Mis solicitudes" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/fr_FR.po b/web/src/locales/fr_FR.po index 424ee161b..ac9355e5b 100644 --- a/web/src/locales/fr_FR.po +++ b/web/src/locales/fr_FR.po @@ -2367,7 +2367,6 @@ msgid "How to connect" msgstr "" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3072,6 +3071,8 @@ msgstr "Mes applications" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/pl.po b/web/src/locales/pl.po index cd9895ba5..1a565311d 100644 --- a/web/src/locales/pl.po +++ b/web/src/locales/pl.po @@ -2338,7 +2338,6 @@ msgid "How to connect" msgstr "Jak się połączyć" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3038,6 +3037,8 @@ msgstr "Moje aplikacje" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/pseudo-LOCALE.po b/web/src/locales/pseudo-LOCALE.po index 472a84221..6c1a1332e 100644 --- a/web/src/locales/pseudo-LOCALE.po +++ b/web/src/locales/pseudo-LOCALE.po @@ -2375,7 +2375,6 @@ msgid "How to connect" msgstr "" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3083,6 +3082,8 @@ msgstr "" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/tr.po b/web/src/locales/tr.po index 12ab99fd5..121ee0d11 100644 --- a/web/src/locales/tr.po +++ b/web/src/locales/tr.po @@ -2341,7 +2341,6 @@ msgid "How to connect" msgstr "Nasıl bağlanır" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3042,6 +3041,8 @@ msgstr "Uygulamalarım" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/zh-Hans.po b/web/src/locales/zh-Hans.po index 35253ef3a..498668c6f 100644 --- a/web/src/locales/zh-Hans.po +++ b/web/src/locales/zh-Hans.po @@ -2338,7 +2338,6 @@ msgid "How to connect" msgstr "如何连接" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3037,6 +3036,8 @@ msgstr "我的应用" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/zh-Hant.po b/web/src/locales/zh-Hant.po index 63ae5ceb8..bb05a891a 100644 --- a/web/src/locales/zh-Hant.po +++ b/web/src/locales/zh-Hant.po @@ -2338,7 +2338,6 @@ msgid "How to connect" msgstr "如何连接" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3037,6 +3036,8 @@ msgstr "我的应用" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/locales/zh_TW.po b/web/src/locales/zh_TW.po index 61ed94678..55aee8a9a 100644 --- a/web/src/locales/zh_TW.po +++ b/web/src/locales/zh_TW.po @@ -2338,7 +2338,6 @@ msgid "How to connect" msgstr "如何连接" #: src/elements/forms/DeleteBulkForm.ts -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/users/RelatedUserList.ts #: src/pages/users/UserListPage.ts msgid "ID" @@ -3037,6 +3036,8 @@ msgstr "我的应用" #: src/pages/stages/dummy/DummyStageForm.ts #: src/pages/stages/email/EmailStageForm.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/password/PasswordStageForm.ts #: src/pages/stages/prompt/PromptStageForm.ts diff --git a/web/src/pages/stages/invitation/InvitationForm.ts b/web/src/pages/stages/invitation/InvitationForm.ts index e4f73c7b7..a3ea9e885 100644 --- a/web/src/pages/stages/invitation/InvitationForm.ts +++ b/web/src/pages/stages/invitation/InvitationForm.ts @@ -44,6 +44,15 @@ export class InvitationForm extends ModelForm { renderForm(): TemplateResult { return html`
+ + + { columns(): TableColumn[] { return [ - new TableColumn(t`ID`, "pk"), + new TableColumn(t`Name`, "name"), new TableColumn(t`Created by`, "created_by"), new TableColumn(t`Expiry`), new TableColumn(t`Actions`), @@ -96,7 +96,7 @@ export class InvitationListPage extends TablePage { row(item: Invitation): TemplateResult[] { return [ - html`${item.pk}`, + html`${item.name}`, html`${item.createdBy?.username}`, html`${item.expires?.toLocaleString() || t`-`}`, html` diff --git a/web/src/pages/stages/invitation/InvitationStageForm.ts b/web/src/pages/stages/invitation/InvitationStageForm.ts index f20b118ae..efc295733 100644 --- a/web/src/pages/stages/invitation/InvitationStageForm.ts +++ b/web/src/pages/stages/invitation/InvitationStageForm.ts @@ -2,7 +2,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; -import { ifDefined } from "lit/directives/if-defined.js"; import { InvitationStage, StagesApi } from "@goauthentik/api"; @@ -49,7 +48,7 @@ export class InvitationStageForm extends ModelForm {