admin: sort types, minor fixups

This commit is contained in:
Jens Langhammer 2020-05-13 11:57:10 +02:00
parent 57fed2b92b
commit c42ed6bc99
11 changed files with 121 additions and 80 deletions

View File

@ -34,7 +34,8 @@ class StageListView(LoginRequiredMixin, PermissionListMixin, ListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs["types"] = { kwargs["types"] = {
x.__name__: x._meta.verbose_name for x in all_subclasses(Stage) x.__name__: x._meta.verbose_name
for x in sorted(all_subclasses(Stage), key=lambda x: x.__name__)
} }
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)

View File

@ -86,13 +86,13 @@ router.register("stages/invitation", InvitationStageViewSet)
router.register("stages/invitation/invitations", InvitationViewSet) router.register("stages/invitation/invitations", InvitationViewSet)
router.register("stages/otp", OTPStageViewSet) router.register("stages/otp", OTPStageViewSet)
router.register("stages/password", PasswordStageViewSet) router.register("stages/password", PasswordStageViewSet)
router.register("stages/prompt", PromptStageViewSet) router.register("stages/prompt/stages", PromptStageViewSet)
router.register("stages/prompt/prompts", PromptViewSet) router.register("stages/prompt/prompts", PromptViewSet)
router.register("stages/user_login", UserLoginStageViewSet) router.register("stages/user_login", UserLoginStageViewSet)
router.register("stages/user_logout", UserLogoutStageViewSet) router.register("stages/user_logout", UserLogoutStageViewSet)
router.register("stages/user_write", UserWriteStageViewSet) router.register("stages/user_write", UserWriteStageViewSet)
router.register("flows", FlowViewSet) router.register("flows/instances", FlowViewSet)
router.register("flows/bindings", FlowStageBindingViewSet) router.register("flows/bindings", FlowStageBindingViewSet)
if settings.DEBUG: if settings.DEBUG:

View File

@ -25,6 +25,11 @@
<div class="select col-sm-10"> <div class="select col-sm-10">
{{ field }} {{ field }}
</div> </div>
{% if field.help_text %}
<span>
{{ field.help_text }}
</span>
{% endif %}
{% elif field.field.widget|fieldtype == 'CheckboxInput' %} {% elif field.field.widget|fieldtype == 'CheckboxInput' %}
<label class="checkbox-label"> <label class="checkbox-label">
{{ field }} {{ field.label }} {{ field }} {{ field.label }}

View File

@ -57,12 +57,8 @@
<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content"> <main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
<section class="pf-c-page__main-section"> <section class="pf-c-page__main-section">
<div class="pf-l-split pf-m-gutter"> <div class="pf-l-split pf-m-gutter">
<div class="pf-l-split__item"> {% block page %}
<div class="pf-c-card"> {% endblock %}
{% block page %}
{% endblock %}
</div>
</div>
</div> </div>
</section> </section>
</main> </main>

View File

