commit
2f43b5b5ec
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
@ -1 +1 @@
|
|||
custom: ["https://www.paypal.me/beryju"]
|
||||
github: [BeryJu]
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -27,7 +27,6 @@ media
|
|||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
|
|
|
@ -13,9 +13,9 @@ passbook is an open-source Identity Provider focused on flexibility and versatil
|
|||
|
||||
## Installation
|
||||
|
||||
For small/test setups it is recommended to use docker-compose, see the [documentation](https://passbook.beryju.org/website/docs/installation/docker-compose/)
|
||||
For small/test setups it is recommended to use docker-compose, see the [documentation](https://passbook.beryju.org/docs/installation/docker-compose/)
|
||||
|
||||
For bigger setups, there is a Helm Chart in the `helm/` directory. This is documented [here](https://passbook.beryju.org/website/docs/installation/kubernetes/)
|
||||
For bigger setups, there is a Helm Chart in the `helm/` directory. This is documented [here](https://passbook.beryju.org/docs/installation/kubernetes/)
|
||||
|
||||
## Screenshots
|
||||
|
||||
|
|
|
@ -261,7 +261,7 @@ stages:
|
|||
script: |
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
pipenv install --dev --python python3.9
|
||||
- task: DockerCompose@0
|
||||
displayName: Run ChromeDriver
|
||||
inputs:
|
||||
|
|
|
@ -36,15 +36,15 @@ class CodeMirrorWidget(forms.Textarea):
|
|||
# CodeMirror mode to enable
|
||||
mode: str
|
||||
|
||||
template_name = "fields/codemirror.html"
|
||||
|
||||
def __init__(self, *args, mode="yaml", **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.mode = mode
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
attrs = kwargs.setdefault("attrs", {})
|
||||
attrs.setdefault("class", "")
|
||||
attrs["class"] += " codemirror"
|
||||
attrs["data-cm-mode"] = self.mode
|
||||
attrs["mode"] = self.mode
|
||||
return super().render(*args, **kwargs)
|
||||
|
||||
|
||||
|
|
18
passbook/admin/forms/overview.py
Normal file
18
passbook/admin/forms/overview.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
"""Forms for modals on overview page"""
|
||||
from django import forms
|
||||
|
||||
|
||||
class PolicyCacheClearForm(forms.Form):
|
||||
"""Form to clear Policy cache"""
|
||||
|
||||
title = "Clear Policy cache"
|
||||
body = """Are you sure you want to clear the policy cache?
|
||||
This will cause all policies to be re-evaluated on their next usage."""
|
||||
|
||||
|
||||
class FlowCacheClearForm(forms.Form):
|
||||
"""Form to clear Flow cache"""
|
||||
|
||||
title = "Clear Flow cache"
|
||||
body = """Are you sure you want to clear the flow cache?
|
||||
This will cause all flows to be re-evaluated on their next usage."""
|
|
@ -20,7 +20,15 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<a href="{% url 'passbook_admin:application-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:application-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -29,6 +37,7 @@
|
|||
<thead>
|
||||
<tr role="row">
|
||||
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Slug' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Provider' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Provider Type' %}</th>
|
||||
<th role="cell"></th>
|
||||
|
@ -45,6 +54,9 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<code>{{ application.slug }}</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ application.get_provider }}
|
||||
|
@ -56,8 +68,18 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:application-update' pk=application.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:application-delete' pk=application.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:application-update' pk=application.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:application-delete' pk=application.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -85,7 +107,12 @@
|
|||
{% trans 'Currently no applications exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_admin:application-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:application-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,180 +1,5 @@
|
|||
{% extends "base/page.html" %}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% load passbook_is_active %}
|
||||
{% load passbook_utils %}
|
||||
|
||||
{% block head %}
|
||||
{{ block.super }}
|
||||
<script src="{% static 'node_modules/codemirror/lib/codemirror.js' %}"></script>
|
||||
<script src="{% static 'node_modules/codemirror/addon/display/autorefresh.js' %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'node_modules/codemirror/lib/codemirror.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'node_modules/codemirror/theme/monokai.css' %}">
|
||||
<script src="{% static 'node_modules/codemirror/mode/xml/xml.js' %}"></script>
|
||||
<script src="{% static 'node_modules/codemirror/mode/yaml/yaml.js' %}"></script>
|
||||
<script src="{% static 'node_modules/codemirror/mode/python/python.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="pf-c-page__sidebar">
|
||||
<div class="pf-c-page__sidebar-body">
|
||||
<nav class="pf-c-nav" id="page-default-nav-example-primary-nav" aria-label="Global">
|
||||
<ul class="pf-c-nav__list">
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:overview' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:overview' %}">
|
||||
{% trans 'Overview' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:applications' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:applications' 'passbook_admin:application-create' 'passbook_admin:application-update' 'passbook_admin:application-delete' %}">
|
||||
{% trans 'Applications' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:sources' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:sources' 'passbook_admin:source-create' 'passbook_admin:source-update' 'passbook_admin:source-delete' %}">
|
||||
{% trans 'Sources' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:providers' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:providers' 'passbook_admin:provider-create' 'passbook_admin:provider-update' 'passbook_admin:provider-delete' %}">
|
||||
{% trans 'Providers' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item pf-m-expanded">
|
||||
<a href="#" class="pf-c-nav__link" aria-expanded="true">{% trans 'Outposts' %}
|
||||
<span class="pf-c-nav__toggle">
|
||||
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||
</span>
|
||||
</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:outposts' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:outposts' 'passbook_admin:outpost-create' 'passbook_admin:outpost-update' 'passbook_admin:outpost-delete' %}">
|
||||
{% trans 'Outposts' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:outpost-service-connections' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:outpost-service-connections' 'passbook_admin:outpost-service-connections-create' 'passbook_admin:outpost-service-connections-update' 'passbook_admin:outpost-service-connections-delete' %}">
|
||||
{% trans 'Service Connections' %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:property-mappings' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:property-mappings' 'passbook_admin:property-mapping-create' 'passbook_admin:property-mapping-update' 'passbook_admin:property-mapping-delete' %}">
|
||||
{% trans 'Property Mappings' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item pf-m-expanded">
|
||||
<a href="#" class="pf-c-nav__link" aria-expanded="true">{% trans 'Flows' %}
|
||||
<span class="pf-c-nav__toggle">
|
||||
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||
</span>
|
||||
</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: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>
|
||||
<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 'Prompts' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:stage-invitations' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:stage-invitations' 'passbook_admin:stage-invitation-create' 'passbook_admin:stage-invitation-delete' %}">
|
||||
{% trans 'Invitations' %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</li>
|
||||
<li class="pf-c-nav__item pf-m-expanded">
|
||||
<a href="#" class="pf-c-nav__link" aria-expanded="true">{% trans 'Policies' %}
|
||||
<span class="pf-c-nav__toggle">
|
||||
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||
</span>
|
||||
</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 class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:certificate_key_pair' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:certificate_key_pair' 'passbook_admin:certificatekeypair-create' 'passbook_admin:certificatekeypair-update' 'passbook_admin:certificatekeypair-delete' %}">
|
||||
{% trans 'Certificates' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:tokens' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:tokens' 'passbook_admin:token-delete' %}">
|
||||
{% trans 'Tokens' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:users' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:users' 'passbook_admin:user-create' 'passbook_admin:user-update' 'passbook_admin:user-delete' %}">
|
||||
{% trans 'Users' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:groups' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:groups' 'passbook_admin:group-create' 'passbook_admin:group-update' 'passbook_admin:group-delete' %}">
|
||||
{% trans 'Groups' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_admin:tasks' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_admin:tasks' %}">
|
||||
{% trans 'System Tasks' %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -20,7 +20,15 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<a href="{% url 'passbook_admin:certificatekeypair-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:certificatekeypair-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -31,7 +39,6 @@
|
|||
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Private Key available' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Fingerprint' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Provider Type' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -53,13 +60,21 @@
|
|||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ kp.fingerprint }}
|
||||
</span>
|
||||
<code>{{ kp.fingerprint }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:certificatekeypair-update' pk=kp.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:certificatekeypair-delete' pk=kp.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:certificatekeypair-update' pk=kp.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:certificatekeypair-delete' pk=kp.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -87,7 +102,12 @@
|
|||
{% trans 'Currently no certificates exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_admin:certificatekeypair-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:certificatekeypair-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -20,8 +20,21 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<a href="{% url 'passbook_admin:flow-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<a href="{% url 'passbook_admin:flow-import' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-secondary" type="button">{% trans 'Import' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:flow-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:flow-import' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Import' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -41,7 +54,7 @@
|
|||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<div>
|
||||
<div>{{ flow.slug }}</div>
|
||||
<div><code>{{ flow.slug }}</code></div>
|
||||
<small>{{ flow.name }}</small>
|
||||
</div>
|
||||
</th>
|
||||
|
@ -61,10 +74,20 @@
|
|||
</span>
|
||||
</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-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>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:flow-export' pk=flow.pk %}?next={{ request.get_full_path }}">{% trans 'Export' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:flow-update' pk=flow.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:flow-delete' pk=flow.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<a class="pf-c-button pf-m-secondary pb-root-link" href="{% url 'passbook_admin:flow-execute' pk=flow.pk %}?next={{ request.get_full_path }}">{% trans 'Execute' %}</a>
|
||||
<a class="pf-c-button pf-m-secondary pb-root-link" href="{% url 'passbook_admin:flow-export' pk=flow.pk %}?next={{ request.get_full_path }}">{% trans 'Export' %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -92,8 +115,18 @@
|
|||
{% trans 'Currently no flows exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_admin:flow-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<a href="{% url 'passbook_admin:flow-import' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Import' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:flow-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:flow-import' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Import' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load passbook_utils %}
|
||||
|
||||
{% block content %}
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
|
@ -21,8 +20,15 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<a href="{% url 'passbook_admin:group-create' %}?back={{ request.get_full_path }}"
|
||||
class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:group-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -55,8 +61,18 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:group-update' pk=group.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:group-delete' pk=group.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:group-update' pk=group.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:group-delete' pk=group.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -84,7 +100,12 @@
|
|||
{% trans 'Currently no group exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_admin:group-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:group-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="fas fa-map-marker"></i>
|
||||
<i class="pf-icon pf-icon-zone"></i>
|
||||
{% trans 'Outposts' %}
|
||||
</h1>
|
||||
<p>{% trans "Outposts are deployments of passbook components to support different environments and protocols, like reverse proxies." %}</p>
|
||||
|
@ -22,7 +22,15 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<a href="{% url 'passbook_admin:outpost-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:outpost-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -84,8 +92,18 @@
|
|||
{% endif %}
|
||||
{% endwith %}
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:outpost-update' pk=outpost.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:outpost-delete' pk=outpost.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:outpost-update' pk=outpost.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:outpost-delete' pk=outpost.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
{% get_htmls outpost as htmls %}
|
||||
{% for html in htmls %}
|
||||
{{ html|safe }}
|
||||
|
@ -117,7 +135,12 @@
|
|||
{% trans 'Currently no outposts exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_admin:outpost-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:outpost-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -30,16 +30,22 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:outpost-service-connection-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:outpost-service-connection-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -80,8 +86,18 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:outpost-service-connection-update' pk=sc.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:outpost-service-connection-delete' pk=sc.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:outpost-service-connection-update' pk=sc.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:outpost-service-connection-delete' pk=sc.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -109,7 +125,7 @@
|
|||
{% trans 'Currently no service connections exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -117,16 +133,19 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:outpost-service-connection-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:outpost-service-connection-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
<i class="pf-icon pf-icon-server"></i> {% trans 'Logins over the last 24 hours' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-card__body" style="position: relative; height:100%; width:100%">
|
||||
<canvas id="logins-last-metrics"></canvas>
|
||||
<div class="pf-c-card__body">
|
||||
<pb-admin-logins-chart url="{% url 'passbook_api:admin_metrics-list' %}"></pb-admin-logins-chart>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-4-col" style="grid-column-end: span 2;grid-row-end: span 3;">
|
||||
|
@ -179,9 +179,12 @@
|
|||
<div class="pf-c-card__header-main">
|
||||
<i class="pf-icon pf-icon-server"></i> {% trans 'Cached Policies' %}
|
||||
</div>
|
||||
<a data-target="modal" data-modal="clearPolicyCache">
|
||||
<i class="fa fa-trash"> </i>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:overview-clear-policy-cache' %}">
|
||||
<a slot="trigger">
|
||||
<i class="fa fa-trash"> </i>
|
||||
</a>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
{% if cached_policies < 1 %}
|
||||
|
@ -202,9 +205,12 @@
|
|||
<div class="pf-c-card__header-main">
|
||||
<i class="pf-icon pf-icon-server"></i> {% trans 'Cached Flows' %}
|
||||
</div>
|
||||
<a data-target="modal" data-modal="clearFlowCache">
|
||||
<i class="fa fa-trash"> </i>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:overview-clear-flow-cache' %}">
|
||||
<a slot="trigger">
|
||||
<i class="fa fa-trash"> </i>
|
||||
</a>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
{% if cached_flows < 1 %}
|
||||
|
@ -221,117 +227,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="pf-c-backdrop" id="clearPolicyCache" hidden>
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-c-modal-box pf-m-sm" role="dialog">
|
||||
<button data-modal-close class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
|
||||
<i class="fas fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="pf-c-modal-box__header">
|
||||
<h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Clear Policy Cache' %}?</h1>
|
||||
</div>
|
||||
<div class="pf-c-modal-box__body" id="modal-description">
|
||||
<form method="post" id="clear_policies">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="clear_policies">
|
||||
<p>
|
||||
{% blocktrans %}
|
||||
Are you sure you want to clear the policy cache? This will cause all policies to be re-evaluated on their next usage.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-modal-box__footer pf-m-align-left">
|
||||
<button form="clear_policies" class="pf-c-button pf-m-primary" type="submit">{% trans 'Clear' %}</button>
|
||||
<button data-modal-close class="pf-c-button pf-m-link" type="button">{% trans 'Cancel' %}</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pf-c-backdrop" id="clearFlowCache" hidden>
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-c-modal-box pf-m-sm" role="dialog">
|
||||
<button data-modal-close class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
|
||||
<i class="fas fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="pf-c-modal-box__header">
|
||||
<h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Clear Flow Cache' %}?</h1>
|
||||
</div>
|
||||
<div class="pf-c-modal-box__body" id="modal-description">
|
||||
<form method="post" id="clear_flows">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="clear_flows">
|
||||
<p>
|
||||
{% blocktrans %}
|
||||
Are you sure you want to clear the flow cache? This will cause all flows to be re-evaluated on their next usage.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-modal-box__footer pf-m-align-left">
|
||||
<button form="clear_flows" class="pf-c-button pf-m-primary" type="submit">{% trans 'Clear' %}</button>
|
||||
<button data-modal-close class="pf-c-button pf-m-link" type="button">{% trans 'Cancel' %}</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{% static 'node_modules/chart.js/dist/Chart.bundle.min.js' %}"></script>
|
||||
<script>
|
||||
var ctx = document.getElementById('logins-last-metrics').getContext('2d');
|
||||
fetch("{% url 'passbook_api:admin_metrics-list' %}").then(r => r.json()).then(r => {
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
label: 'Failed Logins',
|
||||
backgroundColor: "rgba(201, 25, 11, .5)",
|
||||
spanGaps: true,
|
||||
data: r.logins_failed_per_1h,
|
||||
},
|
||||
{
|
||||
label: 'Successful Logins',
|
||||
backgroundColor: "rgba(189, 229, 184, .5)",
|
||||
spanGaps: true,
|
||||
data: r.logins_per_1h,
|
||||
},
|
||||
]
|
||||
},
|
||||
options: {
|
||||
maintainAspectRatio: false,
|
||||
spanGaps: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
stacked: true,
|
||||
gridLines: {
|
||||
color: "rgba(0, 0, 0, 0)",
|
||||
},
|
||||
type: 'time',
|
||||
offset: true,
|
||||
ticks: {
|
||||
callback: function (value, index, values) {
|
||||
const date = new Date();
|
||||
const delta = (date - values[index].value);
|
||||
const ago = Math.round(delta / 1000 / 3600);
|
||||
return `${ago} Hours ago`;
|
||||
},
|
||||
autoSkip: true,
|
||||
maxTicksLimit: 8
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
stacked: true,
|
||||
gridLines: {
|
||||
color: "rgba(0, 0, 0, 0)",
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -28,16 +28,19 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:policy-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -71,9 +74,24 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:policy-update' pk=policy.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-tertiary" href="{% url 'passbook_admin:policy-test' pk=policy.pk %}?back={{ request.get_full_path }}">{% trans 'Test' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:policy-delete' pk=policy.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-update' pk=policy.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-test' pk=policy.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-tertiary">
|
||||
{% trans 'Test' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-delete' pk=policy.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -101,7 +119,7 @@
|
|||
{% trans 'Currently no policies exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -109,17 +127,19 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item"
|
||||
href="{% url 'passbook_admin:policy-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -9,24 +9,3 @@
|
|||
{% block action %}
|
||||
{% trans 'Test' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block beneath_form %}
|
||||
<div class="pf-c-form__group pf-m-action" style="display: none;" id="loading">
|
||||
<div class="pf-c-form__horizontal-group">
|
||||
<span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading...">
|
||||
<span class="pf-c-spinner__clipper"></span>
|
||||
<span class="pf-c-spinner__lead-ball"></span>
|
||||
<span class="pf-c-spinner__tail-ball"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ block.super }}
|
||||
<script>
|
||||
document.querySelector("form").addEventListener("submit", (e) => {
|
||||
document.getElementById("loading").removeAttribute("style");
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -19,8 +19,15 @@
|
|||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<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>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-binding-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -66,9 +73,19 @@
|
|||
<th role="cell">
|
||||
<div>{{ binding.timeout }}</div>
|
||||
</th>
|
||||
<td class="pb-table-action" role="cell">
|
||||
<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>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-binding-update' pk=binding.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-binding-delete' pk=binding.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -88,7 +105,12 @@
|
|||
<div class="pf-c-empty-state__body">
|
||||
{% trans 'Currently no policy bindings exist. Click the button below to create one.' %}
|
||||
</div>
|
||||
<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>
|
||||
<pb-modal-button href="{% url 'passbook_admin:policy-binding-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -29,17 +29,22 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item"
|
||||
href="{% url 'passbook_admin:property-mapping-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:property-mapping-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -66,8 +71,18 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:property-mapping-update' pk=property_mapping.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:property-mapping-delete' pk=property_mapping.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:property-mapping-update' pk=property_mapping.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:property-mapping-delete' pk=property_mapping.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -95,7 +110,7 @@
|
|||
{% trans 'Currently no property mappings exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdownpb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -103,17 +118,19 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item"
|
||||
href="{% url 'passbook_admin:property-mapping-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:property-mapping-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -30,16 +30,22 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:provider-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:provider-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -77,11 +83,21 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:provider-update' pk=provider.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:provider-delete' pk=provider.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:provider-update' pk=provider.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:provider-delete' pk=provider.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
{% get_links provider 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>
|
||||
<a class="pf-c-button pf-m-tertiary pb-root-link" href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a>
|
||||
{% endfor %}
|
||||
{% get_htmls provider as htmls %}
|
||||
{% for html in htmls %}
|
||||
|
@ -114,7 +130,7 @@
|
|||
{% trans 'Currently no providers exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -122,16 +138,19 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:provider-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:provider-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -30,16 +30,22 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:source-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:source-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -75,11 +81,21 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:source-update' pk=source.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:source-delete' pk=source.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:source-update' pk=source.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:source-delete' pk=source.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
{% get_links source as links %}
|
||||
{% for name, href in links %}
|
||||
<a class="pf-c-button pf-m-tertiary" href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a>
|
||||
<a class="pf-c-button pf-m-tertiary pb-root-link" href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -108,7 +124,7 @@
|
|||
{% trans 'Currently no sources exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -116,16 +132,19 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:source-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:source-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -29,16 +29,22 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:stage-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -63,18 +69,28 @@
|
|||
<td role="cell">
|
||||
<ul>
|
||||
{% for flow in stage.flow_set.all %}
|
||||
<li><a href="{% url 'passbook_admin:flow-update' pk=flow.pk %}">{{ flow.slug }}</a></li>
|
||||
<li>{{ flow.slug }}<</li>
|
||||
{% empty %}
|
||||
<li>-</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:stage-update' pk=stage.stage_uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:stage-delete' pk=stage.stage_uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-update' pk=stage.stage_uuid %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-delete' pk=stage.stage_uuid %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
{% get_links stage 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>
|
||||
<a class="pf-c-button pf-m-tertiary pb-root-link" href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -103,7 +119,7 @@
|
|||
{% trans 'Currently no stages exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pf-c-dropdown">
|
||||
<pb-dropdown class="pf-c-dropdown">
|
||||
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
|
@ -111,17 +127,19 @@
|
|||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<a class="pf-c-dropdown__menu-item"
|
||||
href="{% url 'passbook_admin:stage-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-create' %}?type={{ type }}">
|
||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
||||
{{ name|verbose_name }}<br>
|
||||
<small>
|
||||
{{ name|doc }}
|
||||
</small>
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</pb-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -19,8 +19,15 @@
|
|||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<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>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-binding-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -73,8 +80,18 @@
|
|||
</div>
|
||||
</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>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-binding-update' pk=binding.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Update' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-binding-delete' pk=binding.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -94,7 +111,12 @@
|
|||
<div class="pf-c-empty-state__body">
|
||||
{% trans 'Currently no flow-stage bindings exist. Click the button below to create one.' %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_admin:certificatekeypair-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-binding-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -21,8 +21,15 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<a href="{% url 'passbook_admin:stage-invitation-create' %}?back={{ request.get_full_path }}"
|
||||
class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-invitation-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -49,7 +56,12 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:stage-invitation-delete' pk=invitation.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-invitation-delete' pk=invitation.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -77,7 +89,12 @@
|
|||
{% trans 'Currently no invitations exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_admin:stage-invitation-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-invitation-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -21,7 +21,15 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<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>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-prompt-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -63,18 +71,28 @@
|
|||
<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>
|
||||
<li>{{ flow.slug }}</li>
|
||||
{% empty %}
|
||||
<li>-</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:stage-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:stage-prompt-delete' pk=prompt.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-prompt-update' pk=prompt.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Update' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_admin:stage-prompt-delete' pk=prompt.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
{% 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>
|
||||
<a class="pf-c-button pf-m-tertiary pb-root-link" href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
</section>
|
||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
|
||||
<thead>
|
||||
<tr role="row">
|
||||
|
@ -64,9 +71,9 @@
|
|||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
<button is="action-button" class="pf-c-button pf-m-primary" url="{% url 'passbook_api:admin_system_tasks-retry' pk=task.task_name %}">
|
||||
<pb-action-button url="{% url 'passbook_api:admin_system_tasks-retry' pk=task.task_name %}">
|
||||
{% trans 'Retry Task' %}
|
||||
</button>
|
||||
</pb-action-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="fas fa-key"></i>
|
||||
<i class="pf-icon pf-icon-security"></i>
|
||||
{% trans 'Tokens' %}
|
||||
</h1>
|
||||
<p>{% trans "Tokens are used throughout passbook for Email validation stages, Recovery keys and API access." %}</p>
|
||||
|
@ -58,7 +58,15 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:token-delete' pk=token.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:token-delete' pk=token.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-token-copy-button identifier="{{ token.identifier }}">
|
||||
{% trans 'Copy token' %}
|
||||
</pb-token-copy-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -19,7 +19,15 @@
|
|||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<a href="{% url 'passbook_admin:user-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:user-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
@ -53,14 +61,29 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:user-update' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:user-update' pk=user.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
{% if user.is_active %}
|
||||
<a class="pf-c-button pf-m-warning" href="{% url 'passbook_admin:user-disable' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Disable' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:user-disable' pk=user.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-warning">
|
||||
{% trans 'Disable' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
{% else %}
|
||||
<a class="pf-c-button pf-m-primary" href="{% url 'passbook_admin:user-enable' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Enable' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:user-delete' pk=user.pk %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Enable' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
{% endif %}
|
||||
<a class="pf-c-button pf-m-tertiary" href="{% url 'passbook_admin:user-password-reset' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Reset Password' %}</a>
|
||||
<a class="pf-c-button pf-m-tertiary" href="{% url 'passbook_core:impersonate-init' user_id=user.pk %}">{% trans 'Impersonate' %}</a>
|
||||
<a class="pf-c-button pf-m-tertiary pb-root-link" href="{% url 'passbook_admin:user-password-reset' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Reset Password' %}</a>
|
||||
<a class="pf-c-button pf-m-tertiary pb-root-link" href="{% url 'passbook_core:impersonate-init' user_id=user.pk %}">{% trans 'Impersonate' %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -88,7 +111,12 @@
|
|||
{% trans 'Currently no users exist. How did you even get here.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_admin:user-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
<pb-modal-button href="{% url 'passbook_admin:user-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
1
passbook/admin/templates/fields/codemirror.html
Normal file
1
passbook/admin/templates/fields/codemirror.html
Normal file
|
@ -0,0 +1 @@
|
|||
<pb-codemirror mode="{{ widget.attrs.mode }}"><textarea class="pf-c-form-control" name="{{ widget.name }}">{% if widget.value %}{{ widget.value }}{% endif %}</textarea></pb-codemirror>
|
|
@ -30,26 +30,20 @@
|
|||
<div class="pf-l-stack__item">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__body">
|
||||
<form action="" method="post" class="pf-c-form pf-m-horizontal" enctype="multipart/form-data">
|
||||
<form id="main-form" action="" method="post" class="pf-c-form pf-m-horizontal" enctype="multipart/form-data">
|
||||
{% include 'partials/form_horizontal.html' with form=form %}
|
||||
{% block beneath_form %}
|
||||
{% endblock %}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<div class="pf-c-form__group-control">
|
||||
<div class="pf-c-form__horizontal-group">
|
||||
<div class="pf-c-form__actions">
|
||||
<input class="pf-c-button pf-m-primary" type="submit" value="{% block action %}{% endblock %}" />
|
||||
<a class="pf-c-button pf-m-secondary" href="{% back %}">{% trans "Cancel" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<footer class="pf-c-modal-box__footer">
|
||||
<input class="pf-c-button pf-m-primary" type="submit" form="main-form" value="{% block action %}{% endblock %}" />
|
||||
<a class="pf-c-button pf-m-secondary" href="{% back %}">{% trans "Cancel" %}</a>
|
||||
</footer>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
|
|
20
passbook/admin/templates/generic/form_non_model.html
Normal file
20
passbook/admin/templates/generic/form_non_model.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends base_template|default:"generic/form.html" %}
|
||||
|
||||
{% load passbook_utils %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block above_form %}
|
||||
<h1>
|
||||
{% trans form.title %}
|
||||
</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block beneath_form %}
|
||||
<p>
|
||||
{% trans form.body %}
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block action %}
|
||||
{% trans 'Confirm' %}
|
||||
{% endblock %}
|
|
@ -24,7 +24,17 @@ from passbook.admin.views import (
|
|||
)
|
||||
|
||||
urlpatterns = [
|
||||
path("", overview.AdministrationOverviewView.as_view(), name="overview"),
|
||||
path(
|
||||
"overview/cache/flow/",
|
||||
overview.FlowCacheClearView.as_view(),
|
||||
name="overview-clear-flow-cache",
|
||||
),
|
||||
path(
|
||||
"overview/cache/policy/",
|
||||
overview.PolicyCacheClearView.as_view(),
|
||||
name="overview-clear-policy-cache",
|
||||
),
|
||||
path("overview/", overview.AdministrationOverviewView.as_view(), name="overview"),
|
||||
# Applications
|
||||
path(
|
||||
"applications/", applications.ApplicationListView.as_view(), name="applications"
|
||||
|
|
|
@ -2,14 +2,20 @@
|
|||
from typing import Union
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.core.cache import cache
|
||||
from django.db.models import Count
|
||||
from django.db.models.fields.json import KeyTextTransform
|
||||
from django.views.generic import TemplateView
|
||||
from django.http.request import HttpRequest
|
||||
from django.http.response import HttpResponse
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import FormView, TemplateView
|
||||
from packaging.version import LegacyVersion, Version, parse
|
||||
from structlog import get_logger
|
||||
|
||||
from passbook import __version__
|
||||
from passbook.admin.forms.overview import FlowCacheClearForm, PolicyCacheClearForm
|
||||
from passbook.admin.mixins import AdminRequiredMixin
|
||||
from passbook.admin.tasks import VERSION_CACHE_KEY, update_latest_version
|
||||
from passbook.audit.models import Event, EventAction
|
||||
|
@ -24,18 +30,6 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
|
|||
|
||||
template_name = "administration/overview.html"
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
"""Handle post (clear cache from modal)"""
|
||||
if "clear_policies" in self.request.POST:
|
||||
keys = cache.keys("policy_*")
|
||||
cache.delete_many(keys)
|
||||
LOGGER.debug("Cleared Policy cache", keys=len(keys))
|
||||
if "clear_flows" in self.request.POST:
|
||||
keys = cache.keys("flow_*")
|
||||
cache.delete_many(keys)
|
||||
LOGGER.debug("Cleared flow cache", keys=len(keys))
|
||||
return self.get(*args, **kwargs)
|
||||
|
||||
def get_latest_version(self) -> Union[LegacyVersion, Version]:
|
||||
"""Get latest version from cache"""
|
||||
version_in_cache = cache.get(VERSION_CACHE_KEY)
|
||||
|
@ -75,3 +69,35 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
|
|||
kwargs["cached_policies"] = len(cache.keys("policy_*"))
|
||||
kwargs["cached_flows"] = len(cache.keys("flow_*"))
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class PolicyCacheClearView(AdminRequiredMixin, SuccessMessageMixin, FormView):
|
||||
"""View to clear Policy cache"""
|
||||
|
||||
form_class = PolicyCacheClearForm
|
||||
|
||||
template_name = "generic/form_non_model.html"
|
||||
success_url = reverse_lazy("passbook_admin:overview")
|
||||
success_message = _("Successfully cleared Policy cache")
|
||||
|
||||
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
keys = cache.keys("policy_*")
|
||||
cache.delete_many(keys)
|
||||
LOGGER.debug("Cleared Policy cache", keys=len(keys))
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
class FlowCacheClearView(AdminRequiredMixin, SuccessMessageMixin, FormView):
|
||||
"""View to clear Flow cache"""
|
||||
|
||||
form_class = FlowCacheClearForm
|
||||
|
||||
template_name = "generic/form_non_model.html"
|
||||
success_url = reverse_lazy("passbook_admin:overview")
|
||||
success_message = _("Successfully cleared Flow cache")
|
||||
|
||||
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
keys = cache.keys("flow_*")
|
||||
cache.delete_many(keys)
|
||||
LOGGER.debug("Cleared flow cache", keys=len(keys))
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
|
|
@ -155,7 +155,7 @@ class UserPasswordResetView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
|
|||
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
"""Create token for user and return link"""
|
||||
super().get(request, *args, **kwargs)
|
||||
token, _ = Token.objects.get_or_create(
|
||||
token, __ = Token.objects.get_or_create(
|
||||
identifier="password-reset-temp", user=self.object
|
||||
)
|
||||
querystring = urlencode({"token": token.key})
|
||||
|
|
39
passbook/api/v2/config.py
Normal file
39
passbook/api/v2/config.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
"""core Configs API"""
|
||||
from drf_yasg2.utils import swagger_auto_schema
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ReadOnlyField, Serializer
|
||||
from rest_framework.viewsets import ViewSet
|
||||
|
||||
from passbook.lib.config import CONFIG
|
||||
|
||||
|
||||
class ConfigSerializer(Serializer):
|
||||
"""Serialize passbook Config into DRF Object"""
|
||||
|
||||
branding_logo = ReadOnlyField()
|
||||
branding_title = ReadOnlyField()
|
||||
|
||||
def create(self, request: Request) -> Response:
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, request: Request) -> Response:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ConfigsViewSet(ViewSet):
|
||||
"""Read-only view set that returns the current session's Configs"""
|
||||
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
@swagger_auto_schema(responses={200: ConfigSerializer(many=True)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Retrive public configuration options"""
|
||||
config = ConfigSerializer(
|
||||
{
|
||||
"branding_logo": CONFIG.y("passbook.branding.logo"),
|
||||
"branding_title": CONFIG.y("passbook.branding.title"),
|
||||
}
|
||||
)
|
||||
return Response(config.data)
|
|
@ -8,6 +8,7 @@ from rest_framework.permissions import AllowAny
|
|||
from passbook.admin.api.overview import AdministrationOverviewViewSet
|
||||
from passbook.admin.api.overview_metrics import AdministrationMetricsViewSet
|
||||
from passbook.admin.api.tasks import TaskViewSet
|
||||
from passbook.api.v2.config import ConfigsViewSet
|
||||
from passbook.api.v2.messages import MessagesViewSet
|
||||
from passbook.audit.api import EventViewSet
|
||||
from passbook.core.api.applications import ApplicationViewSet
|
||||
|
@ -57,6 +58,7 @@ from passbook.stages.user_write.api import UserWriteStageViewSet
|
|||
router = routers.DefaultRouter()
|
||||
|
||||
router.register("root/messages", MessagesViewSet, basename="messages")
|
||||
router.register("root/config", ConfigsViewSet, basename="configs")
|
||||
|
||||
router.register(
|
||||
"admin/overview", AdministrationOverviewViewSet, basename="admin_overview"
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<button role="pb-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,19 +1,33 @@
|
|||
"""User API Views"""
|
||||
from rest_framework.serializers import BooleanField, ModelSerializer
|
||||
from drf_yasg2.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 (
|
||||
BooleanField,
|
||||
ModelSerializer,
|
||||
SerializerMethodField,
|
||||
)
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from passbook.core.models import User
|
||||
from passbook.lib.templatetags.passbook_utils import avatar
|
||||
|
||||
|
||||
class UserSerializer(ModelSerializer):
|
||||
"""User Serializer"""
|
||||
|
||||
is_superuser = BooleanField(read_only=True)
|
||||
avatar = SerializerMethodField()
|
||||
|
||||
def get_avatar(self, user: User) -> str:
|
||||
"""Add user's avatar as URL"""
|
||||
return avatar(user)
|
||||
|
||||
class Meta:
|
||||
|
||||
model = User
|
||||
fields = ["pk", "username", "name", "is_superuser", "email"]
|
||||
fields = ["pk", "username", "name", "is_superuser", "email", "avatar"]
|
||||
|
||||
|
||||
class UserViewSet(ModelViewSet):
|
||||
|
@ -21,3 +35,10 @@ class UserViewSet(ModelViewSet):
|
|||
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
@swagger_auto_schema(responses={200: UserSerializer(many=False)})
|
||||
@action(detail=False)
|
||||
# pylint: disable=invalid-name
|
||||
def me(self, request: Request) -> Response:
|
||||
"""Get information about current user"""
|
||||
return Response(UserSerializer(request.user).data)
|
||||
|
|
|
@ -29,19 +29,18 @@ class ApplicationForm(forms.ModelForm):
|
|||
]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"meta_launch_url": forms.TextInput(
|
||||
attrs={
|
||||
"placeholder": _(
|
||||
(
|
||||
"If left empty, passbook will try to extract the launch URL "
|
||||
"based on the selected provider."
|
||||
)
|
||||
)
|
||||
}
|
||||
),
|
||||
"meta_launch_url": forms.TextInput(),
|
||||
"meta_icon_url": forms.TextInput(),
|
||||
"meta_publisher": forms.TextInput(),
|
||||
}
|
||||
help_texts = {
|
||||
"meta_launch_url": _(
|
||||
(
|
||||
"If left empty, passbook will try to extract the launch URL "
|
||||
"based on the selected provider."
|
||||
)
|
||||
),
|
||||
}
|
||||
field_classes = {"provider": GroupedModelChoiceField}
|
||||
labels = {
|
||||
"meta_launch_url": _("Launch URL"),
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""passbook Core Group forms"""
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
|
||||
from passbook.admin.fields import CodeMirrorWidget, YAMLField
|
||||
from passbook.core.models import Group, User
|
||||
|
@ -12,7 +11,6 @@ class GroupForm(forms.ModelForm):
|
|||
members = forms.ModelMultipleChoiceField(
|
||||
User.objects.all(),
|
||||
required=False,
|
||||
widget=FilteredSelectMultiple("users", False),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
@ -18,7 +18,7 @@ from structlog import get_logger
|
|||
|
||||
from passbook.core.exceptions import PropertyMappingExpressionException
|
||||
from passbook.core.signals import password_changed
|
||||
from passbook.core.types import UILoginButton, UIUserSettings
|
||||
from passbook.core.types import UILoginButton
|
||||
from passbook.flows.models import Flow
|
||||
from passbook.lib.models import CreatedUpdatedModel
|
||||
from passbook.policies.models import PolicyBindingModel
|
||||
|
@ -249,9 +249,9 @@ class Source(PolicyBindingModel):
|
|||
return None
|
||||
|
||||
@property
|
||||
def ui_user_settings(self) -> Optional[UIUserSettings]:
|
||||
def ui_user_settings(self) -> Optional[str]:
|
||||
"""Entrypoint to integrate with User settings. Can either return None if no
|
||||
user settings are available, or an instanace of UIUserSettings."""
|
||||
user settings are available, or a string with the URL to fetch."""
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -8,54 +8,8 @@
|
|||
|
||||
{% block body %}
|
||||
<pb-messages url="{% url 'passbook_api:messages-list' %}"></pb-messages>
|
||||
<div class="pf-c-page" id="page-default-nav-example">
|
||||
<div class="pf-c-page">
|
||||
<a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">{% trans 'Skip to content' %}</a>
|
||||
<header role="banner" class="pf-c-page__header ws-page-header">
|
||||
<div class="pf-c-page__header-brand">
|
||||
<div class="pf-c-page__header-brand-toggle">
|
||||
<button class="pf-c-button pf-m-plain" type="button" id="page-default-nav-example-nav-toggle"
|
||||
aria-label="Global navigation" aria-expanded="true"
|
||||
aria-controls="page-default-nav-example-primary-nav">
|
||||
<i class="fas fa-bars" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<a href="{% url 'passbook_core:overview' %}" class="pf-c-page__header-brand-link">
|
||||
<div class="pf-c-brand pb-brand">
|
||||
<img src="{{ config.passbook.branding.logo }}" style="width: 100px;" alt="passbook icon">
|
||||
{% if config.passbook.branding.title_show %}
|
||||
<small><small>{{ config.passbook.branding.title }}</small></small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="pf-c-page__header-nav">
|
||||
<nav class="pf-c-nav pf-m-horizontal" aria-label="Nav">
|
||||
<ul class="pf-c-nav__list ws-top-nav">
|
||||
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_core:overview' %}"
|
||||
href="{% url 'passbook_core:overview' %}">{% trans 'Access' %}</a></li>
|
||||
{% if user.is_superuser %}
|
||||
<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>
|
||||
<li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_audit:log' %}"
|
||||
href="{% url 'passbook_audit:log' %}">{% trans 'Monitor' %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="pf-c-page__header-tools">
|
||||
<div class="pf-c-page__header-tools-group pf-m-icons">
|
||||
<a href="{% url 'passbook_flows:default-invalidation' %}" class="pf-c-button pf-m-plain" type="button" id="logout">
|
||||
<i class="fas fa-sign-out-alt" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="pf-c-page__header-tools-group">
|
||||
<a href="{% url 'passbook_core:user-settings' %}" id="user-settings" class="pf-c-button">
|
||||
{{ user.username }}
|
||||
</a>
|
||||
</div>
|
||||
<img class="pf-c-avatar" src="{% avatar user %}" alt="">
|
||||
</div>
|
||||
</header>
|
||||
{% block page_content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
|
|
@ -6,17 +6,18 @@
|
|||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="preload" href="{% static 'passbook/fonts/DINEngschriftStd.woff2' %}" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="{% static 'passbook/fonts/DINEngschriftStd.woff' %}" as="font" type="font/woff" crossorigin>
|
||||
<link rel="preload" href="{% static 'dist/assets/fonts/DINEngschriftStd.woff2' %}" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="{% static 'dist/assets/fonts/DINEngschriftStd.woff' %}" as="font" type="font/woff" crossorigin>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>{% block title %}{% trans title|default:config.passbook.branding.title %}{% endblock %}</title>
|
||||
<link rel="icon" type="image/png" href="{% static 'passbook/logo.png' %}">
|
||||
<link rel="shortcut icon" type="image/png" href="{% static 'passbook/logo.png' %}">
|
||||
<link rel="icon" type="image/png" href="{% static 'dist/assets/images/logo.png' %}">
|
||||
<link rel="shortcut icon" type="image/png" href="{% static 'dist/assets/images/logo.png' %}">
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'node_modules/@patternfly/patternfly/patternfly.css' %}">
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'node_modules/@patternfly/patternfly/patternfly-addons.css' %}">
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css' %}">
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'passbook/passbook.css' %}">
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'dist/passbook.css' %}">
|
||||
<script src="{% static 'dist/main.js' %}" type="module"></script>
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
@ -37,6 +38,5 @@
|
|||
{% endblock %}
|
||||
{% block scripts %}
|
||||
{% endblock %}
|
||||
<script src="{% static 'passbook/passbook.js' %}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
{% extends "base/page.html" %}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% load passbook_is_active %}
|
||||
{% load passbook_utils %}
|
||||
|
||||
{% block page_content %}
|
||||
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -1,65 +1,53 @@
|
|||
{% extends "overview/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head %}
|
||||
{{ block.super }}
|
||||
<style>
|
||||
img.app-icon {
|
||||
max-height: 72px;
|
||||
width: auto !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="pf-icon pf-icon-applications"></i>
|
||||
{% trans 'Applications' %}
|
||||
</h1>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section">
|
||||
{% if applications %}
|
||||
<div class="pf-l-gallery pf-m-gutter">
|
||||
{% for app in applications %}
|
||||
<a href="{{ app.get_launch_url }}" class="pf-c-card pf-m-hoverable pf-m-compact">
|
||||
<div class="pf-c-card__header">
|
||||
{% if not app.meta_icon_url %}
|
||||
<i class="pf-icon pf-icon-arrow"></i>
|
||||
{% else %}
|
||||
<img class="app-icon pf-c-avatar" src="{{ app.meta_icon_url }}" alt="{% trans 'Application Icon' %}">
|
||||
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="pf-icon pf-icon-applications"></i>
|
||||
{% trans 'Applications' %}
|
||||
</h1>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section">
|
||||
{% if applications %}
|
||||
<div class="pf-l-gallery pf-m-gutter">
|
||||
{% for app in applications %}
|
||||
<a href="{{ app.get_launch_url }}" class="pf-c-card pf-m-hoverable pf-m-compact">
|
||||
<div class="pf-c-card__header">
|
||||
{% if not app.meta_icon_url %}
|
||||
<i class="pf-icon pf-icon-arrow"></i>
|
||||
{% else %}
|
||||
<img class="app-icon pf-c-avatar" src="{{ app.meta_icon_url }}" alt="{% trans 'Application Icon' %}">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pf-c-card__title">
|
||||
<p id="card-1-check-label">{{ app.name }}</p>
|
||||
<div class="pf-c-content">
|
||||
<small>{{ app.meta_publisher }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
{% trans app.meta_description|truncatewords:35 %}
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-empty-state pf-m-full-height">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="fas fa-cubes pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">{% trans 'No Applications available.' %}</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% trans "Either no applications are defined, or you don't have access to any." %}
|
||||
</div>
|
||||
{% if perms.passbook_core.add_application %}
|
||||
<a href="{% url 'passbook_admin:application-create' %}" class="pf-c-button pf-m-primary" type="button">
|
||||
{% trans 'Create Application' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pf-c-card__title">
|
||||
<p id="card-1-check-label">{{ app.name }}</p>
|
||||
<div class="pf-c-content">
|
||||
<small>{{ app.meta_publisher }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
{% trans app.meta_description|truncatewords:35 %}
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-empty-state pf-m-full-height">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="fas fa-cubes pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">{% trans 'No Applications available.' %}</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% trans "Either no applications are defined, or you don't have access to any." %}
|
||||
</div>
|
||||
{% if perms.passbook_core.add_application %}
|
||||
<a href="{% url 'passbook_admin:application-create' %}" class="pf-c-button pf-m-primary" type="button">
|
||||
{% trans 'Create Application' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
</section>
|
||||
</main>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<div class="pf-c-pagination__nav-control pf-m-prev">
|
||||
<a class="pf-c-button pf-m-plain"
|
||||
{% if page_obj.has_previous %}
|
||||
href="?{% query_transform page=page_obj.previous_page_number %}"
|
||||
href="{{ request.path }}?{% query_transform page=page_obj.previous_page_number %}"
|
||||
{% else %}
|
||||
disabled
|
||||
{% endif %}
|
||||
|
@ -28,7 +28,7 @@
|
|||
<div class="pf-c-pagination__nav-control pf-m-next">
|
||||
<a class="pf-c-button pf-m-plain"
|
||||
{% if page_obj.has_next %}
|
||||
href="?{% query_transform page=page_obj.next_page_number %}"
|
||||
href="{{ request.path }}?{% query_transform page=page_obj.next_page_number %}"
|
||||
{% else %}
|
||||
disabled
|
||||
{% endif %}
|
||||
|
|
14
passbook/core/templates/shell.html
Normal file
14
passbook/core/templates/shell.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
{% extends "base/page.html" %}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% load passbook_is_active %}
|
||||
{% load passbook_utils %}
|
||||
|
||||
{% block page_content %}
|
||||
<pb-sidebar class="pf-c-page__sidebar">
|
||||
</pb-sidebar>
|
||||
<pb-router-outlet role="main" class="pf-c-page__main" tabindex="-1" id="main-content" defaultUrl="/-/overview/">
|
||||
</pb-router-outlet>
|
||||
{% endblock %}
|
|
@ -1,71 +0,0 @@
|
|||
{% extends "base/page.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load passbook_is_active %}
|
||||
{% load static %}
|
||||
{% load passbook_user_settings %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="pf-c-page__sidebar">
|
||||
<div class="pf-c-page__sidebar-body">
|
||||
<nav class="pf-c-nav" id="page-default-nav-example-primary-nav" aria-label="Global">
|
||||
<section class="pf-c-nav__section">
|
||||
<h2 class="pf-c-nav__section-title">{% trans 'General Settings' %}</h2>
|
||||
<ul class="pf-c-nav__list">
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_core:user-settings' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_core:user-settings' %}">{% trans 'User Details' %}</a>
|
||||
</li>
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{% url 'passbook_core:user-tokens' %}"
|
||||
class="pf-c-nav__link {% is_active 'passbook_core:user-tokens' 'passbook_core:user-tokens-create' 'passbook_core:user-tokens-update' 'passbook_core:user-tokens-delete' %}">{% trans 'Tokens' %}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
{% user_stages as user_stages_loc %}
|
||||
{% if user_stages_loc %}
|
||||
<section class="pf-c-nav__section">
|
||||
<h2 class="pf-c-nav__section-title">{% trans 'Stages' %}</h2>
|
||||
<ul class="pf-c-nav__list">
|
||||
{% for stage in user_stages_loc %}
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{{ stage.url }}" class="pf-c-nav__link {% if stage.url == request.get_full_path %} pf-m-current {% endif %}">
|
||||
{{ stage.name }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% user_sources as user_sources_loc %}
|
||||
{% if user_sources_loc %}
|
||||
<section class="pf-c-nav__section">
|
||||
<h2 class="pf-c-nav__section-title">{% trans 'Sources' %}</h2>
|
||||
<ul class="pf-c-nav__list">
|
||||
{% for source in user_sources_loc %}
|
||||
<li class="pf-c-nav__item">
|
||||
<a href="{{ source.url }}"
|
||||
class="pf-c-nav__link {% if source.url == request.get_full_path %} pf-m-current {% endif %}">
|
||||
{{ source.name }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
|
||||
{% block content %}
|
||||
<section class="pf-c-page__main-section">
|
||||
<div class="pf-u-display-flex pf-u-justify-content-center">
|
||||
<div class="pf-u-w-75">
|
||||
{% block page %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -1,28 +1,78 @@
|
|||
{% extends "user/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load passbook_user_settings %}
|
||||
|
||||
{% block page %}
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
{% trans 'Update details' %}
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<form action="" method="post" class="pf-c-form pf-m-horizontal">
|
||||
{% include 'partials/form_horizontal.html' with form=form %}
|
||||
{% block beneath_form %}
|
||||
{% endblock %}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<div class="pf-c-form__horizontal-group">
|
||||
<div class="pf-c-form__actions">
|
||||
<input class="pf-c-button pf-m-primary" type="submit" value="{% trans 'Update' %}" />
|
||||
{% if unenrollment_enabled %}
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_flows:default-unenrollment' %}?back={{ request.get_full_path }}">{% trans "Delete account" %}</a>
|
||||
{% endif %}
|
||||
<div class="pf-c-page">
|
||||
<main role="main" class="pf-c-page__main" tabindex="-1">
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="pf-icon pf-icon-user"></i>
|
||||
{% trans 'User Settings' %}
|
||||
</h1>
|
||||
<p>{% trans "Configure settings relevant to your user profile." %}</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section">
|
||||
<div class="pf-u-display-flex pf-u-justify-content-center">
|
||||
<div class="pf-u-w-75">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
{% trans 'Update details' %}
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<form action="" method="post" class="pf-c-form pf-m-horizontal">
|
||||
{% include 'partials/form_horizontal.html' with form=form %}
|
||||
{% block beneath_form %}
|
||||
{% endblock %}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<div class="pf-c-form__horizontal-group">
|
||||
<div class="pf-c-form__actions">
|
||||
<input class="pf-c-button pf-m-primary" type="submit" value="{% trans 'Update' %}" />
|
||||
{% if unenrollment_enabled %}
|
||||
<a class="pf-c-button pf-m-danger"
|
||||
href="{% url 'passbook_flows:default-unenrollment' %}?back={{ request.get_full_path }}">{% trans "Delete account" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section">
|
||||
<div class="pf-u-display-flex pf-u-justify-content-center">
|
||||
<div class="pf-u-w-75">
|
||||
<pb-site-shell url="{% url 'passbook_core:user-tokens' %}">
|
||||
<div slot="body"></div>
|
||||
</pb-site-shell>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% user_stages as user_stages_loc %}
|
||||
{% for stage in user_stages_loc %}
|
||||
<section class="pf-c-page__main-section">
|
||||
<div class="pf-u-display-flex pf-u-justify-content-center">
|
||||
<div class="pf-u-w-75">
|
||||
<pb-site-shell url="{{ stage }}">
|
||||
<div slot="body"></div>
|
||||
</pb-site-shell>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
{% user_sources as user_sources_loc %}
|
||||
{% for source in user_sources_loc %}
|
||||
<section class="pf-c-page__main-section">
|
||||
<div class="pf-u-display-flex pf-u-justify-content-center">
|
||||
<div class="pf-u-w-75">
|
||||
<pb-site-shell url="{{ source }}">
|
||||
<div slot="body"></div>
|
||||
</pb-site-shell>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
</main>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,91 +1,100 @@
|
|||
{% extends "user/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-users"></i>
|
||||
{% trans 'Tokens' %}
|
||||
</h1>
|
||||
<p>{% trans "Tokens can be used to access passbook's API." %}
|
||||
</p>
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
<p>{% trans "Tokens can be used to access passbook's API." %}</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
{% if object_list %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<a href="{% url 'passbook_core:user-tokens-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
{% if object_list %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<pb-modal-button href="{% url 'passbook_core:user-tokens-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</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 'Identifier' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Expires?' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Expiry Date' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Description' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for token in object_list %}
|
||||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<div>{{ token.identifier }}</div>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ token.expiring|yesno:"Yes,No" }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{% if not token.expiring %}
|
||||
-
|
||||
{% else %}
|
||||
{{ token.expires }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ token.description }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_core:user-tokens-update' identifier=token.identifier %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_core:user-tokens-delete' identifier=token.identifier %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="fas fa-cubes pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Tokens.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% trans 'Currently no tokens exist. Click the button below to create one.' %}
|
||||
</div>
|
||||
<a href="{% url 'passbook_core:user-tokens-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th role="columnheader" scope="col">{% trans 'Identifier' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Expires?' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Expiry Date' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Description' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for token in object_list %}
|
||||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<div>{{ token.identifier }}</div>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ token.expiring|yesno:"Yes,No" }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{% if not token.expiring %}
|
||||
-
|
||||
{% else %}
|
||||
{{ token.expires }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ token.description }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<pb-modal-button href="{% url 'passbook_core:user-tokens-update' identifier=token.identifier %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-modal-button href="{% url 'passbook_core:user-tokens-delete' identifier=token.identifier %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
<pb-token-copy-button identifier="{{ token.identifier }}">
|
||||
{% trans 'Copy token' %}
|
||||
</pb-token-copy-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="fas fa-cubes pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Tokens.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% trans 'Currently no tokens exist. Click the button below to create one.' %}
|
||||
</div>
|
||||
<pb-modal-button href="{% url 'passbook_core:user-tokens-create' %}">
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</button>
|
||||
<div slot="modal"></div>
|
||||
</pb-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
"""passbook user settings template tags"""
|
||||
from typing import Iterable, List
|
||||
from typing import Iterable
|
||||
|
||||
from django import template
|
||||
from django.template.context import RequestContext
|
||||
|
||||
from passbook.core.models import Source
|
||||
from passbook.core.types import UIUserSettings
|
||||
from passbook.flows.models import Stage
|
||||
from passbook.policies.engine import PolicyEngine
|
||||
|
||||
|
@ -14,26 +13,26 @@ register = template.Library()
|
|||
|
||||
@register.simple_tag(takes_context=True)
|
||||
# pylint: disable=unused-argument
|
||||
def user_stages(context: RequestContext) -> List[UIUserSettings]:
|
||||
def user_stages(context: RequestContext) -> list[str]:
|
||||
"""Return list of all stages which apply to user"""
|
||||
_all_stages: Iterable[Stage] = Stage.objects.all().select_subclasses()
|
||||
matching_stages: List[UIUserSettings] = []
|
||||
matching_stages: list[str] = []
|
||||
for stage in _all_stages:
|
||||
user_settings = stage.ui_user_settings
|
||||
if not user_settings:
|
||||
continue
|
||||
matching_stages.append(user_settings)
|
||||
return sorted(matching_stages, key=lambda x: x.name)
|
||||
return matching_stages
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def user_sources(context: RequestContext) -> List[UIUserSettings]:
|
||||
def user_sources(context: RequestContext) -> list[str]:
|
||||
"""Return a list of all sources which are enabled for the user"""
|
||||
user = context.get("request").user
|
||||
_all_sources: Iterable[Source] = Source.objects.filter(
|
||||
enabled=True
|
||||
).select_subclasses()
|
||||
matching_sources: List[UIUserSettings] = []
|
||||
matching_sources: list[str] = []
|
||||
for source in _all_sources:
|
||||
user_settings = source.ui_user_settings
|
||||
if not user_settings:
|
||||
|
@ -42,4 +41,4 @@ def user_sources(context: RequestContext) -> List[UIUserSettings]:
|
|||
policy_engine.build()
|
||||
if policy_engine.passing:
|
||||
matching_sources.append(user_settings)
|
||||
return sorted(matching_sources, key=lambda x: x.name)
|
||||
return matching_sources
|
||||
|
|
|
@ -23,13 +23,13 @@ class TestImpersonation(TestCase):
|
|||
)
|
||||
)
|
||||
|
||||
response = self.client.get(reverse("passbook_core:overview"))
|
||||
response = self.client.get(reverse("passbook_api:user-me"))
|
||||
self.assertIn(self.other_user.username, response.content.decode())
|
||||
self.assertNotIn(self.pbadmin.username, response.content.decode())
|
||||
|
||||
self.client.get(reverse("passbook_core:impersonate-end"))
|
||||
|
||||
response = self.client.get(reverse("passbook_core:overview"))
|
||||
response = self.client.get(reverse("passbook_api:user-me"))
|
||||
self.assertNotIn(self.other_user.username, response.content.decode())
|
||||
self.assertIn(self.pbadmin.username, response.content.decode())
|
||||
|
||||
|
@ -43,7 +43,7 @@ class TestImpersonation(TestCase):
|
|||
)
|
||||
)
|
||||
|
||||
response = self.client.get(reverse("passbook_core:overview"))
|
||||
response = self.client.get(reverse("passbook_api:user-me"))
|
||||
self.assertIn(self.other_user.username, response.content.decode())
|
||||
self.assertNotIn(self.pbadmin.username, response.content.decode())
|
||||
|
||||
|
@ -52,4 +52,4 @@ class TestImpersonation(TestCase):
|
|||
self.client.force_login(self.other_user)
|
||||
|
||||
response = self.client.get(reverse("passbook_core:impersonate-end"))
|
||||
self.assertRedirects(response, reverse("passbook_core:overview"))
|
||||
self.assertRedirects(response, reverse("passbook_core:shell"))
|
||||
|
|
|
@ -23,8 +23,20 @@ class TestOverviewViews(TestCase):
|
|||
)
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def test_shell(self):
|
||||
"""Test shell"""
|
||||
self.assertEqual(
|
||||
self.client.get(reverse("passbook_core:shell")).status_code, 200
|
||||
)
|
||||
|
||||
def test_overview(self):
|
||||
"""Test UserSettingsView"""
|
||||
"""Test overview"""
|
||||
self.assertEqual(
|
||||
self.client.get(reverse("passbook_core:overview")).status_code, 200
|
||||
)
|
||||
|
||||
def test_user_settings(self):
|
||||
"""Test user settings"""
|
||||
self.assertEqual(
|
||||
self.client.get(reverse("passbook_core:user-settings")).status_code, 200
|
||||
)
|
||||
|
|
|
@ -3,17 +3,9 @@ from dataclasses import dataclass
|
|||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class UIUserSettings:
|
||||
"""Dataclass for Stage and Source's user_settings"""
|
||||
|
||||
name: str
|
||||
url: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class UILoginButton:
|
||||
"""Dataclass for Source's ui_ui_login_button"""
|
||||
"""Dataclass for Source's ui_login_button"""
|
||||
|
||||
# Name, ran through i18n
|
||||
name: str
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""passbook URL Configuration"""
|
||||
from django.urls import path
|
||||
|
||||
from passbook.core.views import impersonate, overview, user
|
||||
from passbook.core.views import impersonate, overview, shell, user
|
||||
|
||||
urlpatterns = [
|
||||
# User views
|
||||
|
@ -23,7 +23,8 @@ urlpatterns = [
|
|||
name="user-tokens-delete",
|
||||
),
|
||||
# Overview
|
||||
path("", overview.OverviewView.as_view(), name="overview"),
|
||||
path("", shell.ShellView.as_view(), name="shell"),
|
||||
path("-/overview/", overview.OverviewView.as_view(), name="overview"),
|
||||
# Impersonation
|
||||
path(
|
||||
"-/impersonation/<int:user_id>/",
|
||||
|
|
|
@ -33,7 +33,7 @@ class ImpersonateInitView(View):
|
|||
|
||||
Event.new(EventAction.IMPERSONATION_STARTED).from_http(request, user_to_be)
|
||||
|
||||
return redirect("passbook_core:overview")
|
||||
return redirect("passbook_core:shell")
|
||||
|
||||
|
||||
class ImpersonateEndView(View):
|
||||
|
@ -46,7 +46,7 @@ class ImpersonateEndView(View):
|
|||
or SESSION_IMPERSONATE_ORIGINAL_USER not in request.session
|
||||
):
|
||||
LOGGER.debug("Can't end impersonation", user=request.user)
|
||||
return redirect("passbook_core:overview")
|
||||
return redirect("passbook_core:shell")
|
||||
|
||||
original_user = request.session[SESSION_IMPERSONATE_ORIGINAL_USER]
|
||||
|
||||
|
@ -55,4 +55,4 @@ class ImpersonateEndView(View):
|
|||
|
||||
Event.new(EventAction.IMPERSONATION_ENDED).from_http(request, original_user)
|
||||
|
||||
return redirect("passbook_core:overview")
|
||||
return redirect("passbook_core:shell")
|
||||
|
|
9
passbook/core/views/shell.py
Normal file
9
passbook/core/views/shell.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
"""core shell view"""
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.views.generic.base import TemplateView
|
||||
|
||||
|
||||
class ShellView(LoginRequiredMixin, TemplateView):
|
||||
"""core shell view"""
|
||||
|
||||
template_name = "shell.html"
|
|
@ -79,7 +79,7 @@ class CertificateKeyPair(CreatedUpdatedModel):
|
|||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Certificate-Key Pair {self.name} {self.fingerprint}"
|
||||
return f"Certificate-Key Pair {self.name}"
|
||||
|
||||
class Meta:
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ from model_utils.managers import InheritanceManager
|
|||
from rest_framework.serializers import BaseSerializer
|
||||
from structlog import get_logger
|
||||
|
||||
from passbook.core.types import UIUserSettings
|
||||
from passbook.lib.models import InheritanceForeignKey, SerializerModel
|
||||
from passbook.policies.models import PolicyBindingModel
|
||||
|
||||
|
@ -64,9 +63,9 @@ class Stage(SerializerModel):
|
|||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def ui_user_settings(self) -> Optional[UIUserSettings]:
|
||||
def ui_user_settings(self) -> Optional[str]:
|
||||
"""Entrypoint to integrate with User settings. Can either return None if no
|
||||
user settings are available, or an instanace of UIUserSettings."""
|
||||
user settings are available, or a string with the URL to fetch."""
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block main_container %}
|
||||
<flow-shell-card
|
||||
<pb-flow-shell-card
|
||||
class="pf-c-login__main"
|
||||
flowBodyUrl="{{ exec_url }}">
|
||||
</flow-shell-card>
|
||||
</pb-flow-shell-card>
|
||||
{% endblock %}
|
||||
|
|
|
@ -207,7 +207,7 @@ class TestFlowExecutor(TestCase):
|
|||
# We do this request without the patch, so the policy results in false
|
||||
response = self.client.post(exec_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse("passbook_core:overview"))
|
||||
self.assertEqual(response.url, reverse("passbook_core:shell"))
|
||||
|
||||
def test_reevaluate_remove_middle(self):
|
||||
"""Test planner with re-evaluate (middle stage is removed)"""
|
||||
|
@ -273,7 +273,7 @@ class TestFlowExecutor(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
def test_reevaluate_remove_consecutive(self):
|
||||
|
@ -349,5 +349,5 @@ class TestFlowExecutor(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
|
|
@ -144,7 +144,7 @@ class FlowExecutorView(View):
|
|||
# Since this is wrapped by the ExecutorShell, the next argument is saved in the session
|
||||
# extract the next param before cancel as that cleans it
|
||||
next_param = self.request.session.get(SESSION_KEY_GET, {}).get(
|
||||
NEXT_ARG_NAME, "passbook_core:overview"
|
||||
NEXT_ARG_NAME, "passbook_core:shell"
|
||||
)
|
||||
self.cancel()
|
||||
return redirect_with_qs(next_param)
|
||||
|
@ -248,7 +248,7 @@ class CancelView(View):
|
|||
if SESSION_KEY_PLAN in request.session:
|
||||
del request.session[SESSION_KEY_PLAN]
|
||||
LOGGER.debug("Canceled current plan")
|
||||
return redirect("passbook_core:overview")
|
||||
return redirect("passbook_core:shell")
|
||||
|
||||
|
||||
class ToDefaultFlow(View):
|
||||
|
|
|
@ -29,7 +29,7 @@ passbook:
|
|||
branding:
|
||||
title: passbook
|
||||
title_show: true
|
||||
logo: /static/passbook/logo.svg
|
||||
logo: /static/dist/assets/images/logo.svg
|
||||
# Optionally add links to the footer on the login page
|
||||
footer_links:
|
||||
- name: Documentation
|
||||
|
|
|
@ -1,44 +1,43 @@
|
|||
{% load i18n %}
|
||||
{% load static %}
|
||||
<button class="pf-c-button pf-m-tertiary" data-target="modal" data-modal="saml-{{ provider.pk }}">{% trans 'View Deployment Info' %}</button>
|
||||
|
||||
<div class="pf-c-backdrop" id="saml-{{ provider.pk }}" hidden>
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-c-modal-box pf-m-lg" role="dialog">
|
||||
<button data-modal-close class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
|
||||
<i class="fas fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="pf-c-modal-box__header">
|
||||
<h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Outpost Deployment Info' %}</h1>
|
||||
</div>
|
||||
<div class="pf-c-modal-box__body" id="modal-description">
|
||||
<p><a href="https://passbook.beryju.org/docs/outposts/outposts/#deploy">{% trans 'View deployment documentation' %}</a></p>
|
||||
<form class="pf-c-form">
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">PASSBOOK_HOST</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ full_url }}" />
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">PASSBOOK_TOKEN</span>
|
||||
</label>
|
||||
{# TODO: Only load key on modal open #}
|
||||
<input class="pf-c-form-control" data-pb-fetch-key="key" data-pb-fetch-fill="{% url 'passbook_api:token-view-key' identifier=outpost.token_identifier %}" readonly type="text" value="" />
|
||||
</div>
|
||||
<h3>{% trans 'If your passbook Instance is using a self-signed certificate, set this value.' %}</h3>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">PASSBOOK_INSECURE</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="true" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-modal-box__footer pf-m-align-left">
|
||||
<button data-modal-close class="pf-c-button pf-m-primary" type="button">{% trans 'Close' %}</button>
|
||||
</footer>
|
||||
<pb-modal-button>
|
||||
<button slot="trigger" class="pf-c-button pf-m-tertiary">
|
||||
{% trans 'View Deployment Info' %}
|
||||
</button>
|
||||
<div slot="modal">
|
||||
<div class="pf-c-modal-box__header">
|
||||
<h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Outpost Deployment Info' %}</h1>
|
||||
</div>
|
||||
<div class="pf-c-modal-box__body" id="modal-description">
|
||||
<p><a href="https://passbook.beryju.org/docs/outposts/outposts/#deploy">{% trans 'View deployment documentation' %}</a></p>
|
||||
<form class="pf-c-form">
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">PASSBOOK_HOST</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ full_url }}" />
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">PASSBOOK_TOKEN</span>
|
||||
</label>
|
||||
<div>
|
||||
<pb-token-copy-button identifier="{{ outpost.token_identifier }}">
|
||||
{% trans 'Click to copy token' %}
|
||||
</pb-token-copy-button>
|
||||
</div>
|
||||
</div>
|
||||
<h3>{% trans 'If your passbook Instance is using a self-signed certificate, set this value.' %}</h3>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">PASSBOOK_INSECURE</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="true" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-modal-box__footer pf-m-align-left">
|
||||
<a class="pf-c-button pf-m-primary">{% trans 'Close' %}</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</pb-modal-button>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""passbook PasswordExpiry Policy forms"""
|
||||
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from passbook.policies.expiry.models import PasswordExpiryPolicy
|
||||
|
@ -19,6 +18,5 @@ class PasswordExpiryPolicyForm(forms.ModelForm):
|
|||
"name": forms.TextInput(),
|
||||
"order": forms.NumberInput(),
|
||||
"days": forms.NumberInput(),
|
||||
"policies": FilteredSelectMultiple(_("policies"), False),
|
||||
}
|
||||
labels = {"deny_only": _("Only fail the policy, don't set user's password.")}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
"""passbook HaveIBeenPwned Policy forms"""
|
||||
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from passbook.policies.forms import GENERAL_FIELDS
|
||||
from passbook.policies.hibp.models import HaveIBeenPwendPolicy
|
||||
|
@ -18,5 +16,4 @@ class HaveIBeenPwnedPolicyForm(forms.ModelForm):
|
|||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"password_field": forms.TextInput(),
|
||||
"policies": FilteredSelectMultiple(_("policies"), False),
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ You've logged out of {{ application }}.
|
|||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
<a id="pb-back-home" href="{% url 'passbook_core:overview' %}" class="pf-c-button pf-m-primary">{% trans 'Go back to overview' %}</a>
|
||||
<a id="pb-back-home" href="{% url 'passbook_core:shell' %}" class="pf-c-button pf-m-primary">{% trans 'Go back to overview' %}</a>
|
||||
|
||||
<a id="logout" href="{% url 'passbook_flows:default-invalidation' %}" class="pf-c-button pf-m-secondary">{% trans 'Log out of passbook' %}</a>
|
||||
|
||||
|
|
|
@ -1,54 +1,50 @@
|
|||
{% load i18n %}
|
||||
|
||||
<button class="pf-c-button pf-m-tertiary" data-target="modal" data-modal="oauth2-{{ provider.pk }}">{% trans 'View Setup URLs' %}</button>
|
||||
|
||||
<div class="pf-c-backdrop" id="oauth2-{{ provider.pk }}" hidden>
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-c-modal-box pf-m-lg" role="dialog">
|
||||
<button data-modal-close class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
|
||||
<i class="fas fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="pf-c-modal-box__header">
|
||||
<h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Setup URLs' %}</h1>
|
||||
</div>
|
||||
<div class="pf-c-modal-box__body" id="modal-description">
|
||||
<form class="pf-c-form">
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'OpenID Configuration URL' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ provider_info }}" />
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'OpenID Configuration Issuer' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ issuer }}" />
|
||||
</div>
|
||||
<hr>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'Authorize URL' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ authorize }}" />
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'Token URL' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ token }}" />
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'Userinfo Endpoint' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ userinfo }}" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-modal-box__footer pf-m-align-left">
|
||||
<button data-modal-close class="pf-c-button pf-m-primary" type="button">{% trans 'Close' %}</button>
|
||||
</footer>
|
||||
<pb-modal-button>
|
||||
<button slot="trigger" class="pf-c-button pf-m-tertiary">
|
||||
{% trans 'View Setup URLs' %}
|
||||
</button>
|
||||
<div slot="modal">
|
||||
<div class="pf-c-modal-box__header">
|
||||
<h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Setup URLs' %}</h1>
|
||||
</div>
|
||||
<div class="pf-c-modal-box__body" id="modal-description">
|
||||
<form class="pf-c-form">
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'OpenID Configuration URL' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ provider_info }}" />
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'OpenID Configuration Issuer' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ issuer }}" />
|
||||
</div>
|
||||
<hr>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'Authorize URL' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ authorize }}" />
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'Token URL' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ token }}" />
|
||||
</div>
|
||||
<div class="pf-c-form__group">
|
||||
<label class="pf-c-form__label" for="help-text-simple-form-name">
|
||||
<span class="pf-c-form__label-text">{% trans 'Userinfo Endpoint' %}</span>
|
||||
</label>
|
||||
<input class="pf-c-form-control" readonly type="text" value="{{ userinfo }}" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-modal-box__footer pf-m-align-left">
|
||||
<a class="pf-c-button pf-m-primary">{% trans 'Close' %}</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</pb-modal-button>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""passbook SAML IDP Forms"""
|
||||
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.utils.html import mark_safe
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
@ -51,7 +50,6 @@ class SAMLProviderForm(forms.ModelForm):
|
|||
"assertion_valid_not_before": forms.TextInput(),
|
||||
"assertion_valid_not_on_or_after": forms.TextInput(),
|
||||
"session_valid_not_on_or_after": forms.TextInput(),
|
||||
"property_mappings": FilteredSelectMultiple(_("Property Mappings"), False),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -105,4 +105,4 @@ class MetadataProcessor:
|
|||
for binding in self.get_bindings():
|
||||
idp_sso_descriptor.append(binding)
|
||||
|
||||
return tostring(entity_descriptor).decode()
|
||||
return tostring(entity_descriptor, pretty_print=True).decode()
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
{% load i18n %}
|
||||
{% load static %}
|
||||
<button class="pf-c-button pf-m-tertiary" data-target="modal" data-modal="saml-{{ provider.pk }}">{% trans 'View Metadata' %}</button>
|
||||
|
||||
<div class="pf-c-backdrop" id="saml-{{ provider.pk }}" hidden>
|
||||
<div class="pf-l-bullseye">
|
||||
<div class="pf-c-modal-box pf-m-lg" role="dialog">
|
||||
<button data-modal-close class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
|
||||
<i class="fas fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="pf-c-modal-box__header">
|
||||
<h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Metadata' %}</h1>
|
||||
</div>
|
||||
<div class="pf-c-modal-box__body" id="modal-description">
|
||||
<form method="post">
|
||||
<textarea class="codemirror" readonly data-cm-mode="xml">{{ metadata }}</textarea>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-modal-box__footer pf-m-align-left">
|
||||
<button data-modal-close class="pf-c-button pf-m-primary" type="button">{% trans 'Close' %}</button>
|
||||
</footer>
|
||||
<pb-modal-button>
|
||||
<button slot="trigger" class="pf-c-button pf-m-tertiary">
|
||||
{% trans 'View Metadata' %}
|
||||
</button>
|
||||
<div slot="modal">
|
||||
<div class="pf-c-modal-box__header">
|
||||
<h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Metadata' %}</h1>
|
||||
</div>
|
||||
<div class="pf-c-modal-box__body" id="modal-description">
|
||||
<form method="post">
|
||||
<pb-codemirror mode="xml"><textarea class="pf-c-form-control"
|
||||
readonly>{{ metadata }}</textarea></pb-codemirror>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-modal-box__footer pf-m-align-left">
|
||||
<a class="pf-c-button pf-m-primary">{% trans 'Close' %}</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</pb-modal-button>
|
||||
|
||||
|
|
|
@ -21,4 +21,4 @@ class UseTokenView(View):
|
|||
login(request, token.user, backend="django.contrib.auth.backends.ModelBackend")
|
||||
token.delete()
|
||||
messages.warning(request, _("Used recovery-link to authenticate."))
|
||||
return redirect("passbook_core:overview")
|
||||
return redirect("passbook_core:shell")
|
||||
|
|
|
@ -412,6 +412,7 @@ _LOGGING_HANDLER_MAP = {
|
|||
"daphne": "WARNING",
|
||||
"dbbackup": "ERROR",
|
||||
"kubernetes": "INFO",
|
||||
"asyncio": "WARNING",
|
||||
}
|
||||
for handler_name, level in _LOGGING_HANDLER_MAP.items():
|
||||
# pyright: reportGeneralTypeIssues=false
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""passbook LDAP Forms"""
|
||||
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from passbook.admin.fields import CodeMirrorWidget
|
||||
|
@ -54,7 +53,6 @@ class LDAPSourceForm(forms.ModelForm):
|
|||
"group_object_filter": forms.TextInput(),
|
||||
"user_group_membership_field": forms.TextInput(),
|
||||
"object_uniqueness_field": forms.TextInput(),
|
||||
"property_mappings": FilteredSelectMultiple(_("Property Mappings"), False),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,12 @@ def ldap_sync_all():
|
|||
@CELERY_APP.task(bind=True, base=MonitoredTask)
|
||||
def ldap_sync(self: MonitoredTask, source_pk: int):
|
||||
"""Synchronization of an LDAP Source"""
|
||||
source: LDAPSource = LDAPSource.objects.get(pk=source_pk)
|
||||
try:
|
||||
source: LDAPSource = LDAPSource.objects.get(pk=source_pk)
|
||||
except LDAPSource.DoesNotExist:
|
||||
# Because the source couldn't be found, we don't have a UID
|
||||
# to set the state with
|
||||
return
|
||||
self.set_uid(slugify(source.name))
|
||||
try:
|
||||
syncer = LDAPSynchronizer(source)
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.urls import reverse, reverse_lazy
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from passbook.core.models import Source, UserSourceConnection
|
||||
from passbook.core.types import UILoginButton, UIUserSettings
|
||||
from passbook.core.types import UILoginButton
|
||||
|
||||
|
||||
class OAuthSource(Source):
|
||||
|
@ -66,12 +66,9 @@ class OAuthSource(Source):
|
|||
return f"Callback URL: <pre>{url}</pre>"
|
||||
|
||||
@property
|
||||
def ui_user_settings(self) -> Optional[UIUserSettings]:
|
||||
def ui_user_settings(self) -> Optional[str]:
|
||||
view_name = "passbook_sources_oauth:oauth-client-user"
|
||||
return UIUserSettings(
|
||||
name=self.name,
|
||||
url=reverse(view_name, kwargs={"source_slug": self.slug}),
|
||||
)
|
||||
return reverse(view_name, kwargs={"source_slug": self.slug})
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"OAuth Source {self.name}"
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{% extends "user/base.html" %}
|
||||
|
||||
{% load passbook_utils %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page %}
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
{% blocktrans with source_name=source.name %}
|
||||
|
@ -26,4 +22,3 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -51,5 +51,5 @@ class TestCaptchaStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
|
|
@ -51,7 +51,7 @@ class TestConsentStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
self.assertFalse(UserConsent.objects.filter(user=self.user).exists())
|
||||
|
||||
|
@ -82,7 +82,7 @@ class TestConsentStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
self.assertTrue(
|
||||
UserConsent.objects.filter(
|
||||
|
@ -119,7 +119,7 @@ class TestConsentStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
self.assertTrue(
|
||||
UserConsent.objects.filter(
|
||||
|
|
|
@ -49,7 +49,7 @@ class TestDummyStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
def test_form(self):
|
||||
|
|
|
@ -117,7 +117,7 @@ class TestEmailStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
session = self.client.session
|
||||
|
|
|
@ -59,7 +59,7 @@ class TestIdentificationStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
def test_invalid_with_username(self):
|
||||
|
|
|
@ -89,7 +89,7 @@ class TestUserLoginStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
self.stage.continue_flow_without_invitation = False
|
||||
|
@ -128,5 +128,5 @@ class TestUserLoginStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
|
|
@ -8,7 +8,6 @@ from django.utils.translation import gettext_lazy as _
|
|||
from django.views import View
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
|
||||
from passbook.core.types import UIUserSettings
|
||||
from passbook.flows.models import ConfigurableStage, Stage
|
||||
|
||||
|
||||
|
@ -36,13 +35,10 @@ class OTPStaticStage(ConfigurableStage, Stage):
|
|||
return OTPStaticStageForm
|
||||
|
||||
@property
|
||||
def ui_user_settings(self) -> Optional[UIUserSettings]:
|
||||
return UIUserSettings(
|
||||
name="Static OTP",
|
||||
url=reverse(
|
||||
"passbook_stages_otp_static:user-settings",
|
||||
kwargs={"stage_uuid": self.stage_uuid},
|
||||
),
|
||||
def ui_user_settings(self) -> Optional[str]:
|
||||
return reverse(
|
||||
"passbook_stages_otp_static:user-settings",
|
||||
kwargs={"stage_uuid": self.stage_uuid},
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{% extends "user/base.html" %}
|
||||
|
||||
{% load passbook_utils %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page %}
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
{% trans "Static One-Time Passwords" %}
|
||||
|
@ -33,4 +29,3 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -8,7 +8,6 @@ from django.utils.translation import gettext_lazy as _
|
|||
from django.views import View
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
|
||||
from passbook.core.types import UIUserSettings
|
||||
from passbook.flows.models import ConfigurableStage, Stage
|
||||
|
||||
|
||||
|
@ -43,13 +42,10 @@ class OTPTimeStage(ConfigurableStage, Stage):
|
|||
return OTPTimeStageForm
|
||||
|
||||
@property
|
||||
def ui_user_settings(self) -> Optional[UIUserSettings]:
|
||||
return UIUserSettings(
|
||||
name="Time-based OTP",
|
||||
url=reverse(
|
||||
"passbook_stages_otp_time:user-settings",
|
||||
kwargs={"stage_uuid": self.stage_uuid},
|
||||
),
|
||||
def ui_user_settings(self) -> Optional[str]:
|
||||
return reverse(
|
||||
"passbook_stages_otp_time:user-settings",
|
||||
kwargs={"stage_uuid": self.stage_uuid},
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{% extends "user/base.html" %}
|
||||
|
||||
{% load passbook_utils %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page %}
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
{% trans "Time-based One-Time Passwords" %}
|
||||
|
@ -30,4 +26,3 @@
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -8,3 +8,4 @@ class PassbookStagePasswordConfig(AppConfig):
|
|||
name = "passbook.stages.password"
|
||||
label = "passbook_stages_password"
|
||||
verbose_name = "passbook Stages.Password"
|
||||
mountpoint = "-/user/password/"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""passbook administration forms"""
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from passbook.flows.models import Flow, FlowDesignation
|
||||
|
@ -54,7 +53,5 @@ class PasswordStageForm(forms.ModelForm):
|
|||
fields = ["name", "backends", "configure_flow", "failed_attempts_before_cancel"]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"backends": FilteredSelectMultiple(
|
||||
_("backends"), False, choices=get_authentication_backends()
|
||||
),
|
||||
"backends": forms.SelectMultiple(get_authentication_backends()),
|
||||
}
|
||||
|
|
|
@ -5,14 +5,11 @@ from django.contrib.postgres.fields import ArrayField
|
|||
from django.db import models
|
||||
from django.forms import ModelForm
|
||||
from django.shortcuts import reverse
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views import View
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
|
||||
from passbook.core.types import UIUserSettings
|
||||
from passbook.flows.models import ConfigurableStage, Stage
|
||||
from passbook.flows.views import NEXT_ARG_NAME
|
||||
|
||||
|
||||
class PasswordStage(ConfigurableStage, Stage):
|
||||
|
@ -51,12 +48,12 @@ class PasswordStage(ConfigurableStage, Stage):
|
|||
return PasswordStageForm
|
||||
|
||||
@property
|
||||
def ui_user_settings(self) -> Optional[UIUserSettings]:
|
||||
def ui_user_settings(self) -> Optional[str]:
|
||||
if not self.configure_flow:
|
||||
return None
|
||||
base_url = reverse("passbook_flows:configure", kwargs={"stage_uuid": self.pk})
|
||||
args = urlencode({NEXT_ARG_NAME: reverse("passbook_core:user-settings")})
|
||||
return UIUserSettings(name=_("Change password"), url=f"{base_url}?{args}")
|
||||
return reverse(
|
||||
"passbook_stages_password:user-settings", kwargs={"stage_uuid": self.pk}
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"Password Stage {self.name}"
|
||||
|
|
|
@ -52,7 +52,7 @@ class PasswordStageView(FormView, StageView):
|
|||
"""Authentication stage which authenticates against django's AuthBackend"""
|
||||
|
||||
form_class = PasswordForm
|
||||
template_name = "stages/password/backend.html"
|
||||
template_name = "stages/password/flow-form.html"
|
||||
|
||||
def get_form(self, form_class=None) -> PasswordForm:
|
||||
form = super().get_form(form_class=form_class)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
{% extends "base/page.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load passbook_utils %}
|
||||
|
||||
{% block body %}
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
{% trans 'Reset your password' %}
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<a class="pf-c-button pf-m-primary" href="{{ url }}">
|
||||
{% trans 'Change password' %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -110,7 +110,7 @@ class TestPasswordStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
def test_invalid_password(self):
|
||||
|
|
12
passbook/stages/password/urls.py
Normal file
12
passbook/stages/password/urls.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
"""Password stage urls"""
|
||||
from django.urls import path
|
||||
|
||||
from passbook.stages.password.views import UserSettingsCardView
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"<uuid:stage_uuid>/change-card/",
|
||||
UserSettingsCardView.as_view(),
|
||||
name="user-settings",
|
||||
),
|
||||
]
|
25
passbook/stages/password/views.py
Normal file
25
passbook/stages/password/views.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
"""password stage user settings card"""
|
||||
from typing import Any
|
||||
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.shortcuts import reverse
|
||||
from django.utils.http import urlencode
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from passbook.flows.views import NEXT_ARG_NAME
|
||||
|
||||
|
||||
class UserSettingsCardView(LoginRequiredMixin, TemplateView):
|
||||
"""Card shown on user settings page to allow user to change their password"""
|
||||
|
||||
template_name = "stages/password/user-settings-card.html"
|
||||
|
||||
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||||
base_url = reverse(
|
||||
"passbook_flows:configure", kwargs={"stage_uuid": self.kwargs["stage_uuid"]}
|
||||
)
|
||||
args = urlencode({NEXT_ARG_NAME: reverse("passbook_core:user-settings")})
|
||||
|
||||
kwargs = super().get_context_data(**kwargs)
|
||||
kwargs["url"] = f"{base_url}?{args}"
|
||||
return kwargs
|
|
@ -4,7 +4,6 @@ from types import MethodType
|
|||
from typing import Any, Callable, Iterator, List
|
||||
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.db.models.query import QuerySet
|
||||
from django.http import HttpRequest
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -27,7 +26,6 @@ class PromptStageForm(forms.ModelForm):
|
|||
fields = ["name", "fields", "validation_policies"]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"fields": FilteredSelectMultiple(_("prompts"), False),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ class TestPromptStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
# Check that valid data has been saved
|
||||
|
|
|
@ -89,7 +89,7 @@ class TestUserDeleteStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
self.assertFalse(User.objects.filter(username=self.username).exists())
|
||||
|
|
|
@ -55,7 +55,7 @@ class TestUserLoginStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
@patch(
|
||||
|
|
|
@ -51,7 +51,7 @@ class TestUserLogoutStage(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{"type": "redirect", "to": reverse("passbook_core:overview")},
|
||||
{"type": "redirect", "to": reverse("passbook_core:shell")},
|
||||
)
|
||||
|
||||
def test_form(self):
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue