admin: add flow-stage-bindings, add policy-bindings, add prompts
This commit is contained in:
parent
df1cb88abc
commit
e68352b09c
|
@ -52,23 +52,63 @@
|
||||||
{% trans 'Property Mappings' %}
|
{% trans 'Property Mappings' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pf-c-nav__item">
|
<li class="pf-c-nav__item pf-m-expandable pf-m-expanded pf-m-current">
|
||||||
<a href="{% url 'passbook_admin:flows' %}"
|
<a href="#" class="pf-c-nav__link" aria-expanded="true">{% trans 'Flows' %}
|
||||||
class="pf-c-nav__link {% is_active 'passbook_admin:flows' 'passbook_admin:flow-create' 'passbook_admin:flow-update' 'passbook_admin:flow-delete' %}">
|
<span class="pf-c-nav__toggle">
|
||||||
{% trans 'Flows' %}
|
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
<section class="pf-c-nav__subnav">
|
||||||
|
<ul class="pf-c-nav__simple-list">
|
||||||
|
<li class="pf-c-nav__item">
|
||||||
|
<a href="{% url 'passbook_admin:flows' %}"
|
||||||
|
class="pf-c-nav__link {% is_active 'passbook_admin:flows' 'passbook_admin:flow-create' 'passbook_admin:flow-update' 'passbook_admin:flow-delete' %}">
|
||||||
|
{% trans 'Flows' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="pf-c-nav__item">
|
||||||
|
<a href="{% url 'passbook_admin:stages' %}"
|
||||||
|
class="pf-c-nav__link {% is_active 'passbook_admin:stages' 'passbook_admin:stage-create' 'passbook_admin:stage-update' 'passbook_admin:stage-delete' %}">
|
||||||
|
{% trans 'Stages' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="pf-c-nav__item">
|
||||||
|
<a href="{% url 'passbook_admin:stage-prompts' %}"
|
||||||
|
class="pf-c-nav__link {% is_active 'passbook_admin:stage-prompts' 'passbook_admin:stage-prompt-create' 'passbook_admin:stage-prompt-update' 'passbook_admin:stage-prompt-delete' %}">
|
||||||
|
{% trans 'Stage Prompts' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="pf-c-nav__item">
|
||||||
|
<a href="{% url 'passbook_admin:stage-bindings' %}"
|
||||||
|
class="pf-c-nav__link {% is_active 'passbook_admin:stage-bindings' 'passbook_admin:stage-binding-create' 'passbook_admin:stage-binding-update' 'passbook_admin:stage-binding-delete' %}">
|
||||||
|
{% trans 'Bindings' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
</li>
|
</li>
|
||||||
<li class="pf-c-nav__item">
|
<li class="pf-c-nav__item pf-m-expandable pf-m-expanded pf-m-current">
|
||||||
<a href="{% url 'passbook_admin:stages' %}"
|
<a href="#" class="pf-c-nav__link" aria-expanded="true">{% trans 'Policies and Bindings' %}
|
||||||
class="pf-c-nav__link {% is_active 'passbook_admin:stages' 'passbook_admin:stage-create' 'passbook_admin:stage-update' 'passbook_admin:stage-delete' %}">
|
<span class="pf-c-nav__toggle">
|
||||||
{% trans 'Stages' %}
|
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||||
</a>
|
</span>
|
||||||
</li>
|
|
||||||
<li class="pf-c-nav__item">
|
|
||||||
<a href="{% url 'passbook_admin:policies' %}"
|
|
||||||
class="pf-c-nav__link {% is_active 'passbook_admin:policies' 'passbook_admin:policy-create' 'passbook_admin:policy-update' 'passbook_admin:policy-delete' 'passbook_admin:policy-test' %}">
|
|
||||||
{% trans 'Policies' %}
|
|
||||||
</a>
|
</a>
|
||||||
|
<section class="pf-c-nav__subnav" aria-labelledby="subnav-title1">
|
||||||
|
<ul class="pf-c-nav__simple-list">
|
||||||
|
<li class="pf-c-nav__item">
|
||||||
|
<a href="{% url 'passbook_admin:policies' %}"
|
||||||
|
class="pf-c-nav__link {% is_active 'passbook_admin:policies' 'passbook_admin:policy-create' 'passbook_admin:policy-update' 'passbook_admin:policy-delete' 'passbook_admin:policy-test' %}">
|
||||||
|
{% trans 'Policies' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="pf-c-nav__item">
|
||||||
|
<a href="{% url 'passbook_admin:policies-bindings' %}"
|
||||||
|
class="pf-c-nav__link {% is_active 'passbook_admin:policies-bindings' 'passbook_admin:policy-binding-create' 'passbook_admin:policy-binding-update' 'passbook_admin:policy-binding-delete' %}">
|
||||||
|
{% trans 'Bindings' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
</li>
|
</li>
|
||||||
<li class="pf-c-nav__item">
|
<li class="pf-c-nav__item">
|
||||||
<a href="{% url 'passbook_admin:certificate_key_pair' %}"
|
<a href="{% url 'passbook_admin:certificate_key_pair' %}"
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
{% extends "administration/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load passbook_utils %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="pf-c-page__main-section pf-m-light">
|
||||||
|
<div class="pf-c-content">
|
||||||
|
<h1>
|
||||||
|
<i class="pf-icon pf-icon-infrastructure"></i>
|
||||||
|
{% trans 'Stage Bindings' %}
|
||||||
|
</h1>
|
||||||
|
<p>{% trans "Bind existing Stages to Flows." %}</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
|
<div class="pf-c-card">
|
||||||
|
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-top">
|
||||||
|
<div class="pf-c-toolbar__action-group">
|
||||||
|
<a href="{% url 'passbook_admin:stage-binding-create' %}?back={{ request.get_full_path }}"
|
||||||
|
class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||||
|
</div>
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
</div>
|
||||||
|
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
|
||||||
|
<thead>
|
||||||
|
<tr role="row">
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Order' %}</th>
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Stage Type' %}</th>
|
||||||
|
<th role="cell"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody role="rowgroup">
|
||||||
|
{% for binding in object_list %}
|
||||||
|
<tr role="row">
|
||||||
|
<td role="cell">
|
||||||
|
<span>
|
||||||
|
{{ binding.order }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<th role="columnheader">
|
||||||
|
<div>
|
||||||
|
<div>{{ binding.stage.name }}</div>
|
||||||
|
<small>
|
||||||
|
{% blocktrans with flow=binding.flow %}
|
||||||
|
Bound to {{ flow }}.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td role="cell">
|
||||||
|
<span>
|
||||||
|
{{ binding.stage }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:stage-binding-update' pk=binding.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
|
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:stage-binding-delete' pk=binding.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom">
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,66 @@
|
||||||
|
{% extends "administration/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load passbook_utils %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="pf-c-page__main-section pf-m-light">
|
||||||
|
<div class="pf-c-content">
|
||||||
|
<h1>
|
||||||
|
<i class="pf-icon pf-icon-infrastructure"></i>
|
||||||
|
{% trans 'Policy Bindings' %}
|
||||||
|
</h1>
|
||||||
|
<p>{% trans "Bind existing Policies to Models accepting policies." %}</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
|
<div class="pf-c-card">
|
||||||
|
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-top">
|
||||||
|
<div class="pf-c-toolbar__action-group">
|
||||||
|
<a href="{% url 'passbook_admin:policy-binding-create' %}?back={{ request.get_full_path }}"
|
||||||
|
class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||||
|
</div>
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
</div>
|
||||||
|
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
|
||||||
|
<thead>
|
||||||
|
<tr role="row">
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Type' %}</th>
|
||||||
|
<th role="cell"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody role="rowgroup">
|
||||||
|
{% for binding in object_list %}
|
||||||
|
<tr role="row">
|
||||||
|
<th role="columnheader">
|
||||||
|
<div>
|
||||||
|
<div>{{ binding.name }}</div>
|
||||||
|
{% if not binding.bindings.exists %}
|
||||||
|
<i class="pf-icon pf-icon-warning-triangle"></i>
|
||||||
|
<small>{% trans 'Warning: Policy is not assigned.' %}</small>
|
||||||
|
{% else %}
|
||||||
|
<i class="pf-icon pf-icon-ok"></i>
|
||||||
|
<small>{% blocktrans with object_count=binding.bindings.all|length %}Assigned to {{ object_count }} objects.{% endblocktrans %}</small>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td role="cell">
|
||||||
|
<span>
|
||||||
|
{{ binding|verbose_name }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:policy-binding-update' pk=binding.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
|
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:policy-binding-delete' pk=binding.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom">
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
|
@ -40,7 +40,6 @@
|
||||||
<tr role="row">
|
<tr role="row">
|
||||||
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
||||||
<th role="columnheader" scope="col">{% trans 'Flows' %}</th>
|
<th role="columnheader" scope="col">{% trans 'Flows' %}</th>
|
||||||
<th role="columnheader" scope="col">{% trans 'Enabled' %}</th>
|
|
||||||
<th role="cell"></th>
|
<th role="cell"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -60,11 +59,6 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
<td role="cell">
|
|
||||||
<span>
|
|
||||||
{{ stage.enabled }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:stage-update' pk=stage.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:stage-update' pk=stage.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:stage-delete' pk=stage.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:stage-delete' pk=stage.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
{% extends "administration/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load passbook_utils %}
|
||||||
|
{% load admin_reflection %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="pf-c-page__main-section pf-m-light">
|
||||||
|
<div class="pf-c-content">
|
||||||
|
<h1>
|
||||||
|
<i class="pf-icon pf-icon-plugged"></i>
|
||||||
|
{% trans 'Prompts' %}
|
||||||
|
</h1>
|
||||||
|
<p>{% trans "Prompts that can be used for Prompt Stages." %}</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
|
<div class="pf-c-card">
|
||||||
|
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-top">
|
||||||
|
<div class="pf-c-toolbar__action-group">
|
||||||
|
<a href="{% url 'passbook_admin:stage-prompt-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||||
|
</div>
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
</div>
|
||||||
|
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
|
||||||
|
<thead>
|
||||||
|
<tr role="row">
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Flows' %}</th>
|
||||||
|
<th role="cell"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody role="rowgroup">
|
||||||
|
{% for prompt in object_list %}
|
||||||
|
<tr role="row">
|
||||||
|
<th role="columnheader">
|
||||||
|
<div>
|
||||||
|
<div>{{ prompt.field_key }}</div>
|
||||||
|
<small>{{ prompt|verbose_name }}</small>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td role="cell">
|
||||||
|
<ul>
|
||||||
|
{% for flow in prompt.flow_set.all %}
|
||||||
|
<li><a href="{% url 'passbook_admin:flow-update' pk=flow.pk %}">{{ flow.slug }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:prompt-update' pk=prompt.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
|
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:prompt-delete' pk=prompt.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
|
{% get_links prompt as links %}
|
||||||
|
{% for name, href in links.items %}
|
||||||
|
<a class="pf-c-button pf-m-tertiary" href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom">
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
|
@ -10,11 +10,14 @@ from passbook.admin.views import (
|
||||||
groups,
|
groups,
|
||||||
invitations,
|
invitations,
|
||||||
overview,
|
overview,
|
||||||
policy,
|
policies,
|
||||||
|
policies_bindings,
|
||||||
property_mapping,
|
property_mapping,
|
||||||
providers,
|
providers,
|
||||||
sources,
|
sources,
|
||||||
stages,
|
stages,
|
||||||
|
stages_bindings,
|
||||||
|
stages_prompts,
|
||||||
users,
|
users,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,20 +56,43 @@ urlpatterns = [
|
||||||
name="source-delete",
|
name="source-delete",
|
||||||
),
|
),
|
||||||
# Policies
|
# Policies
|
||||||
path("policies/", policy.PolicyListView.as_view(), name="policies"),
|
path("policies/", policies.PolicyListView.as_view(), name="policies"),
|
||||||
path("policies/create/", policy.PolicyCreateView.as_view(), name="policy-create"),
|
path("policies/create/", policies.PolicyCreateView.as_view(), name="policy-create"),
|
||||||
path(
|
path(
|
||||||
"policies/<uuid:pk>/update/",
|
"policies/<uuid:pk>/update/",
|
||||||
policy.PolicyUpdateView.as_view(),
|
policies.PolicyUpdateView.as_view(),
|
||||||
name="policy-update",
|
name="policy-update",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"policies/<uuid:pk>/delete/",
|
"policies/<uuid:pk>/delete/",
|
||||||
policy.PolicyDeleteView.as_view(),
|
policies.PolicyDeleteView.as_view(),
|
||||||
name="policy-delete",
|
name="policy-delete",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"policies/<uuid:pk>/test/", policy.PolicyTestView.as_view(), name="policy-test"
|
"policies/<uuid:pk>/test/",
|
||||||
|
policies.PolicyTestView.as_view(),
|
||||||
|
name="policy-test",
|
||||||
|
),
|
||||||
|
# Policy bindings
|
||||||
|
path(
|
||||||
|
"policies/bindings/",
|
||||||
|
policies_bindings.PolicyBindingListView.as_view(),
|
||||||
|
name="policies-bindings",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"policies/bindings/create/",
|
||||||
|
policies_bindings.PolicyBindingCreateView.as_view(),
|
||||||
|
name="policy-binding-create",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"policies/bindings/<uuid:pk>/update/",
|
||||||
|
policies_bindings.PolicyBindingUpdateView.as_view(),
|
||||||
|
name="policy-binding-update",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"policies/bindings/<uuid:pk>/delete/",
|
||||||
|
policies_bindings.PolicyBindingDeleteView.as_view(),
|
||||||
|
name="policy-binding-delete",
|
||||||
),
|
),
|
||||||
# Providers
|
# Providers
|
||||||
path("providers/", providers.ProviderListView.as_view(), name="providers"),
|
path("providers/", providers.ProviderListView.as_view(), name="providers"),
|
||||||
|
@ -98,6 +124,48 @@ urlpatterns = [
|
||||||
stages.StageDeleteView.as_view(),
|
stages.StageDeleteView.as_view(),
|
||||||
name="stage-delete",
|
name="stage-delete",
|
||||||
),
|
),
|
||||||
|
# Stage bindings
|
||||||
|
path(
|
||||||
|
"stages/bindings/",
|
||||||
|
stages_bindings.StageBindingListView.as_view(),
|
||||||
|
name="stage-bindings",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"stages/bindings/create/",
|
||||||
|
stages_bindings.StageBindingCreateView.as_view(),
|
||||||
|
name="stage-binding-create",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"stages/bindings/<uuid:pk>/update/",
|
||||||
|
stages_bindings.StageBindingUpdateView.as_view(),
|
||||||
|
name="stage-binding-update",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"stages/bindings/<uuid:pk>/delete/",
|
||||||
|
stages_bindings.StageBindingDeleteView.as_view(),
|
||||||
|
name="stage-binding-delete",
|
||||||
|
),
|
||||||
|
# Stage Prompts
|
||||||
|
path(
|
||||||
|
"stages/prompts/",
|
||||||
|
stages_prompts.PromptListView.as_view(),
|
||||||
|
name="stage-prompts",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"stages/prompts/create/",
|
||||||
|
stages_prompts.PromptCreateView.as_view(),
|
||||||
|
name="stage-prompt-create",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"stages/prompts/<uuid:pk>/update/",
|
||||||
|
stages_prompts.PromptUpdateView.as_view(),
|
||||||
|
name="stage-prompt-update",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"stages/prompts/<uuid:pk>/delete/",
|
||||||
|
stages_prompts.PromptDeleteView.as_view(),
|
||||||
|
name="stage-prompt-delete",
|
||||||
|
),
|
||||||
# Flows
|
# Flows
|
||||||
path("flows/", flows.FlowListView.as_view(), name="flows"),
|
path("flows/", flows.FlowListView.as_view(), name="flows"),
|
||||||
path("flows/create/", flows.FlowCreateView.as_view(), name="flow-create",),
|
path("flows/create/", flows.FlowCreateView.as_view(), name="flow-create",),
|
||||||
|
|
|
@ -23,7 +23,7 @@ class PolicyListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
||||||
"""Show list of all policies"""
|
"""Show list of all policies"""
|
||||||
|
|
||||||
model = Policy
|
model = Policy
|
||||||
permission_required = "passbook_core.view_policy"
|
permission_required = "passbook_policies.view_policy"
|
||||||
paginate_by = 10
|
paginate_by = 10
|
||||||
ordering = "order"
|
ordering = "order"
|
||||||
template_name = "administration/policy/list.html"
|
template_name = "administration/policy/list.html"
|
||||||
|
@ -47,7 +47,7 @@ class PolicyCreateView(
|
||||||
"""Create new Policy"""
|
"""Create new Policy"""
|
||||||
|
|
||||||
model = Policy
|
model = Policy
|
||||||
permission_required = "passbook_core.add_policy"
|
permission_required = "passbook_policies.add_policy"
|
||||||
|
|
||||||
template_name = "generic/create.html"
|
template_name = "generic/create.html"
|
||||||
success_url = reverse_lazy("passbook_admin:policies")
|
success_url = reverse_lazy("passbook_admin:policies")
|
||||||
|
@ -74,7 +74,7 @@ class PolicyUpdateView(
|
||||||
"""Update policy"""
|
"""Update policy"""
|
||||||
|
|
||||||
model = Policy
|
model = Policy
|
||||||
permission_required = "passbook_core.change_policy"
|
permission_required = "passbook_policies.change_policy"
|
||||||
|
|
||||||
template_name = "generic/update.html"
|
template_name = "generic/update.html"
|
||||||
success_url = reverse_lazy("passbook_admin:policies")
|
success_url = reverse_lazy("passbook_admin:policies")
|
||||||
|
@ -104,7 +104,7 @@ class PolicyDeleteView(
|
||||||
"""Delete policy"""
|
"""Delete policy"""
|
||||||
|
|
||||||
model = Policy
|
model = Policy
|
||||||
permission_required = "passbook_core.delete_policy"
|
permission_required = "passbook_policies.delete_policy"
|
||||||
|
|
||||||
template_name = "generic/delete.html"
|
template_name = "generic/delete.html"
|
||||||
success_url = reverse_lazy("passbook_admin:policies")
|
success_url = reverse_lazy("passbook_admin:policies")
|
||||||
|
@ -125,7 +125,7 @@ class PolicyTestView(LoginRequiredMixin, DetailView, PermissionRequiredMixin, Fo
|
||||||
|
|
||||||
model = Policy
|
model = Policy
|
||||||
form_class = PolicyTestForm
|
form_class = PolicyTestForm
|
||||||
permission_required = "passbook_core.view_policy"
|
permission_required = "passbook_policies.view_policy"
|
||||||
template_name = "administration/policy/test.html"
|
template_name = "administration/policy/test.html"
|
||||||
object = None
|
object = None
|
||||||
|
|
100
passbook/admin/views/policies_bindings.py
Normal file
100
passbook/admin/views/policies_bindings.py
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
"""passbook PolicyBinding administration"""
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.contrib.auth.mixins import (
|
||||||
|
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||||
|
)
|
||||||
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.views.generic import DeleteView, ListView, UpdateView
|
||||||
|
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||||
|
|
||||||
|
from passbook.lib.utils.reflection import path_to_class
|
||||||
|
from passbook.lib.views import CreateAssignPermView
|
||||||
|
from passbook.policies.forms import PolicyBindingForm
|
||||||
|
from passbook.policies.models import PolicyBinding
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyBindingListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
||||||
|
"""Show list of all policies"""
|
||||||
|
|
||||||
|
model = PolicyBinding
|
||||||
|
permission_required = "passbook_policies.view_policybinding"
|
||||||
|
paginate_by = 10
|
||||||
|
ordering = "order"
|
||||||
|
template_name = "administration/policybinding/list.html"
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyBindingCreateView(
|
||||||
|
SuccessMessageMixin,
|
||||||
|
LoginRequiredMixin,
|
||||||
|
DjangoPermissionRequiredMixin,
|
||||||
|
CreateAssignPermView,
|
||||||
|
):
|
||||||
|
"""Create new PolicyBinding"""
|
||||||
|
|
||||||
|
model = PolicyBinding
|
||||||
|
permission_required = "passbook_policies.add_policybinding"
|
||||||
|
form_class = PolicyBindingForm
|
||||||
|
|
||||||
|
template_name = "generic/create.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:policies")
|
||||||
|
success_message = _("Successfully created PolicyBinding")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
kwargs = super().get_context_data(**kwargs)
|
||||||
|
form_cls = self.get_form_class()
|
||||||
|
if hasattr(form_cls, "template_name"):
|
||||||
|
kwargs["base_template"] = form_cls.template_name
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyBindingUpdateView(
|
||||||
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
||||||
|
):
|
||||||
|
"""Update policybinding"""
|
||||||
|
|
||||||
|
model = PolicyBinding
|
||||||
|
permission_required = "passbook_policies.change_policybinding"
|
||||||
|
form_class = PolicyBindingForm
|
||||||
|
|
||||||
|
template_name = "generic/update.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:policies")
|
||||||
|
success_message = _("Successfully updated PolicyBinding")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
kwargs = super().get_context_data(**kwargs)
|
||||||
|
form_cls = self.get_form_class()
|
||||||
|
if hasattr(form_cls, "template_name"):
|
||||||
|
kwargs["base_template"] = form_cls.template_name
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def get_form_class(self):
|
||||||
|
form_class_path = self.get_object().form
|
||||||
|
form_class = path_to_class(form_class_path)
|
||||||
|
return form_class
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
return (
|
||||||
|
PolicyBinding.objects.filter(pk=self.kwargs.get("pk"))
|
||||||
|
.select_subclasses()
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyBindingDeleteView(
|
||||||
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView
|
||||||
|
):
|
||||||
|
"""Delete policybinding"""
|
||||||
|
|
||||||
|
model = PolicyBinding
|
||||||
|
permission_required = "passbook_policies.delete_policybinding"
|
||||||
|
|
||||||
|
template_name = "generic/delete.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:policies")
|
||||||
|
success_message = _("Successfully deleted PolicyBinding")
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
messages.success(self.request, self.success_message)
|
||||||
|
return super().delete(request, *args, **kwargs)
|
87
passbook/admin/views/stages_bindings.py
Normal file
87
passbook/admin/views/stages_bindings.py
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
"""passbook StageBinding administration"""
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.contrib.auth.mixins import (
|
||||||
|
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||||
|
)
|
||||||
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.views.generic import DeleteView, ListView, UpdateView
|
||||||
|
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||||
|
|
||||||
|
from passbook.flows.forms import FlowStageBindingForm
|
||||||
|
from passbook.flows.models import FlowStageBinding
|
||||||
|
from passbook.lib.views import CreateAssignPermView
|
||||||
|
|
||||||
|
|
||||||
|
class StageBindingListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
||||||
|
"""Show list of all flows"""
|
||||||
|
|
||||||
|
model = FlowStageBinding
|
||||||
|
permission_required = "passbook_flows.view_flowstagebinding"
|
||||||
|
paginate_by = 10
|
||||||
|
ordering = "order"
|
||||||
|
template_name = "administration/flowstagebinding/list.html"
|
||||||
|
|
||||||
|
|
||||||
|
class StageBindingCreateView(
|
||||||
|
SuccessMessageMixin,
|
||||||
|
LoginRequiredMixin,
|
||||||
|
DjangoPermissionRequiredMixin,
|
||||||
|
CreateAssignPermView,
|
||||||
|
):
|
||||||
|
"""Create new StageBinding"""
|
||||||
|
|
||||||
|
model = FlowStageBinding
|
||||||
|
permission_required = "passbook_flows.add_flowstagebinding"
|
||||||
|
form_class = FlowStageBindingForm
|
||||||
|
|
||||||
|
template_name = "generic/create.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:flows")
|
||||||
|
success_message = _("Successfully created StageBinding")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
kwargs = super().get_context_data(**kwargs)
|
||||||
|
form_cls = self.get_form_class()
|
||||||
|
if hasattr(form_cls, "template_name"):
|
||||||
|
kwargs["base_template"] = form_cls.template_name
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
class StageBindingUpdateView(
|
||||||
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
||||||
|
):
|
||||||
|
"""Update FlowStageBinding"""
|
||||||
|
|
||||||
|
model = FlowStageBinding
|
||||||
|
permission_required = "passbook_flows.change_flowstagebinding"
|
||||||
|
form_class = FlowStageBindingForm
|
||||||
|
|
||||||
|
template_name = "generic/update.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:flows")
|
||||||
|
success_message = _("Successfully updated StageBinding")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
kwargs = super().get_context_data(**kwargs)
|
||||||
|
form_cls = self.get_form_class()
|
||||||
|
if hasattr(form_cls, "template_name"):
|
||||||
|
kwargs["base_template"] = form_cls.template_name
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
class StageBindingDeleteView(
|
||||||
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView
|
||||||
|
):
|
||||||
|
"""Delete FlowStageBinding"""
|
||||||
|
|
||||||
|
model = FlowStageBinding
|
||||||
|
permission_required = "passbook_flows.delete_flowstagebinding"
|
||||||
|
|
||||||
|
template_name = "generic/delete.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:flows")
|
||||||
|
success_message = _("Successfully deleted FlowStageBinding")
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
messages.success(self.request, self.success_message)
|
||||||
|
return super().delete(request, *args, **kwargs)
|
77
passbook/admin/views/stages_prompts.py
Normal file
77
passbook/admin/views/stages_prompts.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
"""passbook Prompt administration"""
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.contrib.auth.mixins import (
|
||||||
|
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||||
|
)
|
||||||
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.views.generic import DeleteView, ListView, UpdateView
|
||||||
|
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||||
|
|
||||||
|
from passbook.lib.views import CreateAssignPermView
|
||||||
|
from passbook.stages.prompt.forms import PromptAdminForm
|
||||||
|
from passbook.stages.prompt.models import Prompt
|
||||||
|
|
||||||
|
|
||||||
|
class PromptListView(LoginRequiredMixin, PermissionListMixin, ListView):
|
||||||
|
"""Show list of all prompts"""
|
||||||
|
|
||||||
|
model = Prompt
|
||||||
|
permission_required = "passbook_stages_prompt.view_prompt"
|
||||||
|
ordering = "field_key"
|
||||||
|
paginate_by = 40
|
||||||
|
template_name = "administration/stage_prompt/list.html"
|
||||||
|
|
||||||
|
|
||||||
|
class PromptCreateView(
|
||||||
|
SuccessMessageMixin,
|
||||||
|
LoginRequiredMixin,
|
||||||
|
DjangoPermissionRequiredMixin,
|
||||||
|
CreateAssignPermView,
|
||||||
|
):
|
||||||
|
"""Create new Prompt"""
|
||||||
|
|
||||||
|
model = Prompt
|
||||||
|
form_class = PromptAdminForm
|
||||||
|
permission_required = "passbook_stages_prompt.add_prompt"
|
||||||
|
|
||||||
|
template_name = "generic/create.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:prompts")
|
||||||
|
success_message = _("Successfully created Prompt")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
kwargs["type"] = "Prompt"
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class PromptUpdateView(
|
||||||
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, UpdateView
|
||||||
|
):
|
||||||
|
"""Update prompt"""
|
||||||
|
|
||||||
|
model = Prompt
|
||||||
|
form_class = PromptAdminForm
|
||||||
|
permission_required = "passbook_stages_prompt.change_prompt"
|
||||||
|
|
||||||
|
template_name = "generic/update.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:prompts")
|
||||||
|
success_message = _("Successfully updated Prompt")
|
||||||
|
|
||||||
|
|
||||||
|
class PromptDeleteView(
|
||||||
|
SuccessMessageMixin, LoginRequiredMixin, PermissionRequiredMixin, DeleteView
|
||||||
|
):
|
||||||
|
"""Delete prompt"""
|
||||||
|
|
||||||
|
model = Prompt
|
||||||
|
permission_required = "passbook_stages_prompt.delete_prompt"
|
||||||
|
|
||||||
|
template_name = "generic/delete.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:prompts")
|
||||||
|
success_message = _("Successfully deleted Prompt")
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
messages.success(self.request, self.success_message)
|
||||||
|
return super().delete(request, *args, **kwargs)
|
|
@ -11,7 +11,7 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
# ("passbook_policies", "0001_initial"),
|
("passbook_policies", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|
|
@ -76,7 +76,7 @@ def create_default_invalidation_flow(
|
||||||
return
|
return
|
||||||
|
|
||||||
if not UserLogoutStage.objects.using(db_alias).exists():
|
if not UserLogoutStage.objects.using(db_alias).exists():
|
||||||
UserLogoutStage.objects.using(db_alias).create(name="authentication")
|
UserLogoutStage.objects.using(db_alias).create(name="logout")
|
||||||
|
|
||||||
flow = Flow.objects.using(db_alias).create(
|
flow = Flow.objects.using(db_alias).create(
|
||||||
name="default-invalidation-flow",
|
name="default-invalidation-flow",
|
||||||
|
|
|
@ -89,6 +89,8 @@ class FlowStageBinding(PolicyBindingModel, UUIDModel):
|
||||||
|
|
||||||
order = models.IntegerField()
|
order = models.IntegerField()
|
||||||
|
|
||||||
|
objects = InheritanceManager()
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"Flow Stage Binding #{self.order} {self.flow} -> {self.stage}"
|
return f"Flow Stage Binding #{self.order} {self.flow} -> {self.stage}"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,25 @@
|
||||||
"""General fields"""
|
"""General fields"""
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
from passbook.policies.models import PolicyBinding, PolicyBindingModel
|
||||||
|
|
||||||
GENERAL_FIELDS = ["name", "negate", "order", "timeout"]
|
GENERAL_FIELDS = ["name", "negate", "order", "timeout"]
|
||||||
GENERAL_SERIALIZER_FIELDS = ["pk", "name", "negate", "order", "timeout"]
|
GENERAL_SERIALIZER_FIELDS = ["pk", "name", "negate", "order", "timeout"]
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyBindingForm(forms.ModelForm):
|
||||||
|
"""Form to edit Policy to PolicyBindingModel Binding"""
|
||||||
|
|
||||||
|
target = forms.ModelChoiceField(
|
||||||
|
queryset=PolicyBindingModel.objects.all().select_subclasses()
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = PolicyBinding
|
||||||
|
fields = [
|
||||||
|
"enabled",
|
||||||
|
"policy",
|
||||||
|
"target",
|
||||||
|
"order",
|
||||||
|
]
|
||||||
|
|
|
@ -15,6 +15,8 @@ class PolicyBindingModel(models.Model):
|
||||||
"Policy", through="PolicyBinding", related_name="bindings", blank=True
|
"Policy", through="PolicyBinding", related_name="bindings", blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = InheritanceManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
verbose_name = _("Policy Binding Model")
|
verbose_name = _("Policy Binding Model")
|
||||||
|
|
|
@ -19,6 +19,25 @@ class PromptStageForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PromptAdminForm(forms.ModelForm):
|
||||||
|
"""Form to edit Prompt instances for admins"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = Prompt
|
||||||
|
fields = [
|
||||||
|
"field_key",
|
||||||
|
"label",
|
||||||
|
"type",
|
||||||
|
"required",
|
||||||
|
"placeholder",
|
||||||
|
]
|
||||||
|
widgets = {
|
||||||
|
"label": forms.TextInput(),
|
||||||
|
"placeholder": forms.TextInput(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class PromptForm(forms.Form):
|
class PromptForm(forms.Form):
|
||||||
"""Dynamically created form based on PromptStage"""
|
"""Dynamically created form based on PromptStage"""
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,17 @@ class UserWriteStageView(AuthenticationStage):
|
||||||
user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
setter_name = f"set_{key}"
|
setter_name = f"set_{key}"
|
||||||
|
# Check if user has a setter for this key, like set_password
|
||||||
if hasattr(user, setter_name):
|
if hasattr(user, setter_name):
|
||||||
setter = getattr(user, setter_name)
|
setter = getattr(user, setter_name)
|
||||||
if callable(setter):
|
if callable(setter):
|
||||||
setter(value)
|
setter(value)
|
||||||
else:
|
# User has this key already
|
||||||
|
elif hasattr(user, key):
|
||||||
setattr(user, key, value)
|
setattr(user, key, value)
|
||||||
|
# Otherwise we just save it as custom attribute
|
||||||
|
else:
|
||||||
|
user.attributes[key] = value
|
||||||
user.save()
|
user.save()
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"Updated existing user", user=user, flow_slug=self.executor.flow.slug,
|
"Updated existing user", user=user, flow_slug=self.executor.flow.slug,
|
||||||
|
|
Reference in a new issue