Repository: carpentries/amy

Issue:
Workshop issues - filter list by admin assigned
This page:

https://amy.software-carpentry.org/workshops/reports/workshop_issues

So someone can see just the workshops they are responsible for.



Discussion:

Resolving patch:
diff --git a/workshops/util.py b/workshops/util.py
--- a/workshops/util.py
+++ b/workshops/util.py
@@ -664,3 +664,27 @@ def find_emails(text):
             emails.append('{}@{}'.format(local, domain))
 
     return emails
+
+
+def assignment_selection(request):
+    """Parse `assigned_to` query param depending on the logged-in user."""
+    user = request.user
+    is_admin = user.groups.filter(name='administrators').exists()
+
+    # it's always possible to assign something entirely else
+    # in the `?assigned_to` query param
+
+    if is_admin:
+        # One of the administrators.
+        # They should be presented with their events by default.
+        assigned_to = request.GET.get('assigned_to', 'me')
+
+    elif user.is_superuser:
+        # A superuser.  Should see all events by default
+        assigned_to = request.GET.get('assigned_to', 'all')
+
+    else:
+        # Normal user (for example subcommittee members).
+        assigned_to = 'all'
+
+    return assigned_to, is_admin
diff --git a/workshops/views.py b/workshops/views.py
--- a/workshops/views.py
+++ b/workshops/views.py
@@ -73,6 +73,7 @@
     find_tags_on_event_website,
     parse_tags_from_event_website,
     validate_tags_from_event_website,
+    assignment_selection,
 )
 
 from workshops.filters import (
@@ -182,28 +183,13 @@ def dashboard(request):
     unpublished_events = Event.objects.unpublished_events().no_stalled() \
                                       .select_related('host')
 
-    user = request.user
-    is_admin = user.groups.filter(name='administrators').exists()
-
-    assigned_to = 'all'
-
-    if is_admin:
-        # One of the administrators.
-        # They should be presented with their events by default.
-        assigned_to = request.GET.get('assigned_to', 'me')
-
-    elif user.is_superuser:
-        # A superuser.  Should see all events by default
-        assigned_to = request.GET.get('assigned_to', 'all')
-
-    else:
-        # Normal user (for example subcommittee members).
-        assigned_to = 'all'
+    assigned_to, is_admin = assignment_selection(request)
 
     if assigned_to == 'me':
-        current_events = current_events.filter(assigned_to=user)
-        uninvoiced_events = uninvoiced_events.filter(assigned_to=user)
-        unpublished_events = unpublished_events.filter(assigned_to=user)
+        current_events = current_events.filter(assigned_to=request.user)
+        uninvoiced_events = uninvoiced_events.filter(assigned_to=request.user)
+        unpublished_events = unpublished_events.filter(
+            assigned_to=request.user)
 
     elif assigned_to == 'noone':
         current_events = current_events.filter(assigned_to__isnull=True)
@@ -1620,6 +1606,18 @@ def workshop_issues(request):
         Q(start__gt=F('end'))
     )
 
+    assigned_to, is_admin = assignment_selection(request)
+
+    if assigned_to == 'me':
+        events = events.filter(assigned_to=request.user)
+
+    elif assigned_to == 'noone':
+        events = events.filter(assigned_to=None)
+
+    elif assigned_to == 'all':
+        # no filtering
+        pass
+
     for e in events:
         e.missing_attendance_ = (not e.attendance)
         e.missing_location_ = (
@@ -1628,8 +1626,12 @@ def workshop_issues(request):
         )
         e.bad_dates_ = e.start and e.end and (e.start > e.end)
 
-    context = {'title': 'Workshops with Issues',
-               'events': events}
+    context = {
+        'title': 'Workshops with Issues',
+        'events': events,
+        'is_admin': is_admin,
+        'assigned_to': assigned_to,
+    }
     return render(request, 'workshops/workshop_issues.html', context)
 
 


Test patch:
diff --git a/workshops/test/test_util.py b/workshops/test/test_util.py
--- a/workshops/test/test_util.py
+++ b/workshops/test/test_util.py
@@ -3,8 +3,9 @@
 import datetime
 from io import StringIO
 
+from django.contrib.auth.models import Group
 from django.contrib.sessions.serializers import JSONSerializer
-from django.test import TestCase
+from django.test import TestCase, RequestFactory
 from django.core.urlresolvers import reverse
 
 from ..models import Host, Event, Role, Person, Task, Badge, Award
@@ -18,6 +19,7 @@
     validate_tags_from_event_website,
     get_members,
     default_membership_cutoff,
+    assignment_selection,
 )
 
 from .base import TestBase
@@ -846,3 +848,66 @@ def test_members_explicit_earliest(self):
         self.assertNotIn(self.harry, members)  # only teaching in the future
         self.assertIn(self.spiderman, members)  # explicit member
         self.assertEqual(len(members), 1)
+
+
+class TestAssignmentSelection(TestCase):
+    def setUp(self):
+        """Set up RequestFactory and some users with different levels of
+        privileges."""
+        self.factory = RequestFactory()
+        self.superuser = Person.objects.create_superuser(
+            username='superuser', personal='admin', family='admin',
+            email='superuser@superuser', password='superuser')
+        self.admin = Person.objects.create_user(
+            username='admin', personal='admin', family='admin',
+            email='admin@admin', password='admin')
+        self.admin.groups = [Group.objects.get(name='administrators')]
+        self.normal_user = Person.objects.create_user(
+            username='user', personal='typical', family='user',
+            email='typical@user', password='user')
+
+    def test_no_selection_superuser(self):
+        """User is superuser and they selected nothing. The result should be
+        default value for this kind of a user."""
+        request = self.factory.get('/')
+        request.user = self.superuser
+        assignment, is_admin = assignment_selection(request)
+        self.assertEqual(assignment, 'all')
+        self.assertFalse(is_admin)
+
+    def test_no_selection_admin(self):
+        """User is admin and they selected nothing. The result should be
+        default value for this kind of a user."""
+        request = self.factory.get('/')
+        request.user = self.admin
+        assignment, is_admin = assignment_selection(request)
+        self.assertEqual(assignment, 'me')
+        self.assertTrue(is_admin)
+
+    def test_no_selection_normal_user(self):
+        """User is normal user and they selected nothing. The result should be
+        default value for this kind of a user."""
+        request = self.factory.get('/')
+        request.user = self.normal_user
+        assignment, is_admin = assignment_selection(request)
+        self.assertEqual(assignment, 'all')
+        self.assertFalse(is_admin)
+
+    def test_selection_normal_user(self):
+        """User is normal user and they selected self-assigned. This is invalid
+        selection (normal user cannot select anything), so the default option
+        should be returned."""
+        request = self.factory.get('/', {'assigned_to': 'me'})
+        request.user = self.normal_user
+        assignment, is_admin = assignment_selection(request)
+        self.assertEqual(assignment, 'all')
+        self.assertFalse(is_admin)
+
+    def test_selection_privileged_user(self):
+        """User is admin and they selected "not assigned to anyone". Actually
+        for privileged user any selection should make through."""
+        request = self.factory.get('/', {'assigned_to': 'noone'})
+        request.user = self.admin
+        assignment, is_admin = assignment_selection(request)
+        self.assertEqual(assignment, 'noone')
+        self.assertTrue(is_admin)