From 0af0f3e4e5df243e90667fadae2a4be4a263c580 Mon Sep 17 00:00:00 2001 From: cbolles Date: Tue, 16 Jan 2024 15:57:52 -0500 Subject: [PATCH 1/3] Add the ability to query for roles --- .../src/components/SideBar.component.tsx | 37 +++++++++++------- packages/server/schema.gql | 9 +++++ .../src/permission/models/permission.model.ts | 19 +++++++++ .../src/permission/permission.module.ts | 4 +- .../src/permission/permission.service.ts | 13 +++++++ .../resolvers/permission.resolver.ts | 39 +++++++++++++++++++ 6 files changed, 105 insertions(+), 16 deletions(-) create mode 100644 packages/server/src/permission/models/permission.model.ts create mode 100644 packages/server/src/permission/resolvers/permission.resolver.ts diff --git a/packages/client/src/components/SideBar.component.tsx b/packages/client/src/components/SideBar.component.tsx index 91fcbdc4..00e4108a 100644 --- a/packages/client/src/components/SideBar.component.tsx +++ b/packages/client/src/components/SideBar.component.tsx @@ -19,43 +19,48 @@ export const SideBar: FC = ({ open, drawerWidth }) => { name: 'Projects', icon: , action: () => {}, + visible: () => true, subItems: [ - { name: 'New Project', action: () => navigate('/project/new') }, - { name: 'Project Control', action: () => navigate('/project/controls') }, - { name: 'User Permissions', action: () => navigate('/project/permissions') } + { name: 'New Project', action: () => navigate('/project/new'), visible: () => true }, + { name: 'Project Control', action: () => navigate('/project/controls'), visible: () => true }, + { name: 'User Permissions', action: () => navigate('/project/permissions'), visible: () => true }, ] }, { name: 'Studies', action: () => {}, icon: , + visible: () => true, subItems: [ - { name: 'New Study', action: () => navigate('/study/new') }, - { name: 'Study Control', action: () => navigate('/study/controls') }, - { name: 'User Permissions', action: () => navigate('/study/permissions') }, - { name: 'Entry Controls', action: () => navigate('/study/controls') }, - { name: 'Download Tags', action: () => navigate('/study/tags') } + { name: 'New Study', action: () => navigate('/study/new'), visible: () => true }, + { name: 'Study Control', action: () => navigate('/study/controls'), visible: () => true }, + { name: 'User Permissions', action: () => navigate('/study/permissions'), visible: () => true }, + { name: 'Entry Controls', action: () => navigate('/study/controls'), visible: () => true }, + { name: 'Download Tags', action: () => navigate('/study/tags'), visible: () => true }, ] }, { name: 'Datasets', action: () => {}, icon: , + visible: () => true, subItems: [ - { name: 'Dataset Control', action: () => navigate('/dataset/controls') }, - { name: 'Project Access', action: () => navigate('/dataset/projectaccess') } + { name: 'Dataset Control', action: () => navigate('/dataset/controls'), visible: () => true }, + { name: 'Project Access', action: () => navigate('/dataset/projectaccess'), visible: () => true }, ] }, { name: 'Contribute', action: () => {}, icon: , - subItems: [{ name: 'Tag in Study', action: () => navigate('/contribute/landing') }] + visible: () => true, + subItems: [{ name: 'Tag in Study', action: () => navigate('/contribute/landing'), visible: () => true }] }, { name: 'Logout', action: logout, - icon: + icon: , + visible: () => true } ]; @@ -78,9 +83,10 @@ export const SideBar: FC = ({ open, drawerWidth }) => { open={open} > - {navItems.map((navItem) => ( - - ))} + {navItems + .filter((navItem) => navItem.visible()) + .map((navItem) => ) + } @@ -92,6 +98,7 @@ interface NavItemProps { name: string; icon?: ReactNode; subItems?: NavItemProps[]; + visible: () => boolean; } const NavItem: FC = ({ action, name, icon, subItems }) => { diff --git a/packages/server/schema.gql b/packages/server/schema.gql index 00e763c6..aab1322f 100644 --- a/packages/server/schema.gql +++ b/packages/server/schema.gql @@ -73,6 +73,14 @@ type DatasetProjectPermission { projectHasAccess: Boolean! } +type Permission { + owner: Boolean! + projectAdmin: Boolean! + studyAdmin: Boolean! + trainedContributor: Boolean! + contributor: Boolean! +} + type Entry { _id: String! organization: ID! @@ -137,6 +145,7 @@ type Query { getProjectPermissions(project: ID!): [ProjectPermissionModel!]! getStudyPermissions(study: ID!): [StudyPermissionModel!]! getDatasetProjectPermissions(project: ID!): [DatasetProjectPermission!]! + getRoles(project: ID, study: ID): Permission! projectExists(name: String!): Boolean! getProjects: [Project!]! studyExists(name: String!, project: ID!): Boolean! diff --git a/packages/server/src/permission/models/permission.model.ts b/packages/server/src/permission/models/permission.model.ts new file mode 100644 index 00000000..1f20d3e7 --- /dev/null +++ b/packages/server/src/permission/models/permission.model.ts @@ -0,0 +1,19 @@ +import { ObjectType, Field } from '@nestjs/graphql'; + +@ObjectType() +export class Permission { + @Field() + owner: boolean; + + @Field() + projectAdmin: boolean; + + @Field() + studyAdmin: boolean; + + @Field() + trainedContributor: boolean; + + @Field() + contributor: boolean; +} diff --git a/packages/server/src/permission/permission.module.ts b/packages/server/src/permission/permission.module.ts index a0f123f2..bbe82ac0 100644 --- a/packages/server/src/permission/permission.module.ts +++ b/packages/server/src/permission/permission.module.ts @@ -9,6 +9,7 @@ import { OwnerPermissionResolver } from './resolvers/owner.resolver'; import { StudyPermissionResolver } from './resolvers/study.resolver'; import { DatasetPermissionResolver } from './resolvers/dataset.resolver'; import { DatasetModule } from '../dataset/dataset.module'; +import { PermissionResolver } from './resolvers/permission.resolver'; @Module({ imports: [ @@ -23,7 +24,8 @@ import { DatasetModule } from '../dataset/dataset.module'; ProjectPermissionResolver, OwnerPermissionResolver, StudyPermissionResolver, - DatasetPermissionResolver + DatasetPermissionResolver, + PermissionResolver ], exports: [casbinProvider] }) diff --git a/packages/server/src/permission/permission.service.ts b/packages/server/src/permission/permission.service.ts index 242f5870..3ba9e9f0 100644 --- a/packages/server/src/permission/permission.service.ts +++ b/packages/server/src/permission/permission.service.ts @@ -11,6 +11,8 @@ import { StudyPermissionModel } from './models/study.model'; import { Dataset } from '../dataset/dataset.model'; import { DatasetService } from '../dataset/dataset.service'; import { DatasetProjectPermission } from './models/dataset.model'; +import {Permission} from './models/permission.model'; +import {Organization} from '../organization/organization.model'; @Injectable() export class PermissionService { @@ -195,4 +197,15 @@ export class PermissionService { }) ); } + + async getRoles(user: TokenPayload, organization: Organization, project: Project | null, study: Study | null): Promise { + + return { + owner: await this.enforcer.enforce(user.id, Roles.OWNER, organization._id.toString()), + projectAdmin: project ? await this.enforcer.enforce(user.id, Roles.PROJECT_ADMIN, project._id.toString()) : false, + studyAdmin: study ? await this.enforcer.enforce(user.id, Roles.STUDY_ADMIN, study._id.toString()) : false, + trainedContributor: study ? await this.enforcer.enforce(user.id, Roles.TRAINED_CONTRIBUTOR, study._id.toString()) : false, + contributor: study ? await this.enforcer.enforce(user.id, Roles.CONTRIBUTOR, study._id.toString()) : false + }; + } } diff --git a/packages/server/src/permission/resolvers/permission.resolver.ts b/packages/server/src/permission/resolvers/permission.resolver.ts new file mode 100644 index 00000000..04605e3b --- /dev/null +++ b/packages/server/src/permission/resolvers/permission.resolver.ts @@ -0,0 +1,39 @@ +import { Resolver, Query, Args, ID } from '@nestjs/graphql'; +import { StudyPipe } from '../../study/pipes/study.pipe'; +import { ProjectPipe } from '../../project/pipes/project.pipe'; +import { TokenContext } from '../../jwt/token.context'; +import { Permission } from '../models/permission.model'; +import { TokenPayload } from '../../jwt/token.dto'; +import { Study } from '../../study/study.model'; +import { Project } from '../../project/project.model'; +import { PermissionService } from '../permission.service'; +import { OrganizationContext } from '../../organization/organization.context'; +import { Organization } from '../../organization/organization.model'; +import { UseGuards } from '@nestjs/common'; +import { JwtAuthGuard } from '../../jwt/jwt.guard'; + +@UseGuards(JwtAuthGuard) +@Resolver() +export class PermissionResolver { + constructor(private readonly studyPipe: StudyPipe, + private readonly projectPipe: ProjectPipe, + private readonly permissionService: PermissionService) {} + + @Query(() => Permission) + async getRoles(@Args('project', { type: () => ID, nullable: true }) projectID: string | null, + @Args('study', { type: () => ID, nullable: true }) studyID: string | null, + @TokenContext() tokenContext: TokenPayload, + @OrganizationContext() organization: Organization): Promise { + let project: Project | null = null; + let study: Study | null = null; + + if (projectID) { + project = await this.projectPipe.transform(projectID); + } + if (studyID) { + study = await this.studyPipe.transform(studyID); + } + + return this.permissionService.getRoles(tokenContext, organization, project, study); + } +} From 5b5781507f38262e0352ae2ee47a20fe9d82746e Mon Sep 17 00:00:00 2001 From: cbolles Date: Tue, 16 Jan 2024 16:30:35 -0500 Subject: [PATCH 2/3] Working dynamic navigation --- .../src/components/SideBar.component.tsx | 76 ++++++++++++------- packages/client/src/graphql/graphql.ts | 16 ++++ .../src/graphql/permission/permission.graphql | 10 +++ .../src/graphql/permission/permission.ts | 50 +++++++++++- 4 files changed, 124 insertions(+), 28 deletions(-) diff --git a/packages/client/src/components/SideBar.component.tsx b/packages/client/src/components/SideBar.component.tsx index 00e4108a..e75177ee 100644 --- a/packages/client/src/components/SideBar.component.tsx +++ b/packages/client/src/components/SideBar.component.tsx @@ -1,9 +1,13 @@ -import { FC, ReactNode, useState } from 'react'; +import { FC, ReactNode, useEffect, useState } from 'react'; import { Collapse, Divider, Drawer, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'; import { ExpandMore, ExpandLess, School, Dataset, Work, Logout, GroupWork } from '@mui/icons-material'; import { useAuth } from '../context/Auth.context'; import { useNavigate } from 'react-router-dom'; import { Environment } from './Environment.component'; +import { Permission } from '../graphql/graphql'; +import { useGetRolesQuery } from '../graphql/permission/permission'; +import { useProject } from '../context/Project.context'; +import { useStudy } from '../context/Study.context'; interface SideBarProps { open: boolean; @@ -13,48 +17,62 @@ interface SideBarProps { export const SideBar: FC = ({ open, drawerWidth }) => { const { logout } = useAuth(); const navigate = useNavigate(); + const [permission, setPermission] = useState(null); + const { project } = useProject(); + const { study } = useStudy(); + const rolesQueryResults = useGetRolesQuery({ variables: { project: project?._id, study: study?._id } }); + + useEffect(() => { + if (rolesQueryResults.data) { + setPermission(rolesQueryResults.data.getRoles); + } + }, [rolesQueryResults.data]); const navItems: NavItemProps[] = [ { name: 'Projects', icon: , action: () => {}, - visible: () => true, + visible: (p) => p!.owner || p!.projectAdmin, + permission, subItems: [ - { name: 'New Project', action: () => navigate('/project/new'), visible: () => true }, - { name: 'Project Control', action: () => navigate('/project/controls'), visible: () => true }, - { name: 'User Permissions', action: () => navigate('/project/permissions'), visible: () => true }, + { name: 'New Project', action: () => navigate('/project/new'), visible: (p) => p!.owner }, + { name: 'Project Control', action: () => navigate('/project/controls'), visible: (p) => p!.owner }, + { name: 'User Permissions', action: () => navigate('/project/permissions'), visible: (p) => p!.projectAdmin }, ] }, { name: 'Studies', action: () => {}, icon: , - visible: () => true, + visible: (p) => p!.projectAdmin || p!.studyAdmin, + permission, subItems: [ - { name: 'New Study', action: () => navigate('/study/new'), visible: () => true }, - { name: 'Study Control', action: () => navigate('/study/controls'), visible: () => true }, - { name: 'User Permissions', action: () => navigate('/study/permissions'), visible: () => true }, - { name: 'Entry Controls', action: () => navigate('/study/controls'), visible: () => true }, - { name: 'Download Tags', action: () => navigate('/study/tags'), visible: () => true }, + { name: 'New Study', action: () => navigate('/study/new'), visible: (p) => p!.projectAdmin }, + { name: 'Study Control', action: () => navigate('/study/controls'), visible: (p) => p!.projectAdmin }, + { name: 'User Permissions', action: () => navigate('/study/permissions'), visible: (p) => p!.studyAdmin }, + { name: 'Entry Controls', action: () => navigate('/study/controls'), visible: (p) => p!.studyAdmin }, + { name: 'Download Tags', action: () => navigate('/study/tags'), visible: (p) => p!.studyAdmin } ] }, { name: 'Datasets', action: () => {}, icon: , - visible: () => true, + visible: (p) => p!.owner, + permission, subItems: [ - { name: 'Dataset Control', action: () => navigate('/dataset/controls'), visible: () => true }, - { name: 'Project Access', action: () => navigate('/dataset/projectaccess'), visible: () => true }, + { name: 'Dataset Control', action: () => navigate('/dataset/controls'), visible: (p) => p!.owner }, + { name: 'Project Access', action: () => navigate('/dataset/projectaccess'), visible: (p) => p!.owner }, ] }, { name: 'Contribute', action: () => {}, icon: , - visible: () => true, - subItems: [{ name: 'Tag in Study', action: () => navigate('/contribute/landing'), visible: () => true }] + permission, + visible: (p) => p!.contributor, + subItems: [{ name: 'Tag in Study', action: () => navigate('/contribute/landing'), visible: (p) => p!.contributor }] }, { name: 'Logout', @@ -82,12 +100,14 @@ export const SideBar: FC = ({ open, drawerWidth }) => { anchor="left" open={open} > - - {navItems - .filter((navItem) => navItem.visible()) - .map((navItem) => ) - } - + {permission && ( + + {navItems + .filter((navItem) => navItem.visible(permission)) + .map((navItem) => ) + } + + )} ); @@ -98,10 +118,11 @@ interface NavItemProps { name: string; icon?: ReactNode; subItems?: NavItemProps[]; - visible: () => boolean; + permission?: Permission | null; + visible: (permission: Permission | null | undefined) => boolean; } -const NavItem: FC = ({ action, name, icon, subItems }) => { +const NavItem: FC = ({ action, name, icon, subItems, permission }) => { const isExpandable = subItems && subItems.length > 0; const [open, setOpen] = useState(false); @@ -114,9 +135,10 @@ const NavItem: FC = ({ action, name, icon, subItems }) => { - {subItems.map((item, index) => ( - - ))} + {subItems + .filter((subItem) => subItem.visible(permission)) + .map((item, index) => ) + } ) : null; diff --git a/packages/client/src/graphql/graphql.ts b/packages/client/src/graphql/graphql.ts index 498d85ef..ced0238e 100644 --- a/packages/client/src/graphql/graphql.ts +++ b/packages/client/src/graphql/graphql.ts @@ -461,6 +461,15 @@ export type OrganizationCreate = { projectId: Scalars['String']['input']; }; +export type Permission = { + __typename?: 'Permission'; + contributor: Scalars['Boolean']['output']; + owner: Scalars['Boolean']['output']; + projectAdmin: Scalars['Boolean']['output']; + studyAdmin: Scalars['Boolean']['output']; + trainedContributor: Scalars['Boolean']['output']; +}; + export type Project = { __typename?: 'Project'; _id: Scalars['ID']['output']; @@ -548,6 +557,7 @@ export type Query = { getProject: ProjectModel; getProjectPermissions: Array; getProjects: Array; + getRoles: Permission; getStudyPermissions: Array; getUser: UserModel; invite: InviteModel; @@ -613,6 +623,12 @@ export type QueryGetProjectPermissionsArgs = { }; +export type QueryGetRolesArgs = { + project?: InputMaybe; + study?: InputMaybe; +}; + + export type QueryGetStudyPermissionsArgs = { study: Scalars['ID']['input']; }; diff --git a/packages/client/src/graphql/permission/permission.graphql b/packages/client/src/graphql/permission/permission.graphql index 95dc0fc8..8b9e12b6 100644 --- a/packages/client/src/graphql/permission/permission.graphql +++ b/packages/client/src/graphql/permission/permission.graphql @@ -68,3 +68,13 @@ query getDatasetProjectPermissions($project: ID!) { mutation grantProjectDatasetAccess($project: ID!, $dataset: ID!, $hasAccess: Boolean!) { grantProjectDatasetAccess(project: $project, dataset: $dataset, hasAccess: $hasAccess) } + +query getRoles($project: ID, $study: ID) { + getRoles(project: $project, study: $study) { + owner, + projectAdmin, + studyAdmin, + trainedContributor, + contributor + } +} diff --git a/packages/client/src/graphql/permission/permission.ts b/packages/client/src/graphql/permission/permission.ts index 6408aaa3..bd4dbdd7 100644 --- a/packages/client/src/graphql/permission/permission.ts +++ b/packages/client/src/graphql/permission/permission.ts @@ -71,6 +71,14 @@ export type GrantProjectDatasetAccessMutationVariables = Types.Exact<{ export type GrantProjectDatasetAccessMutation = { __typename?: 'Mutation', grantProjectDatasetAccess: boolean }; +export type GetRolesQueryVariables = Types.Exact<{ + project?: Types.InputMaybe; + study?: Types.InputMaybe; +}>; + + +export type GetRolesQuery = { __typename?: 'Query', getRoles: { __typename?: 'Permission', owner: boolean, projectAdmin: boolean, studyAdmin: boolean, trainedContributor: boolean, contributor: boolean } }; + export const GetProjectPermissionsDocument = gql` query getProjectPermissions($project: ID!) { @@ -378,4 +386,44 @@ export function useGrantProjectDatasetAccessMutation(baseOptions?: Apollo.Mutati } export type GrantProjectDatasetAccessMutationHookResult = ReturnType; export type GrantProjectDatasetAccessMutationResult = Apollo.MutationResult; -export type GrantProjectDatasetAccessMutationOptions = Apollo.BaseMutationOptions; \ No newline at end of file +export type GrantProjectDatasetAccessMutationOptions = Apollo.BaseMutationOptions; +export const GetRolesDocument = gql` + query getRoles($project: ID, $study: ID) { + getRoles(project: $project, study: $study) { + owner + projectAdmin + studyAdmin + trainedContributor + contributor + } +} + `; + +/** + * __useGetRolesQuery__ + * + * To run a query within a React component, call `useGetRolesQuery` and pass it any options that fit your needs. + * When your component renders, `useGetRolesQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetRolesQuery({ + * variables: { + * project: // value for 'project' + * study: // value for 'study' + * }, + * }); + */ +export function useGetRolesQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetRolesDocument, options); + } +export function useGetRolesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetRolesDocument, options); + } +export type GetRolesQueryHookResult = ReturnType; +export type GetRolesLazyQueryHookResult = ReturnType; +export type GetRolesQueryResult = Apollo.QueryResult; \ No newline at end of file From ffa133668092475910f3fee6f5d00e69f8a801e3 Mon Sep 17 00:00:00 2001 From: cbolles Date: Tue, 16 Jan 2024 16:31:47 -0500 Subject: [PATCH 3/3] Fix formatting --- .../src/components/SideBar.component.tsx | 18 +++++++++++------- .../src/permission/permission.service.ts | 16 +++++++++++----- .../resolvers/permission.resolver.ts | 18 +++++++++++------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/packages/client/src/components/SideBar.component.tsx b/packages/client/src/components/SideBar.component.tsx index e75177ee..ab1cc280 100644 --- a/packages/client/src/components/SideBar.component.tsx +++ b/packages/client/src/components/SideBar.component.tsx @@ -38,7 +38,7 @@ export const SideBar: FC = ({ open, drawerWidth }) => { subItems: [ { name: 'New Project', action: () => navigate('/project/new'), visible: (p) => p!.owner }, { name: 'Project Control', action: () => navigate('/project/controls'), visible: (p) => p!.owner }, - { name: 'User Permissions', action: () => navigate('/project/permissions'), visible: (p) => p!.projectAdmin }, + { name: 'User Permissions', action: () => navigate('/project/permissions'), visible: (p) => p!.projectAdmin } ] }, { @@ -63,7 +63,7 @@ export const SideBar: FC = ({ open, drawerWidth }) => { permission, subItems: [ { name: 'Dataset Control', action: () => navigate('/dataset/controls'), visible: (p) => p!.owner }, - { name: 'Project Access', action: () => navigate('/dataset/projectaccess'), visible: (p) => p!.owner }, + { name: 'Project Access', action: () => navigate('/dataset/projectaccess'), visible: (p) => p!.owner } ] }, { @@ -72,7 +72,9 @@ export const SideBar: FC = ({ open, drawerWidth }) => { icon: , permission, visible: (p) => p!.contributor, - subItems: [{ name: 'Tag in Study', action: () => navigate('/contribute/landing'), visible: (p) => p!.contributor }] + subItems: [ + { name: 'Tag in Study', action: () => navigate('/contribute/landing'), visible: (p) => p!.contributor } + ] }, { name: 'Logout', @@ -104,8 +106,9 @@ export const SideBar: FC = ({ open, drawerWidth }) => { {navItems .filter((navItem) => navItem.visible(permission)) - .map((navItem) => ) - } + .map((navItem) => ( + + ))} )} @@ -137,8 +140,9 @@ const NavItem: FC = ({ action, name, icon, subItems, permission }) {subItems .filter((subItem) => subItem.visible(permission)) - .map((item, index) => ) - } + .map((item, index) => ( + + ))} ) : null; diff --git a/packages/server/src/permission/permission.service.ts b/packages/server/src/permission/permission.service.ts index 3ba9e9f0..c66d8d31 100644 --- a/packages/server/src/permission/permission.service.ts +++ b/packages/server/src/permission/permission.service.ts @@ -11,8 +11,8 @@ import { StudyPermissionModel } from './models/study.model'; import { Dataset } from '../dataset/dataset.model'; import { DatasetService } from '../dataset/dataset.service'; import { DatasetProjectPermission } from './models/dataset.model'; -import {Permission} from './models/permission.model'; -import {Organization} from '../organization/organization.model'; +import { Permission } from './models/permission.model'; +import { Organization } from '../organization/organization.model'; @Injectable() export class PermissionService { @@ -198,13 +198,19 @@ export class PermissionService { ); } - async getRoles(user: TokenPayload, organization: Organization, project: Project | null, study: Study | null): Promise { - + async getRoles( + user: TokenPayload, + organization: Organization, + project: Project | null, + study: Study | null + ): Promise { return { owner: await this.enforcer.enforce(user.id, Roles.OWNER, organization._id.toString()), projectAdmin: project ? await this.enforcer.enforce(user.id, Roles.PROJECT_ADMIN, project._id.toString()) : false, studyAdmin: study ? await this.enforcer.enforce(user.id, Roles.STUDY_ADMIN, study._id.toString()) : false, - trainedContributor: study ? await this.enforcer.enforce(user.id, Roles.TRAINED_CONTRIBUTOR, study._id.toString()) : false, + trainedContributor: study + ? await this.enforcer.enforce(user.id, Roles.TRAINED_CONTRIBUTOR, study._id.toString()) + : false, contributor: study ? await this.enforcer.enforce(user.id, Roles.CONTRIBUTOR, study._id.toString()) : false }; } diff --git a/packages/server/src/permission/resolvers/permission.resolver.ts b/packages/server/src/permission/resolvers/permission.resolver.ts index 04605e3b..2a17c610 100644 --- a/packages/server/src/permission/resolvers/permission.resolver.ts +++ b/packages/server/src/permission/resolvers/permission.resolver.ts @@ -15,15 +15,19 @@ import { JwtAuthGuard } from '../../jwt/jwt.guard'; @UseGuards(JwtAuthGuard) @Resolver() export class PermissionResolver { - constructor(private readonly studyPipe: StudyPipe, - private readonly projectPipe: ProjectPipe, - private readonly permissionService: PermissionService) {} + constructor( + private readonly studyPipe: StudyPipe, + private readonly projectPipe: ProjectPipe, + private readonly permissionService: PermissionService + ) {} @Query(() => Permission) - async getRoles(@Args('project', { type: () => ID, nullable: true }) projectID: string | null, - @Args('study', { type: () => ID, nullable: true }) studyID: string | null, - @TokenContext() tokenContext: TokenPayload, - @OrganizationContext() organization: Organization): Promise { + async getRoles( + @Args('project', { type: () => ID, nullable: true }) projectID: string | null, + @Args('study', { type: () => ID, nullable: true }) studyID: string | null, + @TokenContext() tokenContext: TokenPayload, + @OrganizationContext() organization: Organization + ): Promise { let project: Project | null = null; let study: Study | null = null;