[permissions V2] Add integration tests on relations and objectRecord permissions (#12450)
In this PR 1. adding tests on relations and nested relations to make sure that if any permission is missing, the query fails 2. adding tests on objectRecord permissions to make sure that permissions granted or restricted by objectPermissions take precedence on the role's allObjectRecords permissions
This commit is contained in:
@ -101,6 +101,7 @@ export abstract class GraphqlQueryBaseResolverService<
|
||||
} else {
|
||||
if (!isPermissionsV2Enabled)
|
||||
await this.validateObjectRecordPermissionsOrThrow({
|
||||
objectMetadataId: objectMetadataItemWithFieldMaps.id,
|
||||
operationName,
|
||||
options,
|
||||
});
|
||||
@ -219,9 +220,11 @@ export abstract class GraphqlQueryBaseResolverService<
|
||||
}
|
||||
|
||||
private async validateObjectRecordPermissionsOrThrow({
|
||||
objectMetadataId,
|
||||
operationName,
|
||||
options,
|
||||
}: {
|
||||
objectMetadataId: string;
|
||||
operationName: WorkspaceResolverBuilderMethodNames;
|
||||
options: WorkspaceQueryRunnerOptions;
|
||||
}) {
|
||||
@ -234,6 +237,7 @@ export abstract class GraphqlQueryBaseResolverService<
|
||||
requiredPermission,
|
||||
workspaceId: options.authContext.workspace.id,
|
||||
isExecutedByApiKey: isDefined(options.authContext.apiKey),
|
||||
objectMetadataId,
|
||||
});
|
||||
|
||||
if (!userHasPermission) {
|
||||
|
||||
@ -226,11 +226,13 @@ export class PermissionsService {
|
||||
workspaceId,
|
||||
requiredPermission,
|
||||
isExecutedByApiKey,
|
||||
objectMetadataId,
|
||||
}: {
|
||||
userWorkspaceId?: string;
|
||||
workspaceId: string;
|
||||
requiredPermission: PermissionsOnAllObjectRecords;
|
||||
isExecutedByApiKey: boolean;
|
||||
objectMetadataId: string;
|
||||
}): Promise<boolean> {
|
||||
const isPermissionsV2Enabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
@ -279,11 +281,10 @@ export class PermissionsService {
|
||||
const objectPermissionKey =
|
||||
this.getObjectPermissionKeyForRequiredPermission(requiredPermission);
|
||||
|
||||
// until permissions V2 is enabled all objects have the same permission values deriving from role, ex role.canReadAllObjectRecords
|
||||
const objectPermissionValue =
|
||||
rolePermissionsForUserWorkspaceRole[
|
||||
Object.keys(rolePermissionsForUserWorkspaceRole)[0]
|
||||
]?.[objectPermissionKey];
|
||||
rolePermissionsForUserWorkspaceRole[objectMetadataId]?.[
|
||||
objectPermissionKey
|
||||
];
|
||||
|
||||
return objectPermissionValue === true;
|
||||
}
|
||||
|
||||
@ -0,0 +1,196 @@
|
||||
import { default as request } from 'supertest';
|
||||
import { createCustomRoleWithObjectPermissions } from 'test/integration/graphql/utils/create-custom-role-with-object-permissions.util';
|
||||
import { deleteRole } from 'test/integration/graphql/utils/delete-one-role.util';
|
||||
import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util';
|
||||
import { makeGraphqlAPIRequestWithMemberRole as makeGraphqlAPIRequestWithJony } from 'test/integration/graphql/utils/make-graphql-api-request-with-member-role.util';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||
import { updateWorkspaceMemberRole } from 'test/integration/graphql/utils/update-workspace-member-role.util';
|
||||
|
||||
import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces';
|
||||
import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members';
|
||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||
|
||||
const client = request(`http://localhost:${APP_PORT}`);
|
||||
|
||||
describe('granularObjectRecordsPermissions', () => {
|
||||
describe('permissions V2 enabled', () => {
|
||||
let originalMemberRoleId: string;
|
||||
let customRoleId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Enable Permissions V2
|
||||
const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||
SEED_APPLE_WORKSPACE_ID,
|
||||
'IS_PERMISSIONS_V2_ENABLED',
|
||||
true,
|
||||
);
|
||||
|
||||
await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||
|
||||
// Get the original Member role ID for restoration later
|
||||
const getRolesQuery = {
|
||||
query: `
|
||||
query GetRoles {
|
||||
getRoles {
|
||||
id
|
||||
label
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
const rolesResponse = await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${ADMIN_ACCESS_TOKEN}`)
|
||||
.send(getRolesQuery);
|
||||
|
||||
originalMemberRoleId = rolesResponse.body.data.getRoles.find(
|
||||
(role: any) => role.label === 'Member',
|
||||
).id;
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
const restoreMemberRoleQuery = {
|
||||
query: `
|
||||
mutation UpdateWorkspaceMemberRole {
|
||||
updateWorkspaceMemberRole(
|
||||
workspaceMemberId: "${DEV_SEED_WORKSPACE_MEMBER_IDS.JONY}"
|
||||
roleId: "${originalMemberRoleId}"
|
||||
) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${ADMIN_ACCESS_TOKEN}`)
|
||||
.send(restoreMemberRoleQuery);
|
||||
|
||||
// Disable Permissions V2
|
||||
const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||
SEED_APPLE_WORKSPACE_ID,
|
||||
'IS_PERMISSIONS_V2_ENABLED',
|
||||
false,
|
||||
);
|
||||
|
||||
await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await deleteRole(client, customRoleId);
|
||||
});
|
||||
|
||||
it('should throw permission error when querying person while person reading rights are overriden to false', async () => {
|
||||
// Arrange
|
||||
const { roleId } = await createCustomRoleWithObjectPermissions({
|
||||
label: 'PersonReadRightsExcludedRole',
|
||||
canReadPerson: false,
|
||||
});
|
||||
|
||||
customRoleId = roleId;
|
||||
|
||||
await updateWorkspaceMemberRole({
|
||||
client,
|
||||
roleId: customRoleId,
|
||||
workspaceMemberId: DEV_SEED_WORKSPACE_MEMBER_IDS.JONY,
|
||||
});
|
||||
|
||||
// Act
|
||||
const graphqlOperation = findOneOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
gqlFields: `
|
||||
id
|
||||
city
|
||||
jobTitle
|
||||
`,
|
||||
filter: { city: { eq: 'Seattle' } },
|
||||
});
|
||||
|
||||
const companyGraphqlOperation = findOneOperationFactory({
|
||||
objectMetadataSingularName: 'company',
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
`,
|
||||
filter: { name: { eq: 'Apple' } },
|
||||
});
|
||||
|
||||
const personResponse =
|
||||
await makeGraphqlAPIRequestWithJony(graphqlOperation);
|
||||
|
||||
const companyResponse = await makeGraphqlAPIRequestWithJony(
|
||||
companyGraphqlOperation,
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(personResponse.body.errors).toBeDefined();
|
||||
expect(personResponse.body.errors[0].message).toBe(
|
||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||
);
|
||||
expect(personResponse.body.errors[0].extensions.code).toBe(
|
||||
ErrorCode.FORBIDDEN,
|
||||
);
|
||||
expect(companyResponse.body.data).toBeDefined();
|
||||
expect(companyResponse.body.data.company).toBeDefined();
|
||||
});
|
||||
|
||||
it('should successfully query person when person reading rights are overriden to true', async () => {
|
||||
// Arrange
|
||||
const { roleId } = await createCustomRoleWithObjectPermissions({
|
||||
label: 'PersonRole',
|
||||
canReadPerson: true,
|
||||
hasAllObjectRecordsReadPermission: false,
|
||||
});
|
||||
|
||||
customRoleId = roleId;
|
||||
|
||||
await updateWorkspaceMemberRole({
|
||||
client,
|
||||
roleId: customRoleId,
|
||||
workspaceMemberId: DEV_SEED_WORKSPACE_MEMBER_IDS.JONY,
|
||||
});
|
||||
|
||||
// Act
|
||||
const graphqlOperation = findOneOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
gqlFields: `
|
||||
id
|
||||
city
|
||||
jobTitle
|
||||
`,
|
||||
filter: { city: { eq: 'Seattle' } },
|
||||
});
|
||||
|
||||
const companyGraphqlOperation = findOneOperationFactory({
|
||||
objectMetadataSingularName: 'company',
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
`,
|
||||
filter: { name: { eq: 'Apple' } },
|
||||
});
|
||||
|
||||
const personResponse =
|
||||
await makeGraphqlAPIRequestWithJony(graphqlOperation);
|
||||
|
||||
const companyResponse = await makeGraphqlAPIRequestWithJony(
|
||||
companyGraphqlOperation,
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(personResponse.body.data).toBeDefined();
|
||||
expect(personResponse.body.data.person).toBeDefined();
|
||||
expect(companyResponse.body.errors).toBeDefined();
|
||||
expect(companyResponse.body.errors[0].message).toBe(
|
||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||
);
|
||||
expect(companyResponse.body.errors[0].extensions.code).toBe(
|
||||
ErrorCode.FORBIDDEN,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,252 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
import { default as request } from 'supertest';
|
||||
import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants';
|
||||
import { createCustomRoleWithObjectPermissions } from 'test/integration/graphql/utils/create-custom-role-with-object-permissions.util';
|
||||
import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util';
|
||||
import { deleteRole } from 'test/integration/graphql/utils/delete-one-role.util';
|
||||
import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util';
|
||||
import { makeGraphqlAPIRequestWithMemberRole as makeGraphqlAPIRequestWithJony } from 'test/integration/graphql/utils/make-graphql-api-request-with-member-role.util';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||
import { updateWorkspaceMemberRole } from 'test/integration/graphql/utils/update-workspace-member-role.util';
|
||||
|
||||
import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces';
|
||||
import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members';
|
||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||
|
||||
const client = request(`http://localhost:${APP_PORT}`);
|
||||
|
||||
describe('permissionsOnRelations', () => {
|
||||
describe('permissions V2 enabled', () => {
|
||||
let originalMemberRoleId: string;
|
||||
let customRoleId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Enable Permissions V2
|
||||
const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||
SEED_APPLE_WORKSPACE_ID,
|
||||
'IS_PERMISSIONS_V2_ENABLED',
|
||||
true,
|
||||
);
|
||||
|
||||
await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||
|
||||
// Get the original Member role ID for restoration later
|
||||
const getRolesQuery = {
|
||||
query: `
|
||||
query GetRoles {
|
||||
getRoles {
|
||||
id
|
||||
label
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
const rolesResponse = await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${ADMIN_ACCESS_TOKEN}`)
|
||||
.send(getRolesQuery);
|
||||
|
||||
originalMemberRoleId = rolesResponse.body.data.getRoles.find(
|
||||
(role: any) => role.label === 'Member',
|
||||
).id;
|
||||
|
||||
// Create a person record
|
||||
const companyId = randomUUID();
|
||||
const graphqlOperationForCompanyCreation = createOneOperationFactory({
|
||||
objectMetadataSingularName: 'company',
|
||||
gqlFields: `
|
||||
name
|
||||
`,
|
||||
data: {
|
||||
id: companyId,
|
||||
name: 'Twenty',
|
||||
},
|
||||
});
|
||||
|
||||
await makeGraphqlAPIRequest(graphqlOperationForCompanyCreation);
|
||||
|
||||
const graphqlOperationForPersonCreation = createOneOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
gqlFields: PERSON_GQL_FIELDS,
|
||||
data: {
|
||||
id: randomUUID(),
|
||||
name: {
|
||||
firstName: 'Marie',
|
||||
},
|
||||
city: 'Paris',
|
||||
companyId,
|
||||
},
|
||||
});
|
||||
|
||||
await makeGraphqlAPIRequest(graphqlOperationForPersonCreation);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
const restoreMemberRoleQuery = {
|
||||
query: `
|
||||
mutation UpdateWorkspaceMemberRole {
|
||||
updateWorkspaceMemberRole(
|
||||
workspaceMemberId: "${DEV_SEED_WORKSPACE_MEMBER_IDS.JONY}"
|
||||
roleId: "${originalMemberRoleId}"
|
||||
) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${ADMIN_ACCESS_TOKEN}`)
|
||||
.send(restoreMemberRoleQuery);
|
||||
|
||||
// Disable Permissions V2
|
||||
const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||
SEED_APPLE_WORKSPACE_ID,
|
||||
'IS_PERMISSIONS_V2_ENABLED',
|
||||
false,
|
||||
);
|
||||
|
||||
await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await deleteRole(client, customRoleId);
|
||||
});
|
||||
|
||||
it('should throw permission error when querying person with company relation without company read permission', async () => {
|
||||
// Create a role with person read permission but no company read permission
|
||||
const { roleId } = await createCustomRoleWithObjectPermissions({
|
||||
label: 'PersonOnlyRole',
|
||||
canReadPerson: true,
|
||||
canReadCompany: false,
|
||||
});
|
||||
|
||||
customRoleId = roleId;
|
||||
|
||||
await updateWorkspaceMemberRole({
|
||||
client,
|
||||
roleId: customRoleId,
|
||||
workspaceMemberId: DEV_SEED_WORKSPACE_MEMBER_IDS.JONY,
|
||||
});
|
||||
|
||||
// Create GraphQL query that includes company relation
|
||||
const graphqlOperation = findManyOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
objectMetadataPluralName: 'people',
|
||||
gqlFields: `
|
||||
id
|
||||
city
|
||||
jobTitle
|
||||
company {
|
||||
id
|
||||
name
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeGraphqlAPIRequestWithJony(graphqlOperation);
|
||||
|
||||
// The query should fail when trying to access company relation without permission
|
||||
expect(response.body.errors[0].message).toBe(
|
||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||
);
|
||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||
});
|
||||
|
||||
it('should successfully query person with company relation when having both permissions', async () => {
|
||||
// Create a role with both person and company read permissions
|
||||
const { roleId } = await createCustomRoleWithObjectPermissions({
|
||||
label: 'PersonAndCompanyRole',
|
||||
canReadPerson: true,
|
||||
canReadCompany: true,
|
||||
});
|
||||
|
||||
customRoleId = roleId;
|
||||
|
||||
await updateWorkspaceMemberRole({
|
||||
client,
|
||||
roleId: customRoleId,
|
||||
workspaceMemberId: DEV_SEED_WORKSPACE_MEMBER_IDS.JONY,
|
||||
});
|
||||
|
||||
// Create GraphQL query that includes company relation
|
||||
const graphqlOperation = findManyOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
objectMetadataPluralName: 'people',
|
||||
gqlFields: `
|
||||
id
|
||||
city
|
||||
jobTitle
|
||||
company {
|
||||
id
|
||||
name
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeGraphqlAPIRequestWithJony(graphqlOperation);
|
||||
|
||||
// The query should succeed
|
||||
expect(response.body.data).toBeDefined();
|
||||
expect(response.body.data.people).toBeDefined();
|
||||
const person = response.body.data.people.edges[0].node;
|
||||
|
||||
expect(person.company).toBeDefined();
|
||||
expect(response.body.error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('nested relations - should throw permission error when querying nested opportunity relation without opportunity read permission', async () => {
|
||||
// Where user has person and company read permissions but not opportunity read permission
|
||||
|
||||
const { roleId } = await createCustomRoleWithObjectPermissions({
|
||||
label: 'PersonCompanyOnlyRole',
|
||||
canReadPerson: true,
|
||||
canReadCompany: true,
|
||||
canReadOpportunities: false,
|
||||
});
|
||||
|
||||
customRoleId = roleId;
|
||||
|
||||
await updateWorkspaceMemberRole({
|
||||
client,
|
||||
roleId: customRoleId,
|
||||
workspaceMemberId: DEV_SEED_WORKSPACE_MEMBER_IDS.JONY,
|
||||
});
|
||||
|
||||
// Create a query with nested relations
|
||||
const graphqlOperation = findManyOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
objectMetadataPluralName: 'people',
|
||||
gqlFields: `
|
||||
id
|
||||
city
|
||||
jobTitle
|
||||
company {
|
||||
id
|
||||
name
|
||||
opportunities {
|
||||
edges {
|
||||
node {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeGraphqlAPIRequestWithJony(graphqlOperation);
|
||||
|
||||
expect(response.body.errors).toBeDefined();
|
||||
expect(response.body.errors[0].message).toBe(
|
||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||
);
|
||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -3,6 +3,7 @@ import request from 'supertest';
|
||||
import { deleteOneRoleOperationFactory } from 'test/integration/graphql/utils/delete-one-role-operation-factory.util';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||
import { updateWorkspaceMemberRole } from 'test/integration/graphql/utils/update-workspace-member-role.util';
|
||||
import { createOneObjectMetadataQueryFactory } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata-query-factory.util';
|
||||
import { deleteOneObjectMetadataQueryFactory } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata-query-factory.util';
|
||||
|
||||
@ -99,27 +100,11 @@ describe('Granular settings permissions', () => {
|
||||
.send(upsertSettingPermissionsQuery);
|
||||
|
||||
// Assign the custom role to JONY (who uses MEMBER_ACCESS_TOKEN)
|
||||
const updateMemberRoleQuery = {
|
||||
query: `
|
||||
mutation UpdateWorkspaceMemberRole {
|
||||
updateWorkspaceMemberRole(
|
||||
workspaceMemberId: "${DEV_SEED_WORKSPACE_MEMBER_IDS.JONY}"
|
||||
roleId: "${customRoleId}"
|
||||
) {
|
||||
id
|
||||
roles {
|
||||
id
|
||||
label
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${ADMIN_ACCESS_TOKEN}`)
|
||||
.send(updateMemberRoleQuery);
|
||||
await updateWorkspaceMemberRole({
|
||||
client,
|
||||
roleId: customRoleId,
|
||||
workspaceMemberId: DEV_SEED_WORKSPACE_MEMBER_IDS.JONY,
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
||||
@ -0,0 +1,131 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
|
||||
export const createCustomRoleWithObjectPermissions = async (options: {
|
||||
label: string;
|
||||
canReadPerson?: boolean;
|
||||
canReadCompany?: boolean;
|
||||
canReadOpportunities?: boolean;
|
||||
hasAllObjectRecordsReadPermission?: boolean;
|
||||
}) => {
|
||||
const createRoleOperation = {
|
||||
query: gql`
|
||||
mutation CreateOneRole {
|
||||
createOneRole(createRoleInput: {
|
||||
label: "${options.label}"
|
||||
description: "Test role for permission testing"
|
||||
canUpdateAllSettings: ${options.hasAllObjectRecordsReadPermission ?? true}
|
||||
canReadAllObjectRecords: ${options.hasAllObjectRecordsReadPermission ?? true}
|
||||
canUpdateAllObjectRecords: ${options.hasAllObjectRecordsReadPermission ?? true}
|
||||
canSoftDeleteAllObjectRecords: ${options.hasAllObjectRecordsReadPermission ?? true}
|
||||
canDestroyAllObjectRecords: ${options.hasAllObjectRecordsReadPermission ?? true}
|
||||
}) {
|
||||
id
|
||||
label
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
const response = await makeGraphqlAPIRequest(createRoleOperation);
|
||||
const roleId = response.body.data.createOneRole.id;
|
||||
|
||||
// Get object metadata IDs for Person and Company
|
||||
const getObjectMetadataOperation = {
|
||||
query: gql`
|
||||
query {
|
||||
objects(paging: { first: 1000 }) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
nameSingular
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
const objectMetadataResponse = await makeMetadataAPIRequest(
|
||||
getObjectMetadataOperation,
|
||||
);
|
||||
const objects = objectMetadataResponse.body.data.objects.edges;
|
||||
|
||||
const personObjectId = objects.find(
|
||||
(obj: any) => obj.node.nameSingular === 'person',
|
||||
)?.node.id;
|
||||
const companyObjectId = objects.find(
|
||||
(obj: any) => obj.node.nameSingular === 'company',
|
||||
)?.node.id;
|
||||
const opportunityObjectId = objects.find(
|
||||
(obj: any) => obj.node.nameSingular === 'opportunity',
|
||||
)?.node.id;
|
||||
|
||||
// Create object permissions based on the options
|
||||
const objectPermissions = [];
|
||||
|
||||
if (options.canReadPerson !== undefined) {
|
||||
objectPermissions.push({
|
||||
objectMetadataId: personObjectId,
|
||||
canReadObjectRecords: options.canReadPerson,
|
||||
canUpdateObjectRecords: false,
|
||||
canSoftDeleteObjectRecords: false,
|
||||
canDestroyObjectRecords: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (options.canReadCompany !== undefined) {
|
||||
objectPermissions.push({
|
||||
objectMetadataId: companyObjectId,
|
||||
canReadObjectRecords: options.canReadCompany,
|
||||
canUpdateObjectRecords: false,
|
||||
canSoftDeleteObjectRecords: false,
|
||||
canDestroyObjectRecords: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (options.canReadOpportunities !== undefined) {
|
||||
objectPermissions.push({
|
||||
objectMetadataId: opportunityObjectId,
|
||||
canReadObjectRecords: options.canReadOpportunities,
|
||||
canUpdateObjectRecords: false,
|
||||
canSoftDeleteObjectRecords: false,
|
||||
canDestroyObjectRecords: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (objectPermissions.length > 0) {
|
||||
const upsertObjectPermissionsOperation = {
|
||||
query: gql`
|
||||
mutation UpsertObjectPermissions(
|
||||
$roleId: String!
|
||||
$objectPermissions: [ObjectPermissionInput!]!
|
||||
) {
|
||||
upsertObjectPermissions(
|
||||
upsertObjectPermissionsInput: {
|
||||
roleId: $roleId
|
||||
objectPermissions: $objectPermissions
|
||||
}
|
||||
) {
|
||||
objectMetadataId
|
||||
canReadObjectRecords
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
roleId,
|
||||
objectPermissions,
|
||||
},
|
||||
};
|
||||
|
||||
await makeGraphqlAPIRequest(upsertObjectPermissionsOperation);
|
||||
}
|
||||
|
||||
return {
|
||||
roleId,
|
||||
personObjectId,
|
||||
companyObjectId,
|
||||
opportunityObjectId,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,10 @@
|
||||
import { deleteOneRoleOperationFactory } from 'test/integration/graphql/utils/delete-one-role-operation-factory.util';
|
||||
|
||||
export const deleteRole = async (client: any, roleId: string) => {
|
||||
const deleteRoleQuery = deleteOneRoleOperationFactory(roleId);
|
||||
|
||||
await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${ADMIN_ACCESS_TOKEN}`)
|
||||
.send(deleteRoleQuery);
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
export const updateWorkspaceMemberRole = async ({
|
||||
client,
|
||||
roleId,
|
||||
workspaceMemberId,
|
||||
}: {
|
||||
client: any;
|
||||
roleId: string;
|
||||
workspaceMemberId: string;
|
||||
}) => {
|
||||
const updateMemberRoleQuery = {
|
||||
query: `
|
||||
mutation UpdateWorkspaceMemberRole {
|
||||
updateWorkspaceMemberRole(
|
||||
workspaceMemberId: "${workspaceMemberId}"
|
||||
roleId: "${roleId}"
|
||||
) {
|
||||
id
|
||||
roles {
|
||||
id
|
||||
label
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${ADMIN_ACCESS_TOKEN}`)
|
||||
.send(updateMemberRoleQuery);
|
||||
};
|
||||
Reference in New Issue
Block a user