Repository: carpentries/amy

Issue:
Instructor Selection: Show selected workshops on top in instructor view
When an instructor user goes to the list of all teaching opportunities, the ones they have already expressed interest in should be on the top of the list, followed by all other workshops in the specified sort order.


Discussion:
@maneesha to change this into filter option with a checkbox

Resolving patch:
diff --git a/amy/dashboard/filters.py b/amy/dashboard/filters.py
--- a/amy/dashboard/filters.py
+++ b/amy/dashboard/filters.py
@@ -1,4 +1,5 @@
 from django.db.models import F, QuerySet
+from django.forms import widgets
 import django_filters as filters
 
 from recruitment.models import InstructorRecruitment
@@ -16,6 +17,12 @@ class UpcomingTeachingOpportunitiesFilter(AMYFilterSet):
         method="filter_status",
     )
 
+    only_applied_to = filters.BooleanFilter(
+        label="Show only workshops I have applied to",
+        method="filter_application_only",
+        widget=widgets.CheckboxInput,
+    )
+
     order_by = filters.OrderingFilter(
         fields=("event__start",),
         choices=(
@@ -66,3 +73,11 @@ def filter_order_by(self, queryset: QuerySet, name: str, values: list) -> QueryS
             return queryset.annotate(distance=distance).order_by("-distance")
         else:
             return queryset.order_by(*values)
+
+    def filter_application_only(
+        self, queryset: QuerySet, name: str, value: bool
+    ) -> QuerySet:
+        if value:
+            return queryset.filter(signups__person=self.request.user)
+
+        return queryset
diff --git a/amy/dashboard/views.py b/amy/dashboard/views.py
--- a/amy/dashboard/views.py
+++ b/amy/dashboard/views.py
@@ -307,6 +307,7 @@ def get_queryset(self):
                 ),
             )
             .order_by("event__start")
+            .distinct()
         )
         return super().get_queryset()
 
diff --git a/amy/recruitment/views.py b/amy/recruitment/views.py
--- a/amy/recruitment/views.py
+++ b/amy/recruitment/views.py
@@ -176,6 +176,7 @@ def get_other_object(self) -> Event:
             Event.objects.filter(start__gte=today)
             .filter(location)
             .select_related("administrator")
+            .distinct()
         )
         return get_object_or_404(qs, pk=event_id)
 


Test patch:
diff --git a/amy/dashboard/tests/test_filters.py b/amy/dashboard/tests/test_filters.py
--- a/amy/dashboard/tests/test_filters.py
+++ b/amy/dashboard/tests/test_filters.py
@@ -14,7 +14,9 @@ def test_fields(self):
         # Act
         filterset = UpcomingTeachingOpportunitiesFilter(data)
         # Assert
-        self.assertEqual(filterset.filters.keys(), {"status", "order_by"})
+        self.assertEqual(
+            filterset.filters.keys(), {"status", "order_by", "only_applied_to"}
+        )
 
     def test_invalid_values_for_status(self):
         # Arrange
@@ -167,3 +169,24 @@ def test_filter_order_by__latlng_provided(self):
         self.assertEqual(
             qs_mock.annotate.call_args_list[0], call(distance=distance_expression)
         )
+
+    def test_filter_application_only__not_applied(self) -> None:
+        # Arrange
+        qs_mock = MagicMock()
+        filterset = UpcomingTeachingOpportunitiesFilter({})
+        name = "only_applied_to"
+        # Act
+        filterset.filter_application_only(qs_mock, name, False)
+        # Assert
+        qs_mock.filter.assert_not_called()
+
+    def test_filter_application_only__applied(self) -> None:
+        # Arrange
+        qs_mock = MagicMock()
+        filterset = UpcomingTeachingOpportunitiesFilter({})
+        filterset.request = MagicMock()
+        name = "only_applied_to"
+        # Act
+        filterset.filter_application_only(qs_mock, name, True)
+        # Assert
+        qs_mock.filter.assert_called_once_with(signups__person=filterset.request.user)