@ -3,22 +3,55 @@
{% load i18n %} {% load i18n %}
{% block page %} {% block page %}
<div class="pf-c-card__header pf-c-title pf-m-md"> <div class="pf-l-split__item">
<h1>{% trans 'Update details' %}</h1> <div class="pf-c-card">
</div> <div class="pf-c-card__header pf-c-title pf-m-md">
<div class="pf-c-card__body"> <h1>{% trans 'Update details' %}</h1>
<form action="" method="post" class="pf-c-form pf-m-horizontal">
{% include 'partials/form_horizontal.html' with form=form %}
{% block beneath_form %}
{% endblock %}
<div class="pf-c-form__group pf-m-action">
<div class="pf-c-form__horizontal-group">
<div class="pf-c-form__actions">
<input class="pf-c-button pf-m-primary" type="submit" value="{% trans 'Update' %}" />
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_flows:default-unenrollment' %}?back={{ request.get_full_path }}">{% trans "Delete account" %}</a>
</div>
</div>
</div> </div>
</form> <div class="pf-c-card__body">
<form action="" method="post" class="pf-c-form pf-m-horizontal">
{% include 'partials/form_horizontal.html' with form=form %}
{% block beneath_form %}
{% endblock %}
<div class="pf-c-form__group pf-m-action">
<div class="pf-c-form__horizontal-group">
<div class="pf-c-form__actions">
<input class="pf-c-button pf-m-primary" type="submit" value="{% trans 'Update' %}" />
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_flows:default-unenrollment' %}?back={{ request.get_full_path }}">{% trans "Delete account" %}</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="pf-l-split__item">
<div class="pf-c-card">
<div class="pf-c-card__header pf-c-title pf-m-md">
<h1>{% trans 'Sessions' %}</h1>
</div>
<div class="pf-c-card__body">
<table class="pf-c-table pf-m-grid-md" role="grid" aria-label="This is a simple table example" id="table-basic">
<thead>
<tr role="row">
<th role="columnheader" scope="col">Repositories</th>
<th role="columnheader" scope="col">Branches</th>
<th role="columnheader" scope="col">Pull requests</th>
<th role="columnheader" scope="col">Workspaces</th>
<th role="columnheader" scope="col">Last commit</th>
</tr>
</thead>
<tbody role="rowgroup">
<tr role="row">
<td role="cell" data-label="Repository name">Repository 1</td>
<td role="cell" data-label="Branches">10</td>
<td role="cell" data-label="Pull requests">25</td>
<td role="cell" data-label="Workspaces">5</td>
<td role="cell" data-label="Last commit">2 days ago</td>
</tr>
</tbody>
</table>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -6,6 +6,7 @@ from django.template.context import RequestContext
from passbook.core.models import Source from passbook.core.models import Source
from passbook.core.types import UIUserSettings from passbook.core.types import UIUserSettings
from passbook.flows.models import Stage
from passbook.policies.engine import PolicyEngine from passbook.policies.engine import PolicyEngine
register = template.Library() register = template.Library()
@ -15,20 +16,14 @@ register = template.Library()
# pylint: disable=unused-argument # pylint: disable=unused-argument
def user_stages(context: RequestContext) -> List[UIUserSettings]: def user_stages(context: RequestContext) -> List[UIUserSettings]:
"""Return list of all stages which apply to user""" """Return list of all stages which apply to user"""
# TODO: Rewrite this based on flows _all_stages: Iterable[Stage] = Stage.objects.all().select_subclasses()
# user = context.get("request").user
# _all_stages: Iterable[Stage] = (Stage.objects.all().select_subclasses())
matching_stages: List[UIUserSettings] = [] matching_stages: List[UIUserSettings] = []
# for stage in _all_stages: for stage in _all_stages:
# user_settings = stage.ui_user_settings user_settings = stage.ui_user_settings
# if not user_settings: if not user_settings:
# continue continue
# policy_engine = PolicyEngine( matching_stages.append(user_settings)
# stage.policies.all(), user, context.get("request") print(matching_stages)
# )
# policy_engine.build()
# if policy_engine.passing:
# matching_stages.append(user_settings)
return matching_stages return matching_stages

View File

