stages/invitation: add single_use flag to delete invitation after use
closes #821 Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
6ae660aea4
commit
4523550422
|
@ -39,6 +39,7 @@ class InvitationSerializer(ModelSerializer):
|
|||
"expires",
|
||||
"fixed_data",
|
||||
"created_by",
|
||||
"single_use",
|
||||
]
|
||||
depth = 2
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# Generated by Django 3.2 on 2021-05-03 07:46
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_stages_invitation", "0003_auto_20201227_1210"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="invitation",
|
||||
name="single_use",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
help_text="When enabled, the invitation will be deleted after usage.",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -53,6 +53,11 @@ class Invitation(models.Model):
|
|||
|
||||
invite_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
|
||||
|
||||
single_use = models.BooleanField(
|
||||
default=False,
|
||||
help_text=_("When enabled, the invitation will be deleted after usage."),
|
||||
)
|
||||
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
expires = models.DateTimeField(default=None, blank=True, null=True)
|
||||
fixed_data = models.JSONField(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""invitation stage logic"""
|
||||
from copy import deepcopy
|
||||
from typing import Optional
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
|
@ -38,7 +39,9 @@ class InvitationStageView(StageView):
|
|||
return self.executor.stage_invalid()
|
||||
|
||||
invite: Invitation = get_object_or_404(Invitation, pk=token)
|
||||
self.executor.plan.context[PLAN_CONTEXT_PROMPT] = invite.fixed_data
|
||||
self.executor.plan.context[PLAN_CONTEXT_PROMPT] = deepcopy(invite.fixed_data)
|
||||
self.executor.plan.context[INVITATION_IN_EFFECT] = True
|
||||
invitation_used.send(sender=self, request=request, invitation=invite)
|
||||
if invite.single_use:
|
||||
invite.delete()
|
||||
return self.executor.stage_ok()
|
||||
|
|
|
@ -130,7 +130,9 @@ class TestUserLoginStage(TestCase):
|
|||
"""Test with invitation, check data in session"""
|
||||
data = {"foo": "bar"}
|
||||
invite = Invitation.objects.create(
|
||||
created_by=get_anonymous_user(), fixed_data=data
|
||||
created_by=get_anonymous_user(),
|
||||
fixed_data=data,
|
||||
single_use=True
|
||||
)
|
||||
|
||||
plan = FlowPlan(
|
||||
|
@ -156,6 +158,7 @@ class TestUserLoginStage(TestCase):
|
|||
force_str(response.content),
|
||||
{"to": reverse("authentik_core:root-redirect"), "type": "redirect"},
|
||||
)
|
||||
self.assertFalse(Invitation.objects.filter(pk=invite.pk))
|
||||
|
||||
|
||||
class TestInvitationsAPI(APITestCase):
|
||||
|
|
|
@ -18248,6 +18248,10 @@ definitions:
|
|||
x-nullable: true
|
||||
readOnly: true
|
||||
readOnly: true
|
||||
single_use:
|
||||
title: Single use
|
||||
description: When enabled, the invitation will be deleted after usage.
|
||||
type: boolean
|
||||
InvitationStage:
|
||||
required:
|
||||
- name
|
||||
|
|
|
@ -2841,6 +2841,10 @@ msgstr "Signing keypair"
|
|||
msgid "Single Prompts that can be used for Prompt Stages."
|
||||
msgstr "Single Prompts that can be used for Prompt Stages."
|
||||
|
||||
#: src/pages/stages/invitation/InvitationForm.ts:62
|
||||
msgid "Single use"
|
||||
msgstr "Single use"
|
||||
|
||||
#: src/pages/providers/proxy/ProxyProviderForm.ts:173
|
||||
msgid "Skip path regex"
|
||||
msgstr "Skip path regex"
|
||||
|
@ -3877,6 +3881,10 @@ msgstr "When a valid username/email has been entered, and this option is enabled
|
|||
msgid "When enabled, global Email connection settings will be used and connection settings below will be ignored."
|
||||
msgstr "When enabled, global Email connection settings will be used and connection settings below will be ignored."
|
||||
|
||||
#: src/pages/stages/invitation/InvitationForm.ts:66
|
||||
msgid "When enabled, the invitation will be deleted after usage."
|
||||
msgstr "When enabled, the invitation will be deleted after usage."
|
||||
|
||||
#: src/pages/stages/identification/IdentificationStageForm.ts:94
|
||||
msgid "When enabled, user fields are matched regardless of their casing."
|
||||
msgstr "When enabled, user fields are matched regardless of their casing."
|
||||
|
|
|
@ -2833,6 +2833,10 @@ msgstr ""
|
|||
msgid "Single Prompts that can be used for Prompt Stages."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/invitation/InvitationForm.ts:62
|
||||
msgid "Single use"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/providers/proxy/ProxyProviderForm.ts:173
|
||||
msgid "Skip path regex"
|
||||
msgstr ""
|
||||
|
@ -3865,6 +3869,10 @@ msgstr ""
|
|||
msgid "When enabled, global Email connection settings will be used and connection settings below will be ignored."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/invitation/InvitationForm.ts:66
|
||||
msgid "When enabled, the invitation will be deleted after usage."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/stages/identification/IdentificationStageForm.ts:94
|
||||
msgid "When enabled, user fields are matched regardless of their casing."
|
||||
msgstr ""
|
||||
|
|
|
@ -51,6 +51,17 @@ export class InvitationForm extends Form<Invitation> {
|
|||
</ak-codemirror>
|
||||
<p class="pf-c-form__helper-text">${t`Optional data which is loaded into the flow's 'prompt_data' context variable. YAML or JSON.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="singleUse">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.invitation?.singleUse, true)}>
|
||||
<label class="pf-c-check__label">
|
||||
${t`Single use`}
|
||||
</label>
|
||||
</div>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${t`When enabled, the invitation will be deleted after usage.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</form>`;
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue