diff --git a/paperwork/api.py b/paperwork/api.py index a2fc114..53455bb 100644 --- a/paperwork/api.py +++ b/paperwork/api.py @@ -22,6 +22,63 @@ 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", + "list_moderator_flag", + Prefetch( + "certificationdefinition_set__certificationversion_set__certification_set__member", + queryset=Member.objects.with_is_active(), + ), + ) + lists = {} + for department in departments: + if department.list_moderator_flag is not None: + moderator_emails = department.list_moderator_flag.members.values_list( + "email", flat=True + ) + 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] = { + "real_name": department.list_name, + "moderator": moderator_emails, + "subject_prefix": f"[CMS {department.name}] ", + "reply_to_address": department.list_reply_to_address, + "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: + if department.parent_id is None: + recurse_children(department) + + return Response(lists) + class CertificationDefinitionSerializer(serializers.HyperlinkedModelSerializer): class Meta: @@ -33,32 +90,6 @@ class CertificationDefinitionViewSet(viewsets.ModelViewSet): queryset = CertificationDefinition.objects.all() serializer_class = CertificationDefinitionSerializer - @action(detail=False, methods=["get"]) - def mailing_lists(self, request, format=None): - """ - Generate a mailing list for each certification definition, - containing all certified users for that tool - """ - lists = {} - for definition in self.queryset.exclude(mailing_list="").prefetch_related( - Prefetch( - "certificationversion_set__certification_set__member", - queryset=Member.objects.with_is_active(), - ), - ): - if definition.mailing_list not in lists: - lists[definition.mailing_list] = set() - # TODO: this could be done in sql instead; was planning to - # maybe also filter to only active certs - for version in definition.certificationversion_set.all(): - for cert in version.certification_set.all(): - if cert.member and cert.member.is_active: - lists[definition.mailing_list].add( - cert.member.sanitized_mailbox - ) - - return Response(lists) - class CertificationVersionSerializer(serializers.HyperlinkedModelSerializer): class Meta: