From a7c38d61a05253c5715cacd750ce3105017498da Mon Sep 17 00:00:00 2001 From: David Code Howard Date: Thu, 21 Sep 2023 11:42:57 -0400 Subject: [PATCH] fix: Restore missing membership_lists filter This can be done be reusing the filterset class with DjangoFilterConnectionField. It would be worthwhile checking if this work can be encapsulated in a resuable function, as there is now a lot of custom code whose function is not obvious. --- .../apps/collaboration/graphql/memberships.py | 24 +++++++++++++++++-- .../apps/graphql/schema/schema.graphql | 20 +++++++++++++++- .../project_management/graphql/projects.py | 11 ++++++--- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/terraso_backend/apps/collaboration/graphql/memberships.py b/terraso_backend/apps/collaboration/graphql/memberships.py index d36d6b4db..635a45c56 100644 --- a/terraso_backend/apps/collaboration/graphql/memberships.py +++ b/terraso_backend/apps/collaboration/graphql/memberships.py @@ -19,13 +19,33 @@ from graphene import relay from graphene_django import DjangoObjectType -from apps.graphql.schema.commons import TerrasoConnection - from ..models import Membership, MembershipList +# from apps.graphql.schema.commons import TerrasoConnection + + logger = structlog.get_logger(__name__) +# TODO: trying to import this from apps.graphql.schema.commons causes a circular import +# Created an issue to move the module to apps.graphql.commons, as that seems simplest +# https://github.com/techmatters/terraso-backend/issues/820 +class TerrasoConnection(graphene.Connection): + class Meta: + abstract = True + + total_count = graphene.Int(required=True) + + def resolve_total_count(self, info, **kwargs): + queryset = self.iterable + return queryset.count() + + @classmethod + def __init_subclass_with_meta__(cls, **options): + options["strict_types"] = options.pop("strict_types", True) + super().__init_subclass_with_meta__(**options) + + class MembershipListNodeMixin: id = graphene.ID(source="pk", required=True) account_membership = graphene.Field("apps.collaboration.graphql.CollaborationMembershipNode") diff --git a/terraso_backend/apps/graphql/schema/schema.graphql b/terraso_backend/apps/graphql/schema/schema.graphql index 542dc10d3..66471fa8f 100644 --- a/terraso_backend/apps/graphql/schema/schema.graphql +++ b/terraso_backend/apps/graphql/schema/schema.graphql @@ -561,7 +561,7 @@ type StoryMapNode implements Node { type ProjectMembershipListNode implements Node { membershipType: CollaborationMembershipListMembershipTypeChoices! - memberships: ProjectMembershipNode! + memberships(offset: Int, before: String, after: String, first: Int, last: Int, user: ID, user_In: [ID], userRole: UserRole, user_Email_Icontains: String, user_Email_In: [String], membershipStatus: CollaborationMembershipMembershipStatusChoices, user_Email_Not: String): ProjectMembershipNodeConnection id: ID! accountMembership: CollaborationMembershipNode membershipsCount: Int @@ -576,6 +576,24 @@ enum CollaborationMembershipListMembershipTypeChoices { CLOSED } +type ProjectMembershipNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ProjectMembershipNodeEdge!]! + totalCount: Int! +} + +"""A Relay edge containing a `ProjectMembershipNode` and its cursor.""" +type ProjectMembershipNodeEdge { + """The item at the end of the edge""" + node: ProjectMembershipNode! + + """A cursor for use in pagination""" + cursor: String! +} + type ProjectMembershipNode implements Node { membershipList: ProjectMembershipListNode! user: UserNode diff --git a/terraso_backend/apps/project_management/graphql/projects.py b/terraso_backend/apps/project_management/graphql/projects.py index ba77479ef..39d87e549 100644 --- a/terraso_backend/apps/project_management/graphql/projects.py +++ b/terraso_backend/apps/project_management/graphql/projects.py @@ -22,9 +22,12 @@ from django_filters import FilterSet from graphene import relay from graphene_django import DjangoObjectType -from graphene_django.filter import TypedFilter +from graphene_django.filter import DjangoFilterConnectionField, TypedFilter from apps.audit_logs import api as log_api +from apps.collaboration.graphql.memberships import ( + CollaborationMembershipFilterSet as MembershipFilterSet, +) from apps.collaboration.graphql.memberships import ( CollaborationMembershipNode as MembershipNode, ) @@ -76,11 +79,13 @@ def resolve_user_role(self, info): class ProjectMembershipListNode(DjangoObjectType, MembershipListNodeMixin): - memberships = graphene.Field(ProjectMembershipNode, required=True) - class Meta(MembershipListNodeMixin.Meta): pass + memberships = DjangoFilterConnectionField( + ProjectMembershipNode, filterset_class=MembershipFilterSet + ) + class ProjectFilterSet(FilterSet): member = TypedFilter(field_name="membership_list__memberships__user")