*: add clear param to file upload API to delete stored file and reset field

closes #949

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-06-05 21:33:03 +02:00
parent 277c2f4aad
commit f5dbdbd48b
7 changed files with 121 additions and 27 deletions

View File

@ -11,7 +11,13 @@ from drf_spectacular.utils import (
inline_serializer, inline_serializer,
) )
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.fields import CharField, FileField, IntegerField, ReadOnlyField from rest_framework.fields import (
BooleanField,
CharField,
FileField,
IntegerField,
ReadOnlyField,
)
from rest_framework.parsers import MultiPartParser from rest_framework.parsers import MultiPartParser
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
@ -173,7 +179,11 @@ class ApplicationViewSet(ModelViewSet):
@extend_schema( @extend_schema(
request={ request={
"multipart/form-data": inline_serializer( "multipart/form-data": inline_serializer(
"SetIcon", fields={"file": FileField()} "SetIcon",
fields={
"file": FileField(required=False),
"clear": BooleanField(default=False),
},
) )
}, },
responses={ responses={
@ -193,11 +203,16 @@ class ApplicationViewSet(ModelViewSet):
"""Set application icon""" """Set application icon"""
app: Application = self.get_object() app: Application = self.get_object()
icon = request.FILES.get("file", None) icon = request.FILES.get("file", None)
if not icon: clear = request.data.get("clear", False)
return HttpResponseBadRequest() if clear:
# .delete() saves the model by default
app.meta_icon.delete()
return Response({})
if icon:
app.meta_icon = icon app.meta_icon = icon
app.save() app.save()
return Response({}) return Response({})
return HttpResponseBadRequest()
@permission_required("authentik_core.change_application") @permission_required("authentik_core.change_application")
@extend_schema( @extend_schema(

View File

@ -10,7 +10,7 @@ from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
from guardian.shortcuts import get_objects_for_user from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.fields import FileField, ReadOnlyField from rest_framework.fields import BooleanField, FileField, ReadOnlyField
from rest_framework.parsers import MultiPartParser from rest_framework.parsers import MultiPartParser
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
@ -269,7 +269,11 @@ class FlowViewSet(ModelViewSet):
@extend_schema( @extend_schema(
request={ request={
"multipart/form-data": inline_serializer( "multipart/form-data": inline_serializer(
"SetIcon", fields={"file": FileField()} "SetIcon",
fields={
"file": FileField(required=False),
"clear": BooleanField(default=False),
},
) )
}, },
responses={ responses={
@ -288,12 +292,17 @@ class FlowViewSet(ModelViewSet):
def set_background(self, request: Request, slug: str): def set_background(self, request: Request, slug: str):
"""Set Flow background""" """Set Flow background"""
flow: Flow = self.get_object() flow: Flow = self.get_object()
icon = request.FILES.get("file", None) background = request.FILES.get("file", None)
if not icon: clear = request.data.get("clear", False)
return HttpResponseBadRequest() if clear:
flow.background = icon # .delete() saves the model by default
flow.background.delete()
return Response({})
if background:
flow.background = background
flow.save() flow.save()
return Response({}) return Response({})
return HttpResponseBadRequest()
@permission_required("authentik_core.change_application") @permission_required("authentik_core.change_application")
@extend_schema( @extend_schema(

View File

@ -1474,7 +1474,6 @@ paths:
multipart/form-data: multipart/form-data:
schema: schema:
$ref: '#/components/schemas/SetIconRequest' $ref: '#/components/schemas/SetIconRequest'
required: true
security: security:
- authentik: [] - authentik: []
- cookieAuth: [] - cookieAuth: []
@ -4519,7 +4518,6 @@ paths:
multipart/form-data: multipart/form-data:
schema: schema:
$ref: '#/components/schemas/SetIconRequest' $ref: '#/components/schemas/SetIconRequest'
required: true
security: security:
- authentik: [] - authentik: []
- cookieAuth: [] - cookieAuth: []
@ -4612,7 +4610,6 @@ paths:
multipart/form-data: multipart/form-data:
schema: schema:
$ref: '#/components/schemas/SetIconRequest' $ref: '#/components/schemas/SetIconRequest'
required: true
security: security:
- authentik: [] - authentik: []
- cookieAuth: [] - cookieAuth: []
@ -24890,8 +24887,9 @@ components:
file: file:
type: string type: string
format: binary format: binary
required: clear:
- file type: boolean
default: false
SetIconURLRequest: SetIconURLRequest:
type: object type: object
properties: properties:

View File

@ -593,6 +593,10 @@ msgstr "Clear Flow cache"
msgid "Clear Policy cache" msgid "Clear Policy cache"
msgstr "Clear Policy cache" msgstr "Clear Policy cache"
#: src/pages/flows/FlowForm.ts
msgid "Clear background image"
msgstr "Clear background image"
#: src/pages/flows/FlowListPage.ts #: src/pages/flows/FlowListPage.ts
#: src/pages/flows/FlowListPage.ts #: src/pages/flows/FlowListPage.ts
#: src/pages/policies/PolicyListPage.ts #: src/pages/policies/PolicyListPage.ts
@ -600,6 +604,10 @@ msgstr "Clear Policy cache"
msgid "Clear cache" msgid "Clear cache"
msgstr "Clear cache" msgstr "Clear cache"
#: src/pages/applications/ApplicationForm.ts
msgid "Clear icon"
msgstr "Clear icon"
#: src/elements/forms/HorizontalFormElement.ts #: src/elements/forms/HorizontalFormElement.ts
msgid "Click to change value" msgid "Click to change value"
msgstr "Click to change value" msgstr "Click to change value"
@ -948,6 +956,7 @@ msgstr "Created {0}"
msgid "Creation Date" msgid "Creation Date"
msgstr "Creation Date" msgstr "Creation Date"
#: src/pages/applications/ApplicationForm.ts
#: src/pages/flows/FlowForm.ts #: src/pages/flows/FlowForm.ts
msgid "Currently set to:" msgid "Currently set to:"
msgstr "Currently set to:" msgstr "Currently set to:"
@ -1040,6 +1049,14 @@ msgstr "Delete Session"
msgid "Delete account" msgid "Delete account"
msgstr "Delete account" msgstr "Delete account"
#: src/pages/flows/FlowForm.ts
msgid "Delete currently set background image."
msgstr "Delete currently set background image."
#: src/pages/applications/ApplicationForm.ts
msgid "Delete currently set icon."
msgstr "Delete currently set icon."
#: src/pages/sources/saml/SAMLSourceForm.ts #: src/pages/sources/saml/SAMLSourceForm.ts
msgid "Delete temporary users after" msgid "Delete temporary users after"
msgstr "Delete temporary users after" msgstr "Delete temporary users after"
@ -1744,6 +1761,7 @@ msgstr "IP"
msgid "IP Reputation" msgid "IP Reputation"
msgstr "IP Reputation" msgstr "IP Reputation"
#: src/pages/applications/ApplicationForm.ts
#: src/pages/applications/ApplicationForm.ts #: src/pages/applications/ApplicationForm.ts
msgid "Icon" msgid "Icon"
msgstr "Icon" msgstr "Icon"

View File

@ -587,6 +587,10 @@ msgstr ""
msgid "Clear Policy cache" msgid "Clear Policy cache"
msgstr "" msgstr ""
#:
msgid "Clear background image"
msgstr ""
#: #:
#: #:
#: #:
@ -594,6 +598,10 @@ msgstr ""
msgid "Clear cache" msgid "Clear cache"
msgstr "" msgstr ""
#:
msgid "Clear icon"
msgstr ""
#: #:
msgid "Click to change value" msgid "Click to change value"
msgstr "" msgstr ""
@ -942,6 +950,7 @@ msgstr ""
msgid "Creation Date" msgid "Creation Date"
msgstr "" msgstr ""
#:
#: #:
msgid "Currently set to:" msgid "Currently set to:"
msgstr "" msgstr ""
@ -1034,6 +1043,14 @@ msgstr ""
msgid "Delete account" msgid "Delete account"
msgstr "" msgstr ""
#:
msgid "Delete currently set background image."
msgstr ""
#:
msgid "Delete currently set icon."
msgstr ""
#: #:
msgid "Delete temporary users after" msgid "Delete temporary users after"
msgstr "" msgstr ""
@ -1736,6 +1753,7 @@ msgstr ""
msgid "IP Reputation" msgid "IP Reputation"
msgstr "" msgstr ""
#:
#: #:
msgid "Icon" msgid "Icon"
msgstr "" msgstr ""

View File

@ -27,6 +27,9 @@ export class ApplicationForm extends ModelForm<Application, string> {
@property({ attribute: false }) @property({ attribute: false })
provider?: number; provider?: number;
@property({ type: Boolean })
clearIcon = false;
getSuccessMessage(): string { getSuccessMessage(): string {
if (this.instance) { if (this.instance) {
return t`Successfully updated application.`; return t`Successfully updated application.`;
@ -54,11 +57,12 @@ export class ApplicationForm extends ModelForm<Application, string> {
return config().then((c) => { return config().then((c) => {
if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) {
const icon = this.getFormFile(); const icon = this.getFormFile();
if (icon) { if (icon || this.clearIcon) {
return writeOp.then(app => { return writeOp.then(app => {
return new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({ return new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({
slug: app.slug, slug: app.slug,
file: icon file: icon,
clear: this.clearIcon,
}); });
}); });
} }
@ -186,7 +190,21 @@ export class ApplicationForm extends ModelForm<Application, string> {
${this.instance?.metaIcon ? html` ${this.instance?.metaIcon ? html`
<p class="pf-c-form__helper-text">${t`Currently set to:`} ${this.instance?.metaIcon}</p> <p class="pf-c-form__helper-text">${t`Currently set to:`} ${this.instance?.metaIcon}</p>
`: html``} `: html``}
</ak-form-element-horizontal>`; </ak-form-element-horizontal>
${this.instance?.metaIcon ? html`
<ak-form-element-horizontal>
<div class="pf-c-check">
<input type="checkbox" class="pf-c-check__input" @change=${(ev: Event) => {
const target = ev.target as HTMLInputElement;
this.clearIcon = target.checked;
}}>
<label class="pf-c-check__label">
${t`Clear icon`}
</label>
</div>
<p class="pf-c-form__helper-text">${t`Delete currently set icon.`}</p>
</ak-form-element-horizontal>
`: html``}`;
} }
return html`<ak-form-element-horizontal return html`<ak-form-element-horizontal
label=${t`Icon`} label=${t`Icon`}

View File

@ -1,6 +1,6 @@
import { Flow, FlowDesignationEnum, PolicyEngineMode, FlowsApi, CapabilitiesEnum } from "authentik-api"; import { Flow, FlowDesignationEnum, PolicyEngineMode, FlowsApi, CapabilitiesEnum } from "authentik-api";
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { customElement } from "lit-element"; import { customElement, property } from "lit-element";
import { html, TemplateResult } from "lit-html"; import { html, TemplateResult } from "lit-html";
import { config, DEFAULT_CONFIG } from "../../api/Config"; import { config, DEFAULT_CONFIG } from "../../api/Config";
import { ifDefined } from "lit-html/directives/if-defined"; import { ifDefined } from "lit-html/directives/if-defined";
@ -26,6 +26,9 @@ export class FlowForm extends ModelForm<Flow, string> {
} }
} }
@property({ type: Boolean })
clearBackground = false;
send = (data: Flow): Promise<void | Flow> => { send = (data: Flow): Promise<void | Flow> => {
let writeOp: Promise<Flow>; let writeOp: Promise<Flow>;
if (this.instance) { if (this.instance) {
@ -41,11 +44,12 @@ export class FlowForm extends ModelForm<Flow, string> {
return config().then((c) => { return config().then((c) => {
if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) {
const icon = this.getFormFile(); const icon = this.getFormFile();
if (icon) { if (icon || this.clearBackground) {
return writeOp.then(app => { return writeOp.then(app => {
return new FlowsApi(DEFAULT_CONFIG).flowsInstancesSetBackgroundCreate({ return new FlowsApi(DEFAULT_CONFIG).flowsInstancesSetBackgroundCreate({
slug: app.slug, slug: app.slug,
file: icon file: icon,
clear: this.clearBackground,
}); });
}); });
} }
@ -143,7 +147,21 @@ export class FlowForm extends ModelForm<Flow, string> {
<p class="pf-c-form__helper-text">${t`Currently set to:`} ${this.instance?.background}</p> <p class="pf-c-form__helper-text">${t`Currently set to:`} ${this.instance?.background}</p>
`: html``} `: html``}
<p class="pf-c-form__helper-text">${t`Background shown during execution.`}</p> <p class="pf-c-form__helper-text">${t`Background shown during execution.`}</p>
</ak-form-element-horizontal>`; </ak-form-element-horizontal>
${this.instance?.background ? html`
<ak-form-element-horizontal>
<div class="pf-c-check">
<input type="checkbox" class="pf-c-check__input" @change=${(ev: Event) => {
const target = ev.target as HTMLInputElement;
this.clearBackground = target.checked;
}}>
<label class="pf-c-check__label">
${t`Clear background image`}
</label>
</div>
<p class="pf-c-form__helper-text">${t`Delete currently set background image.`}</p>
</ak-form-element-horizontal>
`: html``}`;
} }
return html`<ak-form-element-horizontal return html`<ak-form-element-horizontal
label=${t`Background`} label=${t`Background`}