ci(core): Reduce memory usage in tests (part-2) (no-changelog) (#7671)

This also gets rid of `Db.collection`, which was another source of
circular dependencies.
This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2023-11-10 15:04:26 +01:00 committed by GitHub
parent 37dd658dc5
commit 000e76e3b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
174 changed files with 892 additions and 808 deletions

View file

@ -60,6 +60,9 @@ jobs:
- name: Test Backend
run: pnpm test:backend
- name: Test Nodes
run: pnpm test:nodes
- name: Test Frontend
run: pnpm test:frontend

View file

@ -25,7 +25,8 @@
"start:tunnel": "./packages/cli/bin/n8n start --tunnel",
"start:windows": "cd packages/cli/bin && n8n",
"test": "turbo run test",
"test:backend": "pnpm --filter=!n8n-design-system --filter=!n8n-editor-ui test",
"test:backend": "pnpm --filter=!n8n-design-system --filter=!n8n-editor-ui --filter=!n8n-nodes-base test",
"test:nodes": "pnpm --filter=n8n-nodes-base test",
"test:frontend": "pnpm --filter=n8n-design-system --filter=n8n-editor-ui test",
"watch": "turbo run watch",
"webhook": "./packages/cli/bin/n8n webhook",

View file

@ -19,7 +19,7 @@ import type {
IWorkflowExecutionDataProcess,
} from '@/Interfaces';
import { isWorkflowIdValid } from '@/utils';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { Logger } from '@/Logger';
@Service()

View file

@ -33,7 +33,6 @@ import {
import type express from 'express';
import * as Db from '@/Db';
import type {
IResponseCallbackData,
IWebhookManager,
@ -63,7 +62,8 @@ import { webhookNotFoundErrorMessage } from './utils';
import { In } from 'typeorm';
import { WebhookService } from './services/webhook.service';
import { Logger } from './Logger';
import { WorkflowRepository } from '@/databases/repositories';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import config from '@/config';
import type { MultiMainInstancePublisher } from './services/orchestration/main/MultiMainInstance.publisher.ee';
@ -104,6 +104,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
private readonly nodeTypes: NodeTypes,
private readonly webhookService: WebhookService,
private readonly workflowRepository: WorkflowRepository,
private readonly sharedWorkflowRepository: SharedWorkflowRepository,
) {}
async init() {
@ -188,7 +189,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
});
}
const workflowData = await Db.collections.Workflow.findOne({
const workflowData = await this.workflowRepository.findOne({
where: { id: webhook.workflowId },
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
});
@ -296,7 +297,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
Object.assign(where, { workflowId: In(activeIds) });
const sharings = await Db.collections.SharedWorkflow.find({
const sharings = await this.sharedWorkflowRepository.find({
select: ['workflowId'],
where,
});
@ -416,7 +417,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
* Clear workflow-defined webhooks from the `webhook_entity` table.
*/
async clearWebhooks(workflowId: string) {
const workflowData = await Db.collections.Workflow.findOne({
const workflowData = await this.workflowRepository.findOne({
where: { id: workflowId },
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
});

View file

@ -43,7 +43,6 @@ import {
ErrorReporterProxy as ErrorReporter,
} from 'n8n-workflow';
import * as Db from '@/Db';
import type { ICredentialsDb } from '@/Interfaces';
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
import type { User } from '@db/entities/User';
@ -54,6 +53,8 @@ import { CredentialsOverwrites } from '@/CredentialsOverwrites';
import { RESPONSE_ERROR_MESSAGES } from './constants';
import { isObjectLiteral } from './utils';
import { Logger } from '@/Logger';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
const { OAUTH2_CREDENTIAL_TEST_SUCCEEDED, OAUTH2_CREDENTIAL_TEST_FAILED } = RESPONSE_ERROR_MESSAGES;
@ -102,6 +103,8 @@ export class CredentialsHelper extends ICredentialsHelper {
private readonly credentialTypes: CredentialTypes,
private readonly nodeTypes: NodeTypes,
private readonly credentialsOverwrites: CredentialsOverwrites,
private readonly credentialsRepository: CredentialsRepository,
private readonly sharedCredentialsRepository: SharedCredentialsRepository,
) {
super();
}
@ -271,11 +274,13 @@ export class CredentialsHelper extends ICredentialsHelper {
try {
credential = userId
? await Db.collections.SharedCredentials.findOneOrFail({
relations: ['credentials'],
where: { credentials: { id: nodeCredential.id, type }, userId },
}).then((shared) => shared.credentials)
: await Db.collections.Credentials.findOneByOrFail({ id: nodeCredential.id, type });
? await this.sharedCredentialsRepository
.findOneOrFail({
relations: ['credentials'],
where: { credentials: { id: nodeCredential.id, type }, userId },
})
.then((shared) => shared.credentials)
: await this.credentialsRepository.findOneByOrFail({ id: nodeCredential.id, type });
} catch (error) {
throw new CredentialNotFoundError(nodeCredential.id, type);
}
@ -463,7 +468,7 @@ export class CredentialsHelper extends ICredentialsHelper {
type,
};
await Db.collections.Credentials.update(findQuery, newCredentialsData);
await this.credentialsRepository.update(findQuery, newCredentialsData);
}
private static hasAccessToken(credentialsDecrypted: ICredentialsDecrypted) {
@ -774,7 +779,7 @@ export class CredentialsHelper extends ICredentialsHelper {
return false;
}
const credential = await Db.collections.SharedCredentials.findOne({
const credential = await this.sharedCredentialsRepository.findOne({
where: {
role: {
scope: 'credential',

View file

@ -1,13 +1,10 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import { Container } from 'typedi';
import type { DataSourceOptions as ConnectionOptions, EntityManager, LoggerOptions } from 'typeorm';
import { DataSource as Connection } from 'typeorm';
import type { TlsOptions } from 'tls';
import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow';
import type { IDatabaseCollections } from '@/Interfaces';
import config from '@/config';
import { entities } from '@db/entities';
@ -21,28 +18,6 @@ import {
import { inTest } from '@/constants';
import { wrapMigration } from '@db/utils/migrationHelpers';
import type { DatabaseType, Migration } from '@db/types';
import {
AuthIdentityRepository,
AuthProviderSyncHistoryRepository,
CredentialsRepository,
EventDestinationsRepository,
ExecutionDataRepository,
ExecutionMetadataRepository,
ExecutionRepository,
InstalledNodesRepository,
InstalledPackagesRepository,
RoleRepository,
SettingsRepository,
SharedCredentialsRepository,
SharedWorkflowRepository,
UserRepository,
VariablesRepository,
WorkflowRepository,
WorkflowStatisticsRepository,
WorkflowTagMappingRepository,
} from '@db/repositories';
export const collections = {} as IDatabaseCollections;
let connection: Connection;
@ -165,32 +140,6 @@ export async function init(testConnectionOptions?: ConnectionOptions): Promise<v
}
connectionState.connected = true;
/**
* @important Do not add to these collections. Inject the repository as a dependency instead.
*/
collections.AuthIdentity = Container.get(AuthIdentityRepository);
collections.AuthProviderSyncHistory = Container.get(AuthProviderSyncHistoryRepository);
collections.EventDestinations = Container.get(EventDestinationsRepository);
collections.Execution = Container.get(ExecutionRepository);
collections.ExecutionData = Container.get(ExecutionDataRepository);
collections.ExecutionMetadata = Container.get(ExecutionMetadataRepository);
collections.InstalledNodes = Container.get(InstalledNodesRepository);
collections.InstalledPackages = Container.get(InstalledPackagesRepository);
collections.SharedCredentials = Container.get(SharedCredentialsRepository);
collections.SharedWorkflow = Container.get(SharedWorkflowRepository);
collections.Variables = Container.get(VariablesRepository);
collections.WorkflowStatistics = Container.get(WorkflowStatisticsRepository);
collections.WorkflowTagMapping = Container.get(WorkflowTagMappingRepository);
/**
* @important Do not remove these collections until cloud hooks are backwards compatible.
*/
collections.Role = Container.get(RoleRepository);
collections.User = Container.get(UserRepository);
collections.Settings = Container.get(SettingsRepository);
collections.Credentials = Container.get(CredentialsRepository);
collections.Workflow = Container.get(WorkflowRepository);
}
export async function migrate() {

View file

@ -1,14 +1,15 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import { Service } from 'typedi';
import * as Db from '@/Db';
import type {
IExternalHooksClass,
IExternalHooksFileData,
IExternalHooksFunctions,
} from '@/Interfaces';
import config from '@/config';
import { UserRepository } from '@db/repositories/user.repository';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
@Service()
export class ExternalHooks implements IExternalHooksClass {
@ -16,7 +17,25 @@ export class ExternalHooks implements IExternalHooksClass {
[key: string]: Array<() => {}>;
} = {};
initDidRun = false;
private initDidRun = false;
private dbCollections: IExternalHooksFunctions['dbCollections'];
constructor(
userRepository: UserRepository,
settingsRepository: SettingsRepository,
credentialsRepository: CredentialsRepository,
workflowRepository: WorkflowRepository,
) {
/* eslint-disable @typescript-eslint/naming-convention */
this.dbCollections = {
User: userRepository,
Settings: settingsRepository,
Credentials: credentialsRepository,
Workflow: workflowRepository,
};
/* eslint-enable @typescript-eslint/naming-convention */
}
async init(): Promise<void> {
if (this.initDidRun) {
@ -83,14 +102,14 @@ export class ExternalHooks implements IExternalHooksClass {
}
async run(hookName: string, hookParameters?: any[]): Promise<void> {
const externalHookFunctions: IExternalHooksFunctions = {
dbCollections: Db.collections,
};
if (this.externalHooks[hookName] === undefined) {
return;
}
const externalHookFunctions: IExternalHooksFunctions = {
dbCollections: this.dbCollections,
};
for (const externalHookFunction of this.externalHooks[hookName]) {
await externalHookFunction.apply(externalHookFunctions, hookParameters);
}

View file

@ -1,4 +1,4 @@
import { SettingsRepository } from '@/databases/repositories';
import { SettingsRepository } from '@db/repositories/settings.repository';
import type {
ExternalSecretsSettings,
SecretsProvider,

View file

@ -10,7 +10,6 @@ import { validate } from 'class-validator';
import { Container } from 'typedi';
import { Like } from 'typeorm';
import config from '@/config';
import * as Db from '@/Db';
import type { ExecutionPayload, ICredentialsDb, IWorkflowDb } from '@/Interfaces';
import * as ResponseHelper from '@/ResponseHelper';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
@ -18,7 +17,9 @@ import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import type { TagEntity } from '@db/entities/TagEntity';
import type { User } from '@db/entities/User';
import type { UserUpdatePayload } from '@/requests';
import { ExecutionRepository } from '@db/repositories';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
/**
* Returns the base URL n8n is reachable from
@ -64,8 +65,8 @@ export async function generateUniqueName(
const found: Array<WorkflowEntity | ICredentialsDb> =
entityType === 'workflow'
? await Db.collections.Workflow.find(findConditions)
: await Db.collections.Credentials.find(findConditions);
? await Container.get(WorkflowRepository).find(findConditions)
: await Container.get(CredentialsRepository).find(findConditions);
// name is unique
if (found.length === 0) {

View file

@ -30,7 +30,7 @@ import type { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
import type { WorkflowExecute } from 'n8n-core';
import type PCancelable from 'p-cancelable';
import type { FindOperator, Repository } from 'typeorm';
import type { FindOperator } from 'typeorm';
import type { ChildProcess } from 'child_process';
@ -40,26 +40,10 @@ import type { Role } from '@db/entities/Role';
import type { SharedCredentials } from '@db/entities/SharedCredentials';
import type { TagEntity } from '@db/entities/TagEntity';
import type { User } from '@db/entities/User';
import type {
AuthIdentityRepository,
AuthProviderSyncHistoryRepository,
CredentialsRepository,
EventDestinationsRepository,
ExecutionDataRepository,
ExecutionMetadataRepository,
ExecutionRepository,
InstalledNodesRepository,
InstalledPackagesRepository,
RoleRepository,
SettingsRepository,
SharedCredentialsRepository,
SharedWorkflowRepository,
UserRepository,
VariablesRepository,
WorkflowRepository,
WorkflowStatisticsRepository,
WorkflowTagMappingRepository,
} from '@db/repositories';
import type { CredentialsRepository } from '@db/repositories/credentials.repository';
import type { SettingsRepository } from '@db/repositories/settings.repository';
import type { UserRepository } from '@db/repositories/user.repository';
import type { WorkflowRepository } from '@db/repositories/workflow.repository';
import type { LICENSE_FEATURES, LICENSE_QUOTAS } from './constants';
import type { WorkflowWithSharingsAndCredentials } from './workflows/workflows.types';
@ -71,33 +55,6 @@ export interface ICredentialsOverwrite {
[key: string]: ICredentialDataDecryptedObject;
}
/**
* @important Do not add to these collections. Inject the repository as a dependency instead.
*/
/* eslint-disable @typescript-eslint/naming-convention */
export interface IDatabaseCollections extends Record<string, Repository<any>> {
AuthIdentity: AuthIdentityRepository;
AuthProviderSyncHistory: AuthProviderSyncHistoryRepository;
Credentials: CredentialsRepository;
EventDestinations: EventDestinationsRepository;
Execution: ExecutionRepository;
ExecutionData: ExecutionDataRepository;
ExecutionMetadata: ExecutionMetadataRepository;
InstalledNodes: InstalledNodesRepository;
InstalledPackages: InstalledPackagesRepository;
Role: RoleRepository;
Settings: SettingsRepository;
SharedCredentials: SharedCredentialsRepository;
SharedWorkflow: SharedWorkflowRepository;
User: UserRepository;
Variables: VariablesRepository;
Workflow: WorkflowRepository;
WorkflowStatistics: WorkflowStatisticsRepository;
WorkflowTagMapping: WorkflowTagMappingRepository;
}
/* eslint-enable @typescript-eslint/naming-convention */
// ----------------------------------
// tags
// ----------------------------------
@ -285,7 +242,14 @@ export interface IExternalHooksFileData {
}
export interface IExternalHooksFunctions {
dbCollections: IDatabaseCollections;
dbCollections: {
/* eslint-disable @typescript-eslint/naming-convention */
User: UserRepository;
Settings: SettingsRepository;
Credentials: CredentialsRepository;
Workflow: WorkflowRepository;
/* eslint-enable @typescript-eslint/naming-convention */
};
}
export interface IExternalHooksClass {

View file

@ -32,6 +32,10 @@ import {
import { BadRequestError, InternalServerError } from '../ResponseHelper';
import { RoleService } from '@/services/role.service';
import { Logger } from '@/Logger';
import { UserRepository } from '@db/repositories/user.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { AuthProviderSyncHistoryRepository } from '@db/repositories/authProviderSyncHistory.repository';
import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository';
/**
* Check whether the LDAP feature is disabled in the instance
@ -114,7 +118,7 @@ export const validateLdapConfigurationSchema = (
* Retrieve the LDAP configuration (decrypted) form the database
*/
export const getLdapConfig = async (): Promise<LdapConfig> => {
const configuration = await Db.collections.Settings.findOneByOrFail({
const configuration = await Container.get(SettingsRepository).findOneByOrFail({
key: LDAP_FEATURE_NAME,
});
const configurationData = jsonParse<LdapConfig>(configuration.value);
@ -171,7 +175,7 @@ export const updateLdapConfig = async (ldapConfig: LdapConfig): Promise<void> =>
}
}
await Db.collections.Settings.update(
await Container.get(SettingsRepository).update(
{ key: LDAP_FEATURE_NAME },
{ value: JSON.stringify(ldapConfig), loadOnStartup: true },
);
@ -284,7 +288,7 @@ export const findAndAuthenticateLdapUser = async (
export const getAuthIdentityByLdapId = async (
idAttributeValue: string,
): Promise<AuthIdentity | null> => {
return Db.collections.AuthIdentity.findOne({
return Container.get(AuthIdentityRepository).findOne({
relations: ['user', 'user.globalRole'],
where: {
providerId: idAttributeValue,
@ -294,7 +298,7 @@ export const getAuthIdentityByLdapId = async (
};
export const getUserByEmail = async (email: string): Promise<User | null> => {
return Db.collections.User.findOne({
return Container.get(UserRepository).findOne({
where: { email },
relations: ['globalRole'],
});
@ -322,7 +326,7 @@ export const mapLdapAttributesToUser = (
* Retrieve LDAP ID of all LDAP users in the database
*/
export const getLdapIds = async (): Promise<string[]> => {
const identities = await Db.collections.AuthIdentity.find({
const identities = await Container.get(AuthIdentityRepository).find({
select: ['providerId'],
where: {
providerType: 'ldap',
@ -332,7 +336,7 @@ export const getLdapIds = async (): Promise<string[]> => {
};
export const getLdapUsers = async (): Promise<User[]> => {
const identities = await Db.collections.AuthIdentity.find({
const identities = await Container.get(AuthIdentityRepository).find({
relations: ['user'],
where: {
providerType: 'ldap',
@ -409,7 +413,7 @@ export const processUsers = async (
export const saveLdapSynchronization = async (
data: Omit<AuthProviderSyncHistory, 'id' | 'providerType'>,
): Promise<void> => {
await Db.collections.AuthProviderSyncHistory.save({
await Container.get(AuthProviderSyncHistoryRepository).save({
...data,
providerType: 'ldap',
});
@ -423,7 +427,7 @@ export const getLdapSynchronizations = async (
perPage: number,
): Promise<AuthProviderSyncHistory[]> => {
const _page = Math.abs(page);
return Db.collections.AuthProviderSyncHistory.find({
return Container.get(AuthProviderSyncHistoryRepository).find({
where: { providerType: 'ldap' },
order: { id: 'DESC' },
take: perPage,
@ -450,11 +454,11 @@ export const getMappingAttributes = (ldapConfig: LdapConfig): string[] => {
};
export const createLdapAuthIdentity = async (user: User, ldapId: string) => {
return Db.collections.AuthIdentity.save(AuthIdentity.create(user, ldapId));
return Container.get(AuthIdentityRepository).save(AuthIdentity.create(user, ldapId));
};
export const createLdapUserOnLocalDb = async (role: Role, data: Partial<User>, ldapId: string) => {
const user = await Db.collections.User.save({
const user = await Container.get(UserRepository).save({
password: randomPassword(),
globalRole: role,
...data,
@ -466,10 +470,10 @@ export const createLdapUserOnLocalDb = async (role: Role, data: Partial<User>, l
export const updateLdapUserOnLocalDb = async (identity: AuthIdentity, data: Partial<User>) => {
const userId = identity?.user?.id;
if (userId) {
await Db.collections.User.update({ id: userId }, data);
await Container.get(UserRepository).update({ id: userId }, data);
}
};
const deleteAllLdapIdentities = async () => {
return Db.collections.AuthIdentity.delete({ providerType: 'ldap' });
return Container.get(AuthIdentityRepository).delete({ providerType: 'ldap' });
};

View file

@ -4,7 +4,6 @@ import { InstanceSettings, ObjectStoreService } from 'n8n-core';
import Container, { Service } from 'typedi';
import { Logger } from '@/Logger';
import config from '@/config';
import * as Db from '@/Db';
import {
LICENSE_FEATURES,
LICENSE_QUOTAS,
@ -12,7 +11,8 @@ import {
SETTINGS_LICENSE_CERT_KEY,
UNLIMITED_LICENSE_QUOTA,
} from './constants';
import { WorkflowRepository } from '@/databases/repositories';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import type { BooleanLicenseFeature, N8nInstanceType, NumericLicenseFeature } from './Interfaces';
import type { RedisServicePubSubPublisher } from './services/redis/RedisServicePubSubPublisher';
import { RedisService } from './services/redis.service';
@ -40,6 +40,8 @@ export class License {
constructor(
private readonly logger: Logger,
private readonly instanceSettings: InstanceSettings,
private readonly settingsRepository: SettingsRepository,
private readonly workflowRepository: WorkflowRepository,
) {}
async init(instanceType: N8nInstanceType = 'main') {
@ -91,7 +93,7 @@ export class License {
return [
{
name: 'activeWorkflows',
value: await Container.get(WorkflowRepository).count({ where: { active: true } }),
value: await this.workflowRepository.count({ where: { active: true } }),
},
];
}
@ -102,7 +104,7 @@ export class License {
if (ephemeralLicense) {
return ephemeralLicense;
}
const databaseSettings = await Db.collections.Settings.findOne({
const databaseSettings = await this.settingsRepository.findOne({
where: {
key: SETTINGS_LICENSE_CERT_KEY,
},
@ -153,7 +155,7 @@ export class License {
async saveCertStr(value: TLicenseBlock): Promise<void> {
// if we have an ephemeral license, we don't want to save it to the database
if (config.get('license.cert')) return;
await Db.collections.Settings.upsert(
await this.settingsRepository.upsert(
{
key: SETTINGS_LICENSE_CERT_KEY,
value,

View file

@ -1,13 +1,14 @@
import Container from 'typedi';
import config from '@/config';
import * as Db from '@/Db';
import { MFA_FEATURE_ENABLED } from './constants';
import { UserRepository } from '@db/repositories/user.repository';
export const isMfaFeatureEnabled = () => config.get(MFA_FEATURE_ENABLED);
const isMfaFeatureDisabled = () => !isMfaFeatureEnabled();
const getUsersWithMfaEnabled = async () =>
Db.collections.User.count({ where: { mfaEnabled: true } });
Container.get(UserRepository).count({ where: { mfaEnabled: true } });
export const handleMfaDisable = async () => {
if (isMfaFeatureDisabled()) {

View file

@ -1,7 +1,7 @@
import { v4 as uuid } from 'uuid';
import { Service } from 'typedi';
import { Cipher } from 'n8n-core';
import { UserRepository } from '@db/repositories';
import { UserRepository } from '@db/repositories/user.repository';
import { TOTPService } from './totp.service';
@Service()

View file

@ -11,11 +11,11 @@ import type { OpenAPIV3 } from 'openapi-types';
import type { JsonObject } from 'swagger-ui-express';
import config from '@/config';
import * as Db from '@/Db';
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
import { Container } from 'typedi';
import { InternalHooks } from '@/InternalHooks';
import { License } from '@/License';
import { UserRepository } from '@db/repositories/user.repository';
async function createApiRouter(
version: string,
@ -95,7 +95,7 @@ async function createApiRouter(
schema: OpenAPIV3.ApiKeySecurityScheme,
): Promise<boolean> => {
const apiKey = req.headers[schema.name.toLowerCase()] as string;
const user = await Db.collections.User.findOne({
const user = await Container.get(UserRepository).findOne({
where: { apiKey },
relations: ['globalRole'],
});

View file

@ -10,9 +10,11 @@ import type { IDependency, IJsonSchema } from '../../../types';
import type { CredentialRequest } from '@/requests';
import { Container } from 'typedi';
import { RoleService } from '@/services/role.service';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
export async function getCredentials(credentialId: string): Promise<ICredentialsDb | null> {
return Db.collections.Credentials.findOneBy({ id: credentialId });
return Container.get(CredentialsRepository).findOneBy({ id: credentialId });
}
export async function getSharedCredentials(
@ -20,7 +22,7 @@ export async function getSharedCredentials(
credentialId: string,
relations?: string[],
): Promise<SharedCredentials | null> {
return Db.collections.SharedCredentials.findOne({
return Container.get(SharedCredentialsRepository).findOne({
where: {
userId,
credentialsId: credentialId,
@ -83,7 +85,7 @@ export async function saveCredential(
export async function removeCredential(credentials: CredentialsEntity): Promise<ICredentialsDb> {
await Container.get(ExternalHooks).run('credentials.delete', [credentials.id]);
return Db.collections.Credentials.remove(credentials);
return Container.get(CredentialsRepository).remove(credentials);
}
export async function encryptCredential(credential: CredentialsEntity): Promise<ICredentialsDb> {

View file

@ -8,7 +8,7 @@ import { getSharedWorkflowIds } from '../workflows/workflows.service';
import { encodeNextCursor } from '../../shared/services/pagination.service';
import { Container } from 'typedi';
import { InternalHooks } from '@/InternalHooks';
import { ExecutionRepository } from '@/databases/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
export = {
deleteExecution: [

View file

@ -3,9 +3,8 @@ import { In, Not, Raw, LessThan } from 'typeorm';
import { Container } from 'typedi';
import type { ExecutionStatus } from 'n8n-workflow';
import * as Db from '@/Db';
import type { IExecutionBase, IExecutionFlattedDb } from '@/Interfaces';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
function getStatusCondition(status: ExecutionStatus) {
const condition: Pick<FindOptionsWhere<IExecutionFlattedDb>, 'status'> = {};
@ -83,7 +82,7 @@ export async function getExecutionsCount(data: {
excludedWorkflowIds?: string[];
}): Promise<number> {
// TODO: Consider moving this to the repository as well
const executions = await Db.collections.Execution.count({
const executions = await Container.get(ExecutionRepository).count({
where: {
...(data.lastId && { id: LessThan(data.lastId) }),
...(data.status && { ...getStatusCondition(data.status) }),

View file

@ -1,5 +1,5 @@
import { Container } from 'typedi';
import { UserRepository } from '@db/repositories';
import { UserRepository } from '@db/repositories/user.repository';
import type { User } from '@db/entities/User';
import pick from 'lodash/pick';
import { validate as uuidValidate } from 'uuid';

View file

@ -10,6 +10,8 @@ import type { Role } from '@db/entities/Role';
import config from '@/config';
import { TagService } from '@/services/tag.service';
import Container from 'typedi';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
function insertIf(condition: boolean, elements: string[]): string[] {
return condition ? elements : [];
@ -17,7 +19,7 @@ function insertIf(condition: boolean, elements: string[]): string[] {
export async function getSharedWorkflowIds(user: User): Promise<string[]> {
const where = user.globalRole.name === 'owner' ? {} : { userId: user.id };
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
const sharedWorkflows = await Container.get(SharedWorkflowRepository).find({
where,
select: ['workflowId'],
});
@ -28,7 +30,7 @@ export async function getSharedWorkflow(
user: User,
workflowId?: string | undefined,
): Promise<SharedWorkflow | null> {
return Db.collections.SharedWorkflow.findOne({
return Container.get(SharedWorkflowRepository).findOne({
where: {
...(!user.isOwner && { userId: user.id }),
...(workflowId && { workflowId }),
@ -44,7 +46,7 @@ export async function getSharedWorkflows(
workflowIds?: string[];
},
): Promise<SharedWorkflow[]> {
return Db.collections.SharedWorkflow.find({
return Container.get(SharedWorkflowRepository).find({
where: {
...(!user.isOwner && { userId: user.id }),
...(options.workflowIds && { workflowId: In(options.workflowIds) }),
@ -54,7 +56,7 @@ export async function getSharedWorkflows(
}
export async function getWorkflowById(id: string): Promise<WorkflowEntity | null> {
return Db.collections.Workflow.findOne({
return Container.get(WorkflowRepository).findOne({
where: { id },
});
}
@ -97,28 +99,34 @@ export async function createWorkflow(
}
export async function setWorkflowAsActive(workflow: WorkflowEntity): Promise<UpdateResult> {
return Db.collections.Workflow.update(workflow.id, { active: true, updatedAt: new Date() });
return Container.get(WorkflowRepository).update(workflow.id, {
active: true,
updatedAt: new Date(),
});
}
export async function setWorkflowAsInactive(workflow: WorkflowEntity): Promise<UpdateResult> {
return Db.collections.Workflow.update(workflow.id, { active: false, updatedAt: new Date() });
return Container.get(WorkflowRepository).update(workflow.id, {
active: false,
updatedAt: new Date(),
});
}
export async function deleteWorkflow(workflow: WorkflowEntity): Promise<WorkflowEntity> {
return Db.collections.Workflow.remove(workflow);
return Container.get(WorkflowRepository).remove(workflow);
}
export async function getWorkflowsAndCount(
options: FindManyOptions<WorkflowEntity>,
): Promise<[WorkflowEntity[], number]> {
return Db.collections.Workflow.findAndCount(options);
return Container.get(WorkflowRepository).findAndCount(options);
}
export async function updateWorkflow(
workflowId: string,
updateData: WorkflowEntity,
): Promise<UpdateResult> {
return Db.collections.Workflow.update(workflowId, updateData);
return Container.get(WorkflowRepository).update(workflowId, updateData);
}
export function parseTagNames(tags: string): string[] {

View file

@ -85,7 +85,6 @@ import { executionsController } from '@/executions/executions.controller';
import { isApiEnabled, loadPublicApiVersions } from '@/PublicApi';
import { whereClause } from '@/UserManagement/UserManagementHelper';
import { UserManagementMailer } from '@/UserManagement/email';
import * as Db from '@/Db';
import type { ICredentialsOverwrite, IDiagnosticInfo, IExecutionsStopData } from '@/Interfaces';
import { ActiveExecutions } from '@/ActiveExecutions';
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
@ -119,8 +118,14 @@ import {
} from './sso/ssoHelpers';
import { SourceControlService } from '@/environments/sourceControl/sourceControl.service.ee';
import { SourceControlController } from '@/environments/sourceControl/sourceControl.controller.ee';
import { ExecutionRepository, SettingsRepository } from '@db/repositories';
import type { ExecutionEntity } from '@db/entities/ExecutionEntity';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { MfaService } from './Mfa/mfa.service';
import { handleMfaDisable, isMfaFeatureEnabled } from './Mfa/helpers';
import type { FrontendService } from './services/frontend.service';
@ -236,18 +241,19 @@ export class Server extends AbstractServer {
void this.loadNodesAndCredentials.setupHotReload();
}
void Db.collections.Workflow.findOne({
select: ['createdAt'],
order: { createdAt: 'ASC' },
where: {},
}).then(async (workflow) =>
Container.get(InternalHooks).onServerStarted(diagnosticInfo, workflow?.createdAt),
);
void Container.get(WorkflowRepository)
.findOne({
select: ['createdAt'],
order: { createdAt: 'ASC' },
where: {},
})
.then(async (workflow) =>
Container.get(InternalHooks).onServerStarted(diagnosticInfo, workflow?.createdAt),
);
}
private async registerControllers(ignoredEndpoints: Readonly<string[]>) {
const { app, externalHooks, activeWorkflowRunner, nodeTypes, logger } = this;
const repositories = Db.collections;
setupAuthMiddlewares(app, ignoredEndpoints, this.restEndpoint);
const internalHooks = Container.get(InternalHooks);
@ -281,8 +287,8 @@ export class Server extends AbstractServer {
logger,
externalHooks,
internalHooks,
repositories.SharedCredentials,
repositories.SharedWorkflow,
Container.get(SharedCredentialsRepository),
Container.get(SharedWorkflowRepository),
activeWorkflowRunner,
mailer,
jwtService,
@ -623,7 +629,7 @@ export class Server extends AbstractServer {
ResponseHelper.send(async (req: WorkflowRequest.GetAllActivationErrors) => {
const { id: workflowId } = req.params;
const shared = await Db.collections.SharedWorkflow.findOne({
const shared = await Container.get(SharedWorkflowRepository).findOne({
relations: ['workflow'],
where: whereClause({
user: req.user,

View file

@ -2,13 +2,15 @@ import type { INode, Workflow } from 'n8n-workflow';
import { NodeOperationError, SubworkflowOperationError } from 'n8n-workflow';
import type { FindOptionsWhere } from 'typeorm';
import { In } from 'typeorm';
import * as Db from '@/Db';
import config from '@/config';
import type { SharedCredentials } from '@db/entities/SharedCredentials';
import { isSharingEnabled } from './UserManagementHelper';
import { OwnershipService } from '@/services/ownership.service';
import Container from 'typedi';
import { RoleService } from '@/services/role.service';
import { UserRepository } from '@db/repositories/user.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
export class PermissionChecker {
/**
@ -25,7 +27,7 @@ export class PermissionChecker {
// allow if requesting user is instance owner
const user = await Db.collections.User.findOneOrFail({
const user = await Container.get(UserRepository).findOneOrFail({
where: { id: userId },
relations: ['globalRole'],
});
@ -38,7 +40,7 @@ export class PermissionChecker {
let workflowUserIds = [userId];
if (workflow.id && isSharingEnabled()) {
const workflowSharings = await Db.collections.SharedWorkflow.find({
const workflowSharings = await Container.get(SharedWorkflowRepository).find({
relations: ['workflow'],
where: { workflowId: workflow.id },
select: ['userId'],
@ -54,7 +56,7 @@ export class PermissionChecker {
credentialsWhere.roleId = role.id;
}
const credentialSharings = await Db.collections.SharedCredentials.find({
const credentialSharings = await Container.get(SharedCredentialsRepository).find({
where: credentialsWhere,
});

View file

@ -2,7 +2,6 @@ import { In } from 'typeorm';
import { compare, genSaltSync, hash } from 'bcryptjs';
import { Container } from 'typedi';
import * as Db from '@/Db';
import * as ResponseHelper from '@/ResponseHelper';
import type { WhereClause } from '@/Interfaces';
import type { User } from '@db/entities/User';
@ -11,6 +10,7 @@ import config from '@/config';
import { License } from '@/License';
import { getWebhookBaseUrl } from '@/WebhookHelpers';
import { RoleService } from '@/services/role.service';
import { UserRepository } from '@db/repositories/user.repository';
export function isSharingEnabled(): boolean {
return Container.get(License).isSharingEnabled();
@ -19,7 +19,7 @@ export function isSharingEnabled(): boolean {
export async function getInstanceOwner() {
const globalOwnerRole = await Container.get(RoleService).findGlobalOwnerRole();
return Db.collections.User.findOneOrFail({
return Container.get(UserRepository).findOneOrFail({
relations: ['globalRole'],
where: {
globalRoleId: globalOwnerRole.id,
@ -77,7 +77,7 @@ export function validatePassword(password?: string): string {
}
export async function getUserById(userId: string): Promise<User> {
const user = await Db.collections.User.findOneOrFail({
const user = await Container.get(UserRepository).findOneOrFail({
where: { id: userId },
relations: ['globalRole'],
});

View file

@ -13,7 +13,7 @@ import type {
} from '@/Interfaces';
import { WorkflowRunner } from '@/WorkflowRunner';
import { recoverExecutionDataFromEventLogMessages } from './eventbus/MessageEventBus/recoverEvents';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import type { ExecutionEntity } from '@db/entities/ExecutionEntity';
import { OwnershipService } from './services/ownership.service';
import { Logger } from '@/Logger';

View file

@ -12,7 +12,7 @@ import type {
WaitingWebhookRequest,
} from '@/Interfaces';
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { OwnershipService } from './services/ownership.service';
import { Logger } from '@/Logger';

View file

@ -1,5 +1,6 @@
import Container from 'typedi';
import type { INode, IWorkflowCredentials } from 'n8n-workflow';
import * as Db from '@/Db';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
// eslint-disable-next-line @typescript-eslint/naming-convention
export async function WorkflowCredentials(nodes: INode[]): Promise<IWorkflowCredentials> {
@ -29,7 +30,7 @@ export async function WorkflowCredentials(nodes: INode[]): Promise<IWorkflowCred
}
if (!returnCredentials[type][nodeCredentials.id]) {
foundCredentials = await Db.collections.Credentials.findOneBy({
foundCredentials = await Container.get(CredentialsRepository).findOneBy({
id: nodeCredentials.id,
type,
});

View file

@ -52,7 +52,7 @@ import { findSubworkflowStart, isWorkflowIdValid } from '@/utils';
import { PermissionChecker } from './UserManagement/PermissionChecker';
import { WorkflowsService } from './workflows/workflows.services';
import { InternalHooks } from '@/InternalHooks';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { EventsService } from '@/services/events.service';
import { SecretsHelper } from './SecretsHelpers';
import { OwnershipService } from './services/ownership.service';

View file

@ -21,7 +21,7 @@ import {
Workflow,
} from 'n8n-workflow';
import { v4 as uuid } from 'uuid';
import * as Db from '@/Db';
import omit from 'lodash/omit';
import type {
ExecutionPayload,
IWorkflowErrorData,
@ -32,15 +32,18 @@ import { WorkflowRunner } from '@/WorkflowRunner';
import config from '@/config';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import type { User } from '@db/entities/User';
import omit from 'lodash/omit';
import { PermissionChecker } from './UserManagement/PermissionChecker';
import { UserService } from './services/user.service';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import type { SharedWorkflow } from '@db/entities/SharedWorkflow';
import type { RoleNames } from '@db/entities/Role';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { RoleRepository } from '@db/repositories/role.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { RoleService } from './services/role.service';
import { ExecutionRepository, RoleRepository } from './databases/repositories';
import { VariablesService } from './environments/variables/variables.service';
import type { CredentialsEntity } from './databases/entities/CredentialsEntity';
import { Logger } from './Logger';
const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType');
@ -144,7 +147,7 @@ export async function executeErrorWorkflow(
const logger = Container.get(Logger);
// Wrap everything in try/catch to make sure that no errors bubble up and all get caught here
try {
const workflowData = await Db.collections.Workflow.findOneBy({ id: workflowId });
const workflowData = await Container.get(WorkflowRepository).findOneBy({ id: workflowId });
if (workflowData === null) {
// The error workflow could not be found
@ -282,7 +285,7 @@ export async function executeErrorWorkflow(
* Returns the static data of workflow
*/
export async function getStaticDataById(workflowId: string) {
const workflowData = await Db.collections.Workflow.findOne({
const workflowData = await Container.get(WorkflowRepository).findOne({
select: ['staticData'],
where: { id: workflowId },
});
@ -330,7 +333,7 @@ export async function replaceInvalidCredentials(workflow: WorkflowEntity): Promi
credentialsByName[nodeCredentialType] = {};
}
if (credentialsByName[nodeCredentialType][name] === undefined) {
const credentials = await Db.collections.Credentials.findBy({
const credentials = await Container.get(CredentialsRepository).findBy({
name,
type: nodeCredentialType,
});
@ -366,7 +369,7 @@ export async function replaceInvalidCredentials(workflow: WorkflowEntity): Promi
// check if credentials for ID-type are not yet cached
if (credentialsById[nodeCredentialType][nodeCredentials.id] === undefined) {
// check first if ID-type combination exists
const credentials = await Db.collections.Credentials.findOneBy({
const credentials = await Container.get(CredentialsRepository).findOneBy({
id: nodeCredentials.id,
type: nodeCredentialType,
});
@ -380,7 +383,7 @@ export async function replaceInvalidCredentials(workflow: WorkflowEntity): Promi
continue;
}
// no credentials found for ID, check if some exist for name
const credsByName = await Db.collections.Credentials.findBy({
const credsByName = await Container.get(CredentialsRepository).findBy({
name: nodeCredentials.name,
type: nodeCredentialType,
});
@ -429,7 +432,7 @@ export async function getSharedWorkflowIds(user: User, roles?: RoleNames[]): Pro
where.roleId = In(roleIds);
}
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
const sharedWorkflows = await Container.get(SharedWorkflowRepository).find({
where,
select: ['workflowId'],
});
@ -444,19 +447,21 @@ export async function isBelowOnboardingThreshold(user: User): Promise<boolean> {
const skippedTypes = ['n8n-nodes-base.start', 'n8n-nodes-base.stickyNote'];
const workflowOwnerRole = await Container.get(RoleService).findWorkflowOwnerRole();
const ownedWorkflowsIds = await Db.collections.SharedWorkflow.find({
where: {
userId: user.id,
roleId: workflowOwnerRole?.id,
},
select: ['workflowId'],
}).then((ownedWorkflows) => ownedWorkflows.map(({ workflowId }) => workflowId));
const ownedWorkflowsIds = await Container.get(SharedWorkflowRepository)
.find({
where: {
userId: user.id,
roleId: workflowOwnerRole?.id,
},
select: ['workflowId'],
})
.then((ownedWorkflows) => ownedWorkflows.map(({ workflowId }) => workflowId));
if (ownedWorkflowsIds.length > 15) {
belowThreshold = false;
} else {
// just fetch workflows' nodes to keep memory footprint low
const workflows = await Db.collections.Workflow.find({
const workflows = await Container.get(WorkflowRepository).find({
where: { id: In(ownedWorkflowsIds) },
select: ['nodes'],
});

View file

@ -48,7 +48,7 @@ import { PermissionChecker } from '@/UserManagement/PermissionChecker';
import { Push } from '@/push';
import { Container } from 'typedi';
import { InternalHooks } from './InternalHooks';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { Logger } from './Logger';
export class WorkflowRunner {

View file

@ -1,4 +1,3 @@
import * as Db from '@/Db';
import { separate } from '@/utils';
import config from '@/config';
import { RISK_CATEGORIES } from '@/audit/constants';
@ -9,6 +8,8 @@ import { reportNodesRisk } from '@/audit/risks/nodes.risk';
import { reportFilesystemRisk } from '@/audit/risks/filesystem.risk';
import { reportInstanceRisk } from '@/audit/risks/instance.risk';
import type { Risk } from '@/audit/types';
import Container from 'typedi';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
export const SYNC_MAP: Record<string, Risk.SyncReportFn> = {
database: reportDatabaseRisk,
@ -35,7 +36,7 @@ export async function audit(
config.set('security.audit.daysAbandonedWorkflow', daysAbandonedWorkflow);
}
const workflows = await Db.collections.Workflow.find({
const workflows = await Container.get(WorkflowRepository).find({
select: ['id', 'name', 'active', 'nodes', 'connections'],
});

View file

@ -6,11 +6,9 @@ import config from '@/config';
import { CREDENTIALS_REPORT } from '@/audit/constants';
import type { Risk } from '@/audit/types';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import {
CredentialsRepository,
ExecutionDataRepository,
ExecutionRepository,
} from '@db/repositories';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { ExecutionDataRepository } from '@db/repositories/executionData.repository';
async function getAllCredsInUse(workflows: WorkflowEntity[]) {
const credsInAnyUse = new Set<string>();

View file

@ -1,7 +1,6 @@
import jwt from 'jsonwebtoken';
import type { Response } from 'express';
import { createHash } from 'crypto';
import * as Db from '@/Db';
import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants';
import type { JwtPayload, JwtToken } from '@/Interfaces';
import type { User } from '@db/entities/User';
@ -9,6 +8,7 @@ import config from '@/config';
import * as ResponseHelper from '@/ResponseHelper';
import { License } from '@/License';
import { Container } from 'typedi';
import { UserRepository } from '@db/repositories/user.repository';
export function issueJWT(user: User): JwtToken {
const { id, email, password } = user;
@ -50,7 +50,7 @@ export const createPasswordSha = (user: User) =>
.digest('hex');
export async function resolveJwtContent(jwtPayload: JwtPayload): Promise<User> {
const user = await Db.collections.User.findOne({
const user = await Container.get(UserRepository).findOne({
where: { id: jwtPayload.id },
relations: ['globalRole'],
});

View file

@ -1,16 +1,16 @@
import * as Db from '@/Db';
import type { User } from '@db/entities/User';
import { compareHash } from '@/UserManagement/UserManagementHelper';
import * as ResponseHelper from '@/ResponseHelper';
import { Container } from 'typedi';
import { InternalHooks } from '@/InternalHooks';
import { isLdapLoginEnabled } from '@/Ldap/helpers';
import { UserRepository } from '@db/repositories/user.repository';
export const handleEmailLogin = async (
email: string,
password: string,
): Promise<User | undefined> => {
const user = await Db.collections.User.findOne({
const user = await Container.get(UserRepository).findOne({
where: { email },
relations: ['globalRole', 'authIdentities'],
});

View file

@ -1,4 +1,4 @@
import type { User } from '@/databases/entities/User';
import type { User } from '@db/entities/User';
import type { Workflow } from 'n8n-workflow';
import { Service } from 'typedi';

View file

@ -20,7 +20,7 @@ import { PostHogClient } from '@/posthog';
import { License } from '@/License';
import { ExternalSecretsManager } from '@/ExternalSecrets/ExternalSecretsManager.ee';
import { initExpressionEvaluator } from '@/ExpressionEvalator';
import { generateHostInstanceId } from '../databases/utils/generators';
import { generateHostInstanceId } from '@db/utils/generators';
import { WorkflowHistoryManager } from '@/workflows/workflowHistory/workflowHistoryManager.ee';
export abstract class BaseCommand extends Command {

View file

@ -5,13 +5,13 @@ import type { IWorkflowBase } from 'n8n-workflow';
import { ExecutionBaseError } from 'n8n-workflow';
import { ActiveExecutions } from '@/ActiveExecutions';
import * as Db from '@/Db';
import { WorkflowRunner } from '@/WorkflowRunner';
import type { IWorkflowExecutionDataProcess } from '@/Interfaces';
import { getInstanceOwner } from '@/UserManagement/UserManagementHelper';
import { findCliWorkflowStart, isWorkflowIdValid } from '@/utils';
import { BaseCommand } from './BaseCommand';
import { Container } from 'typedi';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
export class Execute extends BaseCommand {
static description = '\nExecutes a given workflow';
@ -81,7 +81,7 @@ export class Execute extends BaseCommand {
if (flags.id) {
// Id of workflow is given
workflowId = flags.id;
workflowData = await Db.collections.Workflow.findOneBy({ id: workflowId });
workflowData = await Container.get(WorkflowRepository).findOneBy({ id: workflowId });
if (workflowData === null) {
this.logger.info(`The workflow with the id "${workflowId}" does not exist.`);
process.exit(1);

View file

@ -9,7 +9,6 @@ import { diff } from 'json-diff';
import pick from 'lodash/pick';
import { ActiveExecutions } from '@/ActiveExecutions';
import * as Db from '@/Db';
import { WorkflowRunner } from '@/WorkflowRunner';
import type { IWorkflowDb, IWorkflowExecutionDataProcess } from '@/Interfaces';
import type { User } from '@db/entities/User';
@ -24,6 +23,7 @@ import type {
IResult,
IWorkflowExecutionProgress,
} from '../types/commands.types';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
const re = /\d+/;
@ -278,7 +278,7 @@ export class ExecuteBatch extends BaseCommand {
ExecuteBatch.instanceOwner = await getInstanceOwner();
const query = Db.collections.Workflow.createQueryBuilder('workflows');
const query = Container.get(WorkflowRepository).createQueryBuilder('workflows');
if (ids.length > 0) {
query.andWhere('workflows.id in (:...ids)', { ids });

View file

@ -3,9 +3,10 @@ import fs from 'fs';
import path from 'path';
import type { FindOptionsWhere } from 'typeorm';
import { Credentials } from 'n8n-core';
import * as Db from '@/Db';
import type { ICredentialsDb, ICredentialsDecryptedDb } from '@/Interfaces';
import { BaseCommand } from '../BaseCommand';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import Container from 'typedi';
export class ExportCredentialsCommand extends BaseCommand {
static description = 'Export credentials';
@ -110,7 +111,8 @@ export class ExportCredentialsCommand extends BaseCommand {
findQuery.id = flags.id;
}
const credentials: ICredentialsDb[] = await Db.collections.Credentials.findBy(findQuery);
const credentials: ICredentialsDb[] =
await Container.get(CredentialsRepository).findBy(findQuery);
if (flags.decrypted) {
for (let i = 0; i < credentials.length; i++) {

View file

@ -2,9 +2,10 @@ import { flags } from '@oclif/command';
import fs from 'fs';
import path from 'path';
import type { FindOptionsWhere } from 'typeorm';
import * as Db from '@/Db';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import { BaseCommand } from '../BaseCommand';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import Container from 'typedi';
export class ExportWorkflowsCommand extends BaseCommand {
static description = 'Export workflows';
@ -104,7 +105,7 @@ export class ExportWorkflowsCommand extends BaseCommand {
findQuery.id = flags.id;
}
const workflows = await Db.collections.Workflow.find({
const workflows = await Container.get(WorkflowRepository).find({
where: findQuery,
relations: ['tags'],
});

View file

@ -15,6 +15,7 @@ import type { ICredentialsEncrypted } from 'n8n-workflow';
import { jsonParse } from 'n8n-workflow';
import { RoleService } from '@/services/role.service';
import { UM_FIX_INSTRUCTION } from '@/constants';
import { UserRepository } from '@db/repositories/user.repository';
export class ImportCredentialsCommand extends BaseCommand {
static description = 'Import credentials';
@ -175,7 +176,7 @@ export class ImportCredentialsCommand extends BaseCommand {
const owner =
ownerGlobalRole &&
(await Db.collections.User.findOneBy({ globalRoleId: ownerGlobalRole.id }));
(await Container.get(UserRepository).findOneBy({ globalRoleId: ownerGlobalRole.id }));
if (!owner) {
throw new Error(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
@ -185,7 +186,7 @@ export class ImportCredentialsCommand extends BaseCommand {
}
private async getAssignee(userId: string) {
const user = await Db.collections.User.findOneBy({ id: userId });
const user = await Container.get(UserRepository).findOneBy({ id: userId });
if (!user) {
throw new Error(`Failed to find user with ID ${userId}`);

View file

@ -19,6 +19,8 @@ import { generateNanoId } from '@db/utils/generators';
import { RoleService } from '@/services/role.service';
import { TagService } from '@/services/tag.service';
import { UM_FIX_INSTRUCTION } from '@/constants';
import { UserRepository } from '@db/repositories/user.repository';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
function assertHasWorkflowsToImport(workflows: unknown): asserts workflows is IWorkflowToImport[] {
if (!Array.isArray(workflows)) {
@ -95,7 +97,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
await this.initOwnerWorkflowRole();
const user = flags.userId ? await this.getAssignee(flags.userId) : await this.getOwner();
const credentials = await Db.collections.Credentials.find();
const credentials = await Container.get(CredentialsRepository).find();
const tags = await this.tagService.getAll();
let totalImported = 0;
@ -239,7 +241,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
const owner =
ownerGlobalRole &&
(await Db.collections.User.findOneBy({ globalRoleId: ownerGlobalRole?.id }));
(await Container.get(UserRepository).findOneBy({ globalRoleId: ownerGlobalRole?.id }));
if (!owner) {
throw new Error(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
@ -249,7 +251,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
}
private async getAssignee(userId: string) {
const user = await Db.collections.User.findOneBy({ id: userId });
const user = await Container.get(UserRepository).findOneBy({ id: userId });
if (!user) {
throw new Error(`Failed to find user with ID ${userId}`);

View file

@ -1,22 +1,25 @@
import * as Db from '@/Db';
import Container from 'typedi';
import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/Ldap/constants';
import { In } from 'typeorm';
import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository';
import { AuthProviderSyncHistoryRepository } from '@db/repositories/authProviderSyncHistory.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { UserRepository } from '@db/repositories/user.repository';
import { BaseCommand } from '../BaseCommand';
export class Reset extends BaseCommand {
static description = '\nResets the database to the default ldap state';
async run(): Promise<void> {
const { AuthIdentity, AuthProviderSyncHistory, Settings, User } = Db.collections;
const ldapIdentities = await AuthIdentity.find({
const ldapIdentities = await Container.get(AuthIdentityRepository).find({
where: { providerType: 'ldap' },
select: ['userId'],
});
await AuthProviderSyncHistory.delete({ providerType: 'ldap' });
await AuthIdentity.delete({ providerType: 'ldap' });
await User.delete({ id: In(ldapIdentities.map((i) => i.userId)) });
await Settings.delete({ key: LDAP_FEATURE_NAME });
await Settings.insert({
await Container.get(AuthProviderSyncHistoryRepository).delete({ providerType: 'ldap' });
await Container.get(AuthIdentityRepository).delete({ providerType: 'ldap' });
await Container.get(UserRepository).delete({ id: In(ldapIdentities.map((i) => i.userId)) });
await Container.get(SettingsRepository).delete({ key: LDAP_FEATURE_NAME });
await Container.get(SettingsRepository).insert({
key: LDAP_FEATURE_NAME,
value: JSON.stringify(LDAP_DEFAULT_CONFIGURATION),
loadOnStartup: true,

View file

@ -1,6 +1,7 @@
import * as Db from '@/Db';
import { SETTINGS_LICENSE_CERT_KEY } from '@/constants';
import { BaseCommand } from '../BaseCommand';
import { SettingsRepository } from '@db/repositories/settings.repository';
import Container from 'typedi';
export class ClearLicenseCommand extends BaseCommand {
static description = 'Clear license';
@ -9,7 +10,7 @@ export class ClearLicenseCommand extends BaseCommand {
async run() {
this.logger.info('Clearing license from database.');
await Db.collections.Settings.delete({
await Container.get(SettingsRepository).delete({
key: SETTINGS_LICENSE_CERT_KEY,
});
this.logger.info('Done. Restart n8n to take effect.');

View file

@ -1,8 +1,9 @@
import { flags } from '@oclif/command';
import type { FindOptionsWhere } from 'typeorm';
import * as Db from '@/Db';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import { BaseCommand } from '../BaseCommand';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import Container from 'typedi';
export class ListWorkflowCommand extends BaseCommand {
static description = '\nList workflows';
@ -36,7 +37,7 @@ export class ListWorkflowCommand extends BaseCommand {
findQuery.active = flags.active === 'true';
}
const workflows = await Db.collections.Workflow.findBy(findQuery);
const workflows = await Container.get(WorkflowRepository).findBy(findQuery);
if (flags.onlyId) {
workflows.forEach((workflow) => this.logger.info(workflow.id));
} else {

View file

@ -1,6 +1,7 @@
import { flags } from '@oclif/command';
import * as Db from '@/Db';
import { BaseCommand } from '../BaseCommand';
import Container from 'typedi';
import { UserRepository } from '@db/repositories/user.repository';
export class DisableMFACommand extends BaseCommand {
static description = 'Disable MFA authentication for a user';
@ -27,7 +28,7 @@ export class DisableMFACommand extends BaseCommand {
return;
}
const updateOperationResult = await Db.collections.User.update(
const updateOperationResult = await Container.get(UserRepository).update(
{ email: flags.email },
{ mfaSecret: null, mfaRecoveryCodes: [], mfaEnabled: false },
);

View file

@ -18,7 +18,6 @@ import config from '@/config';
import { ActiveExecutions } from '@/ActiveExecutions';
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
import * as Db from '@/Db';
import * as GenericHelpers from '@/GenericHelpers';
import { Server } from '@/Server';
import { EDITOR_UI_DIST_DIR, LICENSE_FEATURES } from '@/constants';
@ -30,6 +29,8 @@ import { IConfig } from '@oclif/config';
import { SingleMainInstancePublisher } from '@/services/orchestration/main/SingleMainInstance.publisher';
import { OrchestrationHandlerMainService } from '@/services/orchestration/main/orchestration.handler.main.service';
import { PruningService } from '@/services/pruning.service';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { ExecutionRepository } from '@db/repositories/execution.repository';
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
const open = require('open');
@ -286,7 +287,9 @@ export class Start extends BaseCommand {
}
// Load settings from database and set them to config.
const databaseSettings = await Db.collections.Settings.findBy({ loadOnStartup: true });
const databaseSettings = await Container.get(SettingsRepository).findBy({
loadOnStartup: true,
});
databaseSettings.forEach((setting) => {
config.set(setting.key, jsonParse(setting.value, { fallbackValue: setting.value }));
});
@ -304,7 +307,7 @@ export class Start extends BaseCommand {
if (dbType === 'sqlite') {
const shouldRunVacuum = config.getEnv('database.sqlite.executeVacuumOnStartup');
if (shouldRunVacuum) {
await Db.collections.Execution.query('VACUUM;');
await Container.get(ExecutionRepository).query('VACUUM;');
}
}

View file

@ -1,9 +1,10 @@
import { flags } from '@oclif/command';
import type { FindOptionsWhere } from 'typeorm';
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import * as Db from '@/Db';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import { BaseCommand } from '../BaseCommand';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import Container from 'typedi';
export class UpdateWorkflowCommand extends BaseCommand {
static description = 'Update workflows';
@ -64,7 +65,7 @@ export class UpdateWorkflowCommand extends BaseCommand {
findQuery.active = true;
}
await Db.collections.Workflow.update(findQuery, updateQuery);
await Container.get(WorkflowRepository).update(findQuery, updateQuery);
this.logger.info('Done');
}

View file

@ -1,10 +1,14 @@
import { Container } from 'typedi';
import { Not } from 'typeorm';
import * as Db from '@/Db';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import { User } from '@db/entities/User';
import { BaseCommand } from '../BaseCommand';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { UserRepository } from '@db/repositories/user.repository';
import { RoleService } from '@/services/role.service';
import { BaseCommand } from '../BaseCommand';
const defaultUserProps = {
firstName: null,
@ -24,34 +28,34 @@ export class Reset extends BaseCommand {
const ownerWorkflowRole = await Container.get(RoleService).findWorkflowOwnerRole();
const ownerCredentialRole = await Container.get(RoleService).findCredentialOwnerRole();
await Db.collections.SharedWorkflow.update(
await Container.get(SharedWorkflowRepository).update(
{ userId: Not(owner.id), roleId: ownerWorkflowRole.id },
{ user: owner },
);
await Db.collections.SharedCredentials.update(
await Container.get(SharedCredentialsRepository).update(
{ userId: Not(owner.id), roleId: ownerCredentialRole.id },
{ user: owner },
);
await Db.collections.User.delete({ id: Not(owner.id) });
await Db.collections.User.save(Object.assign(owner, defaultUserProps));
await Container.get(UserRepository).delete({ id: Not(owner.id) });
await Container.get(UserRepository).save(Object.assign(owner, defaultUserProps));
const danglingCredentials: CredentialsEntity[] =
await Db.collections.Credentials.createQueryBuilder('credentials')
.leftJoinAndSelect('credentials.shared', 'shared')
.where('shared.credentialsId is null')
.getMany();
const danglingCredentials: CredentialsEntity[] = await Container.get(CredentialsRepository)
.createQueryBuilder('credentials')
.leftJoinAndSelect('credentials.shared', 'shared')
.where('shared.credentialsId is null')
.getMany();
const newSharedCredentials = danglingCredentials.map((credentials) =>
Db.collections.SharedCredentials.create({
Container.get(SharedCredentialsRepository).create({
credentials,
user: owner,
role: ownerCredentialRole,
}),
);
await Db.collections.SharedCredentials.save(newSharedCredentials);
await Container.get(SharedCredentialsRepository).save(newSharedCredentials);
await Db.collections.Settings.update(
await Container.get(SettingsRepository).update(
{ key: 'userManagement.isInstanceOwnerSetUp' },
{ value: 'false' },
);
@ -62,7 +66,7 @@ export class Reset extends BaseCommand {
async getInstanceOwner(): Promise<User> {
const globalRole = await Container.get(RoleService).findGlobalOwnerRole();
const owner = await Db.collections.User.findOneBy({ globalRoleId: globalRole.id });
const owner = await Container.get(UserRepository).findOneBy({ globalRoleId: globalRole.id });
if (owner) return owner;
@ -70,9 +74,9 @@ export class Reset extends BaseCommand {
Object.assign(user, { ...defaultUserProps, globalRole });
await Db.collections.User.save(user);
await Container.get(UserRepository).save(user);
return Db.collections.User.findOneByOrFail({ globalRoleId: globalRole.id });
return Container.get(UserRepository).findOneByOrFail({ globalRoleId: globalRole.id });
}
async catch(error: Error): Promise<void> {

View file

@ -27,7 +27,8 @@ import { Queue } from '@/Queue';
import { generateFailedExecutionFromError } from '@/WorkflowHelpers';
import { N8N_VERSION } from '@/constants';
import { BaseCommand } from './BaseCommand';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { OwnershipService } from '@/services/ownership.service';
import type { ICredentialsOverwrite } from '@/Interfaces';
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
@ -137,7 +138,7 @@ export class Worker extends BaseCommand {
let { staticData } = fullExecutionData.workflowData;
if (loadStaticData) {
const workflowData = await Db.collections.Workflow.findOne({
const workflowData = await Container.get(WorkflowRepository).findOne({
select: ['id', 'staticData'],
where: {
id: workflowId,

View file

@ -3,7 +3,9 @@ import { Service } from 'typedi';
import { v4 as uuid } from 'uuid';
import config from '@/config';
import type { Role } from '@db/entities/Role';
import { RoleRepository, SettingsRepository, UserRepository } from '@db/repositories';
import { RoleRepository } from '@db/repositories/role.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { UserRepository } from '@db/repositories/user.repository';
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
import { hashPassword } from '@/UserManagement/UserManagementHelper';
import { eventBus } from '@/eventbus/MessageEventBus/MessageEventBus';

View file

@ -4,7 +4,8 @@ import type { ICredentialDataDecryptedObject, IWorkflowExecuteAdditionalData } f
import config from '@/config';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import type { User } from '@db/entities/User';
import { CredentialsRepository, SharedCredentialsRepository } from '@db/repositories';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import type { ICredentialsDb } from '@/Interfaces';
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
import type { OAuthRequest } from '@/requests';

View file

@ -8,7 +8,7 @@ import { Response } from 'express';
import { Config } from '@/config';
import { OwnerRequest } from '@/requests';
import { IInternalHooksClass } from '@/Interfaces';
import { SettingsRepository } from '@db/repositories';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { PostHogClient } from '@/posthog';
import { UserService } from '@/services/user.service';
import { Logger } from '@/Logger';

View file

@ -29,7 +29,8 @@ import type { PublicUser, ITelemetryUserDeletionData } from '@/Interfaces';
import { AuthIdentity } from '@db/entities/AuthIdentity';
import { PostHogClient } from '@/posthog';
import { isSamlLicensedAndEnabled } from '../sso/saml/samlHelpers';
import { SharedCredentialsRepository, SharedWorkflowRepository } from '@db/repositories';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { plainToInstance } from 'class-transformer';
import { License } from '@/License';
import { Container } from 'typedi';

View file

@ -3,7 +3,8 @@ import { Response, NextFunction } from 'express';
import { Get, Middleware, RestController } from '@/decorators';
import type { WorkflowStatistics } from '@db/entities/WorkflowStatistics';
import { StatisticsNames } from '@db/entities/WorkflowStatistics';
import { SharedWorkflowRepository, WorkflowStatisticsRepository } from '@db/repositories';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { WorkflowStatisticsRepository } from '@db/repositories/workflowStatistics.repository';
import { ExecutionRequest } from '@/requests';
import { whereClause } from '@/UserManagement/UserManagementHelper';
import { NotFoundError } from '@/ResponseHelper';

View file

@ -10,7 +10,7 @@ import { EECredentialsService as EECredentials } from './credentials.service.ee'
import { OwnershipService } from '@/services/ownership.service';
import { Container } from 'typedi';
import { InternalHooks } from '@/InternalHooks';
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
export const EECredentialsController = express.Router();

View file

@ -1,6 +1,5 @@
import type { DeleteResult, EntityManager, FindOptionsWhere } from 'typeorm';
import { In, Not } from 'typeorm';
import * as Db from '@/Db';
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
import { SharedCredentials } from '@db/entities/SharedCredentials';
import type { User } from '@db/entities/User';
@ -8,6 +7,7 @@ import { UserService } from '@/services/user.service';
import { CredentialsService } from './credentials.service';
import { RoleService } from '@/services/role.service';
import Container from 'typedi';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
export class EECredentialsService extends CredentialsService {
static async isOwned(
@ -43,7 +43,7 @@ export class EECredentialsService extends CredentialsService {
where.userId = user.id;
}
return Db.collections.SharedCredentials.findOne({
return Container.get(SharedCredentialsRepository).findOne({
where,
relations,
});
@ -83,7 +83,7 @@ export class EECredentialsService extends CredentialsService {
const newSharedCredentials = users
.filter((user) => !user.isPending)
.map((user) =>
Db.collections.SharedCredentials.create({
Container.get(SharedCredentialsRepository).create({
credentialsId: credential.id,
userId: user.id,
roleId: role?.id,

View file

@ -25,13 +25,15 @@ import { CredentialTypes } from '@/CredentialTypes';
import { RoleService } from '@/services/role.service';
import { OwnershipService } from '@/services/ownership.service';
import { Logger } from '@/Logger';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
export class CredentialsService {
static async get(
where: FindOptionsWhere<ICredentialsDb>,
options?: { relations: string[] },
): Promise<ICredentialsDb | null> {
return Db.collections.Credentials.findOne({
return Container.get(CredentialsRepository).findOne({
relations: options?.relations,
where,
});
@ -88,14 +90,14 @@ export class CredentialsService {
const isDefaultSelect = !options.listQueryOptions?.select;
if (returnAll) {
const credentials = await Db.collections.Credentials.find(findManyOptions);
const credentials = await Container.get(CredentialsRepository).find(findManyOptions);
return isDefaultSelect ? this.addOwnedByAndSharedWith(credentials) : credentials;
}
const ids = await this.getAccessibleCredentials(user.id);
const credentials = await Db.collections.Credentials.find({
const credentials = await Container.get(CredentialsRepository).find({
...findManyOptions,
where: { ...findManyOptions.where, id: In(ids) }, // only accessible credentials
});
@ -107,7 +109,7 @@ export class CredentialsService {
* Get the IDs of all credentials owned by or shared with a user.
*/
private static async getAccessibleCredentials(userId: string) {
const sharings = await Db.collections.SharedCredentials.find({
const sharings = await Container.get(SharedCredentialsRepository).find({
relations: ['role'],
where: {
userId,
@ -125,7 +127,7 @@ export class CredentialsService {
options.relations = ['shared', 'shared.user', 'shared.role'];
}
return Db.collections.Credentials.find(options);
return Container.get(CredentialsRepository).find(options);
}
/**
@ -152,7 +154,7 @@ export class CredentialsService {
}
}
return Db.collections.SharedCredentials.findOne({ where, relations });
return Container.get(SharedCredentialsRepository).findOne({ where, relations });
}
static async prepareCreateData(
@ -162,7 +164,7 @@ export class CredentialsService {
// This saves us a merge but requires some type casting. These
// types are compatible for this case.
const newCredentials = Db.collections.Credentials.create(rest as ICredentialsDb);
const newCredentials = Container.get(CredentialsRepository).create(rest as ICredentialsDb);
await validateEntity(newCredentials);
@ -185,7 +187,7 @@ export class CredentialsService {
// This saves us a merge but requires some type casting. These
// types are compatible for this case.
const updateData = Db.collections.Credentials.create(mergedData as ICredentialsDb);
const updateData = Container.get(CredentialsRepository).create(mergedData as ICredentialsDb);
await validateEntity(updateData);
@ -234,11 +236,11 @@ export class CredentialsService {
await Container.get(ExternalHooks).run('credentials.update', [newCredentialData]);
// Update the credentials in DB
await Db.collections.Credentials.update(credentialId, newCredentialData);
await Container.get(CredentialsRepository).update(credentialId, newCredentialData);
// We sadly get nothing back from "update". Neither if it updated a record
// nor the new value. So query now the updated entry.
return Db.collections.Credentials.findOneBy({ id: credentialId });
return Container.get(CredentialsRepository).findOneBy({ id: credentialId });
}
static async save(
@ -281,7 +283,7 @@ export class CredentialsService {
static async delete(credentials: CredentialsEntity): Promise<void> {
await Container.get(ExternalHooks).run('credentials.delete', [credentials.id]);
await Db.collections.Credentials.remove(credentials);
await Container.get(CredentialsRepository).remove(credentials);
}
static async test(

View file

@ -1,21 +0,0 @@
export { AuthIdentityRepository } from './authIdentity.repository';
export { AuthProviderSyncHistoryRepository } from './authProviderSyncHistory.repository';
export { CredentialsRepository } from './credentials.repository';
export { EventDestinationsRepository } from './eventDestinations.repository';
export { ExecutionDataRepository } from './executionData.repository';
export { ExecutionMetadataRepository } from './executionMetadata.repository';
export { ExecutionRepository } from './execution.repository';
export { InstalledNodesRepository } from './installedNodes.repository';
export { InstalledPackagesRepository } from './installedPackages.repository';
export { RoleRepository } from './role.repository';
export { SettingsRepository } from './settings.repository';
export { SharedCredentialsRepository } from './sharedCredentials.repository';
export { SharedWorkflowRepository } from './sharedWorkflow.repository';
export { TagRepository } from './tag.repository';
export { UserRepository } from './user.repository';
export { VariablesRepository } from './variables.repository';
export { WebhookRepository } from './webhook.repository';
export { WorkflowHistoryRepository } from './workflowHistory.repository';
export { WorkflowRepository } from './workflow.repository';
export { WorkflowStatisticsRepository } from './workflowStatistics.repository';
export { WorkflowTagMappingRepository } from './workflowTagMapping.repository';

View file

@ -33,7 +33,7 @@ import type { Variables } from '@db/entities/Variables';
import type { SourceControlWorkflowVersionId } from './types/sourceControlWorkflowVersionId';
import type { ExportableCredential } from './types/exportableCredential';
import { InternalHooks } from '@/InternalHooks';
import { TagRepository } from '@/databases/repositories';
import { TagRepository } from '@db/repositories/tag.repository';
import { Logger } from '@/Logger';
@Service()

View file

@ -1,4 +1,4 @@
import { Service } from 'typedi';
import Container, { Service } from 'typedi';
import path from 'path';
import {
SOURCE_CONTROL_CREDENTIAL_EXPORT_FOLDER,
@ -6,7 +6,6 @@ import {
SOURCE_CONTROL_TAGS_EXPORT_FILE,
SOURCE_CONTROL_WORKFLOW_EXPORT_FOLDER,
} from './constants';
import * as Db from '@/Db';
import type { ICredentialDataDecryptedObject } from 'n8n-workflow';
import { writeFile as fsWriteFile, rm as fsRm } from 'fs/promises';
import { rmSync } from 'fs';
@ -25,8 +24,12 @@ import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import { In } from 'typeorm';
import type { SourceControlledFile } from './types/sourceControlledFile';
import { VariablesService } from '../variables/variables.service';
import { TagRepository } from '@/databases/repositories';
import { TagRepository } from '@db/repositories/tag.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { Logger } from '@/Logger';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { WorkflowTagMappingRepository } from '@db/repositories/workflowTagMapping.repository';
@Service()
export class SourceControlExportService {
@ -102,7 +105,7 @@ export class SourceControlExportService {
try {
sourceControlFoldersExistCheck([this.workflowExportFolder]);
const workflowIds = candidates.map((e) => e.id);
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
const sharedWorkflows = await Container.get(SharedWorkflowRepository).find({
relations: ['role', 'user'],
where: {
role: {
@ -112,7 +115,7 @@ export class SourceControlExportService {
workflowId: In(workflowIds),
},
});
const workflows = await Db.collections.Workflow.find({
const workflows = await Container.get(WorkflowRepository).find({
where: {
id: In(workflowIds),
},
@ -181,7 +184,7 @@ export class SourceControlExportService {
files: [],
};
}
const mappings = await Db.collections.WorkflowTagMapping.find();
const mappings = await Container.get(WorkflowTagMappingRepository).find();
const fileName = path.join(this.gitFolder, SOURCE_CONTROL_TAGS_EXPORT_FILE);
await fsWriteFile(
fileName,
@ -236,7 +239,7 @@ export class SourceControlExportService {
try {
sourceControlFoldersExistCheck([this.credentialExportFolder]);
const credentialIds = candidates.map((e) => e.id);
const credentialsToBeExported = await Db.collections.SharedCredentials.find({
const credentialsToBeExported = await Container.get(SharedCredentialsRepository).find({
relations: ['credentials', 'role', 'user'],
where: {
credentialsId: In(credentialIds),

View file

@ -7,7 +7,6 @@ import {
SOURCE_CONTROL_VARIABLES_EXPORT_FILE,
SOURCE_CONTROL_WORKFLOW_EXPORT_FOLDER,
} from './constants';
import * as Db from '@/Db';
import glob from 'fast-glob';
import { jsonParse } from 'n8n-workflow';
import { readFile as fsReadFile } from 'fs/promises';
@ -26,9 +25,16 @@ import { getCredentialExportPath, getWorkflowExportPath } from './sourceControlH
import type { SourceControlledFile } from './types/sourceControlledFile';
import { RoleService } from '@/services/role.service';
import { VariablesService } from '../variables/variables.service';
import { TagRepository } from '@/databases/repositories';
import { TagRepository } from '@db/repositories/tag.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { UserRepository } from '@db/repositories/user.repository';
import { UM_FIX_INSTRUCTION } from '@/constants';
import { Logger } from '@/Logger';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { WorkflowTagMappingRepository } from '@db/repositories/workflowTagMapping.repository';
import { VariablesRepository } from '@db/repositories/variables.repository';
@Service()
export class SourceControlImportService {
@ -110,7 +116,7 @@ export class SourceControlImportService {
}
public async getLocalVersionIdsFromDb(): Promise<SourceControlWorkflowVersionId[]> {
const localWorkflows = await Db.collections.Workflow.find({
const localWorkflows = await Container.get(WorkflowRepository).find({
select: ['id', 'name', 'versionId', 'updatedAt'],
});
return localWorkflows.map((local) => ({
@ -153,7 +159,7 @@ export class SourceControlImportService {
public async getLocalCredentialsFromDb(): Promise<
Array<ExportableCredential & { filename: string }>
> {
const localCredentials = await Db.collections.Credentials.find({
const localCredentials = await Container.get(CredentialsRepository).find({
select: ['id', 'name', 'type', 'nodesAccess'],
});
return localCredentials.map((local) => ({
@ -209,7 +215,7 @@ export class SourceControlImportService {
const localTags = await this.tagRepository.find({
select: ['id', 'name'],
});
const localMappings = await Db.collections.WorkflowTagMapping.find({
const localMappings = await Container.get(WorkflowTagMappingRepository).find({
select: ['workflowId', 'tagId'],
});
return { tags: localTags, mappings: localMappings };
@ -219,13 +225,13 @@ export class SourceControlImportService {
const ownerWorkflowRole = await this.getWorkflowOwnerRole();
const workflowRunner = this.activeWorkflowRunner;
const candidateIds = candidates.map((c) => c.id);
const existingWorkflows = await Db.collections.Workflow.find({
const existingWorkflows = await Container.get(WorkflowRepository).find({
where: {
id: In(candidateIds),
},
select: ['id', 'name', 'versionId', 'active'],
});
const allSharedWorkflows = await Db.collections.SharedWorkflow.find({
const allSharedWorkflows = await Container.get(SharedWorkflowRepository).find({
where: {
workflowId: In(candidateIds),
},
@ -244,7 +250,10 @@ export class SourceControlImportService {
const existingWorkflow = existingWorkflows.find((e) => e.id === importedWorkflow.id);
importedWorkflow.active = existingWorkflow?.active ?? false;
this.logger.debug(`Updating workflow id ${importedWorkflow.id ?? 'new'}`);
const upsertResult = await Db.collections.Workflow.upsert({ ...importedWorkflow }, ['id']);
const upsertResult = await Container.get(WorkflowRepository).upsert(
{ ...importedWorkflow },
['id'],
);
if (upsertResult?.identifiers?.length !== 1) {
throw new Error(`Failed to upsert workflow ${importedWorkflow.id ?? 'new'}`);
}
@ -254,7 +263,7 @@ export class SourceControlImportService {
if (cachedOwnerIds.has(importedWorkflow.owner)) {
workflowOwnerId = cachedOwnerIds.get(importedWorkflow.owner) ?? userId;
} else {
const foundUser = await Db.collections.User.findOne({
const foundUser = await Container.get(UserRepository).findOne({
where: {
email: importedWorkflow.owner,
},
@ -278,7 +287,7 @@ export class SourceControlImportService {
);
if (!existingSharedWorkflowOwnerByUserId && !existingSharedWorkflowOwnerByRoleId) {
// no owner exists yet, so create one
await Db.collections.SharedWorkflow.insert({
await Container.get(SharedWorkflowRepository).insert({
workflowId: importedWorkflow.id,
userId: workflowOwnerId,
roleId: ownerWorkflowRole.id,
@ -288,7 +297,7 @@ export class SourceControlImportService {
} else if (existingSharedWorkflowOwnerByUserId && !existingSharedWorkflowOwnerByRoleId) {
// if the worklflow has a non-global owner that is referenced by the owner file,
// and no existing global owner, update the owner to the user referenced in the owner file
await Db.collections.SharedWorkflow.update(
await Container.get(SharedWorkflowRepository).update(
{
workflowId: importedWorkflow.id,
userId: workflowOwnerId,
@ -310,7 +319,7 @@ export class SourceControlImportService {
} catch (error) {
this.logger.error(`Failed to activate workflow ${existingWorkflow.id}`, error as Error);
} finally {
await Db.collections.Workflow.update(
await Container.get(WorkflowRepository).update(
{ id: existingWorkflow.id },
{ versionId: importedWorkflow.versionId },
);
@ -331,7 +340,7 @@ export class SourceControlImportService {
public async importCredentialsFromWorkFolder(candidates: SourceControlledFile[], userId: string) {
const candidateIds = candidates.map((c) => c.id);
const existingCredentials = await Db.collections.Credentials.find({
const existingCredentials = await Container.get(CredentialsRepository).find({
where: {
id: In(candidateIds),
},
@ -339,7 +348,7 @@ export class SourceControlImportService {
});
const ownerCredentialRole = await this.getCredentialOwnerRole();
const ownerGlobalRole = await this.getOwnerGlobalRole();
const existingSharedCredentials = await Db.collections.SharedCredentials.find({
const existingSharedCredentials = await Container.get(SharedCredentialsRepository).find({
select: ['userId', 'credentialsId', 'roleId'],
where: {
credentialsId: In(candidateIds),
@ -370,7 +379,7 @@ export class SourceControlImportService {
newCredentialObject.nodesAccess = nodesAccess || existingCredential?.nodesAccess || [];
this.logger.debug(`Updating credential id ${newCredentialObject.id as string}`);
await Db.collections.Credentials.upsert(newCredentialObject, ['id']);
await Container.get(CredentialsRepository).upsert(newCredentialObject, ['id']);
if (!sharedOwner) {
const newSharedCredential = new SharedCredentials();
@ -378,7 +387,7 @@ export class SourceControlImportService {
newSharedCredential.userId = userId;
newSharedCredential.roleId = ownerCredentialRole.id;
await Db.collections.SharedCredentials.upsert({ ...newSharedCredential }, [
await Container.get(SharedCredentialsRepository).upsert({ ...newSharedCredential }, [
'credentialsId',
'userId',
]);
@ -413,7 +422,7 @@ export class SourceControlImportService {
const existingWorkflowIds = new Set(
(
await Db.collections.Workflow.find({
await Container.get(WorkflowRepository).find({
select: ['id'],
})
).map((e) => e.id),
@ -442,7 +451,7 @@ export class SourceControlImportService {
await Promise.all(
mappedTags.mappings.map(async (mapping) => {
if (!existingWorkflowIds.has(String(mapping.workflowId))) return;
await Db.collections.WorkflowTagMapping.upsert(
await Container.get(WorkflowTagMappingRepository).upsert(
{ tagId: String(mapping.tagId), workflowId: String(mapping.workflowId) },
{
skipUpdateIfNoValuesChanged: true,
@ -489,12 +498,12 @@ export class SourceControlImportService {
overriddenKeys.splice(overriddenKeys.indexOf(variable.key), 1);
}
try {
await Db.collections.Variables.upsert({ ...variable }, ['id']);
await Container.get(VariablesRepository).upsert({ ...variable }, ['id']);
} catch (errorUpsert) {
if (isUniqueConstraintError(errorUpsert as Error)) {
this.logger.debug(`Variable ${variable.key} already exists, updating instead`);
try {
await Db.collections.Variables.update({ key: variable.key }, { ...variable });
await Container.get(VariablesRepository).update({ key: variable.key }, { ...variable });
} catch (errorUpdate) {
this.logger.debug(`Failed to update variable ${variable.key}, skipping`);
this.logger.debug((errorUpdate as Error).message);
@ -509,8 +518,11 @@ export class SourceControlImportService {
if (overriddenKeys.length > 0 && valueOverrides) {
for (const key of overriddenKeys) {
result.imported.push(key);
const newVariable = Db.collections.Variables.create({ key, value: valueOverrides[key] });
await Db.collections.Variables.save(newVariable);
const newVariable = Container.get(VariablesRepository).create({
key,
value: valueOverrides[key],
});
await Container.get(VariablesRepository).save(newVariable);
}
}

View file

@ -1,4 +1,4 @@
import { Service } from 'typedi';
import Container, { Service } from 'typedi';
import { SourceControlPreferences } from './types/sourceControlPreferences';
import type { ValidationError } from 'class-validator';
import { validate } from 'class-validator';
@ -11,7 +11,6 @@ import {
} from './sourceControlHelper.ee';
import { InstanceSettings } from 'n8n-core';
import { jsonParse } from 'n8n-workflow';
import * as Db from '@/Db';
import {
SOURCE_CONTROL_SSH_FOLDER,
SOURCE_CONTROL_GIT_FOLDER,
@ -22,6 +21,7 @@ import path from 'path';
import type { KeyPairType } from './types/keyPairType';
import config from '@/config';
import { Logger } from '@/Logger';
import { SettingsRepository } from '@db/repositories/settings.repository';
@Service()
export class SourceControlPreferencesService {
@ -171,7 +171,7 @@ export class SourceControlPreferencesService {
if (saveToDb) {
const settingsValue = JSON.stringify(this._sourceControlPreferences);
try {
await Db.collections.Settings.save({
await Container.get(SettingsRepository).save({
key: SOURCE_CONTROL_PREFERENCES_DB_KEY,
value: settingsValue,
loadOnStartup: true,
@ -186,7 +186,7 @@ export class SourceControlPreferencesService {
async loadFromDbAndApplySourceControlPreferences(): Promise<
SourceControlPreferences | undefined
> {
const loadedPreferences = await Db.collections.Settings.findOne({
const loadedPreferences = await Container.get(SettingsRepository).findOne({
where: { key: SOURCE_CONTROL_PREFERENCES_DB_KEY },
});
if (loadedPreferences) {

View file

@ -1,7 +1,7 @@
import type { Variables } from '@db/entities/Variables';
import { CacheService } from '@/services/cache.service';
import Container, { Service } from 'typedi';
import { VariablesRepository } from '@/databases/repositories';
import { VariablesRepository } from '@db/repositories/variables.repository';
import type { DeepPartial } from 'typeorm';
@Service()

View file

@ -11,7 +11,6 @@ import type { MessageEventBusDestination } from '../MessageEventBusDestination/M
import { MessageEventBusLogWriter } from '../MessageEventBusWriter/MessageEventBusLogWriter';
import EventEmitter from 'events';
import config from '@/config';
import * as Db from '@/Db';
import { messageEventBusDestinationFromDb } from '../MessageEventBusDestination/MessageEventBusDestinationFromDb';
import uniqby from 'lodash/uniqBy';
import type { EventMessageConfirmSource } from '../EventMessageClasses/EventMessageConfirm';
@ -29,11 +28,13 @@ import {
import { recoverExecutionDataFromEventLogMessages } from './recoverEvents';
import { METRICS_EVENT_NAME } from '../MessageEventBusDestination/Helpers.ee';
import { Container, Service } from 'typedi';
import { ExecutionRepository, WorkflowRepository } from '@/databases/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import type { AbstractEventMessageOptions } from '../EventMessageClasses/AbstractEventMessageOptions';
import { getEventMessageObjectByType } from '../EventMessageClasses/Helpers';
import { SingleMainInstancePublisher } from '@/services/orchestration/main/SingleMainInstance.publisher';
import { Logger } from '@/Logger';
import { EventDestinationsRepository } from '@db/repositories/eventDestinations.repository';
export type EventMessageReturnMode = 'sent' | 'unsent' | 'all' | 'unfinished';
@ -79,7 +80,7 @@ export class MessageEventBus extends EventEmitter {
this.logger.debug('Initializing event bus...');
const savedEventDestinations = await Db.collections.EventDestinations.find({});
const savedEventDestinations = await Container.get(EventDestinationsRepository).find({});
if (savedEventDestinations.length > 0) {
for (const destinationData of savedEventDestinations) {
try {

View file

@ -6,7 +6,7 @@ import { Push } from '@/push';
import { Container } from 'typedi';
import { InternalHooks } from '@/InternalHooks';
import { getWorkflowHooksMain } from '@/WorkflowExecuteAdditionalData';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
export async function recoverExecutionDataFromEventLogMessages(
executionId: string,

View file

@ -6,13 +6,13 @@ import {
MessageEventBusDestinationTypeNames,
MessageEventBusDestinationOptions,
} from 'n8n-workflow';
import * as Db from '@/Db';
import { Logger } from '@/Logger';
import type { AbstractEventMessage } from '../EventMessageClasses/AbstractEventMessage';
import type { EventMessageTypes } from '../EventMessageClasses';
import type { EventMessageConfirmSource } from '../EventMessageClasses/EventMessageConfirm';
import { MessageEventBus } from '../MessageEventBus/MessageEventBus';
import type { MessageWithCallback } from '../MessageEventBus/MessageEventBus';
import { EventDestinationsRepository } from '@db/repositories/eventDestinations.repository';
export abstract class MessageEventBusDestination implements MessageEventBusDestinationOptions {
// Since you can't have static abstract functions - this just serves as a reminder that you need to implement these. Please.
@ -96,7 +96,7 @@ export abstract class MessageEventBusDestination implements MessageEventBusDesti
id: this.getId(),
destination: this.serialize(),
};
const dbResult: InsertResult = await Db.collections.EventDestinations.upsert(data, {
const dbResult: InsertResult = await Container.get(EventDestinationsRepository).upsert(data, {
skipUpdateIfNoValuesChanged: true,
conflictPaths: ['id'],
});
@ -108,7 +108,7 @@ export abstract class MessageEventBusDestination implements MessageEventBusDesti
}
static async deleteFromDb(id: string): Promise<DeleteResult> {
const dbResult = await Db.collections.EventDestinations.delete({ id });
const dbResult = await Container.get(EventDestinationsRepository).delete({ id });
return dbResult;
}

View file

@ -1,5 +1,5 @@
import { MessageEventBusDestinationTypeNames } from 'n8n-workflow';
import type { EventDestinations } from '@/databases/entities/EventDestinations';
import type { EventDestinations } from '@db/entities/EventDestinations';
import type { MessageEventBus } from '../MessageEventBus/MessageEventBus';
import type { MessageEventBusDestination } from './MessageEventBusDestination.ee';
import { MessageEventBusDestinationSentry } from './MessageEventBusDestinationSentry.ee';

View file

@ -3,7 +3,7 @@ import type { ExecutionStatus, IRun, IWorkflowBase } from 'n8n-workflow';
import type { ExecutionPayload, IExecutionDb } from '@/Interfaces';
import pick from 'lodash/pick';
import { isWorkflowIdValid } from '@/utils';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { ExecutionMetadataService } from '@/services/executionMetadata.service';
import { Logger } from '@/Logger';

View file

@ -18,11 +18,11 @@ import type { ExecutionRequest } from '@/requests';
import * as ResponseHelper from '@/ResponseHelper';
import { getSharedWorkflowIds } from '@/WorkflowHelpers';
import { WorkflowRunner } from '@/WorkflowRunner';
import * as Db from '@/Db';
import * as GenericHelpers from '@/GenericHelpers';
import { Container } from 'typedi';
import { getStatusUsingPreviousExecutionStatusMethod } from './executionHelpers';
import { ExecutionRepository } from '@db/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { Logger } from '@/Logger';
export interface IGetExecutionsQueryFilter {
@ -274,7 +274,7 @@ export class ExecutionsService {
// Loads the currently saved workflow to execute instead of the
// one saved at the time of the execution.
const workflowId = execution.workflowData.id as string;
const workflowData = (await Db.collections.Workflow.findOneBy({
const workflowData = (await Container.get(WorkflowRepository).findOneBy({
id: workflowId,
})) as IWorkflowBase;

View file

@ -1,11 +1,13 @@
import { Container } from 'typedi';
import { License } from '@/License';
import type { ILicenseReadResponse } from '@/Interfaces';
import * as Db from '@/Db';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
export class LicenseService {
static async getActiveTriggerCount(): Promise<number> {
const totalTriggerCount = await Db.collections.Workflow.sum('triggerCount', { active: true });
const totalTriggerCount = await Container.get(WorkflowRepository).sum('triggerCount', {
active: true,
});
return totalTriggerCount ?? 0;
}

View file

@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
import { assert, jsonStringify } from 'n8n-workflow';
import type { IPushDataType } from '@/Interfaces';
import { Logger } from '@/Logger';
import type { User } from '@/databases/entities/User';
import type { User } from '@db/entities/User';
/**
* Abstract class for two-way push communication.

View file

@ -13,7 +13,7 @@ import { SSEPush } from './sse.push';
import { WebSocketPush } from './websocket.push';
import type { PushResponse, SSEPushRequest, WebSocketPushRequest } from './types';
import type { IPushDataType } from '@/Interfaces';
import type { User } from '@/databases/entities/User';
import type { User } from '@db/entities/User';
const useWebSockets = config.getEnv('push.backend') === 'websocket';

View file

@ -3,7 +3,7 @@ import { Service } from 'typedi';
import { Logger } from '@/Logger';
import { AbstractPush } from './abstract.push';
import type { PushRequest, PushResponse } from './types';
import type { User } from '@/databases/entities/User';
import type { User } from '@db/entities/User';
type Connection = { req: PushRequest; res: PushResponse };

View file

@ -1,4 +1,4 @@
import type { User } from '@/databases/entities/User';
import type { User } from '@db/entities/User';
import type { Request, Response } from 'express';
import type { WebSocket } from 'ws';

View file

@ -2,7 +2,7 @@ import type WebSocket from 'ws';
import { Service } from 'typedi';
import { Logger } from '@/Logger';
import { AbstractPush } from './abstract.push';
import type { User } from '@/databases/entities/User';
import type { User } from '@db/entities/User';
function heartbeat(this: WebSocket) {
this.isAlive = true;

View file

@ -26,9 +26,9 @@ import type { Role } from '@db/entities/Role';
import type { User } from '@db/entities/User';
import type { UserManagementMailer } from '@/UserManagement/email';
import type { Variables } from '@db/entities/Variables';
import type { WorkflowEntity } from './databases/entities/WorkflowEntity';
import type { CredentialsEntity } from './databases/entities/CredentialsEntity';
import type { WorkflowHistory } from './databases/entities/WorkflowHistory';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import type { WorkflowHistory } from '@db/entities/WorkflowHistory';
export class UserUpdatePayload implements Pick<User, 'email' | 'firstName' | 'lastName'> {
@IsEmail()

View file

@ -10,8 +10,8 @@ import { InstanceSettings } from 'n8n-core';
import type { PackageDirectoryLoader } from 'n8n-core';
import { toError } from '@/utils';
import { InstalledPackagesRepository } from '@/databases/repositories/installedPackages.repository';
import type { InstalledPackages } from '@/databases/entities/InstalledPackages';
import { InstalledPackagesRepository } from '@db/repositories/installedPackages.repository';
import type { InstalledPackages } from '@db/entities/InstalledPackages';
import {
NODE_PACKAGE_PREFIX,
NPM_COMMAND_TOKENS,

View file

@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
import { Container, Service } from 'typedi';
import type { INode, IRun, IWorkflowBase } from 'n8n-workflow';
import { StatisticsNames } from '@db/entities/WorkflowStatistics';
import { WorkflowStatisticsRepository } from '@db/repositories';
import { WorkflowStatisticsRepository } from '@db/repositories/workflowStatistics.repository';
import { UserService } from '@/services/user.service';
import { Logger } from '@/Logger';
import { OwnershipService } from './ownership.service';

View file

@ -1,6 +1,6 @@
import { ExecutionMetadataRepository } from '@/databases/repositories';
import { Service } from 'typedi';
import type { ExecutionMetadata } from '@/databases/entities/ExecutionMetadata';
import { ExecutionMetadataRepository } from '@db/repositories/executionMetadata.repository';
import type { ExecutionMetadata } from '@db/entities/ExecutionMetadata';
@Service()
export class ExecutionMetadataService {

View file

@ -1,12 +1,12 @@
import { Service } from 'typedi';
import { CacheService } from './cache.service';
import { SharedWorkflowRepository } from '@/databases/repositories';
import type { User } from '@/databases/entities/User';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import type { User } from '@db/entities/User';
import { RoleService } from './role.service';
import { UserService } from './user.service';
import type { Credentials, ListQuery } from '@/requests';
import type { Role } from '@/databases/entities/Role';
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
import type { Role } from '@db/entities/Role';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
@Service()
export class OwnershipService {

View file

@ -6,9 +6,9 @@ import type { FindOptionsWhere } from 'typeorm';
import { TIME, inTest } from '@/constants';
import config from '@/config';
import { ExecutionRepository } from '@/databases/repositories';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { Logger } from '@/Logger';
import { ExecutionEntity } from '@/databases/entities/ExecutionEntity';
import { ExecutionEntity } from '@db/entities/ExecutionEntity';
@Service()
export class PruningService {

View file

@ -1,7 +1,8 @@
import { RoleRepository, SharedWorkflowRepository } from '@/databases/repositories';
import { Service } from 'typedi';
import { RoleRepository } from '@db/repositories/role.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { CacheService } from './cache.service';
import type { RoleNames, RoleScopes } from '@/databases/entities/Role';
import type { RoleNames, RoleScopes } from '@db/entities/Role';
class InvalidRoleError extends Error {}

View file

@ -1,8 +1,8 @@
import { TagRepository } from '@/databases/repositories';
import { TagRepository } from '@db/repositories/tag.repository';
import { Service } from 'typedi';
import { validateEntity } from '@/GenericHelpers';
import type { ITagToImport, ITagWithCountDb, IWorkflowToImport } from '@/Interfaces';
import type { TagEntity } from '@/databases/entities/TagEntity';
import type { TagEntity } from '@db/entities/TagEntity';
import type { EntityManager, FindManyOptions, FindOneOptions } from 'typeorm';
import type { UpsertOptions } from 'typeorm/repository/UpsertOptions';
import { ExternalHooks } from '@/ExternalHooks';

View file

@ -3,7 +3,7 @@ import type { EntityManager, FindManyOptions, FindOneOptions, FindOptionsWhere }
import { In } from 'typeorm';
import { User } from '@db/entities/User';
import type { IUserSettings } from 'n8n-workflow';
import { UserRepository } from '@/databases/repositories';
import { UserRepository } from '@db/repositories/user.repository';
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
import type { PublicUser } from '@/Interfaces';
import type { PostHogClient } from '@/posthog';

View file

@ -1,7 +1,7 @@
import { WebhookRepository } from '@/databases/repositories';
import { WebhookRepository } from '@db/repositories/webhook.repository';
import { Service } from 'typedi';
import { CacheService } from './cache.service';
import type { WebhookEntity } from '@/databases/entities/WebhookEntity';
import type { WebhookEntity } from '@db/entities/WebhookEntity';
import type { IHttpRequestMethods } from 'n8n-workflow';
import type { DeepPartial } from 'typeorm';

View file

@ -1,6 +1,5 @@
import type express from 'express';
import { Service } from 'typedi';
import * as Db from '@/Db';
import Container, { Service } from 'typedi';
import type { User } from '@db/entities/User';
import { jsonParse } from 'n8n-workflow';
import { AuthError, BadRequestError } from '@/ResponseHelper';
@ -28,6 +27,8 @@ import type { SamlLoginBinding } from './types';
import { validateMetadata, validateResponse } from './samlValidator';
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
import { Logger } from '@/Logger';
import { UserRepository } from '@db/repositories/user.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
@Service()
export class SamlService {
@ -167,7 +168,7 @@ export class SamlService {
const attributes = await this.getAttributesFromLoginResponse(req, binding);
if (attributes.email) {
const lowerCasedEmail = attributes.email.toLowerCase();
const user = await Db.collections.User.findOne({
const user = await Container.get(UserRepository).findOne({
where: { email: lowerCasedEmail },
relations: ['globalRole', 'authIdentities'],
});
@ -257,7 +258,7 @@ export class SamlService {
}
async loadFromDbAndApplySamlPreferences(apply = true): Promise<SamlPreferences | undefined> {
const samlPreferences = await Db.collections.Settings.findOne({
const samlPreferences = await Container.get(SettingsRepository).findOne({
where: { key: SAML_PREFERENCES_DB_KEY },
});
if (samlPreferences) {
@ -275,16 +276,16 @@ export class SamlService {
}
async saveSamlPreferencesToDb(): Promise<SamlPreferences | undefined> {
const samlPreferences = await Db.collections.Settings.findOne({
const samlPreferences = await Container.get(SettingsRepository).findOne({
where: { key: SAML_PREFERENCES_DB_KEY },
});
const settingsValue = JSON.stringify(this.samlPreferences);
let result: Settings;
if (samlPreferences) {
samlPreferences.value = settingsValue;
result = await Db.collections.Settings.save(samlPreferences);
result = await Container.get(SettingsRepository).save(samlPreferences);
} else {
result = await Db.collections.Settings.save({
result = await Container.get(SettingsRepository).save({
key: SAML_PREFERENCES_DB_KEY,
value: settingsValue,
loadOnStartup: true,

View file

@ -1,6 +1,5 @@
import { Container } from 'typedi';
import config from '@/config';
import * as Db from '@/Db';
import { AuthIdentity } from '@db/entities/AuthIdentity';
import { User } from '@db/entities/User';
import { License } from '@/License';
@ -20,6 +19,8 @@ import {
import { getServiceProviderConfigTestReturnUrl } from './serviceProvider.ee';
import type { SamlConfiguration } from './types/requests';
import { RoleService } from '@/services/role.service';
import { UserRepository } from '@db/repositories/user.repository';
import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository';
/**
* Check whether the SAML feature is licensed and enabled in the instance
*/
@ -107,10 +108,10 @@ export async function createUserFromSamlAttributes(attributes: SamlUserAttribute
authIdentity.providerId = attributes.userPrincipalName;
authIdentity.providerType = 'saml';
authIdentity.user = user;
const resultAuthIdentity = await Db.collections.AuthIdentity.save(authIdentity);
const resultAuthIdentity = await Container.get(AuthIdentityRepository).save(authIdentity);
if (!resultAuthIdentity) throw new AuthError('Could not create AuthIdentity');
user.authIdentities = [authIdentity];
const resultUser = await Db.collections.User.save(user);
const resultUser = await Container.get(UserRepository).save(user);
if (!resultUser) throw new AuthError('Could not create User');
return resultUser;
}
@ -131,10 +132,10 @@ export async function updateUserFromSamlAttributes(
} else {
samlAuthIdentity.providerId = attributes.userPrincipalName;
}
await Db.collections.AuthIdentity.save(samlAuthIdentity);
await Container.get(AuthIdentityRepository).save(samlAuthIdentity);
user.firstName = attributes.firstName;
user.lastName = attributes.lastName;
const resultUser = await Db.collections.User.save(user);
const resultUser = await Container.get(UserRepository).save(user);
if (!resultUser) throw new AuthError('Could not create User');
return resultUser;
}

View file

@ -1,6 +1,7 @@
import config from '@/config';
import * as Db from '@/Db';
import { SettingsRepository } from '@db/repositories/settings.repository';
import type { AuthProviderType } from '@db/entities/AuthIdentity';
import Container from 'typedi';
/**
* Only one authentication method can be active at a time. This function sets the current authentication method
@ -12,7 +13,7 @@ export async function setCurrentAuthenticationMethod(
authenticationMethod: AuthProviderType,
): Promise<void> {
config.set('userManagement.authenticationMethod', authenticationMethod);
await Db.collections.Settings.save({
await Container.get(SettingsRepository).save({
key: 'userManagement.authenticationMethod',
value: authenticationMethod,
loadOnStartup: true,

View file

@ -1,8 +1,8 @@
import type { SharedWorkflow } from '@/databases/entities/SharedWorkflow';
import type { User } from '@/databases/entities/User';
import type { WorkflowEntity } from '@/databases/entities/WorkflowEntity';
import type { WorkflowHistory } from '@/databases/entities/WorkflowHistory';
import { SharedWorkflowRepository } from '@/databases/repositories';
import type { SharedWorkflow } from '@db/entities/SharedWorkflow';
import type { User } from '@db/entities/User';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import type { WorkflowHistory } from '@db/entities/WorkflowHistory';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
import { Service } from 'typedi';
import { isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';

View file

@ -1,7 +1,7 @@
import { Service } from 'typedi';
import { LessThan } from 'typeorm';
import { DateTime } from 'luxon';
import { WorkflowHistoryRepository } from '@/databases/repositories';
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
import { WORKFLOW_HISTORY_PRUNE_INTERVAL } from './constants';
import { getWorkflowHistoryPruneTime, isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';

View file

@ -26,6 +26,7 @@ import { listQueryMiddleware } from '@/middlewares';
import { TagService } from '@/services/tag.service';
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
import { Logger } from '@/Logger';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
export const workflowsController = express.Router();
workflowsController.use('/', EEWorkflowController);
@ -205,7 +206,7 @@ workflowsController.get(
relations = relations.filter((relation) => relation !== 'workflow.tags');
}
const shared = await Db.collections.SharedWorkflow.findOne({
const shared = await Container.get(SharedWorkflowRepository).findOne({
relations,
where: whereClause({
user: req.user,

View file

@ -1,6 +1,5 @@
import type { DeleteResult, EntityManager } from 'typeorm';
import { In, Not } from 'typeorm';
import * as Db from '@/Db';
import * as ResponseHelper from '@/ResponseHelper';
import * as WorkflowHelpers from '@/WorkflowHelpers';
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
@ -16,7 +15,8 @@ import { CredentialsService } from '@/credentials/credentials.service';
import { NodeOperationError } from 'n8n-workflow';
import { RoleService } from '@/services/role.service';
import Container from 'typedi';
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
export class EEWorkflowsService extends WorkflowsService {
static async isOwned(
@ -73,7 +73,7 @@ export class EEWorkflowsService extends WorkflowsService {
userId: user.id,
roleId: role?.id,
};
acc.push(Db.collections.SharedWorkflow.create(entity));
acc.push(Container.get(SharedWorkflowRepository).create(entity));
return acc;
}, []);

View file

@ -6,7 +6,6 @@ import { In, Like } from 'typeorm';
import pick from 'lodash/pick';
import { v4 as uuid } from 'uuid';
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
import * as Db from '@/Db';
import * as ResponseHelper from '@/ResponseHelper';
import * as WorkflowHelpers from '@/WorkflowHelpers';
import config from '@/config';
@ -24,13 +23,16 @@ import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'
import { TestWebhooks } from '@/TestWebhooks';
import { whereClause } from '@/UserManagement/UserManagementHelper';
import { InternalHooks } from '@/InternalHooks';
import { WorkflowRepository } from '@/databases/repositories';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { RoleService } from '@/services/role.service';
import { OwnershipService } from '@/services/ownership.service';
import { isStringArray, isWorkflowIdValid } from '@/utils';
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
import { BinaryDataService } from 'n8n-core';
import { Logger } from '@/Logger';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { WorkflowTagMappingRepository } from '@db/repositories/workflowTagMapping.repository';
import { ExecutionRepository } from '@db/repositories/execution.repository';
export class WorkflowsService {
static async getSharing(
@ -48,7 +50,7 @@ export class WorkflowsService {
where.userId = user.id;
}
return Db.collections.SharedWorkflow.findOne({ where, relations });
return Container.get(SharedWorkflowRepository).findOne({ where, relations });
}
/**
@ -94,7 +96,10 @@ export class WorkflowsService {
}
static async get(workflow: FindOptionsWhere<WorkflowEntity>, options?: { relations: string[] }) {
return Db.collections.Workflow.findOne({ where: workflow, relations: options?.relations });
return Container.get(WorkflowRepository).findOne({
where: workflow,
relations: options?.relations,
});
}
static async getMany(sharedWorkflowIds: string[], options?: ListQuery.Options) {
@ -186,7 +191,7 @@ export class WorkflowsService {
forceSave?: boolean,
roles?: string[],
): Promise<WorkflowEntity> {
const shared = await Db.collections.SharedWorkflow.findOne({
const shared = await Container.get(SharedWorkflowRepository).findOne({
relations: ['workflow', 'role'],
where: whereClause({
user,
@ -282,7 +287,7 @@ export class WorkflowsService {
await validateEntity(workflow);
}
await Db.collections.Workflow.update(
await Container.get(WorkflowRepository).update(
workflowId,
pick(workflow, [
'name',
@ -297,8 +302,8 @@ export class WorkflowsService {
);
if (tagIds && !config.getEnv('workflowTagsDisabled')) {
await Db.collections.WorkflowTagMapping.delete({ workflowId });
await Db.collections.WorkflowTagMapping.insert(
await Container.get(WorkflowTagMappingRepository).delete({ workflowId });
await Container.get(WorkflowTagMappingRepository).insert(
tagIds.map((tagId) => ({ tagId, workflowId })),
);
}
@ -311,7 +316,7 @@ export class WorkflowsService {
// We sadly get nothing back from "update". Neither if it updated a record
// nor the new value. So query now the hopefully updated entry.
const updatedWorkflow = await Db.collections.Workflow.findOne({
const updatedWorkflow = await Container.get(WorkflowRepository).findOne({
where: { id: workflowId },
relations,
});
@ -342,7 +347,7 @@ export class WorkflowsService {
} catch (error) {
// If workflow could not be activated set it again to inactive
// and revert the versionId change so UI remains consistent
await Db.collections.Workflow.update(workflowId, {
await Container.get(WorkflowRepository).update(workflowId, {
active: false,
versionId: shared.workflow.versionId,
});
@ -447,7 +452,7 @@ export class WorkflowsService {
static async delete(user: User, workflowId: string): Promise<WorkflowEntity | undefined> {
await Container.get(ExternalHooks).run('workflow.delete', [workflowId]);
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
const sharedWorkflow = await Container.get(SharedWorkflowRepository).findOne({
relations: ['workflow', 'role'],
where: whereClause({
user,
@ -466,12 +471,14 @@ export class WorkflowsService {
await Container.get(ActiveWorkflowRunner).remove(workflowId);
}
const idsForDeletion = await Db.collections.Execution.find({
select: ['id'],
where: { workflowId },
}).then((rows) => rows.map(({ id: executionId }) => ({ workflowId, executionId })));
const idsForDeletion = await Container.get(ExecutionRepository)
.find({
select: ['id'],
where: { workflowId },
})
.then((rows) => rows.map(({ id: executionId }) => ({ workflowId, executionId })));
await Db.collections.Workflow.delete(workflowId);
await Container.get(WorkflowRepository).delete(workflowId);
await Container.get(BinaryDataService).deleteMany(idsForDeletion);
void Container.get(InternalHooks).onWorkflowDeleted(user, workflowId, false);
@ -481,7 +488,7 @@ export class WorkflowsService {
}
static async updateWorkflowTriggerCount(id: string, triggerCount: number): Promise<UpdateResult> {
const qb = Db.collections.Workflow.createQueryBuilder('workflow');
const qb = Container.get(WorkflowRepository).createQueryBuilder('workflow');
return qb
.update()
.set({
@ -527,7 +534,7 @@ export class WorkflowsService {
* @param {IDataObject} newStaticData The static data to save
*/
static async saveStaticDataById(workflowId: string, newStaticData: IDataObject): Promise<void> {
await Db.collections.Workflow.update(workflowId, {
await Container.get(WorkflowRepository).update(workflowId, {
staticData: newStaticData,
});
}

View file

@ -14,14 +14,15 @@ import { WebhookService } from '@/services/webhook.service';
import * as WebhookHelpers from '@/WebhookHelpers';
import * as AdditionalData from '@/WorkflowExecuteAdditionalData';
import { WorkflowRunner } from '@/WorkflowRunner';
import { mockInstance, setSchedulerAsLoadedNode } from './shared/utils';
import * as testDb from './shared/testDb';
import type { User } from '@/databases/entities/User';
import type { WebhookEntity } from '@/databases/entities/WebhookEntity';
import type { User } from '@db/entities/User';
import type { WebhookEntity } from '@db/entities/WebhookEntity';
import { NodeTypes } from '@/NodeTypes';
import { chooseRandomly } from './shared/random';
import { MultiMainInstancePublisher } from '@/services/orchestration/main/MultiMainInstance.publisher.ee';
import { mockInstance } from '../shared/mocking';
import { chooseRandomly } from './shared/random';
import { setSchedulerAsLoadedNode } from './shared/utils';
import * as testDb from './shared/testDb';
import { createOwner } from './shared/db/users';
import { createWorkflow } from './shared/db/workflows';

View file

@ -1,36 +1,38 @@
import type { SuperAgentTest } from 'supertest';
import { License } from '@/License';
import * as utils from '../shared/utils/';
import type { ExternalSecretsSettings, SecretsProviderState } from '@/Interfaces';
import { Cipher } from 'n8n-core';
import { SettingsRepository } from '@/databases/repositories/settings.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { Container } from 'typedi';
import { ExternalSecretsProviders } from '@/ExternalSecrets/ExternalSecretsProviders.ee';
import config from '@/config';
import { ExternalSecretsManager } from '@/ExternalSecrets/ExternalSecretsManager.ee';
import { CREDENTIAL_BLANKING_VALUE } from '@/constants';
import { jsonParse, type IDataObject } from 'n8n-workflow';
import { mock } from 'jest-mock-extended';
import { mockInstance } from '../../shared/mocking';
import { setupTestServer } from '../shared/utils';
import { createOwner, createUser } from '../shared/db/users';
import {
DummyProvider,
FailedProvider,
MockProviders,
TestFailProvider,
} from '../../shared/ExternalSecrets/utils';
import config from '@/config';
import { ExternalSecretsManager } from '@/ExternalSecrets/ExternalSecretsManager.ee';
import { CREDENTIAL_BLANKING_VALUE } from '@/constants';
import { jsonParse, type IDataObject } from 'n8n-workflow';
import { mock } from 'jest-mock-extended';
import { createOwner, createUser } from '../shared/db/users';
let authOwnerAgent: SuperAgentTest;
let authMemberAgent: SuperAgentTest;
const licenseLike = utils.mockInstance(License, {
const licenseLike = mockInstance(License, {
isExternalSecretsEnabled: jest.fn().mockReturnValue(true),
isWithinUsersLimit: jest.fn().mockReturnValue(true),
});
const mockProvidersInstance = new MockProviders();
utils.mockInstance(ExternalSecretsProviders, mockProvidersInstance);
mockInstance(ExternalSecretsProviders, mockProvidersInstance);
const testServer = utils.setupTestServer({ endpointGroups: ['externalSecrets'] });
const testServer = setupTestServer({ endpointGroups: ['externalSecrets'] });
const connectedDate = '2023-08-01T12:32:29.000Z';

View file

@ -1,11 +1,15 @@
import { v4 as uuid } from 'uuid';
import * as Db from '@/Db';
import config from '@/config';
import { audit } from '@/audit';
import { CREDENTIALS_REPORT } from '@/audit/constants';
import { getRiskSection } from './utils';
import * as testDb from '../shared/testDb';
import { generateNanoId } from '@db/utils/generators';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import Container from 'typedi';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { ExecutionDataRepository } from '@db/repositories/executionData.repository';
beforeAll(async () => {
await testDb.init();
@ -46,8 +50,8 @@ test('should report credentials not in any use', async () => {
};
await Promise.all([
Db.collections.Credentials.save(credentialDetails),
Db.collections.Workflow.save(workflowDetails),
Container.get(CredentialsRepository).save(credentialDetails),
Container.get(WorkflowRepository).save(workflowDetails),
]);
const testAudit = await audit(['credentials']);
@ -74,7 +78,7 @@ test('should report credentials not in active use', async () => {
nodesAccess: [{ nodeType: 'n8n-nodes-base.slack', date: '2022-12-21T11:23:00.561Z' }],
};
const credential = await Db.collections.Credentials.save(credentialDetails);
const credential = await Container.get(CredentialsRepository).save(credentialDetails);
const workflowDetails = {
id: generateNanoId(),
@ -93,7 +97,7 @@ test('should report credentials not in active use', async () => {
],
};
await Db.collections.Workflow.save(workflowDetails);
await Container.get(WorkflowRepository).save(workflowDetails);
const testAudit = await audit(['credentials']);
@ -119,7 +123,7 @@ test('should report credential in not recently executed workflow', async () => {
nodesAccess: [{ nodeType: 'n8n-nodes-base.slack', date: '2022-12-21T11:23:00.561Z' }],
};
const credential = await Db.collections.Credentials.save(credentialDetails);
const credential = await Container.get(CredentialsRepository).save(credentialDetails);
const workflowDetails = {
id: generateNanoId(),
@ -144,12 +148,12 @@ test('should report credential in not recently executed workflow', async () => {
],
};
const workflow = await Db.collections.Workflow.save(workflowDetails);
const workflow = await Container.get(WorkflowRepository).save(workflowDetails);
const date = new Date();
date.setDate(date.getDate() - config.getEnv('security.audit.daysAbandonedWorkflow') - 1);
const savedExecution = await Db.collections.Execution.save({
const savedExecution = await Container.get(ExecutionRepository).save({
finished: true,
mode: 'manual',
startedAt: date,
@ -157,7 +161,7 @@ test('should report credential in not recently executed workflow', async () => {
workflowId: workflow.id,
waitTill: null,
});
await Db.collections.ExecutionData.save({
await Container.get(ExecutionDataRepository).save({
execution: savedExecution,
data: '[]',
workflowData: workflow,
@ -187,7 +191,7 @@ test('should not report credentials in recently executed workflow', async () =>
nodesAccess: [{ nodeType: 'n8n-nodes-base.slack', date: '2022-12-21T11:23:00.561Z' }],
};
const credential = await Db.collections.Credentials.save(credentialDetails);
const credential = await Container.get(CredentialsRepository).save(credentialDetails);
const workflowDetails = {
id: generateNanoId(),
@ -212,12 +216,12 @@ test('should not report credentials in recently executed workflow', async () =>
],
};
const workflow = await Db.collections.Workflow.save(workflowDetails);
const workflow = await Container.get(WorkflowRepository).save(workflowDetails);
const date = new Date();
date.setDate(date.getDate() - config.getEnv('security.audit.daysAbandonedWorkflow') + 1);
const savedExecution = await Db.collections.Execution.save({
const savedExecution = await Container.get(ExecutionRepository).save({
finished: true,
mode: 'manual',
startedAt: date,
@ -226,7 +230,7 @@ test('should not report credentials in recently executed workflow', async () =>
waitTill: null,
});
await Db.collections.ExecutionData.save({
await Container.get(ExecutionDataRepository).save({
execution: savedExecution,
data: '[]',
workflowData: workflow,

View file

@ -1,5 +1,4 @@
import { v4 as uuid } from 'uuid';
import * as Db from '@/Db';
import { audit } from '@/audit';
import {
DATABASE_REPORT,
@ -9,6 +8,8 @@ import {
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
import * as testDb from '../shared/testDb';
import { generateNanoId } from '@db/utils/generators';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import Container from 'typedi';
beforeAll(async () => {
await testDb.init();
@ -50,7 +51,7 @@ test('should report expressions in queries', async () => {
],
};
return Db.collections.Workflow.save(details);
return Container.get(WorkflowRepository).save(details);
});
await Promise.all(promises);
@ -105,7 +106,7 @@ test('should report expressions in query params', async () => {
],
};
return Db.collections.Workflow.save(details);
return Container.get(WorkflowRepository).save(details);
});
await Promise.all(promises);
@ -157,7 +158,7 @@ test('should report unused query params', async () => {
],
};
return Db.collections.Workflow.save(details);
return Container.get(WorkflowRepository).save(details);
});
await Promise.all(promises);

View file

@ -1,9 +1,10 @@
import { v4 as uuid } from 'uuid';
import * as Db from '@/Db';
import { audit } from '@/audit';
import { FILESYSTEM_INTERACTION_NODE_TYPES, FILESYSTEM_REPORT } from '@/audit/constants';
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
import * as testDb from '../shared/testDb';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import Container from 'typedi';
beforeAll(async () => {
await testDb.init();
@ -26,7 +27,7 @@ test('should report filesystem interaction nodes', async () => {
);
const promises = Object.entries(map).map(async ([nodeType, nodeId]) => {
const details = Db.collections.Workflow.create({
const details = Container.get(WorkflowRepository).create({
name: 'My Test Workflow',
active: false,
connections: {},
@ -42,7 +43,7 @@ test('should report filesystem interaction nodes', async () => {
],
});
return Db.collections.Workflow.save(details);
return Container.get(WorkflowRepository).save(details);
});
await Promise.all(promises);

View file

@ -1,5 +1,4 @@
import { v4 as uuid } from 'uuid';
import * as Db from '@/Db';
import { audit } from '@/audit';
import { INSTANCE_REPORT, WEBHOOK_VALIDATOR_NODE_TYPES } from '@/audit/constants';
import {
@ -13,6 +12,8 @@ import * as testDb from '../shared/testDb';
import { toReportTitle } from '@/audit/utils';
import config from '@/config';
import { generateNanoId } from '@db/utils/generators';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import Container from 'typedi';
beforeAll(async () => {
await testDb.init();
@ -53,7 +54,7 @@ test('should report webhook lacking authentication', async () => {
],
};
await Db.collections.Workflow.save(details);
await Container.get(WorkflowRepository).save(details);
const testAudit = await audit(['instance']);
@ -97,7 +98,7 @@ test('should not report webhooks having basic or header auth', async () => {
],
};
return Db.collections.Workflow.save(details);
return Container.get(WorkflowRepository).save(details);
});
await Promise.all(promises);
@ -158,7 +159,7 @@ test('should not report webhooks validated by direct children', async () => {
},
};
return Db.collections.Workflow.save(details);
return Container.get(WorkflowRepository).save(details);
});
await Promise.all(promises);

View file

@ -1,15 +1,16 @@
import { v4 as uuid } from 'uuid';
import { Container } from 'typedi';
import * as Db from '@/Db';
import { audit } from '@/audit';
import { OFFICIAL_RISKY_NODE_TYPES, NODES_REPORT } from '@/audit/constants';
import { getRiskSection, MOCK_PACKAGE, saveManualTriggerWorkflow } from './utils';
import * as testDb from '../shared/testDb';
import { toReportTitle } from '@/audit/utils';
import { mockInstance } from '../shared/utils/';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { NodeTypes } from '@/NodeTypes';
import { CommunityPackagesService } from '@/services/communityPackages.service';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { mockInstance } from '../../shared/mocking';
import { getRiskSection, MOCK_PACKAGE, saveManualTriggerWorkflow } from './utils';
import * as testDb from '../shared/testDb';
const nodesAndCredentials = mockInstance(LoadNodesAndCredentials);
nodesAndCredentials.getCustomDirectories.mockReturnValue([]);
@ -37,7 +38,7 @@ test('should report risky official nodes', async () => {
}, {});
const promises = Object.entries(map).map(async ([nodeType, nodeId]) => {
const details = Db.collections.Workflow.create({
const details = Container.get(WorkflowRepository).create({
name: 'My Test Workflow',
active: false,
connections: {},
@ -53,7 +54,7 @@ test('should report risky official nodes', async () => {
],
});
return Db.collections.Workflow.save(details);
return Container.get(WorkflowRepository).save(details);
});
await Promise.all(promises);

Some files were not shown because too many files have changed in this diff Show more