stages/email: add support for custom template to API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
d061868fdc
commit
d1cde64214
|
@ -1,8 +1,18 @@
|
||||||
"""EmailStage API Views"""
|
"""EmailStage API Views"""
|
||||||
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.request import Request
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.serializers import ValidationError
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
from authentik.core.api.utils import TypeCreateSerializer
|
||||||
from authentik.flows.api.stages import StageSerializer
|
from authentik.flows.api.stages import StageSerializer
|
||||||
from authentik.stages.email.models import EmailStage, get_template_choices
|
from authentik.stages.email.models import (
|
||||||
|
EmailStage,
|
||||||
|
EmailTemplates,
|
||||||
|
get_template_choices,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EmailStageSerializer(StageSerializer):
|
class EmailStageSerializer(StageSerializer):
|
||||||
|
@ -12,6 +22,13 @@ class EmailStageSerializer(StageSerializer):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields["template"].choices = get_template_choices()
|
self.fields["template"].choices = get_template_choices()
|
||||||
|
|
||||||
|
def validate_template(self, value: str) -> str:
|
||||||
|
choices = get_template_choices()
|
||||||
|
for path, _ in choices:
|
||||||
|
if path == value:
|
||||||
|
return value
|
||||||
|
raise ValidationError(f"Invalid template '{value}' specified.")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = EmailStage
|
model = EmailStage
|
||||||
|
@ -39,3 +56,17 @@ class EmailStageViewSet(ModelViewSet):
|
||||||
serializer_class = EmailStageSerializer
|
serializer_class = EmailStageSerializer
|
||||||
|
|
||||||
# TODO: Validate connection settings when use_global_settings is unchecked
|
# TODO: Validate connection settings when use_global_settings is unchecked
|
||||||
|
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||||
|
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||||
|
def templates(self, request: Request) -> Response:
|
||||||
|
"""Get all available templates, including custom templates"""
|
||||||
|
choices = []
|
||||||
|
for value, label in get_template_choices():
|
||||||
|
choices.append(
|
||||||
|
{
|
||||||
|
"name": value,
|
||||||
|
"description": label,
|
||||||
|
"component": "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return Response(TypeCreateSerializer(choices, many=True).data)
|
||||||
|
|
18
authentik/stages/email/migrations/0003_auto_20210404_1054.py
Normal file
18
authentik/stages/email/migrations/0003_auto_20210404_1054.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.1.7 on 2021-04-04 10:54
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_stages_email", "0002_emailstage_use_global_settings"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="emailstage",
|
||||||
|
name="template",
|
||||||
|
field=models.TextField(default="email/password_reset.html"),
|
||||||
|
),
|
||||||
|
]
|
|
@ -78,9 +78,7 @@ class EmailStage(Stage):
|
||||||
default=30, help_text=_("Time in minutes the token sent is valid.")
|
default=30, help_text=_("Time in minutes the token sent is valid.")
|
||||||
)
|
)
|
||||||
subject = models.TextField(default="authentik")
|
subject = models.TextField(default="authentik")
|
||||||
template = models.TextField(
|
template = models.TextField(default=EmailTemplates.PASSWORD_RESET)
|
||||||
choices=get_template_choices(), default=EmailTemplates.PASSWORD_RESET
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> BaseSerializer:
|
def serializer(self) -> BaseSerializer:
|
||||||
|
|
23
swagger.yaml
23
swagger.yaml
|
@ -12081,6 +12081,25 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- stages
|
- stages
|
||||||
parameters: []
|
parameters: []
|
||||||
|
/stages/email/templates/:
|
||||||
|
get:
|
||||||
|
operationId: stages_email_templates
|
||||||
|
description: Get all available templates, including custom templates
|
||||||
|
parameters: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: ''
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/TypeCreate'
|
||||||
|
'403':
|
||||||
|
description: Authentication credentials were invalid, absent or insufficient.
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/GenericError'
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
parameters: []
|
||||||
/stages/email/{stage_uuid}/:
|
/stages/email/{stage_uuid}/:
|
||||||
get:
|
get:
|
||||||
operationId: stages_email_read
|
operationId: stages_email_read
|
||||||
|
@ -17693,9 +17712,7 @@ definitions:
|
||||||
template:
|
template:
|
||||||
title: Template
|
title: Template
|
||||||
type: string
|
type: string
|
||||||
enum:
|
minLength: 1
|
||||||
- email/password_reset.html
|
|
||||||
- email/account_confirmation.html
|
|
||||||
IdentificationStage:
|
IdentificationStage:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { EmailStage, EmailStageTemplateEnum, StagesApi } from "authentik-api";
|
import { EmailStage, StagesApi } from "authentik-api";
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { customElement, property } from "lit-element";
|
import { customElement, property } from "lit-element";
|
||||||
import { html, TemplateResult } from "lit-html";
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
@ -8,6 +8,7 @@ import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import "../../../elements/forms/HorizontalFormElement";
|
import "../../../elements/forms/HorizontalFormElement";
|
||||||
import "../../../elements/forms/FormGroup";
|
import "../../../elements/forms/FormGroup";
|
||||||
import { first } from "../../../utils";
|
import { first } from "../../../utils";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
|
||||||
@customElement("ak-stage-email-form")
|
@customElement("ak-stage-email-form")
|
||||||
export class EmailStageForm extends Form<EmailStage> {
|
export class EmailStageForm extends Form<EmailStage> {
|
||||||
|
@ -153,14 +154,16 @@ export class EmailStageForm extends Form<EmailStage> {
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${t`Template`}
|
label=${t`Template`}
|
||||||
?required=${true}
|
?required=${true}
|
||||||
name="subject">
|
name="template">
|
||||||
<select name="users" class="pf-c-form-control">
|
<select name="users" class="pf-c-form-control">
|
||||||
<option value=${EmailStageTemplateEnum.AccountConfirmationHtml} ?selected=${this.stage?.template === EmailStageTemplateEnum.AccountConfirmationHtml}>
|
${until(new StagesApi(DEFAULT_CONFIG).stagesEmailTemplates().then(templates => {
|
||||||
${t`Account confirmation`}
|
return templates.map(template => {
|
||||||
</option>
|
const selected = this.stage?.template === template.name;
|
||||||
<option value=${EmailStageTemplateEnum.PasswordResetHtml} ?selected=${this.stage?.template === EmailStageTemplateEnum.PasswordResetHtml}>
|
return html`<option value=${ifDefined(template.name)} ?selected=${selected}>
|
||||||
${t`Password reset`}
|
${template.description}
|
||||||
</option>
|
</option>`;
|
||||||
|
});
|
||||||
|
}), html`<option>${t`Loading...`}</option>`)}
|
||||||
</select>
|
</select>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
</div>
|
</div>
|
||||||
|
|
Reference in a new issue