From 99be706e79c39a3c2d8f79afde7f1c31b9ab9f07 Mon Sep 17 00:00:00 2001
From: David Cain
Date: Thu, 18 Apr 2024 09:15:31 -0600
Subject: [PATCH] Also show whether or not somebody's a leader
We've historically used "number of trips led" as a weak proxy to
differentiate active club leaders from people who've just been given a
hiking co-leader rating. It's useful to be able to view who's actively a
MITOC leader though. Turns out the numbers don't differ much.
---
ws/api_views.py | 2 +-
ws/templates/stats/membership.html | 10 ++++++++--
ws/utils/geardb.py | 5 ++++-
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/ws/api_views.py b/ws/api_views.py
index b45271b5..ff2b782c 100644
--- a/ws/api_views.py
+++ b/ws/api_views.py
@@ -639,7 +639,7 @@ def dispatch(self, request, *args, **kwargs):
class RawMembershipStatsView(View):
@staticmethod
- def _all_members_info() -> Iterator[dict[str, str | int]]:
+ def _all_members_info() -> Iterator[dict[str, str | int | bool]]:
for info in geardb_utils.membership_information().values():
flat_info: dict[str, str | int] = {
"last_known_affiliation": info.last_known_affiliation,
diff --git a/ws/templates/stats/membership.html b/ws/templates/stats/membership.html
index 4f12f748..a5ef82fc 100644
--- a/ws/templates/stats/membership.html
+++ b/ws/templates/stats/membership.html
@@ -198,6 +198,9 @@
var justLeaders = _.filter(allMembers, 'num_trips_led');
renderChart("#leaders", justLeaders);
+ var ratedLeaders = _.filter(allMembers, 'is_leader');
+ renderChart("#rated_leaders", ratedLeaders);
+
var justDiscounts = _.filter(allMembers, function(info) {
return (info.num_discounts && !info.num_rentals && !info.num_trips_attended);
});
@@ -239,11 +242,14 @@ MITOC members grouped
+ Current Leaders
+ Affiliation of people who hold a leader rating, even if they never lead trips.
+
+
Leaders
- Current affiliation of people who have ever led a trip.
+ Current affiliation of people who have ever led a trip (even if they're not currently rated).
-
All dues-paying members
This is a count of all MITOCers who've paid their dues (but may not have
rented gear, participated on trips, or otherwise made use of the club).
diff --git a/ws/utils/geardb.py b/ws/utils/geardb.py
index fdea792f..f4652484 100644
--- a/ws/utils/geardb.py
+++ b/ws/utils/geardb.py
@@ -15,7 +15,7 @@
import requests
from allauth.account.models import EmailAddress
from django.contrib.auth.models import User
-from django.db.models import Case, Count, IntegerField, Sum, When
+from django.db.models import Case, Count, IntegerField, Q, Sum, When
from django.db.models.functions import Lower
from ws import models, settings
@@ -53,6 +53,7 @@ class Rental(NamedTuple):
class TripsInformation(NamedTuple):
+ is_leader: bool
num_trips_attended: int
num_trips_led: int
num_discounts: int
@@ -328,11 +329,13 @@ def trips_information() -> dict[int, TripsInformation]:
additional_stats = models.Participant.objects.all().annotate(
num_discounts=Count("discounts", distinct=True),
num_trips_led=Count("trips_led", distinct=True),
+ num_leader_ratings=Count("leaderrating", filter=Q(leaderrating__active=True)),
)
return {
par.user_id: TripsInformation(
email=par.email,
+ is_leader=bool(par.num_leader_ratings),
num_trips_attended=trips_per_participant[par.pk],
num_trips_led=par.num_trips_led,
num_discounts=par.num_discounts,