wip: evaluation/tests endpoint CRUD

This commit is contained in:
Eugene Molodkin 2024-11-05 16:10:24 +01:00 committed by Oleg Ivaniv
parent 961d42fd51
commit de4d486223
No known key found for this signature in database
4 changed files with 119 additions and 93 deletions

View file

@ -1,4 +1,4 @@
import type { FindManyOptions, FindOptionsSelect, FindOptionsWhere } from '@n8n/typeorm';
import type { FindManyOptions, FindOptionsWhere } from '@n8n/typeorm';
import { DataSource, In, Repository } from '@n8n/typeorm';
import { Service } from 'typedi';
@ -21,32 +21,12 @@ export class TestRepository extends Repository<TestEntity> {
},
};
type Select = FindOptionsSelect<TestEntity>;
const select: Select = {
id: true,
name: true,
createdAt: true,
updatedAt: true,
};
const relations: string[] = ['workflow', 'evaluationWorkflow', 'annotationTag'];
const isDefaultSelect = options?.select === undefined;
const findManyOptions: FindManyOptions<TestEntity> = {
select: { ...select, id: true },
where,
relations: ['annotationTag'],
order: { createdAt: 'DESC' },
};
if (isDefaultSelect || options?.select?.updatedAt === true) {
findManyOptions.order = { updatedAt: 'ASC' };
}
if (relations.length > 0) {
findManyOptions.relations = relations;
}
if (options?.take) {
findManyOptions.skip = options.skip;
findManyOptions.take = options.take;
@ -56,4 +36,25 @@ export class TestRepository extends Repository<TestEntity> {
return { tests, count };
}
async getOne(id: number, sharedWorkflowIds: string[]) {
return await this.findOne({
where: {
id,
workflow: {
id: In(sharedWorkflowIds),
},
},
relations: ['annotationTag'],
});
}
async deleteById(id: number, sharedWorkflowIds: string[]) {
return await this.delete({
id,
workflow: {
id: In(sharedWorkflowIds),
},
});
}
}

View file

@ -1,5 +1,9 @@
import { Get, /*Patch, Post,*/ RestController } from '@/decorators';
import { Get, Post, Patch, RestController, Delete } from '@/decorators';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { NotFoundError } from '@/errors/response-errors/not-found.error';
import { listQueryMiddleware } from '@/middlewares';
import { getSharedWorkflowIds } from '@/public-api/v1/handlers/workflows/workflows.service';
import { isPositiveInteger } from '@/utils';
import { TestsService } from './tests.service';
import { TestsRequest } from './tests.types';
@ -8,62 +12,61 @@ import { TestsRequest } from './tests.types';
export class TestsController {
constructor(private readonly testsService: TestsService) {}
// private async getAccessibleWorkflowIds(user: User, scope: Scope) {
// if (this.license.isSharingEnabled()) {
// return await this.workflowSharingService.getSharedWorkflowIds(user, { scopes: [scope] });
// } else {
// return await this.workflowSharingService.getSharedWorkflowIds(user, {
// workflowRoles: ['workflow:owner'],
// projectRoles: ['project:personalOwner'],
// });
// }
// }
@Get('/', { middlewares: listQueryMiddleware })
async getMany(req: TestsRequest.GetMany) {
return await this.testsService.getMany(req.user, req.listQueryOptions);
const workflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
return await this.testsService.getMany(req.user, req.listQueryOptions, workflowIds);
}
// @Get('/:id')
// async getOne(req: ExecutionRequest.GetOne) {
// if (!isPositiveInteger(req.params.id)) {
// throw new BadRequestError('Execution ID is not a number');
// }
//
// const workflowIds = await this.getAccessibleWorkflowIds(req.user, 'workflow:read');
//
// if (workflowIds.length === 0) throw new NotFoundError('Execution not found');
//
// return this.license.isSharingEnabled()
// ? await this.enterpriseExecutionService.findOne(req, workflowIds)
// : await this.executionService.findOne(req, workflowIds);
// }
//
// @Post('/delete')
// async delete(req: ExecutionRequest.Delete) {
// const workflowIds = await this.getAccessibleWorkflowIds(req.user, 'workflow:execute');
//
// if (workflowIds.length === 0) throw new NotFoundError('Execution not found');
//
// return await this.executionService.delete(req, workflowIds);
// }
//
// @Patch('/:id')
// async update(req: ExecutionRequest.Update) {
// if (!isPositiveInteger(req.params.id)) {
// throw new BadRequestError('Execution ID is not a number');
// }
//
// const workflowIds = await this.getAccessibleWorkflowIds(req.user, 'workflow:read');
//
// // Fail fast if no workflows are accessible
// if (workflowIds.length === 0) throw new NotFoundError('Execution not found');
//
// const { body: payload } = req;
// const validatedPayload = validateExecutionUpdatePayload(payload);
//
// await this.executionService.annotate(req.params.id, validatedPayload, workflowIds);
//
// return await this.executionService.findOne(req, workflowIds);
// }
@Get('/:id')
async getOne(req: TestsRequest.GetOne) {
if (!isPositiveInteger(req.params.id)) {
throw new BadRequestError('Test ID is not a number');
}
const workflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
return await this.testsService.findOne(Number(req.params.id), workflowIds);
}
@Post('/')
async create(req: TestsRequest.Create) {
const workflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
if (!workflowIds.includes(req.body.workflowId)) {
throw new BadRequestError('User does not have access to the workflow');
}
return await this.testsService.save(this.testsService.toEntity(req.body));
}
@Delete('/:id')
async delete(req: TestsRequest.Delete) {
if (!isPositiveInteger(req.params.id)) {
throw new BadRequestError('Test ID is not a number');
}
const workflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
if (workflowIds.length === 0) throw new NotFoundError('Test not found');
return await this.testsService.delete(Number(req.params.id), workflowIds);
}
@Patch('/:id')
async update(req: TestsRequest.Update) {
if (!isPositiveInteger(req.params.id)) {
throw new BadRequestError('Test ID is not a number');
}
const workflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
// Fail fast if no workflows are accessible
if (workflowIds.length === 0) throw new NotFoundError('Workflow not found');
return await this.testsService.save(
this.testsService.toEntity({ ...req.body, id: Number(req.params.id) }),
);
}
}

