refactor(core): Move second batch of repositories to @n8n/db (#15137)

This commit is contained in:
Iván Ovejero
2025-05-06 16:40:34 +02:00
committed by GitHub
parent cf03a28774
commit 32b72011e6
73 changed files with 124 additions and 109 deletions

View File

@@ -1,5 +1,6 @@
import type { GlobalConfig } from '@n8n/config';
import type { User } from '@n8n/db';
import type { InvalidAuthTokenRepository } from '@n8n/db';
import type { NextFunction, Response } from 'express';
import { mock } from 'jest-mock-extended';
import jwt from 'jsonwebtoken';
@@ -7,7 +8,6 @@ import jwt from 'jsonwebtoken';
import { AuthService } from '@/auth/auth.service';
import config from '@/config';
import { AUTH_COOKIE_NAME, Time } from '@/constants';
import type { InvalidAuthTokenRepository } from '@/databases/repositories/invalid-auth-token.repository';
import type { UserRepository } from '@/databases/repositories/user.repository';
import type { AuthenticatedRequest } from '@/requests';
import { JwtService } from '@/services/jwt.service';

View File

@@ -1,5 +1,6 @@
import { GlobalConfig } from '@n8n/config';
import type { User } from '@n8n/db';
import { InvalidAuthTokenRepository } from '@n8n/db';
import { Service } from '@n8n/di';
import { createHash } from 'crypto';
import type { NextFunction, Response } from 'express';
@@ -8,7 +9,6 @@ import { Logger } from 'n8n-core';
import config from '@/config';
import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES, Time } from '@/constants';
import { InvalidAuthTokenRepository } from '@/databases/repositories/invalid-auth-token.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { AuthError } from '@/errors/response-errors/auth.error';
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';

View File