@ -35,21 +35,27 @@ class FlowStageBindingViewSet(ModelViewSet):
queryset = FlowStageBinding.objects.all() queryset = FlowStageBinding.objects.all()
serializer_class = FlowStageBindingSerializer serializer_class = FlowStageBindingSerializer
filterset_fields = "__all__"
class StageSerializer(ModelSerializer): class StageSerializer(ModelSerializer):
"""Stage Serializer""" """Stage Serializer"""
__type__ = SerializerMethodField(method_name="get_type") __type__ = SerializerMethodField(method_name="get_type")
verbose_name = SerializerMethodField(method_name="get_verbose_name")
def get_type(self, obj): def get_type(self, obj: Stage) -> str:
"""Get object type so that we know which API Endpoint to use to get the full object""" """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", "") return obj._meta.object_name.lower().replace("stage", "")
def get_verbose_name(self, obj: Stage) -> str:
"""Get verbose name for UI"""
return obj._meta.verbose_name
class Meta: class Meta:
model = Stage model = Stage
fields = ["pk", "name", "__type__"] fields = ["pk", "name", "__type__", "verbose_name"]
class StageViewSet(ReadOnlyModelViewSet): class StageViewSet(ReadOnlyModelViewSet):

View File

@ -20,6 +20,16 @@ class FlowForm(forms.ModelForm):
"stages", "stages",
"policies", "policies",
] ]
help_texts = {
"name": _("Shown as the Title in Flow pages."),
"slug": _("Visible in the URL."),
"designation": _(
(
"Decides what this Flow is used for. For example, the Authentication flow "
"is redirect to when an un-authenticated user visits passbook."
)
),
}
widgets = { widgets = {
"name": forms.TextInput(), "name": forms.TextInput(),
"stages": FilteredSelectMultiple(_("stages"), False), "stages": FilteredSelectMultiple(_("stages"), False),

View File

@ -77,6 +77,7 @@ INSTALLED_APPS = [
"django.contrib.postgres", "django.contrib.postgres",
"django.contrib.humanize", "django.contrib.humanize",
"rest_framework", "rest_framework",
"django_filters",
"drf_yasg", "drf_yasg",
"guardian", "guardian",
"django_prometheus", "django_prometheus",

View File

@ -4,45 +4,39 @@
{% load i18n %} {% load i18n %}
{% block page %} {% block page %}
<div class="pf-c-card__header pf-c-title pf-m-md"> <div class="pf-c-card">
<h1>{% trans "One-Time Passwords" %}</h1> <div class="pf-c-card__header pf-c-title pf-m-md">
{% trans "One-Time Passwords" %}
</div>
<div class="pf-c-card__body">
<p>
{% blocktrans with state=state|yesno:"Enabled,Disabled" %}
Status: {{ state }}
{% endblocktrans %}
{% if state %}
<i class="pf-icon pf-icon-ok"></i>
{% else %}
<i class="pf-icon pf-icon-error-circle-o"></i>
{% endif %}
</p>
<p>
{% if not state %}
<a href="{% url 'passbook_stages_otp:otp-enable' %}" class="btn btn-success btn-sm">{% trans "Enable OTP" %}</a>
{% else %}
<a href="{% url 'passbook_stages_otp:otp-disable' %}" class="btn btn-danger btn-sm">{% trans "Disable OTP" %}</a>
{% endif %}
</p>
</div>
</div> </div>
<div class="pf-c-card__body">
<div class="row"> <div class="pf-c-card">
<div class="col-md-6"> <div class="pf-c-card__header pf-c-title pf-m-md">
<div class="card-footer"> {% trans "Your Backup tokens:" %}
<p> </div>
{% blocktrans with state=state|yesno:"Enabled,Disabled" %} <div class="pf-c-card__body">
Status: {{ state }} <pre>{% for token in static_tokens %}{{ token.token }}
{% endblocktrans %} {% empty %}{% trans 'N/A' %}{% endfor %}</pre>
{% if state %}
<i class="pf-icon pf-icon-ok"></i>
{% else %}
<i class="pf-icon pf-icon-error-circle-o"></i>
{% endif %}
</p>
<p>
{% if not state %}
<a href="{% url 'passbook_stages_otp:otp-enable' %}"
class="btn btn-success btn-sm">{% trans "Enable OTP" %}</a>
{% else %}
<a href="{% url 'passbook_stages_otp:otp-disable' %}"
class="btn btn-danger btn-sm">{% trans "Disable OTP" %}</a>
{% endif %}
</p>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
{% trans "Your Backup tokens:" %}
</div>
<div class="card-block">
<pre>{% for token in static_tokens %}{{ token.token }}
{% empty %}{% trans 'N/A' %}{% endfor %}</pre>
</div>
</div>
</div>
</div> </div>
</div> </div>
{% endblock %} </div>
{% endblock %}

View File

@ -31,7 +31,7 @@ LOGGER = get_logger()
class UserSettingsView(LoginRequiredMixin, TemplateView): class UserSettingsView(LoginRequiredMixin, TemplateView):
"""View for user settings to control OTP""" """View for user settings to control OTP"""
template_name = "otp/user_settings.html" template_name = "stages/otp/user_settings.html"
# TODO: Check if OTP Stage exists and applies to user # TODO: Check if OTP Stage exists and applies to user
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):