flows: add API for flow export
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
93bd95436f
commit
a57d524273
|
@ -148,11 +148,6 @@ urlpatterns = [
|
|||
flows.FlowDebugExecuteView.as_view(),
|
||||
name="flow-execute",
|
||||
),
|
||||
path(
|
||||
"flows/<uuid:pk>/export/",
|
||||
flows.FlowExportView.as_view(),
|
||||
name="flow-export",
|
||||
),
|
||||
# Property Mappings
|
||||
path(
|
||||
"property-mappings/create/",
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.contrib.auth.mixins import (
|
|||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.http import HttpRequest, HttpResponse, JsonResponse
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import DetailView, FormView, UpdateView
|
||||
|
@ -15,8 +15,6 @@ from authentik.flows.exceptions import FlowNonApplicableException
|
|||
from authentik.flows.forms import FlowForm, FlowImportForm
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||
from authentik.flows.transfer.common import DataclassEncoder
|
||||
from authentik.flows.transfer.exporter import FlowExporter
|
||||
from authentik.flows.transfer.importer import FlowImporter
|
||||
from authentik.flows.views import SESSION_KEY_PLAN, FlowPlanner
|
||||
from authentik.lib.utils.urls import redirect_with_qs
|
||||
|
@ -108,19 +106,3 @@ class FlowImportView(LoginRequiredMixin, FormView):
|
|||
else:
|
||||
messages.success(self.request, _("Successfully imported flow."))
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class FlowExportView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
"""Export Flow"""
|
||||
|
||||
model = Flow
|
||||
permission_required = "authentik_flows.export_flow"
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def get(self, request: HttpRequest, pk: str) -> HttpResponse:
|
||||
"""Debug exectue flow, setting the current user as pending user"""
|
||||
flow: Flow = self.get_object()
|
||||
exporter = FlowExporter(flow)
|
||||
response = JsonResponse(exporter.export(), encoder=DataclassEncoder, safe=False)
|
||||
response["Content-Disposition"] = f'attachment; filename="{flow.slug}.akflow"'
|
||||
return response
|
||||
|
|
|
@ -3,10 +3,13 @@ from dataclasses import dataclass
|
|||
|
||||
from django.core.cache import cache
|
||||
from django.db.models import Model
|
||||
from django.http.response import JsonResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_yasg2 import openapi
|
||||
from drf_yasg2.utils import swagger_auto_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import (
|
||||
|
@ -20,6 +23,8 @@ from rest_framework.viewsets import ModelViewSet
|
|||
from authentik.core.api.utils import CacheSerializer
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.flows.planner import cache_key
|
||||
from authentik.flows.transfer.common import DataclassEncoder
|
||||
from authentik.flows.transfer.exporter import FlowExporter
|
||||
|
||||
|
||||
class FlowSerializer(ModelSerializer):
|
||||
|
@ -87,6 +92,24 @@ class FlowViewSet(ModelViewSet):
|
|||
"""Info about cached flows"""
|
||||
return Response(data={"count": len(cache.keys("flow_*"))})
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={
|
||||
"200": openapi.Response(
|
||||
"File Attachment", schema=openapi.Schema(type=openapi.TYPE_FILE)
|
||||
),
|
||||
},
|
||||
)
|
||||
@action(detail=True)
|
||||
def export(self, request: Request, slug: str) -> Response:
|
||||
"""Export flow to .akflow file"""
|
||||
flow = self.get_object()
|
||||
if not request.user.has_perm("authentik_flows.export_flow", flow):
|
||||
raise PermissionDenied()
|
||||
exporter = FlowExporter(flow)
|
||||
response = JsonResponse(exporter.export(), encoder=DataclassEncoder, safe=False)
|
||||
response["Content-Disposition"] = f'attachment; filename="{flow.slug}.akflow"'
|
||||
return response
|
||||
|
||||
@swagger_auto_schema(responses={200: FlowDiagramSerializer()})
|
||||
@action(detail=True, methods=["get"])
|
||||
def diagram(self, request: Request, slug: str) -> Response:
|
||||
|
|
20
swagger.yaml
20
swagger.yaml
|
@ -2800,6 +2800,26 @@ paths:
|
|||
type: string
|
||||
format: slug
|
||||
pattern: ^[-a-zA-Z0-9_]+$
|
||||
/flows/instances/{slug}/export/:
|
||||
get:
|
||||
operationId: flows_instances_export
|
||||
description: Export flow to .akflow file
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: File Attachment
|
||||
schema:
|
||||
type: file
|
||||
tags:
|
||||
- flows
|
||||
parameters:
|
||||
- name: slug
|
||||
in: path
|
||||
description: Visible in the URL.
|
||||
required: true
|
||||
type: string
|
||||
format: slug
|
||||
pattern: ^[-a-zA-Z0-9_]+$
|
||||
/outposts/outposts/:
|
||||
get:
|
||||
operationId: outposts_outposts_list
|
||||
|
|
|
@ -81,7 +81,7 @@ export class FlowListPage extends TablePage<Flow> {
|
|||
<a class="pf-c-button pf-m-secondary ak-root-link" href="${AdminURLManager.flows(`${item.pk}/execute/?next=/%23${window.location.href}`)}">
|
||||
${gettext("Execute")}
|
||||
</a>
|
||||
<a class="pf-c-button pf-m-secondary ak-root-link" href="${AdminURLManager.flows(`${item.pk}/export/`)}">
|
||||
<a class="pf-c-button pf-m-secondary ak-root-link" href="${`${DEFAULT_CONFIG.basePath}/flows/instances/${item.slug}/export/`}">
|
||||
${gettext("Export")}
|
||||
</a>
|
||||
`,
|
||||
|
|
Reference in New Issue