View file

@ -14,11 +14,38 @@ export class TestsService {
private readonly workflowSharingService: WorkflowSharingService,
) {}
// toEntity(attrs: { name: string; id?: string }) {
// attrs.name = attrs.name.trim();
//
// return this.testRepository.create(attrs);
// }
toEntity(attrs: {
name?: string;
workflowId?: string;
evaluationWorkflowId?: string;
id?: number;
}) {
const entity = {
name: attrs.name?.trim(),
};
if (attrs.id) {
entity.id = attrs.id;
}
if (attrs.workflowId) {
entity.workflow = {
id: attrs.workflowId,
};
}
if (attrs.evaluationWorkflowId) {
entity.evaluationWorkflow = {
id: attrs.evaluationWorkflowId,
};
}
return this.testRepository.create(entity);
}
async findOne(id: number, accessibleWorkflowIds: string[]) {
return await this.testRepository.getOne(id, accessibleWorkflowIds);
}
async save(test: TestEntity) {
await validateEntity(test);
@ -26,15 +53,11 @@ export class TestsService {
return await this.testRepository.save(test);
}
async delete(id: string) {
return await this.testRepository.delete(id);
async delete(id: number, accessibleWorkflowIds: string[]) {
return await this.testRepository.deleteById(id, accessibleWorkflowIds);
}
async getMany(user: User, options: ListQuery.Options) {
const sharedWorkflowIds = await this.workflowSharingService.getSharedWorkflowIds(user, {
scopes: ['workflow:read'],
});
return await this.testRepository.getMany(sharedWorkflowIds, options);
async getMany(user: User, options: ListQuery.Options, accessibleWorkflowIds: string[] = []) {
return await this.testRepository.getMany(accessibleWorkflowIds, options);
}
}

View file

@ -1,4 +1,3 @@
import type { TestEntity } from '@/databases/entities/test-entity';
import type { AuthenticatedRequest, ListQuery } from '@/requests';
// ----------------------------------
@ -8,7 +7,7 @@ import type { AuthenticatedRequest, ListQuery } from '@/requests';
export declare namespace TestsRequest {
namespace RouteParams {
type TestId = {
id: TestEntity['id'];
id: string;
};
}