cmsmanage/paperwork/api.py

175 lines
5.7 KiB
Python
Raw Permalink Normal View History

2024-05-04 16:38:51 -04:00
from typing import Required, TypedDict
from django.db.models import Q, QuerySet
from rest_framework import routers, serializers, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from membershipworks.models import Member
from .models import (
Certification,
CertificationDefinition,
CertificationVersion,
Department,
)
class DepartmentSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Department
fields = ["name", "parent", "shop_lead_flag", "list_reply_to_address"]
2024-05-04 16:38:51 -04:00
class ListConfig(TypedDict, total=False):
real_name: str
subject_prefix: str
reply_to_address: str
class MailingList(TypedDict, total=False):
config: ListConfig
moderators: set[str]
members: Required[set[str]]
class DepartmentViewSet(viewsets.ModelViewSet):
2024-05-04 16:38:51 -04:00
queryset: QuerySet[Department] = Department.objects.all()
serializer_class = DepartmentSerializer
@action(detail=False, methods=["get"])
2024-08-07 13:46:39 -04:00
def mailing_lists(self, request, format=None): # noqa: A002
"""
Generate a mailing list for each department, containing all
certified users for tools in that department or child departments
"""
departments = self.queryset.prefetch_related(
"children",
"shop_lead_flag__members",
)
2024-05-04 16:38:51 -04:00
lists: dict[str, MailingList] = {}
for department in departments.filter(has_mailing_list=True):
if department.shop_lead_flag is not None:
moderator_emails = {
member.volunteer_email if member.volunteer_email else member.email
for member in department.shop_lead_flag.members.all()
}
else:
2024-05-04 16:38:51 -04:00
moderator_emails = set()
active_certified_members = {
member.sanitized_mailbox()
for member in Member.objects.with_is_active().filter(
is_active=True,
certification__certification_version__definition__department=department,
)
}
2024-05-04 16:38:51 -04:00
# list_name can only be None if has_mailing_list is False
assert department.list_name is not None
lists[department.list_name] = {
"config": {
"real_name": department.list_name,
"subject_prefix": f"[CMS {department.name}] ",
"reply_to_address": department.list_reply_to_address,
},
"moderators": moderator_emails,
"members": active_certified_members,
}
# Add child departments' members to their parents
# TODO: this seems wildly inefficient
def recurse_children(department):
for child in department.children.all():
recurse_children(child)
lists[department.list_name]["members"] |= lists[child.list_name][
"members"
]
for department in departments.filter(has_mailing_list=True):
if department.parent_id is None:
recurse_children(department)
shopleads: dict[Member, list[Department]] = {}
for department in departments.filter(shop_lead_flag__isnull=False):
for member in department.shop_lead_flag.members.all():
if member not in shopleads:
shopleads[member] = []
shopleads[member].append(department)
# Add members to the Shop Leads mailing list, but don't configure it
lists["ShopLeads"] = {
"members": {
shoplead.sanitized_mailbox(use_volunteer=True)
for shoplead, departments in shopleads.items()
},
}
2023-08-26 20:20:05 -04:00
# TODO: this isn't really in the domain of the `paperwork` app...
deskers = (
Member.objects.with_is_active()
.filter(is_active=True)
.filter(
Member.objects.has_flag("label", "Volunteer: Desker")
| Q(billing_method__startswith="Desker")
)
)
lists["Deskers"] = {
"members": {
desker.sanitized_mailbox(use_volunteer=True) for desker in deskers
}
}
return Response(lists)
class CertificationDefinitionSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = CertificationDefinition
fields = ["name", "department"]
class CertificationDefinitionViewSet(viewsets.ModelViewSet):
queryset = CertificationDefinition.objects.all()
serializer_class = CertificationDefinitionSerializer
class CertificationVersionSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = CertificationVersion
fields = ["definition", "version"]
class CertificationVersionViewSet(viewsets.ModelViewSet):
queryset = CertificationVersion.objects.all()
serializer_class = CertificationVersionSerializer
class CertificationSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Certification
fields = [
"name",
"member",
"certification_version",
"certified_by",
"date",
"shop_lead_notified",
"notes",
]
class CertificationViewSet(viewsets.ModelViewSet):
queryset = Certification.objects.all()
serializer_class = CertificationSerializer
router = routers.DefaultRouter()
router.register(r"paperwork/department", DepartmentViewSet)
router.register(r"paperwork/certification_definition", CertificationDefinitionViewSet)
router.register(r"paperwork/certification_version", CertificationVersionViewSet)
router.register(r"paperwork/certification", CertificationViewSet)