From 45883ca1848ef71f3c98fc8c4feec4c7289cd703 Mon Sep 17 00:00:00 2001 From: David Cain Date: Thu, 27 Jun 2024 10:39:16 -0600 Subject: [PATCH] Warn if missing WIMP, provide link to set A requested suggestion from Bjorn -- some trip leaders have been getting a bit confused about how to set the WIMP. --- ws/templates/trips/medical.html | 9 ++++ ws/templatetags/medical_tags.py | 8 +++- ws/tests/views/test_itinerary.py | 70 ++++++++++++++++++++++++++++++-- ws/views/itinerary.py | 17 +++++--- 4 files changed, 93 insertions(+), 11 deletions(-) diff --git a/ws/templates/trips/medical.html b/ws/templates/trips/medical.html index 65664bf2..b9178f75 100644 --- a/ws/templates/trips/medical.html +++ b/ws/templates/trips/medical.html @@ -15,5 +15,14 @@

{% endif %}

+{% if not has_wimp %} +
+ No WIMP has been assigned to this trip! + {% if is_trip_leader %} + Set a WIMP? + {% endif %} +
+{% endif %} + {% trip_info trip True %} {% endblock content %} diff --git a/ws/templatetags/medical_tags.py b/ws/templatetags/medical_tags.py index 56b6fde5..af4d8845 100644 --- a/ws/templatetags/medical_tags.py +++ b/ws/templatetags/medical_tags.py @@ -38,8 +38,12 @@ def trip_itinerary(trip): @register.inclusion_tag("for_templatetags/trip_info.html", takes_context=True) -def trip_info(context, trip, show_participants_if_no_itinerary=False): - participant = context["viewing_participant"] +def trip_info( + context: dict[str, Any], + trip: models.Trip, + show_participants_if_no_itinerary: bool = False, +) -> dict[str, Any]: + participant: models.Participant = context["viewing_participant"] # After a sufficiently long waiting period, hide medical information # (We could need medical info a day or two after a trip was due back) diff --git a/ws/tests/views/test_itinerary.py b/ws/tests/views/test_itinerary.py index 863bf1e0..f9870f82 100644 --- a/ws/tests/views/test_itinerary.py +++ b/ws/tests/views/test_itinerary.py @@ -266,8 +266,33 @@ def test_leader_for_another_trip(self): trip = factories.TripFactory.create() self._assert_cannot_view(trip) - def test_view_as_leader(self): - trip = factories.TripFactory.create(program=enums.Program.HIKING.value) + def test_view_as_leader_with_no_wimp(self): + trip = factories.TripFactory.create( + wimp=None, program=enums.Program.HIKING.value + ) + + leader = factories.ParticipantFactory.create(user=self.user) + factories.LeaderRatingFactory.create( + participant=leader, activity=models.LeaderRating.HIKING + ) + trip.leaders.add(leader) + response = self.client.get(f"/trips/{trip.pk}/medical/") + soup = BeautifulSoup(response.content, "html.parser") + + self.assertIsNone(trip.wimp) + self.assertNotEqual(trip.program_enum, enums.Program.WINTER_SCHOOL) + missing = soup.find(id="wimp-missing") + self.assertEqual( + strip_whitespace(missing.text), + "No WIMP has been assigned to this trip! Set a WIMP?", + ) + self.assertIsNotNone(missing.find("a", href=f"/trips/{trip.pk}/edit/")) + + def test_view_as_leader_with_wimp_set(self): + trip = factories.TripFactory.create( + wimp=factories.ParticipantFactory.create(), + program=enums.Program.HIKING.value, + ) factories.SignUpFactory.create( participant__emergency_info__allergies="Bee stings", trip=trip, on_trip=True @@ -281,6 +306,11 @@ def test_view_as_leader(self): response = self.client.get(f"/trips/{trip.pk}/medical/") soup = BeautifulSoup(response.content, "html.parser") + # This is a non-WS trip with a single WIMP set! + self.assertIsNotNone(trip.wimp) + self.assertNotEqual(trip.program_enum, enums.Program.WINTER_SCHOOL) + self.assertIsNone(soup.find(id="wimp-missing")) + # Participant medical info is given self.assertTrue(soup.find("td", string="Bee stings")) @@ -293,9 +323,37 @@ def test_view_as_leader(self): ) ) - def test_view_as_wimp(self): + def test_view_ws_trip_as_wimp(self): + Group.objects.get(name="WIMP").user_set.add(self.user) + trip = factories.TripFactory.create( + wimp=None, + program=enums.Program.WINTER_SCHOOL.value, + ) + + factories.SignUpFactory.create( + participant__emergency_info__allergies="Bee stings", trip=trip, on_trip=True + ) + + response = self.client.get(f"/trips/{trip.pk}/medical/") + soup = BeautifulSoup(response.content, "html.parser") + + # It's a Winter School trip -- we have one WIMP for *all* trips + self.assertIsNone(trip.wimp_id) + self.assertIsNone(soup.find(id="wimp-missing")) + + # Participant medical info is given + self.assertTrue(soup.find("td", string="Bee stings")) + + # The WIMP cannot provide an itinerary, they're not a leader + self.assertFalse(soup.find("a", href=f"/trips/{trip.pk}/itinerary/")) + + def test_view_as_single_trip_wimp(self): wimp = factories.ParticipantFactory.create(user=self.user) - trip = factories.TripFactory.create(wimp=wimp) + trip = factories.TripFactory.create( + wimp=wimp, + # It's important that this *not* be a WS trip, since it has a WIMP! + program=enums.Program.HIKING.value, + ) factories.SignUpFactory.create( participant__emergency_info__allergies="Bee stings", trip=trip, on_trip=True @@ -304,6 +362,10 @@ def test_view_as_wimp(self): response = self.client.get(f"/trips/{trip.pk}/medical/") soup = BeautifulSoup(response.content, "html.parser") + # We of course have a WIMP + self.assertIsNotNone(trip.wimp_id) + self.assertIsNone(soup.find(id="wimp-missing")) + # Participant medical info is given self.assertTrue(soup.find("td", string="Bee stings")) diff --git a/ws/views/itinerary.py b/ws/views/itinerary.py index 80362790..50901229 100644 --- a/ws/views/itinerary.py +++ b/ws/views/itinerary.py @@ -5,6 +5,8 @@ what the intended route will be, when to worry, and more. """ +from typing import Any + from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.db.models import Q @@ -121,14 +123,19 @@ def dispatch(self, request, *args, **kwargs): return render(request, "not_your_trip.html", {"trip": trip}) return normal_response - def get_context_data(self, **kwargs): + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: """Get a trip info form for display as readonly.""" context_data = super().get_context_data(**kwargs) trip = self.object - participant = self.request.participant - context_data["is_trip_leader"] = perm_utils.leader_on_trip(participant, trip) - - return context_data + participant = self.request.participant # type: ignore[attr-defined] + return { + "is_trip_leader": perm_utils.leader_on_trip(participant, trip), + "has_wimp": ( + trip.program_enum == enums.Program.WINTER_SCHOOL + or (trip.wimp_id is not None) + ), + **context_data, + } class ChairTripView(DetailView):