*: rewrite user settings to use a single page
This commit is contained in:
		| @ -18,7 +18,7 @@ from structlog import get_logger | ||||
|  | ||||
| from passbook.core.exceptions import PropertyMappingExpressionException | ||||
| from passbook.core.signals import password_changed | ||||
| from passbook.core.types import UILoginButton, UIUserSettings | ||||
| from passbook.core.types import UILoginButton | ||||
| from passbook.flows.models import Flow | ||||
| from passbook.lib.models import CreatedUpdatedModel | ||||
| from passbook.policies.models import PolicyBindingModel | ||||
| @ -249,9 +249,9 @@ class Source(PolicyBindingModel): | ||||
|         return None | ||||
|  | ||||
|     @property | ||||
|     def ui_user_settings(self) -> Optional[UIUserSettings]: | ||||
|     def ui_user_settings(self) -> Optional[str]: | ||||
|         """Entrypoint to integrate with User settings. Can either return None if no | ||||
|         user settings are available, or an instanace of UIUserSettings.""" | ||||
|         user settings are available, or a string with the URL to fetch.""" | ||||
|         return None | ||||
|  | ||||
|     def __str__(self): | ||||
|  | ||||
| @ -1,71 +0,0 @@ | ||||
| {% extends "base/page.html" %} | ||||
|  | ||||
| {% load i18n %} | ||||
| {% load passbook_is_active %} | ||||
| {% load static %} | ||||
| {% load passbook_user_settings %} | ||||
|  | ||||
| {% block page_content %} | ||||
| <div class="pf-c-page__sidebar"> | ||||
|     <div class="pf-c-page__sidebar-body"> | ||||
|         <nav class="pf-c-nav" id="page-default-nav-example-primary-nav" aria-label="Global"> | ||||
|             <section class="pf-c-nav__section"> | ||||
|                 <h2 class="pf-c-nav__section-title">{% trans 'General Settings' %}</h2> | ||||
|                 <ul class="pf-c-nav__list"> | ||||
|                     <li class="pf-c-nav__item"> | ||||
|                         <a href="{% url 'passbook_core:user-settings' %}" | ||||
|                             class="pf-c-nav__link {% is_active 'passbook_core:user-settings' %}">{% trans 'User Details' %}</a> | ||||
|                     </li> | ||||
|                     <li class="pf-c-nav__item"> | ||||
|                         <a href="{% url 'passbook_core:user-tokens' %}" | ||||
|                             class="pf-c-nav__link {% is_active 'passbook_core:user-tokens' 'passbook_core:user-tokens-create' 'passbook_core:user-tokens-update' 'passbook_core:user-tokens-delete' %}">{% trans 'Tokens' %}</a> | ||||
|                     </li> | ||||
|                 </ul> | ||||
|             </section> | ||||
|             {% user_stages as user_stages_loc %} | ||||
|             {% if user_stages_loc %} | ||||
|             <section class="pf-c-nav__section"> | ||||
|                 <h2 class="pf-c-nav__section-title">{% trans 'Stages' %}</h2> | ||||
|                 <ul class="pf-c-nav__list"> | ||||
|                     {% for stage in user_stages_loc %} | ||||
|                     <li class="pf-c-nav__item"> | ||||
|                         <a href="{{ stage.url }}" class="pf-c-nav__link {% if stage.url == request.get_full_path %} pf-m-current {% endif %}"> | ||||
|                             {{ stage.name }} | ||||
|                         </a> | ||||
|                     </li> | ||||
|                     {% endfor %} | ||||
|                 </ul> | ||||
|             </section> | ||||
|             {% endif %} | ||||
|             {% user_sources as user_sources_loc %} | ||||
|             {% if user_sources_loc %} | ||||
|             <section class="pf-c-nav__section"> | ||||
|                 <h2 class="pf-c-nav__section-title">{% trans 'Sources' %}</h2> | ||||
|                 <ul class="pf-c-nav__list"> | ||||
|                     {% for source in user_sources_loc %} | ||||
|                     <li class="pf-c-nav__item"> | ||||
|                         <a href="{{ source.url }}" | ||||
|                             class="pf-c-nav__link {% if source.url == request.get_full_path %} pf-m-current {% endif %}"> | ||||
|                             {{ source.name }} | ||||
|                         </a> | ||||
|                     </li> | ||||
|                     {% endfor %} | ||||
|                 </ul> | ||||
|             </section> | ||||
|             {% endif %} | ||||
|         </nav> | ||||
|     </div> | ||||
| </div> | ||||
| <main role="main" class="pf-c-page__main" tabindex="-1" id="main-content"> | ||||
|     {% block content %} | ||||
|     <section class="pf-c-page__main-section"> | ||||
|         <div class="pf-u-display-flex pf-u-justify-content-center"> | ||||
|             <div class="pf-u-w-75"> | ||||
|                 {% block page %} | ||||
|                 {% endblock %} | ||||
|             </div> | ||||
|         </div> | ||||
|     </section> | ||||
|     {% endblock %} | ||||
| </main> | ||||
| {% endblock %} | ||||
| @ -1,28 +1,78 @@ | ||||
| {% extends "user/base.html" %} | ||||
|  | ||||
| {% load i18n %} | ||||
| {% load passbook_user_settings %} | ||||
|  | ||||
| {% block page %} | ||||
| <div class="pf-c-card"> | ||||
|     <div class="pf-c-card__header pf-c-title pf-m-md"> | ||||
|         {% trans 'Update details' %} | ||||
|     </div> | ||||
|     <div class="pf-c-card__body"> | ||||
|         <form action="" method="post" class="pf-c-form pf-m-horizontal"> | ||||
|             {% include 'partials/form_horizontal.html' with form=form %} | ||||
|             {% block beneath_form %} | ||||
|             {% endblock %} | ||||
|             <div class="pf-c-form__group pf-m-action"> | ||||
|                 <div class="pf-c-form__horizontal-group"> | ||||
|                     <div class="pf-c-form__actions"> | ||||
|                         <input class="pf-c-button pf-m-primary" type="submit" value="{% trans 'Update' %}" /> | ||||
|                         {% if unenrollment_enabled %} | ||||
|                         <a class="pf-c-button pf-m-danger" href="{% url 'passbook_flows:default-unenrollment' %}?back={{ request.get_full_path }}">{% trans "Delete account" %}</a> | ||||
|                         {% endif %} | ||||
| <div class="pf-c-page"> | ||||
|     <main role="main" class="pf-c-page__main" tabindex="-1"> | ||||
|         <section class="pf-c-page__main-section pf-m-light"> | ||||
|             <div class="pf-c-content"> | ||||
|                 <h1> | ||||
|                     <i class="pf-icon pf-icon-user"></i> | ||||
|                     {% trans 'User Settings' %} | ||||
|                 </h1> | ||||
|                 <p>{% trans "Configure settings relevant to your user profile." %}</p> | ||||
|             </div> | ||||
|         </section> | ||||
|         <section class="pf-c-page__main-section"> | ||||
|             <div class="pf-u-display-flex pf-u-justify-content-center"> | ||||
|                 <div class="pf-u-w-75"> | ||||
|                     <div class="pf-c-card"> | ||||
|                         <div class="pf-c-card__header pf-c-title pf-m-md"> | ||||
|                             {% trans 'Update details' %} | ||||
|                         </div> | ||||
|                         <div class="pf-c-card__body"> | ||||
|                             <form action="" method="post" class="pf-c-form pf-m-horizontal"> | ||||
|                                 {% include 'partials/form_horizontal.html' with form=form %} | ||||
|                                 {% block beneath_form %} | ||||
|                                 {% endblock %} | ||||
|                                 <div class="pf-c-form__group pf-m-action"> | ||||
|                                     <div class="pf-c-form__horizontal-group"> | ||||
|                                         <div class="pf-c-form__actions"> | ||||
|                                             <input class="pf-c-button pf-m-primary" type="submit" value="{% trans 'Update' %}" /> | ||||
|                                             {% if unenrollment_enabled %} | ||||
|                                             <a class="pf-c-button pf-m-danger" | ||||
|                                                 href="{% url 'passbook_flows:default-unenrollment' %}?back={{ request.get_full_path }}">{% trans "Delete account" %}</a> | ||||
|                                             {% endif %} | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </form> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </form> | ||||
|     </div> | ||||
|         </section> | ||||
|         <section class="pf-c-page__main-section"> | ||||
|             <div class="pf-u-display-flex pf-u-justify-content-center"> | ||||
|                 <div class="pf-u-w-75"> | ||||
|                     <pb-site-shell url="{% url 'passbook_core:user-tokens' %}"> | ||||
|                         <div slot="body"></div> | ||||
|                     </pb-site-shell> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </section> | ||||
|         {% user_stages as user_stages_loc %} | ||||
|         {% for stage in user_stages_loc %} | ||||
|         <section class="pf-c-page__main-section"> | ||||
|             <div class="pf-u-display-flex pf-u-justify-content-center"> | ||||
|                 <div class="pf-u-w-75"> | ||||
|                     <pb-site-shell url="{{ stage }}"> | ||||
|                         <div slot="body"></div> | ||||
|                     </pb-site-shell> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </section> | ||||
|         {% endfor %} | ||||
|         {% user_sources as user_sources_loc %} | ||||
|         {% for source in user_sources_loc %} | ||||
|         <section class="pf-c-page__main-section"> | ||||
|             <div class="pf-u-display-flex pf-u-justify-content-center"> | ||||
|                 <div class="pf-u-w-75"> | ||||
|                     <pb-site-shell url="{{ source }}"> | ||||
|                         <div slot="body"></div> | ||||
|                     </pb-site-shell> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </section> | ||||
|         {% endfor %} | ||||
|     </main> | ||||
| </div> | ||||
| {% endblock %} | ||||
|  | ||||
| @ -1,91 +1,81 @@ | ||||
| {% extends "user/base.html" %} | ||||
|  | ||||
| {% load i18n %} | ||||
| {% load passbook_utils %} | ||||
|  | ||||
| {% block content %} | ||||
| <section class="pf-c-page__main-section pf-m-light"> | ||||
|     <div class="pf-c-content"> | ||||
| <div class="pf-c-card"> | ||||
|     <div class="pf-c-card__header pf-c-title pf-m-md"> | ||||
|         <h1> | ||||
|             <i class="pf-icon pf-icon-users"></i> | ||||
|             {% trans 'Tokens' %} | ||||
|             {% trans 'Manage Tokens' %} | ||||
|         </h1> | ||||
|         <p>{% trans "Tokens can be used to access passbook's API." %} | ||||
|         </p> | ||||
|         <p>{% trans "Tokens can be used to access passbook's API." %}</p> | ||||
|     </div> | ||||
| </section> | ||||
| <section class="pf-c-page__main-section pf-m-no-padding-mobile"> | ||||
|     <div class="pf-c-card"> | ||||
|         {% if object_list %} | ||||
|         <div class="pf-c-toolbar"> | ||||
|             <div class="pf-c-toolbar__content"> | ||||
|                 {% include 'partials/toolbar_search.html' %} | ||||
|                 <div class="pf-c-toolbar__bulk-select"> | ||||
|                     <a href="{% url 'passbook_core:user-tokens-create' %}?back={{ request.get_full_path }}"  class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a> | ||||
|                 </div> | ||||
|                 {% include 'partials/pagination.html' %} | ||||
|     {% if object_list %} | ||||
|     <div class="pf-c-toolbar"> | ||||
|         <div class="pf-c-toolbar__content"> | ||||
|             {% include 'partials/toolbar_search.html' %} | ||||
|             <div class="pf-c-toolbar__bulk-select"> | ||||
|                 <a href="{% url 'passbook_core:user-tokens-create' %}?back={{ request.get_full_path }}"  class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a> | ||||
|             </div> | ||||
|         </div> | ||||
|         <table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid"> | ||||
|             <thead> | ||||
|                 <tr role="row"> | ||||
|                     <th role="columnheader" scope="col">{% trans 'Identifier' %}</th> | ||||
|                     <th role="columnheader" scope="col">{% trans 'Expires?' %}</th> | ||||
|                     <th role="columnheader" scope="col">{% trans 'Expiry Date' %}</th> | ||||
|                     <th role="columnheader" scope="col">{% trans 'Description' %}</th> | ||||
|                     <th role="cell"></th> | ||||
|                 </tr> | ||||
|             </thead> | ||||
|             <tbody role="rowgroup"> | ||||
|                 {% for token in object_list %} | ||||
|                 <tr role="row"> | ||||
|                     <th role="columnheader"> | ||||
|                         <div>{{ token.identifier }}</div> | ||||
|                     </th> | ||||
|                     <td role="cell"> | ||||
|                         <span> | ||||
|                             {{ token.expiring|yesno:"Yes,No" }} | ||||
|                         </span> | ||||
|                     </td> | ||||
|                     <td role="cell"> | ||||
|                         <span> | ||||
|                             {% if not token.expiring %} | ||||
|                             - | ||||
|                             {% else %} | ||||
|                             {{ token.expires }} | ||||
|                             {% endif %} | ||||
|                         </span> | ||||
|                     </td> | ||||
|                     <td role="cell"> | ||||
|                         <span> | ||||
|                             {{ token.description }} | ||||
|                         </span> | ||||
|                     </td> | ||||
|                     <td> | ||||
|                         <a class="pf-c-button pf-m-secondary" href="{% url 'passbook_core:user-tokens-update' identifier=token.identifier %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a> | ||||
|                         <a class="pf-c-button pf-m-danger" href="{% url 'passbook_core:user-tokens-delete' identifier=token.identifier %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> | ||||
|                     </td> | ||||
|                 </tr> | ||||
|                 {% endfor %} | ||||
|             </tbody> | ||||
|         </table> | ||||
|         <div class="pf-c-pagination pf-m-bottom"> | ||||
|             {% include 'partials/pagination.html' %} | ||||
|         </div> | ||||
|         {% else %} | ||||
|         <div class="pf-c-empty-state"> | ||||
|             <div class="pf-c-empty-state__content"> | ||||
|                 <i class="fas fa-cubes pf-c-empty-state__icon" aria-hidden="true"></i> | ||||
|                 <h1 class="pf-c-title pf-m-lg"> | ||||
|                     {% trans 'No Tokens.' %} | ||||
|                 </h1> | ||||
|                 <div class="pf-c-empty-state__body"> | ||||
|                     {% trans 'Currently no tokens exist. Click the button below to create one.' %} | ||||
|                 </div> | ||||
|                 <a href="{% url 'passbook_core:user-tokens-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a> | ||||
|             </div> | ||||
|         </div> | ||||
|         {% endif %} | ||||
|     </div> | ||||
| </section> | ||||
| {% endblock %} | ||||
|     <table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid"> | ||||
|         <thead> | ||||
|             <tr role="row"> | ||||
|                 <th role="columnheader" scope="col">{% trans 'Identifier' %}</th> | ||||
|                 <th role="columnheader" scope="col">{% trans 'Expires?' %}</th> | ||||
|                 <th role="columnheader" scope="col">{% trans 'Expiry Date' %}</th> | ||||
|                 <th role="columnheader" scope="col">{% trans 'Description' %}</th> | ||||
|                 <th role="cell"></th> | ||||
|             </tr> | ||||
|         </thead> | ||||
|         <tbody role="rowgroup"> | ||||
|             {% for token in object_list %} | ||||
|             <tr role="row"> | ||||
|                 <th role="columnheader"> | ||||
|                     <div>{{ token.identifier }}</div> | ||||
|                 </th> | ||||
|                 <td role="cell"> | ||||
|                     <span> | ||||
|                         {{ token.expiring|yesno:"Yes,No" }} | ||||
|                     </span> | ||||
|                 </td> | ||||
|                 <td role="cell"> | ||||
|                     <span> | ||||
|                         {% if not token.expiring %} | ||||
|                         - | ||||
|                         {% else %} | ||||
|                         {{ token.expires }} | ||||
|                         {% endif %} | ||||
|                     </span> | ||||
|                 </td> | ||||
|                 <td role="cell"> | ||||
|                     <span> | ||||
|                         {{ token.description }} | ||||
|                     </span> | ||||
|                 </td> | ||||
|                 <td> | ||||
|                     <a class="pf-c-button pf-m-secondary" href="{% url 'passbook_core:user-tokens-update' identifier=token.identifier %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a> | ||||
|                     <a class="pf-c-button pf-m-danger" href="{% url 'passbook_core:user-tokens-delete' identifier=token.identifier %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> | ||||
|                 </td> | ||||
|             </tr> | ||||
|             {% endfor %} | ||||
|         </tbody> | ||||
|     </table> | ||||
|     <div class="pf-c-pagination pf-m-bottom"> | ||||
|         {% include 'partials/pagination.html' %} | ||||
|     </div> | ||||
|     {% else %} | ||||
|     <div class="pf-c-empty-state"> | ||||
|         <div class="pf-c-empty-state__content"> | ||||
|             <i class="fas fa-cubes pf-c-empty-state__icon" aria-hidden="true"></i> | ||||
|             <h1 class="pf-c-title pf-m-lg"> | ||||
|                 {% trans 'No Tokens.' %} | ||||
|             </h1> | ||||
|             <div class="pf-c-empty-state__body"> | ||||
|                 {% trans 'Currently no tokens exist. Click the button below to create one.' %} | ||||
|             </div> | ||||
|             <a href="{% url 'passbook_core:user-tokens-create' %}?back={{ request.get_full_path }}" class="pf-c-button pf-m-primary" type="button">{% trans 'Create' %}</a> | ||||
|         </div> | ||||
|     </div> | ||||
|     {% endif %} | ||||
| </div> | ||||
|  | ||||
| @ -1,11 +1,10 @@ | ||||
| """passbook user settings template tags""" | ||||
| from typing import Iterable, List | ||||
| from typing import Iterable | ||||
|  | ||||
| from django import template | ||||
| from django.template.context import RequestContext | ||||
|  | ||||
| from passbook.core.models import Source | ||||
| from passbook.core.types import UIUserSettings | ||||
| from passbook.flows.models import Stage | ||||
| from passbook.policies.engine import PolicyEngine | ||||
|  | ||||
| @ -14,26 +13,26 @@ register = template.Library() | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| # pylint: disable=unused-argument | ||||
| def user_stages(context: RequestContext) -> List[UIUserSettings]: | ||||
| def user_stages(context: RequestContext) -> list[str]: | ||||
|     """Return list of all stages which apply to user""" | ||||
|     _all_stages: Iterable[Stage] = Stage.objects.all().select_subclasses() | ||||
|     matching_stages: List[UIUserSettings] = [] | ||||
|     matching_stages: list[str] = [] | ||||
|     for stage in _all_stages: | ||||
|         user_settings = stage.ui_user_settings | ||||
|         if not user_settings: | ||||
|             continue | ||||
|         matching_stages.append(user_settings) | ||||
|     return sorted(matching_stages, key=lambda x: x.name) | ||||
|     return matching_stages | ||||
|  | ||||
|  | ||||
| @register.simple_tag(takes_context=True) | ||||
| def user_sources(context: RequestContext) -> List[UIUserSettings]: | ||||
| def user_sources(context: RequestContext) -> list[str]: | ||||
|     """Return a list of all sources which are enabled for the user""" | ||||
|     user = context.get("request").user | ||||
|     _all_sources: Iterable[Source] = Source.objects.filter( | ||||
|         enabled=True | ||||
|     ).select_subclasses() | ||||
|     matching_sources: List[UIUserSettings] = [] | ||||
|     matching_sources: list[str] = [] | ||||
|     for source in _all_sources: | ||||
|         user_settings = source.ui_user_settings | ||||
|         if not user_settings: | ||||
| @ -42,4 +41,4 @@ def user_sources(context: RequestContext) -> List[UIUserSettings]: | ||||
|         policy_engine.build() | ||||
|         if policy_engine.passing: | ||||
|             matching_sources.append(user_settings) | ||||
|     return sorted(matching_sources, key=lambda x: x.name) | ||||
|     return matching_sources | ||||
|  | ||||
| @ -3,17 +3,9 @@ from dataclasses import dataclass | ||||
| from typing import Optional | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class UIUserSettings: | ||||
|     """Dataclass for Stage and Source's user_settings""" | ||||
|  | ||||
|     name: str | ||||
|     url: str | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class UILoginButton: | ||||
|     """Dataclass for Source's ui_ui_login_button""" | ||||
|     """Dataclass for Source's ui_login_button""" | ||||
|  | ||||
|     # Name, ran through i18n | ||||
|     name: str | ||||
|  | ||||
| @ -10,7 +10,6 @@ from model_utils.managers import InheritanceManager | ||||
| from rest_framework.serializers import BaseSerializer | ||||
| from structlog import get_logger | ||||
|  | ||||
| from passbook.core.types import UIUserSettings | ||||
| from passbook.lib.models import InheritanceForeignKey, SerializerModel | ||||
| from passbook.policies.models import PolicyBindingModel | ||||
|  | ||||
| @ -64,9 +63,9 @@ class Stage(SerializerModel): | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     @property | ||||
|     def ui_user_settings(self) -> Optional[UIUserSettings]: | ||||
|     def ui_user_settings(self) -> Optional[str]: | ||||
|         """Entrypoint to integrate with User settings. Can either return None if no | ||||
|         user settings are available, or an instanace of UIUserSettings.""" | ||||
|         user settings are available, or a string with the URL to fetch.""" | ||||
|         return None | ||||
|  | ||||
|     def __str__(self): | ||||
|  | ||||
| @ -7,7 +7,7 @@ from django.urls import reverse, reverse_lazy | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
|  | ||||
| from passbook.core.models import Source, UserSourceConnection | ||||
| from passbook.core.types import UILoginButton, UIUserSettings | ||||
| from passbook.core.types import UILoginButton | ||||
|  | ||||
|  | ||||
| class OAuthSource(Source): | ||||
| @ -66,12 +66,9 @@ class OAuthSource(Source): | ||||
|         return f"Callback URL: <pre>{url}</pre>" | ||||
|  | ||||
|     @property | ||||
|     def ui_user_settings(self) -> Optional[UIUserSettings]: | ||||
|     def ui_user_settings(self) -> Optional[str]: | ||||
|         view_name = "passbook_sources_oauth:oauth-client-user" | ||||
|         return UIUserSettings( | ||||
|             name=self.name, | ||||
|             url=reverse(view_name, kwargs={"source_slug": self.slug}), | ||||
|         ) | ||||
|         return reverse(view_name, kwargs={"source_slug": self.slug}) | ||||
|  | ||||
|     def __str__(self) -> str: | ||||
|         return f"OAuth Source {self.name}" | ||||
|  | ||||
| @ -1,9 +1,5 @@ | ||||
| {% extends "user/base.html" %} | ||||
|  | ||||
| {% load passbook_utils %} | ||||
| {% load i18n %} | ||||
|  | ||||
| {% block page %} | ||||
| <div class="pf-c-card"> | ||||
|     <div class="pf-c-card__header pf-c-title pf-m-md"> | ||||
|         {% blocktrans with source_name=source.name %} | ||||
| @ -26,4 +22,3 @@ | ||||
|         {% endif %} | ||||
|     </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|  | ||||
| @ -8,7 +8,6 @@ from django.utils.translation import gettext_lazy as _ | ||||
| from django.views import View | ||||
| from rest_framework.serializers import BaseSerializer | ||||
|  | ||||
| from passbook.core.types import UIUserSettings | ||||
| from passbook.flows.models import ConfigurableStage, Stage | ||||
|  | ||||
|  | ||||
| @ -36,14 +35,11 @@ class OTPStaticStage(ConfigurableStage, Stage): | ||||
|         return OTPStaticStageForm | ||||
|  | ||||
|     @property | ||||
|     def ui_user_settings(self) -> Optional[UIUserSettings]: | ||||
|         return UIUserSettings( | ||||
|             name="Static OTP", | ||||
|             url=reverse( | ||||
|     def ui_user_settings(self) -> Optional[str]: | ||||
|         return reverse( | ||||
|                 "passbook_stages_otp_static:user-settings", | ||||
|                 kwargs={"stage_uuid": self.stage_uuid}, | ||||
|             ), | ||||
|         ) | ||||
|             ) | ||||
|  | ||||
|     def __str__(self) -> str: | ||||
|         return f"OTP Static Stage {self.name}" | ||||
|  | ||||
| @ -1,9 +1,5 @@ | ||||
| {% extends "user/base.html" %} | ||||
|  | ||||
| {% load passbook_utils %} | ||||
| {% load i18n %} | ||||
|  | ||||
| {% block page %} | ||||
| <div class="pf-c-card"> | ||||
|     <div class="pf-c-card__header pf-c-title pf-m-md"> | ||||
|         {% trans "Static One-Time Passwords" %} | ||||
| @ -33,4 +29,3 @@ | ||||
|         {% endif %} | ||||
|     </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|  | ||||
| @ -8,7 +8,6 @@ from django.utils.translation import gettext_lazy as _ | ||||
| from django.views import View | ||||
| from rest_framework.serializers import BaseSerializer | ||||
|  | ||||
| from passbook.core.types import UIUserSettings | ||||
| from passbook.flows.models import ConfigurableStage, Stage | ||||
|  | ||||
|  | ||||
| @ -43,14 +42,11 @@ class OTPTimeStage(ConfigurableStage, Stage): | ||||
|         return OTPTimeStageForm | ||||
|  | ||||
|     @property | ||||
|     def ui_user_settings(self) -> Optional[UIUserSettings]: | ||||
|         return UIUserSettings( | ||||
|             name="Time-based OTP", | ||||
|             url=reverse( | ||||
|     def ui_user_settings(self) -> Optional[str]: | ||||
|         return reverse( | ||||
|                 "passbook_stages_otp_time:user-settings", | ||||
|                 kwargs={"stage_uuid": self.stage_uuid}, | ||||
|             ), | ||||
|         ) | ||||
|             ) | ||||
|  | ||||
|     def __str__(self) -> str: | ||||
|         return f"OTP Time (TOTP) Stage {self.name}" | ||||
|  | ||||
| @ -1,9 +1,5 @@ | ||||
| {% extends "user/base.html" %} | ||||
|  | ||||
| {% load passbook_utils %} | ||||
| {% load i18n %} | ||||
|  | ||||
| {% block page %} | ||||
| <div class="pf-c-card"> | ||||
|     <div class="pf-c-card__header pf-c-title pf-m-md"> | ||||
|         {% trans "Time-based One-Time Passwords" %} | ||||
| @ -30,4 +26,3 @@ | ||||
|         </p> | ||||
|     </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|  | ||||
| @ -8,3 +8,4 @@ class PassbookStagePasswordConfig(AppConfig): | ||||
|     name = "passbook.stages.password" | ||||
|     label = "passbook_stages_password" | ||||
|     verbose_name = "passbook Stages.Password" | ||||
|     mountpoint = "-/user/password/" | ||||
|  | ||||
| @ -4,15 +4,12 @@ from typing import Optional, Type | ||||
| from django.contrib.postgres.fields import ArrayField | ||||
| from django.db import models | ||||
| from django.forms import ModelForm | ||||
| from django.shortcuts import reverse | ||||
| from django.utils.http import urlencode | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from django.views import View | ||||
| from rest_framework.serializers import BaseSerializer | ||||
| from django.shortcuts import reverse | ||||
|  | ||||
| from passbook.core.types import UIUserSettings | ||||
| from passbook.flows.models import ConfigurableStage, Stage | ||||
| from passbook.flows.views import NEXT_ARG_NAME | ||||
|  | ||||
|  | ||||
| class PasswordStage(ConfigurableStage, Stage): | ||||
| @ -51,12 +48,10 @@ class PasswordStage(ConfigurableStage, Stage): | ||||
|         return PasswordStageForm | ||||
|  | ||||
|     @property | ||||
|     def ui_user_settings(self) -> Optional[UIUserSettings]: | ||||
|     def ui_user_settings(self) -> Optional[str]: | ||||
|         if not self.configure_flow: | ||||
|             return None | ||||
|         base_url = reverse("passbook_flows:configure", kwargs={"stage_uuid": self.pk}) | ||||
|         args = urlencode({NEXT_ARG_NAME: reverse("passbook_core:user-settings")}) | ||||
|         return UIUserSettings(name=_("Change password"), url=f"{base_url}?{args}") | ||||
|         return reverse("passbook_stages_password:user-settings", kwargs={"stage_uuid": self.pk}) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return f"Password Stage {self.name}" | ||||
|  | ||||
| @ -52,7 +52,7 @@ class PasswordStageView(FormView, StageView): | ||||
|     """Authentication stage which authenticates against django's AuthBackend""" | ||||
|  | ||||
|     form_class = PasswordForm | ||||
|     template_name = "stages/password/backend.html" | ||||
|     template_name = "stages/password/flow-form.html" | ||||
|  | ||||
|     def get_form(self, form_class=None) -> PasswordForm: | ||||
|         form = super().get_form(form_class=form_class) | ||||
|  | ||||
| @ -0,0 +1,17 @@ | ||||
| {% extends "base/page.html" %} | ||||
|  | ||||
| {% load i18n %} | ||||
| {% load passbook_utils %} | ||||
|  | ||||
| {% block body %} | ||||
| <div class="pf-c-card"> | ||||
|     <div class="pf-c-card__header pf-c-title pf-m-md"> | ||||
|         {% trans 'Reset your password' %} | ||||
|     </div> | ||||
|     <div class="pf-c-card__body"> | ||||
|         <a class="pf-c-button pf-m-primary" href="{{ url }}"> | ||||
|             {% trans 'Change password' %} | ||||
|         </a> | ||||
|     </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
							
								
								
									
										10
									
								
								passbook/stages/password/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								passbook/stages/password/urls.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| """Password stage urls""" | ||||
