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 { DataSource, In, Repository } from '@n8n/typeorm';
import { Service } from 'typedi'; 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> = { const findManyOptions: FindManyOptions<TestEntity> = {
select: { ...select, id: true },
where, 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) { if (options?.take) {
findManyOptions.skip = options.skip; findManyOptions.skip = options.skip;
findManyOptions.take = options.take; findManyOptions.take = options.take;
@ -56,4 +36,25 @@ export class TestRepository extends Repository<TestEntity> {
return { tests, count }; 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 { listQueryMiddleware } from '@/middlewares';
import { getSharedWorkflowIds } from '@/public-api/v1/handlers/workflows/workflows.service';
import { isPositiveInteger } from '@/utils';
import { TestsService } from './tests.service'; import { TestsService } from './tests.service';
import { TestsRequest } from './tests.types'; import { TestsRequest } from './tests.types';
@ -8,62 +12,61 @@ import { TestsRequest } from './tests.types';
export class TestsController { export class TestsController {
constructor(private readonly testsService: TestsService) {} 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 }) @Get('/', { middlewares: listQueryMiddleware })
async getMany(req: TestsRequest.GetMany) { 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') @Get('/:id')
// async getOne(req: ExecutionRequest.GetOne) { async getOne(req: TestsRequest.GetOne) {
// if (!isPositiveInteger(req.params.id)) { if (!isPositiveInteger(req.params.id)) {
// throw new BadRequestError('Execution ID is not a number'); throw new BadRequestError('Test ID is not a number');
// } }
//
// const workflowIds = await this.getAccessibleWorkflowIds(req.user, 'workflow:read'); const workflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
//
// if (workflowIds.length === 0) throw new NotFoundError('Execution not found'); return await this.testsService.findOne(Number(req.params.id), workflowIds);
// }
// return this.license.isSharingEnabled()
// ? await this.enterpriseExecutionService.findOne(req, workflowIds) @Post('/')
// : await this.executionService.findOne(req, workflowIds); async create(req: TestsRequest.Create) {
// } const workflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
//
// @Post('/delete') if (!workflowIds.includes(req.body.workflowId)) {
// async delete(req: ExecutionRequest.Delete) { throw new BadRequestError('User does not have access to the workflow');
// const workflowIds = await this.getAccessibleWorkflowIds(req.user, 'workflow:execute'); }
//
// if (workflowIds.length === 0) throw new NotFoundError('Execution not found'); return await this.testsService.save(this.testsService.toEntity(req.body));
// }
// return await this.executionService.delete(req, workflowIds);
// } @Delete('/:id')
// async delete(req: TestsRequest.Delete) {
// @Patch('/:id') if (!isPositiveInteger(req.params.id)) {
// async update(req: ExecutionRequest.Update) { throw new BadRequestError('Test ID is not a number');
// if (!isPositiveInteger(req.params.id)) { }
// throw new BadRequestError('Execution ID is not a number');
// } const workflowIds = await getSharedWorkflowIds(req.user, ['workflow:read']);
//
// const workflowIds = await this.getAccessibleWorkflowIds(req.user, 'workflow:read'); if (workflowIds.length === 0) throw new NotFoundError('Test not found');
//
// // Fail fast if no workflows are accessible return await this.testsService.delete(Number(req.params.id), workflowIds);
// if (workflowIds.length === 0) throw new NotFoundError('Execution not found'); }
//
// const { body: payload } = req; @Patch('/:id')
// const validatedPayload = validateExecutionUpdatePayload(payload); async update(req: TestsRequest.Update) {
// if (!isPositiveInteger(req.params.id)) {
// await this.executionService.annotate(req.params.id, validatedPayload, workflowIds); throw new BadRequestError('Test ID is not a number');
// }
// return await this.executionService.findOne(req, workflowIds);
// } 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, private readonly workflowSharingService: WorkflowSharingService,
) {} ) {}
// toEntity(attrs: { name: string; id?: string }) { toEntity(attrs: {
// attrs.name = attrs.name.trim(); name?: string;
// workflowId?: string;
// return this.testRepository.create(attrs); 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) { async save(test: TestEntity) {
await validateEntity(test); await validateEntity(test);
@ -26,15 +53,11 @@ export class TestsService {
return await this.testRepository.save(test); return await this.testRepository.save(test);
} }
async delete(id: string) { async delete(id: number, accessibleWorkflowIds: string[]) {
return await this.testRepository.delete(id); return await this.testRepository.deleteById(id, accessibleWorkflowIds);
} }
async getMany(user: User, options: ListQuery.Options) { async getMany(user: User, options: ListQuery.Options, accessibleWorkflowIds: string[] = []) {
const sharedWorkflowIds = await this.workflowSharingService.getSharedWorkflowIds(user, { return await this.testRepository.getMany(accessibleWorkflowIds, options);
scopes: ['workflow:read'],
});
return await this.testRepository.getMany(sharedWorkflowIds, options);
} }
} }

View file

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