[permissions V2] Remove feature flag (#12790)
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
@ -12,7 +11,6 @@ import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/wor
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([RoleEntity, UserWorkspaceRoleEntity], 'core'),
|
||||
FeatureFlagModule,
|
||||
TypeOrmModule.forFeature([UserWorkspace], 'core'),
|
||||
UserRoleModule,
|
||||
WorkspacePermissionsCacheModule,
|
||||
|
||||
@ -7,8 +7,6 @@ import {
|
||||
AuthException,
|
||||
AuthExceptionCode,
|
||||
} from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
|
||||
import {
|
||||
PermissionsException,
|
||||
@ -24,7 +22,6 @@ export class PermissionsService {
|
||||
constructor(
|
||||
private readonly userRoleService: UserRoleService,
|
||||
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
) {}
|
||||
|
||||
public async getUserWorkspacePermissions({
|
||||
@ -157,108 +154,10 @@ export class PermissionsService {
|
||||
return true;
|
||||
}
|
||||
|
||||
const isPermissionsV2Enabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED,
|
||||
workspaceId,
|
||||
);
|
||||
const settingPermissions = roleOfUserWorkspace.settingPermissions ?? [];
|
||||
|
||||
if (isPermissionsV2Enabled) {
|
||||
const settingPermissions = roleOfUserWorkspace.settingPermissions ?? [];
|
||||
|
||||
return settingPermissions.some(
|
||||
(settingPermission) => settingPermission.setting === setting,
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async userHasObjectRecordsPermission({
|
||||
userWorkspaceId,
|
||||
workspaceId,
|
||||
requiredPermission,
|
||||
isExecutedByApiKey,
|
||||
objectMetadataId,
|
||||
}: {
|
||||
userWorkspaceId?: string;
|
||||
workspaceId: string;
|
||||
requiredPermission: PermissionsOnAllObjectRecords;
|
||||
isExecutedByApiKey: boolean;
|
||||
objectMetadataId: string;
|
||||
}): Promise<boolean> {
|
||||
const isPermissionsV2Enabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (isPermissionsV2Enabled) {
|
||||
throw new Error(
|
||||
'This should not be called once Permissions V2 is enabled',
|
||||
);
|
||||
}
|
||||
|
||||
if (isExecutedByApiKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isDefined(userWorkspaceId)) {
|
||||
throw new AuthException(
|
||||
'Missing userWorkspaceId or apiKey in authContext',
|
||||
AuthExceptionCode.USER_WORKSPACE_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const roleIdOfUserWorkspace =
|
||||
await this.userRoleService.getRoleIdForUserWorkspace({
|
||||
userWorkspaceId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
if (!isDefined(roleIdOfUserWorkspace)) {
|
||||
throw new PermissionsException(
|
||||
PermissionsExceptionMessage.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
|
||||
PermissionsExceptionCode.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
|
||||
);
|
||||
}
|
||||
|
||||
const { data: rolesPermissions } =
|
||||
await this.workspacePermissionsCacheService.getRolesPermissionsFromCache({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const rolePermissionsForUserWorkspaceRole =
|
||||
rolesPermissions[roleIdOfUserWorkspace];
|
||||
|
||||
const objectPermissionKey =
|
||||
this.getObjectPermissionKeyForRequiredPermission(requiredPermission);
|
||||
|
||||
const objectPermissionValue =
|
||||
rolePermissionsForUserWorkspaceRole[objectMetadataId]?.[
|
||||
objectPermissionKey
|
||||
];
|
||||
|
||||
return objectPermissionValue === true;
|
||||
}
|
||||
|
||||
private getObjectPermissionKeyForRequiredPermission(
|
||||
requiredPermission: PermissionsOnAllObjectRecords,
|
||||
) {
|
||||
switch (requiredPermission) {
|
||||
case PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS:
|
||||
return 'canRead';
|
||||
case PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS:
|
||||
return 'canUpdate';
|
||||
case PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS:
|
||||
return 'canSoftDelete';
|
||||
case PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS:
|
||||
return 'canDestroy';
|
||||
default:
|
||||
throw new PermissionsException(
|
||||
PermissionsExceptionMessage.UNKNOWN_REQUIRED_PERMISSION,
|
||||
PermissionsExceptionCode.UNKNOWN_REQUIRED_PERMISSION,
|
||||
);
|
||||
}
|
||||
return settingPermissions.some(
|
||||
(settingPermission) => settingPermission.setting === setting,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { FileModule } from 'src/engine/core-modules/file/file.module';
|
||||
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
||||
@ -11,19 +10,17 @@ import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permi
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { RoleResolver } from 'src/engine/metadata-modules/role/role.resolver';
|
||||
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 { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([RoleEntity, UserWorkspaceRoleEntity], 'core'),
|
||||
TypeOrmModule.forFeature([RoleEntity], 'core'),
|
||||
TypeOrmModule.forFeature([UserWorkspace, Workspace], 'core'),
|
||||
UserRoleModule,
|
||||
PermissionsModule,
|
||||
UserWorkspaceModule,
|
||||
FeatureFlagModule,
|
||||
ObjectPermissionModule,
|
||||
SettingPermissionModule,
|
||||
WorkspacePermissionsCacheModule,
|
||||
|
||||
@ -8,9 +8,6 @@ import {
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
@ -56,10 +53,8 @@ export class RoleResolver {
|
||||
private readonly userRoleService: UserRoleService,
|
||||
private readonly roleService: RoleService,
|
||||
private readonly userWorkspaceService: UserWorkspaceService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly objectPermissionService: ObjectPermissionService,
|
||||
private readonly settingPermissionService: SettingPermissionService,
|
||||
private readonly fileService: FileService,
|
||||
) {}
|
||||
|
||||
@Query(() => [RoleDTO])
|
||||
@ -123,8 +118,6 @@ export class RoleResolver {
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
@Args('createRoleInput') createRoleInput: CreateRoleInput,
|
||||
): Promise<RoleDTO> {
|
||||
await this.validatePermissionsV2EnabledOrThrow(workspace);
|
||||
|
||||
return await this.roleService.createRole({
|
||||
workspaceId: workspace.id,
|
||||
input: createRoleInput,
|
||||
@ -136,8 +129,6 @@ export class RoleResolver {
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
@Args('updateRoleInput') updateRoleInput: UpdateRoleInput,
|
||||
): Promise<RoleDTO> {
|
||||
await this.validatePermissionsV2EnabledOrThrow(workspace);
|
||||
|
||||
const role = await this.roleService.updateRole({
|
||||
input: updateRoleInput,
|
||||
workspaceId: workspace.id,
|
||||
@ -151,8 +142,6 @@ export class RoleResolver {
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
@Args('roleId') roleId: string,
|
||||
): Promise<string> {
|
||||
await this.validatePermissionsV2EnabledOrThrow(workspace);
|
||||
|
||||
const deletedRoleId = await this.roleService.deleteRole(
|
||||
roleId,
|
||||
workspace.id,
|
||||
@ -167,8 +156,6 @@ export class RoleResolver {
|
||||
@Args('upsertObjectPermissionsInput')
|
||||
upsertObjectPermissionsInput: UpsertObjectPermissionsInput,
|
||||
): Promise<ObjectPermissionDTO[]> {
|
||||
await this.validatePermissionsV2EnabledOrThrow(workspace);
|
||||
|
||||
return this.objectPermissionService.upsertObjectPermissions({
|
||||
workspaceId: workspace.id,
|
||||
input: upsertObjectPermissionsInput,
|
||||
@ -181,8 +168,6 @@ export class RoleResolver {
|
||||
@Args('upsertSettingPermissionsInput')
|
||||
upsertSettingPermissionsInput: UpsertSettingPermissionsInput,
|
||||
): Promise<SettingPermissionDTO[]> {
|
||||
await this.validatePermissionsV2EnabledOrThrow(workspace);
|
||||
|
||||
return this.settingPermissionService.upsertSettingPermissions({
|
||||
workspaceId: workspace.id,
|
||||
input: upsertSettingPermissionsInput,
|
||||
@ -202,19 +187,4 @@ export class RoleResolver {
|
||||
|
||||
return workspaceMembers;
|
||||
}
|
||||
|
||||
private async validatePermissionsV2EnabledOrThrow(workspace: Workspace) {
|
||||
const isPermissionsV2Enabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED,
|
||||
workspace.id,
|
||||
);
|
||||
|
||||
if (!isPermissionsV2Enabled) {
|
||||
throw new PermissionsException(
|
||||
PermissionsExceptionMessage.PERMISSIONS_V2_NOT_ENABLED,
|
||||
PermissionsExceptionCode.PERMISSIONS_V2_NOT_ENABLED,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,6 @@ import {
|
||||
UpdateRolePayload,
|
||||
} from 'src/engine/metadata-modules/role/dtos/update-role-input.dto';
|
||||
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 { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
|
||||
@ -28,8 +27,6 @@ export class RoleService {
|
||||
private readonly workspaceRepository: Repository<Workspace>,
|
||||
@InjectRepository(RoleEntity, 'core')
|
||||
private readonly roleRepository: Repository<RoleEntity>,
|
||||
@InjectRepository(UserWorkspaceRoleEntity, 'core')
|
||||
private readonly userWorkspaceRoleRepository: Repository<UserWorkspaceRoleEntity>,
|
||||
private readonly userRoleService: UserRoleService,
|
||||
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
|
||||
) {}
|
||||
|
||||
@ -8,7 +8,6 @@ import {
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
@ -85,18 +84,9 @@ export class WorkspacePermissionsCacheService {
|
||||
);
|
||||
}
|
||||
|
||||
const workspaceFeatureFlagsMap =
|
||||
await this.workspaceFeatureFlagsMapCacheService.getWorkspaceFeatureFlagsMap(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const isPermissionsV2Enabled =
|
||||
!!workspaceFeatureFlagsMap[FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED];
|
||||
|
||||
const recomputedRolesPermissions =
|
||||
await this.getObjectRecordPermissionsForRoles({
|
||||
workspaceId,
|
||||
isPermissionsV2Enabled,
|
||||
roleIds,
|
||||
});
|
||||
|
||||
@ -232,11 +222,9 @@ export class WorkspacePermissionsCacheService {
|
||||
|
||||
private async getObjectRecordPermissionsForRoles({
|
||||
workspaceId,
|
||||
isPermissionsV2Enabled,
|
||||
roleIds,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
isPermissionsV2Enabled: boolean;
|
||||
roleIds?: string[];
|
||||
}): Promise<ObjectRecordsPermissionsByRoleId> {
|
||||
let roles: RoleEntity[] = [];
|
||||
@ -265,49 +253,47 @@ export class WorkspacePermissionsCacheService {
|
||||
let canSoftDelete = role.canSoftDeleteAllObjectRecords;
|
||||
let canDestroy = role.canDestroyAllObjectRecords;
|
||||
|
||||
if (isPermissionsV2Enabled) {
|
||||
if (
|
||||
standardId &&
|
||||
[
|
||||
STANDARD_OBJECT_IDS.workflow,
|
||||
STANDARD_OBJECT_IDS.workflowRun,
|
||||
STANDARD_OBJECT_IDS.workflowVersion,
|
||||
].includes(standardId)
|
||||
) {
|
||||
const hasWorkflowsPermissions = this.hasWorkflowsPermissions(role);
|
||||
if (
|
||||
standardId &&
|
||||
[
|
||||
STANDARD_OBJECT_IDS.workflow,
|
||||
STANDARD_OBJECT_IDS.workflowRun,
|
||||
STANDARD_OBJECT_IDS.workflowVersion,
|
||||
].includes(standardId)
|
||||
) {
|
||||
const hasWorkflowsPermissions = this.hasWorkflowsPermissions(role);
|
||||
|
||||
canRead = hasWorkflowsPermissions;
|
||||
canUpdate = hasWorkflowsPermissions;
|
||||
canSoftDelete = hasWorkflowsPermissions;
|
||||
canDestroy = hasWorkflowsPermissions;
|
||||
} else {
|
||||
const objectRecordPermissionsOverride = role.objectPermissions.find(
|
||||
(objectPermission) =>
|
||||
objectPermission.objectMetadataId === objectMetadataId,
|
||||
);
|
||||
canRead = hasWorkflowsPermissions;
|
||||
canUpdate = hasWorkflowsPermissions;
|
||||
canSoftDelete = hasWorkflowsPermissions;
|
||||
canDestroy = hasWorkflowsPermissions;
|
||||
} else {
|
||||
const objectRecordPermissionsOverride = role.objectPermissions.find(
|
||||
(objectPermission) =>
|
||||
objectPermission.objectMetadataId === objectMetadataId,
|
||||
);
|
||||
|
||||
const getPermissionValue = (
|
||||
overrideValue: boolean | undefined,
|
||||
defaultValue: boolean,
|
||||
) => (isSystem ? true : (overrideValue ?? defaultValue));
|
||||
const getPermissionValue = (
|
||||
overrideValue: boolean | undefined,
|
||||
defaultValue: boolean,
|
||||
) => (isSystem ? true : (overrideValue ?? defaultValue));
|
||||
|
||||
canRead = getPermissionValue(
|
||||
objectRecordPermissionsOverride?.canReadObjectRecords,
|
||||
canRead,
|
||||
);
|
||||
canUpdate = getPermissionValue(
|
||||
objectRecordPermissionsOverride?.canUpdateObjectRecords,
|
||||
canUpdate,
|
||||
);
|
||||
canSoftDelete = getPermissionValue(
|
||||
objectRecordPermissionsOverride?.canSoftDeleteObjectRecords,
|
||||
canSoftDelete,
|
||||
);
|
||||
canDestroy = getPermissionValue(
|
||||
objectRecordPermissionsOverride?.canDestroyObjectRecords,
|
||||
canDestroy,
|
||||
);
|
||||
}
|
||||
canRead = getPermissionValue(
|
||||
objectRecordPermissionsOverride?.canReadObjectRecords,
|
||||
canRead,
|
||||
);
|
||||
canUpdate = getPermissionValue(
|
||||
objectRecordPermissionsOverride?.canUpdateObjectRecords,
|
||||
canUpdate,
|
||||
);
|
||||
canSoftDelete = getPermissionValue(
|
||||
objectRecordPermissionsOverride?.canSoftDeleteObjectRecords,
|
||||
canSoftDelete,
|
||||
);
|
||||
canDestroy = getPermissionValue(
|
||||
objectRecordPermissionsOverride?.canDestroyObjectRecords,
|
||||
canDestroy,
|
||||
);
|
||||
}
|
||||
|
||||
objectRecordsPermissions[objectMetadataId] = {
|
||||
|
||||
Reference in New Issue
Block a user