Merge branch 'master' into stage-challenge
# Conflicts: # authentik/api/v2/urls.py
This commit is contained in:
commit
391ee10cb8
30
Pipfile.lock
generated
30
Pipfile.lock
generated
|
@ -116,18 +116,18 @@
|
|||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:1709ff5feb363fee7fcaa2330e659fcbc2b4c03a14f75a884ed682ee66011fc4",
|
||||
"sha256:80a761eff3b1cb0798d7e1a41b7c8e6d85c9647a8f7b6105335201a69404caa2"
|
||||
"sha256:7d44cbd931c653cc68e8ccbf39f3ad8b304cb50d4e964d8c8d0936de33ff8c8b",
|
||||
"sha256:b6131751e3cf2f8d4c027518373b6b82264c3897de65d3519e2d782927e8bf1e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.10"
|
||||
"version": "==1.17.11"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:8c84eac6daf38890714e005623083106d68e9b2088e62132fdbf7d2b1228ecbd",
|
||||
"sha256:a601ee5a4ae66832f328ca362b5404d22b75f1c181f6cc0934f3cfca749eb27d"
|
||||
"sha256:8efd206b78269eb115279ca2d23f50eead1307dbe0bf9bcc2bba3ab2ff7bfd87",
|
||||
"sha256:dd7c528c6c936d941b2c267339f0b01cce377b640856240b588d0e0d82fd29e3"
|
||||
],
|
||||
"version": "==1.20.10"
|
||||
"version": "==1.20.11"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
|
@ -409,11 +409,11 @@
|
|||
},
|
||||
"docker": {
|
||||
"hashes": [
|
||||
"sha256:20d71afc593486f2297bb7fb7406b03876f31894337e914a5062050c65085cab",
|
||||
"sha256:67f33d4cf95182db631a17eef7d666d2c91f624c1d3fbc4df6009cb2f2a4c604"
|
||||
"sha256:d4625e70e3d5a12d7cbf1fd68cef2e081ac86b83889e00e5466d975f90e50dad",
|
||||
"sha256:de5753b7f6486dd541a98393e423e387579b8974a5068748b83f852cc76a89d6"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.4.2"
|
||||
"version": "==4.4.3"
|
||||
},
|
||||
"drf-yasg2": {
|
||||
"hashes": [
|
||||
|
@ -1093,11 +1093,11 @@
|
|||
},
|
||||
"sentry-sdk": {
|
||||
"hashes": [
|
||||
"sha256:9044b616ec6663cd50794fb3362efd87586e476e7b51ef2439a711d6569aede7",
|
||||
"sha256:efc65e5ffd38324797a7e1dfc8a4e74b62ea6f56a59df5bb03217b84d58dff6a"
|
||||
"sha256:4ae8d1ced6c67f1c8ea51d82a16721c166c489b76876c9f2c202b8a50334b237",
|
||||
"sha256:e75c8c58932bda8cd293ea8e4b242527129e1caaec91433d21b8b2f20fee030b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.20.2"
|
||||
"version": "==0.20.3"
|
||||
},
|
||||
"service-identity": {
|
||||
"hashes": [
|
||||
|
@ -1123,11 +1123,11 @@
|
|||
},
|
||||
"structlog": {
|
||||
"hashes": [
|
||||
"sha256:33dd6bd5f49355e52c1c61bb6a4f20d0b48ce0328cc4a45fe872d38b97a05ccd",
|
||||
"sha256:af79dfa547d104af8d60f86eac12fb54825f54a46bc998e4504ef66177103174"
|
||||
"sha256:62f06fc0ee32fb8580f0715eea66cb87271eb7efb0eaf9af6b639cba8981de47",
|
||||
"sha256:d9d2d890532e8db83c6977a2a676fb1889922ff0c26ad4dc0ecac26f9fafbc57"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==20.2.0"
|
||||
"version": "==21.1.0"
|
||||
},
|
||||
"swagger-spec-validator": {
|
||||
"hashes": [
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% 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 'Groups' %}
|
||||
</h1>
|
||||
<p>{% trans "Group users together and give them permissions based on the membership." %}
|
||||
</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">
|
||||
<ak-modal-button href="{% url 'authentik_admin:group-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'Name' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Parent' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Members' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for group in object_list %}
|
||||
<tr role="row">
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ group.name }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ group.parent }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ group.users.all|length }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:group-update' pk=group.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-modal-button href="{% url 'authentik_admin:group-delete' pk=group.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="pf-icon pf-icon-users pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Groups.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% if request.GET.search != "" %}
|
||||
{% trans "Your search query doesn't match any groups." %}
|
||||
{% else %}
|
||||
{% trans 'Currently no group exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<ak-modal-button href="{% url 'authentik_admin:group-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,153 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load humanize %}
|
||||
{% load authentik_utils %}
|
||||
|
||||
{% block content %}
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="pf-icon-integration"></i>
|
||||
{% trans 'Outpost Service-Connections' %}
|
||||
</h1>
|
||||
<p>{% trans "Outpost Service-Connections define how authentik connects to external platforms to manage and deploy Outposts." %}</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">
|
||||
<ak-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>
|
||||
</button>
|
||||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<ak-modal-button href="{% url 'authentik_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>
|
||||
</ak-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ak-dropdown>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'Name' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Type' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Local?' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Status' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for sc in object_list %}
|
||||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<span>{{ sc.name }}</span>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ sc|verbose_name }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ sc.local|yesno:"Yes,No" }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{% if sc.state.healthy %}
|
||||
<i class="fas fa-check pf-m-success"></i> {{ sc.state.version }}
|
||||
{% else %}
|
||||
<i class="fas fa-times pf-m-danger"></i> {% trans 'Unhealthy' %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:outpost-service-connection-update' pk=sc.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-modal-button href="{% url 'authentik_admin:outpost-service-connection-delete' pk=sc.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="fas fa-map-marker pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Outpost Service Connections.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% if request.GET.search != "" %}
|
||||
{% trans "Your search query doesn't match any outposts." %}
|
||||
{% else %}
|
||||
{% trans 'Currently no service connections exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<ak-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>
|
||||
</button>
|
||||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<ak-modal-button href="{% url 'authentik_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>
|
||||
</ak-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ak-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,151 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_utils %}
|
||||
|
||||
{% block content %}
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="pf-icon pf-icon-infrastructure"></i>
|
||||
{% trans 'Policies' %}
|
||||
</h1>
|
||||
<p>{% trans "Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Stages." %}</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">
|
||||
<ak-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>
|
||||
</button>
|
||||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<ak-modal-button href="{% url 'authentik_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>
|
||||
</ak-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ak-dropdown>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'Name' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Type' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for policy in object_list %}
|
||||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<div>
|
||||
<div>{{ policy.name }}</div>
|
||||
{% if not policy.bindings.exists and not policy.promptstage_set.exists %}
|
||||
<i class="pf-icon pf-icon-warning-triangle"></i>
|
||||
<small>{% trans 'Warning: Policy is not assigned.' %}</small>
|
||||
{% else %}
|
||||
<i class="pf-icon pf-icon-ok"></i>
|
||||
<small>{% blocktrans with object_count=policy.bindings.all|length %}Assigned to {{ object_count }} objects.{% endblocktrans %}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ policy|verbose_name }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:policy-update' pk=policy.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-modal-button href="{% url 'authentik_admin:policy-test' pk=policy.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Test' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-modal-button href="{% url 'authentik_admin:policy-delete' pk=policy.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="pf-icon pf-icon-infrastructure pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Policies.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% if request.GET.search != "" %}
|
||||
{% trans "Your search query doesn't match any policies." %}
|
||||
{% else %}
|
||||
{% trans 'Currently no policies exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<ak-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>
|
||||
</button>
|
||||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<ak-modal-button href="{% url 'authentik_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>
|
||||
</ak-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ak-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,119 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_utils %}
|
||||
|
||||
{% block content %}
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="pf-icon pf-icon-infrastructure"></i>
|
||||
{% trans 'Policy Bindings' %}
|
||||
</h1>
|
||||
<p>{% trans "Bind existing Policies to Models accepting policies." %}</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
{% if object_list %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<ak-modal-button href="{% url 'authentik_admin:policy-binding-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'Policy' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Enabled' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Order' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Timeout' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for pbm in object_list %}
|
||||
<tr role="role">
|
||||
<td>
|
||||
{{ pbm }}
|
||||
<small>
|
||||
{{ pbm|fieldtype }}
|
||||
</small>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% for binding in pbm.bindings %}
|
||||
<tr class="row pf-c-table__expandable-row pf-m-expanded">
|
||||
<th role="cell">
|
||||
<div>{{ binding.policy }}</div>
|
||||
<small>
|
||||
{{ binding.policy|fieldtype }}
|
||||
</small>
|
||||
</th>
|
||||
<th role="cell">
|
||||
<div>{{ binding.enabled }}</div>
|
||||
</th>
|
||||
<th role="cell">
|
||||
<div>{{ binding.order }}</div>
|
||||
</th>
|
||||
<th role="cell">
|
||||
<div>{{ binding.timeout }}</div>
|
||||
</th>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:policy-binding-update' pk=binding.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-modal-button href="{% url 'authentik_admin:policy-binding-delete' pk=binding.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% 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 Policy Bindings.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% trans 'Currently no policy bindings exist. Click the button below to create one.' %}
|
||||
</div>
|
||||
<ak-modal-button href="{% url 'authentik_admin:policy-binding-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,143 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_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-plugged"></i>
|
||||
{% trans 'Stages' %}
|
||||
</h1>
|
||||
<p>{% trans "Stages are single steps of a Flow that a user is guided through." %}</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">
|
||||
<ak-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>
|
||||
</button>
|
||||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<ak-modal-button href="{% url 'authentik_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>
|
||||
</ak-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ak-dropdown>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'Name' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Flows' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for stage in object_list %}
|
||||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<div>
|
||||
<div>{{ stage.name }}</div>
|
||||
<small>{{ stage|verbose_name }}</small>
|
||||
</div>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<ul>
|
||||
{% for flow in stage.flow_set.all %}
|
||||
<li>{{ flow.slug }}</li>
|
||||
{% empty %}
|
||||
<li>-</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-update' pk=stage.stage_uuid %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-delete' pk=stage.stage_uuid %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="pf-icon pf-icon-plugged pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Stages.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% if request.GET.search != "" %}
|
||||
{% trans "Your search query doesn't match any stages." %}
|
||||
{% else %}
|
||||
{% trans 'Currently no stages exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<ak-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>
|
||||
</button>
|
||||
<ul class="pf-c-dropdown__menu" hidden>
|
||||
{% for type, name in types.items %}
|
||||
<li>
|
||||
<ak-modal-button href="{% url 'authentik_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>
|
||||
</ak-modal-button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ak-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,125 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_utils %}
|
||||
|
||||
{% block content %}
|
||||
<section class="pf-c-page__main-section pf-m-light">
|
||||
<div class="pf-c-content">
|
||||
<h1>
|
||||
<i class="pf-icon pf-icon-infrastructure"></i>
|
||||
{% trans 'Stage Bindings' %}
|
||||
</h1>
|
||||
<p>{% trans "Bind existing Stages to Flows." %}</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
{% if object_list %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
<div class="pf-c-toolbar__bulk-select">
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-binding-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'Order' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Stage Type' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% regroup object_list by target as grouped_bindings %}
|
||||
{% for flow in grouped_bindings %}
|
||||
<tr role="role">
|
||||
<td>
|
||||
{% blocktrans with slug=flow.grouper.slug %}
|
||||
Flow {{ slug }}
|
||||
{% endblocktrans %}
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% for binding in flow.list %}
|
||||
<tr class="pf-c-table__expandable-row pf-m-expanded" role="row">
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ binding.order }}
|
||||
</span>
|
||||
</td>
|
||||
<th role="columnheader">
|
||||
<div>
|
||||
<div>{{ binding.target.slug }}</div>
|
||||
<small>
|
||||
{{ binding.target.name }}
|
||||
</small>
|
||||
</div>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<div>
|
||||
<div>
|
||||
{{ binding.stage.name }}
|
||||
</div>
|
||||
<small>
|
||||
{{ binding.stage }}
|
||||
</small>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-binding-update' pk=binding.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Update' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-binding-delete' pk=binding.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% 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 Flow-Stage Bindings.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% trans 'Currently no flow-stage bindings exist. Click the button below to create one.' %}
|
||||
</div>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-binding-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,109 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_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-migration"></i>
|
||||
{% trans 'Invitations' %}
|
||||
</h1>
|
||||
<p>{% trans "Create Invitation Links to enroll Users, and optionally force specific attributes of their account." %}
|
||||
</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">
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-invitation-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'ID' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Created by' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Expiry' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for invitation in object_list %}
|
||||
<tr role="row">
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ invitation.invite_uuid }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ invitation.created_by }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ invitation.expiry|default:"-" }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-invitation-delete' pk=invitation.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="pf-icon pf-icon-migration pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Invitations.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% if request.GET.search != "" %}
|
||||
{% trans "Your search query doesn't match any invitations." %}
|
||||
{% else %}
|
||||
{% trans 'Currently no invitations exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-invitation-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,125 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_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-plugged"></i>
|
||||
{% trans 'Prompts' %}
|
||||
</h1>
|
||||
<p>{% trans "Single Prompts that can be used for Prompt Stages." %}</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
{% 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">
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-prompt-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'Field' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Label' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Type' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Order' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Flows' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for prompt in object_list %}
|
||||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<div>
|
||||
<div>{{ prompt.field_key }}</div>
|
||||
</div>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<div>
|
||||
{{ prompt.label }}
|
||||
</div>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<div>
|
||||
{{ prompt.type }}
|
||||
</div>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<div>
|
||||
{{ prompt.order }}
|
||||
</div>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<ul>
|
||||
{% for flow in prompt.flow_set.all %}
|
||||
<li>{{ flow.slug }}</li>
|
||||
{% empty %}
|
||||
<li>-</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-prompt-update' pk=prompt.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Update' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-modal-button href="{% url 'authentik_admin:stage-prompt-delete' pk=prompt.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="pf-icon pf-icon-plugged pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Stage Prompts.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% if request.GET.search != "" %}
|
||||
{% trans "Your search query doesn't match any stage prompts." %}
|
||||
{% else %}
|
||||
{% trans 'Currently no stage prompts exist. Click the button below to create one.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="{% url 'authentik_admin:stage-prompt-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,84 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load humanize %}
|
||||
{% load authentik_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-automation"></i>
|
||||
{% trans 'System Tasks' %}
|
||||
</h1>
|
||||
<p>{% trans "Long-running operations which authentik executes in the background." %}</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
<button role="ak-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">
|
||||
<th role="columnheader" scope="col">{% trans 'Identifier' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Description' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Last Run' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Status' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Messages' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for task in object_list %}
|
||||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<span>{{ task.html_name|join:"_­" }}</span>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ task.task_description }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ task.finish_timestamp|naturaltime }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{% if task.result.status == task_successful %}
|
||||
<i class="fas fa-check pf-m-success"></i> {% trans 'Successful' %}
|
||||
{% elif task.result.status == task_warning %}
|
||||
<i class="fas fa-exclamation-triangle pf-m-warning"></i> {% trans 'Warning' %}
|
||||
{% elif task.result.status == task_error %}
|
||||
<i class="fas fa-times pf-m-danger"></i> {% trans 'Error' %}
|
||||
{% else %}
|
||||
<i class="fas fa-question-circle"></i> {% trans 'Unknown' %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{% for message in task.result.messages %}
|
||||
<div>
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
<ak-action-button url="{% url 'authentik_api:admin_system_tasks-retry' pk=task.task_name %}">
|
||||
{% trans 'Retry Task' %}
|
||||
</ak-action-button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,102 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_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-security"></i>
|
||||
{% trans 'Tokens' %}
|
||||
</h1>
|
||||
<p>{% trans "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access." %}</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' %}
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'User' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Expires?' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Expiry Date' %}</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.user }}
|
||||
</span>
|
||||
</td>
|
||||
<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>
|
||||
<ak-modal-button href="{% url 'authentik_admin:token-delete' pk=token.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
{% trans 'Delete' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-token-copy-button identifier="{{ token.identifier }}">
|
||||
{% trans 'Copy token' %}
|
||||
</ak-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-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="fas fa-key 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">
|
||||
{% if request.GET.search != "" %}
|
||||
{% trans "Your search query doesn't match any token." %}
|
||||
{% else %}
|
||||
{% trans 'Currently no tokens exist.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,125 +0,0 @@
|
|||
{% extends "administration/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load authentik_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-user"></i>
|
||||
{% trans 'Users' %}
|
||||
</h1>
|
||||
</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">
|
||||
<ak-modal-button href="{% url 'authentik_admin:user-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
||||
{% trans 'Refresh' %}
|
||||
</button>
|
||||
</div>
|
||||
{% include 'partials/pagination.html' %}
|
||||
</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 'Name' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Active' %}</th>
|
||||
<th role="columnheader" scope="col">{% trans 'Last Login' %}</th>
|
||||
<th role="cell"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody role="rowgroup">
|
||||
{% for user in object_list %}
|
||||
<tr role="row">
|
||||
<th role="columnheader">
|
||||
<div>
|
||||
<div>{{ user.username }}</div>
|
||||
<small>{{ user.name }}</small>
|
||||
</div>
|
||||
</th>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ user.is_active }}
|
||||
</span>
|
||||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ user.last_login }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<ak-modal-button href="{% url 'authentik_admin:user-update' pk=user.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||
{% trans 'Edit' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
{% if user.is_active %}
|
||||
<ak-modal-button href="{% url 'authentik_admin:user-disable' pk=user.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-warning">
|
||||
{% trans 'Disable' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
{% else %}
|
||||
<ak-modal-button href="{% url 'authentik_admin:user-delete' pk=user.pk %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Enable' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
{% endif %}
|
||||
<a class="pf-c-button pf-m-tertiary ak-root-link" href="{% url 'authentik_admin:user-password-reset' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Reset Password' %}</a>
|
||||
<a class="pf-c-button pf-m-tertiary ak-root-link" href="{% url 'authentik_core:impersonate-init' user_id=user.pk %}">{% trans 'Impersonate' %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pf-c-pagination pf-m-bottom">
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pf-c-toolbar">
|
||||
<div class="pf-c-toolbar__content">
|
||||
{% include 'partials/toolbar_search.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-c-empty-state">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="pf-icon pf-icon-user pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">
|
||||
{% trans 'No Users.' %}
|
||||
</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
{% if request.GET.search != "" %}
|
||||
{% trans "Your search query doesn't match any users." %}
|
||||
{% else %}
|
||||
{% trans 'Currently no users exist. How did you even get here.' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<ak-modal-button href="{% url 'authentik_admin:user-create' %}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
||||
{% trans 'Create' %}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -20,7 +20,6 @@ from authentik.admin.views import (
|
|||
stages_bindings,
|
||||
stages_invitations,
|
||||
stages_prompts,
|
||||
tasks,
|
||||
tokens,
|
||||
users,
|
||||
)
|
||||
|
@ -54,7 +53,6 @@ urlpatterns = [
|
|||
name="application-delete",
|
||||
),
|
||||
# Tokens
|
||||
path("tokens/", tokens.TokenListView.as_view(), name="tokens"),
|
||||
path(
|
||||
"tokens/<uuid:pk>/delete/",
|
||||
tokens.TokenDeleteView.as_view(),
|
||||
|
@ -73,7 +71,6 @@ urlpatterns = [
|
|||
name="source-delete",
|
||||
),
|
||||
# Policies
|
||||
path("policies/", policies.PolicyListView.as_view(), name="policies"),
|
||||
path("policies/create/", policies.PolicyCreateView.as_view(), name="policy-create"),
|
||||
path(
|
||||
"policies/<uuid:pk>/update/",
|
||||
|
@ -91,11 +88,6 @@ urlpatterns = [
|
|||
name="policy-test",
|
||||
),
|
||||
# Policy bindings
|
||||
path(
|
||||
"policies/bindings/",
|
||||
policies_bindings.PolicyBindingListView.as_view(),
|
||||
name="policies-bindings",
|
||||
),
|
||||
path(
|
||||
"policies/bindings/create/",
|
||||
policies_bindings.PolicyBindingCreateView.as_view(),
|
||||
|
@ -133,7 +125,6 @@ urlpatterns = [
|
|||
name="provider-delete",
|
||||
),
|
||||
# Stages
|
||||
path("stages/", stages.StageListView.as_view(), name="stages"),
|
||||
path("stages/create/", stages.StageCreateView.as_view(), name="stage-create"),
|
||||
path(
|
||||
"stages/<uuid:pk>/update/",
|
||||
|
@ -146,11 +137,6 @@ urlpatterns = [
|
|||
name="stage-delete",
|
||||
),
|
||||
# Stage bindings
|
||||
path(
|
||||
"stages/bindings/",
|
||||
stages_bindings.StageBindingListView.as_view(),
|
||||
name="stage-bindings",
|
||||
),
|
||||
path(
|
||||
"stages/bindings/create/",
|
||||
stages_bindings.StageBindingCreateView.as_view(),
|
||||
|
@ -167,11 +153,6 @@ urlpatterns = [
|
|||
name="stage-binding-delete",
|
||||
),
|
||||
# Stage Prompts
|
||||
path(
|
||||
"stages_prompts/",
|
||||
stages_prompts.PromptListView.as_view(),
|
||||
name="stage-prompts",
|
||||
),
|
||||
path(
|
||||
"stages_prompts/create/",
|
||||
stages_prompts.PromptCreateView.as_view(),
|
||||
|
@ -188,11 +169,6 @@ urlpatterns = [
|
|||
name="stage-prompt-delete",
|
||||
),
|
||||
# Stage Invitations
|
||||
path(
|
||||
"stages/invitations/",
|
||||
stages_invitations.InvitationListView.as_view(),
|
||||
name="stage-invitations",
|
||||
),
|
||||
path(
|
||||
"stages/invitations/create/",
|
||||
stages_invitations.InvitationCreateView.as_view(),
|
||||
|
@ -256,7 +232,6 @@ urlpatterns = [
|
|||
name="property-mapping-test",
|
||||
),
|
||||
# Users
|
||||
path("users/", users.UserListView.as_view(), name="users"),
|
||||
path("users/create/", users.UserCreateView.as_view(), name="user-create"),
|
||||
path("users/<int:pk>/update/", users.UserUpdateView.as_view(), name="user-update"),
|
||||
path("users/<int:pk>/delete/", users.UserDeleteView.as_view(), name="user-delete"),
|
||||
|
@ -270,7 +245,6 @@ urlpatterns = [
|
|||
name="user-password-reset",
|
||||
),
|
||||
# Groups
|
||||
path("groups/", groups.GroupListView.as_view(), name="groups"),
|
||||
path("groups/create/", groups.GroupCreateView.as_view(), name="group-create"),
|
||||
path(
|
||||
"groups/<uuid:pk>/update/",
|
||||
|
@ -320,11 +294,6 @@ urlpatterns = [
|
|||
name="outpost-delete",
|
||||
),
|
||||
# Outpost Service Connections
|
||||
path(
|
||||
"outpost_service_connections/",
|
||||
outposts_service_connections.OutpostServiceConnectionListView.as_view(),
|
||||
name="outpost-service-connections",
|
||||
),
|
||||
path(
|
||||
"outpost_service_connections/create/",
|
||||
outposts_service_connections.OutpostServiceConnectionCreateView.as_view(),
|
||||
|
@ -340,12 +309,6 @@ urlpatterns = [
|
|||
outposts_service_connections.OutpostServiceConnectionDeleteView.as_view(),
|
||||
name="outpost-service-connection-delete",
|
||||
),
|
||||
# Tasks
|
||||
path(
|
||||
"tasks/",
|
||||
tasks.TaskListView.as_view(),
|
||||
name="tasks",
|
||||
),
|
||||
# Event Notification Transpots
|
||||
path(
|
||||
"events/transports/create/",
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.views.generic import UpdateView
|
|||
from guardian.mixins import PermissionRequiredMixin
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
|
||||
from authentik.admin.views.utils import BackSuccessUrlMixin, DeleteMessageView
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.core.forms.applications import ApplicationForm
|
||||
from authentik.core.models import Application
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
|
@ -19,7 +19,6 @@ from authentik.lib.views import CreateAssignPermView
|
|||
|
||||
class ApplicationCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -52,7 +51,6 @@ class ApplicationCreateView(
|
|||
|
||||
class ApplicationUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
|
|
@ -10,7 +10,7 @@ from django.views.generic import UpdateView
|
|||
from django.views.generic.edit import FormView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import BackSuccessUrlMixin, DeleteMessageView
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.crypto.builder import CertificateBuilder
|
||||
from authentik.crypto.forms import (
|
||||
CertificateKeyPairForm,
|
||||
|
@ -22,7 +22,6 @@ from authentik.lib.views import CreateAssignPermView
|
|||
|
||||
class CertificateKeyPairCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -40,7 +39,6 @@ class CertificateKeyPairCreateView(
|
|||
|
||||
class CertificateKeyPairGenerateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
FormView,
|
||||
|
@ -68,7 +66,6 @@ class CertificateKeyPairGenerateView(
|
|||
|
||||
class CertificateKeyPairUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.utils.translation import gettext as _
|
|||
from django.views.generic import UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import BackSuccessUrlMixin, DeleteMessageView
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.events.forms import NotificationRuleForm
|
||||
from authentik.events.models import NotificationRule
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
|
@ -16,7 +16,6 @@ from authentik.lib.views import CreateAssignPermView
|
|||
|
||||
class NotificationRuleCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -33,7 +32,6 @@ class NotificationRuleCreateView(
|
|||
|
||||
class NotificationRuleUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.utils.translation import gettext as _
|
|||
from django.views.generic import UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import BackSuccessUrlMixin, DeleteMessageView
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.events.forms import NotificationTransportForm
|
||||
from authentik.events.models import NotificationTransport
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
|
@ -16,7 +16,6 @@ from authentik.lib.views import CreateAssignPermView
|
|||
|
||||
class NotificationTransportCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -33,7 +32,6 @@ class NotificationTransportCreateView(
|
|||
|
||||
class NotificationTransportUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
|
|
@ -10,7 +10,7 @@ from django.utils.translation import gettext as _
|
|||
from django.views.generic import DetailView, FormView, UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import BackSuccessUrlMixin, DeleteMessageView
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.flows.exceptions import FlowNonApplicableException
|
||||
from authentik.flows.forms import FlowForm, FlowImportForm
|
||||
from authentik.flows.models import Flow
|
||||
|
@ -25,7 +25,6 @@ from authentik.lib.views import CreateAssignPermView, bad_request_message
|
|||
|
||||
class FlowCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -43,7 +42,6 @@ class FlowCreateView(
|
|||
|
||||
class FlowUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
|
|
@ -4,41 +4,18 @@ from django.contrib.auth.mixins import (
|
|||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView, UpdateView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from django.views.generic import UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.core.forms.groups import GroupForm
|
||||
from authentik.core.models import Group
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
|
||||
|
||||
class GroupListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
ListView,
|
||||
):
|
||||
"""Show list of all groups"""
|
||||
|
||||
model = Group
|
||||
permission_required = "authentik_core.view_group"
|
||||
ordering = "name"
|
||||
template_name = "administration/group/list.html"
|
||||
search_fields = ["name", "attributes"]
|
||||
|
||||
|
||||
class GroupCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -50,13 +27,12 @@ class GroupCreateView(
|
|||
permission_required = "authentik_core.add_group"
|
||||
|
||||
template_name = "generic/create.html"
|
||||
success_url = reverse_lazy("authentik_admin:groups")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created Group")
|
||||
|
||||
|
||||
class GroupUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
@ -68,7 +44,7 @@ class GroupUpdateView(
|
|||
permission_required = "authentik_core.change_group"
|
||||
|
||||
template_name = "generic/update.html"
|
||||
success_url = reverse_lazy("authentik_admin:groups")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully updated Group")
|
||||
|
||||
|
||||
|
@ -79,5 +55,5 @@ class GroupDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessage
|
|||
permission_required = "authentik_flows.delete_group"
|
||||
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:groups")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted Group")
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.utils.translation import gettext as _
|
|||
from django.views.generic import UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import BackSuccessUrlMixin, DeleteMessageView
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
from authentik.outposts.forms import OutpostForm
|
||||
from authentik.outposts.models import Outpost, OutpostConfig
|
||||
|
@ -19,7 +19,6 @@ from authentik.outposts.models import Outpost, OutpostConfig
|
|||
|
||||
class OutpostCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -43,7 +42,6 @@ class OutpostCreateView(
|
|||
|
||||
class OutpostUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
|
|
@ -4,41 +4,19 @@ from django.contrib.auth.mixins import (
|
|||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
InheritanceCreateView,
|
||||
InheritanceListView,
|
||||
InheritanceUpdateView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.outposts.models import OutpostServiceConnection
|
||||
|
||||
|
||||
class OutpostServiceConnectionListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
InheritanceListView,
|
||||
):
|
||||
"""Show list of all outpost-service-connections"""
|
||||
|
||||
model = OutpostServiceConnection
|
||||
permission_required = "authentik_outposts.add_outpostserviceconnection"
|
||||
template_name = "administration/outpost_service_connection/list.html"
|
||||
ordering = "pk"
|
||||
search_fields = ["pk", "name"]
|
||||
|
||||
|
||||
class OutpostServiceConnectionCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
InheritanceCreateView,
|
||||
|
@ -49,13 +27,12 @@ class OutpostServiceConnectionCreateView(
|
|||
permission_required = "authentik_outposts.add_outpostserviceconnection"
|
||||
|
||||
template_name = "generic/create.html"
|
||||
success_url = reverse_lazy("authentik_admin:outpost-service-connections")
|
||||
success_message = _("Successfully created OutpostServiceConnection")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created Outpost Service Connection")
|
||||
|
||||
|
||||
class OutpostServiceConnectionUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
InheritanceUpdateView,
|
||||
|
@ -66,8 +43,8 @@ class OutpostServiceConnectionUpdateView(
|
|||
permission_required = "authentik_outposts.change_outpostserviceconnection"
|
||||
|
||||
template_name = "generic/update.html"
|
||||
success_url = reverse_lazy("authentik_admin:outpost-service-connections")
|
||||
success_message = _("Successfully updated OutpostServiceConnection")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully updated Outpost Service Connection")
|
||||
|
||||
|
||||
class OutpostServiceConnectionDeleteView(
|
||||
|
@ -79,5 +56,5 @@ class OutpostServiceConnectionDeleteView(
|
|||
permission_required = "authentik_outposts.delete_outpostserviceconnection"
|
||||
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:outpost-service-connections")
|
||||
success_message = _("Successfully deleted OutpostServiceConnection")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted Outpost Service Connection")
|
||||
|
|
|
@ -7,45 +7,23 @@ from django.contrib.auth.mixins import (
|
|||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.http import HttpResponse
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import FormView
|
||||
from django.views.generic.detail import DetailView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.forms.policies import PolicyTestForm
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
InheritanceCreateView,
|
||||
InheritanceListView,
|
||||
InheritanceUpdateView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.policies.models import Policy, PolicyBinding
|
||||
from authentik.policies.process import PolicyProcess, PolicyRequest
|
||||
|
||||
|
||||
class PolicyListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
InheritanceListView,
|
||||
):
|
||||
"""Show list of all policies"""
|
||||
|
||||
model = Policy
|
||||
permission_required = "authentik_policies.view_policy"
|
||||
ordering = "name"
|
||||
template_name = "administration/policy/list.html"
|
||||
search_fields = ["name"]
|
||||
|
||||
|
||||
class PolicyCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
InheritanceCreateView,
|
||||
|
@ -56,13 +34,12 @@ class PolicyCreateView(
|
|||
permission_required = "authentik_policies.add_policy"
|
||||
|
||||
template_name = "generic/create.html"
|
||||
success_url = reverse_lazy("authentik_admin:policies")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created Policy")
|
||||
|
||||
|
||||
class PolicyUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
InheritanceUpdateView,
|
||||
|
@ -73,7 +50,7 @@ class PolicyUpdateView(
|
|||
permission_required = "authentik_policies.change_policy"
|
||||
|
||||
template_name = "generic/update.html"
|
||||
success_url = reverse_lazy("authentik_admin:policies")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully updated Policy")
|
||||
|
||||
|
||||
|
@ -84,7 +61,7 @@ class PolicyDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessag
|
|||
permission_required = "authentik_policies.delete_policy"
|
||||
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:policies")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted Policy")
|
||||
|
||||
|
||||
|
|
|
@ -6,55 +6,19 @@ from django.contrib.auth.mixins import (
|
|||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.db.models import Max, QuerySet
|
||||
from django.urls import reverse_lazy
|
||||
from django.db.models import Max
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView, UpdateView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from django.views.generic import UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
from authentik.policies.forms import PolicyBindingForm
|
||||
from authentik.policies.models import PolicyBinding, PolicyBindingModel
|
||||
|
||||
|
||||
class PolicyBindingListView(
|
||||
LoginRequiredMixin, PermissionListMixin, UserPaginateListMixin, ListView
|
||||
):
|
||||
"""Show list of all policies"""
|
||||
|
||||
model = PolicyBinding
|
||||
permission_required = "authentik_policies.view_policybinding"
|
||||
ordering = ["order", "target"]
|
||||
template_name = "administration/policy_binding/list.html"
|
||||
|
||||
def get_queryset(self) -> QuerySet:
|
||||
# Since `select_subclasses` does not work with a foreign key, we have to do two queries here
|
||||
# First, get all pbm objects that have bindings attached
|
||||
objects = (
|
||||
get_objects_for_user(
|
||||
self.request.user, "authentik_policies.view_policybindingmodel"
|
||||
)
|
||||
.filter(policies__isnull=False)
|
||||
.select_subclasses()
|
||||
.select_related()
|
||||
.order_by("pk")
|
||||
)
|
||||
for pbm in objects:
|
||||
pbm.bindings = get_objects_for_user(
|
||||
self.request.user, self.permission_required
|
||||
).filter(target__pk=pbm.pbm_uuid)
|
||||
return objects
|
||||
|
||||
|
||||
class PolicyBindingCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -66,7 +30,7 @@ class PolicyBindingCreateView(
|
|||
form_class = PolicyBindingForm
|
||||
|
||||
template_name = "generic/create.html"
|
||||
success_url = reverse_lazy("authentik_admin:policies-bindings")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created PolicyBinding")
|
||||
|
||||
def get_initial(self) -> dict[str, Any]:
|
||||
|
@ -88,7 +52,6 @@ class PolicyBindingCreateView(
|
|||
|
||||
class PolicyBindingUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
@ -100,7 +63,7 @@ class PolicyBindingUpdateView(
|
|||
form_class = PolicyBindingForm
|
||||
|
||||
template_name = "generic/update.html"
|
||||
success_url = reverse_lazy("authentik_admin:policies-bindings")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully updated PolicyBinding")
|
||||
|
||||
|
||||
|
@ -113,5 +76,5 @@ class PolicyBindingDeleteView(
|
|||
permission_required = "authentik_policies.delete_policybinding"
|
||||
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:policies-bindings")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted PolicyBinding")
|
||||
|
|
|
@ -15,7 +15,6 @@ from guardian.mixins import PermissionRequiredMixin
|
|||
|
||||
from authentik.admin.forms.policies import PolicyTestForm
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
InheritanceCreateView,
|
||||
InheritanceUpdateView,
|
||||
|
@ -25,7 +24,6 @@ from authentik.core.models import PropertyMapping
|
|||
|
||||
class PropertyMappingCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
InheritanceCreateView,
|
||||
|
@ -41,7 +39,6 @@ class PropertyMappingCreateView(
|
|||
|
||||
class PropertyMappingUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
InheritanceUpdateView,
|
||||
|
|
|
@ -8,7 +8,6 @@ from django.utils.translation import gettext as _
|
|||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
InheritanceCreateView,
|
||||
InheritanceUpdateView,
|
||||
|
@ -18,7 +17,6 @@ from authentik.core.models import Provider
|
|||
|
||||
class ProviderCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
InheritanceCreateView,
|
||||
|
@ -34,7 +32,6 @@ class ProviderCreateView(
|
|||
|
||||
class ProviderUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
InheritanceUpdateView,
|
||||
|
|
|
@ -8,7 +8,6 @@ from django.utils.translation import gettext as _
|
|||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
InheritanceCreateView,
|
||||
InheritanceUpdateView,
|
||||
|
@ -18,7 +17,6 @@ from authentik.core.models import Source
|
|||
|
||||
class SourceCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
InheritanceCreateView,
|
||||
|
@ -34,7 +32,6 @@ class SourceCreateView(
|
|||
|
||||
class SourceUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
InheritanceUpdateView,
|
||||
|
|
|
@ -4,41 +4,19 @@ from django.contrib.auth.mixins import (
|
|||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
InheritanceCreateView,
|
||||
InheritanceListView,
|
||||
InheritanceUpdateView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.flows.models import Stage
|
||||
|
||||
|
||||
class StageListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
InheritanceListView,
|
||||
):
|
||||
"""Show list of all stages"""
|
||||
|
||||
model = Stage
|
||||
template_name = "administration/stage/list.html"
|
||||
permission_required = "authentik_flows.view_stage"
|
||||
ordering = "name"
|
||||
search_fields = ["name"]
|
||||
|
||||
|
||||
class StageCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
InheritanceCreateView,
|
||||
|
@ -49,13 +27,12 @@ class StageCreateView(
|
|||
template_name = "generic/create.html"
|
||||
permission_required = "authentik_flows.add_stage"
|
||||
|
||||
success_url = reverse_lazy("authentik_admin:stages")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created Stage")
|
||||
|
||||
|
||||
class StageUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
InheritanceUpdateView,
|
||||
|
@ -65,7 +42,7 @@ class StageUpdateView(
|
|||
model = Stage
|
||||
permission_required = "authentik_flows.update_application"
|
||||
template_name = "generic/update.html"
|
||||
success_url = reverse_lazy("authentik_admin:stages")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully updated Stage")
|
||||
|
||||
|
||||
|
@ -75,5 +52,5 @@ class StageDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessage
|
|||
model = Stage
|
||||
template_name = "generic/delete.html"
|
||||
permission_required = "authentik_flows.delete_stage"
|
||||
success_url = reverse_lazy("authentik_admin:stages")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted Stage")
|
||||
|
|
|
@ -7,35 +7,18 @@ from django.contrib.auth.mixins import (
|
|||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.db.models import Max
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView, UpdateView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from django.views.generic import UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.flows.forms import FlowStageBindingForm
|
||||
from authentik.flows.models import Flow, FlowStageBinding
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
|
||||
|
||||
class StageBindingListView(
|
||||
LoginRequiredMixin, PermissionListMixin, UserPaginateListMixin, ListView
|
||||
):
|
||||
"""Show list of all flows"""
|
||||
|
||||
model = FlowStageBinding
|
||||
permission_required = "authentik_flows.view_flowstagebinding"
|
||||
ordering = ["target", "order"]
|
||||
template_name = "administration/stage_binding/list.html"
|
||||
|
||||
|
||||
class StageBindingCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -47,7 +30,7 @@ class StageBindingCreateView(
|
|||
form_class = FlowStageBindingForm
|
||||
|
||||
template_name = "generic/create.html"
|
||||
success_url = reverse_lazy("authentik_admin:stage-bindings")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created StageBinding")
|
||||
|
||||
def get_initial(self) -> dict[str, Any]:
|
||||
|
@ -67,7 +50,6 @@ class StageBindingCreateView(
|
|||
|
||||
class StageBindingUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
@ -79,7 +61,7 @@ class StageBindingUpdateView(
|
|||
form_class = FlowStageBindingForm
|
||||
|
||||
template_name = "generic/update.html"
|
||||
success_url = reverse_lazy("authentik_admin:stage-bindings")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully updated StageBinding")
|
||||
|
||||
|
||||
|
@ -92,5 +74,5 @@ class StageBindingDeleteView(
|
|||
permission_required = "authentik_flows.delete_flowstagebinding"
|
||||
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:stage-bindings")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted FlowStageBinding")
|
||||
|
|
|
@ -5,41 +5,17 @@ from django.contrib.auth.mixins import (
|
|||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
from authentik.stages.invitation.forms import InvitationForm
|
||||
from authentik.stages.invitation.models import Invitation
|
||||
|
||||
|
||||
class InvitationListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
ListView,
|
||||
):
|
||||
"""Show list of all invitations"""
|
||||
|
||||
model = Invitation
|
||||
permission_required = "authentik_stages_invitation.view_invitation"
|
||||
template_name = "administration/stage_invitation/list.html"
|
||||
ordering = "-expires"
|
||||
search_fields = ["created_by__username", "expires", "fixed_data"]
|
||||
|
||||
|
||||
class InvitationCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -51,7 +27,7 @@ class InvitationCreateView(
|
|||
permission_required = "authentik_stages_invitation.add_invitation"
|
||||
|
||||
template_name = "generic/create.html"
|
||||
success_url = reverse_lazy("authentik_admin:stage-invitations")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created Invitation")
|
||||
|
||||
def form_valid(self, form):
|
||||
|
@ -70,5 +46,5 @@ class InvitationDeleteView(
|
|||
permission_required = "authentik_stages_invitation.delete_invitation"
|
||||
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:stage-invitations")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted Invitation")
|
||||
|
|
|
@ -4,46 +4,18 @@ from django.contrib.auth.mixins import (
|
|||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView, UpdateView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from django.views.generic import UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
from authentik.stages.prompt.forms import PromptAdminForm
|
||||
from authentik.stages.prompt.models import Prompt
|
||||
|
||||
|
||||
class PromptListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
ListView,
|
||||
):
|
||||
"""Show list of all prompts"""
|
||||
|
||||
model = Prompt
|
||||
permission_required = "authentik_stages_prompt.view_prompt"
|
||||
ordering = "order"
|
||||
template_name = "administration/stage_prompt/list.html"
|
||||
search_fields = [
|
||||
"field_key",
|
||||
"label",
|
||||
"type",
|
||||
"placeholder",
|
||||
]
|
||||
|
||||
|
||||
class PromptCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -55,13 +27,12 @@ class PromptCreateView(
|
|||
permission_required = "authentik_stages_prompt.add_prompt"
|
||||
|
||||
template_name = "generic/create.html"
|
||||
success_url = reverse_lazy("authentik_admin:stage-prompts")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created Prompt")
|
||||
|
||||
|
||||
class PromptUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
@ -73,7 +44,7 @@ class PromptUpdateView(
|
|||
permission_required = "authentik_stages_prompt.change_prompt"
|
||||
|
||||
template_name = "generic/update.html"
|
||||
success_url = reverse_lazy("authentik_admin:stage-prompts")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully updated Prompt")
|
||||
|
||||
|
||||
|
@ -84,5 +55,5 @@ class PromptDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessag
|
|||
permission_required = "authentik_stages_prompt.delete_prompt"
|
||||
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:stage-prompts")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted Prompt")
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
"""authentik Tasks List"""
|
||||
from typing import Any
|
||||
|
||||
from django.views.generic.base import TemplateView
|
||||
|
||||
from authentik.admin.mixins import AdminRequiredMixin
|
||||
from authentik.events.monitored_tasks import TaskInfo, TaskResultStatus
|
||||
|
||||
|
||||
class TaskListView(AdminRequiredMixin, TemplateView):
|
||||
"""Show list of all background tasks"""
|
||||
|
||||
template_name = "administration/task/list.html"
|
||||
|
||||
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||||
kwargs = super().get_context_data(**kwargs)
|
||||
kwargs["object_list"] = sorted(
|
||||
TaskInfo.all().values(), key=lambda x: x.task_name
|
||||
)
|
||||
kwargs["task_successful"] = TaskResultStatus.SUCCESSFUL
|
||||
kwargs["task_warning"] = TaskResultStatus.WARNING
|
||||
kwargs["task_error"] = TaskResultStatus.ERROR
|
||||
return kwargs
|
|
@ -1,39 +1,12 @@
|
|||
"""authentik Token administration"""
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
DeleteMessageView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.core.models import Token
|
||||
|
||||
|
||||
class TokenListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
ListView,
|
||||
):
|
||||
"""Show list of all tokens"""
|
||||
|
||||
model = Token
|
||||
permission_required = "authentik_core.view_token"
|
||||
ordering = "expires"
|
||||
template_name = "administration/token/list.html"
|
||||
search_fields = [
|
||||
"identifier",
|
||||
"intent",
|
||||
"user__username",
|
||||
"description",
|
||||
]
|
||||
|
||||
|
||||
class TokenDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageView):
|
||||
"""Delete token"""
|
||||
|
||||
|
@ -41,5 +14,5 @@ class TokenDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessage
|
|||
permission_required = "authentik_core.delete_token"
|
||||
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:tokens")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted Token")
|
||||
|
|
|
@ -7,50 +7,20 @@ from django.contrib.auth.mixins import (
|
|||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.http.response import HttpResponseRedirect
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.shortcuts import redirect, reverse
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import DetailView, ListView, UpdateView
|
||||
from guardian.mixins import (
|
||||
PermissionListMixin,
|
||||
PermissionRequiredMixin,
|
||||
get_anonymous_user,
|
||||
)
|
||||
from django.views.generic import DetailView, UpdateView
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
|
||||
from authentik.admin.forms.users import UserForm
|
||||
from authentik.admin.views.utils import (
|
||||
BackSuccessUrlMixin,
|
||||
DeleteMessageView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.core.models import Token, User
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
|
||||
|
||||
class UserListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
ListView,
|
||||
):
|
||||
"""Show list of all users"""
|
||||
|
||||
model = User
|
||||
permission_required = "authentik_core.view_user"
|
||||
ordering = "username"
|
||||
template_name = "administration/user/list.html"
|
||||
search_fields = ["username", "name", "attributes"]
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().exclude(pk=get_anonymous_user().pk)
|
||||
|
||||
|
||||
class UserCreateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
DjangoPermissionRequiredMixin,
|
||||
CreateAssignPermView,
|
||||
|
@ -62,13 +32,12 @@ class UserCreateView(
|
|||
permission_required = "authentik_core.add_user"
|
||||
|
||||
template_name = "generic/create.html"
|
||||
success_url = reverse_lazy("authentik_admin:users")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully created User")
|
||||
|
||||
|
||||
class UserUpdateView(
|
||||
SuccessMessageMixin,
|
||||
BackSuccessUrlMixin,
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
UpdateView,
|
||||
|
@ -82,7 +51,7 @@ class UserUpdateView(
|
|||
# By default the object's name is user which is used by other checks
|
||||
context_object_name = "object"
|
||||
template_name = "generic/update.html"
|
||||
success_url = reverse_lazy("authentik_admin:users")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully updated User")
|
||||
|
||||
|
||||
|
@ -95,13 +64,11 @@ class UserDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageV
|
|||
# By default the object's name is user which is used by other checks
|
||||
context_object_name = "object"
|
||||
template_name = "generic/delete.html"
|
||||
success_url = reverse_lazy("authentik_admin:users")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully deleted User")
|
||||
|
||||
|
||||
class UserDisableView(
|
||||
LoginRequiredMixin, PermissionRequiredMixin, BackSuccessUrlMixin, DeleteMessageView
|
||||
):
|
||||
class UserDisableView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageView):
|
||||
"""Disable user"""
|
||||
|
||||
object: User
|
||||
|
@ -112,7 +79,7 @@ class UserDisableView(
|
|||
# By default the object's name is user which is used by other checks
|
||||
context_object_name = "object"
|
||||
template_name = "administration/user/disable.html"
|
||||
success_url = reverse_lazy("authentik_admin:users")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully disabled User")
|
||||
|
||||
def delete(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
|
@ -123,9 +90,7 @@ class UserDisableView(
|
|||
return HttpResponseRedirect(success_url)
|
||||
|
||||
|
||||
class UserEnableView(
|
||||
LoginRequiredMixin, PermissionRequiredMixin, BackSuccessUrlMixin, DetailView
|
||||
):
|
||||
class UserEnableView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
"""Enable user"""
|
||||
|
||||
object: User
|
||||
|
@ -135,15 +100,14 @@ class UserEnableView(
|
|||
|
||||
# By default the object's name is user which is used by other checks
|
||||
context_object_name = "object"
|
||||
success_url = reverse_lazy("authentik_admin:users")
|
||||
success_url = "/"
|
||||
success_message = _("Successfully enabled User")
|
||||
|
||||
def get(self, request: HttpRequest, *args, **kwargs):
|
||||
self.object: User = self.get_object()
|
||||
success_url = self.get_success_url()
|
||||
self.object.is_active = True
|
||||
self.object.save()
|
||||
return HttpResponseRedirect(success_url)
|
||||
return HttpResponseRedirect(self.success_url)
|
||||
|
||||
|
||||
class UserPasswordResetView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
|
@ -165,4 +129,4 @@ class UserPasswordResetView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
|
|||
messages.success(
|
||||
request, _("Password reset link: <pre>%(link)s</pre>" % {"link": link})
|
||||
)
|
||||
return redirect("authentik_admin:users")
|
||||
return redirect("/")
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
"""authentik admin util views"""
|
||||
from typing import Any, Optional
|
||||
from urllib.parse import urlparse
|
||||
from typing import Any
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.contrib.postgres.search import SearchQuery, SearchVector
|
||||
from django.db.models import QuerySet
|
||||
from django.http import Http404
|
||||
from django.http.request import HttpRequest
|
||||
from django.views.generic import DeleteView, ListView, UpdateView
|
||||
from django.views.generic.list import MultipleObjectMixin
|
||||
from django.views.generic import DeleteView, UpdateView
|
||||
|
||||
from authentik.lib.utils.reflection import all_subclasses
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
|
@ -25,37 +20,6 @@ class DeleteMessageView(SuccessMessageMixin, DeleteView):
|
|||
return super().delete(request, *args, **kwargs)
|
||||
|
||||
|
||||
class InheritanceListView(ListView):
|
||||
"""ListView for objects using InheritanceManager"""
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs["types"] = {x.__name__: x for x in all_subclasses(self.model)}
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().select_subclasses()
|
||||
|
||||
|
||||
class SearchListMixin(MultipleObjectMixin):
|
||||
"""Accept search query using `search` querystring parameter. Requires self.search_fields,
|
||||
a list of all fields to search. Can contain special lookups like __icontains"""
|
||||
|
||||
search_fields: list[str]
|
||||
|
||||
def get_queryset(self) -> QuerySet:
|
||||
queryset = super().get_queryset()
|
||||
if "search" in self.request.GET:
|
||||
raw_query = self.request.GET["search"]
|
||||
if raw_query == "":
|
||||
# Empty query, don't search at all
|
||||
return queryset
|
||||
search = SearchQuery(raw_query, search_type="websearch")
|
||||
return queryset.annotate(search=SearchVector(*self.search_fields)).filter(
|
||||
search=search
|
||||
)
|
||||
return queryset
|
||||
|
||||
|
||||
class InheritanceCreateView(CreateAssignPermView):
|
||||
"""CreateView for objects using InheritanceManager"""
|
||||
|
||||
|
@ -96,31 +60,3 @@ class InheritanceUpdateView(UpdateView):
|
|||
.select_subclasses()
|
||||
.first()
|
||||
)
|
||||
|
||||
|
||||
class BackSuccessUrlMixin:
|
||||
"""Checks if a relative URL has been given as ?back param, and redirect to it. Otherwise
|
||||
default to self.success_url."""
|
||||
|
||||
request: HttpRequest
|
||||
|
||||
success_url: Optional[str]
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
"""get_success_url from FormMixin"""
|
||||
back_param = self.request.GET.get("back")
|
||||
if back_param:
|
||||
if not bool(urlparse(back_param).netloc):
|
||||
return back_param
|
||||
return str(self.success_url)
|
||||
|
||||
|
||||
class UserPaginateListMixin:
|
||||
"""Get paginate_by value from user's attributes, defaulting to 15"""
|
||||
|
||||
request: HttpRequest
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def get_paginate_by(self, queryset: QuerySet) -> int:
|
||||
"""get_paginate_by Function of ListView"""
|
||||
return self.request.user.attributes.get("paginate_by", 15)
|
||||
|
|
|
@ -23,12 +23,9 @@ from authentik.events.api.event import EventViewSet
|
|||
from authentik.events.api.notification import NotificationViewSet
|
||||
from authentik.events.api.notification_rule import NotificationRuleViewSet
|
||||
from authentik.events.api.notification_transport import NotificationTransportViewSet
|
||||
from authentik.flows.api import (
|
||||
FlowCacheViewSet,
|
||||
FlowStageBindingViewSet,
|
||||
FlowViewSet,
|
||||
StageViewSet,
|
||||
)
|
||||
from authentik.flows.api.bindings import FlowStageBindingViewSet
|
||||
from authentik.flows.api.flows import FlowViewSet
|
||||
from authentik.flows.api.stages import StageViewSet
|
||||
from authentik.flows.views import FlowExecutorView
|
||||
from authentik.outposts.api.outpost_service_connections import (
|
||||
DockerServiceConnectionViewSet,
|
||||
|
@ -36,11 +33,7 @@ from authentik.outposts.api.outpost_service_connections import (
|
|||
ServiceConnectionViewSet,
|
||||
)
|
||||
from authentik.outposts.api.outposts import OutpostViewSet
|
||||
from authentik.policies.api import (
|
||||
PolicyBindingViewSet,
|
||||
PolicyCacheViewSet,
|
||||
PolicyViewSet,
|
||||
)
|
||||
from authentik.policies.api import PolicyBindingViewSet, PolicyViewSet
|
||||
from authentik.policies.dummy.api import DummyPolicyViewSet
|
||||
from authentik.policies.event_matcher.api import EventMatcherPolicyViewSet
|
||||
from authentik.policies.expiry.api import PasswordExpiryPolicyViewSet
|
||||
|
@ -101,7 +94,6 @@ router.register(
|
|||
router.register("outposts/proxy", ProxyOutpostConfigViewSet)
|
||||
|
||||
router.register("flows/instances", FlowViewSet)
|
||||
router.register("flows/cached", FlowCacheViewSet, basename="flows_cache")
|
||||
router.register("flows/bindings", FlowStageBindingViewSet)
|
||||
|
||||
router.register("crypto/certificatekeypairs", CertificateKeyPairViewSet)
|
||||
|
@ -117,7 +109,6 @@ router.register("sources/saml", SAMLSourceViewSet)
|
|||
router.register("sources/oauth", OAuthSourceViewSet)
|
||||
|
||||
router.register("policies/all", PolicyViewSet)
|
||||
router.register("policies/cached", PolicyCacheViewSet, basename="policies_cache")
|
||||
router.register("policies/bindings", PolicyBindingViewSet)
|
||||
router.register("policies/expression", ExpressionPolicyViewSet)
|
||||
router.register("policies/event_matcher", EventMatcherPolicyViewSet)
|
||||
|
@ -146,8 +137,8 @@ router.register("stages/captcha", CaptchaStageViewSet)
|
|||
router.register("stages/consent", ConsentStageViewSet)
|
||||
router.register("stages/email", EmailStageViewSet)
|
||||
router.register("stages/identification", IdentificationStageViewSet)
|
||||
router.register("stages/invitation", InvitationStageViewSet)
|
||||
router.register("stages/invitation/invitations", InvitationViewSet)
|
||||
router.register("stages/invitation/stages", InvitationStageViewSet)
|
||||
router.register("stages/password", PasswordStageViewSet)
|
||||
router.register("stages/prompt/prompts", PromptViewSet)
|
||||
router.register("stages/prompt/stages", PromptStageViewSet)
|
||||
|
|
|
@ -19,3 +19,5 @@ class GroupViewSet(ModelViewSet):
|
|||
|
||||
queryset = Group.objects.all()
|
||||
serializer_class = GroupSerializer
|
||||
search_fields = ["name", "is_superuser"]
|
||||
filterset_fields = ["name", "is_superuser"]
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
"""PropertyMapping API Views"""
|
||||
from django.shortcuts import reverse
|
||||
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 ModelSerializer, SerializerMethodField
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||
|
||||
from authentik.core.api.utils import MetaNameSerializer
|
||||
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
|
||||
from authentik.core.models import PropertyMapping
|
||||
from authentik.lib.templatetags.authentik_utils import verbose_name
|
||||
from authentik.lib.utils.reflection import all_subclasses
|
||||
|
||||
|
||||
class PropertyMappingSerializer(ModelSerializer, MetaNameSerializer):
|
||||
|
@ -47,3 +54,19 @@ class PropertyMappingViewSet(ReadOnlyModelViewSet):
|
|||
|
||||
def get_queryset(self):
|
||||
return PropertyMapping.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False)
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable property-mapping types"""
|
||||
data = []
|
||||
for subclass in all_subclasses(self.queryset.model):
|
||||
data.append(
|
||||
{
|
||||
"name": verbose_name(subclass),
|
||||
"description": subclass.__doc__,
|
||||
"link": reverse("authentik_admin:property-mapping-create")
|
||||
+ f"?type={subclass.__name__}",
|
||||
}
|
||||
)
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
|
|
@ -9,6 +9,7 @@ from rest_framework.response import Response
|
|||
from rest_framework.serializers import ModelSerializer, Serializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.users import UserSerializer
|
||||
from authentik.core.models import Token
|
||||
from authentik.events.models import Event, EventAction
|
||||
|
||||
|
@ -16,10 +17,21 @@ from authentik.events.models import Event, EventAction
|
|||
class TokenSerializer(ModelSerializer):
|
||||
"""Token Serializer"""
|
||||
|
||||
user = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
|
||||
model = Token
|
||||
fields = ["pk", "identifier", "intent", "user", "description"]
|
||||
fields = [
|
||||
"pk",
|
||||
"identifier",
|
||||
"intent",
|
||||
"user",
|
||||
"description",
|
||||
"expires",
|
||||
"expiring",
|
||||
]
|
||||
depth = 2
|
||||
|
||||
|
||||
class TokenViewSerializer(Serializer):
|
||||
|
@ -40,6 +52,19 @@ class TokenViewSet(ModelViewSet):
|
|||
lookup_field = "identifier"
|
||||
queryset = Token.filter_not_expired()
|
||||
serializer_class = TokenSerializer
|
||||
search_fields = [
|
||||
"identifier",
|
||||
"intent",
|
||||
"user__username",
|
||||
"description",
|
||||
]
|
||||
filterset_fields = [
|
||||
"identifier",
|
||||
"intent",
|
||||
"user__username",
|
||||
"description",
|
||||
]
|
||||
ordering = ["expires"]
|
||||
|
||||
@swagger_auto_schema(responses={200: TokenViewSerializer(many=False)})
|
||||
@action(detail=True)
|
||||
|
|
|
@ -28,7 +28,17 @@ class UserSerializer(ModelSerializer):
|
|||
class Meta:
|
||||
|
||||
model = User
|
||||
fields = ["pk", "username", "name", "is_superuser", "email", "avatar"]
|
||||
fields = [
|
||||
"pk",
|
||||
"username",
|
||||
"name",
|
||||
"is_active",
|
||||
"last_login",
|
||||
"is_superuser",
|
||||
"email",
|
||||
"avatar",
|
||||
"attributes",
|
||||
]
|
||||
|
||||
|
||||
class UserViewSet(ModelViewSet):
|
||||
|
@ -36,6 +46,8 @@ class UserViewSet(ModelViewSet):
|
|||
|
||||
queryset = User.objects.none()
|
||||
serializer_class = UserSerializer
|
||||
search_fields = ["username", "name", "is_active"]
|
||||
filterset_fields = ["username", "name", "is_active"]
|
||||
|
||||
def get_queryset(self):
|
||||
return User.objects.all().exclude(pk=get_anonymous_user().pk)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""API Utilities"""
|
||||
from django.db.models import Model
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.fields import CharField, IntegerField
|
||||
from rest_framework.serializers import Serializer, SerializerMethodField
|
||||
|
||||
|
||||
|
@ -37,3 +37,15 @@ class TypeCreateSerializer(Serializer):
|
|||
|
||||
def update(self, instance: Model, validated_data: dict) -> Model:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class CacheSerializer(Serializer):
|
||||
"""Generic cache stats for an object"""
|
||||
|
||||
count = IntegerField(read_only=True)
|
||||
|
||||
def create(self, validated_data: dict) -> Model:
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, instance: Model, validated_data: dict) -> Model:
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
</div>
|
||||
</section>
|
||||
<section slot="page-2" data-tab-title="{% trans 'Tokens' %}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||
<ak-site-shell url="{% url 'authentik_core:user-tokens' %}">
|
||||
<div slot="body"></div>
|
||||
</ak-site-shell>
|
||||
<ak-token-user-list></ak-token-user-list>
|
||||
</section>
|
||||
{% user_stages as user_stages_loc %}
|
||||
{% for stage, stage_link in user_stages_loc.items %}
|
||||
|
|
|
@ -8,7 +8,6 @@ urlpatterns = [
|
|||
# User views
|
||||
path("-/user/", user.UserSettingsView.as_view(), name="user-settings"),
|
||||
path("-/user/details/", user.UserDetailsView.as_view(), name="user-details"),
|
||||
path("-/user/tokens/", user.TokenListView.as_view(), name="user-tokens"),
|
||||
path(
|
||||
"-/user/tokens/create/",
|
||||
user.TokenCreateView.as_view(),
|
||||
|
|
|
@ -6,20 +6,15 @@ from django.contrib.auth.mixins import (
|
|||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||
)
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.db.models.query import QuerySet
|
||||
from django.http.response import HttpResponse
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView, UpdateView
|
||||
from django.views.generic import UpdateView
|
||||
from django.views.generic.base import TemplateView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from guardian.mixins import PermissionRequiredMixin
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
|
||||
from authentik.admin.views.utils import (
|
||||
DeleteMessageView,
|
||||
SearchListMixin,
|
||||
UserPaginateListMixin,
|
||||
)
|
||||
from authentik.admin.views.utils import DeleteMessageView
|
||||
from authentik.core.forms.token import UserTokenForm
|
||||
from authentik.core.forms.users import UserDetailForm
|
||||
from authentik.core.models import Token, TokenIntents
|
||||
|
@ -54,30 +49,6 @@ class UserDetailsView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
|
|||
return kwargs
|
||||
|
||||
|
||||
class TokenListView(
|
||||
LoginRequiredMixin,
|
||||
PermissionListMixin,
|
||||
UserPaginateListMixin,
|
||||
SearchListMixin,
|
||||
ListView,
|
||||
):
|
||||
"""Show list of all tokens"""
|
||||
|
||||
model = Token
|
||||
ordering = "expires"
|
||||
permission_required = "authentik_core.view_token"
|
||||
|
||||
template_name = "user/token_list.html"
|
||||
search_fields = [
|
||||
"identifier",
|
||||
"intent",
|
||||
"description",
|
||||
]
|
||||
|
||||
def get_queryset(self) -> QuerySet:
|
||||
return super().get_queryset().filter(intent=TokenIntents.INTENT_API)
|
||||
|
||||
|
||||
class TokenCreateView(
|
||||
SuccessMessageMixin,
|
||||
LoginRequiredMixin,
|
||||
|
|
0
authentik/flows/api/__init__.py
Normal file
0
authentik/flows/api/__init__.py
Normal file
35
authentik/flows/api/bindings.py
Normal file
35
authentik/flows/api/bindings.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
"""Flow Binding API Views"""
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.flows.models import FlowStageBinding
|
||||
|
||||
|
||||
class FlowStageBindingSerializer(ModelSerializer):
|
||||
"""FlowStageBinding Serializer"""
|
||||
|
||||
stage_obj = StageSerializer(read_only=True, source="stage")
|
||||
|
||||
class Meta:
|
||||
|
||||
model = FlowStageBinding
|
||||
fields = [
|
||||
"pk",
|
||||
"policybindingmodel_ptr_id",
|
||||
"target",
|
||||
"stage",
|
||||
"stage_obj",
|
||||
"evaluate_on_plan",
|
||||
"re_evaluate_policies",
|
||||
"order",
|
||||
"policies",
|
||||
]
|
||||
|
||||
|
||||
class FlowStageBindingViewSet(ModelViewSet):
|
||||
"""FlowStageBinding Viewset"""
|
||||
|
||||
queryset = FlowStageBinding.objects.all()
|
||||
serializer_class = FlowStageBindingSerializer
|
||||
filterset_fields = "__all__"
|
|
@ -3,11 +3,10 @@ from dataclasses import dataclass
|
|||
|
||||
from django.core.cache import cache
|
||||
from django.db.models import Model
|
||||
from django.shortcuts import get_object_or_404, reverse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_yasg2.utils import swagger_auto_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.mixins import ListModelMixin
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import (
|
||||
|
@ -16,13 +15,11 @@ from rest_framework.serializers import (
|
|||
Serializer,
|
||||
SerializerMethodField,
|
||||
)
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
|
||||
from authentik.flows.models import Flow, FlowStageBinding, Stage
|
||||
from authentik.core.api.utils import CacheSerializer
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.flows.planner import cache_key
|
||||
from authentik.lib.templatetags.authentik_utils import verbose_name
|
||||
from authentik.lib.utils.reflection import all_subclasses
|
||||
|
||||
|
||||
class FlowSerializer(ModelSerializer):
|
||||
|
@ -84,6 +81,12 @@ class FlowViewSet(ModelViewSet):
|
|||
search_fields = ["name", "slug", "designation", "title"]
|
||||
filterset_fields = ["flow_uuid", "name", "slug", "designation"]
|
||||
|
||||
@swagger_auto_schema(responses={200: CacheSerializer(many=False)})
|
||||
@action(detail=False)
|
||||
def cached(self, request: Request) -> Response:
|
||||
"""Info about cached flows"""
|
||||
return Response(data={"count": len(cache.keys("flow_*"))})
|
||||
|
||||
@swagger_auto_schema(responses={200: FlowDiagramSerializer()})
|
||||
@action(detail=True, methods=["get"])
|
||||
def diagram(self, request: Request, slug: str) -> Response:
|
||||
|
@ -155,85 +158,3 @@ class FlowViewSet(ModelViewSet):
|
|||
)
|
||||
diagram = "\n".join([str(x) for x in header + body + footer])
|
||||
return Response({"diagram": diagram})
|
||||
|
||||
|
||||
class StageSerializer(ModelSerializer, MetaNameSerializer):
|
||||
"""Stage Serializer"""
|
||||
|
||||
object_type = SerializerMethodField()
|
||||
|
||||
def get_object_type(self, obj):
|
||||
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
||||
return obj._meta.object_name.lower().replace("stage", "")
|
||||
|
||||
class Meta:
|
||||
|
||||
model = Stage
|
||||
fields = ["pk", "name", "object_type", "verbose_name", "verbose_name_plural"]
|
||||
|
||||
|
||||
class StageViewSet(ReadOnlyModelViewSet):
|
||||
"""Stage Viewset"""
|
||||
|
||||
queryset = Stage.objects.all()
|
||||
serializer_class = StageSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return Stage.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False)
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable stage types"""
|
||||
data = []
|
||||
for subclass in all_subclasses(self.queryset.model, False):
|
||||
data.append(
|
||||
{
|
||||
"name": verbose_name(subclass),
|
||||
"description": subclass.__doc__,
|
||||
"link": reverse("authentik_admin:stage-create")
|
||||
+ f"?type={subclass.__name__}",
|
||||
}
|
||||
)
|
||||
data = sorted(data, key=lambda x: x["name"])
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
|
||||
class FlowStageBindingSerializer(ModelSerializer):
|
||||
"""FlowStageBinding Serializer"""
|
||||
|
||||
stage_obj = StageSerializer(read_only=True, source="stage")
|
||||
|
||||
class Meta:
|
||||
|
||||
model = FlowStageBinding
|
||||
fields = [
|
||||
"pk",
|
||||
"policybindingmodel_ptr_id",
|
||||
"target",
|
||||
"stage",
|
||||
"stage_obj",
|
||||
"evaluate_on_plan",
|
||||
"re_evaluate_policies",
|
||||
"order",
|
||||
"policies",
|
||||
]
|
||||
|
||||
|
||||
class FlowStageBindingViewSet(ModelViewSet):
|
||||
"""FlowStageBinding Viewset"""
|
||||
|
||||
queryset = FlowStageBinding.objects.all()
|
||||
serializer_class = FlowStageBindingSerializer
|
||||
filterset_fields = "__all__"
|
||||
|
||||
|
||||
class FlowCacheViewSet(ListModelMixin, GenericViewSet):
|
||||
"""Info about cached flows"""
|
||||
|
||||
queryset = Flow.objects.none()
|
||||
serializer_class = Serializer
|
||||
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Info about cached flows"""
|
||||
return Response(data={"pagination": {"count": len(cache.keys("flow_*"))}})
|
66
authentik/flows/api/stages.py
Normal file
66
authentik/flows/api/stages.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
"""Flow Stage API Views"""
|
||||
from django.shortcuts import reverse
|
||||
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 ModelSerializer, SerializerMethodField
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||
|
||||
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
|
||||
from authentik.flows.api.flows import FlowSerializer
|
||||
from authentik.flows.models import Stage
|
||||
from authentik.lib.templatetags.authentik_utils import verbose_name
|
||||
from authentik.lib.utils.reflection import all_subclasses
|
||||
|
||||
|
||||
class StageSerializer(ModelSerializer, MetaNameSerializer):
|
||||
"""Stage Serializer"""
|
||||
|
||||
object_type = SerializerMethodField()
|
||||
flow_set = FlowSerializer(many=True, required=False)
|
||||
|
||||
def get_object_type(self, obj: Stage) -> str:
|
||||
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
||||
return obj._meta.object_name.lower().replace("stage", "")
|
||||
|
||||
class Meta:
|
||||
|
||||
model = Stage
|
||||
fields = [
|
||||
"pk",
|
||||
"name",
|
||||
"object_type",
|
||||
"verbose_name",
|
||||
"verbose_name_plural",
|
||||
"flow_set",
|
||||
]
|
||||
|
||||
|
||||
class StageViewSet(ReadOnlyModelViewSet):
|
||||
"""Stage Viewset"""
|
||||
|
||||
queryset = Stage.objects.all().select_related("flow_set")
|
||||
serializer_class = StageSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
return Stage.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False)
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable stage types"""
|
||||
data = []
|
||||
for subclass in all_subclasses(self.queryset.model, False):
|
||||
data.append(
|
||||
{
|
||||
"name": verbose_name(subclass),
|
||||
"description": subclass.__doc__,
|
||||
"link": reverse("authentik_admin:stage-create")
|
||||
+ f"?type={subclass.__name__}",
|
||||
}
|
||||
)
|
||||
data = sorted(data, key=lambda x: x["name"])
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
|
@ -118,7 +118,7 @@ class Flow(SerializerModel, PolicyBindingModel):
|
|||
|
||||
@property
|
||||
def serializer(self) -> BaseSerializer:
|
||||
from authentik.flows.api import FlowSerializer
|
||||
from authentik.flows.api.flows import FlowSerializer
|
||||
|
||||
return FlowSerializer
|
||||
|
||||
|
@ -189,12 +189,12 @@ class FlowStageBinding(SerializerModel, PolicyBindingModel):
|
|||
|
||||
@property
|
||||
def serializer(self) -> BaseSerializer:
|
||||
from authentik.flows.api import FlowStageBindingSerializer
|
||||
from authentik.flows.api.bindings import FlowStageBindingSerializer
|
||||
|
||||
return FlowStageBindingSerializer
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.target} #{self.order} -> {self.stage}"
|
||||
return f"{self.target} #{self.order}"
|
||||
|
||||
class Meta:
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.shortcuts import reverse
|
|||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.api import StageSerializer, StageViewSet
|
||||
from authentik.flows.api.stages import StageSerializer, StageViewSet
|
||||
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding, Stage
|
||||
from authentik.policies.dummy.models import DummyPolicy
|
||||
from authentik.policies.models import PolicyBinding
|
||||
|
|
|
@ -22,6 +22,8 @@ def get_attrs(obj: SerializerModel) -> dict[str, Any]:
|
|||
"verbose_name",
|
||||
"verbose_name_plural",
|
||||
"object_type",
|
||||
"flow_set",
|
||||
"promptstage_set",
|
||||
)
|
||||
for to_remove_name in to_remove:
|
||||
if to_remove_name in data:
|
||||
|
|
|
@ -65,14 +65,17 @@ class FlowImporter:
|
|||
return value
|
||||
|
||||
for key, value in attrs.items():
|
||||
if isinstance(value, dict):
|
||||
for idx, _inner_key in enumerate(value):
|
||||
value[_inner_key] = updater(value[_inner_key])
|
||||
elif isinstance(value, list):
|
||||
for idx, _inner_value in enumerate(value):
|
||||
attrs[key][idx] = updater(_inner_value)
|
||||
else:
|
||||
attrs[key] = updater(value)
|
||||
try:
|
||||
if isinstance(value, dict):
|
||||
for idx, _inner_key in enumerate(value):
|
||||
value[_inner_key] = updater(value[_inner_key])
|
||||
elif isinstance(value, list):
|
||||
for idx, _inner_value in enumerate(value):
|
||||
attrs[key][idx] = updater(_inner_value)
|
||||
else:
|
||||
attrs[key] = updater(value)
|
||||
except TypeError:
|
||||
continue
|
||||
return attrs
|
||||
|
||||
def __query_from_identifier(self, attrs: dict[str, Any]) -> Q:
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
"""Outpost API Views"""
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from dataclasses import asdict
|
||||
|
||||
from django.db.models.base import Model
|
||||
from django.shortcuts import reverse
|
||||
from drf_yasg2.utils import swagger_auto_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ModelSerializer, Serializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
|
||||
from authentik.lib.templatetags.authentik_utils import verbose_name
|
||||
from authentik.lib.utils.reflection import all_subclasses
|
||||
from authentik.outposts.models import (
|
||||
DockerServiceConnection,
|
||||
KubernetesServiceConnection,
|
||||
|
@ -9,32 +21,81 @@ from authentik.outposts.models import (
|
|||
)
|
||||
|
||||
|
||||
class ServiceConnectionSerializer(ModelSerializer):
|
||||
class ServiceConnectionSerializer(ModelSerializer, MetaNameSerializer):
|
||||
"""ServiceConnection Serializer"""
|
||||
|
||||
object_type = SerializerMethodField()
|
||||
|
||||
def get_object_type(self, obj: OutpostServiceConnection) -> str:
|
||||
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
||||
return obj._meta.object_name.lower().replace("serviceconnection", "")
|
||||
|
||||
class Meta:
|
||||
|
||||
model = OutpostServiceConnection
|
||||
fields = ["pk", "name"]
|
||||
fields = [
|
||||
"pk",
|
||||
"name",
|
||||
"local",
|
||||
"object_type",
|
||||
"verbose_name",
|
||||
"verbose_name_plural",
|
||||
]
|
||||
|
||||
|
||||
class ServiceConnectionStateSerializer(Serializer):
|
||||
"""Serializer for Service connection state"""
|
||||
|
||||
healthy = BooleanField(read_only=True)
|
||||
version = CharField(read_only=True)
|
||||
|
||||
def create(self, validated_data: dict) -> Model:
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, instance: Model, validated_data: dict) -> Model:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ServiceConnectionViewSet(ModelViewSet):
|
||||
"""ServiceConnection Viewset"""
|
||||
|
||||
queryset = OutpostServiceConnection.objects.all()
|
||||
queryset = OutpostServiceConnection.objects.select_subclasses()
|
||||
serializer_class = ServiceConnectionSerializer
|
||||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False)
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable service connection types"""
|
||||
data = []
|
||||
for subclass in all_subclasses(self.queryset.model):
|
||||
data.append(
|
||||
{
|
||||
"name": verbose_name(subclass),
|
||||
"description": subclass.__doc__,
|
||||
"link": reverse("authentik_admin:outpost-service-connection-create")
|
||||
+ f"?type={subclass.__name__}",
|
||||
}
|
||||
)
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: ServiceConnectionStateSerializer(many=False)})
|
||||
@action(detail=True)
|
||||
# pylint: disable=unused-argument, invalid-name
|
||||
def state(self, request: Request, pk: str) -> Response:
|
||||
"""Get the service connection's state"""
|
||||
connection = self.get_object()
|
||||
return Response(asdict(connection.state))
|
||||
|
||||
|
||||
class DockerServiceConnectionSerializer(ModelSerializer):
|
||||
class DockerServiceConnectionSerializer(ServiceConnectionSerializer):
|
||||
"""DockerServiceConnection Serializer"""
|
||||
|
||||
class Meta:
|
||||
|
||||
model = DockerServiceConnection
|
||||
fields = [
|
||||
"pk",
|
||||
"name",
|
||||
"local",
|
||||
fields = ServiceConnectionSerializer.Meta.fields + [
|
||||
"url",
|
||||
"tls_verification",
|
||||
"tls_authentication",
|
||||
|
@ -48,13 +109,13 @@ class DockerServiceConnectionViewSet(ModelViewSet):
|
|||
serializer_class = DockerServiceConnectionSerializer
|
||||
|
||||
|
||||
class KubernetesServiceConnectionSerializer(ModelSerializer):
|
||||
class KubernetesServiceConnectionSerializer(ServiceConnectionSerializer):
|
||||
"""KubernetesServiceConnection Serializer"""
|
||||
|
||||
class Meta:
|
||||
|
||||
model = KubernetesServiceConnection
|
||||
fields = ["pk", "name", "local", "kubeconfig"]
|
||||
fields = ServiceConnectionSerializer.Meta.fields + ["kubeconfig"]
|
||||
|
||||
|
||||
class KubernetesServiceConnectionViewSet(ModelViewSet):
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
"""policy API Views"""
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from rest_framework.mixins import ListModelMixin
|
||||
from django.shortcuts import reverse
|
||||
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 (
|
||||
ModelSerializer,
|
||||
PrimaryKeyRelatedField,
|
||||
Serializer,
|
||||
SerializerMethodField,
|
||||
)
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||
|
||||
from authentik.core.api.utils import (
|
||||
CacheSerializer,
|
||||
MetaNameSerializer,
|
||||
TypeCreateSerializer,
|
||||
)
|
||||
from authentik.lib.templatetags.authentik_utils import verbose_name
|
||||
from authentik.lib.utils.reflection import all_subclasses
|
||||
from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel
|
||||
|
||||
|
||||
|
@ -45,20 +53,27 @@ class PolicyBindingModelForeignKey(PrimaryKeyRelatedField):
|
|||
return correct_model.pk
|
||||
|
||||
|
||||
class PolicySerializer(ModelSerializer):
|
||||
class PolicySerializer(ModelSerializer, MetaNameSerializer):
|
||||
"""Policy Serializer"""
|
||||
|
||||
_resolve_inheritance: bool
|
||||
|
||||
object_type = SerializerMethodField()
|
||||
bound_to = SerializerMethodField()
|
||||
|
||||
def __init__(self, *args, resolve_inheritance: bool = True, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._resolve_inheritance = resolve_inheritance
|
||||
|
||||
def get_object_type(self, obj):
|
||||
def get_object_type(self, obj: Policy) -> str:
|
||||
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
||||
return obj._meta.object_name.lower().replace("provider", "")
|
||||
return obj._meta.object_name.lower().replace("policy", "")
|
||||
|
||||
def get_bound_to(self, obj: Policy) -> int:
|
||||
"""Return objects policy is bound to"""
|
||||
if not obj.bindings.exists() and not obj.promptstage_set.exists():
|
||||
return 0
|
||||
return obj.bindings.count()
|
||||
|
||||
def to_representation(self, instance: Policy):
|
||||
# pyright: reportGeneralTypeIssues=false
|
||||
|
@ -71,7 +86,15 @@ class PolicySerializer(ModelSerializer):
|
|||
class Meta:
|
||||
|
||||
model = Policy
|
||||
fields = ["pk", "name", "execution_logging", "object_type"]
|
||||
fields = [
|
||||
"pk",
|
||||
"name",
|
||||
"execution_logging",
|
||||
"object_type",
|
||||
"verbose_name",
|
||||
"verbose_name_plural",
|
||||
"bound_to",
|
||||
]
|
||||
depth = 3
|
||||
|
||||
|
||||
|
@ -84,9 +107,34 @@ class PolicyViewSet(ReadOnlyModelViewSet):
|
|||
"bindings": ["isnull"],
|
||||
"promptstage": ["isnull"],
|
||||
}
|
||||
search_fields = ["name"]
|
||||
|
||||
def get_queryset(self):
|
||||
return Policy.objects.select_subclasses()
|
||||
return Policy.objects.select_subclasses().prefetch_related(
|
||||
"bindings", "promptstage_set"
|
||||
)
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False)
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable policy types"""
|
||||
data = []
|
||||
for subclass in all_subclasses(self.queryset.model):
|
||||
data.append(
|
||||
{
|
||||
"name": verbose_name(subclass),
|
||||
"description": subclass.__doc__,
|
||||
"link": reverse("authentik_admin:policy-create")
|
||||
+ f"?type={subclass.__name__}",
|
||||
}
|
||||
)
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: CacheSerializer(many=False)})
|
||||
@action(detail=False)
|
||||
def cached(self, request: Request) -> Response:
|
||||
"""Info about cached policies"""
|
||||
return Response(data={"count": len(cache.keys("policy_*"))})
|
||||
|
||||
|
||||
class PolicyBindingSerializer(ModelSerializer):
|
||||
|
@ -124,14 +172,3 @@ class PolicyBindingViewSet(ModelViewSet):
|
|||
serializer_class = PolicyBindingSerializer
|
||||
filterset_fields = ["policy", "target", "enabled", "order", "timeout"]
|
||||
search_fields = ["policy__name"]
|
||||
|
||||
|
||||
class PolicyCacheViewSet(ListModelMixin, GenericViewSet):
|
||||
"""Info about cached policies"""
|
||||
|
||||
queryset = Policy.objects.none()
|
||||
serializer_class = Serializer
|
||||
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Info about cached policies"""
|
||||
return Response(data={"pagination": {"count": len(cache.keys("policy_*"))}})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""AuthenticatorStaticStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_static.models import AuthenticatorStaticStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""AuthenticatorTOTPStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_totp.models import AuthenticatorTOTPStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""AuthenticatorValidateStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_validate.models import AuthenticatorValidateStage
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class ValidationForm(forms.Form):
|
|||
label=_("Please enter the token from your device."),
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"autocomplete": "off",
|
||||
"autocomplete": "one-time-code",
|
||||
"placeholder": "123456",
|
||||
"autofocus": "autofocus",
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""AuthenticateWebAuthnStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.authenticator_webauthn.models import AuthenticateWebAuthnStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""CaptchaStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.captcha.models import CaptchaStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""ConsentStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.consent.models import ConsentStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""DummyStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.dummy.models import DummyStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""EmailStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.email.models import EmailStage, get_template_choices
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Identification Stage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.identification.models import IdentificationStage
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.invitation.models import Invitation, InvitationStage
|
||||
|
||||
|
||||
|
@ -34,7 +34,9 @@ class InvitationSerializer(ModelSerializer):
|
|||
"pk",
|
||||
"expires",
|
||||
"fixed_data",
|
||||
"created_by",
|
||||
]
|
||||
depth = 2
|
||||
|
||||
|
||||
class InvitationViewSet(ModelViewSet):
|
||||
|
@ -42,6 +44,9 @@ class InvitationViewSet(ModelViewSet):
|
|||
|
||||
queryset = Invitation.objects.all()
|
||||
serializer_class = InvitationSerializer
|
||||
order = ["-expires"]
|
||||
search_fields = ["created_by__username", "expires"]
|
||||
filterset_fields = ["created_by__username", "expires"]
|
||||
|
||||
def perform_create(self, serializer: InvitationSerializer):
|
||||
serializer.instance.created_by = self.request.user
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""PasswordStage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.password.models import PasswordStage
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from rest_framework.serializers import CharField, ModelSerializer
|
|||
from rest_framework.validators import UniqueValidator
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.prompt.models import Prompt, PromptStage
|
||||
|
||||
|
||||
|
@ -31,6 +31,8 @@ class PromptStageViewSet(ModelViewSet):
|
|||
class PromptSerializer(ModelSerializer):
|
||||
"""Prompt Serializer"""
|
||||
|
||||
promptstage_set = StageSerializer(many=True, required=False)
|
||||
|
||||
class Meta:
|
||||
|
||||
model = Prompt
|
||||
|
@ -42,11 +44,13 @@ class PromptSerializer(ModelSerializer):
|
|||
"required",
|
||||
"placeholder",
|
||||
"order",
|
||||
"promptstage_set",
|
||||
]
|
||||
|
||||
|
||||
class PromptViewSet(ModelViewSet):
|
||||
"""Prompt Viewset"""
|
||||
|
||||
queryset = Prompt.objects.all()
|
||||
queryset = Prompt.objects.all().prefetch_related("promptstage_set")
|
||||
serializer_class = PromptSerializer
|
||||
filterset_fields = ["field_key", "label", "type", "placeholder"]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""User Delete Stage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.user_delete.models import UserDeleteStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Login Stage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.user_login.models import UserLoginStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Logout Stage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.user_logout.models import UserLogoutStage
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""User Write Stage API Views"""
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.flows.api import StageSerializer
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.user_write.models import UserWriteStage
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
trigger:
|
||||
- master
|
||||
- next
|
||||
|
||||
resources:
|
||||
- repo: self
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
trigger:
|
||||
- master
|
||||
- next
|
||||
|
||||
variables:
|
||||
${{ if startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}:
|
||||
|
|
1421
swagger.yaml
1421
swagger.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,6 @@
|
|||
trigger:
|
||||
- master
|
||||
- next
|
||||
|
||||
variables:
|
||||
${{ if startsWith(variables['Build.SourceBranch'], 'refs/pull/') }}:
|
||||
|
|
134
web/package-lock.json
generated
134
web/package-lock.json
generated
|
@ -144,30 +144,16 @@
|
|||
}
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.1.0.tgz",
|
||||
"integrity": "sha512-t3y2TLXDWgvfknyH8eKj/9mghJfSEqItFyp74zPu1Src6kOPjkd4Sa7o4+bdkNgA8dIIOrDAhRUbB2sq4sWMCA==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.2.0.tgz",
|
||||
"integrity": "sha512-4r3paHcHXLemj471BtNDhUs2kvJxk5XDRplz1dbC/LHXN5PWEXP4anhGILxOlxqi4y33r53PIZu3xXFjznaVZA==",
|
||||
"requires": {
|
||||
"@sentry/core": "6.1.0",
|
||||
"@sentry/types": "6.1.0",
|
||||
"@sentry/utils": "6.1.0",
|
||||
"@sentry/core": "6.2.0",
|
||||
"@sentry/types": "6.2.0",
|
||||
"@sentry/utils": "6.2.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/types": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.1.0.tgz",
|
||||
"integrity": "sha512-kIaN52Fw5K+2mKRaHE2YluJ+F/qMGSUzZXIFDNdC6OUMXQ4TM8gZTrITXs8CLDm7cK8iCqFCtzKOjKK6KyOKAg=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.1.0.tgz",
|
||||
"integrity": "sha512-6JAplzUOS6bEwfX0PDRZBbYRvn9EN22kZfcL0qGHtM9L0QQ5ybjbbVwOpbXgRkiZx++dQbzLFtelxnDhsbFG+Q==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.1.0",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
|
@ -176,51 +162,17 @@
|
|||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.1.0.tgz",
|
||||
"integrity": "sha512-57mXkp3NoyxRycXrL+Ec6bYS6UYJZp9tYX0lUp5Ry2M0FxDZ3Q4drkjr8MIQOhBaQXP2ukSX4QTVLGMPm60zMw==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.2.0.tgz",
|
||||
"integrity": "sha512-oTr2b25l+0bv/+d6IgMamPuGleWV7OgJb0NFfd+WZhw6UDRgr7CdEJy2gW6tK8SerwXgPHdn4ervxsT3WIBiXw==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.1.0",
|
||||
"@sentry/minimal": "6.1.0",
|
||||
"@sentry/types": "6.1.0",
|
||||
"@sentry/utils": "6.1.0",
|
||||
"@sentry/hub": "6.2.0",
|
||||
"@sentry/minimal": "6.2.0",
|
||||
"@sentry/types": "6.2.0",
|
||||
"@sentry/utils": "6.2.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/hub": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.1.0.tgz",
|
||||
"integrity": "sha512-JnBSCgNg3VHiMojUl5tCHU8iWPVuE+qqENIzG9A722oJms1kKWBvWl+yQzhWBNdgk5qeAY3F5UzKWJZkbJ6xow==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.1.0",
|
||||
"@sentry/utils": "6.1.0",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/minimal": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.1.0.tgz",
|
||||
"integrity": "sha512-g6sfNKenL7wnsr/tibp8nFiMv/XRH0s0Pt4p151npmNI+SmjuUz3GGYEXk8ChCyaKldYKilkNOFdVXJxUf5gZw==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.1.0",
|
||||
"@sentry/types": "6.1.0",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.1.0.tgz",
|
||||
"integrity": "sha512-kIaN52Fw5K+2mKRaHE2YluJ+F/qMGSUzZXIFDNdC6OUMXQ4TM8gZTrITXs8CLDm7cK8iCqFCtzKOjKK6KyOKAg=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.1.0.tgz",
|
||||
"integrity": "sha512-6JAplzUOS6bEwfX0PDRZBbYRvn9EN22kZfcL0qGHtM9L0QQ5ybjbbVwOpbXgRkiZx++dQbzLFtelxnDhsbFG+Q==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.1.0",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
|
@ -229,12 +181,12 @@
|
|||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.1.0.tgz",
|
||||
"integrity": "sha512-JnBSCgNg3VHiMojUl5tCHU8iWPVuE+qqENIzG9A722oJms1kKWBvWl+yQzhWBNdgk5qeAY3F5UzKWJZkbJ6xow==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.2.0.tgz",
|
||||
"integrity": "sha512-BDTEFK8vlJydWXp/KMX0stvv73V7od224iLi+w3k7BcPwMKXBuURBXPU8d5XIC4G8nwg8X6cnDvwL+zBBlBbkg==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.1.0",
|
||||
"@sentry/utils": "6.1.0",
|
||||
"@sentry/types": "6.2.0",
|
||||
"@sentry/utils": "6.2.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -246,12 +198,12 @@
|
|||
}
|
||||
},
|
||||
"@sentry/minimal": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.1.0.tgz",
|
||||
"integrity": "sha512-g6sfNKenL7wnsr/tibp8nFiMv/XRH0s0Pt4p151npmNI+SmjuUz3GGYEXk8ChCyaKldYKilkNOFdVXJxUf5gZw==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.2.0.tgz",
|
||||
"integrity": "sha512-haxsx8/ZafhZUaGeeMtY7bJt9HbDlqeiaXrRMp1CxGtd0ZRQwHt60imEjl6IH1I73SEWxNfqScGsX2s3HzztMg==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.1.0",
|
||||
"@sentry/types": "6.1.0",
|
||||
"@sentry/hub": "6.2.0",
|
||||
"@sentry/types": "6.2.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -263,14 +215,14 @@
|
|||
}
|
||||
},
|
||||
"@sentry/tracing": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.1.0.tgz",
|
||||
"integrity": "sha512-s6a4Ra3hHn4awiNz4fOEK6TCV2w2iLcxdppijcYEB7S/1rJpmqZgHWDicqufbOmVMOLmyKLEQ7w+pZq3TR3WgQ==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.2.0.tgz",
|
||||
"integrity": "sha512-pzgM1dePPJysVnzaFCMp+BKtjM5q46HZeyShiR+KcQYvneD3fmUPJigDkkcsB2DcrY3mFvDcswjoqxaTIW7ZBQ==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.1.0",
|
||||
"@sentry/minimal": "6.1.0",
|
||||
"@sentry/types": "6.1.0",
|
||||
"@sentry/utils": "6.1.0",
|
||||
"@sentry/hub": "6.2.0",
|
||||
"@sentry/minimal": "6.2.0",
|
||||
"@sentry/types": "6.2.0",
|
||||
"@sentry/utils": "6.2.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -282,16 +234,16 @@
|
|||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.1.0.tgz",
|
||||
"integrity": "sha512-kIaN52Fw5K+2mKRaHE2YluJ+F/qMGSUzZXIFDNdC6OUMXQ4TM8gZTrITXs8CLDm7cK8iCqFCtzKOjKK6KyOKAg=="
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.2.0.tgz",
|
||||
"integrity": "sha512-vN4P/a+QqAuVfWFB9G3nQ7d6bgnM9jd/RLVi49owMuqvM24pv5mTQHUk2Hk4S3k7ConrHFl69E7xH6Dv5VpQnQ=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.1.0.tgz",
|
||||
"integrity": "sha512-6JAplzUOS6bEwfX0PDRZBbYRvn9EN22kZfcL0qGHtM9L0QQ5ybjbbVwOpbXgRkiZx++dQbzLFtelxnDhsbFG+Q==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.0.tgz",
|
||||
"integrity": "sha512-YToUC7xYf2E/pIluI7upYTlj8fKXOtdwoOBkcQZifHgX/dP+qDaHibbBFe5PyZwdmU2UiLnWFsBr0gjo0QFo1g==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.1.0",
|
||||
"@sentry/types": "6.2.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -1682,9 +1634,9 @@
|
|||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
|
||||
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
|
@ -2729,9 +2681,9 @@
|
|||
}
|
||||
},
|
||||
"rollup-plugin-copy": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.3.0.tgz",
|
||||
"integrity": "sha512-euDjCUSBXZa06nqnwCNADbkAcYDfzwowfZQkto9K/TFhiH+QG7I4PUsEMwM9tDgomGWJc//z7KLW8t+tZwxADA==",
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz",
|
||||
"integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==",
|
||||
"requires": {
|
||||
"@types/fs-extra": "^8.0.1",
|
||||
"colorette": "^1.1.0",
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.2",
|
||||
"@patternfly/patternfly": "^4.87.3",
|
||||
"@sentry/browser": "^6.1.0",
|
||||
"@sentry/tracing": "^6.1.0",
|
||||
"@sentry/browser": "^6.2.0",
|
||||
"@sentry/tracing": "^6.2.0",
|
||||
"@types/chart.js": "^2.9.30",
|
||||
"@types/codemirror": "0.0.108",
|
||||
"base64-js": "^1.5.1",
|
||||
|
@ -24,7 +24,7 @@
|
|||
"lit-element": "^2.4.0",
|
||||
"lit-html": "^1.3.0",
|
||||
"rollup": "^2.39.0",
|
||||
"rollup-plugin-copy": "^3.3.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-cssimport": "^1.0.2",
|
||||
"rollup-plugin-external-globals": "^0.6.1",
|
||||
"tslib": "^2.1.0"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { DefaultClient, AKResponse, QueryArguments, BaseInheritanceModel } from "./Client";
|
||||
import { TypeCreate } from "./Providers";
|
||||
|
||||
export enum FlowDesignation {
|
||||
|
@ -40,8 +40,8 @@ export class Flow {
|
|||
}
|
||||
|
||||
static cached(): Promise<number> {
|
||||
return DefaultClient.fetch<AKResponse<Flow>>(["flows", "cached"]).then(r => {
|
||||
return r.pagination.count;
|
||||
return DefaultClient.fetch<{ count: number }>(["flows", "all", "cached"]).then(r => {
|
||||
return r.count;
|
||||
});
|
||||
}
|
||||
static adminUrl(rest: string): string {
|
||||
|
@ -49,16 +49,26 @@ export class Flow {
|
|||
}
|
||||
}
|
||||
|
||||
export class Stage {
|
||||
export class Stage implements BaseInheritanceModel {
|
||||
pk: string;
|
||||
name: string;
|
||||
__type__: string;
|
||||
object_type: string;
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
flow_set: Flow[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(slug: string): Promise<Stage> {
|
||||
return DefaultClient.fetch<Stage>(["stages", "all", slug]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Stage>> {
|
||||
return DefaultClient.fetch<AKResponse<Stage>>(["stages", "all"], filter);
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["stages", "all", "types"]);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,28 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
import { EventContext } from "./Events";
|
||||
|
||||
export class Group {
|
||||
|
||||
group_uuid: string;
|
||||
pk: string;
|
||||
name: string;
|
||||
is_superuser: boolean;
|
||||
attributes: EventContext;
|
||||
parent?: Group;
|
||||
users: number[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Group> {
|
||||
return DefaultClient.fetch<Group>(["core", "groups", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Group>> {
|
||||
return DefaultClient.fetch<AKResponse<Group>>(["core", "groups"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/groups/${rest}`;
|
||||
}
|
||||
}
|
||||
|
|
27
web/src/api/Invitations.ts
Normal file
27
web/src/api/Invitations.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
import { EventContext } from "./Events";
|
||||
import { User } from "./Users";
|
||||
|
||||
export class Invitation {
|
||||
|
||||
pk: string;
|
||||
expires: number;
|
||||
fixed_date: EventContext;
|
||||
created_by: User;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Invitation> {
|
||||
return DefaultClient.fetch<Invitation>(["stages", "invitation", "invitations", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Invitation>> {
|
||||
return DefaultClient.fetch<AKResponse<Invitation>>(["stages", "invitation", "invitations"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/stages/invitations/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { Provider } from "./Providers";
|
||||
import { Provider, TypeCreate } from "./Providers";
|
||||
|
||||
export interface OutpostHealth {
|
||||
last_seen: number;
|
||||
|
@ -38,3 +38,42 @@ export class Outpost {
|
|||
return `/administration/outposts/${rest}`;
|
||||
}
|
||||
}
|
||||
|
||||
export interface OutpostServiceConnectionState {
|
||||
version: string;
|
||||
healthy: boolean;
|
||||
}
|
||||
|
||||
export class OutpostServiceConnection {
|
||||
pk: string;
|
||||
name: string;
|
||||
local: boolean;
|
||||
object_type: string;
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<OutpostServiceConnection> {
|
||||
return DefaultClient.fetch<OutpostServiceConnection>(["outposts", "service_connections", "all", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<OutpostServiceConnection>> {
|
||||
return DefaultClient.fetch<AKResponse<OutpostServiceConnection>>(["outposts", "service_connections", "all"], filter);
|
||||
}
|
||||
|
||||
static state(pk: string): Promise<OutpostServiceConnectionState> {
|
||||
return DefaultClient.fetch<OutpostServiceConnectionState>(["outposts", "service_connections", "all", pk, "state"]);
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["outposts", "service_connections", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/outpost_service_connections/${rest}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
import { DefaultClient, BaseInheritanceModel, AKResponse, QueryArguments } from "./Client";
|
||||
import { TypeCreate } from "./Providers";
|
||||
|
||||
export class Policy implements BaseInheritanceModel {
|
||||
pk: string;
|
||||
name: string;
|
||||
execution_logging: boolean;
|
||||
object_type: string;
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
bound_to: number;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
object_type: string;
|
||||
verbose_name: string;
|
||||
verbose_name_plural: string;
|
||||
|
||||
static get(pk: string): Promise<Policy> {
|
||||
return DefaultClient.fetch<Policy>(["policies", "all", pk]);
|
||||
|
@ -20,8 +23,16 @@ export class Policy implements BaseInheritanceModel {
|
|||
}
|
||||
|
||||
static cached(): Promise<number> {
|
||||
return DefaultClient.fetch<AKResponse<Policy>>(["policies", "cached"]).then(r => {
|
||||
return r.pagination.count;
|
||||
return DefaultClient.fetch<{ count: number }>(["policies", "all", "cached"]).then(r => {
|
||||
return r.count;
|
||||
});
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["policies", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/policies/${rest}`;
|
||||
}
|
||||
}
|
||||
|
|
30
web/src/api/Prompts.ts
Normal file
30
web/src/api/Prompts.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { DefaultClient, QueryArguments, AKResponse } from "./Client";
|
||||
import { Stage } from "./Flows";
|
||||
|
||||
export class Prompt {
|
||||
|
||||
pk: string;
|
||||
field_key: string;
|
||||
label: string;
|
||||
type: string;
|
||||
required: boolean;
|
||||
placeholder: string;
|
||||
order: number;
|
||||
promptstage_set: Stage[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<Prompt> {
|
||||
return DefaultClient.fetch<Prompt>(["stages", "prompt", "prompts", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Prompt>> {
|
||||
return DefaultClient.fetch<AKResponse<Prompt>>(["stages", "prompt", "prompts"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/stages/prompts/${rest}`;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
import { TypeCreate } from "./Providers";
|
||||
|
||||
export class PropertyMapping {
|
||||
pk: string;
|
||||
|
@ -20,6 +21,10 @@ export class PropertyMapping {
|
|||
return DefaultClient.fetch<AKResponse<PropertyMapping>>(["propertymappings", "all"], filter);
|
||||
}
|
||||
|
||||
static getTypes(): Promise<TypeCreate[]> {
|
||||
return DefaultClient.fetch<TypeCreate[]>(["propertymappings", "all", "types"]);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/property-mappings/${rest}`;
|
||||
}
|
||||
|
|
33
web/src/api/SystemTask.ts
Normal file
33
web/src/api/SystemTask.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { DefaultClient, QueryArguments } from "./Client";
|
||||
|
||||
export enum TaskStatus {
|
||||
SUCCESSFUL = 1,
|
||||
WARNING = 2,
|
||||
ERROR = 4,
|
||||
}
|
||||
|
||||
export class SystemTask {
|
||||
|
||||
task_name: string;
|
||||
task_description: string;
|
||||
task_finish_timestamp: number;
|
||||
status: TaskStatus;
|
||||
messages: string[];
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(task_name: string): Promise<SystemTask> {
|
||||
return DefaultClient.fetch<SystemTask>(["admin", "system_tasks", task_name]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<SystemTask[]> {
|
||||
return DefaultClient.fetch<SystemTask[]>(["admin", "system_tasks"], filter);
|
||||
}
|
||||
|
||||
static retry(task_name: string): string {
|
||||
return DefaultClient.makeUrl(["admin", "system_tasks", task_name, "retry"]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,47 @@
|
|||
import { DefaultClient } from "./Client";
|
||||
import { AKResponse, DefaultClient, QueryArguments } from "./Client";
|
||||
import { User } from "./Users";
|
||||
|
||||
interface TokenResponse {
|
||||
key: string;
|
||||
export enum TokenIntent {
|
||||
INTENT_VERIFICATION = "verification",
|
||||
INTENT_API = "api",
|
||||
INTENT_RECOVERY = "recovery",
|
||||
}
|
||||
|
||||
export function tokenByIdentifier(identifier: string): Promise<string> {
|
||||
return DefaultClient.fetch<TokenResponse>(["core", "tokens", identifier, "view_key"]).then(
|
||||
(r) => r.key
|
||||
);
|
||||
export class Token {
|
||||
|
||||
pk: string;
|
||||
identifier: string;
|
||||
intent: TokenIntent;
|
||||
user: User;
|
||||
description: string;
|
||||
|
||||
expires: number;
|
||||
expiring: boolean;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<User> {
|
||||
return DefaultClient.fetch<User>(["core", "tokens", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Token>> {
|
||||
return DefaultClient.fetch<AKResponse<Token>>(["core", "tokens"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/tokens/${rest}`;
|
||||
}
|
||||
|
||||
static userUrl(rest: string): string {
|
||||
return `/-/user/tokens/${rest}`;
|
||||
}
|
||||
|
||||
static getKey(identifier: string): Promise<string> {
|
||||
return DefaultClient.fetch<{ key: string }>(["core", "tokens", identifier, "view_key"]).then(
|
||||
(r) => r.key
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { DefaultClient, AKResponse } from "./Client";
|
||||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||
|
||||
let _globalMePromise: Promise<User>;
|
||||
|
||||
|
@ -9,11 +9,25 @@ export class User {
|
|||
is_superuser: boolean;
|
||||
email: boolean;
|
||||
avatar: string;
|
||||
is_active: boolean;
|
||||
last_login: number;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<User> {
|
||||
return DefaultClient.fetch<User>(["core", "users", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<User>> {
|
||||
return DefaultClient.fetch<AKResponse<User>>(["core", "users"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/users/${rest}`;
|
||||
}
|
||||
|
||||
static me(): Promise<User> {
|
||||
if (!_globalMePromise) {
|
||||
_globalMePromise = DefaultClient.fetch<User>(["core", "users", "me"]);
|
||||
|
|
|
@ -85,10 +85,6 @@ select[multiple] {
|
|||
z-index: auto !important;
|
||||
}
|
||||
|
||||
.pf-c-page__main {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--ak-dark-foreground: #fafafa;
|
||||
|
|
|
@ -70,18 +70,18 @@ export class SpinnerButton extends LitElement {
|
|||
@click=${() => this.callAction()}
|
||||
>
|
||||
${this.isRunning
|
||||
? html` <span class="pf-c-button__progress">
|
||||
<span
|
||||
class="pf-c-spinner pf-m-md"
|
||||
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>
|
||||
</span>`
|
||||
: ""}
|
||||
? html` <span class="pf-c-button__progress">
|
||||
<span
|
||||
class="pf-c-spinner pf-m-md"
|
||||
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>
|
||||
</span>`
|
||||
: ""}
|
||||
<slot></slot>
|
||||
</button>`;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { css, CSSResult, customElement, html, LitElement, property, TemplateResu
|
|||
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
|
||||
// @ts-ignore
|
||||
import ButtonStyle from "@patternfly/patternfly/components/Button/button.css";
|
||||
import { tokenByIdentifier } from "../../api/Tokens";
|
||||
import { Token } from "../../api/Tokens";
|
||||
import { ColorStyles, ERROR_CLASS, PRIMARY_CLASS, SUCCESS_CLASS } from "../../constants";
|
||||
|
||||
@customElement("ak-token-copy-button")
|
||||
|
@ -35,7 +35,7 @@ export class TokenCopyButton extends LitElement {
|
|||
}, 1500);
|
||||
return;
|
||||
}
|
||||
tokenByIdentifier(this.identifier).then((token) => {
|
||||
Token.getKey(this.identifier).then((token) => {
|
||||
navigator.clipboard.writeText(token).then(() => {
|
||||
this.buttonClass = SUCCESS_CLASS;
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -47,6 +47,7 @@ export class MessageContainer extends LitElement {
|
|||
this.messageSocket = new WebSocket(wsUrl);
|
||||
this.messageSocket.addEventListener("open", () => {
|
||||
console.debug(`authentik/messages: connected to ${wsUrl}`);
|
||||
this.retryDelay = 200;
|
||||
});
|
||||
this.messageSocket.addEventListener("close", (e) => {
|
||||
console.debug(`authentik/messages: closed ws connection: ${e}`);
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import { customElement, html, LitElement, TemplateResult } from "lit-element";
|
||||
import { CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element";
|
||||
import { COMMON_STYLES } from "../../common/styles";
|
||||
|
||||
@customElement("ak-notification-trigger")
|
||||
export class NotificationRule extends LitElement {
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return COMMON_STYLES;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.addEventListener("click", () => {
|
||||
|
@ -16,7 +21,8 @@ export class NotificationRule extends LitElement {
|
|||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
return html`<slot></slot>`;
|
||||
// TODO: Show icon with red dot when unread notifications exist
|
||||
return html`<i class="fas fa-bell pf-c-dropdown__toggle-icon" aria-hidden="true"></i>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
27
web/src/elements/router/Router404.ts
Normal file
27
web/src/elements/router/Router404.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { gettext } from "django";
|
||||
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||
import { COMMON_STYLES } from "../../common/styles";
|
||||
|
||||
@customElement("ak-router-404")
|
||||
export class Router404 extends LitElement {
|
||||
|
||||
@property()
|
||||
url = "";
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return COMMON_STYLES;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
return html`<div class="pf-c-empty-state pf-m-full-height">
|
||||
<div class="pf-c-empty-state__content">
|
||||
<i class="fas fa-question-circle pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||
<h1 class="pf-c-title pf-m-lg">${gettext("Not found")}</h1>
|
||||
<div class="pf-c-empty-state__body">
|
||||
${gettext(`The url '${this.url}' was not found.`)}
|
||||
</div>
|
||||
<a href="#/" class="pf-c-button pf-m-primary" type="button">${gettext("Return home")}</a>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import { ROUTES } from "../../routes";
|
|||
import { RouteMatch } from "./RouteMatch";
|
||||
|
||||
import "../../pages/generic/SiteShell";
|
||||
import "./Router404";
|
||||
|
||||
@customElement("ak-router-outlet")
|
||||
export class RouterOutlet extends LitElement {
|
||||
|
@ -28,6 +29,11 @@ export class RouterOutlet extends LitElement {
|
|||
:host {
|
||||
height: 100vh;
|
||||
}
|
||||
*:first-child {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
`,
|
||||
].concat(...COMMON_STYLES);
|
||||
}
|
||||
|
@ -62,12 +68,12 @@ export class RouterOutlet extends LitElement {
|
|||
}
|
||||
});
|
||||
if (!matchedRoute) {
|
||||
console.debug(`authentik/router: route "${activeUrl}" not defined, defaulting to shell`);
|
||||
console.debug(`authentik/router: route "${activeUrl}" not defined`);
|
||||
const route = new Route(
|
||||
RegExp(""),
|
||||
html`<ak-site-shell url=${activeUrl}>
|
||||
<div slot="body"></div>
|
||||
</ak-site-shell>`
|
||||
html`<div class="pf-c-page__main">
|
||||
<ak-router-404 url=${activeUrl}></ak-router-404>
|
||||
</div>`
|
||||
);
|
||||
matchedRoute = new RouteMatch(route);
|
||||
matchedRoute.arguments = route.url.exec(activeUrl)?.groups || {};
|
||||
|
@ -77,7 +83,6 @@ export class RouterOutlet extends LitElement {
|
|||
}
|
||||
|
||||
render(): TemplateResult | undefined {
|
||||
// TODO: Render 404 when current Route is empty
|
||||
return this.current?.render();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ export class SidebarItem {
|
|||
this.condition = async () => true;
|
||||
this.activeMatchers = [];
|
||||
if (this.path) {
|
||||
this.activeMatchers.push(new RegExp(`^${this.path}`));
|
||||
this.activeMatchers.push(new RegExp(`^${this.path}$`));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,11 +37,11 @@ export class SidebarUser extends LitElement {
|
|||
render(): TemplateResult {
|
||||
return html`
|
||||
<a href="#/-/user/" class="pf-c-nav__link user-avatar" id="user-settings">
|
||||
${until(User.me().then(u => {
|
||||
return html`<img class="pf-c-avatar" src="${u.avatar}" alt="" />`;}), html``)}
|
||||
${until(User.me().then((u) => {
|
||||
return html`<img class="pf-c-avatar" src="${u.avatar}" alt="" />`;
|
||||
}), html``)}
|
||||
</a>
|
||||
<ak-notification-trigger class="pf-c-nav__link user-notifications">
|
||||
<i class="fas fa-bell pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||
</ak-notification-trigger>
|
||||
<a href="/flows/-/default/invalidation/" class="pf-c-nav__link user-logout" id="logout">
|
||||
<i class="fas fa-sign-out-alt" aria-hidden="true"></i>
|
||||
|
|
|
@ -43,7 +43,7 @@ export class TablePagination extends LitElement {
|
|||
<button
|
||||
class="pf-c-button pf-m-plain"
|
||||
@click=${() => { this.pageChangeHandler(this.pages?.next || 0); }}
|
||||
?disabled="${(this.pages?.next || 0) < 0}"
|
||||
?disabled="${(this.pages?.next || 0) <= 0}"
|
||||
aria-label="${gettext("Go to next page")}"
|
||||
>
|
||||
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||
|
|
|
@ -8,7 +8,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
|||
new SidebarItem("Library", "/library"),
|
||||
new SidebarItem("Monitor").children(
|
||||
new SidebarItem("Overview", "/administration/overview"),
|
||||
new SidebarItem("System Tasks", "/administration/tasks/"),
|
||||
new SidebarItem("System Tasks", "/administration/system-tasks"),
|
||||
).when((): Promise<boolean> => {
|
||||
return User.me().then(u => u.is_superuser);
|
||||
}),
|
||||
|
@ -20,37 +20,37 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
|||
return User.me().then(u => u.is_superuser);
|
||||
}),
|
||||
new SidebarItem("Resources").children(
|
||||
new SidebarItem("Applications", "/applications").activeWhen(
|
||||
`^/applications/(?<slug>${SLUG_REGEX})$`
|
||||
new SidebarItem("Applications", "/core/applications").activeWhen(
|
||||
`^/core/applications/(?<slug>${SLUG_REGEX})$`
|
||||
),
|
||||
new SidebarItem("Sources", "/sources").activeWhen(
|
||||
`^/sources/(?<slug>${SLUG_REGEX})$`,
|
||||
new SidebarItem("Sources", "/core/sources").activeWhen(
|
||||
`^/core/sources/(?<slug>${SLUG_REGEX})$`,
|
||||
),
|
||||
new SidebarItem("Providers", "/providers"),
|
||||
new SidebarItem("Outposts", "/outposts"),
|
||||
new SidebarItem("Outpost Service Connections", "/administration/outpost_service_connections/"),
|
||||
new SidebarItem("Providers", "/core/providers"),
|
||||
new SidebarItem("Outposts", "/outpost/outposts"),
|
||||
new SidebarItem("Outpost Service Connections", "/outpost/service-connections"),
|
||||
).when((): Promise<boolean> => {
|
||||
return User.me().then(u => u.is_superuser);
|
||||
}),
|
||||
new SidebarItem("Customisation").children(
|
||||
new SidebarItem("Policies", "/administration/policies/"),
|
||||
new SidebarItem("Property Mappings", "/property-mappings"),
|
||||
new SidebarItem("Policies", "/policy/policies"),
|
||||
new SidebarItem("Property Mappings", "/core/property-mappings"),
|
||||
).when((): Promise<boolean> => {
|
||||
return User.me().then(u => u.is_superuser);
|
||||
}),
|
||||
new SidebarItem("Flows").children(
|
||||
new SidebarItem("Flows", "/flows").activeWhen(`^/flows/(?<slug>${SLUG_REGEX})$`),
|
||||
new SidebarItem("Stages", "/administration/stages/"),
|
||||
new SidebarItem("Prompts", "/administration/stages_prompts/"),
|
||||
new SidebarItem("Invitations", "/administration/stages/invitations/"),
|
||||
new SidebarItem("Flows", "/flow/flows").activeWhen(`^/flow/flows/(?<slug>${SLUG_REGEX})$`),
|
||||
new SidebarItem("Stages", "/flow/stages"),
|
||||
new SidebarItem("Prompts", "/flow/stages/prompts"),
|
||||
new SidebarItem("Invitations", "/flow/stages/invitations"),
|
||||
).when((): Promise<boolean> => {
|
||||
return User.me().then(u => u.is_superuser);
|
||||
}),
|
||||
new SidebarItem("Identity & Cryptography").children(
|
||||
new SidebarItem("User", "/administration/users/"),
|
||||
new SidebarItem("Groups", "/administration/groups/"),
|
||||
new SidebarItem("User", "/identity/users"),
|
||||
new SidebarItem("Groups", "/identity/groups"),
|
||||
new SidebarItem("Certificates", "/crypto/certificates"),
|
||||
new SidebarItem("Tokens", "/administration/tokens/"),
|
||||
new SidebarItem("Tokens", "/core/tokens"),
|
||||
).when((): Promise<boolean> => {
|
||||
return User.me().then(u => u.is_superuser);
|
||||
}),
|
||||
|
|
|
@ -28,6 +28,7 @@ import "./pages/admin-overview/AdminOverviewPage";
|
|||
import "./pages/admin-overview/TopApplicationsTable";
|
||||
import "./pages/applications/ApplicationListPage";
|
||||
import "./pages/applications/ApplicationViewPage";
|
||||
import "./pages/tokens/UserTokenList";
|
||||
import "./pages/LibraryPage";
|
||||
|
||||
import "./elements/stages/authenticator_webauthn/WebAuthnRegister";
|
||||
|
|
|
@ -14,6 +14,10 @@ export class LibraryApplication extends LitElement {
|
|||
static get styles(): CSSResult[] {
|
||||
return COMMON_STYLES.concat(
|
||||
css`
|
||||
:host,
|
||||
main {
|
||||
height: 100%;
|
||||
}
|
||||
a {
|
||||
height: 100%;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ export class AdminOverviewPage extends LitElement {
|
|||
<ak-aggregate-card class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-server" header="Apps with most usage" style="grid-column-end: span 2;grid-row-end: span 3;">
|
||||
<ak-top-applications-table></ak-top-applications-table>
|
||||
</ak-aggregate-card>
|
||||
<ak-admin-status-card-provider class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/providers/">
|
||||
<ak-admin-status-card-provider class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-plugged" header="Providers" headerLink="#/core/providers/">
|
||||
</ak-admin-status-card-provider>
|
||||
<ak-admin-status-card-policy-unbound class="pf-l-gallery__item pf-m-4-col" icon="pf-icon pf-icon-infrastructure" header="Policies" headerLink="#/administration/policies/">
|
||||
</ak-admin-status-card-policy-unbound>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue