[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:
@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { SettingsFeatures } from 'twenty-shared';
|
||||
import { PermissionsOnAllObjectRecords, SettingsFeatures } from 'twenty-shared';
|
||||
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||
@ -12,13 +12,21 @@ export class PermissionsService {
|
||||
private readonly userRoleService: UserRoleService,
|
||||
) {}
|
||||
|
||||
public async getUserWorkspaceSettingsPermissions({
|
||||
public async getUserWorkspacePermissions({
|
||||
userWorkspaceId,
|
||||
workspaceId,
|
||||
}: {
|
||||
userWorkspaceId: string;
|
||||
}): Promise<Record<SettingsFeatures, boolean>> {
|
||||
workspaceId: string;
|
||||
}): Promise<{
|
||||
settingsPermissions: Record<SettingsFeatures, boolean>;
|
||||
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
|
||||
}> {
|
||||
const [roleOfUserWorkspace] = await this.userRoleService
|
||||
.getRolesByUserWorkspaces([userWorkspaceId])
|
||||
.getRolesByUserWorkspaces({
|
||||
userWorkspaceIds: [userWorkspaceId],
|
||||
workspaceId,
|
||||
})
|
||||
.then((roles) => roles?.get(userWorkspaceId) ?? []);
|
||||
|
||||
let hasPermissionOnSettingFeature = false;
|
||||
@ -27,24 +35,48 @@ export class PermissionsService {
|
||||
hasPermissionOnSettingFeature = true;
|
||||
}
|
||||
|
||||
return Object.keys(SettingsFeatures).reduce(
|
||||
const settingsPermissionsMap = Object.keys(SettingsFeatures).reduce(
|
||||
(acc, feature) => ({
|
||||
...acc,
|
||||
[feature]: hasPermissionOnSettingFeature,
|
||||
}),
|
||||
{} as Record<SettingsFeatures, boolean>,
|
||||
);
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
return {
|
||||
settingsPermissions: settingsPermissionsMap,
|
||||
objectRecordsPermissions: objectRecordsPermissionsMap,
|
||||
};
|
||||
}
|
||||
|
||||
public async userHasWorkspaceSettingPermission({
|
||||
userWorkspaceId,
|
||||
workspaceId,
|
||||
_setting,
|
||||
}: {
|
||||
userWorkspaceId: string;
|
||||
workspaceId: string;
|
||||
_setting: SettingsFeatures;
|
||||
}): Promise<boolean> {
|
||||
const [roleOfUserWorkspace] = await this.userRoleService
|
||||
.getRolesByUserWorkspaces([userWorkspaceId])
|
||||
.getRolesByUserWorkspaces({
|
||||
userWorkspaceIds: [userWorkspaceId],
|
||||
workspaceId,
|
||||
})
|
||||
.then((roles) => roles?.get(userWorkspaceId) ?? []);
|
||||
|
||||
if (roleOfUserWorkspace?.canUpdateAllSettings === true) {
|
||||
|
||||
@ -13,9 +13,6 @@ export class RoleDTO {
|
||||
@Field({ nullable: false })
|
||||
label: string;
|
||||
|
||||
@Field({ nullable: false })
|
||||
canUpdateAllSettings: boolean;
|
||||
|
||||
@Field({ nullable: true })
|
||||
description: string;
|
||||
|
||||
@ -27,4 +24,19 @@ export class RoleDTO {
|
||||
|
||||
@Field(() => [WorkspaceMember], { nullable: true })
|
||||
workspaceMembers?: WorkspaceMember[];
|
||||
|
||||
@Field({ nullable: false })
|
||||
canUpdateAllSettings: boolean;
|
||||
|
||||
@Field({ nullable: false })
|
||||
canReadAllObjectRecords: boolean;
|
||||
|
||||
@Field({ nullable: false })
|
||||
canUpdateAllObjectRecords: boolean;
|
||||
|
||||
@Field({ nullable: false })
|
||||
canSoftDeleteAllObjectRecords: boolean;
|
||||
|
||||
@Field({ nullable: false })
|
||||
canDestroyAllObjectRecords: boolean;
|
||||
}
|
||||
|
||||
@ -21,6 +21,18 @@ export class RoleEntity {
|
||||
@Column({ nullable: false, default: false })
|
||||
canUpdateAllSettings: boolean;
|
||||
|
||||
@Column({ nullable: false, default: false })
|
||||
canReadAllObjectRecords: boolean;
|
||||
|
||||
@Column({ nullable: false, default: false })
|
||||
canUpdateAllObjectRecords: boolean;
|
||||
|
||||
@Column({ nullable: false, default: false })
|
||||
canSoftDeleteAllObjectRecords: boolean;
|
||||
|
||||
@Column({ nullable: false, default: false })
|
||||
canDestroyAllObjectRecords: boolean;
|
||||
|
||||
@Column({ nullable: true, type: 'text' })
|
||||
description: string;
|
||||
|
||||
|
||||
@ -38,13 +38,17 @@ export class RoleResolver {
|
||||
return roles.map((role) => ({
|
||||
id: role.id,
|
||||
label: role.label,
|
||||
canUpdateAllSettings: role.canUpdateAllSettings,
|
||||
description: role.description,
|
||||
workspaceId: role.workspaceId,
|
||||
createdAt: role.createdAt,
|
||||
updatedAt: role.updatedAt,
|
||||
isEditable: role.isEditable,
|
||||
userWorkspaceRoles: role.userWorkspaceRoles,
|
||||
canUpdateAllSettings: role.canUpdateAllSettings,
|
||||
canReadAllObjectRecords: role.canReadAllObjectRecords,
|
||||
canUpdateAllObjectRecords: role.canUpdateAllObjectRecords,
|
||||
canSoftDeleteAllObjectRecords: role.canSoftDeleteAllObjectRecords,
|
||||
canDestroyAllObjectRecords: role.canDestroyAllObjectRecords,
|
||||
}));
|
||||
}
|
||||
|
||||
@ -81,7 +85,10 @@ export class RoleResolver {
|
||||
}
|
||||
|
||||
const roles = await this.userRoleService
|
||||
.getRolesByUserWorkspaces([userWorkspace.id])
|
||||
.getRolesByUserWorkspaces({
|
||||
userWorkspaceIds: [userWorkspace.id],
|
||||
workspaceId: workspace.id,
|
||||
})
|
||||
.then(
|
||||
(rolesByUserWorkspaces) =>
|
||||
rolesByUserWorkspaces?.get(userWorkspace.id) ?? [],
|
||||
|
||||
@ -30,6 +30,10 @@ export class RoleService {
|
||||
label: ADMIN_ROLE_LABEL,
|
||||
description: 'Admin role',
|
||||
canUpdateAllSettings: true,
|
||||
canReadAllObjectRecords: true,
|
||||
canUpdateAllObjectRecords: true,
|
||||
canSoftDeleteAllObjectRecords: true,
|
||||
canDestroyAllObjectRecords: true,
|
||||
isEditable: false,
|
||||
workspaceId,
|
||||
});
|
||||
@ -44,6 +48,10 @@ export class RoleService {
|
||||
label: MEMBER_ROLE_LABEL,
|
||||
description: 'Member role',
|
||||
canUpdateAllSettings: false,
|
||||
canReadAllObjectRecords: true,
|
||||
canUpdateAllObjectRecords: true,
|
||||
canSoftDeleteAllObjectRecords: true,
|
||||
canDestroyAllObjectRecords: true,
|
||||
isEditable: false,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
@ -60,7 +60,10 @@ export class UserRoleService {
|
||||
);
|
||||
}
|
||||
|
||||
const roles = await this.getRolesByUserWorkspaces([userWorkspace.id]);
|
||||
const roles = await this.getRolesByUserWorkspaces({
|
||||
userWorkspaceIds: [userWorkspace.id],
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const currentRole = roles.get(userWorkspace.id)?.[0];
|
||||
|
||||
@ -88,8 +91,10 @@ export class UserRoleService {
|
||||
workspaceId: string;
|
||||
}): Promise<void> {
|
||||
await this.validatesUserWorkspaceIsNotLastAdminIfUnassigningAdminRoleOrThrow(
|
||||
userWorkspaceId,
|
||||
workspaceId,
|
||||
{
|
||||
userWorkspaceId,
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
await this.userWorkspaceRoleRepository.delete({
|
||||
@ -98,9 +103,13 @@ export class UserRoleService {
|
||||
});
|
||||
}
|
||||
|
||||
public async getRolesByUserWorkspaces(
|
||||
userWorkspaceIds: string[],
|
||||
): Promise<Map<string, RoleDTO[]>> {
|
||||
public async getRolesByUserWorkspaces({
|
||||
userWorkspaceIds,
|
||||
workspaceId,
|
||||
}: {
|
||||
userWorkspaceIds: string[];
|
||||
workspaceId: string;
|
||||
}): Promise<Map<string, RoleDTO[]>> {
|
||||
if (!userWorkspaceIds.length) {
|
||||
return new Map();
|
||||
}
|
||||
@ -108,6 +117,7 @@ export class UserRoleService {
|
||||
const allUserWorkspaceRoles = await this.userWorkspaceRoleRepository.find({
|
||||
where: {
|
||||
userWorkspaceId: In(userWorkspaceIds),
|
||||
workspaceId,
|
||||
},
|
||||
relations: {
|
||||
role: true,
|
||||
@ -176,11 +186,17 @@ export class UserRoleService {
|
||||
return workspaceMembers;
|
||||
}
|
||||
|
||||
private async validatesUserWorkspaceIsNotLastAdminIfUnassigningAdminRoleOrThrow(
|
||||
userWorkspaceId: string,
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
const roles = await this.getRolesByUserWorkspaces([userWorkspaceId]);
|
||||
private async validatesUserWorkspaceIsNotLastAdminIfUnassigningAdminRoleOrThrow({
|
||||
userWorkspaceId,
|
||||
workspaceId,
|
||||
}: {
|
||||
userWorkspaceId: string;
|
||||
workspaceId: string;
|
||||
}): Promise<void> {
|
||||
const roles = await this.getRolesByUserWorkspaces({
|
||||
userWorkspaceIds: [userWorkspaceId],
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const currentRoles = roles.get(userWorkspaceId);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user