[permissions] Add object records permissions to role entity (#10255)

Closes https://github.com/twentyhq/core-team-issues/issues/388

- Add object records-related permissions to role entity
- Add it to queriable `currentUserWorkspace` (used in FE)
This commit is contained in:
Marie
2025-02-17 18:32:39 +01:00
committed by GitHub
parent 5b4cb4bd2c
commit cb3bd1353a
22 changed files with 255 additions and 60 deletions

View File

@ -1,7 +1,7 @@
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
import { IDField } from '@ptc-org/nestjs-query-graphql';
import { SettingsFeatures } from 'twenty-shared';
import { PermissionsOnAllObjectRecords, SettingsFeatures } from 'twenty-shared';
import {
Column,
CreateDateColumn,
@ -25,6 +25,10 @@ registerEnumType(SettingsFeatures, {
name: 'SettingsFeatures',
});
registerEnumType(PermissionsOnAllObjectRecords, {
name: 'PermissionsOnAllObjectRecords',
});
@Entity({ name: 'userWorkspace', schema: 'core' })
@ObjectType()
@Unique('IndexOnUserIdAndWorkspaceIdUnique', ['userId', 'workspaceId'])
@ -75,4 +79,7 @@ export class UserWorkspace {
@Field(() => [SettingsFeatures], { nullable: true })
settingsPermissions?: SettingsFeatures[];
@Field(() => [PermissionsOnAllObjectRecords], { nullable: true })
objectRecordsPermissions?: PermissionsOnAllObjectRecords[];
}

View File

@ -13,7 +13,7 @@ import crypto from 'crypto';
import { GraphQLJSONObject } from 'graphql-type-json';
import { FileUpload, GraphQLUpload } from 'graphql-upload';
import { SettingsFeatures } from 'twenty-shared';
import { PermissionsOnAllObjectRecords, SettingsFeatures } from 'twenty-shared';
import { In, Repository } from 'typeorm';
import { SupportDriver } from 'src/engine/core-modules/environment/interfaces/support.interface';
@ -113,16 +113,23 @@ export class UserResolver {
if (!currentUserWorkspace) {
throw new Error('Current user workspace not found');
}
const permissions =
await this.permissionsService.getUserWorkspaceSettingsPermissions({
const { settingsPermissions, objectRecordsPermissions } =
await this.permissionsService.getUserWorkspacePermissions({
userWorkspaceId: currentUserWorkspace.id,
workspaceId: workspace.id,
});
const permittedFeatures: SettingsFeatures[] = (
Object.keys(permissions) as SettingsFeatures[]
).filter((feature) => permissions[feature] === true);
Object.keys(settingsPermissions) as SettingsFeatures[]
).filter((feature) => settingsPermissions[feature] === true);
const permittedObjectRecordsPermissions = (
Object.keys(objectRecordsPermissions) as PermissionsOnAllObjectRecords[]
).filter((permission) => objectRecordsPermissions[permission] === true);
currentUserWorkspace.settingsPermissions = permittedFeatures;
currentUserWorkspace.objectRecordsPermissions =
permittedObjectRecordsPermissions;
user.currentUserWorkspace = currentUserWorkspace;
}
@ -216,9 +223,12 @@ export class UserResolver {
);
rolesByUserWorkspaces =
await this.userRoleService.getRolesByUserWorkspaces(
userWorkspaces.map((userWorkspace) => userWorkspace.id),
);
await this.userRoleService.getRolesByUserWorkspaces({
userWorkspaceIds: userWorkspaces.map(
(userWorkspace) => userWorkspace.id,
),
workspaceId: workspace.id,
});
}
for (const workspaceMemberEntity of workspaceMemberEntities) {
@ -254,6 +264,11 @@ export class UserResolver {
description: roleEntity.description,
isEditable: roleEntity.isEditable,
userWorkspaceRoles: roleEntity.userWorkspaceRoles,
canReadAllObjectRecords: roleEntity.canReadAllObjectRecords,
canUpdateAllObjectRecords: roleEntity.canUpdateAllObjectRecords,
canSoftDeleteAllObjectRecords:
roleEntity.canSoftDeleteAllObjectRecords,
canDestroyAllObjectRecords: roleEntity.canDestroyAllObjectRecords,
};
});

View File

@ -152,11 +152,13 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
await this.validateSecurityPermissions({
payload,
userWorkspaceId,
workspaceId: workspace.id,
});
await this.validateWorkspacePermissions({
payload,
userWorkspaceId,
workspaceId: workspace.id,
});
}
@ -378,9 +380,11 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
private async validateSecurityPermissions({
payload,
userWorkspaceId,
workspaceId,
}: {
payload: Partial<Workspace>;
userWorkspaceId?: string;
workspaceId: string;
}) {
if (
'isGoogleAuthEnabled' in payload ||
@ -396,6 +400,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
await this.permissionsService.userHasWorkspaceSettingPermission({
userWorkspaceId,
_setting: SettingsFeatures.SECURITY,
workspaceId: workspaceId,
});
if (!userHasPermission) {
@ -410,9 +415,11 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
private async validateWorkspacePermissions({
payload,
userWorkspaceId,
workspaceId,
}: {
payload: Partial<Workspace>;
userWorkspaceId?: string;
workspaceId: string;
}) {
if (
'displayName' in payload ||
@ -427,6 +434,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
const userHasPermission =
await this.permissionsService.userHasWorkspaceSettingPermission({
userWorkspaceId,
workspaceId,
_setting: SettingsFeatures.WORKSPACE,
});