Refactor WorkspaceMemberDto transpilation (#12110)

# Introduction

In a nutshell this PR introduces a `workspaceMemberEntity` to
`workspaceMemberDto` transpilation which was not done but commented as
`// TODO` across the `user resolver`.
Also passed on the `Roles` and `UserWorkspacePermissions` transpilation
We now also compute the roles for the `workspaceMember` resolver ( not
only the `workspaceMembers` )
Some refactor

In the following days about to create a PR that introduces integration
testing on the user resolver

## Conclusion
As always any suggestions are more than welcomed ! Please let me know !

## Misc

Following https://github.com/twentyhq/twenty/pull/11914

closing https://github.com/twentyhq/core-team-issues/issues/1011
This commit is contained in:
Paul Rastoin
2025-06-13 11:01:25 +02:00
committed by GitHub
parent 7c4ddb9448
commit 4182a3d306
11 changed files with 407 additions and 252 deletions

View File

@ -1,7 +1,6 @@
import { Injectable } from '@nestjs/common';
import { PermissionsOnAllObjectRecords } from 'twenty-shared/constants';
import { ObjectRecordsPermissions } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import {
@ -16,6 +15,7 @@ import {
PermissionsExceptionCode,
PermissionsExceptionMessage,
} from 'src/engine/metadata-modules/permissions/permissions.exception';
import { UserWorkspacePermissions } from 'src/engine/metadata-modules/permissions/types/user-workspace-permissions';
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
@ -33,11 +33,7 @@ export class PermissionsService {
}: {
userWorkspaceId: string;
workspaceId: string;
}): Promise<{
settingsPermissions: Record<SettingPermissionType, boolean>;
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
objectPermissions: ObjectRecordsPermissions;
}> {
}): Promise<UserWorkspacePermissions> {
const [roleOfUserWorkspace] = await this.userRoleService
.getRolesByUserWorkspaces({
userWorkspaceIds: [userWorkspaceId],
@ -60,7 +56,9 @@ export class PermissionsService {
const settingPermissions = roleOfUserWorkspace.settingPermissions ?? [];
const settingsPermissionsMap = Object.keys(SettingPermissionType).reduce(
const defaultSettingsPermissions =
this.getDefaultUserWorkspacePermissions().settingsPermissions;
const settingsPermissions = Object.keys(SettingPermissionType).reduce(
(acc, feature) => ({
...acc,
[feature]:
@ -69,7 +67,7 @@ export class PermissionsService {
(settingPermission) => settingPermission.setting === feature,
),
}),
{} as Record<SettingPermissionType, boolean>,
defaultSettingsPermissions,
);
const { data: rolesPermissions } =
@ -79,37 +77,53 @@ export class PermissionsService {
const objectPermissions = rolesPermissions[roleOfUserWorkspace.id] ?? {};
const objectRecordsPermissionsMap: Record<
PermissionsOnAllObjectRecords,
boolean
> = {
[PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canReadAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canUpdateAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canSoftDeleteAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canDestroyAllObjectRecords ?? false,
};
const objectRecordsPermissions: UserWorkspacePermissions['objectRecordsPermissions'] =
{
[PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canReadAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canUpdateAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canSoftDeleteAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canDestroyAllObjectRecords ?? false,
};
return {
settingsPermissions: settingsPermissionsMap,
objectRecordsPermissions: objectRecordsPermissionsMap,
settingsPermissions,
objectRecordsPermissions,
objectPermissions,
};
}
public getDefaultUserWorkspacePermissions = () =>
({
objectRecordsPermissions: {
[PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS]: false,
[PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS]: false,
[PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]: false,
[PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]: false,
},
settingsPermissions: {
[SettingPermissionType.API_KEYS_AND_WEBHOOKS]: false,
[SettingPermissionType.WORKSPACE]: false,
[SettingPermissionType.WORKSPACE_MEMBERS]: false,
[SettingPermissionType.ROLES]: false,
[SettingPermissionType.DATA_MODEL]: false,
[SettingPermissionType.ADMIN_PANEL]: false,
[SettingPermissionType.SECURITY]: false,
[SettingPermissionType.WORKFLOWS]: false,
},
objectPermissions: {},
}) as const satisfies UserWorkspacePermissions;
public async getUserWorkspacePermissions({
userWorkspaceId,
workspaceId,
}: {
userWorkspaceId: string;
workspaceId: string;
}): Promise<{
settingsPermissions: Record<SettingPermissionType, boolean>;
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
}> {
}): Promise<UserWorkspacePermissions> {
const [roleOfUserWorkspace] = await this.userRoleService
.getRolesByUserWorkspaces({
userWorkspaceIds: [userWorkspaceId],
@ -132,7 +146,9 @@ export class PermissionsService {
const settingPermissions = roleOfUserWorkspace.settingPermissions ?? [];
const settingsPermissionsMap = Object.keys(SettingPermissionType).reduce(
const defaultSettingsPermissions =
this.getDefaultUserWorkspacePermissions().settingsPermissions;
const settingsPermissions = Object.keys(SettingPermissionType).reduce(
(acc, feature) => ({
...acc,
[feature]:
@ -141,26 +157,25 @@ export class PermissionsService {
(settingPermission) => settingPermission.setting === feature,
),
}),
{} as Record<SettingPermissionType, boolean>,
defaultSettingsPermissions,
);
const objectRecordsPermissionsMap: Record<
PermissionsOnAllObjectRecords,
boolean
> = {
[PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canReadAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canUpdateAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canSoftDeleteAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canDestroyAllObjectRecords ?? false,
};
const objectRecordsPermissions: UserWorkspacePermissions['objectRecordsPermissions'] =
{
[PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canReadAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canUpdateAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canSoftDeleteAllObjectRecords ?? false,
[PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]:
roleOfUserWorkspace.canDestroyAllObjectRecords ?? false,
};
return {
settingsPermissions: settingsPermissionsMap,
objectRecordsPermissions: objectRecordsPermissionsMap,
settingsPermissions,
objectRecordsPermissions,
objectPermissions: {},
};
}

View File

@ -0,0 +1,10 @@
import { PermissionsOnAllObjectRecords } from 'twenty-shared/constants';
import { ObjectRecordsPermissions } from 'twenty-shared/types';
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
export type UserWorkspacePermissions = {
settingsPermissions: Record<SettingPermissionType, boolean>;
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
objectPermissions: ObjectRecordsPermissions;
};

View File

@ -0,0 +1,6 @@
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
export type UserWorkspacePermissionsDto = Pick<
UserWorkspace,
'objectPermissions' | 'settingsPermissions' | 'objectRecordsPermissions'
>;

View File

@ -0,0 +1,33 @@
import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
export const fromRoleEntityToRoleDto = ({
id,
label,
canUpdateAllSettings,
description,
icon,
isEditable,
userWorkspaceRoles,
canReadAllObjectRecords,
canUpdateAllObjectRecords,
canSoftDeleteAllObjectRecords,
canDestroyAllObjectRecords,
}: RoleEntity): RoleDTO => {
return {
id,
label,
canUpdateAllSettings,
description,
icon,
isEditable,
userWorkspaceRoles,
canReadAllObjectRecords,
canUpdateAllObjectRecords,
canSoftDeleteAllObjectRecords,
canDestroyAllObjectRecords,
};
};
export const fromRoleEntitiesToRoleDtos = (roleEntities: RoleEntity[]) =>
roleEntities.map(fromRoleEntityToRoleDto);

View File

@ -0,0 +1,35 @@
import { PermissionsOnAllObjectRecords } from 'twenty-shared/constants';
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
import { UserWorkspacePermissions } from 'src/engine/metadata-modules/permissions/types/user-workspace-permissions';
import { UserWorkspacePermissionsDto } from 'src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto';
export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({
objectPermissions: rawObjectPermissions,
objectRecordsPermissions: rawObjectRecordsPermissions,
settingsPermissions: rawSettingsPermissions,
}: UserWorkspacePermissions): UserWorkspacePermissionsDto => {
const objectPermissions = Object.entries(rawObjectPermissions).map(
([objectMetadataId, permissions]) => ({
objectMetadataId,
canReadObjectRecords: permissions.canRead,
canUpdateObjectRecords: permissions.canUpdate,
canSoftDeleteObjectRecords: permissions.canSoftDelete,
canDestroyObjectRecords: permissions.canDestroy,
}),
);
const settingsPermissions = (
Object.keys(rawSettingsPermissions) as SettingPermissionType[]
).filter((feature) => rawSettingsPermissions[feature] === true);
const objectRecordsPermissions = (
Object.keys(rawObjectRecordsPermissions) as PermissionsOnAllObjectRecords[]
).filter((feature) => rawObjectRecordsPermissions[feature] === true);
return {
objectPermissions,
objectRecordsPermissions,
settingsPermissions,
};
};