mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
refactor(core): Separate list query entities from request types (#15015)
This commit is contained in:
@@ -21,9 +21,9 @@ import { FolderNotFoundError } from '@/errors/folder-not-found.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import type { ListQuery } from '@/requests';
|
||||
import { AuthenticatedRequest } from '@/requests';
|
||||
import { FolderService } from '@/services/folder.service';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
|
||||
@RestController('/projects/:projectId/folders')
|
||||
export class ProjectController {
|
||||
|
||||
@@ -27,11 +27,10 @@ import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { listQueryMiddleware } from '@/middlewares';
|
||||
import { AuthenticatedRequest, UserRequest } from '@/requests';
|
||||
import { ListQuery, AuthenticatedRequest, UserRequest } from '@/requests';
|
||||
import { FolderService } from '@/services/folder.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { ListQuery } from '@/types-db';
|
||||
import type { PublicUser } from '@/types-db';
|
||||
import { WorkflowService } from '@/workflows/workflow.service';
|
||||
|
||||
|
||||
@@ -33,12 +33,12 @@ import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { validateEntity } from '@/generic-helpers';
|
||||
import { userHasScopes } from '@/permissions.ee/check-access';
|
||||
import type { CredentialRequest } from '@/requests';
|
||||
import type { CredentialRequest, ListQuery } from '@/requests';
|
||||
import { CredentialsTester } from '@/services/credentials-tester.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import type { ICredentialsDb, ListQuery, ScopesField } from '@/types-db';
|
||||
import type { ICredentialsDb, ScopesField } from '@/types-db';
|
||||
|
||||
import { CredentialsFinderService } from './credentials-finder.service';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Service } from '@n8n/di';
|
||||
import { DataSource, In, Repository, Like } from '@n8n/typeorm';
|
||||
import type { FindManyOptions } from '@n8n/typeorm';
|
||||
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQuery } from '@/requests';
|
||||
|
||||
import { CredentialsEntity } from '../entities/credentials-entity';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { EntityManager, SelectQueryBuilder } from '@n8n/typeorm';
|
||||
import { DataSource, Repository } from '@n8n/typeorm';
|
||||
import { PROJECT_ROOT } from 'n8n-workflow';
|
||||
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQuery } from '@/requests';
|
||||
|
||||
import type { FolderWithWorkflowAndSubFolderCount } from '../entities/folder';
|
||||
import { Folder } from '../entities/folder';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { DataSource, In, Repository } from '@n8n/typeorm';
|
||||
|
||||
import { TestDefinition } from '@/databases/entities/test-definition.ee';
|
||||
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQuery } from '@/requests';
|
||||
|
||||
@Service()
|
||||
export class TestDefinitionRepository extends Repository<TestDefinition> {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { TestRun } from '@/databases/entities/test-run.ee';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import type { TestRunErrorCode } from '@/evaluation.ee/test-runner/errors.ee';
|
||||
import { getTestRunFinalResult } from '@/evaluation.ee/test-runner/utils.ee';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQuery } from '@/requests';
|
||||
|
||||
export type TestRunFinalResult = 'success' | 'error' | 'warning';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { GlobalRole } from '@n8n/permissions';
|
||||
import type { DeepPartial, EntityManager, FindManyOptions } from '@n8n/typeorm';
|
||||
import { DataSource, In, IsNull, Not, Repository } from '@n8n/typeorm';
|
||||
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQuery } from '@/requests';
|
||||
|
||||
import { Project } from '../entities/project';
|
||||
import { ProjectRelation } from '../entities/project-relation';
|
||||
|
||||
@@ -13,7 +13,8 @@ import type {
|
||||
} from '@n8n/typeorm';
|
||||
import { PROJECT_ROOT } from 'n8n-workflow';
|
||||
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQuery } from '@/requests';
|
||||
import type { ListQueryDb } from '@/types-db';
|
||||
|
||||
import { FolderRepository } from './folder.repository';
|
||||
import type { Folder, FolderWithWorkflowAndSubFolderCount } from '../entities/folder';
|
||||
@@ -33,8 +34,8 @@ type WorkflowFolderUnionRow = {
|
||||
};
|
||||
|
||||
export type WorkflowFolderUnionFull = (
|
||||
| ListQuery.Workflow.Plain
|
||||
| ListQuery.Workflow.WithSharing
|
||||
| ListQueryDb.Workflow.Plain
|
||||
| ListQueryDb.Workflow.WithSharing
|
||||
| FolderWithWorkflowAndSubFolderCount
|
||||
) & {
|
||||
resource: ResourceType;
|
||||
@@ -320,7 +321,7 @@ export class WorkflowRepository extends Repository<WorkflowEntity> {
|
||||
private enrichDataWithExtras(
|
||||
baseData: WorkflowFolderUnionRow[],
|
||||
extraData: {
|
||||
workflows: ListQuery.Workflow.WithSharing[] | ListQuery.Workflow.Plain[];
|
||||
workflows: ListQueryDb.Workflow.WithSharing[] | ListQueryDb.Workflow.Plain[];
|
||||
folders: Folder[];
|
||||
},
|
||||
): WorkflowFolderUnionFull[] {
|
||||
@@ -343,8 +344,8 @@ export class WorkflowRepository extends Repository<WorkflowEntity> {
|
||||
const query = this.getManyQuery(workflowIds, options);
|
||||
|
||||
const workflows = (await query.getMany()) as
|
||||
| ListQuery.Workflow.Plain[]
|
||||
| ListQuery.Workflow.WithSharing[];
|
||||
| ListQueryDb.Workflow.Plain[]
|
||||
| ListQueryDb.Workflow.WithSharing[];
|
||||
|
||||
return workflows;
|
||||
}
|
||||
@@ -357,7 +358,7 @@ export class WorkflowRepository extends Repository<WorkflowEntity> {
|
||||
const query = this.getManyQuery(sharedWorkflowIds, options);
|
||||
|
||||
const [workflows, count] = (await query.getManyAndCount()) as [
|
||||
ListQuery.Workflow.Plain[] | ListQuery.Workflow.WithSharing[],
|
||||
ListQueryDb.Workflow.Plain[] | ListQueryDb.Workflow.WithSharing[],
|
||||
number,
|
||||
];
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ import { TestDefinitionRepository } from '@/databases/repositories/test-definiti
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { validateEntity } from '@/generic-helpers';
|
||||
import type { ListQuery } from '@/requests';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
|
||||
type TestDefinitionLike = Omit<
|
||||
Partial<TestDefinition>,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { MockedNodeItem } from '@/databases/entities/test-definition.ee';
|
||||
import type { AuthenticatedRequest } from '@/requests';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { AuthenticatedRequest, ListQuery } from '@/requests';
|
||||
|
||||
// ----------------------------------
|
||||
// /test-definitions
|
||||
|
||||
@@ -3,8 +3,9 @@ import type { Response, NextFunction } from 'express';
|
||||
import { filterListQueryMiddleware } from '@/middlewares/list-query/filter';
|
||||
import { paginationListQueryMiddleware } from '@/middlewares/list-query/pagination';
|
||||
import { selectListQueryMiddleware } from '@/middlewares/list-query/select';
|
||||
import type { ListQuery } from '@/requests';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQueryDb } from '@/types-db';
|
||||
|
||||
import { sortByQueryMiddleware } from '../sort-by';
|
||||
|
||||
@@ -177,7 +178,7 @@ describe('List query middleware', () => {
|
||||
});
|
||||
|
||||
describe('Query sort by', () => {
|
||||
const validCases: Array<{ name: string; value: ListQuery.Workflow.SortOrder }> = [
|
||||
const validCases: Array<{ name: string; value: ListQueryDb.Workflow.SortOrder }> = [
|
||||
{
|
||||
name: 'sorting by name asc',
|
||||
value: 'name:asc',
|
||||
@@ -236,7 +237,7 @@ describe('List query middleware', () => {
|
||||
|
||||
test.each(invalidCases)('should fail validation when $name', async ({ value }) => {
|
||||
mockReq.query = {
|
||||
sortBy: value as ListQuery.Workflow.SortOrder,
|
||||
sortBy: value as ListQueryDb.Workflow.SortOrder,
|
||||
};
|
||||
|
||||
await sortByQueryMiddleware(...args);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { NextFunction, Response } from 'express';
|
||||
|
||||
import type { ListQuery } from '@/requests';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import { toError } from '@/utils';
|
||||
|
||||
import { CredentialsFilter } from './dtos/credentials.filter.dto';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type NextFunction, type Response } from 'express';
|
||||
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQuery } from '@/requests';
|
||||
|
||||
import { filterListQueryMiddleware } from './filter';
|
||||
import { paginationListQueryMiddleware } from './pagination';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { RequestHandler } from 'express';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { ListQuery } from '@/requests';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import { toError } from '@/utils';
|
||||
|
||||
import { Pagination } from './dtos/pagination.dto';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { RequestHandler } from 'express';
|
||||
|
||||
import type { ListQuery } from '@/requests';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import { toError } from '@/utils';
|
||||
|
||||
import { CredentialsSelect } from './dtos/credentials.select.dto';
|
||||
|
||||
@@ -3,8 +3,8 @@ import { validateSync } from 'class-validator';
|
||||
import type { RequestHandler } from 'express';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { ListQuery } from '@/requests';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import { toError } from '@/utils';
|
||||
|
||||
import { WorkflowSorting } from './dtos/workflow.sort-by.dto';
|
||||
|
||||
@@ -11,7 +11,8 @@ import type {
|
||||
import type { Project } from '@/databases/entities/project';
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import type { WorkflowHistory } from '@/databases/entities/workflow-history';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
|
||||
import type { ListQueryDb } from './types-db';
|
||||
|
||||
export type APIRequest<
|
||||
RouteParams = {},
|
||||
@@ -42,13 +43,35 @@ export type AuthenticatedRequest<
|
||||
};
|
||||
};
|
||||
|
||||
export namespace ListQuery {
|
||||
export type Request = AuthenticatedRequest<{}, {}, {}, Params> & {
|
||||
listQueryOptions?: Options;
|
||||
};
|
||||
|
||||
export type Params = {
|
||||
filter?: string;
|
||||
skip?: string;
|
||||
take?: string;
|
||||
select?: string;
|
||||
sortBy?: string;
|
||||
};
|
||||
|
||||
export type Options = {
|
||||
filter?: Record<string, unknown>;
|
||||
select?: Record<string, true>;
|
||||
skip?: number;
|
||||
take?: number;
|
||||
sortBy?: string;
|
||||
};
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// list query
|
||||
// ----------------------------------
|
||||
|
||||
export function hasSharing(
|
||||
workflows: ListQuery.Workflow.Plain[] | ListQuery.Workflow.WithSharing[],
|
||||
): workflows is ListQuery.Workflow.WithSharing[] {
|
||||
workflows: ListQueryDb.Workflow.Plain[] | ListQueryDb.Workflow.WithSharing[],
|
||||
): workflows is ListQueryDb.Workflow.WithSharing[] {
|
||||
return workflows.some((w) => 'shared' in w);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@ import { Service } from '@n8n/di';
|
||||
import type { AnnotationTagEntity } from '@/databases/entities/annotation-tag-entity.ee';
|
||||
import { AnnotationTagRepository } from '@/databases/repositories/annotation-tag.repository.ee';
|
||||
import { validateEntity } from '@/generic-helpers';
|
||||
import type { IAnnotationTagDb, IAnnotationTagWithCountDb } from '@/types-db';
|
||||
|
||||
type IAnnotationTagDb = Pick<AnnotationTagEntity, 'id' | 'name' | 'createdAt' | 'updatedAt'>;
|
||||
|
||||
type IAnnotationTagWithCountDb = IAnnotationTagDb & { usageCount: number };
|
||||
|
||||
type GetAllResult<T> = T extends { withUsageCount: true }
|
||||
? IAnnotationTagWithCountDb[]
|
||||
|
||||
@@ -9,7 +9,7 @@ import { FolderTagMappingRepository } from '@/databases/repositories/folder-tag-
|
||||
import { FolderRepository } from '@/databases/repositories/folder.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { FolderNotFoundError } from '@/errors/folder-not-found.error';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQuery } from '@/requests';
|
||||
|
||||
export interface SimpleFolderNode {
|
||||
id: string;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ProjectRepository } from '@/databases/repositories/project.repository';
|
||||
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { CacheService } from '@/services/cache/cache.service';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQueryDb } from '@/types-db';
|
||||
|
||||
@Service()
|
||||
export class OwnershipService {
|
||||
@@ -57,18 +57,20 @@ export class OwnershipService {
|
||||
}
|
||||
|
||||
addOwnedByAndSharedWith(
|
||||
rawWorkflow: ListQuery.Workflow.WithSharing,
|
||||
): ListQuery.Workflow.WithOwnedByAndSharedWith;
|
||||
rawWorkflow: ListQueryDb.Workflow.WithSharing,
|
||||
): ListQueryDb.Workflow.WithOwnedByAndSharedWith;
|
||||
addOwnedByAndSharedWith(
|
||||
rawCredential: ListQuery.Credentials.WithSharing,
|
||||
): ListQuery.Credentials.WithOwnedByAndSharedWith;
|
||||
rawCredential: ListQueryDb.Credentials.WithSharing,
|
||||
): ListQueryDb.Credentials.WithOwnedByAndSharedWith;
|
||||
addOwnedByAndSharedWith(
|
||||
rawEntity: ListQuery.Workflow.WithSharing | ListQuery.Credentials.WithSharing,
|
||||
): ListQuery.Workflow.WithOwnedByAndSharedWith | ListQuery.Credentials.WithOwnedByAndSharedWith {
|
||||
rawEntity: ListQueryDb.Workflow.WithSharing | ListQueryDb.Credentials.WithSharing,
|
||||
):
|
||||
| ListQueryDb.Workflow.WithOwnedByAndSharedWith
|
||||
| ListQueryDb.Credentials.WithOwnedByAndSharedWith {
|
||||
const shared = rawEntity.shared;
|
||||
const entity = rawEntity as
|
||||
| ListQuery.Workflow.WithOwnedByAndSharedWith
|
||||
| ListQuery.Credentials.WithOwnedByAndSharedWith;
|
||||
| ListQueryDb.Workflow.WithOwnedByAndSharedWith
|
||||
| ListQueryDb.Credentials.WithOwnedByAndSharedWith;
|
||||
|
||||
Object.assign(entity, {
|
||||
homeProject: null,
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
WORKFLOW_SHARING_EDITOR_SCOPES,
|
||||
WORKFLOW_SHARING_OWNER_SCOPES,
|
||||
} from '@/permissions.ee/resource-roles';
|
||||
import type { ListQuery, ScopesField } from '@/types-db';
|
||||
import type { ListQueryDb, ScopesField } from '@/types-db';
|
||||
|
||||
export type RoleNamespace = 'global' | 'project' | 'credential' | 'workflow';
|
||||
|
||||
@@ -159,10 +159,10 @@ export class RoleService {
|
||||
}
|
||||
|
||||
addScopes(
|
||||
rawWorkflow: ListQuery.Workflow.WithSharing | ListQuery.Workflow.WithOwnedByAndSharedWith,
|
||||
rawWorkflow: ListQueryDb.Workflow.WithSharing | ListQueryDb.Workflow.WithOwnedByAndSharedWith,
|
||||
user: User,
|
||||
userProjectRelations: ProjectRelation[],
|
||||
): ListQuery.Workflow.WithScopes;
|
||||
): ListQueryDb.Workflow.WithScopes;
|
||||
addScopes(
|
||||
rawCredential: CredentialsEntity,
|
||||
user: User,
|
||||
@@ -170,29 +170,29 @@ export class RoleService {
|
||||
): CredentialsEntity & ScopesField;
|
||||
addScopes(
|
||||
rawCredential:
|
||||
| ListQuery.Credentials.WithSharing
|
||||
| ListQuery.Credentials.WithOwnedByAndSharedWith,
|
||||
| ListQueryDb.Credentials.WithSharing
|
||||
| ListQueryDb.Credentials.WithOwnedByAndSharedWith,
|
||||
user: User,
|
||||
userProjectRelations: ProjectRelation[],
|
||||
): ListQuery.Credentials.WithScopes;
|
||||
): ListQueryDb.Credentials.WithScopes;
|
||||
addScopes(
|
||||
rawEntity:
|
||||
| CredentialsEntity
|
||||
| ListQuery.Workflow.WithSharing
|
||||
| ListQuery.Credentials.WithOwnedByAndSharedWith
|
||||
| ListQuery.Credentials.WithSharing
|
||||
| ListQuery.Workflow.WithOwnedByAndSharedWith,
|
||||
| ListQueryDb.Workflow.WithSharing
|
||||
| ListQueryDb.Credentials.WithOwnedByAndSharedWith
|
||||
| ListQueryDb.Credentials.WithSharing
|
||||
| ListQueryDb.Workflow.WithOwnedByAndSharedWith,
|
||||
user: User,
|
||||
userProjectRelations: ProjectRelation[],
|
||||
):
|
||||
| (CredentialsEntity & ScopesField)
|
||||
| ListQuery.Workflow.WithScopes
|
||||
| ListQuery.Credentials.WithScopes {
|
||||
| ListQueryDb.Workflow.WithScopes
|
||||
| ListQueryDb.Credentials.WithScopes {
|
||||
const shared = rawEntity.shared;
|
||||
const entity = rawEntity as
|
||||
| (CredentialsEntity & ScopesField)
|
||||
| ListQuery.Workflow.WithScopes
|
||||
| ListQuery.Credentials.WithScopes;
|
||||
| ListQueryDb.Workflow.WithScopes
|
||||
| ListQueryDb.Credentials.WithScopes;
|
||||
|
||||
Object.assign(entity, {
|
||||
scopes: [],
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { GlobalRole, Scope } from '@n8n/permissions';
|
||||
import type express from 'express';
|
||||
import type {
|
||||
ICredentialsEncrypted,
|
||||
IRunExecutionData,
|
||||
@@ -13,7 +12,6 @@ import type {
|
||||
IUser,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import type { AnnotationTagEntity } from '@/databases/entities/annotation-tag-entity.ee';
|
||||
import type { AuthProviderType } from '@/databases/entities/auth-identity';
|
||||
import type { CredentialsEntity } from '@/databases/entities/credentials-entity';
|
||||
import type { Folder } from '@/databases/entities/folder';
|
||||
@@ -71,10 +69,6 @@ export type ITagDb = Pick<TagEntity, 'id' | 'name' | 'createdAt' | 'updatedAt'>;
|
||||
|
||||
export type ITagWithCountDb = ITagDb & UsageCount;
|
||||
|
||||
export type IAnnotationTagDb = Pick<AnnotationTagEntity, 'id' | 'name' | 'createdAt' | 'updatedAt'>;
|
||||
|
||||
export type IAnnotationTagWithCountDb = IAnnotationTagDb & UsageCount;
|
||||
|
||||
// Almost identical to editor-ui.Interfaces.ts
|
||||
export interface IWorkflowDb extends IWorkflowBase {
|
||||
triggerCount: number;
|
||||
@@ -211,49 +205,7 @@ export namespace ExecutionSummaries {
|
||||
export type ExecutionSummaryWithScopes = ExecutionSummary & { scopes: Scope[] };
|
||||
}
|
||||
|
||||
export type APIRequest<
|
||||
RouteParams = {},
|
||||
ResponseBody = {},
|
||||
RequestBody = {},
|
||||
RequestQuery = {},
|
||||
> = express.Request<RouteParams, ResponseBody, RequestBody, RequestQuery> & {
|
||||
browserId?: string;
|
||||
};
|
||||
|
||||
export type AuthenticatedRequest<
|
||||
RouteParams = {},
|
||||
ResponseBody = {},
|
||||
RequestBody = {},
|
||||
RequestQuery = {},
|
||||
> = Omit<APIRequest<RouteParams, ResponseBody, RequestBody, RequestQuery>, 'user' | 'cookies'> & {
|
||||
user: User;
|
||||
cookies: Record<string, string | undefined>;
|
||||
headers: express.Request['headers'] & {
|
||||
'push-ref': string;
|
||||
};
|
||||
};
|
||||
|
||||
export namespace ListQuery {
|
||||
export type Request = AuthenticatedRequest<{}, {}, {}, Params> & {
|
||||
listQueryOptions?: Options;
|
||||
};
|
||||
|
||||
export type Params = {
|
||||
filter?: string;
|
||||
skip?: string;
|
||||
take?: string;
|
||||
select?: string;
|
||||
sortBy?: string;
|
||||
};
|
||||
|
||||
export type Options = {
|
||||
filter?: Record<string, unknown>;
|
||||
select?: Record<string, true>;
|
||||
skip?: number;
|
||||
take?: number;
|
||||
sortBy?: string;
|
||||
};
|
||||
|
||||
export namespace ListQueryDb {
|
||||
/**
|
||||
* Slim workflow returned from a list query operation.
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,7 @@ import type {
|
||||
IWorkflowBase,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import type { AuthenticatedRequest } from '@/requests';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { AuthenticatedRequest, ListQuery } from '@/requests';
|
||||
|
||||
export declare namespace WorkflowRequest {
|
||||
type CreateUpdatePayload = Partial<{
|
||||
|
||||
@@ -27,6 +27,7 @@ import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { validateEntity } from '@/generic-helpers';
|
||||
import type { ListQuery } from '@/requests';
|
||||
import { hasSharing } from '@/requests';
|
||||
import { FolderService } from '@/services/folder.service';
|
||||
import { OrchestrationService } from '@/services/orchestration.service';
|
||||
@@ -34,7 +35,7 @@ import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQueryDb } from '@/types-db';
|
||||
import * as WorkflowHelpers from '@/workflow-helpers';
|
||||
|
||||
import { WorkflowFinderService } from './workflow-finder.service';
|
||||
@@ -138,7 +139,7 @@ export class WorkflowService {
|
||||
}
|
||||
|
||||
private async processSharedWorkflows(
|
||||
workflows: ListQuery.Workflow.WithSharing[],
|
||||
workflows: ListQueryDb.Workflow.WithSharing[],
|
||||
options?: ListQuery.Options,
|
||||
) {
|
||||
const projectId = options?.filter?.projectId;
|
||||
@@ -152,7 +153,7 @@ export class WorkflowService {
|
||||
return workflows.map((workflow) => this.ownershipService.addOwnedByAndSharedWith(workflow));
|
||||
}
|
||||
|
||||
private async addSharedRelation(workflows: ListQuery.Workflow.WithSharing[]): Promise<void> {
|
||||
private async addSharedRelation(workflows: ListQueryDb.Workflow.WithSharing[]): Promise<void> {
|
||||
const workflowIds = workflows.map((workflow) => workflow.id);
|
||||
const relations = await this.sharedWorkflowRepository.getAllRelationsForWorkflows(workflowIds);
|
||||
|
||||
@@ -162,7 +163,7 @@ export class WorkflowService {
|
||||
}
|
||||
|
||||
private async addUserScopes(
|
||||
workflows: ListQuery.Workflow.Plain[] | ListQuery.Workflow.WithSharing[],
|
||||
workflows: ListQueryDb.Workflow.Plain[] | ListQueryDb.Workflow.WithSharing[],
|
||||
user: User,
|
||||
) {
|
||||
const projectRelations = await this.projectService.getProjectRelationsForUser(user);
|
||||
@@ -173,7 +174,7 @@ export class WorkflowService {
|
||||
}
|
||||
|
||||
private cleanupSharedField(
|
||||
workflows: ListQuery.Workflow.Plain[] | ListQuery.Workflow.WithSharing[],
|
||||
workflows: ListQueryDb.Workflow.Plain[] | ListQueryDb.Workflow.WithSharing[],
|
||||
): void {
|
||||
/*
|
||||
This is to emulate the old behavior of removing the shared field as
|
||||
@@ -187,7 +188,7 @@ export class WorkflowService {
|
||||
|
||||
private mergeProcessedWorkflows(
|
||||
workflowsAndFolders: WorkflowFolderUnionFull[],
|
||||
processedWorkflows: ListQuery.Workflow.Plain[] | ListQuery.Workflow.WithSharing[],
|
||||
processedWorkflows: ListQueryDb.Workflow.Plain[] | ListQueryDb.Workflow.WithSharing[],
|
||||
) {
|
||||
const workflowMap = new Map(processedWorkflows.map((workflow) => [workflow.id, workflow]));
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { User } from '@/databases/entities/user';
|
||||
import { ProjectRepository } from '@/databases/repositories/project.repository';
|
||||
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQueryDb } from '@/types-db';
|
||||
import { UserManagementMailer } from '@/user-management/email';
|
||||
import { createWorkflow, shareWorkflowWithUsers } from '@test-integration/db/workflows';
|
||||
|
||||
@@ -134,13 +134,14 @@ describe('GET /credentials', () => {
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data).toHaveLength(2); // owner retrieved owner cred and member cred
|
||||
const ownerCredential: ListQuery.Credentials.WithOwnedByAndSharedWith = response.body.data.find(
|
||||
(e: ListQuery.Credentials.WithOwnedByAndSharedWith) =>
|
||||
const ownerCredential: ListQueryDb.Credentials.WithOwnedByAndSharedWith =
|
||||
response.body.data.find(
|
||||
(e: ListQueryDb.Credentials.WithOwnedByAndSharedWith) =>
|
||||
e.homeProject?.id === ownerPersonalProject.id,
|
||||
);
|
||||
const memberCredential: ListQuery.Credentials.WithOwnedByAndSharedWith =
|
||||
const memberCredential: ListQueryDb.Credentials.WithOwnedByAndSharedWith =
|
||||
response.body.data.find(
|
||||
(e: ListQuery.Credentials.WithOwnedByAndSharedWith) =>
|
||||
(e: ListQueryDb.Credentials.WithOwnedByAndSharedWith) =>
|
||||
e.homeProject?.id === member1PersonalProject.id,
|
||||
);
|
||||
|
||||
@@ -205,7 +206,7 @@ describe('GET /credentials', () => {
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data).toHaveLength(1); // member retrieved only member cred
|
||||
|
||||
const [member1Credential]: [ListQuery.Credentials.WithOwnedByAndSharedWith] =
|
||||
const [member1Credential]: [ListQueryDb.Credentials.WithOwnedByAndSharedWith] =
|
||||
response.body.data;
|
||||
|
||||
validateMainCredentialData(member1Credential);
|
||||
@@ -536,7 +537,8 @@ describe('GET /credentials/:id', () => {
|
||||
|
||||
expect(firstResponse.statusCode).toBe(200);
|
||||
|
||||
const firstCredential: ListQuery.Credentials.WithOwnedByAndSharedWith = firstResponse.body.data;
|
||||
const firstCredential: ListQueryDb.Credentials.WithOwnedByAndSharedWith =
|
||||
firstResponse.body.data;
|
||||
validateMainCredentialData(firstCredential);
|
||||
expect(firstCredential.data).toBeUndefined();
|
||||
|
||||
@@ -593,7 +595,7 @@ describe('GET /credentials/:id', () => {
|
||||
|
||||
const response1 = await authOwnerAgent.get(`/credentials/${savedCredential.id}`).expect(200);
|
||||
|
||||
const credential: ListQuery.Credentials.WithOwnedByAndSharedWith = response1.body.data;
|
||||
const credential: ListQueryDb.Credentials.WithOwnedByAndSharedWith = response1.body.data;
|
||||
|
||||
validateMainCredentialData(credential);
|
||||
expect(credential.data).toBeUndefined();
|
||||
@@ -617,7 +619,7 @@ describe('GET /credentials/:id', () => {
|
||||
.query({ includeData: true })
|
||||
.expect(200);
|
||||
|
||||
const credential2: ListQuery.Credentials.WithOwnedByAndSharedWith = response2.body.data;
|
||||
const credential2: ListQueryDb.Credentials.WithOwnedByAndSharedWith = response2.body.data;
|
||||
|
||||
validateMainCredentialData(credential);
|
||||
expect(credential2.data).toBeDefined(); // Instance owners should be capable of editing all credentials
|
||||
@@ -645,7 +647,8 @@ describe('GET /credentials/:id', () => {
|
||||
.get(`/credentials/${savedCredential.id}`)
|
||||
.expect(200);
|
||||
|
||||
const firstCredential: ListQuery.Credentials.WithOwnedByAndSharedWith = firstResponse.body.data;
|
||||
const firstCredential: ListQueryDb.Credentials.WithOwnedByAndSharedWith =
|
||||
firstResponse.body.data;
|
||||
validateMainCredentialData(firstCredential);
|
||||
expect(firstCredential.data).toBeUndefined();
|
||||
expect(firstCredential).toMatchObject({
|
||||
@@ -676,7 +679,7 @@ describe('GET /credentials/:id', () => {
|
||||
.query({ includeData: true })
|
||||
.expect(200);
|
||||
|
||||
const secondCredential: ListQuery.Credentials.WithOwnedByAndSharedWith =
|
||||
const secondCredential: ListQueryDb.Credentials.WithOwnedByAndSharedWith =
|
||||
secondResponse.body.data;
|
||||
validateMainCredentialData(secondCredential);
|
||||
expect(secondCredential.data).toBeDefined();
|
||||
@@ -1359,7 +1362,7 @@ describe('PUT /:credentialId/transfer', () => {
|
||||
);
|
||||
});
|
||||
|
||||
function validateMainCredentialData(credential: ListQuery.Credentials.WithOwnedByAndSharedWith) {
|
||||
function validateMainCredentialData(credential: ListQueryDb.Credentials.WithOwnedByAndSharedWith) {
|
||||
expect(typeof credential.name).toBe('string');
|
||||
expect(typeof credential.type).toBe('string');
|
||||
expect(credential.homeProject).toBeDefined();
|
||||
|
||||
@@ -15,7 +15,7 @@ import { CredentialsRepository } from '@/databases/repositories/credentials.repo
|
||||
import { ProjectRepository } from '@/databases/repositories/project.repository';
|
||||
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
|
||||
import { CredentialsTester } from '@/services/credentials-tester.service';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQueryDb } from '@/types-db';
|
||||
|
||||
import {
|
||||
decryptCredentialData,
|
||||
@@ -74,7 +74,7 @@ beforeEach(async () => {
|
||||
sharedCredentialsRepository = Container.get(SharedCredentialsRepository);
|
||||
});
|
||||
|
||||
type GetAllResponse = { body: { data: ListQuery.Credentials.WithOwnedByAndSharedWith[] } };
|
||||
type GetAllResponse = { body: { data: ListQueryDb.Credentials.WithOwnedByAndSharedWith[] } };
|
||||
|
||||
// ----------------------------------------
|
||||
// GET /credentials - fetch all credentials
|
||||
@@ -92,7 +92,7 @@ describe('GET /credentials', () => {
|
||||
expect(response.body.data.length).toBe(2); // owner retrieved owner cred and member cred
|
||||
|
||||
const savedCredentialsIds = [savedOwnerCredentialId, savedMemberCredentialId];
|
||||
response.body.data.forEach((credential: ListQuery.Credentials.WithOwnedByAndSharedWith) => {
|
||||
response.body.data.forEach((credential: ListQueryDb.Credentials.WithOwnedByAndSharedWith) => {
|
||||
validateMainCredentialData(credential);
|
||||
expect('data' in credential).toBe(false);
|
||||
expect(savedCredentialsIds).toContain(credential.id);
|
||||
@@ -1502,7 +1502,7 @@ const INVALID_PAYLOADS = [
|
||||
undefined,
|
||||
];
|
||||
|
||||
function validateMainCredentialData(credential: ListQuery.Credentials.WithOwnedByAndSharedWith) {
|
||||
function validateMainCredentialData(credential: ListQueryDb.Credentials.WithOwnedByAndSharedWith) {
|
||||
const { name, type, sharedWithProjects, homeProject, isManaged } = credential;
|
||||
|
||||
expect(typeof name).toBe('string');
|
||||
@@ -1522,7 +1522,9 @@ function validateMainCredentialData(credential: ListQuery.Credentials.WithOwnedB
|
||||
}
|
||||
}
|
||||
|
||||
function validateCredentialWithNoData(credential: ListQuery.Credentials.WithOwnedByAndSharedWith) {
|
||||
function validateCredentialWithNoData(
|
||||
credential: ListQueryDb.Credentials.WithOwnedByAndSharedWith,
|
||||
) {
|
||||
validateMainCredentialData(credential);
|
||||
|
||||
expect('data' in credential).toBe(false);
|
||||
|
||||
@@ -13,7 +13,7 @@ import type { WorkflowFolderUnionFull } from '@/databases/repositories/workflow.
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { License } from '@/license';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import type { ListQuery } from '@/types-db';
|
||||
import type { ListQueryDb } from '@/types-db';
|
||||
import { EnterpriseWorkflowService } from '@/workflows/workflow.service.ee';
|
||||
import { createFolder } from '@test-integration/db/folders';
|
||||
|
||||
@@ -641,7 +641,7 @@ describe('GET /workflows', () => {
|
||||
});
|
||||
|
||||
const found = response.body.data.find(
|
||||
(w: ListQuery.Workflow.WithOwnership) => w.name === 'First',
|
||||
(w: ListQueryDb.Workflow.WithOwnership) => w.name === 'First',
|
||||
);
|
||||
|
||||
expect(found.nodes).toBeUndefined();
|
||||
@@ -1458,7 +1458,7 @@ describe('GET /workflows?includeFolders=true', () => {
|
||||
});
|
||||
|
||||
const found = response.body.data.find(
|
||||
(w: ListQuery.Workflow.WithOwnership) => w.name === 'First',
|
||||
(w: ListQueryDb.Workflow.WithOwnership) => w.name === 'First',
|
||||
);
|
||||
|
||||
expect(found.nodes).toBeUndefined();
|
||||
|
||||
Reference in New Issue
Block a user