[permissions] Improve performances using a cache for userWorkspaces roles (#11587)

In this PR we are 

- introducing a cached map `{ userworkspaceId: roleId } `to reduce calls
to get a userWorkspace's role (we were having N+1 around that with
combinedFindMany queries and generally having a lot of avoidable
queries)
- using the roles permissions cache (`{ roleId: { objectNameSingular:
{ canRead: bool, canUpdate: bool, ...} } `) in Permissions V1's
userHasObjectPermission, in order to 1) improve performances to avoid
calls to get roles 2) start using our permissions cache
This commit is contained in:
Marie
2025-04-16 17:07:43 +02:00
committed by GitHub
parent ab277476a8
commit 4d78f5f97f
20 changed files with 692 additions and 350 deletions

View File

@ -13,7 +13,7 @@ import { RoleService } from 'src/engine/metadata-modules/role/role.service';
import { UserWorkspaceRoleEntity } from 'src/engine/metadata-modules/role/user-workspace-role.entity';
import { SettingPermissionModule } from 'src/engine/metadata-modules/setting-permission/setting-permission.module';
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
import { WorkspaceRolesPermissionsCacheModule } from 'src/engine/metadata-modules/workspace-roles-permissions-cache/workspace-roles-permissions-cache.module';
import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.module';
@Module({
imports: [
@ -25,7 +25,7 @@ import { WorkspaceRolesPermissionsCacheModule } from 'src/engine/metadata-module
FeatureFlagModule,
ObjectPermissionModule,
SettingPermissionModule,
WorkspaceRolesPermissionsCacheModule,
WorkspacePermissionsCacheModule,
],
providers: [RoleService, RoleResolver],
exports: [RoleService],

View File

@ -20,7 +20,7 @@ import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { UserWorkspaceRoleEntity } from 'src/engine/metadata-modules/role/user-workspace-role.entity';
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
import { isArgDefinedIfProvidedOrThrow } from 'src/engine/metadata-modules/utils/is-arg-defined-if-provided-or-throw.util';
import { WorkspaceRolesPermissionsCacheService } from 'src/engine/metadata-modules/workspace-roles-permissions-cache/workspace-roles-permissions-cache.service';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
export class RoleService {
constructor(
@ -31,7 +31,7 @@ export class RoleService {
@InjectRepository(UserWorkspaceRoleEntity, 'metadata')
private readonly userWorkspaceRoleRepository: Repository<UserWorkspaceRoleEntity>,
private readonly userRoleService: UserRoleService,
private readonly workspaceRolesPermissionsCacheService: WorkspaceRolesPermissionsCacheService,
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
) {}
public async getWorkspaceRoles(workspaceId: string): Promise<RoleEntity[]> {
@ -69,7 +69,7 @@ export class RoleService {
}): Promise<RoleEntity> {
await this.validateRoleInput({ input, workspaceId });
const role = this.roleRepository.save({
const role = await this.roleRepository.save({
label: input.label,
description: input.description,
icon: input.icon,
@ -82,11 +82,10 @@ export class RoleService {
workspaceId,
});
await this.workspaceRolesPermissionsCacheService.recomputeRolesPermissionsCache(
{
workspaceId,
},
);
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache({
workspaceId,
roleIds: [role.id],
});
return role;
}
@ -128,11 +127,10 @@ export class RoleService {
...input.update,
});
await this.workspaceRolesPermissionsCacheService.recomputeRolesPermissionsCache(
{
workspaceId,
},
);
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache({
workspaceId,
roleIds: [input.id],
});
return { ...existingRole, ...updatedRole };
}
@ -196,11 +194,9 @@ export class RoleService {
workspaceId,
});
await this.workspaceRolesPermissionsCacheService.recomputeRolesPermissionsCache(
{
workspaceId,
},
);
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache({
workspaceId,
});
return roleId;
}
@ -317,10 +313,11 @@ export class RoleService {
workspaceId: string;
defaultRoleId: string;
}): Promise<void> {
const userWorkspaceIds = await this.getUserWorkspaceIdsForRole(
roleId,
workspaceId,
);
const userWorkspaceIds =
await this.userRoleService.getUserWorkspaceIdsAssignedToRole(
roleId,
workspaceId,
);
await Promise.all(
userWorkspaceIds.map((userWorkspaceId) =>
@ -333,24 +330,6 @@ export class RoleService {
);
}
private async getUserWorkspaceIdsForRole(
roleId: string,
workspaceId: string,
): Promise<string[]> {
return this.userWorkspaceRoleRepository
.find({
where: {
roleId: roleId,
workspaceId,
},
})
.then((userWorkspaceRoles) =>
userWorkspaceRoles.map(
(userWorkspaceRole) => userWorkspaceRole.userWorkspaceId,
),
);
}
private async getRole(
roleId: string,
workspaceId: string,