From 0e8130f1b030f3d439a224b13e459b1ffbfb0b80 Mon Sep 17 00:00:00 2001 From: catborise Date: Sun, 25 Oct 2026 22:26:23 +0300 Subject: [PATCH] fix(admin): the Users pages keep an administrator in and say what their fields mean - An administrator could block, delete or demote (unset Active or Superuser on) their own account, and with it the last one, leaving the panel without anyone to undo it. These are now refused. - The user form showed "No password set." for users who have one: its password field never read the user's password. Its "Set password" link went to ../password/, a page this panel does not have. The form now says whether a password is set and links the page that sets it. - "Staff status" said "can log into this admin site"; here it lets a user change and delete the template VMs given to them, and is now called Template editor. - A quota of 0 counted as no limit, like -1, so a user's quota could not be taken away. Now -1 has no limit and 0 allows none; the help says so, and the labels give the units: memory in MiB, disk in GiB. - A user's page for a user that does not exist answered with a server error instead of not found. - The user list said "None" for a user who never logged in; it says "never", and dates fit their column. - The password form's labels no longer break mid-word. --- accounts/migrations/0011_quota_help.py | 34 ++++++++++ accounts/models.py | 12 ++-- .../accounts/change_password_form.html | 2 +- accounts/views.py | 2 +- admin/forms.py | 28 +------- admin/templates/admin/user_form.html | 9 +++ admin/templates/admin/user_list.html | 4 +- admin/tests/test_user_pages.py | 67 +++++++++++++++++++ admin/views.py | 18 ++++- instances/tests/test_quota.py | 15 ++++- instances/utils.py | 13 ++-- 11 files changed, 161 insertions(+), 43 deletions(-) create mode 100644 accounts/migrations/0011_quota_help.py create mode 100644 admin/tests/test_user_pages.py diff --git a/accounts/migrations/0011_quota_help.py b/accounts/migrations/0011_quota_help.py new file mode 100644 index 00000000..a389d250 --- /dev/null +++ b/accounts/migrations/0011_quota_help.py @@ -0,0 +1,34 @@ +# Generated by Django 5.2.18 on 2026-10-25 19:29 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0010_api_token_last_used'), + ] + + operations = [ + migrations.AlterField( + model_name='userattributes', + name='max_cpus', + field=models.IntegerField(default=2, help_text='-1: no limit; 0: none allowed', validators=[django.core.validators.MinValueValidator(-1)], verbose_name='max CPUs'), + ), + migrations.AlterField( + model_name='userattributes', + name='max_disk_size', + field=models.IntegerField(default=20, help_text='-1: no limit; 0: none allowed', validators=[django.core.validators.MinValueValidator(-1)], verbose_name='max disk size (GiB)'), + ), + migrations.AlterField( + model_name='userattributes', + name='max_instances', + field=models.IntegerField(default=2, help_text='-1: no limit; 0: none allowed', validators=[django.core.validators.MinValueValidator(-1)], verbose_name='max instances'), + ), + migrations.AlterField( + model_name='userattributes', + name='max_memory', + field=models.IntegerField(default=2048, help_text='-1: no limit; 0: none allowed', validators=[django.core.validators.MinValueValidator(-1)], verbose_name='max memory (MiB)'), + ), + ] diff --git a/accounts/models.py b/accounts/models.py index dcdcaaf8..61f7187a 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -46,25 +46,25 @@ class UserAttributes(models.Model): max_instances = models.IntegerField( _("max instances"), default=2, - help_text=_("-1 for unlimited. Any integer value"), + help_text=_("-1: no limit; 0: none allowed"), validators=[MinValueValidator(-1)], ) max_cpus = models.IntegerField( _("max CPUs"), default=2, - help_text=_("-1 for unlimited. Any integer value"), + help_text=_("-1: no limit; 0: none allowed"), validators=[MinValueValidator(-1)], ) max_memory = models.IntegerField( - _("max memory"), + _("max memory (MiB)"), default=2048, - help_text=_("-1 for unlimited. Any integer value"), + help_text=_("-1: no limit; 0: none allowed"), validators=[MinValueValidator(-1)], ) max_disk_size = models.IntegerField( - _("max disk size"), + _("max disk size (GiB)"), default=20, - help_text=_("-1 for unlimited. Any integer value"), + help_text=_("-1: no limit; 0: none allowed"), validators=[MinValueValidator(-1)], ) diff --git a/accounts/templates/accounts/change_password_form.html b/accounts/templates/accounts/change_password_form.html index 35dab319..046447e8 100644 --- a/accounts/templates/accounts/change_password_form.html +++ b/accounts/templates/accounts/change_password_form.html @@ -16,7 +16,7 @@
{% csrf_token %} - {% bootstrap_form form layout='horizontal' %} + {% bootstrap_form form layout='horizontal' horizontal_label_class='col-sm-4' horizontal_field_class='col-sm-8' horizontal_field_offset_class='offset-sm-4' %}