from rest_framework import routers, serializers, viewsets from django.db.models import Prefetch, Q from rest_framework.decorators import action from rest_framework.response import Response from membershipworks.models import Member from .models import ( Department, Certification, CertificationDefinition, CertificationVersion, ) class DepartmentSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Department fields = ["name", "parent", "shop_lead_flag", "list_reply_to_address"] class DepartmentViewSet(viewsets.ModelViewSet): queryset = Department.objects.all() serializer_class = DepartmentSerializer @action(detail=False, methods=["get"]) def mailing_lists(self, request, format=None): """ 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", Prefetch( "certificationdefinition_set__certificationversion_set__certification_set__member", queryset=Member.objects.with_is_active(), ), ) lists = {} 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: moderator_emails = [] # TODO: this could be done in SQL instead if # membershipworks was in the same database active_certified_members = { member_cert.member.sanitized_mailbox() for certification in department.certificationdefinition_set.all() for version in certification.certificationversion_set.all() for member_cert in version.certification_set.all() if member_cert.member and member_cert.member.is_active } 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 = {} 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( f" - {'/'.join(department.name for department in departments)}", use_volunteer=True, ) for shoplead, departments in shopleads.items() }, } # 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)