[permissions] Add SettingsPermissionGuard on data model and roles features (#10063)
Adding SettingsPermissionsGuard to execute permission check. The guard is added directly in resolver, either at resolver level (ex: roles) or resolver-endpoint level (ex: metadata). this can be challenged !
This commit is contained in:
@ -0,0 +1,63 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
mixin,
|
||||
Type,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { SettingsFeatures } from 'twenty-shared';
|
||||
|
||||
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 {
|
||||
PermissionsException,
|
||||
PermissionsExceptionCode,
|
||||
} from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
|
||||
|
||||
export const SettingsPermissionsGuard = (
|
||||
requiredPermission: SettingsFeatures,
|
||||
): Type<CanActivate> => {
|
||||
@Injectable()
|
||||
class SettingsPermissionsMixin implements CanActivate {
|
||||
constructor(
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly permissionsService: PermissionsService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const ctx = GqlExecutionContext.create(context);
|
||||
const workspaceId = ctx.getContext().req.workspace.id;
|
||||
|
||||
const permissionsEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsPermissionsEnabled,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (!permissionsEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const userWorkspaceId = ctx.getContext().req.userWorkspaceId;
|
||||
|
||||
const hasPermission =
|
||||
await this.permissionsService.userHasWorkspaceSettingPermission({
|
||||
userWorkspaceId,
|
||||
_setting: requiredPermission,
|
||||
});
|
||||
|
||||
if (hasPermission === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new PermissionsException(
|
||||
'User is not authorized to perform this action',
|
||||
PermissionsExceptionCode.PERMISSION_DENIED,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return mixin(SettingsPermissionsMixin);
|
||||
};
|
||||
@ -22,6 +22,7 @@ import { IsFieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-m
|
||||
import { IsFieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/validators/is-field-metadata-options.validator';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
|
||||
import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module';
|
||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||
@ -52,6 +53,7 @@ import { UpdateFieldInput } from './dtos/update-field.input';
|
||||
TypeORMModule,
|
||||
ActorModule,
|
||||
ViewModule,
|
||||
PermissionsModule,
|
||||
],
|
||||
services: [
|
||||
IsFieldMetadataDefaultValue,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
UnauthorizedException,
|
||||
UseFilters,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
@ -12,7 +13,7 @@ import {
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
import { FieldMetadataType, SettingsFeatures } from 'twenty-shared';
|
||||
|
||||
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';
|
||||
@ -20,6 +21,7 @@ import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.typ
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { IDataloaders } from 'src/engine/dataloaders/dataloader.interface';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { CreateOneFieldMetadataInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { DeleteOneFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/delete-field.input';
|
||||
@ -34,10 +36,12 @@ import {
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service';
|
||||
import { fieldMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@Resolver(() => FieldMetadataDTO)
|
||||
@UseFilters(PermissionsGraphqlApiExceptionFilter)
|
||||
export class FieldMetadataResolver {
|
||||
constructor(
|
||||
private readonly fieldMetadataService: FieldMetadataService,
|
||||
@ -68,6 +72,7 @@ export class FieldMetadataResolver {
|
||||
);
|
||||
}
|
||||
|
||||
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL))
|
||||
@Mutation(() => FieldMetadataDTO)
|
||||
async createOneField(
|
||||
@Args('input') input: CreateOneFieldMetadataInput,
|
||||
@ -83,6 +88,7 @@ export class FieldMetadataResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL))
|
||||
@Mutation(() => FieldMetadataDTO)
|
||||
async updateOneField(
|
||||
@Args('input') input: UpdateOneFieldMetadataInput,
|
||||
@ -98,6 +104,7 @@ export class FieldMetadataResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL))
|
||||
@Mutation(() => FieldMetadataDTO)
|
||||
async deleteOneField(
|
||||
@Args('input') input: DeleteOneFieldInput,
|
||||
|
||||
@ -7,9 +7,12 @@ import {
|
||||
PagingStrategies,
|
||||
} from '@ptc-org/nestjs-query-graphql';
|
||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { SettingsFeatures } from 'twenty-shared';
|
||||
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
@ -20,6 +23,8 @@ import { ObjectMetadataResolver } from 'src/engine/metadata-modules/object-metad
|
||||
import { ObjectMetadataMigrationService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-migration.service';
|
||||
import { ObjectMetadataRelatedRecordsService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service';
|
||||
import { ObjectMetadataRelationService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-relation.service';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
import { RelationMetadataEntity } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
import { RemoteTableRelationsModule } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table-relations/remote-table-relations.module';
|
||||
import { SearchModule } from 'src/engine/metadata-modules/search/search.module';
|
||||
@ -51,6 +56,8 @@ import { UpdateObjectPayload } from './dtos/update-object.input';
|
||||
RemoteTableRelationsModule,
|
||||
SearchModule,
|
||||
IndexMetadataModule,
|
||||
FeatureFlagModule,
|
||||
PermissionsModule,
|
||||
],
|
||||
services: [
|
||||
ObjectMetadataService,
|
||||
@ -71,11 +78,13 @@ import { UpdateObjectPayload } from './dtos/update-object.input';
|
||||
},
|
||||
create: {
|
||||
many: { disabled: true },
|
||||
guards: [SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)],
|
||||
},
|
||||
update: { disabled: true },
|
||||
delete: { disabled: true },
|
||||
guards: [WorkspaceAuthGuard],
|
||||
interceptors: [ObjectMetadataGraphqlApiExceptionInterceptor],
|
||||
filters: [PermissionsGraphqlApiExceptionFilter],
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import {
|
||||
Args,
|
||||
Context,
|
||||
@ -8,9 +8,12 @@ import {
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { SettingsFeatures } from 'twenty-shared';
|
||||
|
||||
import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { DeleteOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/delete-object.input';
|
||||
import { ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
|
||||
@ -21,9 +24,11 @@ import {
|
||||
import { BeforeUpdateOneObject } from 'src/engine/metadata-modules/object-metadata/hooks/before-update-one-object.hook';
|
||||
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
||||
import { objectMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@Resolver(() => ObjectMetadataDTO)
|
||||
@UseFilters(PermissionsGraphqlApiExceptionFilter)
|
||||
export class ObjectMetadataResolver {
|
||||
constructor(
|
||||
private readonly objectMetadataService: ObjectMetadataService,
|
||||
@ -66,6 +71,7 @@ export class ObjectMetadataResolver {
|
||||
);
|
||||
}
|
||||
|
||||
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL))
|
||||
@Mutation(() => ObjectMetadataDTO)
|
||||
async deleteOneObject(
|
||||
@Args('input') input: DeleteOneObjectInput,
|
||||
@ -81,6 +87,7 @@ export class ObjectMetadataResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL))
|
||||
@Mutation(() => ObjectMetadataDTO)
|
||||
async updateOneObject(
|
||||
@Args('input') input: UpdateOneObjectInput,
|
||||
|
||||
@ -3,10 +3,6 @@ import { Injectable } from '@nestjs/common';
|
||||
import { SettingsFeatures } from 'twenty-shared';
|
||||
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import {
|
||||
PermissionsException,
|
||||
PermissionsExceptionCode,
|
||||
} from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||
|
||||
@Injectable()
|
||||
@ -40,25 +36,22 @@ export class PermissionsService {
|
||||
);
|
||||
}
|
||||
|
||||
public async validateUserHasWorkspaceSettingPermissionOrThrow({
|
||||
public async userHasWorkspaceSettingPermission({
|
||||
userWorkspaceId,
|
||||
setting,
|
||||
_setting,
|
||||
}: {
|
||||
userWorkspaceId: string;
|
||||
setting: SettingsFeatures;
|
||||
}): Promise<void> {
|
||||
_setting: SettingsFeatures;
|
||||
}): Promise<boolean> {
|
||||
const [roleOfUserWorkspace] = await this.userRoleService
|
||||
.getRolesByUserWorkspaces([userWorkspaceId])
|
||||
.then((roles) => roles?.get(userWorkspaceId) ?? []);
|
||||
|
||||
if (roleOfUserWorkspace?.canUpdateAllSettings === true) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new PermissionsException(
|
||||
`User does not have permission to access this setting: ${setting}`,
|
||||
PermissionsExceptionCode.PERMISSION_DENIED,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
public async isPermissionsEnabled(): Promise<boolean> {
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { Catch, ExceptionFilter } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
ForbiddenError,
|
||||
InternalServerError,
|
||||
@ -7,16 +9,15 @@ import {
|
||||
PermissionsExceptionCode,
|
||||
} from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||
|
||||
export const permissionsGraphqlApiExceptionHandler = (error: Error) => {
|
||||
if (error instanceof PermissionsException) {
|
||||
switch (error.code) {
|
||||
@Catch(PermissionsException)
|
||||
export class PermissionsGraphqlApiExceptionFilter implements ExceptionFilter {
|
||||
catch(exception: PermissionsException) {
|
||||
switch (exception.code) {
|
||||
case PermissionsExceptionCode.PERMISSION_DENIED:
|
||||
case PermissionsExceptionCode.CANNOT_UNASSIGN_LAST_ADMIN:
|
||||
throw new ForbiddenError(error.message);
|
||||
throw new ForbiddenError(exception.message);
|
||||
default:
|
||||
throw new InternalServerError(error.message);
|
||||
throw new InternalServerError(exception.message);
|
||||
}
|
||||
}
|
||||
|
||||
throw error;
|
||||
};
|
||||
}
|
||||
@ -5,12 +5,17 @@ import {
|
||||
PagingStrategies,
|
||||
} from '@ptc-org/nestjs-query-graphql';
|
||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { SettingsFeatures } from 'twenty-shared';
|
||||
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
|
||||
import { IndexMetadataModule } from 'src/engine/metadata-modules/index-metadata/index-metadata.module';
|
||||
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
import { RelationMetadataGraphqlApiExceptionInterceptor } from 'src/engine/metadata-modules/relation-metadata/interceptors/relation-metadata-graphql-api-exception.interceptor';
|
||||
import { RelationMetadataResolver } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.resolver';
|
||||
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
|
||||
@ -39,6 +44,8 @@ import { RelationMetadataDTO } from './dtos/relation-metadata.dto';
|
||||
WorkspaceMigrationModule,
|
||||
WorkspaceCacheStorageModule,
|
||||
WorkspaceMetadataVersionModule,
|
||||
FeatureFlagModule,
|
||||
PermissionsModule,
|
||||
],
|
||||
services: [RelationMetadataService],
|
||||
resolvers: [
|
||||
@ -48,11 +55,15 @@ import { RelationMetadataDTO } from './dtos/relation-metadata.dto';
|
||||
ServiceClass: RelationMetadataService,
|
||||
CreateDTOClass: CreateRelationInput,
|
||||
pagingStrategy: PagingStrategies.CURSOR,
|
||||
create: { many: { disabled: true } },
|
||||
create: {
|
||||
many: { disabled: true },
|
||||
guards: [SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)],
|
||||
},
|
||||
update: { disabled: true },
|
||||
delete: { disabled: true },
|
||||
guards: [WorkspaceAuthGuard],
|
||||
interceptors: [RelationMetadataGraphqlApiExceptionInterceptor],
|
||||
filters: [PermissionsGraphqlApiExceptionFilter],
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { SettingsFeatures } from 'twenty-shared';
|
||||
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
import { DeleteOneRelationInput } from 'src/engine/metadata-modules/relation-metadata/dtos/delete-relation.input';
|
||||
import { RelationMetadataDTO } from 'src/engine/metadata-modules/relation-metadata/dtos/relation-metadata.dto';
|
||||
import { RelationMetadataService } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.service';
|
||||
@ -11,11 +15,13 @@ import { relationMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@Resolver()
|
||||
@UseFilters(PermissionsGraphqlApiExceptionFilter)
|
||||
export class RelationMetadataResolver {
|
||||
constructor(
|
||||
private readonly relationMetadataService: RelationMetadataService,
|
||||
) {}
|
||||
|
||||
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL))
|
||||
@Mutation(() => RelationMetadataDTO)
|
||||
async deleteOneRelation(
|
||||
@Args('input') input: DeleteOneRelationInput,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
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 { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
@ -17,6 +18,7 @@ import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.
|
||||
UserRoleModule,
|
||||
PermissionsModule,
|
||||
UserWorkspaceModule,
|
||||
FeatureFlagModule,
|
||||
],
|
||||
providers: [RoleService, RoleResolver],
|
||||
exports: [RoleService],
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import {
|
||||
Args,
|
||||
Mutation,
|
||||
@ -12,70 +13,48 @@ import { isDefined, SettingsFeatures } from 'twenty-shared';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
|
||||
import { permissionsGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception-handler';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto';
|
||||
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
|
||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||
|
||||
@Resolver(() => RoleDTO)
|
||||
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.ROLES))
|
||||
@UseFilters(PermissionsGraphqlApiExceptionFilter)
|
||||
export class RoleResolver {
|
||||
constructor(
|
||||
private readonly userRoleService: UserRoleService,
|
||||
private readonly permissionsService: PermissionsService,
|
||||
private readonly roleService: RoleService,
|
||||
private readonly userWorkspaceService: UserWorkspaceService,
|
||||
) {}
|
||||
|
||||
@Query(() => [RoleDTO])
|
||||
async getRoles(
|
||||
@AuthUserWorkspaceId() userWorkspaceId: string,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
): Promise<RoleDTO[]> {
|
||||
try {
|
||||
await this.permissionsService.validateUserHasWorkspaceSettingPermissionOrThrow(
|
||||
{
|
||||
userWorkspaceId,
|
||||
setting: SettingsFeatures.ROLES,
|
||||
},
|
||||
);
|
||||
async getRoles(@AuthWorkspace() workspace: Workspace): Promise<RoleDTO[]> {
|
||||
const roles = await this.roleService.getWorkspaceRoles(workspace.id);
|
||||
|
||||
const roles = await this.roleService.getWorkspaceRoles(workspace.id);
|
||||
|
||||
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,
|
||||
}));
|
||||
} catch (error) {
|
||||
return permissionsGraphqlApiExceptionHandler(error);
|
||||
}
|
||||
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,
|
||||
}));
|
||||
}
|
||||
|
||||
@Mutation(() => WorkspaceMember)
|
||||
async updateWorkspaceMemberRole(
|
||||
@AuthUserWorkspaceId() currentUserWorkspaceId: string,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
@Args('workspaceMemberId') workspaceMemberId: string,
|
||||
@Args('roleId', { type: () => String, nullable: true })
|
||||
roleId: string | null,
|
||||
): Promise<WorkspaceMember> {
|
||||
await this.permissionsService.validateUserHasWorkspaceSettingPermissionOrThrow(
|
||||
{
|
||||
userWorkspaceId: currentUserWorkspaceId,
|
||||
setting: SettingsFeatures.ROLES,
|
||||
},
|
||||
);
|
||||
|
||||
const workspaceMember =
|
||||
await this.userWorkspaceService.getWorkspaceMemberOrThrow({
|
||||
workspaceMemberId,
|
||||
|
||||
Reference in New Issue
Block a user