| from django.urls import path | ||||
|  | ||||
| from passbook.stages.password.views import UserSettingsCardView | ||||
|  | ||||
| urlpatterns = [ | ||||
|     path( | ||||
|         "<uuid:stage_uuid>/change-card/", UserSettingsCardView.as_view(), name="user-settings" | ||||
|     ), | ||||
| ] | ||||
							
								
								
									
										20
									
								
								passbook/stages/password/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								passbook/stages/password/views.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| from typing import Any | ||||
| from django.contrib.auth.mixins import LoginRequiredMixin | ||||
| from django.views.generic import TemplateView | ||||
|  | ||||
| from django.shortcuts import reverse | ||||
| from django.utils.http import urlencode | ||||
|  | ||||
| from passbook.flows.views import NEXT_ARG_NAME | ||||
|  | ||||
| class UserSettingsCardView(LoginRequiredMixin, TemplateView): | ||||
|  | ||||
|     template_name = "stages/password/user-settings-card.html" | ||||
|  | ||||
|     def get_context_data(self, **kwargs: Any) -> dict[str, Any]: | ||||
|         base_url = reverse("passbook_flows:configure", kwargs={"stage_uuid": self.kwargs["stage_uuid"]}) | ||||
|         args = urlencode({NEXT_ARG_NAME: reverse("passbook_core:user-settings")}) | ||||
|  | ||||
|         kwargs = super().get_context_data(**kwargs) | ||||
|         kwargs["url"] = f"{base_url}?{args}" | ||||
|         return kwargs | ||||
							
								
								
									
										2
									
								
								passbook/static/static/dist/main.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								passbook/static/static/dist/main.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer