From 8b6cddc37c6000bf3333da44676e98a00feae086 Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Thu, 5 Feb 2026 22:38:58 +0100 Subject: [PATCH 1/4] Add properties, method and template tag for showing the right name - Rename properties and change logic for showing names - Add tests for new logic in showing private/public names - Add `get_display_name` method with tests - Add a custom template tag `display_name` - Change all `get_public_credit_name` and `get_name` property calls --- .../includes/posreport_list_table.html | 8 +- .../templates/posreport_detail.html | 8 +- .../includes/expense_detail_panel.html | 4 +- .../includes/expense_list_panel.html | 4 +- .../includes/reimbursement_detail_panel.html | 3 +- .../includes/reimbursement_list_panel.html | 6 +- .../includes/revenue_detail_panel.html | 4 +- .../includes/revenue_list_panel.html | 4 +- src/maps/views.py | 2 +- src/profiles/models.py | 58 +++-- src/profiles/templatetags/__init__.py | 0 src/profiles/templatetags/profile_display.py | 19 ++ src/profiles/tests.py | 201 ++++++++++++++++++ src/profiles/views.py | 2 +- src/rideshare/views.py | 2 +- src/teams/templates/task_detail.html | 3 +- src/teams/templates/team_list.html | 3 +- src/teams/templates/team_members.html | 3 +- src/teams/templates/team_shift_list.html | 3 +- src/teams/templates/teammember_make_lead.html | 5 +- src/teams/templates/teammember_take_lead.html | 5 +- src/tokens/views.py | 2 +- 22 files changed, 307 insertions(+), 42 deletions(-) create mode 100644 src/profiles/templatetags/__init__.py create mode 100644 src/profiles/templatetags/profile_display.py create mode 100644 src/profiles/tests.py diff --git a/src/backoffice/templates/includes/posreport_list_table.html b/src/backoffice/templates/includes/posreport_list_table.html index 9a860a2cf..ad63323d6 100644 --- a/src/backoffice/templates/includes/posreport_list_table.html +++ b/src/backoffice/templates/includes/posreport_list_table.html @@ -19,10 +19,10 @@ {{ pr.period.lower }} - {{ pr.period.upper }} - Bank Start: {{ pr.bank_responsible_start.profile.get_name|default:"N/A" }}
- Bank End: {{ pr.bank_responsible_end.profile.get_name|default:"N/A" }}
- Pos Start: {{ pr.pos_responsible_start.profile.get_name|default:"N/A" }}
- Pos End: {{ pr.pos_responsible_end.profile.get_name|default:"N/A" }} + Bank Start: {{ pr.bank_responsible_start.profile.private_name|default:"N/A" }}
+ Bank End: {{ pr.bank_responsible_end.profile.private_name|default:"N/A" }}
+ Pos Start: {{ pr.pos_responsible_start.profile.private_name|default:"N/A" }}
+ Pos End: {{ pr.pos_responsible_end.profile.private_name|default:"N/A" }} {{ pr.dkk_sales_izettle }} DKK diff --git a/src/backoffice/templates/posreport_detail.html b/src/backoffice/templates/posreport_detail.html index 988ba685a..3bb36e7d1 100644 --- a/src/backoffice/templates/posreport_detail.html +++ b/src/backoffice/templates/posreport_detail.html @@ -41,19 +41,19 @@

PosReport {{ posreport.date }} {{ posreport.pos.name }} | Bank Responsible Start - {{ posreport.bank_responsible_start.profile.get_name|default:"N/A" }}

+ {{ posreport.bank_responsible_start.profile.private_name|default:"N/A" }}

Bank Responsible End - {{ posreport.bank_responsible_end.profile.get_name|default:"N/A" }}

+ {{ posreport.bank_responsible_end.profile.private_name|default:"N/A" }}

Pos Responsible Start - {{ posreport.pos_responsible_start.profile.get_name|default:"N/A" }}

+ {{ posreport.pos_responsible_start.profile.private_name|default:"N/A" }}

Pos Responsible End - {{ posreport.pos_responsible_end.profile.get_name|default:"N/A" }}

+ {{ posreport.pos_responsible_end.profile.private_name|default:"N/A" }}

