Merge branch 'master' into otp-rework
This commit is contained in:
commit
285a69d91f
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -52,6 +52,14 @@ jobs:
|
||||||
run: sudo pip install -U wheel pipenv && pipenv install --dev
|
run: sudo pip install -U wheel pipenv && pipenv install --dev
|
||||||
- name: Lint with bandit
|
- name: Lint with bandit
|
||||||
run: pipenv run bandit -r passbook
|
run: pipenv run bandit -r passbook
|
||||||
|
snyk:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@master
|
||||||
|
- name: Run Snyk to check for vulnerabilities
|
||||||
|
uses: snyk/actions/python@master
|
||||||
|
env:
|
||||||
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||||
pyright:
|
pyright:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
12
Pipfile.lock
generated
12
Pipfile.lock
generated
|
@ -46,18 +46,18 @@
|
||||||
},
|
},
|
||||||
"boto3": {
|
"boto3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:2616351c98eec18d20a1d64b33355c86cd855ac96219d1b8428c9bfc590bde53",
|
"sha256:77d926c16ab2ab2bfe68811f3bc987e7d79c97f3e2adebf9265c587cdb1fc47b",
|
||||||
"sha256:7daad26a008c91dd7b82fde17d246d1fe6e4b3813426689ef8bac9017a277cfb"
|
"sha256:7f558165eaa608a5d0e05227ee820f4b3cc74533a52c9dde7eb488eba091d50d"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.14.12"
|
"version": "==1.14.13"
|
||||||
},
|
},
|
||||||
"botocore": {
|
"botocore": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:45934d880378777cefeca727f369d1f5aebf6b254e9be58e7c77dd0b059338bb",
|
"sha256:37b65cc48c99b7dd4d5606e56f76ecd88eb7be392ea8a166df734a6b3035301c",
|
||||||
"sha256:a94e0e2307f1b9fe3a84660842909cd2680b57a9fc9fb0c3a03b0afb2eadbe21"
|
"sha256:5ac9b53a75852fe4282be8741c8136e6948714fef6eff1bd9babb861f8647ba3"
|
||||||
],
|
],
|
||||||
"version": "==1.17.12"
|
"version": "==1.17.13"
|
||||||
},
|
},
|
||||||
"celery": {
|
"celery": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
<td>
|
<td>
|
||||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:flow-update' pk=flow.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:flow-update' pk=flow.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:flow-delete' pk=flow.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:flow-delete' pk=flow.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
|
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:flow-execute' pk=flow.pk %}?next={{ request.get_full_path }}">{% trans 'Execute' %}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -120,7 +120,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-card__body">
|
<div class="pf-c-card__body">
|
||||||
<i class="pf-icon pf-icon-ok"></i> {{ version }}
|
{% if version >= version_latest %}
|
||||||
|
<i class="pf-icon pf-icon-ok"></i>
|
||||||
|
{% blocktrans with version=version %}
|
||||||
|
{{ version }} (Up-to-date!)
|
||||||
|
{% endblocktrans %}
|
||||||
|
{% else %}
|
||||||
|
<i class="pf-icon pf-icon-warning-triangle"></i>
|
||||||
|
{% blocktrans with version=version latest=version_latest %}
|
||||||
|
{{ version }} ({{ latest }} is available!)
|
||||||
|
{% endblocktrans %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ from django.urls import path
|
||||||
|
|
||||||
from passbook.admin.views import (
|
from passbook.admin.views import (
|
||||||
applications,
|
applications,
|
||||||
audit,
|
|
||||||
certificate_key_pair,
|
certificate_key_pair,
|
||||||
debug,
|
debug,
|
||||||
flows,
|
flows,
|
||||||
|
@ -188,6 +187,11 @@ urlpatterns = [
|
||||||
path(
|
path(
|
||||||
"flows/<uuid:pk>/update/", flows.FlowUpdateView.as_view(), name="flow-update",
|
"flows/<uuid:pk>/update/", flows.FlowUpdateView.as_view(), name="flow-update",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"flows/<uuid:pk>/execute/",
|
||||||
|
flows.FlowDebugExecuteView.as_view(),
|
||||||
|
name="flow-execute",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"flows/<uuid:pk>/delete/", flows.FlowDeleteView.as_view(), name="flow-delete",
|
"flows/<uuid:pk>/delete/", flows.FlowDeleteView.as_view(), name="flow-delete",
|
||||||
),
|
),
|
||||||
|
@ -252,8 +256,6 @@ urlpatterns = [
|
||||||
certificate_key_pair.CertificateKeyPairDeleteView.as_view(),
|
certificate_key_pair.CertificateKeyPairDeleteView.as_view(),
|
||||||
name="certificatekeypair-delete",
|
name="certificatekeypair-delete",
|
||||||
),
|
),
|
||||||
# Audit Log
|
|
||||||
path("audit/", audit.EventListView.as_view(), name="audit-log"),
|
|
||||||
# Groups
|
# Groups
|
||||||
path("groups/", groups.GroupListView.as_view(), name="groups"),
|
path("groups/", groups.GroupListView.as_view(), name="groups"),
|
||||||
# Debug
|
# Debug
|
||||||
|
|
|
@ -5,13 +5,17 @@ from django.contrib.auth.mixins import (
|
||||||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||||
)
|
)
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import DeleteView, ListView, UpdateView
|
from django.views.generic import DeleteView, DetailView, ListView, UpdateView
|
||||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||||
|
|
||||||
from passbook.flows.forms import FlowForm
|
from passbook.flows.forms import FlowForm
|
||||||
from passbook.flows.models import Flow
|
from passbook.flows.models import Flow
|
||||||
|
from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
|
from passbook.flows.views import SESSION_KEY_PLAN, FlowPlanner
|
||||||
|
from passbook.lib.utils.urls import redirect_with_qs
|
||||||
from passbook.lib.views import CreateAssignPermView
|
from passbook.lib.views import CreateAssignPermView
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +50,25 @@ class FlowCreateView(
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class FlowDebugExecuteView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||||
|
"""Debug exectue flow, setting the current user as pending user"""
|
||||||
|
|
||||||
|
model = Flow
|
||||||
|
permission_required = "passbook_flows.view_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()
|
||||||
|
planner = FlowPlanner(flow)
|
||||||
|
planner.use_cache = False
|
||||||
|
plan = planner.plan(self.request, {PLAN_CONTEXT_PENDING_USER: request.user,},)
|
||||||
|
self.request.session[SESSION_KEY_PLAN] = plan
|
||||||
|
return redirect_with_qs(
|
||||||
|
"passbook_flows:flow-executor-shell", self.request.GET, flow_slug=flow.slug,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FlowUpdateView(
|
class FlowUpdateView(
|
||||||
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
||||||
):
|
):
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
"""passbook administration overview"""
|
"""passbook administration overview"""
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.shortcuts import redirect, reverse
|
from django.shortcuts import redirect, reverse
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
from packaging.version import Version, parse
|
||||||
|
from requests import RequestException, get
|
||||||
|
|
||||||
from passbook import __version__
|
from passbook import __version__
|
||||||
from passbook.admin.mixins import AdminRequiredMixin
|
from passbook.admin.mixins import AdminRequiredMixin
|
||||||
|
@ -12,6 +16,19 @@ from passbook.root.celery import CELERY_APP
|
||||||
from passbook.stages.invitation.models import Invitation
|
from passbook.stages.invitation.models import Invitation
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def latest_version() -> Version:
|
||||||
|
"""Get latest release from GitHub, cached"""
|
||||||
|
try:
|
||||||
|
data = get(
|
||||||
|
"https://api.github.com/repos/beryju/passbook/releases/latest"
|
||||||
|
).json()
|
||||||
|
tag_name = data.get("tag_name")
|
||||||
|
return parse(tag_name.split("/")[1])
|
||||||
|
except RequestException:
|
||||||
|
return parse("0.0.0")
|
||||||
|
|
||||||
|
|
||||||
class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
|
class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
|
||||||
"""Overview View"""
|
"""Overview View"""
|
||||||
|
|
||||||
|
@ -33,7 +50,8 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
|
||||||
kwargs["stage_count"] = len(Stage.objects.all())
|
kwargs["stage_count"] = len(Stage.objects.all())
|
||||||
kwargs["flow_count"] = len(Flow.objects.all())
|
kwargs["flow_count"] = len(Flow.objects.all())
|
||||||
kwargs["invitation_count"] = len(Invitation.objects.all())
|
kwargs["invitation_count"] = len(Invitation.objects.all())
|
||||||
kwargs["version"] = __version__
|
kwargs["version"] = parse(__version__)
|
||||||
|
kwargs["version_latest"] = latest_version()
|
||||||
kwargs["worker_count"] = len(CELERY_APP.control.ping(timeout=0.5))
|
kwargs["worker_count"] = len(CELERY_APP.control.ping(timeout=0.5))
|
||||||
kwargs["providers_without_application"] = Provider.objects.filter(
|
kwargs["providers_without_application"] = Provider.objects.filter(
|
||||||
application=None
|
application=None
|
||||||
|
|
|
@ -32,6 +32,7 @@ from passbook.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceView
|
||||||
from passbook.sources.oauth.api import OAuthSourceViewSet
|
from passbook.sources.oauth.api import OAuthSourceViewSet
|
||||||
from passbook.sources.saml.api import SAMLSourceViewSet
|
from passbook.sources.saml.api import SAMLSourceViewSet
|
||||||
from passbook.stages.captcha.api import CaptchaStageViewSet
|
from passbook.stages.captcha.api import CaptchaStageViewSet
|
||||||
|
from passbook.stages.consent.api import ConsentStageViewSet
|
||||||
from passbook.stages.dummy.api import DummyStageViewSet
|
from passbook.stages.dummy.api import DummyStageViewSet
|
||||||
from passbook.stages.email.api import EmailStageViewSet
|
from passbook.stages.email.api import EmailStageViewSet
|
||||||
from passbook.stages.identification.api import IdentificationStageViewSet
|
from passbook.stages.identification.api import IdentificationStageViewSet
|
||||||
|
@ -85,6 +86,7 @@ router.register("propertymappings/saml", SAMLPropertyMappingViewSet)
|
||||||
|
|
||||||
router.register("stages/all", StageViewSet)
|
router.register("stages/all", StageViewSet)
|
||||||
router.register("stages/captcha", CaptchaStageViewSet)
|
router.register("stages/captcha", CaptchaStageViewSet)
|
||||||
|
router.register("stages/consent", ConsentStageViewSet)
|
||||||
router.register("stages/email", EmailStageViewSet)
|
router.register("stages/email", EmailStageViewSet)
|
||||||
router.register("stages/identification", IdentificationStageViewSet)
|
router.register("stages/identification", IdentificationStageViewSet)
|
||||||
router.register("stages/invitation", InvitationStageViewSet)
|
router.register("stages/invitation", InvitationStageViewSet)
|
||||||
|
|
|
@ -1,2 +1,9 @@
|
||||||
"""passbook audit urls"""
|
"""passbook audit urls"""
|
||||||
urlpatterns = []
|
from django.urls import path
|
||||||
|
|
||||||
|
from passbook.audit.views import EventListView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
# Audit Log
|
||||||
|
path("audit/", EventListView.as_view(), name="log"),
|
||||||
|
]
|
||||||
|
|
|
@ -9,7 +9,7 @@ class EventListView(PermissionListMixin, ListView):
|
||||||
"""Show list of all invitations"""
|
"""Show list of all invitations"""
|
||||||
|
|
||||||
model = Event
|
model = Event
|
||||||
template_name = "administration/audit/list.html"
|
template_name = "audit/list.html"
|
||||||
permission_required = "passbook_audit.view_event"
|
permission_required = "passbook_audit.view_event"
|
||||||
ordering = "-created"
|
ordering = "-created"
|
||||||
paginate_by = 20
|
paginate_by = 20
|
|
@ -32,8 +32,8 @@
|
||||||
{% if user.is_superuser %}
|
{% if user.is_superuser %}
|
||||||
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_app 'passbook_admin' %}"
|
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_app 'passbook_admin' %}"
|
||||||
href="{% url 'passbook_admin:overview' %}">{% trans 'Administrate' %}</a></li>
|
href="{% url 'passbook_admin:overview' %}">{% trans 'Administrate' %}</a></li>
|
||||||
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_admin:audit-log' %}"
|
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_audit:log' %}"
|
||||||
href="{% url 'passbook_admin:audit-log' %}">{% trans 'Monitor' %}</a></li>
|
href="{% url 'passbook_audit:log' %}">{% trans 'Monitor' %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
{{ user.username }}
|
{{ user.username }}
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<a href="{% url 'passbook_flows:default-authentication' %}">{% trans 'Not you?' %}</a>
|
<a href="{% url 'passbook_flows:cancel' %}">{% trans 'Not you?' %}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
22
passbook/flows/templates/flows/error.html
Normal file
22
passbook/flows/templates/flows/error.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.pb-exception {
|
||||||
|
font-family: monospace;
|
||||||
|
overflow-x: scroll;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<header class="pf-c-login__main-header">
|
||||||
|
<h1 class="pf-c-title pf-m-3xl">
|
||||||
|
{% trans 'Whoops!' %}
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<div class="pf-c-login__main-body">
|
||||||
|
<h3>
|
||||||
|
{% trans 'Something went wrong! Please try again later.' %}
|
||||||
|
</h3>
|
||||||
|
{% if debug %}
|
||||||
|
<pre class="pb-exception">{{ tb }}</pre>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
|
@ -3,6 +3,7 @@ from django.urls import path
|
||||||
|
|
||||||
from passbook.flows.models import FlowDesignation
|
from passbook.flows.models import FlowDesignation
|
||||||
from passbook.flows.views import (
|
from passbook.flows.views import (
|
||||||
|
CancelView,
|
||||||
FlowExecutorShellView,
|
FlowExecutorShellView,
|
||||||
FlowExecutorView,
|
FlowExecutorView,
|
||||||
FlowPermissionDeniedView,
|
FlowPermissionDeniedView,
|
||||||
|
@ -36,6 +37,7 @@ urlpatterns = [
|
||||||
ToDefaultFlow.as_view(designation=FlowDesignation.UNRENOLLMENT),
|
ToDefaultFlow.as_view(designation=FlowDesignation.UNRENOLLMENT),
|
||||||
name="default-unenrollment",
|
name="default-unenrollment",
|
||||||
),
|
),
|
||||||
|
path("-/cancel/", CancelView.as_view(), name="cancel"),
|
||||||
path("b/<slug:flow_slug>/", FlowExecutorView.as_view(), name="flow-executor"),
|
path("b/<slug:flow_slug>/", FlowExecutorView.as_view(), name="flow-executor"),
|
||||||
path(
|
path(
|
||||||
"<slug:flow_slug>/", FlowExecutorShellView.as_view(), name="flow-executor-shell"
|
"<slug:flow_slug>/", FlowExecutorShellView.as_view(), name="flow-executor-shell"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""passbook multi-stage authentication engine"""
|
"""passbook multi-stage authentication engine"""
|
||||||
|
from traceback import format_tb
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from django.http import (
|
from django.http import (
|
||||||
|
@ -8,7 +9,7 @@ from django.http import (
|
||||||
HttpResponseRedirect,
|
HttpResponseRedirect,
|
||||||
JsonResponse,
|
JsonResponse,
|
||||||
)
|
)
|
||||||
from django.shortcuts import get_object_or_404, redirect, reverse
|
from django.shortcuts import get_object_or_404, redirect, render, reverse
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
||||||
|
@ -106,8 +107,18 @@ class FlowExecutorView(View):
|
||||||
stage=self.current_stage,
|
stage=self.current_stage,
|
||||||
flow_slug=self.flow.slug,
|
flow_slug=self.flow.slug,
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
stage_response = self.current_stage_view.get(request, *args, **kwargs)
|
stage_response = self.current_stage_view.get(request, *args, **kwargs)
|
||||||
return to_stage_response(request, stage_response)
|
return to_stage_response(request, stage_response)
|
||||||
|
except Exception as exc: # pylint: disable=broad-except
|
||||||
|
return to_stage_response(
|
||||||
|
request,
|
||||||
|
render(
|
||||||
|
request,
|
||||||
|
"flows/error.html",
|
||||||
|
{"error": exc, "tb": "".join(format_tb(exc.__traceback__)),},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||||
"""pass post request to current stage"""
|
"""pass post request to current stage"""
|
||||||
|
@ -117,8 +128,18 @@ class FlowExecutorView(View):
|
||||||
stage=self.current_stage,
|
stage=self.current_stage,
|
||||||
flow_slug=self.flow.slug,
|
flow_slug=self.flow.slug,
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
stage_response = self.current_stage_view.post(request, *args, **kwargs)
|
stage_response = self.current_stage_view.post(request, *args, **kwargs)
|
||||||
return to_stage_response(request, stage_response)
|
return to_stage_response(request, stage_response)
|
||||||
|
except Exception as exc: # pylint: disable=broad-except
|
||||||
|
return to_stage_response(
|
||||||
|
request,
|
||||||
|
render(
|
||||||
|
request,
|
||||||
|
"flows/error.html",
|
||||||
|
{"error": exc, "tb": "".join(format_tb(exc.__traceback__)),},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def _initiate_plan(self) -> FlowPlan:
|
def _initiate_plan(self) -> FlowPlan:
|
||||||
planner = FlowPlanner(self.flow)
|
planner = FlowPlanner(self.flow)
|
||||||
|
@ -183,6 +204,30 @@ class FlowPermissionDeniedView(PermissionDeniedView):
|
||||||
"""User could not be authenticated"""
|
"""User could not be authenticated"""
|
||||||
|
|
||||||
|
|
||||||
|
class FlowExecutorShellView(TemplateView):
|
||||||
|
"""Executor Shell view, loads a dummy card with a spinner
|
||||||
|
that loads the next stage in the background."""
|
||||||
|
|
||||||
|
template_name = "flows/shell.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||||
|
kwargs["exec_url"] = reverse("passbook_flows:flow-executor", kwargs=self.kwargs)
|
||||||
|
kwargs["msg_url"] = reverse("passbook_api:messages-list")
|
||||||
|
self.request.session[SESSION_KEY_GET] = self.request.GET
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
class CancelView(View):
|
||||||
|
"""View which canels the currently active plan"""
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest) -> HttpResponse:
|
||||||
|
"""View which canels the currently active plan"""
|
||||||
|
if SESSION_KEY_PLAN in request.session:
|
||||||
|
del request.session[SESSION_KEY_PLAN]
|
||||||
|
LOGGER.debug("Canceled current plan")
|
||||||
|
return redirect("passbook_core:overview")
|
||||||
|
|
||||||
|
|
||||||
class ToDefaultFlow(View):
|
class ToDefaultFlow(View):
|
||||||
"""Redirect to default flow matching by designation"""
|
"""Redirect to default flow matching by designation"""
|
||||||
|
|
||||||
|
@ -206,19 +251,6 @@ class ToDefaultFlow(View):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FlowExecutorShellView(TemplateView):
|
|
||||||
"""Executor Shell view, loads a dummy card with a spinner
|
|
||||||
that loads the next stage in the background."""
|
|
||||||
|
|
||||||
template_name = "flows/shell.html"
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
|
||||||
kwargs["exec_url"] = reverse("passbook_flows:flow-executor", kwargs=self.kwargs)
|
|
||||||
kwargs["msg_url"] = reverse("passbook_api:messages-list")
|
|
||||||
self.request.session[SESSION_KEY_GET] = self.request.GET
|
|
||||||
return kwargs
|
|
||||||
|
|
||||||
|
|
||||||
def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpResponse:
|
def to_stage_response(request: HttpRequest, source: HttpResponse) -> HttpResponse:
|
||||||
"""Convert normal HttpResponse into JSON Response"""
|
"""Convert normal HttpResponse into JSON Response"""
|
||||||
if isinstance(source, HttpResponseRedirect) or source.status_code == 302:
|
if isinstance(source, HttpResponseRedirect) or source.status_code == 302:
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
{% blocktrans with user=user %}
|
{% blocktrans with user=user %}
|
||||||
You are logged in as {{ user }}. Not you?
|
You are logged in as {{ user }}. Not you?
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
<a href="{% url 'passbook_flows:default-invalidation' %}">{% trans 'Logout' %}</a>
|
<a href="{% url 'passbook_flows:cancel' %}">{% trans 'Logout' %}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-form__group pf-m-action">
|
<div class="pf-c-form__group pf-m-action">
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
{{ user.username }}
|
{{ user.username }}
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<a href="{% url 'passbook_flows:default-authentication' %}">{% trans 'Not you?' %}</a>
|
<a href="{% url 'passbook_flows:cancel' %}">{% trans 'Not you?' %}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
141
swagger.yaml
141
swagger.yaml
|
@ -3275,6 +3275,133 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
/stages/consent/:
|
||||||
|
get:
|
||||||
|
operationId: stages_consent_list
|
||||||
|
description: ConsentStage Viewset
|
||||||
|
parameters:
|
||||||
|
- name: ordering
|
||||||
|
in: query
|
||||||
|
description: Which field to use when ordering the results.
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: search
|
||||||
|
in: query
|
||||||
|
description: A search term.
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: limit
|
||||||
|
in: query
|
||||||
|
description: Number of results to return per page.
|
||||||
|
required: false
|
||||||
|
type: integer
|
||||||
|
- name: offset
|
||||||
|
in: query
|
||||||
|
description: The initial index from which to return the results.
|
||||||
|
required: false
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: ''
|
||||||
|
schema:
|
||||||
|
required:
|
||||||
|
- count
|
||||||
|
- results
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
count:
|
||||||
|
type: integer
|
||||||
|
next:
|
||||||
|
type: string
|
||||||
|
format: uri
|
||||||
|
x-nullable: true
|
||||||
|
previous:
|
||||||
|
type: string
|
||||||
|
format: uri
|
||||||
|
x-nullable: true
|
||||||
|
results:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/ConsentStage'
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
post:
|
||||||
|
operationId: stages_consent_create
|
||||||
|
description: ConsentStage Viewset
|
||||||
|
parameters:
|
||||||
|
- name: data
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ConsentStage'
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: ''
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ConsentStage'
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
parameters: []
|
||||||
|
/stages/consent/{stage_uuid}/:
|
||||||
|
get:
|
||||||
|
operationId: stages_consent_read
|
||||||
|
description: ConsentStage Viewset
|
||||||
|
parameters: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: ''
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ConsentStage'
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
put:
|
||||||
|
operationId: stages_consent_update
|
||||||
|
description: ConsentStage Viewset
|
||||||
|
parameters:
|
||||||
|
- name: data
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ConsentStage'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: ''
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ConsentStage'
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
patch:
|
||||||
|
operationId: stages_consent_partial_update
|
||||||
|
description: ConsentStage Viewset
|
||||||
|
parameters:
|
||||||
|
- name: data
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ConsentStage'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: ''
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ConsentStage'
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
delete:
|
||||||
|
operationId: stages_consent_delete
|
||||||
|
description: ConsentStage Viewset
|
||||||
|
parameters: []
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: ''
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
parameters:
|
||||||
|
- name: stage_uuid
|
||||||
|
in: path
|
||||||
|
description: A UUID string identifying this Consent Stage.
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
/stages/dummy/:
|
/stages/dummy/:
|
||||||
get:
|
get:
|
||||||
operationId: stages_dummy_list
|
operationId: stages_dummy_list
|
||||||
|
@ -6052,6 +6179,20 @@ definitions:
|
||||||
description: Private key, acquired from https://www.google.com/recaptcha/intro/v3.html
|
description: Private key, acquired from https://www.google.com/recaptcha/intro/v3.html
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
|
ConsentStage:
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
pk:
|
||||||
|
title: Stage uuid
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
readOnly: true
|
||||||
|
name:
|
||||||
|
title: Name
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
DummyStage:
|
DummyStage:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
|
|
Reference in a new issue