From 84dfbd5884bf56024566025c932b90522999d1d8 Mon Sep 17 00:00:00 2001 From: catborise Date: Wed, 4 Nov 2026 22:53:40 +0300 Subject: [PATCH] style(accounts): the password pages have the account forms' layout The page where a user changes their own password and the one where an administrator sets a user's password shared an old card: a horizontal form, a blue Cancel and a green Change. The administrator's had Django's "Password-based authentication: Enabled/Disabled" with a paragraph about other backends, and its password fields stayed while Disabled was chosen. Both pages now have the user and group forms' layout, each its own template. The administrator chooses how the user signs in, With a password or Without a password (such as LDAP), and the password fields and "must change it" show only with a password; Cancel goes back to the user. A user's own page says that their other sessions end, or, when they must change it, that they choose one before going on, without a Cancel. A refused password is said at its field only, without the general "Wrong Data Provided". The section styles of these forms move into webvirtcloud.css. --- .../accounts/change_password_form.html | 51 +++--- .../tests/test_change_password_permission.py | 13 ++ accounts/views.py | 2 +- admin/forms.py | 2 + admin/templates/admin/group_form.html | 23 +-- admin/templates/admin/user_form.html | 32 ++-- admin/templates/admin/user_password_form.html | 52 ++++++ admin/tests/test_user_pages.py | 11 ++ admin/views.py | 11 +- locale/tr/LC_MESSAGES/django.mo | Bin 190958 -> 191566 bytes locale/tr/LC_MESSAGES/django.po | 148 ++++++++++-------- locale/zh/LC_MESSAGES/django.mo | Bin 178557 -> 179127 bytes locale/zh/LC_MESSAGES/django.po | 148 ++++++++++-------- static/css/webvirtcloud.css | 23 +++ 14 files changed, 323 insertions(+), 193 deletions(-) create mode 100644 admin/templates/admin/user_password_form.html diff --git a/accounts/templates/accounts/change_password_form.html b/accounts/templates/accounts/change_password_form.html index 406fbab9..6d3f2dae 100644 --- a/accounts/templates/accounts/change_password_form.html +++ b/accounts/templates/accounts/change_password_form.html @@ -1,34 +1,39 @@ {% extends "base.html" %} - {% load django_bootstrap5 %} {% load i18n %} -{% load bootstrap_icons %} -{% block title %}{%trans "Change Password" %}{% endblock title %} +{% block title %}{% trans "Change Password" %}{% endblock title %} + +{% block page_heading %}{% trans "Change Password" %}{% endblock page_heading %} {% block content %} -
-
-
-
-

{%trans "Change Password" %}: {{ user }}