@@ -1,10 +1,9 @@
import { type InstalledNodes, type InstalledPackages, type User } from '@n8n/db';
import { CredentialsRepository } from '@n8n/db';
import { CredentialsRepository, InstalledNodesRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { Flags } from '@oclif/core';
import { CredentialsService } from '@/credentials/credentials.service';
import { InstalledNodesRepository } from '@/databases/repositories/installed-nodes.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { CommunityPackagesService } from '@/services/community-packages.service';

View File

@@ -1,4 +1,4 @@
import { CredentialsEntity, Project, User, SharedCredentials } from '@n8n/db';
import { CredentialsEntity, Project, User, SharedCredentials, ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import type { EntityManager } from '@n8n/typeorm';
@@ -10,7 +10,6 @@ import type { ICredentialsEncrypted } from 'n8n-workflow';
import { jsonParse, UserError } from 'n8n-workflow';
import { UM_FIX_INSTRUCTION } from '@/constants';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import * as Db from '@/db';
import { BaseCommand } from '../base-command';

View File

@@ -1,5 +1,5 @@
import { generateNanoId } from '@n8n/db';
import type { WorkflowEntity } from '@n8n/db';
import { generateNanoId, ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { Flags } from '@oclif/core';
import glob from 'fast-glob';
@@ -8,7 +8,6 @@ import type { IWorkflowBase, WorkflowId } from 'n8n-workflow';
import { jsonParse, UserError } from 'n8n-workflow';
import { UM_FIX_INSTRUCTION } from '@/constants';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';

View File

@@ -1,4 +1,9 @@
import { AuthIdentityRepository, AuthProviderSyncHistoryRepository } from '@n8n/db';
import {
AuthIdentityRepository,
AuthProviderSyncHistoryRepository,
ProjectRelationRepository,
ProjectRepository,
} from '@n8n/db';
import { Container } from '@n8n/di';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { In } from '@n8n/typeorm';
@@ -7,8 +12,6 @@ import { UserError } from 'n8n-workflow';
import { UM_FIX_INSTRUCTION } from '@/constants';
import { CredentialsService } from '@/credentials/credentials.service';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SettingsRepository } from '@/databases/repositories/settings.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';

View File

@@ -1,8 +1,7 @@
import type { CredentialsEntity } from '@n8n/db';
import { User, CredentialsRepository } from '@n8n/db';
import { User, CredentialsRepository, ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SettingsRepository } from '@/databases/repositories/settings.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';

View File

@@ -2,6 +2,7 @@ import { UserUpdateRequestDto } from '@n8n/api-types';
import type { User } from '@n8n/db';
import type { PublicUser } from '@n8n/db';
import { AuthUserRepository } from '@n8n/db';
import { InvalidAuthTokenRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { Response } from 'express';
import { mock, anyObject } from 'jest-mock-extended';
@@ -9,7 +10,6 @@ import jwt from 'jsonwebtoken';
import { AUTH_COOKIE_NAME } from '@/constants';
import { MeController } from '@/controllers/me.controller';
import { InvalidAuthTokenRepository } from '@/databases/repositories/invalid-auth-token.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { InvalidMfaCodeError } from '@/errors/response-errors/invalid-mfa-code.error';

View File

@@ -1,5 +1,6 @@
import { CreateProjectDto, DeleteProjectDto, UpdateProjectDto } from '@n8n/api-types';
import type { Project } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import {
Get,
Post,
@@ -19,7 +20,6 @@ import type { Scope } from '@n8n/permissions';
import { In, Not } from '@n8n/typeorm';
import { Response } from 'express';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { NotFoundError } from '@/errors/response-errors/not-found.error';
import { EventService } from '@/events/event.service';

View File

@@ -1,6 +1,6 @@
import { RoleChangeRequestDto, SettingsUpdateRequestDto } from '@n8n/api-types';
import type { PublicUser } from '@n8n/db';
import { Project, User, AuthIdentity } from '@n8n/db';
import { Project, User, AuthIdentity, ProjectRepository } from '@n8n/db';
import {
GlobalScope,
Delete,
@@ -16,7 +16,6 @@ import { Logger } from 'n8n-core';
import { AuthService } from '@/auth/auth.service';
import { CredentialsService } from '@/credentials/credentials.service';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { UserRepository } from '@/databases/repositories/user.repository';

View File

@@ -5,7 +5,7 @@ import {
GenerateCredentialNameRequestQuery,
} from '@n8n/api-types';
import { GlobalConfig } from '@n8n/config';
import { SharedCredentials } from '@n8n/db';
import { SharedCredentials, ProjectRelationRepository } from '@n8n/db';
import {
Delete,
Get,
@@ -26,7 +26,6 @@ import { deepCopy } from 'n8n-workflow';
import type { ICredentialDataDecryptedObject } from 'n8n-workflow';
import { z } from 'zod';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import * as Db from '@/db';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';

View File

@@ -1,6 +1,11 @@
import type { CreateCredentialDto } from '@n8n/api-types';
import type { Project, User, ICredentialsDb, ScopesField } from '@n8n/db';
import { CredentialsEntity, SharedCredentials, CredentialsRepository } from '@n8n/db';
import {
CredentialsEntity,
SharedCredentials,
CredentialsRepository,
ProjectRepository,
} from '@n8n/db';
import { Service } from '@n8n/di';
import { hasGlobalScope, type Scope } from '@n8n/permissions';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
@@ -22,7 +27,6 @@ import { CREDENTIAL_EMPTY_VALUE, deepCopy, NodeHelpers, UnexpectedError } from '
import { CREDENTIAL_BLANKING_VALUE } from '@/constants';
import { CredentialTypes } from '@/credential-types';
import { createCredentialsFromCredentialsEntity } from '@/credentials-helper';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import * as Db from '@/db';

View File

@@ -1,6 +1,7 @@
import type { Project } from '@n8n/db';
import type { User } from '@n8n/db';
import type { Folder } from '@n8n/db';
import { FolderRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { DateTime } from 'luxon';
@@ -11,7 +12,6 @@ import { createMember, createOwner } from '@test-integration/db/users';
import { createWorkflow } from '@test-integration/db/workflows';
import * as testDb from '../../../../test/integration/shared/test-db';
import { FolderRepository } from '../folder.repository';
describe('FolderRepository', () => {
let folderRepository: FolderRepository;

View File

@@ -1,20 +0,0 @@
import { FolderTagMapping } from '@n8n/db';
import { Service } from '@n8n/di';
import { DataSource, Repository } from '@n8n/typeorm';
@Service()
export class FolderTagMappingRepository extends Repository<FolderTagMapping> {
constructor(dataSource: DataSource) {
super(FolderTagMapping, dataSource.manager);
}
async overwriteTags(folderId: string, tagIds: string[]) {
return await this.manager.transaction(async (tx) => {
await tx.delete(FolderTagMapping, { folderId });
const tags = tagIds.map((tagId) => this.create({ folderId, tagId }));
return await tx.insert(FolderTagMapping, tags);
});
}
}

View File

@@ -1,377 +0,0 @@
import type { FolderWithWorkflowAndSubFolderCount } from '@n8n/db';
import { Folder, FolderTagMapping, TagEntity } from '@n8n/db';
import { Service } from '@n8n/di';
import type { EntityManager, SelectQueryBuilder } from '@n8n/typeorm';
import { DataSource, Repository } from '@n8n/typeorm';
import { PROJECT_ROOT } from 'n8n-workflow';
import type { ListQuery } from '@/requests';
@Service()
export class FolderRepository extends Repository<FolderWithWorkflowAndSubFolderCount> {
constructor(dataSource: DataSource) {
super(Folder, dataSource.manager);
}
async getManyAndCount(
options: ListQuery.Options = {},
): Promise<[FolderWithWorkflowAndSubFolderCount[], number]> {
const query = this.getManyQuery(options);
return await query.getManyAndCount();
}
async getMany(options: ListQuery.Options = {}): Promise<FolderWithWorkflowAndSubFolderCount[]> {
const query = this.getManyQuery(options);
return await query.getMany();
}
getManyQuery(
options: ListQuery.Options = {},
): SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount> {
const query = this.createQueryBuilder('folder');
this.applySelections(query, options.select);
this.applyFilters(query, options.filter);
this.applySorting(query, options.sortBy);
this.applyPagination(query, options);
return query;
}
private applySelections(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
select?: Record<string, boolean>,
): void {
if (select) {
this.applyCustomSelect(query, select);
} else {
this.applyDefaultSelect(query);
}
}
private applyDefaultSelect(query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>): void {
query
.leftJoinAndSelect('folder.homeProject', 'homeProject')
.leftJoinAndSelect('folder.parentFolder', 'parentFolder')
.leftJoinAndSelect('folder.tags', 'tags')
.loadRelationCountAndMap('folder.workflowCount', 'folder.workflows')
.loadRelationCountAndMap('folder.subFolderCount', 'folder.subFolders')
.select([
'folder',
...this.getProjectFields('homeProject'),
...this.getTagFields(),
...this.getParentFolderFields('parentFolder'),
]);
}
private applyCustomSelect(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
select?: Record<string, boolean>,
): void {
const selections = ['folder.id'];
this.addBasicFields(selections, select);
this.addRelationFields(query, selections, select);
query.select(selections);
}
private addBasicFields(selections: string[], select?: Record<string, boolean>): void {
if (select?.name) selections.push('folder.name');
if (select?.createdAt) selections.push('folder.createdAt');
if (select?.updatedAt) selections.push('folder.updatedAt');
}
private addRelationFields(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
selections: string[],
select?: Record<string, boolean>,
): void {
if (select?.project) {
query.leftJoin('folder.homeProject', 'homeProject');
selections.push(...this.getProjectFields('homeProject'));
}
if (select?.tags) {
query.leftJoin('folder.tags', 'tags').addOrderBy('tags.createdAt', 'ASC');
selections.push(...this.getTagFields());
}
if (select?.parentFolder) {
query.leftJoin('folder.parentFolder', 'parentFolder');
selections.push(...this.getParentFolderFields('parentFolder'));
}
if (select?.workflowCount) {
query.loadRelationCountAndMap('folder.workflowCount', 'folder.workflows');
}
if (select?.subFolderCount) {
if (!query.hasRelation(Folder, 'folder.parentFolder')) {
query.loadRelationCountAndMap('folder.subFolderCount', 'folder.subFolders');
}
}
}
private getProjectFields(alias: string): string[] {
return [`${alias}.id`, `${alias}.name`, `${alias}.type`, `${alias}.icon`];
}
private getTagFields(): string[] {
return ['tags.id', 'tags.name'];
}
private getParentFolderFields(alias: string): string[] {
return [`${alias}.id`, `${alias}.name`, `${alias}.parentFolderId`];
}
private applyFilters(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
filter?: ListQuery.Options['filter'],
): void {
if (!filter) return;
this.applyBasicFilters(query, filter);
this.applyTagsFilter(query, Array.isArray(filter?.tags) ? filter.tags : undefined);
if (
filter?.excludeFolderIdAndDescendants &&
typeof filter.excludeFolderIdAndDescendants === 'string'
) {
this.applyExcludeFolderFilter(query, filter.excludeFolderIdAndDescendants);
}
}
private applyBasicFilters(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
filter: ListQuery.Options['filter'],
): void {
if (filter?.folderIds && Array.isArray(filter.folderIds)) {
query.andWhere('folder.id IN (:...folderIds)', {
/*
* If folderIds is empty, add a dummy value to prevent an error
* when using the IN operator with an empty array.
*/
folderIds: !filter?.folderIds.length ? [''] : filter?.folderIds,
});
}
if (filter?.projectId) {
query.andWhere('folder.projectId = :projectId', { projectId: filter.projectId });
}
if (filter?.name && typeof filter.name === 'string') {
query.andWhere('LOWER(folder.name) LIKE LOWER(:name)', {
name: `%${filter.name}%`,
});
}
if (filter?.parentFolderId === PROJECT_ROOT) {
query.andWhere('folder.parentFolderId IS NULL');
} else if (filter?.parentFolderId) {
query.andWhere('folder.parentFolderId = :parentFolderId', {
parentFolderId: filter.parentFolderId,
});
}
}
private applyTagsFilter(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
tags?: string[],
): void {
if (!Array.isArray(tags) || tags.length === 0) return;
const subQuery = this.createTagsSubQuery(query, tags);
query.andWhere(`folder.id IN (${subQuery.getQuery()})`).setParameters({
tagNames: tags,
tagCount: tags.length,
});
}
private createTagsSubQuery(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
tags: string[],
): SelectQueryBuilder<FolderTagMapping> {
return query
.subQuery()
.select('ft.folderId')
.from(FolderTagMapping, 'ft')
.innerJoin(TagEntity, 'filter_tags', 'filter_tags.id = ft.tagId')
.where('filter_tags.name IN (:...tagNames)', { tagNames: tags })
.groupBy('ft.folderId')
.having('COUNT(DISTINCT filter_tags.name) = :tagCount', {
tagCount: tags.length,
});
}
private applySorting(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
sortBy?: string,
): void {
if (!sortBy) {
query.orderBy('folder.updatedAt', 'DESC');
return;
}
const [field, order] = this.parseSortingParams(sortBy);
this.applySortingByField(query, field, order);
}
private parseSortingParams(sortBy: string): [string, 'DESC' | 'ASC'] {
const [field, order] = sortBy.split(':');
return [field, order?.toLowerCase() === 'desc' ? 'DESC' : 'ASC'];
}
private applySortingByField(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
field: string,
direction: 'DESC' | 'ASC',
): void {
if (field === 'name') {
query
.addSelect('LOWER(folder.name)', 'folder_name_lower')
.orderBy('folder_name_lower', direction);
} else if (['createdAt', 'updatedAt'].includes(field)) {
query.orderBy(`folder.${field}`, direction);
}
}
private applyPagination(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
options: ListQuery.Options,
): void {
if (options?.take) {
query.skip(options.skip ?? 0).take(options.take);
}
}
async findOneOrFailFolderInProject(
folderId: string,
projectId: string,
em?: EntityManager,
): Promise<Folder> {
const manager = em ?? this.manager;
return await manager.findOneOrFail(Folder, {
where: {
id: folderId,
homeProject: {
id: projectId,
},
},
});
}
async moveAllToFolder(
fromFolderId: string,
toFolderId: string,
tx: EntityManager,
): Promise<void> {
await tx.update(
Folder,
{ parentFolder: { id: fromFolderId } },
{
parentFolder:
toFolderId === PROJECT_ROOT
? null
: {
id: toFolderId,
},
},
);
}
async transferAllFoldersToProject(
fromProjectId: string,
toProjectId: string,
tx?: EntityManager,
) {
const manager = tx ?? this.manager;
return await manager.update(
Folder,
{
homeProject: { id: fromProjectId },
},
{
homeProject: { id: toProjectId },
},
);
}
private applyExcludeFolderFilter(
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
excludeFolderIdAndDescendants: string,
): void {
// Exclude the specific folder by ID
query.andWhere('folder.id != :excludeFolderIdAndDescendants', {
excludeFolderIdAndDescendants,
});
// Use a WITH RECURSIVE CTE to find all child folders of the excluded folder
const baseQuery = this.createQueryBuilder('f')
.select('f.id', 'id')
.addSelect('f.parentFolderId', 'parentFolderId')
.where('f.id = :excludeFolderIdAndDescendants', { excludeFolderIdAndDescendants });
const recursiveQuery = this.createQueryBuilder('child')
.select('child.id', 'id')
.addSelect('child.parentFolderId', 'parentFolderId')
.innerJoin('folder_tree', 'parent', 'child.parentFolderId = parent.id');
const subQuery = this.createQueryBuilder()
.select('tree.id')
.addCommonTableExpression(
`${baseQuery.getQuery()} UNION ALL ${recursiveQuery.getQuery()}`,
'folder_tree',
{ recursive: true },
)
.from('folder_tree', 'tree')
.setParameters({ excludeFolderIdAndDescendants });
// Exclude all children of the specified folder
query.andWhere(`folder.id NOT IN (${subQuery.getQuery()})`);
}
/**
* Get all folder and subfolder IDs in a hierarchy (including direct children and all descendants)
* @param parentFolderId The ID of the parent folder
* @param projectId Optional project ID to restrict search to a project
* @returns Array of unique folder IDs including direct children and all descendants
*/
async getAllFolderIdsInHierarchy(parentFolderId: string, projectId?: string): Promise<string[]> {
// Start with direct children as the base case
const baseQuery = this.createQueryBuilder('f')
.select('f.id', 'id')
.where('f.parentFolderId = :parentFolderId', { parentFolderId });
// Add project filter if provided
if (projectId) {
baseQuery.andWhere('f.projectId = :projectId', { projectId });
}
// Create the recursive query for descendants
const recursiveQuery = this.createQueryBuilder('child')
.select('child.id', 'id')
.innerJoin('folder_tree', 'parent', 'child.parentFolderId = parent.id');
// Add project filter if provided
if (projectId) {
recursiveQuery.andWhere('child.projectId = :projectId', { projectId });
}
// Create the main query with CTE
const query = this.createQueryBuilder()
.addCommonTableExpression(
`${baseQuery.getQuery()} UNION ALL ${recursiveQuery.getQuery()}`,
'folder_tree',
{ recursive: true },
)
.select('DISTINCT tree.id', 'id')
.from('folder_tree', 'tree')
.setParameters(baseQuery.getParameters());
// Execute the query and extract IDs
const result = await query.getRawMany<{ id: string }>();
return result.map((row) => row.id);
}
}

View File

@@ -1,10 +0,0 @@
import { InstalledNodes } from '@n8n/db';
import { Service } from '@n8n/di';
import { DataSource, Repository } from '@n8n/typeorm';
@Service()
export class InstalledNodesRepository extends Repository<InstalledNodes> {
constructor(dataSource: DataSource) {
super(InstalledNodes, dataSource.manager);
}
}

View File

@@ -1,51 +0,0 @@
import { InstalledPackages } from '@n8n/db';
import { Service } from '@n8n/di';
import { DataSource, Repository } from '@n8n/typeorm';
import type { PackageDirectoryLoader } from 'n8n-core';
import { InstalledNodesRepository } from './installed-nodes.repository';
@Service()
export class InstalledPackagesRepository extends Repository<InstalledPackages> {
constructor(
dataSource: DataSource,
private installedNodesRepository: InstalledNodesRepository,
) {
super(InstalledPackages, dataSource.manager);
}
async saveInstalledPackageWithNodes(packageLoader: PackageDirectoryLoader) {
const { packageJson, nodeTypes, loadedNodes } = packageLoader;
const { name: packageName, version: installedVersion, author } = packageJson;
let installedPackage: InstalledPackages;
await this.manager.transaction(async (manager) => {
installedPackage = await manager.save(
this.create({
packageName,
installedVersion,
authorName: author?.name,
authorEmail: author?.email,
}),
);
installedPackage.installedNodes = [];
for (const loadedNode of loadedNodes) {
const installedNode = this.installedNodesRepository.create({
name: nodeTypes[loadedNode.name].type.description.displayName,
type: `${packageName}.${loadedNode.name}`,
latestVersion: loadedNode.version,
package: { packageName },
});
installedPackage.installedNodes.push(installedNode);
await manager.save(installedNode);
}
});
return installedPackage!;
}
}

View File

@@ -1,10 +0,0 @@
import { InvalidAuthToken } from '@n8n/db';
import { Service } from '@n8n/di';
import { DataSource, Repository } from '@n8n/typeorm';
@Service()
export class InvalidAuthTokenRepository extends Repository<InvalidAuthToken> {
constructor(dataSource: DataSource) {
super(InvalidAuthToken, dataSource.manager);
}
}

View File

@@ -1,80 +0,0 @@
import { GlobalConfig } from '@n8n/config';
import { Service } from '@n8n/di';
import { DataSource, Repository, Entity } from '@n8n/typeorm';
@Entity()
export class LicenseMetrics {}
@Service()
export class LicenseMetricsRepository extends Repository<LicenseMetrics> {
constructor(
dataSource: DataSource,
private readonly globalConfig: GlobalConfig,
) {
super(LicenseMetrics, dataSource.manager);
}
toTableName(name: string) {
const { tablePrefix } = this.globalConfig.database;
return this.manager.connection.driver.escape(`${tablePrefix}${name}`);
}
toColumnName(name: string) {
return this.manager.connection.driver.escape(name);
}
async getLicenseRenewalMetrics() {
type Row = {
enabled_user_count: string | number;
total_user_count: string | number;
active_workflow_count: string | number;
total_workflow_count: string | number;
total_credentials_count: string | number;
production_executions_count: string | number;
production_root_executions_count: string | number;
manual_executions_count: string | number;
};
const userTable = this.toTableName('user');
const workflowTable = this.toTableName('workflow_entity');
const credentialTable = this.toTableName('credentials_entity');
const workflowStatsTable = this.toTableName('workflow_statistics');
const [
{
enabled_user_count: enabledUsers,
total_user_count: totalUsers,
active_workflow_count: activeWorkflows,
total_workflow_count: totalWorkflows,
total_credentials_count: totalCredentials,
production_executions_count: productionExecutions,
production_root_executions_count: productionRootExecutions,
manual_executions_count: manualExecutions,
},
] = (await this.query(`
SELECT
(SELECT COUNT(*) FROM ${userTable} WHERE disabled = false) AS enabled_user_count,
(SELECT COUNT(*) FROM ${userTable}) AS total_user_count,
(SELECT COUNT(*) FROM ${workflowTable} WHERE active = true) AS active_workflow_count,
(SELECT COUNT(*) FROM ${workflowTable}) AS total_workflow_count,
(SELECT COUNT(*) FROM ${credentialTable}) AS total_credentials_count,
(SELECT SUM(count) FROM ${workflowStatsTable} WHERE name IN ('production_success', 'production_error')) AS production_executions_count,
(SELECT SUM(${this.toColumnName('rootCount')}) FROM ${workflowStatsTable} WHERE name IN ('production_success', 'production_error')) AS production_root_executions_count,
(SELECT SUM(count) FROM ${workflowStatsTable} WHERE name IN ('manual_success', 'manual_error')) AS manual_executions_count;
`)) as Row[];
const toNumber = (value: string | number) =>
(typeof value === 'number' ? value : parseInt(value, 10)) || 0;
return {
enabledUsers: toNumber(enabledUsers),
totalUsers: toNumber(totalUsers),
activeWorkflows: toNumber(activeWorkflows),
totalWorkflows: toNumber(totalWorkflows),
totalCredentials: toNumber(totalCredentials),
productionExecutions: toNumber(productionExecutions),
productionRootExecutions: toNumber(productionRootExecutions),
manualExecutions: toNumber(manualExecutions),
};
}
}

View File

@@ -1,10 +0,0 @@
import { ProcessedData } from '@n8n/db';
import { Service } from '@n8n/di';
import { DataSource, Repository } from '@n8n/typeorm';
@Service()
export class ProcessedDataRepository extends Repository<ProcessedData> {
constructor(dataSource: DataSource) {
super(ProcessedData, dataSource.manager);
}
}

View File

@@ -1,73 +0,0 @@
import { ProjectRelation } from '@n8n/db';
import { Service } from '@n8n/di';
import type { ProjectRole } from '@n8n/permissions';
import { DataSource, In, Repository } from '@n8n/typeorm';
@Service()
export class ProjectRelationRepository extends Repository<ProjectRelation> {
constructor(dataSource: DataSource) {
super(ProjectRelation, dataSource.manager);
}
async getPersonalProjectOwners(projectIds: string[]) {
return await this.find({
where: {
projectId: In(projectIds),
role: 'project:personalOwner',
},
relations: { user: true },
});
}
async getPersonalProjectsForUsers(userIds: string[]) {
const projectRelations = await this.find({
where: {
userId: In(userIds),
role: 'project:personalOwner',
},
});
return projectRelations.map((pr) => pr.projectId);
}
/**
* Find the role of a user in a project.
*/
async findProjectRole({ userId, projectId }: { userId: string; projectId: string }) {
const relation = await this.findOneBy({ projectId, userId });
return relation?.role ?? null;
}
/** Counts the number of users in each role, e.g. `{ admin: 2, member: 6, owner: 1 }` */
async countUsersByRole() {
const rows = (await this.createQueryBuilder()
.select(['role', 'COUNT(role) as count'])
.groupBy('role')
.execute()) as Array<{ role: ProjectRole; count: string }>;
return rows.reduce(
(acc, row) => {
acc[row.role] = parseInt(row.count, 10);
return acc;
},
{} as Record<ProjectRole, number>,
);
}
async findUserIdsByProjectId(projectId: string): Promise<string[]> {
const rows = await this.find({
select: ['userId'],
where: { projectId },
});
return [...new Set(rows.map((r) => r.userId))];
}
async findAllByUser(userId: string) {
return await this.find({
where: {
userId,
},
});
}
}

View File

@@ -1,47 +0,0 @@
import { Project } from '@n8n/db';
import { Service } from '@n8n/di';
import type { EntityManager } from '@n8n/typeorm';
import { DataSource, Repository } from '@n8n/typeorm';
@Service()
export class ProjectRepository extends Repository<Project> {
constructor(dataSource: DataSource) {
super(Project, dataSource.manager);
}
async getPersonalProjectForUser(userId: string, entityManager?: EntityManager) {
const em = entityManager ?? this.manager;
return await em.findOne(Project, {
where: { type: 'personal', projectRelations: { userId, role: 'project:personalOwner' } },
});
}
async getPersonalProjectForUserOrFail(userId: string, entityManager?: EntityManager) {
const em = entityManager ?? this.manager;
return await em.findOneOrFail(Project, {
where: { type: 'personal', projectRelations: { userId, role: 'project:personalOwner' } },
});
}
async getAccessibleProjects(userId: string) {
return await this.find({
where: [
{ type: 'personal' },
{
projectRelations: {
userId,
},
},
],
});
}
async getProjectCounts() {
return {
personal: await this.count({ where: { type: 'personal' } }),
team: await this.count({ where: { type: 'team' } }),
};
}
}

View File

@@ -6,6 +6,7 @@ import {
TagEntity,
WorkflowEntity,
WorkflowTagMapping,
FolderRepository,
} from '@n8n/db';
import { Service } from '@n8n/di';
import { DataSource, Repository, In, Like } from '@n8n/typeorm';
@@ -22,8 +23,6 @@ import { PROJECT_ROOT } from 'n8n-workflow';
import type { ListQuery } from '@/requests';
import { FolderRepository } from './folder.repository';
type ResourceType = 'folder' | 'workflow';
type WorkflowFolderUnionRow = {

View File

@@ -1,4 +1,5 @@
import type { ProcessedData } from '@n8n/db';
import { ProcessedDataRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { createHash } from 'crypto';
import { tryToParseDateTime } from 'n8n-workflow';
@@ -15,7 +16,6 @@ import type {
} from 'n8n-workflow';
import * as assert from 'node:assert/strict';
import { ProcessedDataRepository } from '@/databases/repositories/processed-data.repository';
import { DeduplicationError } from '@/errors/deduplication.error';
export class DeduplicationHelper implements IDataDeduplicator {

View File

@@ -1,12 +1,12 @@
import type { SourceControlledFile } from '@n8n/api-types';
import type { SharedCredentials } from '@n8n/db';
import type { SharedWorkflow } from '@n8n/db';
import type { FolderRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { mock, captor } from 'jest-mock-extended';
import { Cipher, type InstanceSettings } from 'n8n-core';
import fsp from 'node:fs/promises';
import type { FolderRepository } from '@/databases/repositories/folder.repository';
import type { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import type { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import type { TagRepository } from '@/databases/repositories/tag.repository';

View File

@@ -1,10 +1,10 @@
import type { WorkflowEntity } from '@n8n/db';
import type { FolderRepository } from '@n8n/db';
import * as fastGlob from 'fast-glob';
import { mock } from 'jest-mock-extended';
import { type InstanceSettings } from 'n8n-core';
import fsp from 'node:fs/promises';
import type { FolderRepository } from '@/databases/repositories/folder.repository';
import type { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { SourceControlImportService } from '../source-control-import.service.ee';

View File

@@ -3,11 +3,11 @@ import type { Variables } from '@n8n/db';
import type { FolderWithWorkflowAndSubFolderCount } from '@n8n/db';
import type { TagEntity } from '@n8n/db';
import type { User } from '@n8n/db';
import type { FolderRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { mock } from 'jest-mock-extended';
import { InstanceSettings } from 'n8n-core';
import type { FolderRepository } from '@/databases/repositories/folder.repository';
import type { TagRepository } from '@/databases/repositories/tag.repository';
import { SourceControlPreferencesService } from '@/environments.ee/source-control/source-control-preferences.service.ee';
import { SourceControlService } from '@/environments.ee/source-control/source-control.service.ee';

View File

@@ -1,5 +1,6 @@
import type { SourceControlledFile } from '@n8n/api-types';
import type { IWorkflowDb } from '@n8n/db';
import { FolderRepository } from '@n8n/db';
import { Service } from '@n8n/di';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { In } from '@n8n/typeorm';
@@ -9,7 +10,6 @@ import { UnexpectedError, type ICredentialDataDecryptedObject } from 'n8n-workfl
import { writeFile as fsWriteFile, rm as fsRm } from 'node:fs/promises';
import path from 'path';
import { FolderRepository } from '@/databases/repositories/folder.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { TagRepository } from '@/databases/repositories/tag.repository';

View File

@@ -1,6 +1,11 @@
import type { SourceControlledFile } from '@n8n/api-types';
import type { Variables, Project, TagEntity, User, WorkflowTagMapping } from '@n8n/db';
import { SharedCredentials, CredentialsRepository } from '@n8n/db';
import {
SharedCredentials,
CredentialsRepository,
FolderRepository,
ProjectRepository,
} from '@n8n/db';
import { Service } from '@n8n/di';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { In } from '@n8n/typeorm';
@@ -12,8 +17,6 @@ import path from 'path';
import { ActiveWorkflowManager } from '@/active-workflow-manager';
import { CredentialsService } from '@/credentials/credentials.service';
import { FolderRepository } from '@/databases/repositories/folder.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { TagRepository } from '@/databases/repositories/tag.repository';

View File

@@ -4,6 +4,7 @@ import type {
SourceControlledFile,
} from '@n8n/api-types';
import type { Variables, TagEntity, User } from '@n8n/db';
import { FolderRepository } from '@n8n/db';
import { Service } from '@n8n/di';
import { writeFileSync } from 'fs';
import { Logger } from 'n8n-core';
@@ -11,7 +12,6 @@ import { UnexpectedError, UserError } from 'n8n-workflow';
import path from 'path';
import type { PushResult } from 'simple-git';
import { FolderRepository } from '@/databases/repositories/folder.repository';
import { TagRepository } from '@/databases/repositories/tag.repository';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { EventService } from '@/events/event.service';

View File

@@ -3,13 +3,13 @@ import type { CredentialsEntity } from '@n8n/db';
import type { WorkflowEntity } from '@n8n/db';
import type { IWorkflowDb } from '@n8n/db';
import type { CredentialsRepository } from '@n8n/db';
import type { ProjectRelationRepository } from '@n8n/db';
import { mock } from 'jest-mock-extended';
import { type BinaryDataConfig, InstanceSettings } from 'n8n-core';
import type { INode, INodesGraphResult } from 'n8n-workflow';
import { NodeApiError, TelemetryHelpers, type IRun, type IWorkflowBase } from 'n8n-workflow';
import { N8N_VERSION } from '@/constants';
import type { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import type { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import type { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { EventService } from '@/events/event.service';

View File

@@ -1,5 +1,5 @@
import { GlobalConfig } from '@n8n/config';
import { CredentialsRepository } from '@n8n/db';
import { CredentialsRepository, ProjectRelationRepository } from '@n8n/db';
import { Service } from '@n8n/di';
import { snakeCase } from 'change-case';
import { BinaryDataConfig, InstanceSettings } from 'n8n-core';
@@ -10,7 +10,6 @@ import { get as pslGet } from 'psl';
import config from '@/config';
import { N8N_VERSION } from '@/constants';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { EventService } from '@/events/event.service';

View File

@@ -1,6 +1,6 @@
import type { LicenseMetricsRepository } from '@n8n/db';
import { mock } from 'jest-mock-extended';
import type { LicenseMetricsRepository } from '@/databases/repositories/license-metrics.repository';
import type { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { LicenseMetricsService } from '@/metrics/license-metrics.service';

View File

@@ -1,6 +1,6 @@
import { LicenseMetricsRepository } from '@n8n/db';
import { Service } from '@n8n/di';
import { LicenseMetricsRepository } from '@/databases/repositories/license-metrics.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
@Service()

View File

@@ -1,11 +1,11 @@
import type { User } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { hasGlobalScope, rolesWithScope, type Scope } from '@n8n/permissions';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { In } from '@n8n/typeorm';
import { UnexpectedError } from 'n8n-workflow';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';

View File

@@ -1,5 +1,10 @@
import type { User, ICredentialsDb } from '@n8n/db';
import { CredentialsEntity, SharedCredentials, CredentialsRepository } from '@n8n/db';
import {
CredentialsEntity,
SharedCredentials,
CredentialsRepository,
ProjectRepository,
} from '@n8n/db';
import { Container } from '@n8n/di';
import { Credentials } from 'n8n-core';
import type {
@@ -9,7 +14,6 @@ import type {
INodePropertyOptions,
} from 'n8n-workflow';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import * as Db from '@/db';
import { EventService } from '@/events/event.service';

View File

@@ -1,9 +1,9 @@
import { CreateProjectDto, DeleteProjectDto, UpdateProjectDto } from '@n8n/api-types';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { Response } from 'express';
import { ProjectController } from '@/controllers/project.controller';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import type { PaginatedRequest } from '@/public-api/types';
import type { AuthenticatedRequest } from '@/requests';

View File

@@ -1,11 +1,11 @@
import { InviteUsersRequestDto, RoleChangeRequestDto } from '@n8n/api-types';
import { ProjectRelationRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type express from 'express';
import type { Response } from 'express';
import { InvitationController } from '@/controllers/invitation.controller';
import { UsersController } from '@/controllers/users.controller';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { EventService } from '@/events/event.service';
import type { AuthenticatedRequest, UserRequest } from '@/requests';

View File

@@ -1,5 +1,5 @@
import { GlobalConfig } from '@n8n/config';
import { WorkflowEntity } from '@n8n/db';
import { WorkflowEntity, ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { In, Like, QueryFailedError } from '@n8n/typeorm';
@@ -10,7 +10,6 @@ import { v4 as uuid } from 'uuid';
import { z } from 'zod';
import { ActiveWorkflowManager } from '@/active-workflow-manager';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { TagRepository } from '@/databases/repositories/tag.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { EventService } from '@/events/event.service';

View File

@@ -1,6 +1,8 @@
import type { GlobalConfig } from '@n8n/config';
import { InstalledNodes } from '@n8n/db';
import { InstalledPackages } from '@n8n/db';
import { InstalledNodesRepository } from '@n8n/db';
import { InstalledPackagesRepository } from '@n8n/db';
import axios from 'axios';
import { exec } from 'child_process';
import { mkdir as fsMkdir } from 'fs/promises';
@@ -15,8 +17,6 @@ import {
NPM_PACKAGE_STATUS_GOOD,
RESPONSE_ERROR_MESSAGES,
} from '@/constants';
import { InstalledNodesRepository } from '@/databases/repositories/installed-nodes.repository';
import { InstalledPackagesRepository } from '@/databases/repositories/installed-packages.repository';
import type { CommunityPackages } from '@/interfaces';
import type { License } from '@/license';
import type { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';

View File

@@ -1,9 +1,9 @@
import type { SharedCredentials } from '@n8n/db';
import { Project, SharedWorkflow, User, WorkflowEntity, ProjectRelation } from '@n8n/db';
import { ProjectRelationRepository } from '@n8n/db';
import { mock } from 'jest-mock-extended';
import { v4 as uuid } from 'uuid';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { OwnershipService } from '@/services/ownership.service';

View File

@@ -1,6 +1,7 @@
import { GlobalConfig } from '@n8n/config';
import { LICENSE_FEATURES } from '@n8n/constants';
import type { InstalledPackages } from '@n8n/db';
import { InstalledPackagesRepository } from '@n8n/db';
import { Service } from '@n8n/di';
import axios from 'axios';
import { exec } from 'child_process';
@@ -17,7 +18,6 @@ import {
RESPONSE_ERROR_MESSAGES,
UNKNOWN_FAILURE_REASON,
} from '@/constants';
import { InstalledPackagesRepository } from '@/databases/repositories/installed-packages.repository';
import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error';
import type { CommunityPackages } from '@/interfaces';
import { License } from '@/license';

View File

@@ -1,12 +1,10 @@
import type { CreateFolderDto, DeleteFolderDto, UpdateFolderDto } from '@n8n/api-types';
import { Folder } from '@n8n/db';
import { Folder, FolderTagMappingRepository, FolderRepository } from '@n8n/db';
import { Service } from '@n8n/di';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import type { EntityManager } from '@n8n/typeorm';
import { UserError, PROJECT_ROOT } from 'n8n-workflow';
import { FolderTagMappingRepository } from '@/databases/repositories/folder-tag-mapping.repository';
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 '@/requests';

View File

@@ -1,8 +1,7 @@
import type { Project, User, ListQueryDb } from '@n8n/db';
import { ProjectRelationRepository, ProjectRepository } from '@n8n/db';
import { Service } from '@n8n/di';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
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';

View File

@@ -1,7 +1,7 @@
import type { CreateProjectDto, ProjectType, UpdateProjectDto } from '@n8n/api-types';
import { UNLIMITED_LICENSE_QUOTA } from '@n8n/constants';
import type { User } from '@n8n/db';
import { Project, ProjectRelation } from '@n8n/db';
import { Project, ProjectRelation, ProjectRelationRepository, ProjectRepository } from '@n8n/db';
import { Container, Service } from '@n8n/di';
import { hasGlobalScope, rolesWithScope, type Scope, type ProjectRole } from '@n8n/permissions';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
@@ -10,8 +10,6 @@ import type { FindOptionsWhere, EntityManager } from '@n8n/typeorm';
import { In, Not } from '@n8n/typeorm';
import { UserError } from 'n8n-workflow';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';

View File

@@ -1,4 +1,5 @@
import { GlobalConfig } from '@n8n/config';
import { ProjectRelationRepository, ProjectRepository } from '@n8n/db';
import { OnShutdown } from '@n8n/decorators';
import { Container, Service } from '@n8n/di';
import type RudderStack from '@rudderstack/rudder-sdk-node';
@@ -7,8 +8,6 @@ import { InstanceSettings, Logger } from 'n8n-core';
import type { ITelemetryTrackProperties } from 'n8n-workflow';
import { LOWEST_SHUTDOWN_PRIORITY, N8N_VERSION } from '@/constants';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import type { IExecutionTrackProperties } from '@/interfaces';

View File

@@ -1,3 +1,4 @@
import { ProjectRelationRepository } from '@n8n/db';
import type { User } from '@n8n/db';
import { Service } from '@n8n/di';
import {
@@ -10,7 +11,6 @@ import {
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { In } from '@n8n/typeorm';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { RoleService } from '@/services/role.service';

View File

@@ -5,7 +5,12 @@ import {
} from '@n8n/api-types';
import { GlobalConfig } from '@n8n/config';
import type { Project } from '@n8n/db';
import { SharedWorkflow, WorkflowEntity } from '@n8n/db';
import {
SharedWorkflow,
WorkflowEntity,
ProjectRelationRepository,
ProjectRepository,
} from '@n8n/db';
import {
Body,
Delete,
@@ -27,8 +32,6 @@ import { Logger } from 'n8n-core';
import { UnexpectedError } from 'n8n-workflow';
import { v4 as uuid } from 'uuid';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { TagRepository } from '@/databases/repositories/tag.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';

View File

@@ -1,13 +1,13 @@
import type { Project } from '@n8n/db';
import type { User } from '@n8n/db';
import { CredentialsRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { randomUUID } from 'crypto';
import { mock } from 'jest-mock-extended';
import { OPEN_AI_API_CREDENTIAL_TYPE } from 'n8n-workflow';
import { FREE_AI_CREDITS_CREDENTIAL_NAME } from '@/constants';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { AiService } from '@/services/ai.service';

View File

@@ -1,8 +1,8 @@
import type { User } from '@n8n/db';
import { ProjectRelationRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { Not } from '@n8n/typeorm';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { EventService } from '@/events/event.service';
import { ExternalHooks } from '@/external-hooks';

View File

@@ -1,13 +1,13 @@
import type { Project } from '@n8n/db';
import type { User } from '@n8n/db';
import type { ListQueryDb } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { ProjectRole } from '@n8n/permissions';
import { In } from '@n8n/typeorm';
import config from '@/config';
import { CredentialsService } from '@/credentials/credentials.service';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { ProjectService } from '@/services/project.service.ee';
import { UserManagementMailer } from '@/user-management/email';

View File

@@ -3,6 +3,7 @@ import type { Project } from '@n8n/db';
import type { User } from '@n8n/db';
import type { ListQueryDb } from '@n8n/db';
import { CredentialsRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { Scope } from '@sentry/node';
import * as a from 'assert';
@@ -13,7 +14,6 @@ import { randomString } from 'n8n-workflow';
import { CREDENTIAL_BLANKING_VALUE } from '@/constants';
import { CredentialsService } from '@/credentials/credentials.service';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { CredentialsTester } from '@/services/credentials-tester.service';

View File

@@ -1,8 +1,8 @@
import { AuthIdentity } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { EntityNotFoundError } from '@n8n/typeorm';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { createTeamProject } from '../../shared/db/projects';

View File

@@ -1,5 +1,7 @@
import type { SourceControlledFile } from '@n8n/api-types';
import { CredentialsRepository } from '@n8n/db';
import { FolderRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { mock } from 'jest-mock-extended';
import { Cipher } from 'n8n-core';
@@ -8,8 +10,6 @@ import * as utils from 'n8n-workflow';
import { nanoid } from 'nanoid';
import fsp from 'node:fs/promises';
import { FolderRepository } from '@/databases/repositories/folder.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { SourceControlImportService } from '@/environments.ee/source-control/source-control-import.service.ee';

View File

@@ -1,10 +1,10 @@
import type { User } from '@n8n/db';
import type { TestDefinition } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { mockInstance } from 'n8n-core/test/utils';
import type { IWorkflowBase } from 'n8n-workflow';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { TestDefinitionRepository } from '@/databases/repositories/test-definition.repository.ee';
import { TestRunRepository } from '@/databases/repositories/test-run.repository.ee';
import { TestRunnerService } from '@/evaluation.ee/test-runner/test-runner.service.ee';

View File

@@ -1,11 +1,11 @@
import type { Project } from '@n8n/db';
import type { User } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { INode, IWorkflowBase } from 'n8n-workflow';
import { randomInt } from 'n8n-workflow';
import { v4 as uuid } from 'uuid';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';

View File

@@ -1,11 +1,11 @@
import type { Project } from '@n8n/db';
import type { User } from '@n8n/db';
import { FolderRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { DateTime } from 'luxon';
import { PROJECT_ROOT } from 'n8n-workflow';
import { FolderRepository } from '@/databases/repositories/folder.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { createFolder } from '@test-integration/db/folders';
import { createTag } from '@test-integration/db/tags';

View File

@@ -1,7 +1,7 @@
import { StatisticsNames } from '@n8n/db';
import { LicenseMetricsRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { LicenseMetricsRepository } from '@/databases/repositories/license-metrics.repository';
import { WorkflowStatisticsRepository } from '@/databases/repositories/workflow-statistics.repository';
import { createManyCredentials } from './shared/db/credentials';

View File

@@ -1,10 +1,10 @@
import { GlobalConfig } from '@n8n/config';
import type { User } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { IPersonalizationSurveyAnswersV4 } from 'n8n-workflow';
import validator from 'validator';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { mockInstance } from '@test/mocking';

View File

@@ -1,12 +1,12 @@
import type { Project } from '@n8n/db';
import { FolderRepository } from '@n8n/db';
import { ProjectRelationRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { getRoleScopes, type GlobalRole, type ProjectRole, type Scope } from '@n8n/permissions';
import { EntityNotFoundError } from '@n8n/typeorm';
import { ActiveWorkflowManager } from '@/active-workflow-manager';
import { FolderRepository } from '@/databases/repositories/folder.repository';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { getWorkflowById } from '@/public-api/v1/handlers/workflows/workflows.service';

View File

@@ -1,11 +1,11 @@
import type { TagEntity } from '@n8n/db';
import { ApiKeyRepository } from '@n8n/db';
import { CredentialsRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { randomString } from 'n8n-workflow';
import validator from 'validator';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { TagRepository } from '@/databases/repositories/tag.repository';

View File

@@ -2,12 +2,12 @@ import { GlobalConfig } from '@n8n/config';
import type { Project } from '@n8n/db';
import type { TagEntity } from '@n8n/db';
import type { User } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { INode } from 'n8n-workflow';
import { ActiveWorkflowManager } from '@/active-workflow-manager';
import { STARTING_NODES } from '@/constants';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { WorkflowHistoryRepository } from '@/databases/repositories/workflow-history.repository';
import { ExecutionService } from '@/executions/execution.service';

View File

@@ -1,8 +1,8 @@
import { ProjectRelationRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { ProjectRole, Scope } from '@n8n/permissions';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { ProjectService } from '@/services/project.service.ee';
import { createMember } from '../shared/db/users';

View File

@@ -3,10 +3,10 @@ import type { User } from '@n8n/db';
import type { ICredentialsDb } from '@n8n/db';
import { CredentialsEntity } from '@n8n/db';
import { CredentialsRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { CredentialSharingRole } from '@n8n/permissions';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import type { CredentialPayload } from '../types';

View File

@@ -1,9 +1,9 @@
import type { Folder } from '@n8n/db';
import type { Project } from '@n8n/db';
import type { TagEntity } from '@n8n/db';
import { FolderRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { FolderRepository } from '@/databases/repositories/folder.repository';
import { randomName } from '@test-integration/random';
export const createFolder = async (

View File

@@ -1,12 +1,11 @@
import type { Project } from '@n8n/db';
import type { User } from '@n8n/db';
import type { ProjectRelation } from '@n8n/db';
import { ProjectRelationRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { ProjectRole } from '@n8n/permissions';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { randomName } from '../random';
export const createTeamProject = async (name?: string, adminUser?: User) => {

View File

@@ -1,7 +1,8 @@
import { Project } from '@n8n/db';
import { User } from '@n8n/db';
import type { SharedWorkflow } from '@n8n/db';
import type { IWorkflowDb } from '@n8n/db';
import { Project } from '@n8n/db';
import { User } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { WorkflowSharingRole } from '@n8n/permissions';
import type { DeepPartial } from '@n8n/typeorm';
@@ -9,7 +10,6 @@ import type { IWorkflowBase } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { v4 as uuid } from 'uuid';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';

View File

@@ -1,9 +1,9 @@
import { InstalledPackages } from '@n8n/db';
import { InstalledNodesRepository } from '@n8n/db';
import { InstalledPackagesRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { NODE_PACKAGE_PREFIX } from '@/constants';
import { InstalledNodesRepository } from '@/databases/repositories/installed-nodes.repository';
import { InstalledPackagesRepository } from '@/databases/repositories/installed-packages.repository';
import { COMMUNITY_NODE_VERSION, COMMUNITY_PACKAGE_VERSION } from '../constants';
import { randomName } from '../random';

View File

@@ -1,6 +1,6 @@
import { ProjectRelationRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { createAdmin, createMember, createOwner } from './shared/db/users';

View File

@@ -1,12 +1,12 @@
import type { User } from '@n8n/db';
import { FolderRepository } from '@n8n/db';
import { ProjectRelationRepository } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import { v4 as uuid } from 'uuid';
import { RESPONSE_ERROR_MESSAGES } from '@/constants';
import { UsersController } from '@/controllers/users.controller';
import { FolderRepository } from '@/databases/repositories/folder.repository';
import { ProjectRelationRepository } from '@/databases/repositories/project-relation.repository';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/shared-credentials.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { UserRepository } from '@/databases/repositories/user.repository';

View File

@@ -1,6 +1,7 @@
import type { Project } from '@n8n/db';
import type { User } from '@n8n/db';
import type { WorkflowWithSharingsMetaDataAndCredentials } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { ProjectRole } from '@n8n/permissions';
import { ApplicationError, WorkflowActivationError, type INode } from 'n8n-workflow';
@@ -8,7 +9,6 @@ import { v4 as uuid } from 'uuid';
import { ActiveWorkflowManager } from '@/active-workflow-manager';
import config from '@/config';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { WorkflowHistoryRepository } from '@/databases/repositories/workflow-history.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';

View File

@@ -1,5 +1,6 @@
import type { User } from '@n8n/db';
import type { ListQueryDb } from '@n8n/db';
import { ProjectRepository } from '@n8n/db';
import { Container } from '@n8n/di';
import type { Scope } from '@n8n/permissions';
import { DateTime } from 'luxon';
@@ -7,7 +8,6 @@ import { PROJECT_ROOT, type INode, type IPinData, type IWorkflowBase } from 'n8n
import { v4 as uuid } from 'uuid';
import { ActiveWorkflowManager } from '@/active-workflow-manager';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { SharedWorkflowRepository } from '@/databases/repositories/shared-workflow.repository';
import { WorkflowHistoryRepository } from '@/databases/repositories/workflow-history.repository';
import type { WorkflowFolderUnionFull } from '@/databases/repositories/workflow.repository';