Code first roles sync (#13667)

This commit is contained in:
Abdul Rahman
2025-08-11 16:44:45 +05:30
committed by GitHub
parent 2a2a2faadf
commit 9b11735c57
26 changed files with 474 additions and 73 deletions
@@ -0,0 +1,18 @@
import { type RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
export const roleEntityRelationProperties = [
'roleTargets',
'objectPermissions',
'permissionFlags',
'fieldPermissions',
] as const;
export type RoleEntityRelationProperties =
(typeof roleEntityRelationProperties)[number];
export type FlatRole = Omit<
RoleEntity,
RoleEntityRelationProperties | 'createdAt' | 'updatedAt'
> & {
uniqueIdentifier: string;
};
@@ -0,0 +1,21 @@
import { type FlatRole } from 'src/engine/metadata-modules/flat-role/types/flat-role.type';
import { type RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
export const fromRoleEntityToFlatRole = (role: RoleEntity): FlatRole => {
return {
id: role.id,
standardId: role.standardId,
label: role.label,
description: role.description,
icon: role.icon,
isEditable: role.isEditable,
canUpdateAllSettings: role.canUpdateAllSettings,
canAccessAllTools: role.canAccessAllTools,
canReadAllObjectRecords: role.canReadAllObjectRecords,
canUpdateAllObjectRecords: role.canUpdateAllObjectRecords,
canSoftDeleteAllObjectRecords: role.canSoftDeleteAllObjectRecords,
canDestroyAllObjectRecords: role.canDestroyAllObjectRecords,
workspaceId: role.workspaceId,
uniqueIdentifier: role.standardId || role.id,
};
};
@@ -0,0 +1,16 @@
import { v4 } from 'uuid';
import { type FlatRole } from 'src/engine/metadata-modules/flat-role/types/flat-role.type';
import { type StandardRoleDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/types/standard-role-definition.interface';
export const fromStandardRoleDefinitionToFlatRole = (
standardRoleDefinition: StandardRoleDefinition,
workspaceId: string,
): FlatRole => {
return {
...standardRoleDefinition,
id: v4(),
workspaceId,
uniqueIdentifier: standardRoleDefinition.standardId || v4(),
};
};
@@ -14,6 +14,9 @@ export class RoleDTO {
@Field(() => UUIDScalarType, { nullable: false })
id: string;
@Field(() => UUIDScalarType, { nullable: true })
standardId?: string;
@Field({ nullable: false })
label: string;
@@ -20,6 +20,9 @@ export class RoleEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ nullable: true, type: 'uuid' })
standardId?: string;
@Column({ nullable: false })
label: string;
@@ -5,7 +5,6 @@ import { isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { ADMIN_ROLE_LABEL } from 'src/engine/metadata-modules/permissions/constants/admin-role-label.constants';
import { MEMBER_ROLE_LABEL } from 'src/engine/metadata-modules/permissions/constants/member-role-label.constants';
import {
PermissionsException,
@@ -145,26 +144,6 @@ export class RoleService {
return { ...existingRole, ...updatedRole };
}
public async createAdminRole({
workspaceId,
}: {
workspaceId: string;
}): Promise<RoleEntity> {
return this.roleRepository.save({
label: ADMIN_ROLE_LABEL,
description: 'Admin role',
icon: 'IconUserCog',
canUpdateAllSettings: true,
canAccessAllTools: true,
canReadAllObjectRecords: true,
canUpdateAllObjectRecords: true,
canSoftDeleteAllObjectRecords: true,
canDestroyAllObjectRecords: true,
isEditable: false,
workspaceId,
});
}
public async deleteRole(
roleId: string,
workspaceId: string,
@@ -226,7 +205,7 @@ export class RoleService {
description: 'Member role',
icon: 'IconUser',
canUpdateAllSettings: false,
canAccessAllTools: false,
canAccessAllTools: true,
canReadAllObjectRecords: true,
canUpdateAllObjectRecords: true,
canSoftDeleteAllObjectRecords: true,
@@ -4,6 +4,7 @@ import { type RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
export const fromRoleEntityToRoleDto = (role: RoleEntity): RoleDTO => {
return {
id: role.id,
standardId: role.standardId,
label: role.label,
canUpdateAllSettings: role.canUpdateAllSettings,
canAccessAllTools: role.canAccessAllTools,
@@ -4,7 +4,6 @@ import { isDefined } from 'twenty-shared/utils';
import { In, Not, Repository } from 'typeorm';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { ADMIN_ROLE_LABEL } from 'src/engine/metadata-modules/permissions/constants/admin-role-label.constants';
import {
PermissionsException,
PermissionsExceptionCode,
@@ -14,6 +13,7 @@ import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { ADMIN_ROLE } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/roles/admin-role';
import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
export class UserRoleService {
@@ -202,7 +202,10 @@ export class UserRoleService {
);
}
if (roleOfUserWorkspace.label === ADMIN_ROLE_LABEL) {
if (
isDefined(roleOfUserWorkspace) &&
roleOfUserWorkspace.standardId === ADMIN_ROLE.standardId
) {
const adminRole = roleOfUserWorkspace;
await this.validateMoreThanOneWorkspaceMemberHasAdminRoleOrThrow({
@@ -268,7 +271,12 @@ export class UserRoleService {
};
}
if (!(currentRole?.label === ADMIN_ROLE_LABEL)) {
if (
!(
isDefined(currentRole) &&
currentRole.standardId === ADMIN_ROLE.standardId
)
) {
return;
}