From 6139c5caff32ae3ddf5a3fedb0ca31de2c72f1d7 Mon Sep 17 00:00:00 2001
From: Lucas Brandstaetter <lucas@brandstaetter.tech>
Date: Fri, 27 Dec 2024 15:18:35 +0000
Subject: [PATCH] Fix RedeemTokenDetailView

- Redirect user to awards view if they have no permission
- Allow staff members with view_assembly permission to view the token
---
 src/core/models/assemblies.py |  2 +-
 src/plainui/views/badges.py   | 17 ++++++++++-------
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/src/core/models/assemblies.py b/src/core/models/assemblies.py
index 8990771ec..d5c6244df 100644
--- a/src/core/models/assemblies.py
+++ b/src/core/models/assemblies.py
@@ -85,7 +85,7 @@ class Assembly(TaggedItemMixin, ActivityLogMixin, RulesModel):
         verbose_name = _('Assembly')
         verbose_name_plural = _('Assemblies')
         rules_permissions = {
-            'view': is_assembly_member,
+            'view': is_assembly_member | has_perms('core.view_assembly', require_staff=True),
             'add': is_authenticated,
             'change': is_assembly_manager | has_perms('core.change_assembly', require_staff=True),
             'delete': is_assembly_manager | has_perms('core.delete_assembly', require_staff=True),
diff --git a/src/plainui/views/badges.py b/src/plainui/views/badges.py
index dbc254e8b..83e9bb3ad 100644
--- a/src/plainui/views/badges.py
+++ b/src/plainui/views/badges.py
@@ -24,7 +24,7 @@ from django.views.generic.base import TemplateView
 from django.views.generic.detail import DetailView
 from django.views.generic.edit import FormView, UpdateView
 
-from core.models import Assembly, Badge, BadgeToken, UserBadge
+from core.models import Badge, BadgeToken, UserBadge
 from core.models.badges import TokenInvalid
 from core.models.conference import ConferenceMember
 from core.views.list_views import FilteredListView
@@ -108,6 +108,15 @@ class RedeemTokenDetailView(ConferenceRequiredMixin, DetailView):
     model = BadgeToken
     template_name = 'plainui/badges/token_detail.html.j2'
     context_object_name = 'token'
+    require_user = True
+
+    def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
+        if not BadgeToken.type_is(token := self.get_object()):  # pragma: no cover
+            raise ValueError('Token is not a badge token')
+        if self.request.user.has_perm('core.view_assembly', token.badge.issuing_assembly):
+            return super().get(request, *args, **kwargs)
+        else:
+            return HttpResponseRedirect(f"{reverse('plainui:manage_badges')}?redeem_token={token.token}")
 
     def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
         # Regenerate the qr code if needed
@@ -119,12 +128,6 @@ class RedeemTokenDetailView(ConferenceRequiredMixin, DetailView):
             'conf': self.conf,
         }
 
-    def get_queryset(self) -> QuerySet[BadgeToken]:
-        manageable = Assembly.objects.manageable_by_user(user=self.request.user, conference=self.conf, staff_can_manage=False)
-        qs = super().get_queryset()
-        qs = qs.filter(badge__issuing_assembly__in=manageable)
-        return qs
-
 
 @method_decorator(ratelimit(group='redeem_badge', key='user', rate=settings.BADGE_RATE_LIMIT), name='dispatch')
 class RedeemBadgeView(ConferenceRequiredMixin, FormView):
-- 
GitLab