[permission] Override query builders db-executing methods (#11714)
closes https://github.com/twentyhq/core-team-issues/issues/843
This commit is contained in:
@ -69,6 +69,7 @@ export const validateQueryIsPermittedOrThrow = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'restore':
|
||||||
case 'soft-delete':
|
case 'soft-delete':
|
||||||
if (!permissionsForEntity?.canSoftDelete) {
|
if (!permissionsForEntity?.canSoftDelete) {
|
||||||
throw new PermissionsException(
|
throw new PermissionsException(
|
||||||
|
|||||||
@ -0,0 +1,84 @@
|
|||||||
|
import { ObjectRecordsPermissions } from 'twenty-shared/types';
|
||||||
|
import {
|
||||||
|
DeleteQueryBuilder,
|
||||||
|
DeleteResult,
|
||||||
|
InsertQueryBuilder,
|
||||||
|
ObjectLiteral,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
|
||||||
|
|
||||||
|
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
||||||
|
|
||||||
|
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util';
|
||||||
|
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||||
|
import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder';
|
||||||
|
import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder';
|
||||||
|
|
||||||
|
export class WorkspaceDeleteQueryBuilder<
|
||||||
|
T extends ObjectLiteral,
|
||||||
|
> extends DeleteQueryBuilder<T> {
|
||||||
|
private objectRecordsPermissions: ObjectRecordsPermissions;
|
||||||
|
private shouldBypassPermissionChecks: boolean;
|
||||||
|
private internalContext: WorkspaceInternalContext;
|
||||||
|
constructor(
|
||||||
|
queryBuilder: DeleteQueryBuilder<T>,
|
||||||
|
objectRecordsPermissions: ObjectRecordsPermissions,
|
||||||
|
internalContext: WorkspaceInternalContext,
|
||||||
|
shouldBypassPermissionChecks: boolean,
|
||||||
|
) {
|
||||||
|
super(queryBuilder);
|
||||||
|
this.objectRecordsPermissions = objectRecordsPermissions;
|
||||||
|
this.internalContext = internalContext;
|
||||||
|
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
override clone(): this {
|
||||||
|
const clonedQueryBuilder = super.clone();
|
||||||
|
|
||||||
|
return new WorkspaceDeleteQueryBuilder(
|
||||||
|
clonedQueryBuilder,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
) as this;
|
||||||
|
}
|
||||||
|
|
||||||
|
override execute(): Promise<DeleteResult> {
|
||||||
|
validateQueryIsPermittedOrThrow(
|
||||||
|
this.expressionMap,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext.objectMetadataMaps,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
);
|
||||||
|
|
||||||
|
return super.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
override select(): WorkspaceSelectQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a select builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override update(): WorkspaceUpdateQueryBuilder<T>;
|
||||||
|
|
||||||
|
override update(
|
||||||
|
updateSet: QueryDeepPartialEntity<T>,
|
||||||
|
): WorkspaceUpdateQueryBuilder<T>;
|
||||||
|
|
||||||
|
override update(
|
||||||
|
_updateSet?: QueryDeepPartialEntity<T>,
|
||||||
|
): WorkspaceUpdateQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into an update builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override insert(): InsertQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into an insert builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override softDelete(): WorkspaceSoftDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a soft delete builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override restore(): WorkspaceSoftDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a soft delete builder');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
import { ObjectRecordsPermissions } from 'twenty-shared/types';
|
||||||
|
import { InsertQueryBuilder, ObjectLiteral } from 'typeorm';
|
||||||
|
|
||||||
|
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
||||||
|
|
||||||
|
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util';
|
||||||
|
import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder';
|
||||||
|
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||||
|
import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder';
|
||||||
|
import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder';
|
||||||
|
|
||||||
|
export class WorkspaceInsertQueryBuilder<
|
||||||
|
T extends ObjectLiteral,
|
||||||
|
> extends InsertQueryBuilder<T> {
|
||||||
|
private objectRecordsPermissions: ObjectRecordsPermissions;
|
||||||
|
private shouldBypassPermissionChecks: boolean;
|
||||||
|
private internalContext: WorkspaceInternalContext;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
queryBuilder: InsertQueryBuilder<T>,
|
||||||
|
objectRecordsPermissions: ObjectRecordsPermissions,
|
||||||
|
internalContext: WorkspaceInternalContext,
|
||||||
|
shouldBypassPermissionChecks: boolean,
|
||||||
|
) {
|
||||||
|
super(queryBuilder);
|
||||||
|
this.objectRecordsPermissions = objectRecordsPermissions;
|
||||||
|
this.internalContext = internalContext;
|
||||||
|
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
override clone(): this {
|
||||||
|
const clonedQueryBuilder = super.clone();
|
||||||
|
|
||||||
|
return new WorkspaceInsertQueryBuilder(
|
||||||
|
clonedQueryBuilder,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
) as this;
|
||||||
|
}
|
||||||
|
|
||||||
|
override execute(): Promise<any> {
|
||||||
|
validateQueryIsPermittedOrThrow(
|
||||||
|
this.expressionMap,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext.objectMetadataMaps,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
);
|
||||||
|
|
||||||
|
return super.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
override select(): WorkspaceSelectQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a select builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override update(): WorkspaceUpdateQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into an update builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override delete(): WorkspaceDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a delete builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override softDelete(): WorkspaceSoftDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a soft delete builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override restore(): WorkspaceSoftDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a soft delete builder');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,35 +0,0 @@
|
|||||||
import { ObjectRecordsPermissions } from 'twenty-shared/types';
|
|
||||||
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
||||||
|
|
||||||
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
|
||||||
|
|
||||||
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
|
||||||
|
|
||||||
export class WorkspaceQueryBuilder<
|
|
||||||
T extends ObjectLiteral,
|
|
||||||
> extends WorkspaceSelectQueryBuilder<T> {
|
|
||||||
constructor(
|
|
||||||
queryBuilder: SelectQueryBuilder<T>,
|
|
||||||
objectRecordsPermissions: ObjectRecordsPermissions,
|
|
||||||
internalContext: WorkspaceInternalContext,
|
|
||||||
shouldBypassPermissionChecks: boolean,
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
queryBuilder,
|
|
||||||
objectRecordsPermissions,
|
|
||||||
internalContext,
|
|
||||||
shouldBypassPermissionChecks,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
override clone(): this {
|
|
||||||
const clonedQueryBuilder = super.clone();
|
|
||||||
|
|
||||||
return new WorkspaceQueryBuilder(
|
|
||||||
clonedQueryBuilder,
|
|
||||||
this.objectRecordsPermissions,
|
|
||||||
this.internalContext,
|
|
||||||
this.shouldBypassPermissionChecks,
|
|
||||||
) as this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +1,12 @@
|
|||||||
import { ObjectRecordsPermissions } from 'twenty-shared/types';
|
import { ObjectRecordsPermissions } from 'twenty-shared/types';
|
||||||
import { ObjectLiteral, SelectQueryBuilder, UpdateQueryBuilder } from 'typeorm';
|
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
||||||
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
|
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
|
||||||
|
|
||||||
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
||||||
|
|
||||||
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util';
|
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util';
|
||||||
|
import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder';
|
||||||
|
import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder';
|
||||||
import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder';
|
import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder';
|
||||||
|
|
||||||
export class WorkspaceSelectQueryBuilder<
|
export class WorkspaceSelectQueryBuilder<
|
||||||
@ -25,6 +27,29 @@ export class WorkspaceSelectQueryBuilder<
|
|||||||
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
|
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override clone(): this {
|
||||||
|
const clonedQueryBuilder = super.clone();
|
||||||
|
|
||||||
|
return new WorkspaceSelectQueryBuilder(
|
||||||
|
clonedQueryBuilder,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
) as this;
|
||||||
|
}
|
||||||
|
|
||||||
|
override execute(): Promise<T[]> {
|
||||||
|
this.validatePermissions();
|
||||||
|
|
||||||
|
return super.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
override getMany(): Promise<T[]> {
|
||||||
|
this.validatePermissions();
|
||||||
|
|
||||||
|
return super.getMany();
|
||||||
|
}
|
||||||
|
|
||||||
override update(): WorkspaceUpdateQueryBuilder<T>;
|
override update(): WorkspaceUpdateQueryBuilder<T>;
|
||||||
|
|
||||||
override update(
|
override update(
|
||||||
@ -33,7 +58,7 @@ export class WorkspaceSelectQueryBuilder<
|
|||||||
|
|
||||||
override update(
|
override update(
|
||||||
updateSet?: QueryDeepPartialEntity<T>,
|
updateSet?: QueryDeepPartialEntity<T>,
|
||||||
): UpdateQueryBuilder<T> {
|
): WorkspaceUpdateQueryBuilder<T> {
|
||||||
const updateQueryBuilder = updateSet
|
const updateQueryBuilder = updateSet
|
||||||
? super.update(updateSet)
|
? super.update(updateSet)
|
||||||
: super.update();
|
: super.update();
|
||||||
@ -46,25 +71,45 @@ export class WorkspaceSelectQueryBuilder<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
override execute(): Promise<T[]> {
|
override delete(): WorkspaceDeleteQueryBuilder<T> {
|
||||||
validateQueryIsPermittedOrThrow(
|
const deleteQueryBuilder = super.delete();
|
||||||
this.expressionMap,
|
|
||||||
|
return new WorkspaceDeleteQueryBuilder<T>(
|
||||||
|
deleteQueryBuilder,
|
||||||
this.objectRecordsPermissions,
|
this.objectRecordsPermissions,
|
||||||
this.internalContext.objectMetadataMaps,
|
this.internalContext,
|
||||||
this.shouldBypassPermissionChecks,
|
this.shouldBypassPermissionChecks,
|
||||||
);
|
);
|
||||||
|
|
||||||
return super.execute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override getMany(): Promise<T[]> {
|
override softDelete(): WorkspaceSoftDeleteQueryBuilder<T> {
|
||||||
|
const softDeleteQueryBuilder = super.softDelete();
|
||||||
|
|
||||||
|
return new WorkspaceSoftDeleteQueryBuilder<T>(
|
||||||
|
softDeleteQueryBuilder,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
override restore(): WorkspaceSoftDeleteQueryBuilder<T> {
|
||||||
|
const restoreQueryBuilder = super.restore();
|
||||||
|
|
||||||
|
return new WorkspaceSoftDeleteQueryBuilder<T>(
|
||||||
|
restoreQueryBuilder,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private validatePermissions(): void {
|
||||||
validateQueryIsPermittedOrThrow(
|
validateQueryIsPermittedOrThrow(
|
||||||
this.expressionMap,
|
this.expressionMap,
|
||||||
this.objectRecordsPermissions,
|
this.objectRecordsPermissions,
|
||||||
this.internalContext.objectMetadataMaps,
|
this.internalContext.objectMetadataMaps,
|
||||||
this.shouldBypassPermissionChecks,
|
this.shouldBypassPermissionChecks,
|
||||||
);
|
);
|
||||||
|
|
||||||
return super.getMany();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,68 @@
|
|||||||
|
import { ObjectRecordsPermissions } from 'twenty-shared/types';
|
||||||
|
import { InsertQueryBuilder, ObjectLiteral, UpdateResult } from 'typeorm';
|
||||||
|
import { SoftDeleteQueryBuilder } from 'typeorm/query-builder/SoftDeleteQueryBuilder';
|
||||||
|
|
||||||
|
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
||||||
|
|
||||||
|
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util';
|
||||||
|
import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder';
|
||||||
|
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||||
|
import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder';
|
||||||
|
|
||||||
|
export class WorkspaceSoftDeleteQueryBuilder<
|
||||||
|
T extends ObjectLiteral,
|
||||||
|
> extends SoftDeleteQueryBuilder<T> {
|
||||||
|
private objectRecordsPermissions: ObjectRecordsPermissions;
|
||||||
|
private shouldBypassPermissionChecks: boolean;
|
||||||
|
private internalContext: WorkspaceInternalContext;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
queryBuilder: SoftDeleteQueryBuilder<T>,
|
||||||
|
objectRecordsPermissions: ObjectRecordsPermissions,
|
||||||
|
internalContext: WorkspaceInternalContext,
|
||||||
|
shouldBypassPermissionChecks: boolean,
|
||||||
|
) {
|
||||||
|
super(queryBuilder);
|
||||||
|
this.objectRecordsPermissions = objectRecordsPermissions;
|
||||||
|
this.internalContext = internalContext;
|
||||||
|
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
override clone(): this {
|
||||||
|
const clonedQueryBuilder = super.clone();
|
||||||
|
|
||||||
|
return new WorkspaceSoftDeleteQueryBuilder(
|
||||||
|
clonedQueryBuilder,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
) as this;
|
||||||
|
}
|
||||||
|
|
||||||
|
override execute(): Promise<UpdateResult> {
|
||||||
|
validateQueryIsPermittedOrThrow(
|
||||||
|
this.expressionMap,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext.objectMetadataMaps,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
);
|
||||||
|
|
||||||
|
return super.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
override select(): WorkspaceSelectQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a select builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override update(): WorkspaceUpdateQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into an update builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override insert(): InsertQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into an insert builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override delete(): WorkspaceDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a delete builder');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,15 +4,18 @@ import { ObjectLiteral, UpdateQueryBuilder, UpdateResult } from 'typeorm';
|
|||||||
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
|
||||||
|
|
||||||
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util';
|
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util';
|
||||||
|
import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder';
|
||||||
|
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||||
|
import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder';
|
||||||
|
|
||||||
export class WorkspaceUpdateQueryBuilder<
|
export class WorkspaceUpdateQueryBuilder<
|
||||||
Entity extends ObjectLiteral,
|
T extends ObjectLiteral,
|
||||||
> extends UpdateQueryBuilder<Entity> {
|
> extends UpdateQueryBuilder<T> {
|
||||||
private objectRecordsPermissions: ObjectRecordsPermissions;
|
private objectRecordsPermissions: ObjectRecordsPermissions;
|
||||||
private shouldBypassPermissionChecks: boolean;
|
private shouldBypassPermissionChecks: boolean;
|
||||||
private internalContext: WorkspaceInternalContext;
|
private internalContext: WorkspaceInternalContext;
|
||||||
constructor(
|
constructor(
|
||||||
queryBuilder: UpdateQueryBuilder<Entity>,
|
queryBuilder: UpdateQueryBuilder<T>,
|
||||||
objectRecordsPermissions: ObjectRecordsPermissions,
|
objectRecordsPermissions: ObjectRecordsPermissions,
|
||||||
internalContext: WorkspaceInternalContext,
|
internalContext: WorkspaceInternalContext,
|
||||||
shouldBypassPermissionChecks: boolean,
|
shouldBypassPermissionChecks: boolean,
|
||||||
@ -23,6 +26,17 @@ export class WorkspaceUpdateQueryBuilder<
|
|||||||
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
|
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override clone(): this {
|
||||||
|
const clonedQueryBuilder = super.clone();
|
||||||
|
|
||||||
|
return new WorkspaceUpdateQueryBuilder(
|
||||||
|
clonedQueryBuilder,
|
||||||
|
this.objectRecordsPermissions,
|
||||||
|
this.internalContext,
|
||||||
|
this.shouldBypassPermissionChecks,
|
||||||
|
) as this;
|
||||||
|
}
|
||||||
|
|
||||||
override execute(): Promise<UpdateResult> {
|
override execute(): Promise<UpdateResult> {
|
||||||
validateQueryIsPermittedOrThrow(
|
validateQueryIsPermittedOrThrow(
|
||||||
this.expressionMap,
|
this.expressionMap,
|
||||||
@ -33,4 +47,20 @@ export class WorkspaceUpdateQueryBuilder<
|
|||||||
|
|
||||||
return super.execute();
|
return super.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override select(): WorkspaceSelectQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a select builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override delete(): WorkspaceDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a delete builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override softDelete(): WorkspaceSoftDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a soft delete builder');
|
||||||
|
}
|
||||||
|
|
||||||
|
override restore(): WorkspaceSoftDeleteQueryBuilder<T> {
|
||||||
|
throw new Error('This builder cannot morph into a soft delete builder');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/works
|
|||||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||||
import { WorkspaceQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-query-builder';
|
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||||
import { WorkspaceEntitiesStorage } from 'src/engine/twenty-orm/storage/workspace-entities.storage';
|
import { WorkspaceEntitiesStorage } from 'src/engine/twenty-orm/storage/workspace-entities.storage';
|
||||||
import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
|
import { formatData } from 'src/engine/twenty-orm/utils/format-data.util';
|
||||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
@ -58,11 +58,11 @@ export class WorkspaceRepository<
|
|||||||
override createQueryBuilder<U extends T>(
|
override createQueryBuilder<U extends T>(
|
||||||
alias?: string,
|
alias?: string,
|
||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
): WorkspaceQueryBuilder<U> {
|
): WorkspaceSelectQueryBuilder<U> {
|
||||||
const queryBuilder = super.createQueryBuilder(
|
const queryBuilder = super.createQueryBuilder(
|
||||||
alias,
|
alias,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
) as unknown as WorkspaceQueryBuilder<U>;
|
) as unknown as WorkspaceSelectQueryBuilder<U>;
|
||||||
const isPermissionsV2Enabled =
|
const isPermissionsV2Enabled =
|
||||||
this.featureFlagMap[FeatureFlagKey.IsPermissionsV2Enabled];
|
this.featureFlagMap[FeatureFlagKey.IsPermissionsV2Enabled];
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ export class WorkspaceRepository<
|
|||||||
throw new Error('Object records permissions are required');
|
throw new Error('Object records permissions are required');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new WorkspaceQueryBuilder(
|
return new WorkspaceSelectQueryBuilder(
|
||||||
queryBuilder,
|
queryBuilder,
|
||||||
this.objectRecordsPermissions,
|
this.objectRecordsPermissions,
|
||||||
this.internalContext,
|
this.internalContext,
|
||||||
|
|||||||
@ -9,55 +9,160 @@ import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.
|
|||||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||||
|
|
||||||
describe('createManyObjectRecordsPermissions', () => {
|
describe('createManyObjectRecordsPermissions', () => {
|
||||||
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
describe('permissions V2 disabled', () => {
|
||||||
const graphqlOperation = createManyOperationFactory({
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
objectMetadataSingularName: 'person',
|
const graphqlOperation = createManyOperationFactory({
|
||||||
objectMetadataPluralName: 'people',
|
objectMetadataSingularName: 'person',
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
objectMetadataPluralName: 'people',
|
||||||
data: [
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
{
|
data: [
|
||||||
id: randomUUID(),
|
{
|
||||||
},
|
id: randomUUID(),
|
||||||
{
|
},
|
||||||
id: randomUUID(),
|
{
|
||||||
},
|
id: randomUUID(),
|
||||||
],
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ createPeople: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
it('should create multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
|
||||||
expect(response.body.data).toStrictEqual({ createPeople: null });
|
const graphqlOperation = createManyOperationFactory({
|
||||||
expect(response.body.errors).toBeDefined();
|
objectMetadataSingularName: 'person',
|
||||||
expect(response.body.errors[0].message).toBe(
|
objectMetadataPluralName: 'people',
|
||||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
);
|
data: [
|
||||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
{
|
||||||
});
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
it('should create multiple object records when user has permission (admin role)', async () => {
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
const personId1 = randomUUID();
|
|
||||||
const personId2 = randomUUID();
|
|
||||||
|
|
||||||
const graphqlOperation = createManyOperationFactory({
|
expect(response.body.data).toBeDefined();
|
||||||
objectMetadataSingularName: 'person',
|
expect(response.body.data.createPeople).toBeDefined();
|
||||||
objectMetadataPluralName: 'people',
|
expect(response.body.data.createPeople).toHaveLength(2);
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
expect(response.body.data.createPeople[0].id).toBe(personId1);
|
||||||
data: [
|
expect(response.body.data.createPeople[1].id).toBe(personId2);
|
||||||
{
|
|
||||||
id: personId1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: personId2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
|
||||||
|
|
||||||
expect(response.body.data).toBeDefined();
|
|
||||||
expect(response.body.data.createPeople).toBeDefined();
|
|
||||||
expect(response.body.data.createPeople).toHaveLength(2);
|
|
||||||
expect(response.body.data.createPeople[0].id).toBe(personId1);
|
|
||||||
expect(response.body.data.createPeople[1].id).toBe(personId2);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// describe('permissions V2 enabled', () => {
|
||||||
|
// beforeAll(async () => {
|
||||||
|
// const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
// SEED_APPLE_WORKSPACE_ID,
|
||||||
|
// 'IsPermissionsV2Enabled',
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// afterAll(async () => {
|
||||||
|
// const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
// SEED_APPLE_WORKSPACE_ID,
|
||||||
|
// 'IsPermissionsV2Enabled',
|
||||||
|
// false,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
// const graphqlOperation = createManyOperationFactory({
|
||||||
|
// objectMetadataSingularName: 'person',
|
||||||
|
// objectMetadataPluralName: 'people',
|
||||||
|
// gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
// data: [
|
||||||
|
// {
|
||||||
|
// id: randomUUID(),
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// id: randomUUID(),
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const response =
|
||||||
|
// await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
// expect(response.body.data).toStrictEqual({ createPeople: null });
|
||||||
|
// expect(response.body.errors).toBeDefined();
|
||||||
|
// expect(response.body.errors[0].message).toBe(
|
||||||
|
// PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
// );
|
||||||
|
// expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should create multiple object records when user has permission (admin role)', async () => {
|
||||||
|
// const personId1 = randomUUID();
|
||||||
|
// const personId2 = randomUUID();
|
||||||
|
|
||||||
|
// const graphqlOperation = createManyOperationFactory({
|
||||||
|
// objectMetadataSingularName: 'person',
|
||||||
|
// objectMetadataPluralName: 'people',
|
||||||
|
// gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
// data: [
|
||||||
|
// {
|
||||||
|
// id: personId1,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// id: personId2,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
// expect(response.body.data).toBeDefined();
|
||||||
|
// expect(response.body.data.createPeople).toBeDefined();
|
||||||
|
// expect(response.body.data.createPeople).toHaveLength(2);
|
||||||
|
// expect(response.body.data.createPeople[0].id).toBe(personId1);
|
||||||
|
// expect(response.body.data.createPeople[1].id).toBe(personId2);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should create multiple object records when executed by api key', async () => {
|
||||||
|
// const personId1 = randomUUID();
|
||||||
|
// const personId2 = randomUUID();
|
||||||
|
|
||||||
|
// const graphqlOperation = createManyOperationFactory({
|
||||||
|
// objectMetadataSingularName: 'person',
|
||||||
|
// objectMetadataPluralName: 'people',
|
||||||
|
// gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
// data: [
|
||||||
|
// {
|
||||||
|
// id: personId1,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// id: personId2,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
|
||||||
|
|
||||||
|
// expect(response.body.data).toBeDefined();
|
||||||
|
// expect(response.body.data.createPeople).toBeDefined();
|
||||||
|
// expect(response.body.data.createPeople).toHaveLength(2);
|
||||||
|
// expect(response.body.data.createPeople[0].id).toBe(personId1);
|
||||||
|
// expect(response.body.data.createPeople[1].id).toBe(personId2);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,39 +9,118 @@ import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.
|
|||||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||||
|
|
||||||
describe('createOneObjectRecordsPermissions', () => {
|
describe('createOneObjectRecordsPermissions', () => {
|
||||||
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
describe('permissions V2 disabled', () => {
|
||||||
const graphqlOperation = createOneOperationFactory({
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
objectMetadataSingularName: 'person',
|
const graphqlOperation = createOneOperationFactory({
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
objectMetadataSingularName: 'person',
|
||||||
data: {
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
id: randomUUID(),
|
data: {
|
||||||
},
|
id: randomUUID(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ createPerson: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
it('should create an object record when user has permission (admin role)', async () => {
|
||||||
|
const personId = randomUUID();
|
||||||
|
const graphqlOperation = createOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: {
|
||||||
|
id: personId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(response.body.data).toStrictEqual({ createPerson: null });
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
expect(response.body.errors).toBeDefined();
|
|
||||||
expect(response.body.errors[0].message).toBe(
|
|
||||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
|
||||||
);
|
|
||||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create an object record when user has permission (admin role)', async () => {
|
expect(response.body.data).toBeDefined();
|
||||||
const personId = randomUUID();
|
expect(response.body.data.createPerson).toBeDefined();
|
||||||
const graphqlOperation = createOneOperationFactory({
|
expect(response.body.data.createPerson.id).toBe(personId);
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
data: {
|
|
||||||
id: personId,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
|
||||||
|
|
||||||
expect(response.body.data).toBeDefined();
|
|
||||||
expect(response.body.data.createPerson).toBeDefined();
|
|
||||||
expect(response.body.data.createPerson.id).toBe(personId);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// describe('permissions V2 enabled', () => {
|
||||||
|
// beforeAll(async () => {
|
||||||
|
// const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
// SEED_APPLE_WORKSPACE_ID,
|
||||||
|
// 'IsPermissionsV2Enabled',
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// afterAll(async () => {
|
||||||
|
// const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
// SEED_APPLE_WORKSPACE_ID,
|
||||||
|
// 'IsPermissionsV2Enabled',
|
||||||
|
// false,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
// const graphqlOperation = createOneOperationFactory({
|
||||||
|
// objectMetadataSingularName: 'person',
|
||||||
|
// gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
// data: {
|
||||||
|
// id: randomUUID(),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const response =
|
||||||
|
// await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
// expect(response.body.data).toStrictEqual({ createPerson: null });
|
||||||
|
// expect(response.body.errors).toBeDefined();
|
||||||
|
// expect(response.body.errors[0].message).toBe(
|
||||||
|
// PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
// );
|
||||||
|
// expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should create an object record when user has permission (admin role)', async () => {
|
||||||
|
// const personId = randomUUID();
|
||||||
|
// const graphqlOperation = createOneOperationFactory({
|
||||||
|
// objectMetadataSingularName: 'person',
|
||||||
|
// gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
// data: {
|
||||||
|
// id: personId,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
// expect(response.body.data).toBeDefined();
|
||||||
|
// expect(response.body.data.createPerson).toBeDefined();
|
||||||
|
// expect(response.body.data.createPerson.id).toBe(personId);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it('should create an object record when executed by api key', async () => {
|
||||||
|
// const personId = randomUUID();
|
||||||
|
// const graphqlOperation = createOneOperationFactory({
|
||||||
|
// objectMetadataSingularName: 'person',
|
||||||
|
// gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
// data: {
|
||||||
|
// id: personId,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
|
||||||
|
|
||||||
|
// expect(response.body.data).toBeDefined();
|
||||||
|
// expect(response.body.data.createPerson).toBeDefined();
|
||||||
|
// expect(response.body.data.createPerson.id).toBe(personId);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,72 +3,205 @@ import { randomUUID } from 'node:crypto';
|
|||||||
import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants';
|
import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants';
|
||||||
import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util';
|
import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util';
|
||||||
import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util';
|
import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util';
|
||||||
|
import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util';
|
||||||
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
||||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||||
|
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||||
|
|
||||||
|
import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces';
|
||||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||||
|
|
||||||
describe('deleteManyObjectRecordsPermissions', () => {
|
describe('deleteManyObjectRecordsPermissions', () => {
|
||||||
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
describe('permissions V2 disabled', () => {
|
||||||
const graphqlOperation = deleteManyOperationFactory({
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
objectMetadataSingularName: 'person',
|
const graphqlOperation = deleteManyOperationFactory({
|
||||||
objectMetadataPluralName: 'people',
|
objectMetadataSingularName: 'person',
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
objectMetadataPluralName: 'people',
|
||||||
filter: {
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
id: {
|
filter: {
|
||||||
in: [randomUUID(), randomUUID()],
|
id: {
|
||||||
|
in: [randomUUID(), randomUUID()],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ deletePeople: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
it('should delete multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
|
||||||
expect(response.body.data).toStrictEqual({ deletePeople: null });
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
expect(response.body.errors).toBeDefined();
|
objectMetadataSingularName: 'person',
|
||||||
expect(response.body.errors[0].message).toBe(
|
objectMetadataPluralName: 'people',
|
||||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
);
|
data: [
|
||||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const deleteGraphqlOperation = deleteManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.deletePeople).toBeDefined();
|
||||||
|
expect(response.body.data.deletePeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.deletePeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.deletePeople[1].id).toBe(personId2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete multiple object records when user has permission (admin role)', async () => {
|
describe('permissions V2 enabled', () => {
|
||||||
const personId1 = randomUUID();
|
beforeAll(async () => {
|
||||||
const personId2 = randomUUID();
|
const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
const createGraphqlOperation = createManyOperationFactory({
|
await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
objectMetadataPluralName: 'people',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
id: personId1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: personId2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await makeGraphqlAPIRequest(createGraphqlOperation);
|
afterAll(async () => {
|
||||||
|
const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
const deleteGraphqlOperation = deleteManyOperationFactory({
|
await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
objectMetadataPluralName: 'people',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
filter: {
|
|
||||||
id: {
|
|
||||||
in: [personId1, personId2],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const graphqlOperation = deleteManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [randomUUID(), randomUUID()],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(response.body.data).toBeDefined();
|
const response =
|
||||||
expect(response.body.data.deletePeople).toBeDefined();
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
expect(response.body.data.deletePeople).toHaveLength(2);
|
|
||||||
expect(response.body.data.deletePeople[0].id).toBe(personId1);
|
expect(response.body.data).toStrictEqual({ deletePeople: null });
|
||||||
expect(response.body.data.deletePeople[1].id).toBe(personId2);
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
|
||||||
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const deleteGraphqlOperation = deleteManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.deletePeople).toBeDefined();
|
||||||
|
expect(response.body.data.deletePeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.deletePeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.deletePeople[1].id).toBe(personId2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete multiple object records when executed by api key', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
|
||||||
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const deleteGraphqlOperation = deleteManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequestWithApiKey(
|
||||||
|
deleteGraphqlOperation,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.deletePeople).toBeDefined();
|
||||||
|
expect(response.body.data.deletePeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.deletePeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.deletePeople[1].id).toBe(personId2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,56 +3,178 @@ import { randomUUID } from 'node:crypto';
|
|||||||
import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants';
|
import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants';
|
||||||
import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util';
|
import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util';
|
||||||
import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util';
|
import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util';
|
||||||
|
import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util';
|
||||||
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
||||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||||
|
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||||
|
|
||||||
|
import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces';
|
||||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||||
|
|
||||||
describe('deleteOneObjectRecordsPermissions', () => {
|
describe('deleteOneObjectRecordsPermissions', () => {
|
||||||
const personId = randomUUID();
|
describe('permissions V2 disabled', () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const createOnePersonRecordOperation = createOneOperationFactory({
|
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
data: {
|
|
||||||
id: personId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await makeGraphqlAPIRequest(createOnePersonRecordOperation);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
|
||||||
const personId = randomUUID();
|
const personId = randomUUID();
|
||||||
const graphqlOperation = deleteOneOperationFactory({
|
|
||||||
objectMetadataSingularName: 'person',
|
beforeAll(async () => {
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
const createOnePersonRecordOperation = createOneOperationFactory({
|
||||||
recordId: personId,
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: {
|
||||||
|
id: personId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createOnePersonRecordOperation);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const personId = randomUUID();
|
||||||
|
const graphqlOperation = deleteOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
expect(response.body.data).toStrictEqual({ deletePerson: null });
|
const response =
|
||||||
expect(response.body.errors).toBeDefined();
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
expect(response.body.errors[0].message).toBe(
|
|
||||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
expect(response.body.data).toStrictEqual({ deletePerson: null });
|
||||||
);
|
expect(response.body.errors).toBeDefined();
|
||||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete an object record when user has permission (admin role)', async () => {
|
||||||
|
const deleteGraphqlOperation = deleteOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.deletePerson).toBeDefined();
|
||||||
|
expect(response.body.data.deletePerson.id).toBe(personId);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete an object record when user has permission (admin role)', async () => {
|
describe('permissions V2 enabled', () => {
|
||||||
const deleteGraphqlOperation = deleteOneOperationFactory({
|
const personId = randomUUID();
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
beforeAll(async () => {
|
||||||
recordId: personId,
|
const createOnePersonRecordOperation = createOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: {
|
||||||
|
id: personId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createOnePersonRecordOperation);
|
||||||
|
|
||||||
|
const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
afterAll(async () => {
|
||||||
|
const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
expect(response.body.data).toBeDefined();
|
await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||||
expect(response.body.data.deletePerson).toBeDefined();
|
});
|
||||||
expect(response.body.data.deletePerson.id).toBe(personId);
|
|
||||||
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const personId = randomUUID();
|
||||||
|
const createGraphqlOperation = createOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: {
|
||||||
|
id: personId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const deleteGraphqlOperation = deleteOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequestWithGuestRole(
|
||||||
|
deleteGraphqlOperation,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ deletePerson: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete an object record when user has permission (admin role)', async () => {
|
||||||
|
const personId = randomUUID();
|
||||||
|
const createGraphqlOperation = createOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: {
|
||||||
|
id: personId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const deleteGraphqlOperation = deleteOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.deletePerson).toBeDefined();
|
||||||
|
expect(response.body.data.deletePerson.id).toBe(personId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete an object record when executed by api key', async () => {
|
||||||
|
const personId = randomUUID();
|
||||||
|
const createGraphqlOperation = createOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: {
|
||||||
|
id: personId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const deleteGraphqlOperation = deleteOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequestWithApiKey(
|
||||||
|
deleteGraphqlOperation,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.deletePerson).toBeDefined();
|
||||||
|
expect(response.body.data.deletePerson.id).toBe(personId);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,70 +5,160 @@ import { createManyOperationFactory } from 'test/integration/graphql/utils/creat
|
|||||||
import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util';
|
import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util';
|
||||||
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
||||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||||
|
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||||
|
|
||||||
|
import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces';
|
||||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||||
|
|
||||||
describe('destroyManyObjectRecordsPermissions', () => {
|
describe('destroyManyObjectRecordsPermissions', () => {
|
||||||
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
describe('permissions V2 disabled', () => {
|
||||||
const graphqlOperation = destroyManyOperationFactory({
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
objectMetadataSingularName: 'person',
|
const graphqlOperation = destroyManyOperationFactory({
|
||||||
objectMetadataPluralName: 'people',
|
objectMetadataSingularName: 'person',
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
objectMetadataPluralName: 'people',
|
||||||
filter: {
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
id: {
|
filter: {
|
||||||
in: [randomUUID(), randomUUID()],
|
id: {
|
||||||
|
in: [randomUUID(), randomUUID()],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ destroyPeople: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
it('should destroy multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
|
||||||
expect(response.body.data).toStrictEqual({ destroyPeople: null });
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
expect(response.body.errors).toBeDefined();
|
objectMetadataSingularName: 'person',
|
||||||
expect(response.body.errors[0].message).toBe(
|
objectMetadataPluralName: 'people',
|
||||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
);
|
data: [
|
||||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const graphqlOperation = destroyManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.destroyPeople).toBeDefined();
|
||||||
|
expect(response.body.data.destroyPeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.destroyPeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.destroyPeople[1].id).toBe(personId2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should destroy multiple object records when user has permission (admin role)', async () => {
|
describe('permissions V2 enabled', () => {
|
||||||
const personId1 = randomUUID();
|
beforeAll(async () => {
|
||||||
const personId2 = randomUUID();
|
const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
const createGraphqlOperation = createManyOperationFactory({
|
await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
objectMetadataPluralName: 'people',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
id: personId1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: personId2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await makeGraphqlAPIRequest(createGraphqlOperation);
|
afterAll(async () => {
|
||||||
|
const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
const graphqlOperation = destroyManyOperationFactory({
|
await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
objectMetadataPluralName: 'people',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
filter: {
|
|
||||||
id: {
|
|
||||||
in: [personId1, personId2],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const graphqlOperation = destroyManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [randomUUID(), randomUUID()],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(response.body.data).toBeDefined();
|
const response =
|
||||||
expect(response.body.data.destroyPeople).toBeDefined();
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
expect(response.body.data.destroyPeople).toHaveLength(2);
|
|
||||||
expect(response.body.data.destroyPeople[0].id).toBe(personId1);
|
expect(response.body.data).toStrictEqual({ destroyPeople: null });
|
||||||
expect(response.body.data.destroyPeople[1].id).toBe(personId2);
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should destroy multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
|
||||||
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const graphqlOperation = destroyManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.destroyPeople).toBeDefined();
|
||||||
|
expect(response.body.data.destroyPeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.destroyPeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.destroyPeople[1].id).toBe(personId2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,54 +5,126 @@ import { createOneOperationFactory } from 'test/integration/graphql/utils/create
|
|||||||
import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util';
|
import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util';
|
||||||
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
||||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||||
|
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||||
|
|
||||||
|
import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces';
|
||||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||||
|
|
||||||
describe('destroyOneObjectRecordsPermissions', () => {
|
describe('destroyOneObjectRecordsPermissions', () => {
|
||||||
const personId = randomUUID();
|
describe('permissions V2 disabled', () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const createGraphqlOperation = createOneOperationFactory({
|
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
data: {
|
|
||||||
id: personId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await makeGraphqlAPIRequest(createGraphqlOperation);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
|
||||||
const personId = randomUUID();
|
const personId = randomUUID();
|
||||||
const graphqlOperation = destroyOneOperationFactory({
|
|
||||||
objectMetadataSingularName: 'person',
|
beforeAll(async () => {
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
const createGraphqlOperation = createOneOperationFactory({
|
||||||
recordId: personId,
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: {
|
||||||
|
id: personId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const personId = randomUUID();
|
||||||
|
const graphqlOperation = destroyOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
expect(response.body.data).toStrictEqual({ destroyPerson: null });
|
const response =
|
||||||
expect(response.body.errors).toBeDefined();
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
expect(response.body.errors[0].message).toBe(
|
|
||||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
expect(response.body.data).toStrictEqual({ destroyPerson: null });
|
||||||
);
|
expect(response.body.errors).toBeDefined();
|
||||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should destroy an object record when user has permission (admin role)', async () => {
|
||||||
|
const graphqlOperation = destroyOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.destroyPerson).toBeDefined();
|
||||||
|
expect(response.body.data.destroyPerson.id).toBe(personId);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should destroy an object record when user has permission (admin role)', async () => {
|
describe('permissions V2 enabled', () => {
|
||||||
const graphqlOperation = destroyOneOperationFactory({
|
const personId = randomUUID();
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
beforeAll(async () => {
|
||||||
recordId: personId,
|
const createGraphqlOperation = createOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: {
|
||||||
|
id: personId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
afterAll(async () => {
|
||||||
|
const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
expect(response.body.data).toBeDefined();
|
await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||||
expect(response.body.data.destroyPerson).toBeDefined();
|
});
|
||||||
expect(response.body.data.destroyPerson.id).toBe(personId);
|
|
||||||
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const personId = randomUUID();
|
||||||
|
const graphqlOperation = destroyOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ destroyPerson: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should destroy an object record when user has permission (admin role)', async () => {
|
||||||
|
const graphqlOperation = destroyOneOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
recordId: personId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.destroyPerson).toBeDefined();
|
||||||
|
expect(response.body.data.destroyPerson.id).toBe(personId);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,87 +6,192 @@ import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delet
|
|||||||
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
||||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||||
import { restoreManyOperationFactory } from 'test/integration/graphql/utils/restore-many-operation-factory.util';
|
import { restoreManyOperationFactory } from 'test/integration/graphql/utils/restore-many-operation-factory.util';
|
||||||
|
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||||
|
|
||||||
|
import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces';
|
||||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||||
|
|
||||||
describe('restoreManyObjectRecordsPermissions', () => {
|
describe('restoreManyObjectRecordsPermissions', () => {
|
||||||
const personId1 = randomUUID();
|
describe('permissions V2 disabled', () => {
|
||||||
const personId2 = randomUUID();
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// Create people
|
// Create people
|
||||||
const createGraphqlOperation = createManyOperationFactory({
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
objectMetadataSingularName: 'person',
|
objectMetadataSingularName: 'person',
|
||||||
objectMetadataPluralName: 'people',
|
objectMetadataPluralName: 'people',
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
id: personId1,
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
// Delete people
|
||||||
|
const deleteGraphqlOperation = deleteManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
});
|
||||||
id: personId2,
|
|
||||||
},
|
await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await makeGraphqlAPIRequest(createGraphqlOperation);
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const graphqlOperation = restoreManyOperationFactory({
|
||||||
// Delete people
|
objectMetadataSingularName: 'person',
|
||||||
const deleteGraphqlOperation = deleteManyOperationFactory({
|
objectMetadataPluralName: 'people',
|
||||||
objectMetadataSingularName: 'person',
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
objectMetadataPluralName: 'people',
|
filter: {
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
id: {
|
||||||
filter: {
|
in: [personId1, personId2],
|
||||||
id: {
|
},
|
||||||
in: [personId1, personId2],
|
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ restorePeople: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
});
|
});
|
||||||
|
|
||||||
await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
it('should restore multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const graphqlOperation = restoreManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.restorePeople).toBeDefined();
|
||||||
|
expect(response.body.data.restorePeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.restorePeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.restorePeople[1].id).toBe(personId2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
describe('permissions V2 enabled', () => {
|
||||||
const graphqlOperation = restoreManyOperationFactory({
|
const personId1 = randomUUID();
|
||||||
objectMetadataSingularName: 'person',
|
const personId2 = randomUUID();
|
||||||
objectMetadataPluralName: 'people',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
beforeAll(async () => {
|
||||||
filter: {
|
// Create people
|
||||||
id: {
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
in: [personId1, personId2],
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
// Delete people
|
||||||
|
const deleteGraphqlOperation = deleteManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(deleteGraphqlOperation);
|
||||||
|
|
||||||
|
const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
afterAll(async () => {
|
||||||
|
const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
expect(response.body.data).toStrictEqual({ restorePeople: null });
|
await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||||
expect(response.body.errors).toBeDefined();
|
|
||||||
expect(response.body.errors[0].message).toBe(
|
|
||||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
|
||||||
);
|
|
||||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should restore multiple object records when user has permission (admin role)', async () => {
|
|
||||||
const graphqlOperation = restoreManyOperationFactory({
|
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
objectMetadataPluralName: 'people',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
filter: {
|
|
||||||
id: {
|
|
||||||
in: [personId1, personId2],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const graphqlOperation = restoreManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(response.body.data).toBeDefined();
|
const response =
|
||||||
expect(response.body.data.restorePeople).toBeDefined();
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
expect(response.body.data.restorePeople).toHaveLength(2);
|
|
||||||
expect(response.body.data.restorePeople[0].id).toBe(personId1);
|
expect(response.body.data).toStrictEqual({ restorePeople: null });
|
||||||
expect(response.body.data.restorePeople[1].id).toBe(personId2);
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should restore multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const graphqlOperation = restoreManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.restorePeople).toBeDefined();
|
||||||
|
expect(response.body.data.restorePeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.restorePeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.restorePeople[1].id).toBe(personId2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,81 +2,248 @@ import { randomUUID } from 'node:crypto';
|
|||||||
|
|
||||||
import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants';
|
import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants';
|
||||||
import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util';
|
import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util';
|
||||||
|
import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util';
|
||||||
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util';
|
||||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||||
|
import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util';
|
||||||
import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util';
|
import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util';
|
||||||
|
|
||||||
|
import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces';
|
||||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||||
|
|
||||||
describe('updateManyObjectRecordsPermissions', () => {
|
describe('updateManyObjectRecordsPermissions', () => {
|
||||||
const personId1 = randomUUID();
|
describe('permissions V2 disabled', () => {
|
||||||
const personId2 = randomUUID();
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const createGraphqlOperation = createManyOperationFactory({
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
objectMetadataSingularName: 'person',
|
objectMetadataSingularName: 'person',
|
||||||
objectMetadataPluralName: 'people',
|
objectMetadataPluralName: 'people',
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
id: personId1,
|
id: personId1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: personId2,
|
id: personId2,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
});
|
});
|
||||||
|
|
||||||
await makeGraphqlAPIRequest(createGraphqlOperation);
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const graphqlOperation = updateManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [randomUUID(), randomUUID()],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
jobTitle: 'Architect',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ updatePeople: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const graphqlOperation = updateManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
jobTitle: 'Architect',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.updatePeople).toBeDefined();
|
||||||
|
expect(response.body.data.updatePeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.updatePeople[0].jobTitle).toBe('Architect');
|
||||||
|
expect(response.body.data.updatePeople[1].jobTitle).toBe('Architect');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
describe('permissions V2 enabled', () => {
|
||||||
const graphqlOperation = updateManyOperationFactory({
|
beforeAll(async () => {
|
||||||
objectMetadataSingularName: 'person',
|
const enablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
objectMetadataPluralName: 'people',
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
'IsPermissionsV2Enabled',
|
||||||
filter: {
|
true,
|
||||||
id: {
|
);
|
||||||
in: [randomUUID(), randomUUID()],
|
|
||||||
},
|
await makeGraphqlAPIRequest(enablePermissionsQuery);
|
||||||
},
|
|
||||||
data: {
|
|
||||||
jobTitle: 'Architect',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequestWithGuestRole(graphqlOperation);
|
afterAll(async () => {
|
||||||
|
const disablePermissionsQuery = updateFeatureFlagFactory(
|
||||||
|
SEED_APPLE_WORKSPACE_ID,
|
||||||
|
'IsPermissionsV2Enabled',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
expect(response.body.data).toStrictEqual({ updatePeople: null });
|
await makeGraphqlAPIRequest(disablePermissionsQuery);
|
||||||
expect(response.body.errors).toBeDefined();
|
|
||||||
expect(response.body.errors[0].message).toBe(
|
|
||||||
PermissionsExceptionMessage.PERMISSION_DENIED,
|
|
||||||
);
|
|
||||||
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update multiple object records when user has permission (admin role)', async () => {
|
|
||||||
const graphqlOperation = updateManyOperationFactory({
|
|
||||||
objectMetadataSingularName: 'person',
|
|
||||||
objectMetadataPluralName: 'people',
|
|
||||||
gqlFields: PERSON_GQL_FIELDS,
|
|
||||||
filter: {
|
|
||||||
id: {
|
|
||||||
in: [personId1, personId2],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
jobTitle: 'Architect',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await makeGraphqlAPIRequest(graphqlOperation);
|
it('should throw a permission error when user does not have permission (guest role)', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
expect(response.body.data).toBeDefined();
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
expect(response.body.data.updatePeople).toBeDefined();
|
|
||||||
expect(response.body.data.updatePeople).toHaveLength(2);
|
const updateGraphqlOperation = updateManyOperationFactory({
|
||||||
expect(response.body.data.updatePeople[0].jobTitle).toBe('Architect');
|
objectMetadataSingularName: 'person',
|
||||||
expect(response.body.data.updatePeople[1].jobTitle).toBe('Architect');
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
jobTitle: 'Senior Developer',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequestWithGuestRole(
|
||||||
|
updateGraphqlOperation,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.body.data).toStrictEqual({ updatePeople: null });
|
||||||
|
expect(response.body.errors).toBeDefined();
|
||||||
|
expect(response.body.errors[0].message).toBe(
|
||||||
|
PermissionsExceptionMessage.PERMISSION_DENIED,
|
||||||
|
);
|
||||||
|
expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update multiple object records when user has permission (admin role)', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const updateGraphqlOperation = updateManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
jobTitle: 'Tech Lead',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequest(updateGraphqlOperation);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.updatePeople).toBeDefined();
|
||||||
|
expect(response.body.data.updatePeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.updatePeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.updatePeople[1].id).toBe(personId2);
|
||||||
|
expect(response.body.data.updatePeople[0].jobTitle).toBe('Tech Lead');
|
||||||
|
expect(response.body.data.updatePeople[1].jobTitle).toBe('Tech Lead');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update multiple object records when executed by api key', async () => {
|
||||||
|
const personId1 = randomUUID();
|
||||||
|
const personId2 = randomUUID();
|
||||||
|
const createGraphqlOperation = createManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: personId1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: personId2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await makeGraphqlAPIRequest(createGraphqlOperation);
|
||||||
|
|
||||||
|
const updateGraphqlOperation = updateManyOperationFactory({
|
||||||
|
objectMetadataSingularName: 'person',
|
||||||
|
objectMetadataPluralName: 'people',
|
||||||
|
gqlFields: PERSON_GQL_FIELDS,
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
in: [personId1, personId2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
jobTitle: 'Product Manager',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await makeGraphqlAPIRequestWithApiKey(
|
||||||
|
updateGraphqlOperation,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.body.data).toBeDefined();
|
||||||
|
expect(response.body.data.updatePeople).toBeDefined();
|
||||||
|
expect(response.body.data.updatePeople).toHaveLength(2);
|
||||||
|
expect(response.body.data.updatePeople[0].id).toBe(personId1);
|
||||||
|
expect(response.body.data.updatePeople[1].id).toBe(personId2);
|
||||||
|
expect(response.body.data.updatePeople[0].jobTitle).toBe(
|
||||||
|
'Product Manager',
|
||||||
|
);
|
||||||
|
expect(response.body.data.updatePeople[1].jobTitle).toBe(
|
||||||
|
'Product Manager',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user