From edbf07e6b818a00a86c96b89d55b5599ad62cf10 Mon Sep 17 00:00:00 2001 From: imperosol Date: Sun, 9 Nov 2025 18:25:51 +0100 Subject: [PATCH] rename `User.is_subscriber_viewable` => `User.is_viewable` --- com/views.py | 2 +- core/migrations/0048_alter_user_options.py | 33 ++++++++++++++++++ core/models.py | 23 ++++++++++--- core/static/user/user_edit.scss | 27 +++------------ core/templates/core/user_edit.jinja | 15 +++++--- core/tests/test_family.py | 2 +- core/views/forms.py | 6 ++-- .../templates/election/election_detail.jinja | 2 +- galaxy/models.py | 2 +- locale/fr/LC_MESSAGES/django.po | 34 ++++++++++++------- matmat/views.py | 4 +-- sas/models.py | 4 +-- sas/tests/test_api.py | 2 +- sas/tests/test_model.py | 2 +- 14 files changed, 101 insertions(+), 57 deletions(-) create mode 100644 core/migrations/0048_alter_user_options.py diff --git a/com/views.py b/com/views.py index eae9bf6a..72b4cc41 100644 --- a/com/views.py +++ b/com/views.py @@ -243,7 +243,7 @@ class NewsListView(TemplateView): User.objects.filter( date_of_birth__month=localdate().month, date_of_birth__day=localdate().day, - is_subscriber_viewable=True, + is_viewable=True, ) .filter(role__in=["STUDENT", "FORMER STUDENT"]) .order_by("-date_of_birth"), diff --git a/core/migrations/0048_alter_user_options.py b/core/migrations/0048_alter_user_options.py new file mode 100644 index 00000000..f446273a --- /dev/null +++ b/core/migrations/0048_alter_user_options.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.8 on 2025-11-09 15:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [("core", "0047_alter_notification_date_alter_notification_type")] + + operations = [ + migrations.AlterModelOptions( + name="user", + options={ + "permissions": [("view_hidden_user", "Can view hidden users")], + "verbose_name": "user", + "verbose_name_plural": "users", + }, + ), + migrations.RenameField( + model_name="user", old_name="is_subscriber_viewable", new_name="is_viewable" + ), + migrations.AlterField( + model_name="user", + name="is_viewable", + field=models.BooleanField( + default=True, + verbose_name="Profile visible by subscribers", + help_text=( + "If you disable this option, only admin users " + "will be able to see your profile." + ), + ), + ), + ] diff --git a/core/models.py b/core/models.py index bf54a33a..3c53419b 100644 --- a/core/models.py +++ b/core/models.py @@ -315,13 +315,24 @@ class User(AbstractUser): parent_address = models.CharField( _("parent address"), max_length=128, blank=True, default="" ) - is_subscriber_viewable = models.BooleanField( - _("is subscriber viewable"), default=True + is_viewable = models.BooleanField( + _("Profile visible by subscribers"), + help_text=_( + "If you disable this option, only admin users " + "will be able to see your profile." + ), + default=True, ) godfathers = models.ManyToManyField("User", related_name="godchildren", blank=True) objects = CustomUserManager() + class Meta(AbstractUser.Meta): + abstract = False + permissions = [ + ("view_hidden_user", "Can view hidden users"), + ] + def __str__(self): return self.get_display_name() @@ -604,8 +615,12 @@ class User(AbstractUser): def can_be_edited_by(self, user): return user.is_root or user.is_board_member - def can_be_viewed_by(self, user): - return (user.was_subscribed and self.is_subscriber_viewable) or user.is_root + def can_be_viewed_by(self, user: User) -> bool: + return ( + user.id == self.id + or user.has_perm("core.view_hidden_user") + or (user.has_perm("core.view_user") and self.is_viewable) + ) def get_mini_item(self): return """ diff --git a/core/static/user/user_edit.scss b/core/static/user/user_edit.scss index 888ae729..5b20fcee 100644 --- a/core/static/user/user_edit.scss +++ b/core/static/user/user_edit.scss @@ -7,10 +7,13 @@ .profile { &-visible { display: flex; - justify-content: center; + flex-direction: column; align-items: center; gap: 5px; padding-top: 10px; + input[type="checkbox"]+label { + max-width: unset; + } } &-pictures { @@ -116,23 +119,19 @@ display: flex; flex-direction: row; flex-wrap: wrap; - gap: 10px; + gap: var(--nf-input-size) 10px; justify-content: center; } &-field { display: flex; - flex-direction: row; - align-items: center; flex-wrap: wrap; justify-content: center; - gap: 10px; width: 100%; max-width: 330px; min-width: 300px; @media (max-width: 750px) { - gap: 4px; max-width: 100%; } @@ -145,22 +144,6 @@ } } - &-label { - text-align: left !important; - } - - &-content { - > * { - box-sizing: border-box; - text-align: left !important; - margin: 0; - - > * { - text-align: left !important; - } - } - } - textarea { height: 7rem; } diff --git a/core/templates/core/user_edit.jinja b/core/templates/core/user_edit.jinja index 8d015467..2f069da7 100644 --- a/core/templates/core/user_edit.jinja +++ b/core/templates/core/user_edit.jinja @@ -116,12 +116,12 @@ {# All fields #}
{%- for field in form -%} - {%- if field.name in ["quote","profile_pict","avatar_pict","scrub_pict","is_subscriber_viewable","forum_signature"] -%} + {%- if field.name in ["quote","profile_pict","avatar_pict","scrub_pict","is_viewable","forum_signature"] -%} {%- continue -%} {%- endif -%}
-
{{ field.label }}
+ {{ field.label_tag() }}
{{ field }} {%- if field.errors -%} @@ -136,7 +136,7 @@
{%- for field in [form.quote, form.forum_signature] -%}
-
{{ field.label }}
+ {{ field.label_tag() }}
{{ field }} {%- if field.errors -%} @@ -149,8 +149,13 @@ {# Checkboxes #}
- {{ form.is_subscriber_viewable }} - {{ form.is_subscriber_viewable.label }} +
+ {{ form.is_viewable }} + {{ form.is_viewable.label_tag() }} +
+ + {{ form.is_viewable.help_text }} +
diff --git a/core/tests/test_family.py b/core/tests/test_family.py index 795de590..f64e103f 100644 --- a/core/tests/test_family.py +++ b/core/tests/test_family.py @@ -55,7 +55,7 @@ class TestFetchFamilyApi(TestCase): assert response.status_code == 403 def test_fetch_family_hidden_user(self): - self.main_user.is_subscriber_viewable = False + self.main_user.is_viewable = False self.main_user.save() for user_to_login, error_code in [ (self.main_user, 200), diff --git a/core/views/forms.py b/core/views/forms.py index fdfe61cf..a7d0589c 100644 --- a/core/views/forms.py +++ b/core/views/forms.py @@ -202,7 +202,7 @@ class UserProfileForm(forms.ModelForm): "school", "promo", "forum_signature", - "is_subscriber_viewable", + "is_viewable", ] widgets = { "date_of_birth": SelectDate, @@ -211,8 +211,8 @@ class UserProfileForm(forms.ModelForm): "quote": forms.Textarea, } - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, *args, label_suffix: str = "", **kwargs): + super().__init__(*args, label_suffix=label_suffix, **kwargs) # Image fields are injected here to override the file field provided by the model # This would be better if we could have a SithImage sort of model input instead of a generic SithFile diff --git a/election/templates/election/election_detail.jinja b/election/templates/election/election_detail.jinja index b93ab9b7..b450e2c0 100644 --- a/election/templates/election/election_detail.jinja +++ b/election/templates/election/election_detail.jinja @@ -141,7 +141,7 @@