Repository: dotkom/onlineweb4

Issue:
Users attending events that are group restricted should be able to see them
With closed events for groups (like julebord), some users may get added to them that are not specifically in the list of allowed groups. This can happen in many ways, but these users should also be able to see these events as if they were part of these groups while they are listed as attending.

Either that or allow them to pay for the events in some other way.



Discussion:

Resolving patch:
diff --git a/apps/events/models.py b/apps/events/models.py
--- a/apps/events/models.py
+++ b/apps/events/models.py
@@ -186,6 +186,8 @@ def _feedback_mail_fallback(self):
 
     def can_display(self, user):
         restriction = GroupRestriction.objects.filter(event=self).first()
+        if not user.is_anonymous and self.is_attendance_event() and self.attendance_event.is_attendee(user):
+            return True
         if not self.visible:
             return False
         if not restriction:
diff --git a/apps/events/views.py b/apps/events/views.py
--- a/apps/events/views.py
+++ b/apps/events/views.py
@@ -392,11 +392,15 @@ def get_queryset(self):
         """
         :return: Queryset filtered by these requirements:
             event is visible AND (event has NO group restriction OR user having access to restricted event)
+            OR the user is attending the event themselves
         """
-        return Event.by_registration.filter(
-            (Q(group_restriction__isnull=True) | Q(group_restriction__groups__in=self.request.user.groups.all())) &
-            Q(visible=True)). \
-            distinct()
+        user = self.request.user
+        group_restriction_query = Q(group_restriction__isnull=True) | Q(group_restriction__groups__in=user.groups.all())
+        is_attending_query = (
+            Q(attendance_event__isnull=False) & Q(attendance_event__attendees__user=user)
+        ) if not user.is_anonymous else Q()
+        is_visible_query = Q(visible=True)
+        return Event.by_registration.filter(group_restriction_query & is_visible_query | is_attending_query).distinct()
 
 
 class RegistrationAttendaceEventViewSet(viewsets.ReadOnlyModelViewSet):


Test patch:
diff --git a/apps/events/tests/api_tests.py b/apps/events/tests/api_tests.py
--- a/apps/events/tests/api_tests.py
+++ b/apps/events/tests/api_tests.py
@@ -10,7 +10,7 @@
 from apps.authentication.models import OnlineUser
 from apps.companyprofile.models import Company
 from apps.events.constants import AttendStatus
-from apps.events.models import Attendee, CompanyEvent
+from apps.events.models import Attendee, CompanyEvent, GroupRestriction
 from apps.online_oidc_provider.test import OIDCTestCase
 from apps.profiles.models import Privacy
 
@@ -326,6 +326,10 @@ def setUp(self):
         self.user = generate_user(username='_user')
         self.privacy = G(Privacy, user=self.user)
         self.token = self.generate_access_token(self.user)
+        self.headers = {
+            **self.headers,
+            **self.generate_headers(),
+        }
 
         self.url = reverse('events-list')
         self.id_url = lambda _id: self.url + str(_id) + '/'
@@ -377,6 +381,22 @@ def test_filter_companies_in_event_list(self):
         self.assertIn(bedpres_with_onlinecorp.id, event_titles_list)
         self.assertNotIn(bedpres_with_evilcorp.id, event_titles_list)
 
+    def test_event_with_group_restriction(self):
+        response = self.client.get(self.id_url(self.event.id), **self.headers)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+        restricted_to_group: Group = G(Group)
+        G(GroupRestriction, event=self.event, group=restricted_to_group)
+
+        response = self.client.get(self.id_url(self.event.id), **self.headers)
+        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+        attendee = attend_user_to_event(self.event, self.user)
+
+        self.assertIn(attendee, self.event.attendance_event.attendees.all())
+        response = self.client.get(self.id_url(self.event.id), **self.headers)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
 
 class AttendAPITestCase(OIDCTestCase):
 
diff --git a/apps/events/tests/model_tests.py b/apps/events/tests/model_tests.py
--- a/apps/events/tests/model_tests.py
+++ b/apps/events/tests/model_tests.py
@@ -16,7 +16,7 @@
 from apps.feedback.models import Feedback, FeedbackRelation
 from apps.marks.models import DURATION, Mark, MarkUser
 
-from .utils import generate_attendance_event, generate_attendee
+from .utils import attend_user_to_event, generate_attendance_event, generate_attendee
 
 
 class EventModelTest(TestCase):
@@ -299,9 +299,10 @@ def testRestrictedEvents(self):
         denied_user = G(User, groups=[denied_groups[0], ])
 
         unrestricted_event = G(Event)
+        G(AttendanceEvent, event=unrestricted_event)
         restricted_event = G(Event)
         G(GroupRestriction, event=restricted_event, groups=allowed_groups)
-        # restricted_event.group_restriction.add(allowed_groups)
+        G(AttendanceEvent, event=restricted_event)
 
         self.assertTrue(restricted_event.can_display(allowed_user),
                         "User should be able to view restricted event if in allowed group")
@@ -312,6 +313,10 @@ def testRestrictedEvents(self):
         self.assertTrue(unrestricted_event.can_display(denied_user),
                         "Any user should be able to see unrestricted events")
 
+        attend_user_to_event(restricted_event, denied_user)
+        self.assertTrue(restricted_event.can_display(denied_user),
+                        "User should be able to see event when they are attending even if the event is restricted")
+
 
 class WaitlistAttendanceEventTest(TestCase):
     def setUp(self):