feat: refactoring casl permission checks for recursive nested operations (#778)
* feat: nested casl abilities * fix: remove unused packages * Fixes * Fix createMany broken * Fix lint * Fix lint * Fix lint * Fix lint * Fixes * Fix CommentThread * Fix bugs * Fix lint * Fix bugs * Fixed auto routing * Fixed app path --------- Co-authored-by: Charles Bochet <charles@twenty.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -16,6 +16,7 @@ import {
|
||||
PipelineStage,
|
||||
PipelineProgress,
|
||||
Attachment,
|
||||
UserSettings,
|
||||
} from '@prisma/client';
|
||||
|
||||
import { AbilityAction } from './ability.action';
|
||||
@ -34,6 +35,7 @@ type SubjectsAbility = Subjects<{
|
||||
PipelineStage: PipelineStage;
|
||||
PipelineProgress: PipelineProgress;
|
||||
Attachment: Attachment;
|
||||
UserSettings: UserSettings;
|
||||
}>;
|
||||
|
||||
export type AppAbility = PureAbility<
|
||||
@ -58,8 +60,9 @@ export class AbilityFactory {
|
||||
cannot(AbilityAction.Delete, 'User');
|
||||
|
||||
// Workspace
|
||||
can(AbilityAction.Read, 'Workspace', { id: workspace.id });
|
||||
can(AbilityAction.Update, 'Workspace', { id: workspace.id });
|
||||
can(AbilityAction.Read, 'Workspace');
|
||||
can(AbilityAction.Update, 'Workspace');
|
||||
can(AbilityAction.Delete, 'Workspace');
|
||||
|
||||
// Workspace Member
|
||||
can(AbilityAction.Read, 'WorkspaceMember', { workspaceId: workspace.id });
|
||||
@ -101,6 +104,7 @@ export class AbilityFactory {
|
||||
|
||||
// CommentThreadTarget
|
||||
can(AbilityAction.Read, 'CommentThreadTarget');
|
||||
can(AbilityAction.Create, 'CommentThreadTarget');
|
||||
|
||||
// Attachment
|
||||
can(AbilityAction.Read, 'Attachment', { workspaceId: workspace.id });
|
||||
|
||||
207
server/src/ability/ability.util.ts
Normal file
207
server/src/ability/ability.util.ts
Normal file
@ -0,0 +1,207 @@
|
||||
import { Prisma, PrismaClient } from '@prisma/client';
|
||||
import { subject } from '@casl/ability';
|
||||
|
||||
import { camelCase } from 'src/utils/camel-case';
|
||||
|
||||
import { AppAbility } from './ability.factory';
|
||||
import { AbilityAction } from './ability.action';
|
||||
|
||||
type OperationType =
|
||||
| 'create'
|
||||
| 'connectOrCreate'
|
||||
| 'upsert'
|
||||
| 'createMany'
|
||||
| 'set'
|
||||
| 'disconnect'
|
||||
| 'delete'
|
||||
| 'connect'
|
||||
| 'update'
|
||||
| 'updateMany'
|
||||
| 'deleteMany';
|
||||
|
||||
// in most case unique identifier is the id, but it can be something else...
|
||||
|
||||
type OperationAbilityChecker = (
|
||||
modelName: Prisma.ModelName,
|
||||
ability: AppAbility,
|
||||
prisma: PrismaClient,
|
||||
data: any,
|
||||
) => Promise<boolean>;
|
||||
|
||||
const createAbilityCheck: OperationAbilityChecker = async (
|
||||
modelName,
|
||||
ability,
|
||||
prisma,
|
||||
data,
|
||||
) => {
|
||||
// Handle all operations cases
|
||||
const items = data?.data
|
||||
? !Array.isArray(data.data)
|
||||
? [data.data]
|
||||
: data.data
|
||||
: !Array.isArray(data)
|
||||
? [data]
|
||||
: data;
|
||||
|
||||
// Check if user try to create an element that is not allowed to create
|
||||
for (const {} of items) {
|
||||
if (!ability.can(AbilityAction.Create, modelName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const simpleAbilityCheck: OperationAbilityChecker = async (
|
||||
modelName,
|
||||
ability,
|
||||
prisma,
|
||||
data,
|
||||
) => {
|
||||
// Extract entity name from model name
|
||||
const entity = camelCase(modelName);
|
||||
// Handle all operations cases
|
||||
const operations = !Array.isArray(data) ? [data] : data;
|
||||
// Handle where case
|
||||
const normalizedOperations = operations.map((op) =>
|
||||
op.where ? op.where : op,
|
||||
);
|
||||
// Force entity type because of Prisma typing
|
||||
const items = await prisma[entity as string].findMany({
|
||||
where: {
|
||||
OR: normalizedOperations,
|
||||
},
|
||||
});
|
||||
|
||||
// Check if user try to connect an element that is not allowed to read
|
||||
for (const item of items) {
|
||||
// TODO: Replace user by workspaceMember and remove this check
|
||||
if (
|
||||
modelName === 'User' ||
|
||||
modelName === 'UserSettings' ||
|
||||
modelName === 'Workspace'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ability.can(AbilityAction.Read, subject(modelName, item))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const operationAbilityCheckers: Record<OperationType, OperationAbilityChecker> =
|
||||
{
|
||||
create: createAbilityCheck,
|
||||
createMany: createAbilityCheck,
|
||||
upsert: simpleAbilityCheck,
|
||||
update: simpleAbilityCheck,
|
||||
updateMany: simpleAbilityCheck,
|
||||
delete: simpleAbilityCheck,
|
||||
deleteMany: simpleAbilityCheck,
|
||||
connectOrCreate: simpleAbilityCheck,
|
||||
connect: simpleAbilityCheck,
|
||||
disconnect: simpleAbilityCheck,
|
||||
set: simpleAbilityCheck,
|
||||
};
|
||||
|
||||
// Check relation nested abilities
|
||||
export async function relationAbilityChecker(
|
||||
modelName: Prisma.ModelName,
|
||||
ability: AppAbility,
|
||||
prisma: PrismaClient,
|
||||
args: any,
|
||||
) {
|
||||
// Extract models from Prisma
|
||||
const models = Prisma.dmmf.datamodel.models;
|
||||
// Find main model from options
|
||||
const mainModel = models.find((item) => item.name === modelName);
|
||||
|
||||
if (!mainModel) {
|
||||
throw new Error('Main model not found');
|
||||
}
|
||||
|
||||
// Loop over fields
|
||||
for (const field of mainModel.fields) {
|
||||
// Check if field is a relation
|
||||
if (field.relationName) {
|
||||
// Check if field is in args
|
||||
const operation = args.data?.[field.name] ?? args?.[field.name];
|
||||
|
||||
if (operation) {
|
||||
// Extract operation name and value
|
||||
const operationType = Object.keys(operation)[0] as OperationType;
|
||||
const operationValue = operation[operationType];
|
||||
|
||||
// Get operation checker for the operation type
|
||||
const operationChecker = operationAbilityCheckers[operationType];
|
||||
|
||||
if (!operationChecker) {
|
||||
throw new Error('Operation not found');
|
||||
}
|
||||
|
||||
// Check if operation is allowed
|
||||
const allowed = await operationChecker(
|
||||
field.type as Prisma.ModelName,
|
||||
ability,
|
||||
prisma,
|
||||
operationValue,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For the 'create', 'connectOrCreate', 'upsert', 'update', and 'updateMany' operations,
|
||||
// we should also check the nested operations.
|
||||
if (
|
||||
[
|
||||
'create',
|
||||
'connectOrCreate',
|
||||
'upsert',
|
||||
'update',
|
||||
'updateMany',
|
||||
].includes(operationType)
|
||||
) {
|
||||
// Handle nested operations all cases
|
||||
|
||||
const operationValues = !Array.isArray(operationValue)
|
||||
? [operationValue]
|
||||
: operationValue;
|
||||
|
||||
// Loop over nested args
|
||||
for (const nestedArgs of operationValues) {
|
||||
const nestedCreateAllowed = await relationAbilityChecker(
|
||||
field.type as Prisma.ModelName,
|
||||
ability,
|
||||
prisma,
|
||||
nestedArgs.create ?? nestedArgs.data ?? nestedArgs,
|
||||
);
|
||||
|
||||
if (!nestedCreateAllowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nestedArgs.update) {
|
||||
const nestedUpdateAllowed = await relationAbilityChecker(
|
||||
field.type as Prisma.ModelName,
|
||||
ability,
|
||||
prisma,
|
||||
nestedArgs.update,
|
||||
);
|
||||
|
||||
if (!nestedUpdateAllowed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -42,7 +42,7 @@ export class CreateAttachmentAbilityHandler implements IAbilityHandler {
|
||||
const args = gqlContext.getArgs<AttachmentArgs>();
|
||||
assert(args.activityId, '', ForbiddenException);
|
||||
|
||||
const activity = await this.prismaService.commentThread.findUnique({
|
||||
const activity = await this.prismaService.client.commentThread.findUnique({
|
||||
where: { id: args.activityId },
|
||||
include: { workspace: true },
|
||||
});
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { CommentThreadTargetWhereInput } from 'src/core/@generated/comment-thread-target/comment-thread-target-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class CommentThreadTargetArgs {
|
||||
where?: CommentThreadTargetWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -39,7 +41,23 @@ export class ReadCommentThreadTargetAbilityHandler implements IAbilityHandler {
|
||||
export class CreateCommentThreadTargetAbilityHandler
|
||||
implements IAbilityHandler
|
||||
{
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'CommentThreadTarget',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'CommentThreadTarget');
|
||||
}
|
||||
}
|
||||
@ -54,11 +72,22 @@ export class UpdateCommentThreadTargetAbilityHandler
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<CommentThreadTargetArgs>();
|
||||
const commentThreadTarget =
|
||||
await this.prismaService.commentThreadTarget.findFirst({
|
||||
await this.prismaService.client.commentThreadTarget.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(commentThreadTarget, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'CommentThreadTarget',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(
|
||||
AbilityAction.Update,
|
||||
subject('CommentThreadTarget', commentThreadTarget),
|
||||
@ -76,7 +105,7 @@ export class DeleteCommentThreadTargetAbilityHandler
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<CommentThreadTargetArgs>();
|
||||
const commentThreadTarget =
|
||||
await this.prismaService.commentThreadTarget.findFirst({
|
||||
await this.prismaService.client.commentThreadTarget.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(commentThreadTarget, '', NotFoundException);
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { CommentThreadWhereInput } from 'src/core/@generated/comment-thread/comment-thread-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class CommentThreadArgs {
|
||||
where?: CommentThreadWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadCommentThreadAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreateCommentThreadAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'CommentThread',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'CommentThread');
|
||||
}
|
||||
}
|
||||
@ -47,11 +65,23 @@ export class UpdateCommentThreadAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<CommentThreadArgs>();
|
||||
const commentThread = await this.prismaService.commentThread.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
const commentThread =
|
||||
await this.prismaService.client.commentThread.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(commentThread, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'CommentThread',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(
|
||||
AbilityAction.Update,
|
||||
subject('CommentThread', commentThread),
|
||||
@ -66,9 +96,10 @@ export class DeleteCommentThreadAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<CommentThreadArgs>();
|
||||
const commentThread = await this.prismaService.commentThread.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
const commentThread =
|
||||
await this.prismaService.client.commentThread.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(commentThread, '', NotFoundException);
|
||||
|
||||
return ability.can(
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { CommentWhereInput } from 'src/core/@generated/comment/comment-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class CommentArgs {
|
||||
where?: CommentWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadCommentAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreateCommentAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Comment',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'Comment');
|
||||
}
|
||||
}
|
||||
@ -47,11 +65,22 @@ export class UpdateCommentAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<CommentArgs>();
|
||||
const comment = await this.prismaService.comment.findFirst({
|
||||
const comment = await this.prismaService.client.comment.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(comment, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Comment',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Update, subject('Comment', comment));
|
||||
}
|
||||
}
|
||||
@ -63,7 +92,7 @@ export class DeleteCommentAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<CommentArgs>();
|
||||
const comment = await this.prismaService.comment.findFirst({
|
||||
const comment = await this.prismaService.client.comment.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(comment, '', NotFoundException);
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { CompanyWhereInput } from 'src/core/@generated/company/company-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class CompanyArgs {
|
||||
where?: CompanyWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadCompanyAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreateCompanyAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Company',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'Company');
|
||||
}
|
||||
}
|
||||
@ -47,12 +65,22 @@ export class UpdateCompanyAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<CompanyArgs>();
|
||||
const company = await this.prismaService.company.findFirst({
|
||||
const company = await this.prismaService.client.company.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
|
||||
assert(company, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Company',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Update, subject('Company', company));
|
||||
}
|
||||
}
|
||||
@ -64,7 +92,7 @@ export class DeleteCompanyAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<CompanyArgs>();
|
||||
const company = await this.prismaService.company.findFirst({
|
||||
const company = await this.prismaService.client.company.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(company, '', NotFoundException);
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { PersonWhereInput } from 'src/core/@generated/person/person-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class PersonArgs {
|
||||
where?: PersonWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadPersonAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreatePersonAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Person',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'Person');
|
||||
}
|
||||
}
|
||||
@ -47,11 +65,22 @@ export class UpdatePersonAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<PersonArgs>();
|
||||
const person = await this.prismaService.person.findFirst({
|
||||
const person = await this.prismaService.client.person.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(person, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Person',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Update, subject('Person', person));
|
||||
}
|
||||
}
|
||||
@ -63,7 +92,7 @@ export class DeletePersonAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<PersonArgs>();
|
||||
const person = await this.prismaService.person.findFirst({
|
||||
const person = await this.prismaService.client.person.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(person, '', NotFoundException);
|
||||
|
||||
@ -12,11 +12,13 @@ import { IAbilityHandler } from 'src/ability/interfaces/ability-handler.interfac
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { assert } from 'src/utils/assert';
|
||||
import { PipelineProgressWhereInput } from 'src/core/@generated/pipeline-progress/pipeline-progress-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class PipelineProgressArgs {
|
||||
where?: PipelineProgressWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadPipelineProgressAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreatePipelineProgressAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'PipelineProgress',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'PipelineProgress');
|
||||
}
|
||||
}
|
||||
@ -48,11 +66,22 @@ export class UpdatePipelineProgressAbilityHandler implements IAbilityHandler {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<PipelineProgressArgs>();
|
||||
const pipelineProgress =
|
||||
await this.prismaService.pipelineProgress.findFirst({
|
||||
await this.prismaService.client.pipelineProgress.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(pipelineProgress, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'PipelineProgress',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(
|
||||
AbilityAction.Update,
|
||||
subject('PipelineProgress', pipelineProgress),
|
||||
@ -68,7 +97,7 @@ export class DeletePipelineProgressAbilityHandler implements IAbilityHandler {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<PipelineProgressArgs>();
|
||||
const pipelineProgress =
|
||||
await this.prismaService.pipelineProgress.findFirst({
|
||||
await this.prismaService.client.pipelineProgress.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(pipelineProgress, '', NotFoundException);
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { PipelineStageWhereInput } from 'src/core/@generated/pipeline-stage/pipeline-stage-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class PipelineStageArgs {
|
||||
where?: PipelineStageWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadPipelineStageAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreatePipelineStageAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'PipelineStage',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'PipelineStage');
|
||||
}
|
||||
}
|
||||
@ -47,11 +65,23 @@ export class UpdatePipelineStageAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<PipelineStageArgs>();
|
||||
const pipelineStage = await this.prismaService.pipelineStage.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
const pipelineStage =
|
||||
await this.prismaService.client.pipelineStage.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(pipelineStage, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'PipelineStage',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(
|
||||
AbilityAction.Update,
|
||||
subject('PipelineStage', pipelineStage),
|
||||
@ -66,9 +96,10 @@ export class DeletePipelineStageAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<PipelineStageArgs>();
|
||||
const pipelineStage = await this.prismaService.pipelineStage.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
const pipelineStage =
|
||||
await this.prismaService.client.pipelineStage.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(pipelineStage, '', NotFoundException);
|
||||
|
||||
return ability.can(
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { PipelineWhereInput } from 'src/core/@generated/pipeline/pipeline-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class PipelineArgs {
|
||||
where?: PipelineWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadPipelineAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreatePipelineAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Pipeline',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'Pipeline');
|
||||
}
|
||||
}
|
||||
@ -47,11 +65,22 @@ export class UpdatePipelineAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<PipelineArgs>();
|
||||
const pipeline = await this.prismaService.pipeline.findFirst({
|
||||
const pipeline = await this.prismaService.client.pipeline.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(pipeline, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Pipeline',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Update, subject('Pipeline', pipeline));
|
||||
}
|
||||
}
|
||||
@ -63,7 +92,7 @@ export class DeletePipelineAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<PipelineArgs>();
|
||||
const pipeline = await this.prismaService.pipeline.findFirst({
|
||||
const pipeline = await this.prismaService.client.pipeline.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(pipeline, '', NotFoundException);
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { RefreshTokenWhereInput } from 'src/core/@generated/refresh-token/refresh-token-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class RefreshTokenArgs {
|
||||
where?: RefreshTokenWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadRefreshTokenAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreateRefreshTokenAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'RefreshToken',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'RefreshToken');
|
||||
}
|
||||
}
|
||||
@ -47,11 +65,24 @@ export class UpdateRefreshTokenAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<RefreshTokenArgs>();
|
||||
const refreshToken = await this.prismaService.refreshToken.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
const refreshToken = await this.prismaService.client.refreshToken.findFirst(
|
||||
{
|
||||
where: args.where,
|
||||
},
|
||||
);
|
||||
assert(refreshToken, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'RefreshToken',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(
|
||||
AbilityAction.Update,
|
||||
subject('RefreshToken', refreshToken),
|
||||
@ -66,9 +97,11 @@ export class DeleteRefreshTokenAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<RefreshTokenArgs>();
|
||||
const refreshToken = await this.prismaService.refreshToken.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
const refreshToken = await this.prismaService.client.refreshToken.findFirst(
|
||||
{
|
||||
where: args.where,
|
||||
},
|
||||
);
|
||||
assert(refreshToken, '', NotFoundException);
|
||||
|
||||
return ability.can(
|
||||
|
||||
@ -12,11 +12,13 @@ import { IAbilityHandler } from 'src/ability/interfaces/ability-handler.interfac
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { assert } from 'src/utils/assert';
|
||||
import { UserWhereInput } from 'src/core/@generated/user/user-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class UserArgs {
|
||||
where?: UserWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadUserAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreateUserAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'User',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'User');
|
||||
}
|
||||
}
|
||||
@ -47,11 +65,22 @@ export class UpdateUserAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<UserArgs>();
|
||||
const user = await this.prismaService.user.findFirst({
|
||||
const user = await this.prismaService.client.user.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(user, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'User',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Update, subject('User', user));
|
||||
}
|
||||
}
|
||||
@ -63,7 +92,7 @@ export class DeleteUserAbilityHandler implements IAbilityHandler {
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<UserArgs>();
|
||||
const user = await this.prismaService.user.findFirst({
|
||||
const user = await this.prismaService.client.user.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(user, '', NotFoundException);
|
||||
|
||||
@ -13,10 +13,12 @@ import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { WorkspaceMemberWhereInput } from 'src/core/@generated/workspace-member/workspace-member-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class WorksapceMemberArgs {
|
||||
class WorkspaceMemberArgs {
|
||||
where?: WorkspaceMemberWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -35,7 +37,23 @@ export class ReadWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreateWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'WorkspaceMember',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'WorkspaceMember');
|
||||
}
|
||||
}
|
||||
@ -46,12 +64,24 @@ export class UpdateWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<WorksapceMemberArgs>();
|
||||
const workspaceMember = await this.prismaService.workspaceMember.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
const args = gqlContext.getArgs<WorkspaceMemberArgs>();
|
||||
const workspaceMember =
|
||||
await this.prismaService.client.workspaceMember.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(workspaceMember, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'WorkspaceMember',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(
|
||||
AbilityAction.Update,
|
||||
subject('WorkspaceMember', workspaceMember),
|
||||
@ -65,10 +95,11 @@ export class DeleteWorkspaceMemberAbilityHandler implements IAbilityHandler {
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<WorksapceMemberArgs>();
|
||||
const workspaceMember = await this.prismaService.workspaceMember.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
const args = gqlContext.getArgs<WorkspaceMemberArgs>();
|
||||
const workspaceMember =
|
||||
await this.prismaService.client.workspaceMember.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(workspaceMember, '', NotFoundException);
|
||||
|
||||
return ability.can(
|
||||
|
||||
@ -1,24 +1,22 @@
|
||||
import {
|
||||
ExecutionContext,
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { subject } from '@casl/ability';
|
||||
|
||||
import { IAbilityHandler } from 'src/ability/interfaces/ability-handler.interface';
|
||||
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { AbilityAction } from 'src/ability/ability.action';
|
||||
import { AppAbility } from 'src/ability/ability.factory';
|
||||
import { WorkspaceWhereInput } from 'src/core/@generated/workspace/workspace-where.input';
|
||||
import { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { assert } from 'src/utils/assert';
|
||||
import { getRequest } from 'src/utils/extract-request';
|
||||
|
||||
class WorksapceArgs {
|
||||
class WorkspaceArgs {
|
||||
where?: WorkspaceWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -37,7 +35,23 @@ export class ReadWorkspaceAbilityHandler implements IAbilityHandler {
|
||||
|
||||
@Injectable()
|
||||
export class CreateWorkspaceAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Workspace',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'Workspace');
|
||||
}
|
||||
}
|
||||
@ -47,15 +61,25 @@ export class UpdateWorkspaceAbilityHandler implements IAbilityHandler {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const request = getRequest(context);
|
||||
assert(request.user.workspace.id, '', ForbiddenException);
|
||||
|
||||
const workspace = await this.prismaService.workspace.findUnique({
|
||||
where: { id: request.user.workspace.id },
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<WorkspaceArgs>();
|
||||
const workspace = await this.prismaService.client.workspace.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(workspace, '', NotFoundException);
|
||||
|
||||
return ability.can(AbilityAction.Update, subject('Workspace', workspace));
|
||||
const allowed = await relationAbilityChecker(
|
||||
'Workspace',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Update, 'Workspace');
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,12 +89,12 @@ export class DeleteWorkspaceAbilityHandler implements IAbilityHandler {
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<WorksapceArgs>();
|
||||
const workspace = await this.prismaService.workspace.findFirst({
|
||||
const args = gqlContext.getArgs<WorkspaceArgs>();
|
||||
const workspace = await this.prismaService.client.workspace.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(workspace, '', NotFoundException);
|
||||
|
||||
return ability.can(AbilityAction.Delete, subject('Workspace', workspace));
|
||||
return ability.can(AbilityAction.Delete, 'Workspace');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user