All OK? diff --git a/src/economy/templates/includes/expense_detail_panel.html b/src/economy/templates/includes/expense_detail_panel.html index 491c2c460..1ea7dfff2 100644 --- a/src/economy/templates/includes/expense_detail_panel.html +++ b/src/economy/templates/includes/expense_detail_panel.html @@ -1,3 +1,5 @@ +{% load profile_display %} +
Expense Details for {{ expense.pk }}
@@ -5,7 +7,7 @@ {% if request.resolver_match.app_name == "backoffice" %} Created By - {{ expense.user.profile.get_name }} + {% display_name expense.user.profile %} {% endif %} diff --git a/src/economy/templates/includes/expense_list_panel.html b/src/economy/templates/includes/expense_list_panel.html index a949b4350..4343d6336 100644 --- a/src/economy/templates/includes/expense_list_panel.html +++ b/src/economy/templates/includes/expense_list_panel.html @@ -1,4 +1,6 @@ {% load bornhack %} +{% load profile_display %} + {% if expense_list %} @@ -31,7 +33,7 @@ {% endif %} - + diff --git a/src/economy/templates/includes/reimbursement_detail_panel.html b/src/economy/templates/includes/reimbursement_detail_panel.html index 7b871e96a..98732baca 100644 --- a/src/economy/templates/includes/reimbursement_detail_panel.html +++ b/src/economy/templates/includes/reimbursement_detail_panel.html @@ -1,4 +1,5 @@ {% load bornhack %} +{% load profile_display %}
Reimbursement {{ reimbursement.pk }} Details
@@ -9,7 +10,7 @@
- + diff --git a/src/economy/templates/includes/reimbursement_list_panel.html b/src/economy/templates/includes/reimbursement_list_panel.html index 4b88c228e..1d56925c3 100644 --- a/src/economy/templates/includes/reimbursement_list_panel.html +++ b/src/economy/templates/includes/reimbursement_list_panel.html @@ -1,4 +1,6 @@ {% load bornhack %} +{% load profile_display %} + {% if reimbursement_list %}
{{ expense.invoice_date }}{{ expense.user.profile.get_name }}{% display_name expense.user.profile %} {{ expense.get_payment_status_display }} {{ expense.creditor.name }} {{ expense.amount }} DKK
Reimbursement User{{ reimbursement.reimbursement_user.profile.get_name }}{% display_name reimbursement.reimbursement_user.profile %}
Total Amount
@@ -25,8 +27,8 @@ {% else %} {% endif %} - - + + diff --git a/src/economy/templates/includes/revenue_detail_panel.html b/src/economy/templates/includes/revenue_detail_panel.html index aa3cbab20..fe6c080cf 100644 --- a/src/economy/templates/includes/revenue_detail_panel.html +++ b/src/economy/templates/includes/revenue_detail_panel.html @@ -1,3 +1,5 @@ +{% load profile_display %} +
Revenue Details for {{ revenue.pk }}
@@ -5,7 +7,7 @@ {% if request.resolver_match.app_name == "backoffice" %}
- + {% endif %} diff --git a/src/economy/templates/includes/revenue_list_panel.html b/src/economy/templates/includes/revenue_list_panel.html index 0600aed23..2bde8b19a 100644 --- a/src/economy/templates/includes/revenue_list_panel.html +++ b/src/economy/templates/includes/revenue_list_panel.html @@ -1,4 +1,6 @@ {% load bornhack %} +{% load profile_display %} + {% if revenue_list %}
{{ reim.camp }}{{ reim.user.profile.get_name }}{{ reim.reimbursement_user.profile.get_name }}{% display_name reim.user.profile %}{% display_name reim.reimbursement_user.profile %} {{ reim.bank_account|default:"N/A" }} {{ reim.notes|default:"N/A" }} {{ reim.amount }} DKK
Created By{{ revenue.user.profile.get_name }}{% display_name revenue.user.profile %}
@@ -31,7 +33,7 @@ {% endif %} - + diff --git a/src/maps/views.py b/src/maps/views.py index 0960e7817..0c1ca078f 100644 --- a/src/maps/views.py +++ b/src/maps/views.py @@ -403,7 +403,7 @@ def dump_locations(self) -> list[object]: "type": location.type.name, "icon": location.type.icon, "marker": location.type.marker, - "user": location.user.profile.get_public_credit_name, + "user": location.user.profile.public_name, "data": location.data, }, } diff --git a/src/profiles/models.py b/src/profiles/models.py index 9ab0c5bb3..a79772da9 100644 --- a/src/profiles/models.py +++ b/src/profiles/models.py @@ -7,6 +7,8 @@ from django.utils.translation import gettext_lazy as _ from django_prometheus.models import ExportModelOperationsMixin +from camps.models import Camp +from teams.models import TeamMember from utils.models import CreatedUpdatedModel from utils.models import UUIDModel @@ -34,7 +36,7 @@ class Meta: max_length=200, default="", blank=True, - help_text="Your name or handle (only visible to team leads and orga)", + help_text="Your name or handle (visible to all team members aka. volunteers)", ) description = models.TextField( @@ -46,7 +48,7 @@ class Meta: public_credit_name = models.CharField( blank=True, max_length=100, - help_text="The name you want to appear on in the credits section of the public website (on Team and People pages). Leave this empty if you want your name hidden on the public webpages.", + help_text="The name you want to appear in the credits section of the public website (on Team and People pages). Leave this empty if you want your name hidden on the public webpages.", ) public_credit_name_approved = models.BooleanField( @@ -75,10 +77,6 @@ class Meta: help_text="When using your BornHack account to login to other sites with OIDC this value is served as the OIDC standard claim 'preferred_username'. You can set this to the username you would prefer to use on remote sites where you login with your BornHack account.", ) - @property - def email(self): - return self.user.email - def __str__(self) -> str: return self.user.username @@ -90,17 +88,47 @@ def approve_public_credit_name(self) -> None: self.save() @property - def get_public_credit_name(self): - """Convenience method to return profile.public_credit_name if it is approved, - and the string "Unnamed" otherwise. + def email(self): + return self.user.email + + def get_display_name(self, user: User, camp: Camp) -> str: """ - if self.public_credit_name_approved: - return self.public_credit_name - return "Unnamed" + Return the profile's public or private name depending on + requesting user's team membership. + + `private_name` is returned for all volunteers, defined as someone who is + a team member in the relevant camp. + + `public_name` is unrestricted and returned in all other cases. + """ + if TeamMember.objects.filter(user=user, team__camp=camp).exists(): + return self.private_name + + return self.public_name + + @property + def public_name(self) -> str: + """Return `public_credit_name` if it is approved or else `Unnamed`. + + Unrestricted usage. + """ + return ( + self.public_credit_name + if self.public_credit_name_approved + else "Unnamed" + ) @property - def get_name(self): - """Convenience method to return profile.name if set, otherwise username.""" + def private_name(self) -> str: + """Return `name` if set or else `public_credit_name` if approved, + with fallback to username. + + Restricted usage: Should only be visible to team members for related camp. + """ if self.name: return self.name - return self.user.username + elif self.public_credit_name_approved: + return self.public_credit_name + else: + return self.user.username + diff --git a/src/profiles/templatetags/__init__.py b/src/profiles/templatetags/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/profiles/templatetags/profile_display.py b/src/profiles/templatetags/profile_display.py new file mode 100644 index 000000000..3eefadc94 --- /dev/null +++ b/src/profiles/templatetags/profile_display.py @@ -0,0 +1,19 @@ +from django import template + +from profiles.models import Profile + +register = template.Library() + +@register.simple_tag(takes_context=True) +def display_name(context, profile: Profile): + """ + Return the profile display name depending on the users permissions. + """ + try: + user = context["request"].user + camp = context["camp"] + except KeyError: + return profile.public_name + + return profile.get_display_name(user, camp) + diff --git a/src/profiles/tests.py b/src/profiles/tests.py new file mode 100644 index 000000000..b086ff09a --- /dev/null +++ b/src/profiles/tests.py @@ -0,0 +1,201 @@ +from collections import namedtuple +from django.template import Context +from django.template import Template + +from teams.models import TeamMember +from utils.tests import BornhackTestBase + + +class TestTemplateTags(BornhackTestBase): + """Class for grouping `templatetags` tests.""" + + @classmethod + def setUpTestData(cls) -> None: + """Test setup.""" + super().setUpTestData() + cls.profile = cls.users[9].profile + cls.profile.public_credit_name_approved = False + + cls.public_fallback = "Unnamed" + cls.user = cls.users[8] + cls.FakeRequest = namedtuple("FakeRequest", ["user"]) + cls.fake_request = cls.FakeRequest(user=cls.user) + + def test_display_name_for_anon_user(self) -> None: + """Test `display_name` for an anonymous user.""" + context = {"user": self.profile} + # Profile without approved `public_credit_name` + result = Template( + "{% load profile_display %}" + "{% display_name user %}" + ).render(Context(context)) + + assert result == self.public_fallback + + # Profile with approved `public_credit_name` + self.profile.public_credit_name_approved = True + result = Template( + "{% load profile_display %}" + "{% display_name user %}" + ).render(Context(context)) + + assert result == self.profile.public_credit_name + + def test_display_name_for_volunteer(self) -> None: + """Test `display_name` for a volunteer (team member).""" + context = { + "user": self.profile, + "request": self.fake_request, + "camp": self.camp, + } + # Profile with `name` + result = Template( + "{% load profile_display %}" + "{% display_name user %}" + ).render(Context(context)) + + assert result == self.profile.name + + # Profile with approved `public_credit_name` + self.profile.name = None + self.profile.public_credit_name_approved = True + result = Template( + "{% load profile_display %}" + "{% display_name user %}" + ).render(Context(context)) + + assert result == self.profile.public_credit_name + + # Profile without name and approved `public_credit_name` + self.profile.name = None + self.profile.public_credit_name_approved = False + result = Template( + "{% load profile_display %}" + "{% display_name user %}" + ).render(Context(context)) + + assert result == self.profile.user.username + + def test_display_name_handling_team_member_by_camp(self) -> None: + """Test `display_name` handles a user being volunteer at another camp.""" + context = { + "user": self.profile, + "request": self.fake_request, + "camp": self.camp, + } + # Team member of related camp + result = Template( + "{% load profile_display %}" + "{% display_name user %}" + ).render(Context(context)) + + assert result == self.profile.private_name + + # Team member of previous camp + TeamMember.objects.filter(user=self.user, team__camp=self.camp).delete() + result = Template( + "{% load profile_display %}" + "{% display_name user %}" + ).render(Context(context)) + + assert result == self.profile.public_name + + # Not a Team member of any camps + fake_request = self.FakeRequest(user=self.users[13]) + context.update({"request": fake_request}) + result = Template( + "{% load profile_display %}" + "{% display_name user %}" + ).render(Context(context)) + + assert result == self.profile.public_name + + +class TestProfileModel(BornhackTestBase): + """Class for grouping `ProfileModel` tests.""" + + @classmethod + def setUpTestData(cls) -> None: + """Test setup.""" + super().setUpTestData() + cls.profile = cls.users[10].profile + cls.profile.public_credit_name_approved = False + + def test_approving_public_credit_name(self) -> None: + """Test `approve_public_credit_name` changes object state.""" + assert self.profile.public_credit_name_approved is False + + self.profile.approve_public_credit_name() + + assert self.profile.public_credit_name_approved is True + + def test_return_approved_public_credit_name(self) -> None: + """ + Test `public_name` property returns the approved `public_credit_name`. + """ + self.profile.public_credit_name_approved = True + + assert self.profile.public_name == self.profile.public_credit_name + + def test_public_name_not_approved_return_unnamed(self) -> None: + """ + Test `public_name` property returns `Unnamed` + when `public_credit_name` isn't approved. + """ + assert self.profile.public_name == "Unnamed" + + def test_private_name_returns_display_name(self) -> None: + """Test `private_name` property returns `name` when set.""" + expected = "Test" + self.profile.name = expected + + assert self.profile.private_name == expected + + self.profile.public_credit_name_approved = True + + assert self.profile.private_name == expected + + def test_private_name_return_public_credit_name(self) -> None: + """ + Test `private_name` property returns the approved public_credit_name, + when no `name` is set. + """ + self.profile.name = None + self.profile.public_credit_name_approved = True + + assert self.profile.private_name == self.profile.public_credit_name + + def test_private_name_return_username_as_fallback(self) -> None: + """ + Test `private_name` property return the username as a fallback, + when no profile name or public_credit_name is added. + """ + self.profile.name = None + self.profile.public_credit_name = None + + assert self.profile.private_name == self.profile.user.username + + def test_get_display_name_handling_team_member_by_related_camp(self) -> None: + """Test `get_display_name` handles a user being volunteer at related camp.""" + user = self.users[8] + + result = self.profile.get_display_name(user, self.camp) + + assert result == self.profile.private_name + + def test_get_display_name_handling_team_member_by_previous_camp(self) -> None: + """Test `get_display_name` handles a user being volunteer at previous camp.""" + user = self.users[8] + TeamMember.objects.filter(user=user, team__camp=self.camp).delete() + + result = self.profile.get_display_name(user, self.camp) + + assert result == self.profile.public_name + + def test_get_display_name_handling_not_a_team_member_in_any_camp(self) -> None: + """Test `get_display_name` handles a user not being a team member in any camps.""" + user = self.users[13] + + result = self.profile.get_display_name(user, self.camp) + + assert result == self.profile.public_name diff --git a/src/profiles/views.py b/src/profiles/views.py index dd5a11783..c61951bb8 100644 --- a/src/profiles/views.py +++ b/src/profiles/views.py @@ -92,7 +92,7 @@ def get_context_data(self, **kwargs) -> dict: "user_id": self.request.user.id, } context["profile"] = { - "public_credit_name": self.request.user.profile.get_public_credit_name, + "public_credit_name": self.request.user.profile.public_name, "description": self.request.user.profile.description, } context["teams"] = [{"team": team.name, "camp": team.camp.title} for team in self.request.user.teams.all()] diff --git a/src/rideshare/views.py b/src/rideshare/views.py index 463f756a9..2e577f33c 100644 --- a/src/rideshare/views.py +++ b/src/rideshare/views.py @@ -79,7 +79,7 @@ class RideCreate(LoginRequiredMixin, CampViewMixin, CreateView): def get_initial(self): """Default 'author' to users public_credit_name where relevant.""" - return {"author": self.request.user.profile.get_public_credit_name} + return {"author": self.request.user.profile.public_name} def form_valid(self, form, **kwargs): """Set camp and user before saving.""" diff --git a/src/teams/templates/task_detail.html b/src/teams/templates/task_detail.html index bd716c14b..bdc5ce3c4 100644 --- a/src/teams/templates/task_detail.html +++ b/src/teams/templates/task_detail.html @@ -1,6 +1,7 @@ {% extends 'team_base.html' %} {% load commonmark %} {% load django_bootstrap5 %} +{% load profile_display %} {% block title %} {{ task.name }} @@ -25,7 +26,7 @@

Comments

    {% for comment in task.comments.all %}
  • - {{ comment.author.user.profile.get_public_credit_name }}: {{ comment.comment }} + {% display_name comment.author.user.profile %}: {{ comment.comment }}
  • {% empty %}
  • diff --git a/src/teams/templates/team_list.html b/src/teams/templates/team_list.html index d16e8f8d8..e1397bf80 100644 --- a/src/teams/templates/team_list.html +++ b/src/teams/templates/team_list.html @@ -1,6 +1,7 @@ {% extends 'base.html' %} {% load commonmark %} {% load teams_tags %} +{% load profile_display %} {% block title %} Teams | {{ block.super }} @@ -77,7 +78,7 @@

    Your teams

diff --git a/src/teams/templates/team_members.html b/src/teams/templates/team_members.html index c18e00338..8c7cb25fe 100644 --- a/src/teams/templates/team_members.html +++ b/src/teams/templates/team_members.html @@ -2,6 +2,7 @@ {% load commonmark %} {% load django_bootstrap5 %} {% load teams_tags %} +{% load profile_display %} {% block title %} Members | {{ block.super }} @@ -45,7 +46,7 @@

Members

{% if member.approved or not member.approved and team.lead_permission_set in perms %} + Not visible to the public but visible to volunteers. (defined as a person being a team member at any camp) From e3ed709101bed3dc1921a02856efe7cb5427e49e Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Fri, 6 Feb 2026 22:02:44 +0100 Subject: [PATCH 3/4] Add logic and test for handling anonymous users --- src/profiles/models.py | 3 +++ src/profiles/tests.py | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/profiles/models.py b/src/profiles/models.py index 87a475803..a2debc3fc 100644 --- a/src/profiles/models.py +++ b/src/profiles/models.py @@ -101,6 +101,9 @@ def get_display_name(self, user: User, camp: Camp) -> str: `public_name` is unrestricted and returned in all other cases. """ + if not user.is_authenticated: + return self.public_name + if TeamMember.objects.filter(user=user, team__camp=camp).exists(): return self.private_name diff --git a/src/profiles/tests.py b/src/profiles/tests.py index b086ff09a..53a27025b 100644 --- a/src/profiles/tests.py +++ b/src/profiles/tests.py @@ -1,4 +1,5 @@ from collections import namedtuple +from django.contrib.auth.models import AnonymousUser from django.template import Context from django.template import Template @@ -199,3 +200,13 @@ def test_get_display_name_handling_not_a_team_member_in_any_camp(self) -> None: result = self.profile.get_display_name(user, self.camp) assert result == self.profile.public_name + + def test_get_display_name_with_unauthenticated_user(self) -> None: + """ + Test `get_display_name` return public name when user is unauthenticated. + """ + user = AnonymousUser() + + result = self.profile.get_display_name(user, self.camp) + + assert result == self.profile.public_name From ca15494e8b16d75cd456a3f63bd2caad8e094cb7 Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Fri, 6 Feb 2026 22:47:59 +0100 Subject: [PATCH 4/4] Refactor most calls for a profile/user name --- .../approve_public_credit_names.html | 8 +++----- .../facilityfeedback_backoffice.html | 20 ++++++++++--------- src/backoffice/templates/feedback_detail.html | 3 ++- src/backoffice/templates/feedback_list.html | 8 ++++---- .../feedback_list_processed_confirm.html | 3 ++- .../includes/invoice_list_panel.html | 4 +++- .../templates/includes/refund_list_panel.html | 4 +++- .../templates/permissions_by_permission.html | 12 +++++++---- .../templates/permissions_by_user.html | 10 ++++------ .../templates/shop_ticket_overview.html | 3 ++- .../templates/team_permissions_manage.html | 8 +++----- src/backoffice/templates/token_detail.html | 7 +++---- src/backoffice/templates/token_stats.html | 7 +++---- src/people/templates/people.html | 7 +++---- src/program/mixins.py | 13 ++++++------ .../includes/event_feedback_detail_panel.html | 6 ++++-- src/teams/admin.py | 2 +- src/teams/templates/team_members.html | 13 +++++------- src/teams/templates/teammember_approve.html | 9 +++++---- src/teams/templates/teammember_remove.html | 9 +++++---- 20 files changed, 80 insertions(+), 76 deletions(-) diff --git a/src/backoffice/templates/approve_public_credit_names.html b/src/backoffice/templates/approve_public_credit_names.html index 2bebe16db..307ea997b 100644 --- a/src/backoffice/templates/approve_public_credit_names.html +++ b/src/backoffice/templates/approve_public_credit_names.html @@ -19,17 +19,15 @@

Approve Public Credit Names

{{ revenue.invoice_date }}{{ revenue.user.profile.get_name }}{% display_name revenue.user.profile %} {{ revenue.get_payment_status_display }} {{ revenue.debtor }} {{ revenue.amount }} DKK {% for resp in team.leads.all %} - {{ resp.profile.get_public_credit_name }}{% if not forloop.last %},{% endif %}
+ {% display_name resp.profile %}{% if not forloop.last %},{% endif %}
{% endfor %}
- {{ member.user.profile.get_public_credit_name }} {% if member.user == request.user %}(this is you!){% endif %} + {% display_name member.user.profile %} {% if member.user == request.user %}(this is you!){% endif %} Team {% if member.lead %}Lead{% else %}Member{% endif %} diff --git a/src/teams/templates/team_shift_list.html b/src/teams/templates/team_shift_list.html index a2a2cb789..bafe51ff8 100644 --- a/src/teams/templates/team_shift_list.html +++ b/src/teams/templates/team_shift_list.html @@ -1,6 +1,7 @@ {% extends 'team_base.html' %} {% load commonmark %} {% load django_bootstrap5 %} +{% load profile_display %} {% block title %} Shifts | {{ block.super }} @@ -59,7 +60,7 @@

{% for member in shift.team_members.all %} - {{ member.user.profile.get_public_credit_name }}{% if not forloop.last %},{% endif %} + {% display_name member.user.profile %}{% if not forloop.last %},{% endif %} {% empty %} None! {% endfor %} diff --git a/src/teams/templates/teammember_make_lead.html b/src/teams/templates/teammember_make_lead.html index c34b1a1b6..2c117f3d7 100644 --- a/src/teams/templates/teammember_make_lead.html +++ b/src/teams/templates/teammember_make_lead.html @@ -1,14 +1,15 @@ {% extends 'team_base.html' %} {% load commonmark %} +{% load profile_display %} {% block title %} - Make team member {{ teammember.user.profile.get_name }} team lead for the {{ teammember.team.name }} team + Make team member {% display_name teammember.user.profile %} team lead for the {{ teammember.team.name }} team {% endblock %} {% block team_content %}

Make team lead

-

Really make the user {{ teammember.user.profile.get_name }} team lead for the {{ teammember.team.name }} team?

+

Really make the user {% display_name teammember.user.profile %} team lead for the {{ teammember.team.name }} team?

{% csrf_token %} {{ form }} diff --git a/src/teams/templates/teammember_take_lead.html b/src/teams/templates/teammember_take_lead.html index ace2e95f5..a39414427 100644 --- a/src/teams/templates/teammember_take_lead.html +++ b/src/teams/templates/teammember_take_lead.html @@ -1,13 +1,14 @@ {% extends 'team_base.html' %} {% load commonmark %} +{% load profile_display %} {% block title %} - Make team lead {{ teammember.user.profile.get_name }} a normal member of the {{ teammember.team.name }} team + Make team lead {% display_name teammember.user.profile %} a normal member of the {{ teammember.team.name }} team {% endblock %} {% block team_content %}

Remove team lead

-

Really make the team lead {{ teammember.user.profile.get_name }} a normal member of the {{ teammember.team.name }} team?

+

Really make the team lead {% display_name teammember.user.profile %} a normal member of the {{ teammember.team.name }} team?

{% csrf_token %} {{ form }} diff --git a/src/tokens/views.py b/src/tokens/views.py index 9888a92be..363163968 100644 --- a/src/tokens/views.py +++ b/src/tokens/views.py @@ -282,7 +282,7 @@ def form_valid(self, form): if created: # user found a new token - username = self.request.user.profile.get_public_credit_name + username = self.request.user.profile.public_name if username == "Unnamed": username = "anonymous_player_{request.user.id}" From 4d9a881f38c15545970d0869d8c1533de59bb230 Mon Sep 17 00:00:00 2001 From: Christian Henriksen Date: Fri, 6 Feb 2026 20:32:53 +0100 Subject: [PATCH 2/4] Change text for @tykling feedback --- ...e_name_alter_profile_public_credit_name.py | 32 +++++++++++++++++++ src/profiles/models.py | 2 +- src/profiles/templates/profile_detail.html | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/profiles/migrations/0020_alter_profile_name_alter_profile_public_credit_name.py diff --git a/src/profiles/migrations/0020_alter_profile_name_alter_profile_public_credit_name.py b/src/profiles/migrations/0020_alter_profile_name_alter_profile_public_credit_name.py new file mode 100644 index 000000000..01214748b --- /dev/null +++ b/src/profiles/migrations/0020_alter_profile_name_alter_profile_public_credit_name.py @@ -0,0 +1,32 @@ +# Generated by Django 5.2.9 on 2026-02-06 19:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("profiles", "0019_remove_profile_location"), + ] + + operations = [ + migrations.AlterField( + model_name="profile", + name="name", + field=models.CharField( + blank=True, + default="", + help_text="What can we call you? (visible to any team member aka. volunteer, but not the public)", + max_length=200, + ), + ), + migrations.AlterField( + model_name="profile", + name="public_credit_name", + field=models.CharField( + blank=True, + help_text="The name you want to appear in the credits section of the public website (on Team and People pages). Leave this empty if you want your name hidden on the public webpages.", + max_length=100, + ), + ), + ] diff --git a/src/profiles/models.py b/src/profiles/models.py index a79772da9..87a475803 100644 --- a/src/profiles/models.py +++ b/src/profiles/models.py @@ -36,7 +36,7 @@ class Meta: max_length=200, default="", blank=True, - help_text="Your name or handle (visible to all team members aka. volunteers)", + help_text="What can we call you? (visible to any team member aka. volunteer, but not the public)", ) description = models.TextField( diff --git a/src/profiles/templates/profile_detail.html b/src/profiles/templates/profile_detail.html index 0de92e80f..1c27d0df9 100644 --- a/src/profiles/templates/profile_detail.html +++ b/src/profiles/templates/profile_detail.html @@ -28,7 +28,7 @@

Your information

Name
- Not visible to the public.
{{ profile.name|default:"N/A" }}
- - - + + {% for profile in profiles %} - - +
UsernameEmailPublic Credit NamePrivate namePublic credit name Actions
{{ profile.user.username }}{{ profile.user.email }}{{ profile.private_name }} {{ profile.public_credit_name }} Open In Admin diff --git a/src/backoffice/templates/facilityfeedback_backoffice.html b/src/backoffice/templates/facilityfeedback_backoffice.html index b59f9f967..0fe0945d4 100644 --- a/src/backoffice/templates/facilityfeedback_backoffice.html +++ b/src/backoffice/templates/facilityfeedback_backoffice.html @@ -16,36 +16,38 @@

Facility Feedback for {{ team.name }} Team ({{ feedback_l {{ formset.management_form }} {% csrf_token %} - {% for form, feedback in formset|zip:feedback_list %} + {% for form in formset %}
-

Feedback for {{ feedback.facility.name }} by {{ feedback.user.profile.public_credit_name|default:"Anonymous User" }}

+

+ Feedback for {{ form.instance.facility.name }} by {{ form.instance.user.profile.public_name|default:'Anonymous user' }} +

- - + + - + - + - + - + - + diff --git a/src/backoffice/templates/feedback_detail.html b/src/backoffice/templates/feedback_detail.html index 50c22010d..1acc12270 100644 --- a/src/backoffice/templates/feedback_detail.html +++ b/src/backoffice/templates/feedback_detail.html @@ -1,4 +1,5 @@ {% extends 'base.html' %} +{% load profile_display %} {% block title %} Event Feedback Detail | Orga | BackOffice | {{ block.super }} @@ -16,7 +17,7 @@

Event Feedback detail

{{ feedback.feedback }}

diff --git a/src/backoffice/templates/feedback_list.html b/src/backoffice/templates/feedback_list.html index 6c5c26956..3afe7ae56 100644 --- a/src/backoffice/templates/feedback_list.html +++ b/src/backoffice/templates/feedback_list.html @@ -20,8 +20,8 @@

Event Feedback List

Username{{ feedback.user }}User{{ form.instance.user.profile.private_name|default:'Anonymous user' }}
Created{{ feedback.created }}{{ form.instance.created }}
Facility{{ feedback.facility }}{{ form.instance.facility }}
Quick Feedback {{ feedback.quick_feedback }} {{ form.instance.quick_feedback }}
Comment{{ feedback.comment|default:"N/A" }}{{ form.instance.comment|default:"N/A" }}
Urgent{{ feedback.urgent|yesno }}{{ form.instance.urgent|yesno }}
Handled
- - + + @@ -31,8 +31,8 @@

Event Feedback List

{% for feedback in object_list %} - - + + diff --git a/src/backoffice/templates/feedback_list_processed_confirm.html b/src/backoffice/templates/feedback_list_processed_confirm.html index 630d9ddd0..bf4c9e4c3 100644 --- a/src/backoffice/templates/feedback_list_processed_confirm.html +++ b/src/backoffice/templates/feedback_list_processed_confirm.html @@ -1,4 +1,5 @@ {% extends 'base.html' %} +{% load profile_display %} {% block title %} Confirm Event Feedback Processed | {{ block.super }} @@ -16,7 +17,7 @@

Mark event feedback as processed

{{ feedback.feedback }}

diff --git a/src/backoffice/templates/includes/invoice_list_panel.html b/src/backoffice/templates/includes/invoice_list_panel.html index 903130c09..71b1f705f 100644 --- a/src/backoffice/templates/includes/invoice_list_panel.html +++ b/src/backoffice/templates/includes/invoice_list_panel.html @@ -1,4 +1,6 @@ {% load bornhack %} +{% load profile_display %} + {% if invoice_list %}
UsernamePublic Credit NamePrivate namePublic credit name Feedback Processed at Processed by
{{ feedback.user.username }}{{ feedback.user.profile.public_credit_name }}{{ feedback.user.profile.private_name }}{{ feedback.user.profile.public_name }} {{ feedback.feedback|truncatewords:12 }} {{ feedback.processed_at|default_if_none:"" }} {{ feedback.processed_by|default_if_none:"" }}
@@ -16,7 +18,7 @@ {% for invoice in invoice_list %} - + diff --git a/src/backoffice/templates/includes/refund_list_panel.html b/src/backoffice/templates/includes/refund_list_panel.html index 7d1d57b26..3e9c89bc5 100644 --- a/src/backoffice/templates/includes/refund_list_panel.html +++ b/src/backoffice/templates/includes/refund_list_panel.html @@ -1,4 +1,6 @@ {% load bornhack %} +{% load profile_display %} +
{{ invoice.id }}{% if invoice.order %}{{ invoice.order.user.username }} <{{ invoice.order.user.email }}>{% else %}{{ invoice.customorder.customer }}{% endif %}{% if invoice.order %}{% display_name invoice.order.user.profile %} <{{ invoice.order.user.email }}>{% else %}{{ invoice.customorder.customer }}{% endif %} {{ invoice.created|date }} {% if invoice.order %}{{ invoice.order.total }}{% else %}{{ invoice.customorder.amount }}{% endif %} DKK {{ invoice.get_order }}
@@ -19,7 +21,7 @@ {% for refund in refund_list %} - + diff --git a/src/backoffice/templates/permissions_by_permission.html b/src/backoffice/templates/permissions_by_permission.html index 1d19a9fcd..28cb050f2 100644 --- a/src/backoffice/templates/permissions_by_permission.html +++ b/src/backoffice/templates/permissions_by_permission.html @@ -27,13 +27,17 @@
{{ refund.id }}{{ refund.order.user.username }} <{{ refund.order.user.email }}>{% display_name refund.order.user.profile %} <{{ refund.order.user.email }}> {{ refund.amount }} DKK {{ refund.created }} {{ refund.updated }}{{ perm.name }} - + + + + + + {% for user in users %} - - - + + {% endfor %}
UsernameNamePublic Credit Name
Private namePublic credit name
{{ user.username }}{{ user.profile.name }}{{ user.profile.public_credit_name }}{{ user.profile.private_name }}{{ user.profile.public_name }}
diff --git a/src/backoffice/templates/permissions_by_user.html b/src/backoffice/templates/permissions_by_user.html index 8247dc078..5c78d3cf2 100644 --- a/src/backoffice/templates/permissions_by_user.html +++ b/src/backoffice/templates/permissions_by_user.html @@ -14,9 +14,8 @@ - - - + + @@ -26,9 +25,8 @@ {% for user in user_list %} - - - + + diff --git a/src/backoffice/templates/shop_ticket_overview.html b/src/backoffice/templates/shop_ticket_overview.html index 7b4b7cc25..5517eeece 100644 --- a/src/backoffice/templates/shop_ticket_overview.html +++ b/src/backoffice/templates/shop_ticket_overview.html @@ -3,6 +3,7 @@ {% load commonmark %} {% load static %} {% load imageutils %} +{% load profile_display %} {% block title %} Shop Tickets | {{ block.super }} @@ -37,7 +38,7 @@

Shop Tickets

- diff --git a/src/backoffice/templates/team_permissions_manage.html b/src/backoffice/templates/team_permissions_manage.html index 6cfb094b8..6890084cb 100644 --- a/src/backoffice/templates/team_permissions_manage.html +++ b/src/backoffice/templates/team_permissions_manage.html @@ -13,8 +13,7 @@

Manage {{ team.name }} Team Permissions

UsernameNamePublic Credit NamePrivate namePublic credit name Staff Superuser User Permissions
{{ user.username }}{{ user.profile.name }}{{ user.profile.public_credit_name }}{{ user.profile.private_name }}{{ user.profile.public_name }} {{ user.is_staff|truefalseicon }} {{ user.is_superuser|truefalseicon }} {% if user.is_superuser %}ALL{% else %}{% for perm in user.get_user_permissions %}{% if perm|slice:"0:6" == "camps." %}{{ perm }}
{% endif %}{% endfor %}{% endif %}
{{ ticket.product.name }} {{ ticket.opr.quantity }} {{ ticket.order.customer_comment|default:"None" }}{{ ticket.order.user.profile.name }} + {% display_name ticket.order.user.profile %} / {{ ticket.order.user.email }} {{ ticket.used_at|default:"N/A" }} {{ ticket.order.payment_method }}
- - + {% for perm in perms %} @@ -25,9 +24,8 @@

Manage {{ team.name }} Team Permissions

{% for member in team.approved_members.all %} - - - + + {% for perm in perms %} {% for field in form.visible_fields %} diff --git a/src/backoffice/templates/token_detail.html b/src/backoffice/templates/token_detail.html index 8a4dcc4a5..38ac39bc0 100644 --- a/src/backoffice/templates/token_detail.html +++ b/src/backoffice/templates/token_detail.html @@ -1,4 +1,5 @@ {% extends 'base.html' %} +{% load profile_display %} {% block title %} Token Details | Pos | BackOffice | {{ block.super }} @@ -51,16 +52,14 @@

Token Finds

UsernameNamePrivate Name Public Credit Name Superuser
{{ member.username }}{{ member.profile.name }}{{ member.profile.public_credit_name }}{{ member.profile.private_name }}{{ member.profile.public_name }} {{ member.is_superuser|truefalseicon }}
- - + {% for tf in token.tokenfind_set.all %} - - + {% endfor %} diff --git a/src/backoffice/templates/token_stats.html b/src/backoffice/templates/token_stats.html index 5fe8230b4..27d41bc4c 100644 --- a/src/backoffice/templates/token_stats.html +++ b/src/backoffice/templates/token_stats.html @@ -1,5 +1,6 @@ {% extends 'base.html' %} {% load bornhack %} +{% load profile_display %} {% block title %} Token Stats | Backoffice | {{ block.super }} @@ -15,8 +16,7 @@
Public credit nameUsernameUser Timestamp
{{ tf.user.profile.public_credit_name }}{{ tf.user.username }}{% display_name tf.user.profile %} {{ tf.created }}
- - + @@ -24,8 +24,7 @@ {% for user in user_list %} - - + diff --git a/src/people/templates/people.html b/src/people/templates/people.html index a6d083ec3..c51758a40 100644 --- a/src/people/templates/people.html +++ b/src/people/templates/people.html @@ -2,6 +2,7 @@ {% load commonmark %} {% load teams_tags %} {% load static %} +{% load profile_display %} {% block title %} People | {{ block.super }} @@ -35,14 +36,12 @@

Public credit nameUsernameUser Finds Last token found
{{ user.profile.public_credit_name }}{{ user.username }}{% display_name user.profile %} {{ user.token_find_count }} {{ user.last_token_find }}
{% for resp in team.leads.all %} - {{ resp.profile.get_public_credit_name }}
+ {% display_name resp.profile %}
{% endfor %}
{% for member in team.regular_members.all %} - {% if member.profile.get_public_credit_name != "Unnamed" %} - {{ member.profile.get_public_credit_name }}
- {% endif %} + {% display_name member.profile %}
{% empty %} No team members {% endfor %} diff --git a/src/program/mixins.py b/src/program/mixins.py index b48b4d72f..a121dbc7a 100644 --- a/src/program/mixins.py +++ b/src/program/mixins.py @@ -59,14 +59,13 @@ def dispatch(self, request, *args, **kwargs): class EnsureUserOwnsProposalMixin(SingleObjectMixin): def dispatch(self, request, *args, **kwargs): # make sure that this proposal belongs to the logged in user - if self.get_object().user.username != request.user.username: - messages.error(request, "No thanks") - return redirect( - reverse("program:proposal_list", kwargs={"camp_slug": self.camp.slug}), - ) + if self.get_object().user is request.user: + return super().dispatch(request, *args, **kwargs) - # alright, continue with the request - return super().dispatch(request, *args, **kwargs) + messages.error(request, "No thanks") + return redirect( + reverse("program:proposal_list", kwargs={"camp_slug": self.camp.slug}), + ) class UrlViewMixin: diff --git a/src/program/templates/includes/event_feedback_detail_panel.html b/src/program/templates/includes/event_feedback_detail_panel.html index c5cda4f7c..7cc78dad7 100644 --- a/src/program/templates/includes/event_feedback_detail_panel.html +++ b/src/program/templates/includes/event_feedback_detail_panel.html @@ -1,5 +1,7 @@ {% load django_bootstrap5 %} {% load commonmark %} +{% load profile_display %} +
Feedback for Event: {{ event.title }} @@ -8,8 +10,8 @@ {% if request.resolver_match.url_name == "approve_event_feedback" %} - - + + {% endif %} diff --git a/src/teams/admin.py b/src/teams/admin.py index 9b661855d..362b13962 100644 --- a/src/teams/admin.py +++ b/src/teams/admin.py @@ -43,7 +43,7 @@ class TeamAdmin(admin.ModelAdmin): def get_leads(self, obj: Team) -> str: """Method to return team leads.""" return ", ".join( - [lead.profile.public_credit_name for lead in obj.leads.all()], + [lead.profile.private_name for lead in obj.leads.all()], ) list_display: ClassVar[list[str]] = [ diff --git a/src/teams/templates/team_members.html b/src/teams/templates/team_members.html index 8c7cb25fe..26fae34b7 100644 --- a/src/teams/templates/team_members.html +++ b/src/teams/templates/team_members.html @@ -20,15 +20,12 @@

Members

{% if team.lead_permission_set in perms %} - @@ -46,16 +43,16 @@

Members

{% if member.approved or not member.approved and team.lead_permission_set in perms %} {% if team.lead_permission_set in perms %} - diff --git a/src/teams/templates/teammember_approve.html b/src/teams/templates/teammember_approve.html index 71fb35a2d..0d720e61e 100644 --- a/src/teams/templates/teammember_approve.html +++ b/src/teams/templates/teammember_approve.html @@ -1,18 +1,19 @@ {% extends 'team_base.html' %} {% load commonmark %} +{% load profile_display %} {% block title %} - Approve team member {{ teammember.user.profile.name }} for the {{ teammember.team.name }} team + Approve team member {% display_name teammember.user.profile %} for the {{ teammember.team.name }} team {% endblock %} {% block team_content %} -

Approve member {{ teammember.user.profile.name }} for the {{ teammember.team.name }} team

-

Really approve the user {{ teammember.user.profile.name }} for the {{ teammember.team.name }} team? The user will receive an email with a message.

+

Approve member {% display_name teammember.user.profile %} for the {{ teammember.team.name }} team

+

The user will receive an email with a message.

{% csrf_token %} {{ form }} - + Cancel diff --git a/src/teams/templates/teammember_remove.html b/src/teams/templates/teammember_remove.html index 15bcc58f3..3d8bd18a1 100644 --- a/src/teams/templates/teammember_remove.html +++ b/src/teams/templates/teammember_remove.html @@ -1,18 +1,19 @@ {% extends 'team_base.html' %} {% load commonmark %} +{% load profile_display %} {% block title %} - Remove member {{ teammember.user.profile.name }} from the {{ teammember.team.name }} team + Remove member {% display_name teammember.user.profile %} from the {{ teammember.team.name }} team {% endblock %} {% block team_content %} -

Remove member {{ teammember.user.profile.name }} from the {{ teammember.team.name }} team

-

Really remove the user {{ teammember.user.profile.name }} from the {{ teammember.team.name }} team? The user will receive an email with a message.

+

Remove member {% display_name teammember.user.profile %} from the {{ teammember.team.name }} team

+

The user will receive an email with a message.

{% csrf_token %} {{ form }} - + Cancel {% endblock %}
Username (feedback submitter){{ event_feedback.user.username }}User{% display_name event_feedback.user.profile %}
- Public name + User Status - Name - Email
- {% display_name member.user.profile %} {% if member.user == request.user %}(this is you!){% endif %} + {% display_name member.user.profile %} + {% if member.user == request.user %} + This is you + {% endif %} Team {% if member.lead %}Lead{% else %}Member{% endif %} {% if not member.approved %}(pending approval){% endif %} - {{ member.user.profile.name }} - {{ member.user.email }}