From aa710dba6e509bf7110640ca5dc8d3f7456eecf1 Mon Sep 17 00:00:00 2001 From: guru_sainath Date: Tue, 27 Aug 2024 18:58:00 +0530 Subject: [PATCH] [MOBIL-141] chore: added project and user details in inbox (#947) * chore: added project and user details in inbox * chore: project detail * chore: cycle and module user properties queries and mutation * chore: typo in mutation * chore: created prjects in your work --- apiserver/plane/graphql/mutations/cycle.py | 40 ++++++++++++++++- apiserver/plane/graphql/mutations/module.py | 40 ++++++++++++++++- apiserver/plane/graphql/queries/cycle.py | 32 +++++++++++++- apiserver/plane/graphql/queries/issue.py | 13 +++--- apiserver/plane/graphql/queries/module.py | 32 +++++++++++++- .../plane/graphql/queries/notification.py | 1 - apiserver/plane/graphql/queries/project.py | 44 +++++++++++++++++++ apiserver/plane/graphql/queries/workspace.py | 3 +- apiserver/plane/graphql/schema.py | 20 +++++++-- apiserver/plane/graphql/types/cycle.py | 30 ++++++++++++- apiserver/plane/graphql/types/module.py | 30 ++++++++++++- apiserver/plane/graphql/types/notification.py | 14 ++---- apiserver/plane/graphql/types/users.py | 4 +- 13 files changed, 268 insertions(+), 35 deletions(-) diff --git a/apiserver/plane/graphql/mutations/cycle.py b/apiserver/plane/graphql/mutations/cycle.py index 71ee75368a..b41b94cd19 100644 --- a/apiserver/plane/graphql/mutations/cycle.py +++ b/apiserver/plane/graphql/mutations/cycle.py @@ -20,7 +20,13 @@ from plane.graphql.permissions.project import ( ProjectMemberPermission, ProjectBasePermission, ) -from plane.db.models import CycleIssue, Cycle, UserFavorite +from plane.db.models import ( + CycleIssue, + Cycle, + UserFavorite, + CycleUserProperties, +) +from plane.graphql.types.cycle import CycleUserPropertyType from plane.graphql.bgtasks.issue_activity_task import issue_activity @@ -160,7 +166,6 @@ class CycleIssueMutation: @strawberry.type class CycleFavoriteMutation: - @strawberry.mutation( extensions=[PermissionExtension(permissions=[ProjectBasePermission()])] ) @@ -199,3 +204,34 @@ class CycleFavoriteMutation: await sync_to_async(cycle_favorite.delete)() return True + + +@strawberry.type +class CycleIssueUserPropertyMutation: + @strawberry.mutation( + extensions=[PermissionExtension(permissions=[ProjectBasePermission()])] + ) + async def updateCycleUserProperties( + self, + info: Info, + slug: str, + project: strawberry.ID, + cycle: strawberry.ID, + filters: JSON, + display_filters: JSON, + display_properties: JSON, + ) -> CycleUserPropertyType: + cycle_issue_properties = await sync_to_async( + CycleUserProperties.objects.get + )( + workspace__slug=slug, + project_id=project, + cycle_id=cycle, + user=info.context.user, + ) + cycle_issue_properties.filters = filters + cycle_issue_properties.display_filters = display_filters + cycle_issue_properties.display_properties = display_properties + + await sync_to_async(cycle_issue_properties.save)() + return cycle_issue_properties diff --git a/apiserver/plane/graphql/mutations/module.py b/apiserver/plane/graphql/mutations/module.py index bb05373761..c53e88014a 100644 --- a/apiserver/plane/graphql/mutations/module.py +++ b/apiserver/plane/graphql/mutations/module.py @@ -18,7 +18,13 @@ from plane.graphql.permissions.project import ( ProjectMemberPermission, ProjectBasePermission, ) -from plane.db.models import Project, ModuleIssue, UserFavorite +from plane.db.models import ( + Project, + ModuleIssue, + UserFavorite, + ModuleUserProperties, +) +from plane.graphql.types.module import ModuleUserPropertyType from plane.graphql.bgtasks.issue_activity_task import issue_activity @@ -115,7 +121,6 @@ class ModuleIssueMutation: @strawberry.type class ModuleFavoriteMutation: - @strawberry.mutation( extensions=[PermissionExtension(permissions=[ProjectBasePermission()])] ) @@ -154,3 +159,34 @@ class ModuleFavoriteMutation: await sync_to_async(module_favorite.delete)() return True + + +@strawberry.type +class ModuleIssueUserPropertyMutation: + @strawberry.mutation( + extensions=[PermissionExtension(permissions=[ProjectBasePermission()])] + ) + async def updateModuleUserProperties( + self, + info: Info, + slug: str, + project: strawberry.ID, + module: strawberry.ID, + filters: JSON, + display_filters: JSON, + display_properties: JSON, + ) -> ModuleUserPropertyType: + module_issue_properties = await sync_to_async( + ModuleUserProperties.objects.get + )( + workspace__slug=slug, + project_id=project, + module_id=module, + user=info.context.user, + ) + module_issue_properties.filters = filters + module_issue_properties.display_filters = display_filters + module_issue_properties.display_properties = display_properties + + await sync_to_async(module_issue_properties.save)() + return module_issue_properties diff --git a/apiserver/plane/graphql/queries/cycle.py b/apiserver/plane/graphql/queries/cycle.py index a171778181..bc9e4b9d94 100644 --- a/apiserver/plane/graphql/queries/cycle.py +++ b/apiserver/plane/graphql/queries/cycle.py @@ -17,8 +17,8 @@ from strawberry.scalars import JSON from strawberry.permission import PermissionExtension # Module Imports -from plane.db.models import Cycle, Issue -from plane.graphql.types.cycle import CycleType +from plane.db.models import Cycle, Issue, CycleUserProperties +from plane.graphql.types.cycle import CycleType, CycleUserPropertyType from plane.graphql.types.issue import ( IssuesInformationType, IssuesInformationObjectType, @@ -84,6 +84,34 @@ class CycleQuery: return cycle +# cycle issue user properties +@strawberry.type +class CycleIssueUserPropertyQuery: + @strawberry.field( + extensions=[PermissionExtension(permissions=[ProjectBasePermission()])] + ) + async def cycleIssueUserProperties( + self, + info: Info, + slug: str, + project: strawberry.ID, + cycle: strawberry.ID, + ) -> CycleUserPropertyType: + cycle_issue_property = await sync_to_async( + lambda: CycleUserProperties.objects.filter( + workspace__slug=slug, project_id=project, cycle_id=cycle + ) + .filter( + project__project_projectmember__member=info.context.user, + project__project_projectmember__is_active=True, + ) + .order_by("-created_at") + .first() + )() + + return cycle_issue_property + + # cycle issues information query @strawberry.type class CycleIssuesInformationQuery: diff --git a/apiserver/plane/graphql/queries/issue.py b/apiserver/plane/graphql/queries/issue.py index 8ead450bfa..5a956aacfd 100644 --- a/apiserver/plane/graphql/queries/issue.py +++ b/apiserver/plane/graphql/queries/issue.py @@ -364,16 +364,13 @@ class SubIssuesQuery: @strawberry.type class IssueTypesTypeQuery: @strawberry.field( - extensions=[PermissionExtension(permissions=[WorkspaceBasePermission()])] + extensions=[ + PermissionExtension(permissions=[WorkspaceBasePermission()]) + ] ) - async def issueTypes( - self, info: Info, slug: str - ) -> list[IssueTypesType]: + async def issueTypes(self, info: Info, slug: str) -> list[IssueTypesType]: issue_types = await sync_to_async(list)( - IssueType.objects.filter( - workspace__slug=slug - ) - .distinct() + IssueType.objects.filter(workspace__slug=slug).distinct() ) return issue_types diff --git a/apiserver/plane/graphql/queries/module.py b/apiserver/plane/graphql/queries/module.py index c3c5b13de0..1b7dabffef 100644 --- a/apiserver/plane/graphql/queries/module.py +++ b/apiserver/plane/graphql/queries/module.py @@ -13,8 +13,8 @@ from strawberry.scalars import JSON from strawberry.permission import PermissionExtension # Module Imports -from plane.db.models import Module, Issue -from plane.graphql.types.module import ModuleType +from plane.db.models import Module, Issue, ModuleUserProperties +from plane.graphql.types.module import ModuleType, ModuleUserPropertyType from plane.graphql.types.issue import ( IssuesInformationType, IssuesInformationObjectType, @@ -93,6 +93,34 @@ class ModuleQuery: return modules +# module issue user properties +@strawberry.type +class ModuleIssueUserPropertyQuery: + @strawberry.field( + extensions=[PermissionExtension(permissions=[ProjectBasePermission()])] + ) + async def moduleIssueUserProperties( + self, + info: Info, + slug: str, + project: strawberry.ID, + module: strawberry.ID, + ) -> ModuleUserPropertyType: + module_issue_property = await sync_to_async( + lambda: ModuleUserProperties.objects.filter( + workspace__slug=slug, project_id=project, module_id=module + ) + .filter( + project__project_projectmember__member=info.context.user, + project__project_projectmember__is_active=True, + ) + .order_by("-created_at") + .first() + )() + + return module_issue_property + + # module issues information query @strawberry.type class ModuleIssuesInformationQuery: diff --git a/apiserver/plane/graphql/queries/notification.py b/apiserver/plane/graphql/queries/notification.py index 512cf9ed1c..0576caa55d 100644 --- a/apiserver/plane/graphql/queries/notification.py +++ b/apiserver/plane/graphql/queries/notification.py @@ -28,7 +28,6 @@ from typing import Optional, List @strawberry.type class NotificationQuery: - @strawberry.field( extensions=[ PermissionExtension(permissions=[WorkspaceBasePermission()]) diff --git a/apiserver/plane/graphql/queries/project.py b/apiserver/plane/graphql/queries/project.py index a141c1b2ca..35d323745f 100644 --- a/apiserver/plane/graphql/queries/project.py +++ b/apiserver/plane/graphql/queries/project.py @@ -71,6 +71,50 @@ class ProjectQuery: return paginate(results_object=project, cursor=cursor) + @strawberry.field( + extensions=[ + PermissionExtension(permissions=[WorkspaceBasePermission()]) + ] + ) + async def project( + self, + info: Info, + slug: str, + project: strawberry.ID, + ) -> Optional[ProjectType]: + def get_project() -> Optional[ProjectType]: + return ( + Project.objects.filter( + workspace__slug=slug, + pk=project, + archived_at__isnull=True, + ) + .annotate( + is_favorite=Exists( + UserFavorite.objects.filter( + user=info.context.user, + entity_identifier=OuterRef("pk"), + entity_type="project", + project_id=OuterRef("pk"), + ) + ) + ) + .annotate( + is_member=Exists( + ProjectMember.objects.filter( + member=info.context.user, + project_id=OuterRef("pk"), + workspace__slug=slug, + is_active=True, + ) + ) + ) + .first() + ) + + project = await sync_to_async(get_project)() + return project + @strawberry.type class ProjectMembersQuery: diff --git a/apiserver/plane/graphql/queries/workspace.py b/apiserver/plane/graphql/queries/workspace.py index 9856571d6f..f0d889e13a 100644 --- a/apiserver/plane/graphql/queries/workspace.py +++ b/apiserver/plane/graphql/queries/workspace.py @@ -158,7 +158,8 @@ class YourWorkQuery: projects = await sync_to_async(list)( Project.objects.filter(workspace__slug=slug) .filter( - Q( + Q(created_by=info.context.user) + & Q( project_projectmember__member=info.context.user, project_projectmember__is_active=True, ) diff --git a/apiserver/plane/graphql/schema.py b/apiserver/plane/graphql/schema.py index a4b1fc7078..5142afece2 100644 --- a/apiserver/plane/graphql/schema.py +++ b/apiserver/plane/graphql/schema.py @@ -30,11 +30,13 @@ from .queries.cycle import ( CycleQuery, CycleIssuesInformationQuery, CycleIssueQuery, + CycleIssueUserPropertyQuery, ) from .queries.module import ( ModuleQuery, ModuleIssuesInformationQuery, ModuleIssueQuery, + ModuleIssueUserPropertyQuery, ) from .queries.search import ProjectSearchQuery from .queries.attachment import IssueAttachmentQuery @@ -52,13 +54,21 @@ from .mutations.issue import ( IssueMutation, IssueUserPropertyMutation, IssueAttachmentMutation, - IssueSubscriptionMutation + IssueSubscriptionMutation, ) from .mutations.notification import NotificationMutation from .mutations.user import ProfileMutation from .mutations.page import PageFavoriteMutation -from .mutations.cycle import CycleIssueMutation, CycleFavoriteMutation -from .mutations.module import ModuleIssueMutation, ModuleFavoriteMutation +from .mutations.cycle import ( + CycleIssueMutation, + CycleFavoriteMutation, + CycleIssueUserPropertyMutation, +) +from .mutations.module import ( + ModuleIssueMutation, + ModuleFavoriteMutation, + ModuleIssueUserPropertyMutation, +) from .mutations.link import IssueLinkMutation from .mutations.favorite import UserFavoriteMutation @@ -102,6 +112,8 @@ class Query( IssueTypesTypeQuery, EstimatePointQuery, UserPageQuery, + CycleIssueUserPropertyQuery, + ModuleIssueUserPropertyQuery, ): pass @@ -127,6 +139,8 @@ class Mutation( CycleFavoriteMutation, ModuleFavoriteMutation, UserFavoriteMutation, + CycleIssueUserPropertyMutation, + ModuleIssueUserPropertyMutation, ): pass diff --git a/apiserver/plane/graphql/types/cycle.py b/apiserver/plane/graphql/types/cycle.py index d0b033d3d3..c5cd4b7691 100644 --- a/apiserver/plane/graphql/types/cycle.py +++ b/apiserver/plane/graphql/types/cycle.py @@ -13,7 +13,7 @@ from asgiref.sync import sync_to_async # Module Imports -from plane.db.models import Cycle, Issue +from plane.db.models import Cycle, Issue, CycleUserProperties from plane.graphql.types.users import UserType @@ -83,3 +83,31 @@ class CycleType: .count() )() return issue_assignees_count + + +@strawberry_django.type(CycleUserProperties) +class CycleUserPropertyType: + display_filters: JSON + display_properties: JSON + filters: JSON + id: strawberry.ID + user: strawberry.ID + workspace: strawberry.ID + project: strawberry.ID + cycle: strawberry.ID + + @strawberry.field + def user(self) -> int: + return self.user_id + + @strawberry.field + def workspace(self) -> int: + return self.workspace_id + + @strawberry.field + def project(self) -> int: + return self.project_id + + @strawberry.field + def cycle(self) -> int: + return self.cycle_id diff --git a/apiserver/plane/graphql/types/module.py b/apiserver/plane/graphql/types/module.py index 47ef874034..1ec6087449 100644 --- a/apiserver/plane/graphql/types/module.py +++ b/apiserver/plane/graphql/types/module.py @@ -9,7 +9,7 @@ from strawberry.types import Info from strawberry.scalars import JSON # Module Imports -from plane.db.models import Module, Issue +from plane.db.models import Module, Issue, ModuleUserProperties from plane.graphql.types.users import UserType # Third-party library imports @@ -85,3 +85,31 @@ class ModuleType: .count() )() return issue_assignees_count + + +@strawberry_django.type(ModuleUserProperties) +class ModuleUserPropertyType: + display_filters: JSON + display_properties: JSON + filters: JSON + id: strawberry.ID + user: strawberry.ID + workspace: strawberry.ID + project: strawberry.ID + module: strawberry.ID + + @strawberry.field + def user(self) -> int: + return self.user_id + + @strawberry.field + def workspace(self) -> int: + return self.workspace_id + + @strawberry.field + def project(self) -> int: + return self.project_id + + @strawberry.field + def module(self) -> int: + return self.module_id diff --git a/apiserver/plane/graphql/types/notification.py b/apiserver/plane/graphql/types/notification.py index 6a2c32370c..b25d94e034 100644 --- a/apiserver/plane/graphql/types/notification.py +++ b/apiserver/plane/graphql/types/notification.py @@ -9,6 +9,8 @@ from strawberry.scalars import JSON # Module imports from plane.db.models import Notification +from plane.graphql.types.users import UserType +from plane.graphql.types.project import ProjectType @strawberry_django.type(Notification) @@ -19,7 +21,7 @@ class NotificationType: message_html = Optional[str] message_stripped = Optional[str] sender: str - triggered_by: strawberry.ID + triggered_by: Optional[UserType] receiver: strawberry.ID read_at: Optional[datetime] snoozed_till: Optional[datetime] @@ -28,7 +30,7 @@ class NotificationType: entity_identifier: strawberry.ID data: JSON workspace: strawberry.ID - project: strawberry.ID + project: Optional[ProjectType] created_at: datetime updated_at: datetime @@ -36,14 +38,6 @@ class NotificationType: def workspace(self) -> int: return self.workspace_id - @strawberry.field - def project(self) -> int: - return self.project_id - - @strawberry.field - def triggered_by(self) -> int: - return self.triggered_by_id - @strawberry.field def receiver(self) -> int: return self.receiver_id diff --git a/apiserver/plane/graphql/types/users.py b/apiserver/plane/graphql/types/users.py index 6f92ff9081..064b05d5dc 100644 --- a/apiserver/plane/graphql/types/users.py +++ b/apiserver/plane/graphql/types/users.py @@ -109,7 +109,7 @@ class UserFavoriteEntityData: class UserFavoriteType: id: strawberry.ID entity_type: str - entity_identifier: str + entity_identifier: Optional[str] name: Optional[str] is_folder: bool sequence: float @@ -214,7 +214,7 @@ class UserRecentVisitType: @strawberry.field def project(self) -> int: return self.project_id - + @strawberry.field def user(self) -> int: return self.user_id