+{# a user changes their own password; one who must (a new or reset account) cannot go elsewhere first #} +
+ {% csrf_token %} + {% bootstrap_form_errors form type="non_fields" %} + +
+
+
+

{{ request.user.username }}

+

+ {% if must_change %}{% trans "Choose a new password before you go on." %}{% else %}{% trans "You stay signed in here; your other sessions end." %}{% endif %} +

-
- - {% csrf_token %} - {% bootstrap_form form layout='horizontal' horizontal_label_class='col-sm-4' horizontal_field_class='col-sm-8' horizontal_field_offset_class='offset-sm-4' %} - -
-
+ +
+ {% if not must_change %}{% trans "Cancel" %}{% endif %} +
-
-{% endblock content %} \ No newline at end of file + +{% endblock content %} diff --git a/accounts/tests/test_change_password_permission.py b/accounts/tests/test_change_password_permission.py index 01bb1d43..4c40279a 100644 --- a/accounts/tests/test_change_password_permission.py +++ b/accounts/tests/test_change_password_permission.py @@ -34,6 +34,19 @@ class ChangePasswordPermissionTestCase(TestCase): self.client.force_login(user) self.assertEqual(self.client.get(reverse("accounts:change_password")).status_code, 403) + def test_a_user_who_must_change_it_has_no_cancel(self): + from accounts.models import UserAttributes + + user = get_user_model().objects.create_user("forced", password="pw") + self.client.force_login(user) + page = self.client.get(reverse("accounts:change_password")) + self.assertContains(page, "your other sessions end") + self.assertContains(page, f'href="{reverse("accounts:profile")}">Cancel') + UserAttributes.objects.create(user=user, must_change_password=True) + page = self.client.get(reverse("accounts:change_password")) + self.assertContains(page, "Choose a new password before you go on.") + self.assertNotContains(page, f'href="{reverse("accounts:profile")}">Cancel') + def test_a_user_without_a_local_password_cannot_change_it(self): user = get_user_model().objects.create_user("ldap-user") # as django-auth-ldap makes them self.client.force_login(user) diff --git a/accounts/views.py b/accounts/views.py index d29571bb..52a29a02 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -212,7 +212,7 @@ def change_password(request): messages.success(request, _("Password Changed")) return redirect("accounts:profile") - return render(request, "accounts/change_password_form.html", {"form": form}) + return render(request, "accounts/change_password_form.html", {"form": form, "must_change": must_change}) @superuser_only diff --git a/admin/forms.py b/admin/forms.py index e5962a39..331a181d 100644 --- a/admin/forms.py +++ b/admin/forms.py @@ -232,6 +232,8 @@ class AdminPasswordForm(AdminPasswordChangeForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["must_change_password"] = self.fields.pop("must_change_password") # last, after Django's own + # Django's "Password-based authentication: Enabled/Disabled", said as how the user signs in + self.fields["usable_password"].choices = [("true", _("With a password")), ("false", _("Without a password"))] def clean(self): cleaned = super().clean() diff --git a/admin/templates/admin/group_form.html b/admin/templates/admin/group_form.html index cb322ed6..2880d660 100644 --- a/admin/templates/admin/group_form.html +++ b/admin/templates/admin/group_form.html @@ -7,39 +7,30 @@ {% block page_heading %}{{ title }}{% endblock page_heading %} -{% block style %} - -{% endblock style %} - {% block content %}
{% csrf_token %} {% bootstrap_form_errors form type="non_fields" %} -
+

{% trans "Group" %}

{% trans "Users who share a set of permissions." %}

-
+
{% bootstrap_field form.name %}
-
+

{% trans "Permissions" %}

{% trans "Each member has these permissions besides their own." %}

-
+
{% for box, help in form.permission_rows %}
@@ -57,13 +48,13 @@
-
+

{% trans "Members" %}

{% trans "Who gets these permissions." %}

-
+
{% trans "Members" %} {# the members first, then everyone else; each by username #} @@ -77,7 +68,7 @@
-
+
{% trans "Cancel" %}
diff --git a/admin/templates/admin/user_form.html b/admin/templates/admin/user_form.html index 392420b4..fa467720 100644 --- a/admin/templates/admin/user_form.html +++ b/admin/templates/admin/user_form.html @@ -7,23 +7,13 @@ {% block page_heading %}{{ title }}{% endblock page_heading %} -{% block style %} - -{% endblock style %} - {% block content %} {# who the user is, what they manage, what they may use, then what more they may do #} {% csrf_token %} {% bootstrap_form_errors user_form type="non_fields" %} -
+

{% trans "Account" %}

@@ -33,7 +23,7 @@

{% trans "What the user signs in with." %}

{% endif %}
-
+
{% bootstrap_field user_form.username %}
@@ -61,20 +51,20 @@
-
+

{% trans "Role" %}

{% trans "What the user manages." %}

-
+
{% trans "Uses the VMs given to them, within their quota." as user_help %} {% trans "May change and delete the template VMs given to them." as editor_help %} {% trans "Manages the panel: every permission, no quota." as superuser_help %}
{% for choice in user_form.role %}
-