mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
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:
parent
37dd658dc5
commit
000e76e3b4
3
.github/workflows/units-tests-reusable.yml
vendored
3
.github/workflows/units-tests-reusable.yml
vendored
|
@ -60,6 +60,9 @@ jobs:
|
||||||
- name: Test Backend
|
- name: Test Backend
|
||||||
run: pnpm test:backend
|
run: pnpm test:backend
|
||||||
|
|
||||||
|
- name: Test Nodes
|
||||||
|
run: pnpm test:nodes
|
||||||
|
|
||||||
- name: Test Frontend
|
- name: Test Frontend
|
||||||
run: pnpm test:frontend
|
run: pnpm test:frontend
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
"start:tunnel": "./packages/cli/bin/n8n start --tunnel",
|
"start:tunnel": "./packages/cli/bin/n8n start --tunnel",
|
||||||
"start:windows": "cd packages/cli/bin && n8n",
|
"start:windows": "cd packages/cli/bin && n8n",
|
||||||
"test": "turbo run test",
|
"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",
|
"test:frontend": "pnpm --filter=n8n-design-system --filter=n8n-editor-ui test",
|
||||||
"watch": "turbo run watch",
|
"watch": "turbo run watch",
|
||||||
"webhook": "./packages/cli/bin/n8n webhook",
|
"webhook": "./packages/cli/bin/n8n webhook",
|
||||||
|
|
|
@ -19,7 +19,7 @@ import type {
|
||||||
IWorkflowExecutionDataProcess,
|
IWorkflowExecutionDataProcess,
|
||||||
} from '@/Interfaces';
|
} from '@/Interfaces';
|
||||||
import { isWorkflowIdValid } from '@/utils';
|
import { isWorkflowIdValid } from '@/utils';
|
||||||
import { ExecutionRepository } from '@db/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
|
|
|
@ -33,7 +33,6 @@ import {
|
||||||
|
|
||||||
import type express from 'express';
|
import type express from 'express';
|
||||||
|
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type {
|
import type {
|
||||||
IResponseCallbackData,
|
IResponseCallbackData,
|
||||||
IWebhookManager,
|
IWebhookManager,
|
||||||
|
@ -63,7 +62,8 @@ import { webhookNotFoundErrorMessage } from './utils';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import { WebhookService } from './services/webhook.service';
|
import { WebhookService } from './services/webhook.service';
|
||||||
import { Logger } from './Logger';
|
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 config from '@/config';
|
||||||
import type { MultiMainInstancePublisher } from './services/orchestration/main/MultiMainInstance.publisher.ee';
|
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 nodeTypes: NodeTypes,
|
||||||
private readonly webhookService: WebhookService,
|
private readonly webhookService: WebhookService,
|
||||||
private readonly workflowRepository: WorkflowRepository,
|
private readonly workflowRepository: WorkflowRepository,
|
||||||
|
private readonly sharedWorkflowRepository: SharedWorkflowRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async init() {
|
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 },
|
where: { id: webhook.workflowId },
|
||||||
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
||||||
});
|
});
|
||||||
|
@ -296,7 +297,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
|
||||||
|
|
||||||
Object.assign(where, { workflowId: In(activeIds) });
|
Object.assign(where, { workflowId: In(activeIds) });
|
||||||
|
|
||||||
const sharings = await Db.collections.SharedWorkflow.find({
|
const sharings = await this.sharedWorkflowRepository.find({
|
||||||
select: ['workflowId'],
|
select: ['workflowId'],
|
||||||
where,
|
where,
|
||||||
});
|
});
|
||||||
|
@ -416,7 +417,7 @@ export class ActiveWorkflowRunner implements IWebhookManager {
|
||||||
* Clear workflow-defined webhooks from the `webhook_entity` table.
|
* Clear workflow-defined webhooks from the `webhook_entity` table.
|
||||||
*/
|
*/
|
||||||
async clearWebhooks(workflowId: string) {
|
async clearWebhooks(workflowId: string) {
|
||||||
const workflowData = await Db.collections.Workflow.findOne({
|
const workflowData = await this.workflowRepository.findOne({
|
||||||
where: { id: workflowId },
|
where: { id: workflowId },
|
||||||
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -43,7 +43,6 @@ import {
|
||||||
ErrorReporterProxy as ErrorReporter,
|
ErrorReporterProxy as ErrorReporter,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { ICredentialsDb } from '@/Interfaces';
|
import type { ICredentialsDb } from '@/Interfaces';
|
||||||
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
|
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
|
@ -54,6 +53,8 @@ import { CredentialsOverwrites } from '@/CredentialsOverwrites';
|
||||||
import { RESPONSE_ERROR_MESSAGES } from './constants';
|
import { RESPONSE_ERROR_MESSAGES } from './constants';
|
||||||
import { isObjectLiteral } from './utils';
|
import { isObjectLiteral } from './utils';
|
||||||
import { Logger } from '@/Logger';
|
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;
|
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 credentialTypes: CredentialTypes,
|
||||||
private readonly nodeTypes: NodeTypes,
|
private readonly nodeTypes: NodeTypes,
|
||||||
private readonly credentialsOverwrites: CredentialsOverwrites,
|
private readonly credentialsOverwrites: CredentialsOverwrites,
|
||||||
|
private readonly credentialsRepository: CredentialsRepository,
|
||||||
|
private readonly sharedCredentialsRepository: SharedCredentialsRepository,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -271,11 +274,13 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
credential = userId
|
credential = userId
|
||||||
? await Db.collections.SharedCredentials.findOneOrFail({
|
? await this.sharedCredentialsRepository
|
||||||
relations: ['credentials'],
|
.findOneOrFail({
|
||||||
where: { credentials: { id: nodeCredential.id, type }, userId },
|
relations: ['credentials'],
|
||||||
}).then((shared) => shared.credentials)
|
where: { credentials: { id: nodeCredential.id, type }, userId },
|
||||||
: await Db.collections.Credentials.findOneByOrFail({ id: nodeCredential.id, type });
|
})
|
||||||
|
.then((shared) => shared.credentials)
|
||||||
|
: await this.credentialsRepository.findOneByOrFail({ id: nodeCredential.id, type });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new CredentialNotFoundError(nodeCredential.id, type);
|
throw new CredentialNotFoundError(nodeCredential.id, type);
|
||||||
}
|
}
|
||||||
|
@ -463,7 +468,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||||
type,
|
type,
|
||||||
};
|
};
|
||||||
|
|
||||||
await Db.collections.Credentials.update(findQuery, newCredentialsData);
|
await this.credentialsRepository.update(findQuery, newCredentialsData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static hasAccessToken(credentialsDecrypted: ICredentialsDecrypted) {
|
private static hasAccessToken(credentialsDecrypted: ICredentialsDecrypted) {
|
||||||
|
@ -774,7 +779,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const credential = await Db.collections.SharedCredentials.findOne({
|
const credential = await this.sharedCredentialsRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
role: {
|
role: {
|
||||||
scope: 'credential',
|
scope: 'credential',
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||||
|
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import type { DataSourceOptions as ConnectionOptions, EntityManager, LoggerOptions } from 'typeorm';
|
import type { DataSourceOptions as ConnectionOptions, EntityManager, LoggerOptions } from 'typeorm';
|
||||||
import { DataSource as Connection } from 'typeorm';
|
import { DataSource as Connection } from 'typeorm';
|
||||||
import type { TlsOptions } from 'tls';
|
import type { TlsOptions } from 'tls';
|
||||||
import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow';
|
import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow';
|
||||||
|
|
||||||
import type { IDatabaseCollections } from '@/Interfaces';
|
|
||||||
|
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
|
||||||
import { entities } from '@db/entities';
|
import { entities } from '@db/entities';
|
||||||
|
@ -21,28 +18,6 @@ import {
|
||||||
import { inTest } from '@/constants';
|
import { inTest } from '@/constants';
|
||||||
import { wrapMigration } from '@db/utils/migrationHelpers';
|
import { wrapMigration } from '@db/utils/migrationHelpers';
|
||||||
import type { DatabaseType, Migration } from '@db/types';
|
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;
|
let connection: Connection;
|
||||||
|
|
||||||
|
@ -165,32 +140,6 @@ export async function init(testConnectionOptions?: ConnectionOptions): Promise<v
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionState.connected = true;
|
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() {
|
export async function migrate() {
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type {
|
import type {
|
||||||
IExternalHooksClass,
|
IExternalHooksClass,
|
||||||
IExternalHooksFileData,
|
IExternalHooksFileData,
|
||||||
IExternalHooksFunctions,
|
IExternalHooksFunctions,
|
||||||
} from '@/Interfaces';
|
} from '@/Interfaces';
|
||||||
|
|
||||||
import config from '@/config';
|
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()
|
@Service()
|
||||||
export class ExternalHooks implements IExternalHooksClass {
|
export class ExternalHooks implements IExternalHooksClass {
|
||||||
|
@ -16,7 +17,25 @@ export class ExternalHooks implements IExternalHooksClass {
|
||||||
[key: string]: Array<() => {}>;
|
[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> {
|
async init(): Promise<void> {
|
||||||
if (this.initDidRun) {
|
if (this.initDidRun) {
|
||||||
|
@ -83,14 +102,14 @@ export class ExternalHooks implements IExternalHooksClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(hookName: string, hookParameters?: any[]): Promise<void> {
|
async run(hookName: string, hookParameters?: any[]): Promise<void> {
|
||||||
const externalHookFunctions: IExternalHooksFunctions = {
|
|
||||||
dbCollections: Db.collections,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.externalHooks[hookName] === undefined) {
|
if (this.externalHooks[hookName] === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const externalHookFunctions: IExternalHooksFunctions = {
|
||||||
|
dbCollections: this.dbCollections,
|
||||||
|
};
|
||||||
|
|
||||||
for (const externalHookFunction of this.externalHooks[hookName]) {
|
for (const externalHookFunction of this.externalHooks[hookName]) {
|
||||||
await externalHookFunction.apply(externalHookFunctions, hookParameters);
|
await externalHookFunction.apply(externalHookFunctions, hookParameters);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { SettingsRepository } from '@/databases/repositories';
|
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||||
import type {
|
import type {
|
||||||
ExternalSecretsSettings,
|
ExternalSecretsSettings,
|
||||||
SecretsProvider,
|
SecretsProvider,
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { validate } from 'class-validator';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { Like } from 'typeorm';
|
import { Like } from 'typeorm';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { ExecutionPayload, ICredentialsDb, IWorkflowDb } from '@/Interfaces';
|
import type { ExecutionPayload, ICredentialsDb, IWorkflowDb } from '@/Interfaces';
|
||||||
import * as ResponseHelper from '@/ResponseHelper';
|
import * as ResponseHelper from '@/ResponseHelper';
|
||||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
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 { TagEntity } from '@db/entities/TagEntity';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import type { UserUpdatePayload } from '@/requests';
|
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
|
* Returns the base URL n8n is reachable from
|
||||||
|
@ -64,8 +65,8 @@ export async function generateUniqueName(
|
||||||
|
|
||||||
const found: Array<WorkflowEntity | ICredentialsDb> =
|
const found: Array<WorkflowEntity | ICredentialsDb> =
|
||||||
entityType === 'workflow'
|
entityType === 'workflow'
|
||||||
? await Db.collections.Workflow.find(findConditions)
|
? await Container.get(WorkflowRepository).find(findConditions)
|
||||||
: await Db.collections.Credentials.find(findConditions);
|
: await Container.get(CredentialsRepository).find(findConditions);
|
||||||
|
|
||||||
// name is unique
|
// name is unique
|
||||||
if (found.length === 0) {
|
if (found.length === 0) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ import type { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||||
import type { WorkflowExecute } from 'n8n-core';
|
import type { WorkflowExecute } from 'n8n-core';
|
||||||
|
|
||||||
import type PCancelable from 'p-cancelable';
|
import type PCancelable from 'p-cancelable';
|
||||||
import type { FindOperator, Repository } from 'typeorm';
|
import type { FindOperator } from 'typeorm';
|
||||||
|
|
||||||
import type { ChildProcess } from 'child_process';
|
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 { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||||
import type { TagEntity } from '@db/entities/TagEntity';
|
import type { TagEntity } from '@db/entities/TagEntity';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import type {
|
import type { CredentialsRepository } from '@db/repositories/credentials.repository';
|
||||||
AuthIdentityRepository,
|
import type { SettingsRepository } from '@db/repositories/settings.repository';
|
||||||
AuthProviderSyncHistoryRepository,
|
import type { UserRepository } from '@db/repositories/user.repository';
|
||||||
CredentialsRepository,
|
import type { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
EventDestinationsRepository,
|
|
||||||
ExecutionDataRepository,
|
|
||||||
ExecutionMetadataRepository,
|
|
||||||
ExecutionRepository,
|
|
||||||
InstalledNodesRepository,
|
|
||||||
InstalledPackagesRepository,
|
|
||||||
RoleRepository,
|
|
||||||
SettingsRepository,
|
|
||||||
SharedCredentialsRepository,
|
|
||||||
SharedWorkflowRepository,
|
|
||||||
UserRepository,
|
|
||||||
VariablesRepository,
|
|
||||||
WorkflowRepository,
|
|
||||||
WorkflowStatisticsRepository,
|
|
||||||
WorkflowTagMappingRepository,
|
|
||||||
} from '@db/repositories';
|
|
||||||
import type { LICENSE_FEATURES, LICENSE_QUOTAS } from './constants';
|
import type { LICENSE_FEATURES, LICENSE_QUOTAS } from './constants';
|
||||||
import type { WorkflowWithSharingsAndCredentials } from './workflows/workflows.types';
|
import type { WorkflowWithSharingsAndCredentials } from './workflows/workflows.types';
|
||||||
|
|
||||||
|
@ -71,33 +55,6 @@ export interface ICredentialsOverwrite {
|
||||||
[key: string]: ICredentialDataDecryptedObject;
|
[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
|
// tags
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
@ -285,7 +242,14 @@ export interface IExternalHooksFileData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IExternalHooksFunctions {
|
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 {
|
export interface IExternalHooksClass {
|
||||||
|
|
|
@ -32,6 +32,10 @@ import {
|
||||||
import { BadRequestError, InternalServerError } from '../ResponseHelper';
|
import { BadRequestError, InternalServerError } from '../ResponseHelper';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import { Logger } from '@/Logger';
|
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
|
* 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
|
* Retrieve the LDAP configuration (decrypted) form the database
|
||||||
*/
|
*/
|
||||||
export const getLdapConfig = async (): Promise<LdapConfig> => {
|
export const getLdapConfig = async (): Promise<LdapConfig> => {
|
||||||
const configuration = await Db.collections.Settings.findOneByOrFail({
|
const configuration = await Container.get(SettingsRepository).findOneByOrFail({
|
||||||
key: LDAP_FEATURE_NAME,
|
key: LDAP_FEATURE_NAME,
|
||||||
});
|
});
|
||||||
const configurationData = jsonParse<LdapConfig>(configuration.value);
|
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 },
|
{ key: LDAP_FEATURE_NAME },
|
||||||
{ value: JSON.stringify(ldapConfig), loadOnStartup: true },
|
{ value: JSON.stringify(ldapConfig), loadOnStartup: true },
|
||||||
);
|
);
|
||||||
|
@ -284,7 +288,7 @@ export const findAndAuthenticateLdapUser = async (
|
||||||
export const getAuthIdentityByLdapId = async (
|
export const getAuthIdentityByLdapId = async (
|
||||||
idAttributeValue: string,
|
idAttributeValue: string,
|
||||||
): Promise<AuthIdentity | null> => {
|
): Promise<AuthIdentity | null> => {
|
||||||
return Db.collections.AuthIdentity.findOne({
|
return Container.get(AuthIdentityRepository).findOne({
|
||||||
relations: ['user', 'user.globalRole'],
|
relations: ['user', 'user.globalRole'],
|
||||||
where: {
|
where: {
|
||||||
providerId: idAttributeValue,
|
providerId: idAttributeValue,
|
||||||
|
@ -294,7 +298,7 @@ export const getAuthIdentityByLdapId = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserByEmail = async (email: string): Promise<User | null> => {
|
export const getUserByEmail = async (email: string): Promise<User | null> => {
|
||||||
return Db.collections.User.findOne({
|
return Container.get(UserRepository).findOne({
|
||||||
where: { email },
|
where: { email },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
});
|
});
|
||||||
|
@ -322,7 +326,7 @@ export const mapLdapAttributesToUser = (
|
||||||
* Retrieve LDAP ID of all LDAP users in the database
|
* Retrieve LDAP ID of all LDAP users in the database
|
||||||
*/
|
*/
|
||||||
export const getLdapIds = async (): Promise<string[]> => {
|
export const getLdapIds = async (): Promise<string[]> => {
|
||||||
const identities = await Db.collections.AuthIdentity.find({
|
const identities = await Container.get(AuthIdentityRepository).find({
|
||||||
select: ['providerId'],
|
select: ['providerId'],
|
||||||
where: {
|
where: {
|
||||||
providerType: 'ldap',
|
providerType: 'ldap',
|
||||||
|
@ -332,7 +336,7 @@ export const getLdapIds = async (): Promise<string[]> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getLdapUsers = async (): Promise<User[]> => {
|
export const getLdapUsers = async (): Promise<User[]> => {
|
||||||
const identities = await Db.collections.AuthIdentity.find({
|
const identities = await Container.get(AuthIdentityRepository).find({
|
||||||
relations: ['user'],
|
relations: ['user'],
|
||||||
where: {
|
where: {
|
||||||
providerType: 'ldap',
|
providerType: 'ldap',
|
||||||
|
@ -409,7 +413,7 @@ export const processUsers = async (
|
||||||
export const saveLdapSynchronization = async (
|
export const saveLdapSynchronization = async (
|
||||||
data: Omit<AuthProviderSyncHistory, 'id' | 'providerType'>,
|
data: Omit<AuthProviderSyncHistory, 'id' | 'providerType'>,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
await Db.collections.AuthProviderSyncHistory.save({
|
await Container.get(AuthProviderSyncHistoryRepository).save({
|
||||||
...data,
|
...data,
|
||||||
providerType: 'ldap',
|
providerType: 'ldap',
|
||||||
});
|
});
|
||||||
|
@ -423,7 +427,7 @@ export const getLdapSynchronizations = async (
|
||||||
perPage: number,
|
perPage: number,
|
||||||
): Promise<AuthProviderSyncHistory[]> => {
|
): Promise<AuthProviderSyncHistory[]> => {
|
||||||
const _page = Math.abs(page);
|
const _page = Math.abs(page);
|
||||||
return Db.collections.AuthProviderSyncHistory.find({
|
return Container.get(AuthProviderSyncHistoryRepository).find({
|
||||||
where: { providerType: 'ldap' },
|
where: { providerType: 'ldap' },
|
||||||
order: { id: 'DESC' },
|
order: { id: 'DESC' },
|
||||||
take: perPage,
|
take: perPage,
|
||||||
|
@ -450,11 +454,11 @@ export const getMappingAttributes = (ldapConfig: LdapConfig): string[] => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createLdapAuthIdentity = async (user: User, ldapId: 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) => {
|
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(),
|
password: randomPassword(),
|
||||||
globalRole: role,
|
globalRole: role,
|
||||||
...data,
|
...data,
|
||||||
|
@ -466,10 +470,10 @@ export const createLdapUserOnLocalDb = async (role: Role, data: Partial<User>, l
|
||||||
export const updateLdapUserOnLocalDb = async (identity: AuthIdentity, data: Partial<User>) => {
|
export const updateLdapUserOnLocalDb = async (identity: AuthIdentity, data: Partial<User>) => {
|
||||||
const userId = identity?.user?.id;
|
const userId = identity?.user?.id;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
await Db.collections.User.update({ id: userId }, data);
|
await Container.get(UserRepository).update({ id: userId }, data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteAllLdapIdentities = async () => {
|
const deleteAllLdapIdentities = async () => {
|
||||||
return Db.collections.AuthIdentity.delete({ providerType: 'ldap' });
|
return Container.get(AuthIdentityRepository).delete({ providerType: 'ldap' });
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { InstanceSettings, ObjectStoreService } from 'n8n-core';
|
||||||
import Container, { Service } from 'typedi';
|
import Container, { Service } from 'typedi';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import {
|
import {
|
||||||
LICENSE_FEATURES,
|
LICENSE_FEATURES,
|
||||||
LICENSE_QUOTAS,
|
LICENSE_QUOTAS,
|
||||||
|
@ -12,7 +11,8 @@ import {
|
||||||
SETTINGS_LICENSE_CERT_KEY,
|
SETTINGS_LICENSE_CERT_KEY,
|
||||||
UNLIMITED_LICENSE_QUOTA,
|
UNLIMITED_LICENSE_QUOTA,
|
||||||
} from './constants';
|
} 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 { BooleanLicenseFeature, N8nInstanceType, NumericLicenseFeature } from './Interfaces';
|
||||||
import type { RedisServicePubSubPublisher } from './services/redis/RedisServicePubSubPublisher';
|
import type { RedisServicePubSubPublisher } from './services/redis/RedisServicePubSubPublisher';
|
||||||
import { RedisService } from './services/redis.service';
|
import { RedisService } from './services/redis.service';
|
||||||
|
@ -40,6 +40,8 @@ export class License {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly logger: Logger,
|
private readonly logger: Logger,
|
||||||
private readonly instanceSettings: InstanceSettings,
|
private readonly instanceSettings: InstanceSettings,
|
||||||
|
private readonly settingsRepository: SettingsRepository,
|
||||||
|
private readonly workflowRepository: WorkflowRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async init(instanceType: N8nInstanceType = 'main') {
|
async init(instanceType: N8nInstanceType = 'main') {
|
||||||
|
@ -91,7 +93,7 @@ export class License {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'activeWorkflows',
|
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) {
|
if (ephemeralLicense) {
|
||||||
return ephemeralLicense;
|
return ephemeralLicense;
|
||||||
}
|
}
|
||||||
const databaseSettings = await Db.collections.Settings.findOne({
|
const databaseSettings = await this.settingsRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
key: SETTINGS_LICENSE_CERT_KEY,
|
key: SETTINGS_LICENSE_CERT_KEY,
|
||||||
},
|
},
|
||||||
|
@ -153,7 +155,7 @@ export class License {
|
||||||
async saveCertStr(value: TLicenseBlock): Promise<void> {
|
async saveCertStr(value: TLicenseBlock): Promise<void> {
|
||||||
// if we have an ephemeral license, we don't want to save it to the database
|
// if we have an ephemeral license, we don't want to save it to the database
|
||||||
if (config.get('license.cert')) return;
|
if (config.get('license.cert')) return;
|
||||||
await Db.collections.Settings.upsert(
|
await this.settingsRepository.upsert(
|
||||||
{
|
{
|
||||||
key: SETTINGS_LICENSE_CERT_KEY,
|
key: SETTINGS_LICENSE_CERT_KEY,
|
||||||
value,
|
value,
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
|
import Container from 'typedi';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { MFA_FEATURE_ENABLED } from './constants';
|
import { MFA_FEATURE_ENABLED } from './constants';
|
||||||
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
|
|
||||||
export const isMfaFeatureEnabled = () => config.get(MFA_FEATURE_ENABLED);
|
export const isMfaFeatureEnabled = () => config.get(MFA_FEATURE_ENABLED);
|
||||||
|
|
||||||
const isMfaFeatureDisabled = () => !isMfaFeatureEnabled();
|
const isMfaFeatureDisabled = () => !isMfaFeatureEnabled();
|
||||||
|
|
||||||
const getUsersWithMfaEnabled = async () =>
|
const getUsersWithMfaEnabled = async () =>
|
||||||
Db.collections.User.count({ where: { mfaEnabled: true } });
|
Container.get(UserRepository).count({ where: { mfaEnabled: true } });
|
||||||
|
|
||||||
export const handleMfaDisable = async () => {
|
export const handleMfaDisable = async () => {
|
||||||
if (isMfaFeatureDisabled()) {
|
if (isMfaFeatureDisabled()) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { Cipher } from 'n8n-core';
|
import { Cipher } from 'n8n-core';
|
||||||
import { UserRepository } from '@db/repositories';
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
import { TOTPService } from './totp.service';
|
import { TOTPService } from './totp.service';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
|
|
|
@ -11,11 +11,11 @@ import type { OpenAPIV3 } from 'openapi-types';
|
||||||
import type { JsonObject } from 'swagger-ui-express';
|
import type { JsonObject } from 'swagger-ui-express';
|
||||||
|
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
|
|
||||||
async function createApiRouter(
|
async function createApiRouter(
|
||||||
version: string,
|
version: string,
|
||||||
|
@ -95,7 +95,7 @@ async function createApiRouter(
|
||||||
schema: OpenAPIV3.ApiKeySecurityScheme,
|
schema: OpenAPIV3.ApiKeySecurityScheme,
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
const apiKey = req.headers[schema.name.toLowerCase()] as string;
|
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 },
|
where: { apiKey },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,9 +10,11 @@ import type { IDependency, IJsonSchema } from '../../../types';
|
||||||
import type { CredentialRequest } from '@/requests';
|
import type { CredentialRequest } from '@/requests';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { RoleService } from '@/services/role.service';
|
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> {
|
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(
|
export async function getSharedCredentials(
|
||||||
|
@ -20,7 +22,7 @@ export async function getSharedCredentials(
|
||||||
credentialId: string,
|
credentialId: string,
|
||||||
relations?: string[],
|
relations?: string[],
|
||||||
): Promise<SharedCredentials | null> {
|
): Promise<SharedCredentials | null> {
|
||||||
return Db.collections.SharedCredentials.findOne({
|
return Container.get(SharedCredentialsRepository).findOne({
|
||||||
where: {
|
where: {
|
||||||
userId,
|
userId,
|
||||||
credentialsId: credentialId,
|
credentialsId: credentialId,
|
||||||
|
@ -83,7 +85,7 @@ export async function saveCredential(
|
||||||
|
|
||||||
export async function removeCredential(credentials: CredentialsEntity): Promise<ICredentialsDb> {
|
export async function removeCredential(credentials: CredentialsEntity): Promise<ICredentialsDb> {
|
||||||
await Container.get(ExternalHooks).run('credentials.delete', [credentials.id]);
|
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> {
|
export async function encryptCredential(credential: CredentialsEntity): Promise<ICredentialsDb> {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { getSharedWorkflowIds } from '../workflows/workflows.service';
|
||||||
import { encodeNextCursor } from '../../shared/services/pagination.service';
|
import { encodeNextCursor } from '../../shared/services/pagination.service';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import { ExecutionRepository } from '@/databases/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
|
|
||||||
export = {
|
export = {
|
||||||
deleteExecution: [
|
deleteExecution: [
|
||||||
|
|
|
@ -3,9 +3,8 @@ import { In, Not, Raw, LessThan } from 'typeorm';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import type { ExecutionStatus } from 'n8n-workflow';
|
import type { ExecutionStatus } from 'n8n-workflow';
|
||||||
|
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { IExecutionBase, IExecutionFlattedDb } from '@/Interfaces';
|
import type { IExecutionBase, IExecutionFlattedDb } from '@/Interfaces';
|
||||||
import { ExecutionRepository } from '@db/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
|
|
||||||
function getStatusCondition(status: ExecutionStatus) {
|
function getStatusCondition(status: ExecutionStatus) {
|
||||||
const condition: Pick<FindOptionsWhere<IExecutionFlattedDb>, 'status'> = {};
|
const condition: Pick<FindOptionsWhere<IExecutionFlattedDb>, 'status'> = {};
|
||||||
|
@ -83,7 +82,7 @@ export async function getExecutionsCount(data: {
|
||||||
excludedWorkflowIds?: string[];
|
excludedWorkflowIds?: string[];
|
||||||
}): Promise<number> {
|
}): Promise<number> {
|
||||||
// TODO: Consider moving this to the repository as well
|
// TODO: Consider moving this to the repository as well
|
||||||
const executions = await Db.collections.Execution.count({
|
const executions = await Container.get(ExecutionRepository).count({
|
||||||
where: {
|
where: {
|
||||||
...(data.lastId && { id: LessThan(data.lastId) }),
|
...(data.lastId && { id: LessThan(data.lastId) }),
|
||||||
...(data.status && { ...getStatusCondition(data.status) }),
|
...(data.status && { ...getStatusCondition(data.status) }),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { UserRepository } from '@db/repositories';
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import pick from 'lodash/pick';
|
import pick from 'lodash/pick';
|
||||||
import { validate as uuidValidate } from 'uuid';
|
import { validate as uuidValidate } from 'uuid';
|
||||||
|
|
|
@ -10,6 +10,8 @@ import type { Role } from '@db/entities/Role';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { TagService } from '@/services/tag.service';
|
import { TagService } from '@/services/tag.service';
|
||||||
import Container from 'typedi';
|
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[] {
|
function insertIf(condition: boolean, elements: string[]): string[] {
|
||||||
return condition ? elements : [];
|
return condition ? elements : [];
|
||||||
|
@ -17,7 +19,7 @@ function insertIf(condition: boolean, elements: string[]): string[] {
|
||||||
|
|
||||||
export async function getSharedWorkflowIds(user: User): Promise<string[]> {
|
export async function getSharedWorkflowIds(user: User): Promise<string[]> {
|
||||||
const where = user.globalRole.name === 'owner' ? {} : { userId: user.id };
|
const where = user.globalRole.name === 'owner' ? {} : { userId: user.id };
|
||||||
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
const sharedWorkflows = await Container.get(SharedWorkflowRepository).find({
|
||||||
where,
|
where,
|
||||||
select: ['workflowId'],
|
select: ['workflowId'],
|
||||||
});
|
});
|
||||||
|
@ -28,7 +30,7 @@ export async function getSharedWorkflow(
|
||||||
user: User,
|
user: User,
|
||||||
workflowId?: string | undefined,
|
workflowId?: string | undefined,
|
||||||
): Promise<SharedWorkflow | null> {
|
): Promise<SharedWorkflow | null> {
|
||||||
return Db.collections.SharedWorkflow.findOne({
|
return Container.get(SharedWorkflowRepository).findOne({
|
||||||
where: {
|
where: {
|
||||||
...(!user.isOwner && { userId: user.id }),
|
...(!user.isOwner && { userId: user.id }),
|
||||||
...(workflowId && { workflowId }),
|
...(workflowId && { workflowId }),
|
||||||
|
@ -44,7 +46,7 @@ export async function getSharedWorkflows(
|
||||||
workflowIds?: string[];
|
workflowIds?: string[];
|
||||||
},
|
},
|
||||||
): Promise<SharedWorkflow[]> {
|
): Promise<SharedWorkflow[]> {
|
||||||
return Db.collections.SharedWorkflow.find({
|
return Container.get(SharedWorkflowRepository).find({
|
||||||
where: {
|
where: {
|
||||||
...(!user.isOwner && { userId: user.id }),
|
...(!user.isOwner && { userId: user.id }),
|
||||||
...(options.workflowIds && { workflowId: In(options.workflowIds) }),
|
...(options.workflowIds && { workflowId: In(options.workflowIds) }),
|
||||||
|
@ -54,7 +56,7 @@ export async function getSharedWorkflows(
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getWorkflowById(id: string): Promise<WorkflowEntity | null> {
|
export async function getWorkflowById(id: string): Promise<WorkflowEntity | null> {
|
||||||
return Db.collections.Workflow.findOne({
|
return Container.get(WorkflowRepository).findOne({
|
||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -97,28 +99,34 @@ export async function createWorkflow(
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setWorkflowAsActive(workflow: WorkflowEntity): Promise<UpdateResult> {
|
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> {
|
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> {
|
export async function deleteWorkflow(workflow: WorkflowEntity): Promise<WorkflowEntity> {
|
||||||
return Db.collections.Workflow.remove(workflow);
|
return Container.get(WorkflowRepository).remove(workflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getWorkflowsAndCount(
|
export async function getWorkflowsAndCount(
|
||||||
options: FindManyOptions<WorkflowEntity>,
|
options: FindManyOptions<WorkflowEntity>,
|
||||||
): Promise<[WorkflowEntity[], number]> {
|
): Promise<[WorkflowEntity[], number]> {
|
||||||
return Db.collections.Workflow.findAndCount(options);
|
return Container.get(WorkflowRepository).findAndCount(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateWorkflow(
|
export async function updateWorkflow(
|
||||||
workflowId: string,
|
workflowId: string,
|
||||||
updateData: WorkflowEntity,
|
updateData: WorkflowEntity,
|
||||||
): Promise<UpdateResult> {
|
): Promise<UpdateResult> {
|
||||||
return Db.collections.Workflow.update(workflowId, updateData);
|
return Container.get(WorkflowRepository).update(workflowId, updateData);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseTagNames(tags: string): string[] {
|
export function parseTagNames(tags: string): string[] {
|
||||||
|
|
|
@ -85,7 +85,6 @@ import { executionsController } from '@/executions/executions.controller';
|
||||||
import { isApiEnabled, loadPublicApiVersions } from '@/PublicApi';
|
import { isApiEnabled, loadPublicApiVersions } from '@/PublicApi';
|
||||||
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
||||||
import { UserManagementMailer } from '@/UserManagement/email';
|
import { UserManagementMailer } from '@/UserManagement/email';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { ICredentialsOverwrite, IDiagnosticInfo, IExecutionsStopData } from '@/Interfaces';
|
import type { ICredentialsOverwrite, IDiagnosticInfo, IExecutionsStopData } from '@/Interfaces';
|
||||||
import { ActiveExecutions } from '@/ActiveExecutions';
|
import { ActiveExecutions } from '@/ActiveExecutions';
|
||||||
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
|
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
|
||||||
|
@ -119,8 +118,14 @@ import {
|
||||||
} from './sso/ssoHelpers';
|
} from './sso/ssoHelpers';
|
||||||
import { SourceControlService } from '@/environments/sourceControl/sourceControl.service.ee';
|
import { SourceControlService } from '@/environments/sourceControl/sourceControl.service.ee';
|
||||||
import { SourceControlController } from '@/environments/sourceControl/sourceControl.controller.ee';
|
import { SourceControlController } from '@/environments/sourceControl/sourceControl.controller.ee';
|
||||||
import { ExecutionRepository, SettingsRepository } from '@db/repositories';
|
|
||||||
import type { ExecutionEntity } from '@db/entities/ExecutionEntity';
|
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 { MfaService } from './Mfa/mfa.service';
|
||||||
import { handleMfaDisable, isMfaFeatureEnabled } from './Mfa/helpers';
|
import { handleMfaDisable, isMfaFeatureEnabled } from './Mfa/helpers';
|
||||||
import type { FrontendService } from './services/frontend.service';
|
import type { FrontendService } from './services/frontend.service';
|
||||||
|
@ -236,18 +241,19 @@ export class Server extends AbstractServer {
|
||||||
void this.loadNodesAndCredentials.setupHotReload();
|
void this.loadNodesAndCredentials.setupHotReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Db.collections.Workflow.findOne({
|
void Container.get(WorkflowRepository)
|
||||||
select: ['createdAt'],
|
.findOne({
|
||||||
order: { createdAt: 'ASC' },
|
select: ['createdAt'],
|
||||||
where: {},
|
order: { createdAt: 'ASC' },
|
||||||
}).then(async (workflow) =>
|
where: {},
|
||||||
Container.get(InternalHooks).onServerStarted(diagnosticInfo, workflow?.createdAt),
|
})
|
||||||
);
|
.then(async (workflow) =>
|
||||||
|
Container.get(InternalHooks).onServerStarted(diagnosticInfo, workflow?.createdAt),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async registerControllers(ignoredEndpoints: Readonly<string[]>) {
|
private async registerControllers(ignoredEndpoints: Readonly<string[]>) {
|
||||||
const { app, externalHooks, activeWorkflowRunner, nodeTypes, logger } = this;
|
const { app, externalHooks, activeWorkflowRunner, nodeTypes, logger } = this;
|
||||||
const repositories = Db.collections;
|
|
||||||
setupAuthMiddlewares(app, ignoredEndpoints, this.restEndpoint);
|
setupAuthMiddlewares(app, ignoredEndpoints, this.restEndpoint);
|
||||||
|
|
||||||
const internalHooks = Container.get(InternalHooks);
|
const internalHooks = Container.get(InternalHooks);
|
||||||
|
@ -281,8 +287,8 @@ export class Server extends AbstractServer {
|
||||||
logger,
|
logger,
|
||||||
externalHooks,
|
externalHooks,
|
||||||
internalHooks,
|
internalHooks,
|
||||||
repositories.SharedCredentials,
|
Container.get(SharedCredentialsRepository),
|
||||||
repositories.SharedWorkflow,
|
Container.get(SharedWorkflowRepository),
|
||||||
activeWorkflowRunner,
|
activeWorkflowRunner,
|
||||||
mailer,
|
mailer,
|
||||||
jwtService,
|
jwtService,
|
||||||
|
@ -623,7 +629,7 @@ export class Server extends AbstractServer {
|
||||||
ResponseHelper.send(async (req: WorkflowRequest.GetAllActivationErrors) => {
|
ResponseHelper.send(async (req: WorkflowRequest.GetAllActivationErrors) => {
|
||||||
const { id: workflowId } = req.params;
|
const { id: workflowId } = req.params;
|
||||||
|
|
||||||
const shared = await Db.collections.SharedWorkflow.findOne({
|
const shared = await Container.get(SharedWorkflowRepository).findOne({
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
where: whereClause({
|
where: whereClause({
|
||||||
user: req.user,
|
user: req.user,
|
||||||
|
|
|
@ -2,13 +2,15 @@ import type { INode, Workflow } from 'n8n-workflow';
|
||||||
import { NodeOperationError, SubworkflowOperationError } from 'n8n-workflow';
|
import { NodeOperationError, SubworkflowOperationError } from 'n8n-workflow';
|
||||||
import type { FindOptionsWhere } from 'typeorm';
|
import type { FindOptionsWhere } from 'typeorm';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import type { SharedCredentials } from '@db/entities/SharedCredentials';
|
import type { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||||
import { isSharingEnabled } from './UserManagementHelper';
|
import { isSharingEnabled } from './UserManagementHelper';
|
||||||
import { OwnershipService } from '@/services/ownership.service';
|
import { OwnershipService } from '@/services/ownership.service';
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
import { RoleService } from '@/services/role.service';
|
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 {
|
export class PermissionChecker {
|
||||||
/**
|
/**
|
||||||
|
@ -25,7 +27,7 @@ export class PermissionChecker {
|
||||||
|
|
||||||
// allow if requesting user is instance owner
|
// allow if requesting user is instance owner
|
||||||
|
|
||||||
const user = await Db.collections.User.findOneOrFail({
|
const user = await Container.get(UserRepository).findOneOrFail({
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
});
|
});
|
||||||
|
@ -38,7 +40,7 @@ export class PermissionChecker {
|
||||||
let workflowUserIds = [userId];
|
let workflowUserIds = [userId];
|
||||||
|
|
||||||
if (workflow.id && isSharingEnabled()) {
|
if (workflow.id && isSharingEnabled()) {
|
||||||
const workflowSharings = await Db.collections.SharedWorkflow.find({
|
const workflowSharings = await Container.get(SharedWorkflowRepository).find({
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
where: { workflowId: workflow.id },
|
where: { workflowId: workflow.id },
|
||||||
select: ['userId'],
|
select: ['userId'],
|
||||||
|
@ -54,7 +56,7 @@ export class PermissionChecker {
|
||||||
credentialsWhere.roleId = role.id;
|
credentialsWhere.roleId = role.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const credentialSharings = await Db.collections.SharedCredentials.find({
|
const credentialSharings = await Container.get(SharedCredentialsRepository).find({
|
||||||
where: credentialsWhere,
|
where: credentialsWhere,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { In } from 'typeorm';
|
||||||
import { compare, genSaltSync, hash } from 'bcryptjs';
|
import { compare, genSaltSync, hash } from 'bcryptjs';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
|
||||||
import * as Db from '@/Db';
|
|
||||||
import * as ResponseHelper from '@/ResponseHelper';
|
import * as ResponseHelper from '@/ResponseHelper';
|
||||||
import type { WhereClause } from '@/Interfaces';
|
import type { WhereClause } from '@/Interfaces';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
|
@ -11,6 +10,7 @@ import config from '@/config';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import { getWebhookBaseUrl } from '@/WebhookHelpers';
|
import { getWebhookBaseUrl } from '@/WebhookHelpers';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
|
|
||||||
export function isSharingEnabled(): boolean {
|
export function isSharingEnabled(): boolean {
|
||||||
return Container.get(License).isSharingEnabled();
|
return Container.get(License).isSharingEnabled();
|
||||||
|
@ -19,7 +19,7 @@ export function isSharingEnabled(): boolean {
|
||||||
export async function getInstanceOwner() {
|
export async function getInstanceOwner() {
|
||||||
const globalOwnerRole = await Container.get(RoleService).findGlobalOwnerRole();
|
const globalOwnerRole = await Container.get(RoleService).findGlobalOwnerRole();
|
||||||
|
|
||||||
return Db.collections.User.findOneOrFail({
|
return Container.get(UserRepository).findOneOrFail({
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
where: {
|
where: {
|
||||||
globalRoleId: globalOwnerRole.id,
|
globalRoleId: globalOwnerRole.id,
|
||||||
|
@ -77,7 +77,7 @@ export function validatePassword(password?: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserById(userId: string): Promise<User> {
|
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 },
|
where: { id: userId },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@ import type {
|
||||||
} from '@/Interfaces';
|
} from '@/Interfaces';
|
||||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||||
import { recoverExecutionDataFromEventLogMessages } from './eventbus/MessageEventBus/recoverEvents';
|
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 type { ExecutionEntity } from '@db/entities/ExecutionEntity';
|
||||||
import { OwnershipService } from './services/ownership.service';
|
import { OwnershipService } from './services/ownership.service';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
|
|
@ -12,7 +12,7 @@ import type {
|
||||||
WaitingWebhookRequest,
|
WaitingWebhookRequest,
|
||||||
} from '@/Interfaces';
|
} from '@/Interfaces';
|
||||||
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
|
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
|
||||||
import { ExecutionRepository } from '@db/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
import { OwnershipService } from './services/ownership.service';
|
import { OwnershipService } from './services/ownership.service';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
import Container from 'typedi';
|
||||||
import type { INode, IWorkflowCredentials } from 'n8n-workflow';
|
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
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
export async function WorkflowCredentials(nodes: INode[]): Promise<IWorkflowCredentials> {
|
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]) {
|
if (!returnCredentials[type][nodeCredentials.id]) {
|
||||||
foundCredentials = await Db.collections.Credentials.findOneBy({
|
foundCredentials = await Container.get(CredentialsRepository).findOneBy({
|
||||||
id: nodeCredentials.id,
|
id: nodeCredentials.id,
|
||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
|
|
|
@ -52,7 +52,7 @@ import { findSubworkflowStart, isWorkflowIdValid } from '@/utils';
|
||||||
import { PermissionChecker } from './UserManagement/PermissionChecker';
|
import { PermissionChecker } from './UserManagement/PermissionChecker';
|
||||||
import { WorkflowsService } from './workflows/workflows.services';
|
import { WorkflowsService } from './workflows/workflows.services';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import { ExecutionRepository } from '@db/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
import { EventsService } from '@/services/events.service';
|
import { EventsService } from '@/services/events.service';
|
||||||
import { SecretsHelper } from './SecretsHelpers';
|
import { SecretsHelper } from './SecretsHelpers';
|
||||||
import { OwnershipService } from './services/ownership.service';
|
import { OwnershipService } from './services/ownership.service';
|
||||||
|
|
|
@ -21,7 +21,7 @@ import {
|
||||||
Workflow,
|
Workflow,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import * as Db from '@/Db';
|
import omit from 'lodash/omit';
|
||||||
import type {
|
import type {
|
||||||
ExecutionPayload,
|
ExecutionPayload,
|
||||||
IWorkflowErrorData,
|
IWorkflowErrorData,
|
||||||
|
@ -32,15 +32,18 @@ import { WorkflowRunner } from '@/WorkflowRunner';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import omit from 'lodash/omit';
|
|
||||||
import { PermissionChecker } from './UserManagement/PermissionChecker';
|
import { PermissionChecker } from './UserManagement/PermissionChecker';
|
||||||
import { UserService } from './services/user.service';
|
import { UserService } from './services/user.service';
|
||||||
|
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
import type { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
import type { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||||
import type { RoleNames } from '@db/entities/Role';
|
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 { RoleService } from './services/role.service';
|
||||||
import { ExecutionRepository, RoleRepository } from './databases/repositories';
|
|
||||||
import { VariablesService } from './environments/variables/variables.service';
|
import { VariablesService } from './environments/variables/variables.service';
|
||||||
import type { CredentialsEntity } from './databases/entities/CredentialsEntity';
|
|
||||||
import { Logger } from './Logger';
|
import { Logger } from './Logger';
|
||||||
|
|
||||||
const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType');
|
const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType');
|
||||||
|
@ -144,7 +147,7 @@ export async function executeErrorWorkflow(
|
||||||
const logger = Container.get(Logger);
|
const logger = Container.get(Logger);
|
||||||
// Wrap everything in try/catch to make sure that no errors bubble up and all get caught here
|
// Wrap everything in try/catch to make sure that no errors bubble up and all get caught here
|
||||||
try {
|
try {
|
||||||
const workflowData = await Db.collections.Workflow.findOneBy({ id: workflowId });
|
const workflowData = await Container.get(WorkflowRepository).findOneBy({ id: workflowId });
|
||||||
|
|
||||||
if (workflowData === null) {
|
if (workflowData === null) {
|
||||||
// The error workflow could not be found
|
// The error workflow could not be found
|
||||||
|
@ -282,7 +285,7 @@ export async function executeErrorWorkflow(
|
||||||
* Returns the static data of workflow
|
* Returns the static data of workflow
|
||||||
*/
|
*/
|
||||||
export async function getStaticDataById(workflowId: string) {
|
export async function getStaticDataById(workflowId: string) {
|
||||||
const workflowData = await Db.collections.Workflow.findOne({
|
const workflowData = await Container.get(WorkflowRepository).findOne({
|
||||||
select: ['staticData'],
|
select: ['staticData'],
|
||||||
where: { id: workflowId },
|
where: { id: workflowId },
|
||||||
});
|
});
|
||||||
|
@ -330,7 +333,7 @@ export async function replaceInvalidCredentials(workflow: WorkflowEntity): Promi
|
||||||
credentialsByName[nodeCredentialType] = {};
|
credentialsByName[nodeCredentialType] = {};
|
||||||
}
|
}
|
||||||
if (credentialsByName[nodeCredentialType][name] === undefined) {
|
if (credentialsByName[nodeCredentialType][name] === undefined) {
|
||||||
const credentials = await Db.collections.Credentials.findBy({
|
const credentials = await Container.get(CredentialsRepository).findBy({
|
||||||
name,
|
name,
|
||||||
type: nodeCredentialType,
|
type: nodeCredentialType,
|
||||||
});
|
});
|
||||||
|
@ -366,7 +369,7 @@ export async function replaceInvalidCredentials(workflow: WorkflowEntity): Promi
|
||||||
// check if credentials for ID-type are not yet cached
|
// check if credentials for ID-type are not yet cached
|
||||||
if (credentialsById[nodeCredentialType][nodeCredentials.id] === undefined) {
|
if (credentialsById[nodeCredentialType][nodeCredentials.id] === undefined) {
|
||||||
// check first if ID-type combination exists
|
// check first if ID-type combination exists
|
||||||
const credentials = await Db.collections.Credentials.findOneBy({
|
const credentials = await Container.get(CredentialsRepository).findOneBy({
|
||||||
id: nodeCredentials.id,
|
id: nodeCredentials.id,
|
||||||
type: nodeCredentialType,
|
type: nodeCredentialType,
|
||||||
});
|
});
|
||||||
|
@ -380,7 +383,7 @@ export async function replaceInvalidCredentials(workflow: WorkflowEntity): Promi
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// no credentials found for ID, check if some exist for name
|
// 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,
|
name: nodeCredentials.name,
|
||||||
type: nodeCredentialType,
|
type: nodeCredentialType,
|
||||||
});
|
});
|
||||||
|
@ -429,7 +432,7 @@ export async function getSharedWorkflowIds(user: User, roles?: RoleNames[]): Pro
|
||||||
|
|
||||||
where.roleId = In(roleIds);
|
where.roleId = In(roleIds);
|
||||||
}
|
}
|
||||||
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
const sharedWorkflows = await Container.get(SharedWorkflowRepository).find({
|
||||||
where,
|
where,
|
||||||
select: ['workflowId'],
|
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 skippedTypes = ['n8n-nodes-base.start', 'n8n-nodes-base.stickyNote'];
|
||||||
|
|
||||||
const workflowOwnerRole = await Container.get(RoleService).findWorkflowOwnerRole();
|
const workflowOwnerRole = await Container.get(RoleService).findWorkflowOwnerRole();
|
||||||
const ownedWorkflowsIds = await Db.collections.SharedWorkflow.find({
|
const ownedWorkflowsIds = await Container.get(SharedWorkflowRepository)
|
||||||
where: {
|
.find({
|
||||||
userId: user.id,
|
where: {
|
||||||
roleId: workflowOwnerRole?.id,
|
userId: user.id,
|
||||||
},
|
roleId: workflowOwnerRole?.id,
|
||||||
select: ['workflowId'],
|
},
|
||||||
}).then((ownedWorkflows) => ownedWorkflows.map(({ workflowId }) => workflowId));
|
select: ['workflowId'],
|
||||||
|
})
|
||||||
|
.then((ownedWorkflows) => ownedWorkflows.map(({ workflowId }) => workflowId));
|
||||||
|
|
||||||
if (ownedWorkflowsIds.length > 15) {
|
if (ownedWorkflowsIds.length > 15) {
|
||||||
belowThreshold = false;
|
belowThreshold = false;
|
||||||
} else {
|
} else {
|
||||||
// just fetch workflows' nodes to keep memory footprint low
|
// 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) },
|
where: { id: In(ownedWorkflowsIds) },
|
||||||
select: ['nodes'],
|
select: ['nodes'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -48,7 +48,7 @@ import { PermissionChecker } from '@/UserManagement/PermissionChecker';
|
||||||
import { Push } from '@/push';
|
import { Push } from '@/push';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { InternalHooks } from './InternalHooks';
|
import { InternalHooks } from './InternalHooks';
|
||||||
import { ExecutionRepository } from '@db/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
import { Logger } from './Logger';
|
import { Logger } from './Logger';
|
||||||
|
|
||||||
export class WorkflowRunner {
|
export class WorkflowRunner {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { separate } from '@/utils';
|
import { separate } from '@/utils';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { RISK_CATEGORIES } from '@/audit/constants';
|
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 { reportFilesystemRisk } from '@/audit/risks/filesystem.risk';
|
||||||
import { reportInstanceRisk } from '@/audit/risks/instance.risk';
|
import { reportInstanceRisk } from '@/audit/risks/instance.risk';
|
||||||
import type { Risk } from '@/audit/types';
|
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> = {
|
export const SYNC_MAP: Record<string, Risk.SyncReportFn> = {
|
||||||
database: reportDatabaseRisk,
|
database: reportDatabaseRisk,
|
||||||
|
@ -35,7 +36,7 @@ export async function audit(
|
||||||
config.set('security.audit.daysAbandonedWorkflow', daysAbandonedWorkflow);
|
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'],
|
select: ['id', 'name', 'active', 'nodes', 'connections'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,9 @@ import config from '@/config';
|
||||||
import { CREDENTIALS_REPORT } from '@/audit/constants';
|
import { CREDENTIALS_REPORT } from '@/audit/constants';
|
||||||
import type { Risk } from '@/audit/types';
|
import type { Risk } from '@/audit/types';
|
||||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import {
|
import { CredentialsRepository } from '@db/repositories/credentials.repository';
|
||||||
CredentialsRepository,
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
ExecutionDataRepository,
|
import { ExecutionDataRepository } from '@db/repositories/executionData.repository';
|
||||||
ExecutionRepository,
|
|
||||||
} from '@db/repositories';
|
|
||||||
|
|
||||||
async function getAllCredsInUse(workflows: WorkflowEntity[]) {
|
async function getAllCredsInUse(workflows: WorkflowEntity[]) {
|
||||||
const credsInAnyUse = new Set<string>();
|
const credsInAnyUse = new Set<string>();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import type { Response } from 'express';
|
import type { Response } from 'express';
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants';
|
import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||||
import type { JwtPayload, JwtToken } from '@/Interfaces';
|
import type { JwtPayload, JwtToken } from '@/Interfaces';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
|
@ -9,6 +8,7 @@ import config from '@/config';
|
||||||
import * as ResponseHelper from '@/ResponseHelper';
|
import * as ResponseHelper from '@/ResponseHelper';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
|
|
||||||
export function issueJWT(user: User): JwtToken {
|
export function issueJWT(user: User): JwtToken {
|
||||||
const { id, email, password } = user;
|
const { id, email, password } = user;
|
||||||
|
@ -50,7 +50,7 @@ export const createPasswordSha = (user: User) =>
|
||||||
.digest('hex');
|
.digest('hex');
|
||||||
|
|
||||||
export async function resolveJwtContent(jwtPayload: JwtPayload): Promise<User> {
|
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 },
|
where: { id: jwtPayload.id },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import { compareHash } from '@/UserManagement/UserManagementHelper';
|
import { compareHash } from '@/UserManagement/UserManagementHelper';
|
||||||
import * as ResponseHelper from '@/ResponseHelper';
|
import * as ResponseHelper from '@/ResponseHelper';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import { isLdapLoginEnabled } from '@/Ldap/helpers';
|
import { isLdapLoginEnabled } from '@/Ldap/helpers';
|
||||||
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
|
|
||||||
export const handleEmailLogin = async (
|
export const handleEmailLogin = async (
|
||||||
email: string,
|
email: string,
|
||||||
password: string,
|
password: string,
|
||||||
): Promise<User | undefined> => {
|
): Promise<User | undefined> => {
|
||||||
const user = await Db.collections.User.findOne({
|
const user = await Container.get(UserRepository).findOne({
|
||||||
where: { email },
|
where: { email },
|
||||||
relations: ['globalRole', 'authIdentities'],
|
relations: ['globalRole', 'authIdentities'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 type { Workflow } from 'n8n-workflow';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { PostHogClient } from '@/posthog';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import { ExternalSecretsManager } from '@/ExternalSecrets/ExternalSecretsManager.ee';
|
import { ExternalSecretsManager } from '@/ExternalSecrets/ExternalSecretsManager.ee';
|
||||||
import { initExpressionEvaluator } from '@/ExpressionEvalator';
|
import { initExpressionEvaluator } from '@/ExpressionEvalator';
|
||||||
import { generateHostInstanceId } from '../databases/utils/generators';
|
import { generateHostInstanceId } from '@db/utils/generators';
|
||||||
import { WorkflowHistoryManager } from '@/workflows/workflowHistory/workflowHistoryManager.ee';
|
import { WorkflowHistoryManager } from '@/workflows/workflowHistory/workflowHistoryManager.ee';
|
||||||
|
|
||||||
export abstract class BaseCommand extends Command {
|
export abstract class BaseCommand extends Command {
|
||||||
|
|
|
@ -5,13 +5,13 @@ import type { IWorkflowBase } from 'n8n-workflow';
|
||||||
import { ExecutionBaseError } from 'n8n-workflow';
|
import { ExecutionBaseError } from 'n8n-workflow';
|
||||||
|
|
||||||
import { ActiveExecutions } from '@/ActiveExecutions';
|
import { ActiveExecutions } from '@/ActiveExecutions';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||||
import type { IWorkflowExecutionDataProcess } from '@/Interfaces';
|
import type { IWorkflowExecutionDataProcess } from '@/Interfaces';
|
||||||
import { getInstanceOwner } from '@/UserManagement/UserManagementHelper';
|
import { getInstanceOwner } from '@/UserManagement/UserManagementHelper';
|
||||||
import { findCliWorkflowStart, isWorkflowIdValid } from '@/utils';
|
import { findCliWorkflowStart, isWorkflowIdValid } from '@/utils';
|
||||||
import { BaseCommand } from './BaseCommand';
|
import { BaseCommand } from './BaseCommand';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
|
||||||
export class Execute extends BaseCommand {
|
export class Execute extends BaseCommand {
|
||||||
static description = '\nExecutes a given workflow';
|
static description = '\nExecutes a given workflow';
|
||||||
|
@ -81,7 +81,7 @@ export class Execute extends BaseCommand {
|
||||||
if (flags.id) {
|
if (flags.id) {
|
||||||
// Id of workflow is given
|
// Id of workflow is given
|
||||||
workflowId = flags.id;
|
workflowId = flags.id;
|
||||||
workflowData = await Db.collections.Workflow.findOneBy({ id: workflowId });
|
workflowData = await Container.get(WorkflowRepository).findOneBy({ id: workflowId });
|
||||||
if (workflowData === null) {
|
if (workflowData === null) {
|
||||||
this.logger.info(`The workflow with the id "${workflowId}" does not exist.`);
|
this.logger.info(`The workflow with the id "${workflowId}" does not exist.`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { diff } from 'json-diff';
|
||||||
import pick from 'lodash/pick';
|
import pick from 'lodash/pick';
|
||||||
|
|
||||||
import { ActiveExecutions } from '@/ActiveExecutions';
|
import { ActiveExecutions } from '@/ActiveExecutions';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||||
import type { IWorkflowDb, IWorkflowExecutionDataProcess } from '@/Interfaces';
|
import type { IWorkflowDb, IWorkflowExecutionDataProcess } from '@/Interfaces';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
|
@ -24,6 +23,7 @@ import type {
|
||||||
IResult,
|
IResult,
|
||||||
IWorkflowExecutionProgress,
|
IWorkflowExecutionProgress,
|
||||||
} from '../types/commands.types';
|
} from '../types/commands.types';
|
||||||
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
|
||||||
const re = /\d+/;
|
const re = /\d+/;
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ export class ExecuteBatch extends BaseCommand {
|
||||||
|
|
||||||
ExecuteBatch.instanceOwner = await getInstanceOwner();
|
ExecuteBatch.instanceOwner = await getInstanceOwner();
|
||||||
|
|
||||||
const query = Db.collections.Workflow.createQueryBuilder('workflows');
|
const query = Container.get(WorkflowRepository).createQueryBuilder('workflows');
|
||||||
|
|
||||||
if (ids.length > 0) {
|
if (ids.length > 0) {
|
||||||
query.andWhere('workflows.id in (:...ids)', { ids });
|
query.andWhere('workflows.id in (:...ids)', { ids });
|
||||||
|
|
|
@ -3,9 +3,10 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type { FindOptionsWhere } from 'typeorm';
|
import type { FindOptionsWhere } from 'typeorm';
|
||||||
import { Credentials } from 'n8n-core';
|
import { Credentials } from 'n8n-core';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { ICredentialsDb, ICredentialsDecryptedDb } from '@/Interfaces';
|
import type { ICredentialsDb, ICredentialsDecryptedDb } from '@/Interfaces';
|
||||||
import { BaseCommand } from '../BaseCommand';
|
import { BaseCommand } from '../BaseCommand';
|
||||||
|
import { CredentialsRepository } from '@db/repositories/credentials.repository';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
export class ExportCredentialsCommand extends BaseCommand {
|
export class ExportCredentialsCommand extends BaseCommand {
|
||||||
static description = 'Export credentials';
|
static description = 'Export credentials';
|
||||||
|
@ -110,7 +111,8 @@ export class ExportCredentialsCommand extends BaseCommand {
|
||||||
findQuery.id = flags.id;
|
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) {
|
if (flags.decrypted) {
|
||||||
for (let i = 0; i < credentials.length; i++) {
|
for (let i = 0; i < credentials.length; i++) {
|
||||||
|
|
|
@ -2,9 +2,10 @@ import { flags } from '@oclif/command';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type { FindOptionsWhere } from 'typeorm';
|
import type { FindOptionsWhere } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import { BaseCommand } from '../BaseCommand';
|
import { BaseCommand } from '../BaseCommand';
|
||||||
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
export class ExportWorkflowsCommand extends BaseCommand {
|
export class ExportWorkflowsCommand extends BaseCommand {
|
||||||
static description = 'Export workflows';
|
static description = 'Export workflows';
|
||||||
|
@ -104,7 +105,7 @@ export class ExportWorkflowsCommand extends BaseCommand {
|
||||||
findQuery.id = flags.id;
|
findQuery.id = flags.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflows = await Db.collections.Workflow.find({
|
const workflows = await Container.get(WorkflowRepository).find({
|
||||||
where: findQuery,
|
where: findQuery,
|
||||||
relations: ['tags'],
|
relations: ['tags'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,6 +15,7 @@ import type { ICredentialsEncrypted } from 'n8n-workflow';
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { jsonParse } from 'n8n-workflow';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import { UM_FIX_INSTRUCTION } from '@/constants';
|
import { UM_FIX_INSTRUCTION } from '@/constants';
|
||||||
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
|
|
||||||
export class ImportCredentialsCommand extends BaseCommand {
|
export class ImportCredentialsCommand extends BaseCommand {
|
||||||
static description = 'Import credentials';
|
static description = 'Import credentials';
|
||||||
|
@ -175,7 +176,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
||||||
|
|
||||||
const owner =
|
const owner =
|
||||||
ownerGlobalRole &&
|
ownerGlobalRole &&
|
||||||
(await Db.collections.User.findOneBy({ globalRoleId: ownerGlobalRole.id }));
|
(await Container.get(UserRepository).findOneBy({ globalRoleId: ownerGlobalRole.id }));
|
||||||
|
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
throw new Error(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
throw new Error(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
||||||
|
@ -185,7 +186,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAssignee(userId: string) {
|
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) {
|
if (!user) {
|
||||||
throw new Error(`Failed to find user with ID ${userId}`);
|
throw new Error(`Failed to find user with ID ${userId}`);
|
||||||
|
|
|
@ -19,6 +19,8 @@ import { generateNanoId } from '@db/utils/generators';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import { TagService } from '@/services/tag.service';
|
import { TagService } from '@/services/tag.service';
|
||||||
import { UM_FIX_INSTRUCTION } from '@/constants';
|
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[] {
|
function assertHasWorkflowsToImport(workflows: unknown): asserts workflows is IWorkflowToImport[] {
|
||||||
if (!Array.isArray(workflows)) {
|
if (!Array.isArray(workflows)) {
|
||||||
|
@ -95,7 +97,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
||||||
await this.initOwnerWorkflowRole();
|
await this.initOwnerWorkflowRole();
|
||||||
const user = flags.userId ? await this.getAssignee(flags.userId) : await this.getOwner();
|
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();
|
const tags = await this.tagService.getAll();
|
||||||
|
|
||||||
let totalImported = 0;
|
let totalImported = 0;
|
||||||
|
@ -239,7 +241,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
||||||
|
|
||||||
const owner =
|
const owner =
|
||||||
ownerGlobalRole &&
|
ownerGlobalRole &&
|
||||||
(await Db.collections.User.findOneBy({ globalRoleId: ownerGlobalRole?.id }));
|
(await Container.get(UserRepository).findOneBy({ globalRoleId: ownerGlobalRole?.id }));
|
||||||
|
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
throw new Error(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
throw new Error(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
||||||
|
@ -249,7 +251,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAssignee(userId: string) {
|
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) {
|
if (!user) {
|
||||||
throw new Error(`Failed to find user with ID ${userId}`);
|
throw new Error(`Failed to find user with ID ${userId}`);
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
import * as Db from '@/Db';
|
import Container from 'typedi';
|
||||||
import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/Ldap/constants';
|
import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/Ldap/constants';
|
||||||
import { In } from 'typeorm';
|
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';
|
import { BaseCommand } from '../BaseCommand';
|
||||||
|
|
||||||
export class Reset extends BaseCommand {
|
export class Reset extends BaseCommand {
|
||||||
static description = '\nResets the database to the default ldap state';
|
static description = '\nResets the database to the default ldap state';
|
||||||
|
|
||||||
async run(): Promise<void> {
|
async run(): Promise<void> {
|
||||||
const { AuthIdentity, AuthProviderSyncHistory, Settings, User } = Db.collections;
|
const ldapIdentities = await Container.get(AuthIdentityRepository).find({
|
||||||
const ldapIdentities = await AuthIdentity.find({
|
|
||||||
where: { providerType: 'ldap' },
|
where: { providerType: 'ldap' },
|
||||||
select: ['userId'],
|
select: ['userId'],
|
||||||
});
|
});
|
||||||
await AuthProviderSyncHistory.delete({ providerType: 'ldap' });
|
await Container.get(AuthProviderSyncHistoryRepository).delete({ providerType: 'ldap' });
|
||||||
await AuthIdentity.delete({ providerType: 'ldap' });
|
await Container.get(AuthIdentityRepository).delete({ providerType: 'ldap' });
|
||||||
await User.delete({ id: In(ldapIdentities.map((i) => i.userId)) });
|
await Container.get(UserRepository).delete({ id: In(ldapIdentities.map((i) => i.userId)) });
|
||||||
await Settings.delete({ key: LDAP_FEATURE_NAME });
|
await Container.get(SettingsRepository).delete({ key: LDAP_FEATURE_NAME });
|
||||||
await Settings.insert({
|
await Container.get(SettingsRepository).insert({
|
||||||
key: LDAP_FEATURE_NAME,
|
key: LDAP_FEATURE_NAME,
|
||||||
value: JSON.stringify(LDAP_DEFAULT_CONFIGURATION),
|
value: JSON.stringify(LDAP_DEFAULT_CONFIGURATION),
|
||||||
loadOnStartup: true,
|
loadOnStartup: true,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { SETTINGS_LICENSE_CERT_KEY } from '@/constants';
|
import { SETTINGS_LICENSE_CERT_KEY } from '@/constants';
|
||||||
import { BaseCommand } from '../BaseCommand';
|
import { BaseCommand } from '../BaseCommand';
|
||||||
|
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
export class ClearLicenseCommand extends BaseCommand {
|
export class ClearLicenseCommand extends BaseCommand {
|
||||||
static description = 'Clear license';
|
static description = 'Clear license';
|
||||||
|
@ -9,7 +10,7 @@ export class ClearLicenseCommand extends BaseCommand {
|
||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
this.logger.info('Clearing license from database.');
|
this.logger.info('Clearing license from database.');
|
||||||
await Db.collections.Settings.delete({
|
await Container.get(SettingsRepository).delete({
|
||||||
key: SETTINGS_LICENSE_CERT_KEY,
|
key: SETTINGS_LICENSE_CERT_KEY,
|
||||||
});
|
});
|
||||||
this.logger.info('Done. Restart n8n to take effect.');
|
this.logger.info('Done. Restart n8n to take effect.');
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { flags } from '@oclif/command';
|
import { flags } from '@oclif/command';
|
||||||
import type { FindOptionsWhere } from 'typeorm';
|
import type { FindOptionsWhere } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import { BaseCommand } from '../BaseCommand';
|
import { BaseCommand } from '../BaseCommand';
|
||||||
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
export class ListWorkflowCommand extends BaseCommand {
|
export class ListWorkflowCommand extends BaseCommand {
|
||||||
static description = '\nList workflows';
|
static description = '\nList workflows';
|
||||||
|
@ -36,7 +37,7 @@ export class ListWorkflowCommand extends BaseCommand {
|
||||||
findQuery.active = flags.active === 'true';
|
findQuery.active = flags.active === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflows = await Db.collections.Workflow.findBy(findQuery);
|
const workflows = await Container.get(WorkflowRepository).findBy(findQuery);
|
||||||
if (flags.onlyId) {
|
if (flags.onlyId) {
|
||||||
workflows.forEach((workflow) => this.logger.info(workflow.id));
|
workflows.forEach((workflow) => this.logger.info(workflow.id));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { flags } from '@oclif/command';
|
import { flags } from '@oclif/command';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { BaseCommand } from '../BaseCommand';
|
import { BaseCommand } from '../BaseCommand';
|
||||||
|
import Container from 'typedi';
|
||||||
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
|
|
||||||
export class DisableMFACommand extends BaseCommand {
|
export class DisableMFACommand extends BaseCommand {
|
||||||
static description = 'Disable MFA authentication for a user';
|
static description = 'Disable MFA authentication for a user';
|
||||||
|
@ -27,7 +28,7 @@ export class DisableMFACommand extends BaseCommand {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateOperationResult = await Db.collections.User.update(
|
const updateOperationResult = await Container.get(UserRepository).update(
|
||||||
{ email: flags.email },
|
{ email: flags.email },
|
||||||
{ mfaSecret: null, mfaRecoveryCodes: [], mfaEnabled: false },
|
{ mfaSecret: null, mfaRecoveryCodes: [], mfaEnabled: false },
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,7 +18,6 @@ import config from '@/config';
|
||||||
|
|
||||||
import { ActiveExecutions } from '@/ActiveExecutions';
|
import { ActiveExecutions } from '@/ActiveExecutions';
|
||||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import * as GenericHelpers from '@/GenericHelpers';
|
import * as GenericHelpers from '@/GenericHelpers';
|
||||||
import { Server } from '@/Server';
|
import { Server } from '@/Server';
|
||||||
import { EDITOR_UI_DIST_DIR, LICENSE_FEATURES } from '@/constants';
|
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 { SingleMainInstancePublisher } from '@/services/orchestration/main/SingleMainInstance.publisher';
|
||||||
import { OrchestrationHandlerMainService } from '@/services/orchestration/main/orchestration.handler.main.service';
|
import { OrchestrationHandlerMainService } from '@/services/orchestration/main/orchestration.handler.main.service';
|
||||||
import { PruningService } from '@/services/pruning.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
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
|
||||||
const open = require('open');
|
const open = require('open');
|
||||||
|
@ -286,7 +287,9 @@ export class Start extends BaseCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load settings from database and set them to config.
|
// 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) => {
|
databaseSettings.forEach((setting) => {
|
||||||
config.set(setting.key, jsonParse(setting.value, { fallbackValue: setting.value }));
|
config.set(setting.key, jsonParse(setting.value, { fallbackValue: setting.value }));
|
||||||
});
|
});
|
||||||
|
@ -304,7 +307,7 @@ export class Start extends BaseCommand {
|
||||||
if (dbType === 'sqlite') {
|
if (dbType === 'sqlite') {
|
||||||
const shouldRunVacuum = config.getEnv('database.sqlite.executeVacuumOnStartup');
|
const shouldRunVacuum = config.getEnv('database.sqlite.executeVacuumOnStartup');
|
||||||
if (shouldRunVacuum) {
|
if (shouldRunVacuum) {
|
||||||
await Db.collections.Execution.query('VACUUM;');
|
await Container.get(ExecutionRepository).query('VACUUM;');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { flags } from '@oclif/command';
|
import { flags } from '@oclif/command';
|
||||||
import type { FindOptionsWhere } from 'typeorm';
|
import type { FindOptionsWhere } from 'typeorm';
|
||||||
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
|
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import { BaseCommand } from '../BaseCommand';
|
import { BaseCommand } from '../BaseCommand';
|
||||||
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
export class UpdateWorkflowCommand extends BaseCommand {
|
export class UpdateWorkflowCommand extends BaseCommand {
|
||||||
static description = 'Update workflows';
|
static description = 'Update workflows';
|
||||||
|
@ -64,7 +65,7 @@ export class UpdateWorkflowCommand extends BaseCommand {
|
||||||
findQuery.active = true;
|
findQuery.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Db.collections.Workflow.update(findQuery, updateQuery);
|
await Container.get(WorkflowRepository).update(findQuery, updateQuery);
|
||||||
this.logger.info('Done');
|
this.logger.info('Done');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { Not } from 'typeorm';
|
import { Not } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
import { User } from '@db/entities/User';
|
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 { RoleService } from '@/services/role.service';
|
||||||
|
import { BaseCommand } from '../BaseCommand';
|
||||||
|
|
||||||
const defaultUserProps = {
|
const defaultUserProps = {
|
||||||
firstName: null,
|
firstName: null,
|
||||||
|
@ -24,34 +28,34 @@ export class Reset extends BaseCommand {
|
||||||
const ownerWorkflowRole = await Container.get(RoleService).findWorkflowOwnerRole();
|
const ownerWorkflowRole = await Container.get(RoleService).findWorkflowOwnerRole();
|
||||||
const ownerCredentialRole = await Container.get(RoleService).findCredentialOwnerRole();
|
const ownerCredentialRole = await Container.get(RoleService).findCredentialOwnerRole();
|
||||||
|
|
||||||
await Db.collections.SharedWorkflow.update(
|
await Container.get(SharedWorkflowRepository).update(
|
||||||
{ userId: Not(owner.id), roleId: ownerWorkflowRole.id },
|
{ userId: Not(owner.id), roleId: ownerWorkflowRole.id },
|
||||||
{ user: owner },
|
{ user: owner },
|
||||||
);
|
);
|
||||||
|
|
||||||
await Db.collections.SharedCredentials.update(
|
await Container.get(SharedCredentialsRepository).update(
|
||||||
{ userId: Not(owner.id), roleId: ownerCredentialRole.id },
|
{ userId: Not(owner.id), roleId: ownerCredentialRole.id },
|
||||||
{ user: owner },
|
{ user: owner },
|
||||||
);
|
);
|
||||||
|
|
||||||
await Db.collections.User.delete({ id: Not(owner.id) });
|
await Container.get(UserRepository).delete({ id: Not(owner.id) });
|
||||||
await Db.collections.User.save(Object.assign(owner, defaultUserProps));
|
await Container.get(UserRepository).save(Object.assign(owner, defaultUserProps));
|
||||||
|
|
||||||
const danglingCredentials: CredentialsEntity[] =
|
const danglingCredentials: CredentialsEntity[] = await Container.get(CredentialsRepository)
|
||||||
await Db.collections.Credentials.createQueryBuilder('credentials')
|
.createQueryBuilder('credentials')
|
||||||
.leftJoinAndSelect('credentials.shared', 'shared')
|
.leftJoinAndSelect('credentials.shared', 'shared')
|
||||||
.where('shared.credentialsId is null')
|
.where('shared.credentialsId is null')
|
||||||
.getMany();
|
.getMany();
|
||||||
const newSharedCredentials = danglingCredentials.map((credentials) =>
|
const newSharedCredentials = danglingCredentials.map((credentials) =>
|
||||||
Db.collections.SharedCredentials.create({
|
Container.get(SharedCredentialsRepository).create({
|
||||||
credentials,
|
credentials,
|
||||||
user: owner,
|
user: owner,
|
||||||
role: ownerCredentialRole,
|
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' },
|
{ key: 'userManagement.isInstanceOwnerSetUp' },
|
||||||
{ value: 'false' },
|
{ value: 'false' },
|
||||||
);
|
);
|
||||||
|
@ -62,7 +66,7 @@ export class Reset extends BaseCommand {
|
||||||
async getInstanceOwner(): Promise<User> {
|
async getInstanceOwner(): Promise<User> {
|
||||||
const globalRole = await Container.get(RoleService).findGlobalOwnerRole();
|
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;
|
if (owner) return owner;
|
||||||
|
|
||||||
|
@ -70,9 +74,9 @@ export class Reset extends BaseCommand {
|
||||||
|
|
||||||
Object.assign(user, { ...defaultUserProps, globalRole });
|
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> {
|
async catch(error: Error): Promise<void> {
|
||||||
|
|
|
@ -27,7 +27,8 @@ import { Queue } from '@/Queue';
|
||||||
import { generateFailedExecutionFromError } from '@/WorkflowHelpers';
|
import { generateFailedExecutionFromError } from '@/WorkflowHelpers';
|
||||||
import { N8N_VERSION } from '@/constants';
|
import { N8N_VERSION } from '@/constants';
|
||||||
import { BaseCommand } from './BaseCommand';
|
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 { OwnershipService } from '@/services/ownership.service';
|
||||||
import type { ICredentialsOverwrite } from '@/Interfaces';
|
import type { ICredentialsOverwrite } from '@/Interfaces';
|
||||||
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
|
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
|
||||||
|
@ -137,7 +138,7 @@ export class Worker extends BaseCommand {
|
||||||
|
|
||||||
let { staticData } = fullExecutionData.workflowData;
|
let { staticData } = fullExecutionData.workflowData;
|
||||||
if (loadStaticData) {
|
if (loadStaticData) {
|
||||||
const workflowData = await Db.collections.Workflow.findOne({
|
const workflowData = await Container.get(WorkflowRepository).findOne({
|
||||||
select: ['id', 'staticData'],
|
select: ['id', 'staticData'],
|
||||||
where: {
|
where: {
|
||||||
id: workflowId,
|
id: workflowId,
|
||||||
|
|
|
@ -3,7 +3,9 @@ import { Service } from 'typedi';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import type { Role } from '@db/entities/Role';
|
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 { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||||
import { hashPassword } from '@/UserManagement/UserManagementHelper';
|
import { hashPassword } from '@/UserManagement/UserManagementHelper';
|
||||||
import { eventBus } from '@/eventbus/MessageEventBus/MessageEventBus';
|
import { eventBus } from '@/eventbus/MessageEventBus/MessageEventBus';
|
||||||
|
|
|
@ -4,7 +4,8 @@ import type { ICredentialDataDecryptedObject, IWorkflowExecuteAdditionalData } f
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
import type { User } from '@db/entities/User';
|
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 type { ICredentialsDb } from '@/Interfaces';
|
||||||
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
||||||
import type { OAuthRequest } from '@/requests';
|
import type { OAuthRequest } from '@/requests';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { Response } from 'express';
|
||||||
import { Config } from '@/config';
|
import { Config } from '@/config';
|
||||||
import { OwnerRequest } from '@/requests';
|
import { OwnerRequest } from '@/requests';
|
||||||
import { IInternalHooksClass } from '@/Interfaces';
|
import { IInternalHooksClass } from '@/Interfaces';
|
||||||
import { SettingsRepository } from '@db/repositories';
|
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||||
import { PostHogClient } from '@/posthog';
|
import { PostHogClient } from '@/posthog';
|
||||||
import { UserService } from '@/services/user.service';
|
import { UserService } from '@/services/user.service';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
|
|
@ -29,7 +29,8 @@ import type { PublicUser, ITelemetryUserDeletionData } from '@/Interfaces';
|
||||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||||
import { PostHogClient } from '@/posthog';
|
import { PostHogClient } from '@/posthog';
|
||||||
import { isSamlLicensedAndEnabled } from '../sso/saml/samlHelpers';
|
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 { plainToInstance } from 'class-transformer';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { Response, NextFunction } from 'express';
|
||||||
import { Get, Middleware, RestController } from '@/decorators';
|
import { Get, Middleware, RestController } from '@/decorators';
|
||||||
import type { WorkflowStatistics } from '@db/entities/WorkflowStatistics';
|
import type { WorkflowStatistics } from '@db/entities/WorkflowStatistics';
|
||||||
import { StatisticsNames } 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 { ExecutionRequest } from '@/requests';
|
||||||
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
||||||
import { NotFoundError } from '@/ResponseHelper';
|
import { NotFoundError } from '@/ResponseHelper';
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { EECredentialsService as EECredentials } from './credentials.service.ee'
|
||||||
import { OwnershipService } from '@/services/ownership.service';
|
import { OwnershipService } from '@/services/ownership.service';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
|
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
|
|
||||||
export const EECredentialsController = express.Router();
|
export const EECredentialsController = express.Router();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { DeleteResult, EntityManager, FindOptionsWhere } from 'typeorm';
|
import type { DeleteResult, EntityManager, FindOptionsWhere } from 'typeorm';
|
||||||
import { In, Not } from 'typeorm';
|
import { In, Not } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
import { SharedCredentials } from '@db/entities/SharedCredentials';
|
import { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
|
@ -8,6 +7,7 @@ import { UserService } from '@/services/user.service';
|
||||||
import { CredentialsService } from './credentials.service';
|
import { CredentialsService } from './credentials.service';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
|
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
|
||||||
|
|
||||||
export class EECredentialsService extends CredentialsService {
|
export class EECredentialsService extends CredentialsService {
|
||||||
static async isOwned(
|
static async isOwned(
|
||||||
|
@ -43,7 +43,7 @@ export class EECredentialsService extends CredentialsService {
|
||||||
where.userId = user.id;
|
where.userId = user.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Db.collections.SharedCredentials.findOne({
|
return Container.get(SharedCredentialsRepository).findOne({
|
||||||
where,
|
where,
|
||||||
relations,
|
relations,
|
||||||
});
|
});
|
||||||
|
@ -83,7 +83,7 @@ export class EECredentialsService extends CredentialsService {
|
||||||
const newSharedCredentials = users
|
const newSharedCredentials = users
|
||||||
.filter((user) => !user.isPending)
|
.filter((user) => !user.isPending)
|
||||||
.map((user) =>
|
.map((user) =>
|
||||||
Db.collections.SharedCredentials.create({
|
Container.get(SharedCredentialsRepository).create({
|
||||||
credentialsId: credential.id,
|
credentialsId: credential.id,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
roleId: role?.id,
|
roleId: role?.id,
|
||||||
|
|
|
@ -25,13 +25,15 @@ import { CredentialTypes } from '@/CredentialTypes';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import { OwnershipService } from '@/services/ownership.service';
|
import { OwnershipService } from '@/services/ownership.service';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
import { CredentialsRepository } from '@db/repositories/credentials.repository';
|
||||||
|
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
|
||||||
|
|
||||||
export class CredentialsService {
|
export class CredentialsService {
|
||||||
static async get(
|
static async get(
|
||||||
where: FindOptionsWhere<ICredentialsDb>,
|
where: FindOptionsWhere<ICredentialsDb>,
|
||||||
options?: { relations: string[] },
|
options?: { relations: string[] },
|
||||||
): Promise<ICredentialsDb | null> {
|
): Promise<ICredentialsDb | null> {
|
||||||
return Db.collections.Credentials.findOne({
|
return Container.get(CredentialsRepository).findOne({
|
||||||
relations: options?.relations,
|
relations: options?.relations,
|
||||||
where,
|
where,
|
||||||
});
|
});
|
||||||
|
@ -88,14 +90,14 @@ export class CredentialsService {
|
||||||
const isDefaultSelect = !options.listQueryOptions?.select;
|
const isDefaultSelect = !options.listQueryOptions?.select;
|
||||||
|
|
||||||
if (returnAll) {
|
if (returnAll) {
|
||||||
const credentials = await Db.collections.Credentials.find(findManyOptions);
|
const credentials = await Container.get(CredentialsRepository).find(findManyOptions);
|
||||||
|
|
||||||
return isDefaultSelect ? this.addOwnedByAndSharedWith(credentials) : credentials;
|
return isDefaultSelect ? this.addOwnedByAndSharedWith(credentials) : credentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ids = await this.getAccessibleCredentials(user.id);
|
const ids = await this.getAccessibleCredentials(user.id);
|
||||||
|
|
||||||
const credentials = await Db.collections.Credentials.find({
|
const credentials = await Container.get(CredentialsRepository).find({
|
||||||
...findManyOptions,
|
...findManyOptions,
|
||||||
where: { ...findManyOptions.where, id: In(ids) }, // only accessible credentials
|
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.
|
* Get the IDs of all credentials owned by or shared with a user.
|
||||||
*/
|
*/
|
||||||
private static async getAccessibleCredentials(userId: string) {
|
private static async getAccessibleCredentials(userId: string) {
|
||||||
const sharings = await Db.collections.SharedCredentials.find({
|
const sharings = await Container.get(SharedCredentialsRepository).find({
|
||||||
relations: ['role'],
|
relations: ['role'],
|
||||||
where: {
|
where: {
|
||||||
userId,
|
userId,
|
||||||
|
@ -125,7 +127,7 @@ export class CredentialsService {
|
||||||
options.relations = ['shared', 'shared.user', 'shared.role'];
|
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(
|
static async prepareCreateData(
|
||||||
|
@ -162,7 +164,7 @@ export class CredentialsService {
|
||||||
|
|
||||||
// This saves us a merge but requires some type casting. These
|
// This saves us a merge but requires some type casting. These
|
||||||
// types are compatible for this case.
|
// 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);
|
await validateEntity(newCredentials);
|
||||||
|
|
||||||
|
@ -185,7 +187,7 @@ export class CredentialsService {
|
||||||
|
|
||||||
// This saves us a merge but requires some type casting. These
|
// This saves us a merge but requires some type casting. These
|
||||||
// types are compatible for this case.
|
// 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);
|
await validateEntity(updateData);
|
||||||
|
|
||||||
|
@ -234,11 +236,11 @@ export class CredentialsService {
|
||||||
await Container.get(ExternalHooks).run('credentials.update', [newCredentialData]);
|
await Container.get(ExternalHooks).run('credentials.update', [newCredentialData]);
|
||||||
|
|
||||||
// Update the credentials in DB
|
// 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
|
// We sadly get nothing back from "update". Neither if it updated a record
|
||||||
// nor the new value. So query now the updated entry.
|
// 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(
|
static async save(
|
||||||
|
@ -281,7 +283,7 @@ export class CredentialsService {
|
||||||
static async delete(credentials: CredentialsEntity): Promise<void> {
|
static async delete(credentials: CredentialsEntity): Promise<void> {
|
||||||
await Container.get(ExternalHooks).run('credentials.delete', [credentials.id]);
|
await Container.get(ExternalHooks).run('credentials.delete', [credentials.id]);
|
||||||
|
|
||||||
await Db.collections.Credentials.remove(credentials);
|
await Container.get(CredentialsRepository).remove(credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async test(
|
static async test(
|
||||||
|
|
|
@ -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';
|
|
|
@ -33,7 +33,7 @@ import type { Variables } from '@db/entities/Variables';
|
||||||
import type { SourceControlWorkflowVersionId } from './types/sourceControlWorkflowVersionId';
|
import type { SourceControlWorkflowVersionId } from './types/sourceControlWorkflowVersionId';
|
||||||
import type { ExportableCredential } from './types/exportableCredential';
|
import type { ExportableCredential } from './types/exportableCredential';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import { TagRepository } from '@/databases/repositories';
|
import { TagRepository } from '@db/repositories/tag.repository';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Service } from 'typedi';
|
import Container, { Service } from 'typedi';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {
|
import {
|
||||||
SOURCE_CONTROL_CREDENTIAL_EXPORT_FOLDER,
|
SOURCE_CONTROL_CREDENTIAL_EXPORT_FOLDER,
|
||||||
|
@ -6,7 +6,6 @@ import {
|
||||||
SOURCE_CONTROL_TAGS_EXPORT_FILE,
|
SOURCE_CONTROL_TAGS_EXPORT_FILE,
|
||||||
SOURCE_CONTROL_WORKFLOW_EXPORT_FOLDER,
|
SOURCE_CONTROL_WORKFLOW_EXPORT_FOLDER,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { ICredentialDataDecryptedObject } from 'n8n-workflow';
|
import type { ICredentialDataDecryptedObject } from 'n8n-workflow';
|
||||||
import { writeFile as fsWriteFile, rm as fsRm } from 'fs/promises';
|
import { writeFile as fsWriteFile, rm as fsRm } from 'fs/promises';
|
||||||
import { rmSync } from 'fs';
|
import { rmSync } from 'fs';
|
||||||
|
@ -25,8 +24,12 @@ import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import type { SourceControlledFile } from './types/sourceControlledFile';
|
import type { SourceControlledFile } from './types/sourceControlledFile';
|
||||||
import { VariablesService } from '../variables/variables.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 { Logger } from '@/Logger';
|
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()
|
@Service()
|
||||||
export class SourceControlExportService {
|
export class SourceControlExportService {
|
||||||
|
@ -102,7 +105,7 @@ export class SourceControlExportService {
|
||||||
try {
|
try {
|
||||||
sourceControlFoldersExistCheck([this.workflowExportFolder]);
|
sourceControlFoldersExistCheck([this.workflowExportFolder]);
|
||||||
const workflowIds = candidates.map((e) => e.id);
|
const workflowIds = candidates.map((e) => e.id);
|
||||||
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
const sharedWorkflows = await Container.get(SharedWorkflowRepository).find({
|
||||||
relations: ['role', 'user'],
|
relations: ['role', 'user'],
|
||||||
where: {
|
where: {
|
||||||
role: {
|
role: {
|
||||||
|
@ -112,7 +115,7 @@ export class SourceControlExportService {
|
||||||
workflowId: In(workflowIds),
|
workflowId: In(workflowIds),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const workflows = await Db.collections.Workflow.find({
|
const workflows = await Container.get(WorkflowRepository).find({
|
||||||
where: {
|
where: {
|
||||||
id: In(workflowIds),
|
id: In(workflowIds),
|
||||||
},
|
},
|
||||||
|
@ -181,7 +184,7 @@ export class SourceControlExportService {
|
||||||
files: [],
|
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);
|
const fileName = path.join(this.gitFolder, SOURCE_CONTROL_TAGS_EXPORT_FILE);
|
||||||
await fsWriteFile(
|
await fsWriteFile(
|
||||||
fileName,
|
fileName,
|
||||||
|
@ -236,7 +239,7 @@ export class SourceControlExportService {
|
||||||
try {
|
try {
|
||||||
sourceControlFoldersExistCheck([this.credentialExportFolder]);
|
sourceControlFoldersExistCheck([this.credentialExportFolder]);
|
||||||
const credentialIds = candidates.map((e) => e.id);
|
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'],
|
relations: ['credentials', 'role', 'user'],
|
||||||
where: {
|
where: {
|
||||||
credentialsId: In(credentialIds),
|
credentialsId: In(credentialIds),
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {
|
||||||
SOURCE_CONTROL_VARIABLES_EXPORT_FILE,
|
SOURCE_CONTROL_VARIABLES_EXPORT_FILE,
|
||||||
SOURCE_CONTROL_WORKFLOW_EXPORT_FOLDER,
|
SOURCE_CONTROL_WORKFLOW_EXPORT_FOLDER,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import glob from 'fast-glob';
|
import glob from 'fast-glob';
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { jsonParse } from 'n8n-workflow';
|
||||||
import { readFile as fsReadFile } from 'fs/promises';
|
import { readFile as fsReadFile } from 'fs/promises';
|
||||||
|
@ -26,9 +25,16 @@ import { getCredentialExportPath, getWorkflowExportPath } from './sourceControlH
|
||||||
import type { SourceControlledFile } from './types/sourceControlledFile';
|
import type { SourceControlledFile } from './types/sourceControlledFile';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import { VariablesService } from '../variables/variables.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 { UM_FIX_INSTRUCTION } from '@/constants';
|
||||||
import { Logger } from '@/Logger';
|
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()
|
@Service()
|
||||||
export class SourceControlImportService {
|
export class SourceControlImportService {
|
||||||
|
@ -110,7 +116,7 @@ export class SourceControlImportService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getLocalVersionIdsFromDb(): Promise<SourceControlWorkflowVersionId[]> {
|
public async getLocalVersionIdsFromDb(): Promise<SourceControlWorkflowVersionId[]> {
|
||||||
const localWorkflows = await Db.collections.Workflow.find({
|
const localWorkflows = await Container.get(WorkflowRepository).find({
|
||||||
select: ['id', 'name', 'versionId', 'updatedAt'],
|
select: ['id', 'name', 'versionId', 'updatedAt'],
|
||||||
});
|
});
|
||||||
return localWorkflows.map((local) => ({
|
return localWorkflows.map((local) => ({
|
||||||
|
@ -153,7 +159,7 @@ export class SourceControlImportService {
|
||||||
public async getLocalCredentialsFromDb(): Promise<
|
public async getLocalCredentialsFromDb(): Promise<
|
||||||
Array<ExportableCredential & { filename: string }>
|
Array<ExportableCredential & { filename: string }>
|
||||||
> {
|
> {
|
||||||
const localCredentials = await Db.collections.Credentials.find({
|
const localCredentials = await Container.get(CredentialsRepository).find({
|
||||||
select: ['id', 'name', 'type', 'nodesAccess'],
|
select: ['id', 'name', 'type', 'nodesAccess'],
|
||||||
});
|
});
|
||||||
return localCredentials.map((local) => ({
|
return localCredentials.map((local) => ({
|
||||||
|
@ -209,7 +215,7 @@ export class SourceControlImportService {
|
||||||
const localTags = await this.tagRepository.find({
|
const localTags = await this.tagRepository.find({
|
||||||
select: ['id', 'name'],
|
select: ['id', 'name'],
|
||||||
});
|
});
|
||||||
const localMappings = await Db.collections.WorkflowTagMapping.find({
|
const localMappings = await Container.get(WorkflowTagMappingRepository).find({
|
||||||
select: ['workflowId', 'tagId'],
|
select: ['workflowId', 'tagId'],
|
||||||
});
|
});
|
||||||
return { tags: localTags, mappings: localMappings };
|
return { tags: localTags, mappings: localMappings };
|
||||||
|
@ -219,13 +225,13 @@ export class SourceControlImportService {
|
||||||
const ownerWorkflowRole = await this.getWorkflowOwnerRole();
|
const ownerWorkflowRole = await this.getWorkflowOwnerRole();
|
||||||
const workflowRunner = this.activeWorkflowRunner;
|
const workflowRunner = this.activeWorkflowRunner;
|
||||||
const candidateIds = candidates.map((c) => c.id);
|
const candidateIds = candidates.map((c) => c.id);
|
||||||
const existingWorkflows = await Db.collections.Workflow.find({
|
const existingWorkflows = await Container.get(WorkflowRepository).find({
|
||||||
where: {
|
where: {
|
||||||
id: In(candidateIds),
|
id: In(candidateIds),
|
||||||
},
|
},
|
||||||
select: ['id', 'name', 'versionId', 'active'],
|
select: ['id', 'name', 'versionId', 'active'],
|
||||||
});
|
});
|
||||||
const allSharedWorkflows = await Db.collections.SharedWorkflow.find({
|
const allSharedWorkflows = await Container.get(SharedWorkflowRepository).find({
|
||||||
where: {
|
where: {
|
||||||
workflowId: In(candidateIds),
|
workflowId: In(candidateIds),
|
||||||
},
|
},
|
||||||
|
@ -244,7 +250,10 @@ export class SourceControlImportService {
|
||||||
const existingWorkflow = existingWorkflows.find((e) => e.id === importedWorkflow.id);
|
const existingWorkflow = existingWorkflows.find((e) => e.id === importedWorkflow.id);
|
||||||
importedWorkflow.active = existingWorkflow?.active ?? false;
|
importedWorkflow.active = existingWorkflow?.active ?? false;
|
||||||
this.logger.debug(`Updating workflow id ${importedWorkflow.id ?? 'new'}`);
|
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) {
|
if (upsertResult?.identifiers?.length !== 1) {
|
||||||
throw new Error(`Failed to upsert workflow ${importedWorkflow.id ?? 'new'}`);
|
throw new Error(`Failed to upsert workflow ${importedWorkflow.id ?? 'new'}`);
|
||||||
}
|
}
|
||||||
|
@ -254,7 +263,7 @@ export class SourceControlImportService {
|
||||||
if (cachedOwnerIds.has(importedWorkflow.owner)) {
|
if (cachedOwnerIds.has(importedWorkflow.owner)) {
|
||||||
workflowOwnerId = cachedOwnerIds.get(importedWorkflow.owner) ?? userId;
|
workflowOwnerId = cachedOwnerIds.get(importedWorkflow.owner) ?? userId;
|
||||||
} else {
|
} else {
|
||||||
const foundUser = await Db.collections.User.findOne({
|
const foundUser = await Container.get(UserRepository).findOne({
|
||||||
where: {
|
where: {
|
||||||
email: importedWorkflow.owner,
|
email: importedWorkflow.owner,
|
||||||
},
|
},
|
||||||
|
@ -278,7 +287,7 @@ export class SourceControlImportService {
|
||||||
);
|
);
|
||||||
if (!existingSharedWorkflowOwnerByUserId && !existingSharedWorkflowOwnerByRoleId) {
|
if (!existingSharedWorkflowOwnerByUserId && !existingSharedWorkflowOwnerByRoleId) {
|
||||||
// no owner exists yet, so create one
|
// no owner exists yet, so create one
|
||||||
await Db.collections.SharedWorkflow.insert({
|
await Container.get(SharedWorkflowRepository).insert({
|
||||||
workflowId: importedWorkflow.id,
|
workflowId: importedWorkflow.id,
|
||||||
userId: workflowOwnerId,
|
userId: workflowOwnerId,
|
||||||
roleId: ownerWorkflowRole.id,
|
roleId: ownerWorkflowRole.id,
|
||||||
|
@ -288,7 +297,7 @@ export class SourceControlImportService {
|
||||||
} else if (existingSharedWorkflowOwnerByUserId && !existingSharedWorkflowOwnerByRoleId) {
|
} else if (existingSharedWorkflowOwnerByUserId && !existingSharedWorkflowOwnerByRoleId) {
|
||||||
// if the worklflow has a non-global owner that is referenced by the owner file,
|
// 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
|
// 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,
|
workflowId: importedWorkflow.id,
|
||||||
userId: workflowOwnerId,
|
userId: workflowOwnerId,
|
||||||
|
@ -310,7 +319,7 @@ export class SourceControlImportService {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`Failed to activate workflow ${existingWorkflow.id}`, error as Error);
|
this.logger.error(`Failed to activate workflow ${existingWorkflow.id}`, error as Error);
|
||||||
} finally {
|
} finally {
|
||||||
await Db.collections.Workflow.update(
|
await Container.get(WorkflowRepository).update(
|
||||||
{ id: existingWorkflow.id },
|
{ id: existingWorkflow.id },
|
||||||
{ versionId: importedWorkflow.versionId },
|
{ versionId: importedWorkflow.versionId },
|
||||||
);
|
);
|
||||||
|
@ -331,7 +340,7 @@ export class SourceControlImportService {
|
||||||
|
|
||||||
public async importCredentialsFromWorkFolder(candidates: SourceControlledFile[], userId: string) {
|
public async importCredentialsFromWorkFolder(candidates: SourceControlledFile[], userId: string) {
|
||||||
const candidateIds = candidates.map((c) => c.id);
|
const candidateIds = candidates.map((c) => c.id);
|
||||||
const existingCredentials = await Db.collections.Credentials.find({
|
const existingCredentials = await Container.get(CredentialsRepository).find({
|
||||||
where: {
|
where: {
|
||||||
id: In(candidateIds),
|
id: In(candidateIds),
|
||||||
},
|
},
|
||||||
|
@ -339,7 +348,7 @@ export class SourceControlImportService {
|
||||||
});
|
});
|
||||||
const ownerCredentialRole = await this.getCredentialOwnerRole();
|
const ownerCredentialRole = await this.getCredentialOwnerRole();
|
||||||
const ownerGlobalRole = await this.getOwnerGlobalRole();
|
const ownerGlobalRole = await this.getOwnerGlobalRole();
|
||||||
const existingSharedCredentials = await Db.collections.SharedCredentials.find({
|
const existingSharedCredentials = await Container.get(SharedCredentialsRepository).find({
|
||||||
select: ['userId', 'credentialsId', 'roleId'],
|
select: ['userId', 'credentialsId', 'roleId'],
|
||||||
where: {
|
where: {
|
||||||
credentialsId: In(candidateIds),
|
credentialsId: In(candidateIds),
|
||||||
|
@ -370,7 +379,7 @@ export class SourceControlImportService {
|
||||||
newCredentialObject.nodesAccess = nodesAccess || existingCredential?.nodesAccess || [];
|
newCredentialObject.nodesAccess = nodesAccess || existingCredential?.nodesAccess || [];
|
||||||
|
|
||||||
this.logger.debug(`Updating credential id ${newCredentialObject.id as string}`);
|
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) {
|
if (!sharedOwner) {
|
||||||
const newSharedCredential = new SharedCredentials();
|
const newSharedCredential = new SharedCredentials();
|
||||||
|
@ -378,7 +387,7 @@ export class SourceControlImportService {
|
||||||
newSharedCredential.userId = userId;
|
newSharedCredential.userId = userId;
|
||||||
newSharedCredential.roleId = ownerCredentialRole.id;
|
newSharedCredential.roleId = ownerCredentialRole.id;
|
||||||
|
|
||||||
await Db.collections.SharedCredentials.upsert({ ...newSharedCredential }, [
|
await Container.get(SharedCredentialsRepository).upsert({ ...newSharedCredential }, [
|
||||||
'credentialsId',
|
'credentialsId',
|
||||||
'userId',
|
'userId',
|
||||||
]);
|
]);
|
||||||
|
@ -413,7 +422,7 @@ export class SourceControlImportService {
|
||||||
|
|
||||||
const existingWorkflowIds = new Set(
|
const existingWorkflowIds = new Set(
|
||||||
(
|
(
|
||||||
await Db.collections.Workflow.find({
|
await Container.get(WorkflowRepository).find({
|
||||||
select: ['id'],
|
select: ['id'],
|
||||||
})
|
})
|
||||||
).map((e) => e.id),
|
).map((e) => e.id),
|
||||||
|
@ -442,7 +451,7 @@ export class SourceControlImportService {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
mappedTags.mappings.map(async (mapping) => {
|
mappedTags.mappings.map(async (mapping) => {
|
||||||
if (!existingWorkflowIds.has(String(mapping.workflowId))) return;
|
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) },
|
{ tagId: String(mapping.tagId), workflowId: String(mapping.workflowId) },
|
||||||
{
|
{
|
||||||
skipUpdateIfNoValuesChanged: true,
|
skipUpdateIfNoValuesChanged: true,
|
||||||
|
@ -489,12 +498,12 @@ export class SourceControlImportService {
|
||||||
overriddenKeys.splice(overriddenKeys.indexOf(variable.key), 1);
|
overriddenKeys.splice(overriddenKeys.indexOf(variable.key), 1);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await Db.collections.Variables.upsert({ ...variable }, ['id']);
|
await Container.get(VariablesRepository).upsert({ ...variable }, ['id']);
|
||||||
} catch (errorUpsert) {
|
} catch (errorUpsert) {
|
||||||
if (isUniqueConstraintError(errorUpsert as Error)) {
|
if (isUniqueConstraintError(errorUpsert as Error)) {
|
||||||
this.logger.debug(`Variable ${variable.key} already exists, updating instead`);
|
this.logger.debug(`Variable ${variable.key} already exists, updating instead`);
|
||||||
try {
|
try {
|
||||||
await Db.collections.Variables.update({ key: variable.key }, { ...variable });
|
await Container.get(VariablesRepository).update({ key: variable.key }, { ...variable });
|
||||||
} catch (errorUpdate) {
|
} catch (errorUpdate) {
|
||||||
this.logger.debug(`Failed to update variable ${variable.key}, skipping`);
|
this.logger.debug(`Failed to update variable ${variable.key}, skipping`);
|
||||||
this.logger.debug((errorUpdate as Error).message);
|
this.logger.debug((errorUpdate as Error).message);
|
||||||
|
@ -509,8 +518,11 @@ export class SourceControlImportService {
|
||||||
if (overriddenKeys.length > 0 && valueOverrides) {
|
if (overriddenKeys.length > 0 && valueOverrides) {
|
||||||
for (const key of overriddenKeys) {
|
for (const key of overriddenKeys) {
|
||||||
result.imported.push(key);
|
result.imported.push(key);
|
||||||
const newVariable = Db.collections.Variables.create({ key, value: valueOverrides[key] });
|
const newVariable = Container.get(VariablesRepository).create({
|
||||||
await Db.collections.Variables.save(newVariable);
|
key,
|
||||||
|
value: valueOverrides[key],
|
||||||
|
});
|
||||||
|
await Container.get(VariablesRepository).save(newVariable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Service } from 'typedi';
|
import Container, { Service } from 'typedi';
|
||||||
import { SourceControlPreferences } from './types/sourceControlPreferences';
|
import { SourceControlPreferences } from './types/sourceControlPreferences';
|
||||||
import type { ValidationError } from 'class-validator';
|
import type { ValidationError } from 'class-validator';
|
||||||
import { validate } from 'class-validator';
|
import { validate } from 'class-validator';
|
||||||
|
@ -11,7 +11,6 @@ import {
|
||||||
} from './sourceControlHelper.ee';
|
} from './sourceControlHelper.ee';
|
||||||
import { InstanceSettings } from 'n8n-core';
|
import { InstanceSettings } from 'n8n-core';
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { jsonParse } from 'n8n-workflow';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import {
|
import {
|
||||||
SOURCE_CONTROL_SSH_FOLDER,
|
SOURCE_CONTROL_SSH_FOLDER,
|
||||||
SOURCE_CONTROL_GIT_FOLDER,
|
SOURCE_CONTROL_GIT_FOLDER,
|
||||||
|
@ -22,6 +21,7 @@ import path from 'path';
|
||||||
import type { KeyPairType } from './types/keyPairType';
|
import type { KeyPairType } from './types/keyPairType';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class SourceControlPreferencesService {
|
export class SourceControlPreferencesService {
|
||||||
|
@ -171,7 +171,7 @@ export class SourceControlPreferencesService {
|
||||||
if (saveToDb) {
|
if (saveToDb) {
|
||||||
const settingsValue = JSON.stringify(this._sourceControlPreferences);
|
const settingsValue = JSON.stringify(this._sourceControlPreferences);
|
||||||
try {
|
try {
|
||||||
await Db.collections.Settings.save({
|
await Container.get(SettingsRepository).save({
|
||||||
key: SOURCE_CONTROL_PREFERENCES_DB_KEY,
|
key: SOURCE_CONTROL_PREFERENCES_DB_KEY,
|
||||||
value: settingsValue,
|
value: settingsValue,
|
||||||
loadOnStartup: true,
|
loadOnStartup: true,
|
||||||
|
@ -186,7 +186,7 @@ export class SourceControlPreferencesService {
|
||||||
async loadFromDbAndApplySourceControlPreferences(): Promise<
|
async loadFromDbAndApplySourceControlPreferences(): Promise<
|
||||||
SourceControlPreferences | undefined
|
SourceControlPreferences | undefined
|
||||||
> {
|
> {
|
||||||
const loadedPreferences = await Db.collections.Settings.findOne({
|
const loadedPreferences = await Container.get(SettingsRepository).findOne({
|
||||||
where: { key: SOURCE_CONTROL_PREFERENCES_DB_KEY },
|
where: { key: SOURCE_CONTROL_PREFERENCES_DB_KEY },
|
||||||
});
|
});
|
||||||
if (loadedPreferences) {
|
if (loadedPreferences) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Variables } from '@db/entities/Variables';
|
import type { Variables } from '@db/entities/Variables';
|
||||||
import { CacheService } from '@/services/cache.service';
|
import { CacheService } from '@/services/cache.service';
|
||||||
import Container, { Service } from 'typedi';
|
import Container, { Service } from 'typedi';
|
||||||
import { VariablesRepository } from '@/databases/repositories';
|
import { VariablesRepository } from '@db/repositories/variables.repository';
|
||||||
import type { DeepPartial } from 'typeorm';
|
import type { DeepPartial } from 'typeorm';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
|
|
|
@ -11,7 +11,6 @@ import type { MessageEventBusDestination } from '../MessageEventBusDestination/M
|
||||||
import { MessageEventBusLogWriter } from '../MessageEventBusWriter/MessageEventBusLogWriter';
|
import { MessageEventBusLogWriter } from '../MessageEventBusWriter/MessageEventBusLogWriter';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { messageEventBusDestinationFromDb } from '../MessageEventBusDestination/MessageEventBusDestinationFromDb';
|
import { messageEventBusDestinationFromDb } from '../MessageEventBusDestination/MessageEventBusDestinationFromDb';
|
||||||
import uniqby from 'lodash/uniqBy';
|
import uniqby from 'lodash/uniqBy';
|
||||||
import type { EventMessageConfirmSource } from '../EventMessageClasses/EventMessageConfirm';
|
import type { EventMessageConfirmSource } from '../EventMessageClasses/EventMessageConfirm';
|
||||||
|
@ -29,11 +28,13 @@ import {
|
||||||
import { recoverExecutionDataFromEventLogMessages } from './recoverEvents';
|
import { recoverExecutionDataFromEventLogMessages } from './recoverEvents';
|
||||||
import { METRICS_EVENT_NAME } from '../MessageEventBusDestination/Helpers.ee';
|
import { METRICS_EVENT_NAME } from '../MessageEventBusDestination/Helpers.ee';
|
||||||
import { Container, Service } from 'typedi';
|
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 type { AbstractEventMessageOptions } from '../EventMessageClasses/AbstractEventMessageOptions';
|
||||||
import { getEventMessageObjectByType } from '../EventMessageClasses/Helpers';
|
import { getEventMessageObjectByType } from '../EventMessageClasses/Helpers';
|
||||||
import { SingleMainInstancePublisher } from '@/services/orchestration/main/SingleMainInstance.publisher';
|
import { SingleMainInstancePublisher } from '@/services/orchestration/main/SingleMainInstance.publisher';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
import { EventDestinationsRepository } from '@db/repositories/eventDestinations.repository';
|
||||||
|
|
||||||
export type EventMessageReturnMode = 'sent' | 'unsent' | 'all' | 'unfinished';
|
export type EventMessageReturnMode = 'sent' | 'unsent' | 'all' | 'unfinished';
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ export class MessageEventBus extends EventEmitter {
|
||||||
|
|
||||||
this.logger.debug('Initializing event bus...');
|
this.logger.debug('Initializing event bus...');
|
||||||
|
|
||||||
const savedEventDestinations = await Db.collections.EventDestinations.find({});
|
const savedEventDestinations = await Container.get(EventDestinationsRepository).find({});
|
||||||
if (savedEventDestinations.length > 0) {
|
if (savedEventDestinations.length > 0) {
|
||||||
for (const destinationData of savedEventDestinations) {
|
for (const destinationData of savedEventDestinations) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Push } from '@/push';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import { getWorkflowHooksMain } from '@/WorkflowExecuteAdditionalData';
|
import { getWorkflowHooksMain } from '@/WorkflowExecuteAdditionalData';
|
||||||
import { ExecutionRepository } from '@db/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
|
|
||||||
export async function recoverExecutionDataFromEventLogMessages(
|
export async function recoverExecutionDataFromEventLogMessages(
|
||||||
executionId: string,
|
executionId: string,
|
||||||
|
|
|
@ -6,13 +6,13 @@ import {
|
||||||
MessageEventBusDestinationTypeNames,
|
MessageEventBusDestinationTypeNames,
|
||||||
MessageEventBusDestinationOptions,
|
MessageEventBusDestinationOptions,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
import type { AbstractEventMessage } from '../EventMessageClasses/AbstractEventMessage';
|
import type { AbstractEventMessage } from '../EventMessageClasses/AbstractEventMessage';
|
||||||
import type { EventMessageTypes } from '../EventMessageClasses';
|
import type { EventMessageTypes } from '../EventMessageClasses';
|
||||||
import type { EventMessageConfirmSource } from '../EventMessageClasses/EventMessageConfirm';
|
import type { EventMessageConfirmSource } from '../EventMessageClasses/EventMessageConfirm';
|
||||||
import { MessageEventBus } from '../MessageEventBus/MessageEventBus';
|
import { MessageEventBus } from '../MessageEventBus/MessageEventBus';
|
||||||
import type { MessageWithCallback } from '../MessageEventBus/MessageEventBus';
|
import type { MessageWithCallback } from '../MessageEventBus/MessageEventBus';
|
||||||
|
import { EventDestinationsRepository } from '@db/repositories/eventDestinations.repository';
|
||||||
|
|
||||||
export abstract class MessageEventBusDestination implements MessageEventBusDestinationOptions {
|
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.
|
// 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(),
|
id: this.getId(),
|
||||||
destination: this.serialize(),
|
destination: this.serialize(),
|
||||||
};
|
};
|
||||||
const dbResult: InsertResult = await Db.collections.EventDestinations.upsert(data, {
|
const dbResult: InsertResult = await Container.get(EventDestinationsRepository).upsert(data, {
|
||||||
skipUpdateIfNoValuesChanged: true,
|
skipUpdateIfNoValuesChanged: true,
|
||||||
conflictPaths: ['id'],
|
conflictPaths: ['id'],
|
||||||
});
|
});
|
||||||
|
@ -108,7 +108,7 @@ export abstract class MessageEventBusDestination implements MessageEventBusDesti
|
||||||
}
|
}
|
||||||
|
|
||||||
static async deleteFromDb(id: string): Promise<DeleteResult> {
|
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;
|
return dbResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { MessageEventBusDestinationTypeNames } from 'n8n-workflow';
|
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 { MessageEventBus } from '../MessageEventBus/MessageEventBus';
|
||||||
import type { MessageEventBusDestination } from './MessageEventBusDestination.ee';
|
import type { MessageEventBusDestination } from './MessageEventBusDestination.ee';
|
||||||
import { MessageEventBusDestinationSentry } from './MessageEventBusDestinationSentry.ee';
|
import { MessageEventBusDestinationSentry } from './MessageEventBusDestinationSentry.ee';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { ExecutionStatus, IRun, IWorkflowBase } from 'n8n-workflow';
|
||||||
import type { ExecutionPayload, IExecutionDb } from '@/Interfaces';
|
import type { ExecutionPayload, IExecutionDb } from '@/Interfaces';
|
||||||
import pick from 'lodash/pick';
|
import pick from 'lodash/pick';
|
||||||
import { isWorkflowIdValid } from '@/utils';
|
import { isWorkflowIdValid } from '@/utils';
|
||||||
import { ExecutionRepository } from '@db/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
import { ExecutionMetadataService } from '@/services/executionMetadata.service';
|
import { ExecutionMetadataService } from '@/services/executionMetadata.service';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,11 @@ import type { ExecutionRequest } from '@/requests';
|
||||||
import * as ResponseHelper from '@/ResponseHelper';
|
import * as ResponseHelper from '@/ResponseHelper';
|
||||||
import { getSharedWorkflowIds } from '@/WorkflowHelpers';
|
import { getSharedWorkflowIds } from '@/WorkflowHelpers';
|
||||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import * as GenericHelpers from '@/GenericHelpers';
|
import * as GenericHelpers from '@/GenericHelpers';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { getStatusUsingPreviousExecutionStatusMethod } from './executionHelpers';
|
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';
|
import { Logger } from '@/Logger';
|
||||||
|
|
||||||
export interface IGetExecutionsQueryFilter {
|
export interface IGetExecutionsQueryFilter {
|
||||||
|
@ -274,7 +274,7 @@ export class ExecutionsService {
|
||||||
// Loads the currently saved workflow to execute instead of the
|
// Loads the currently saved workflow to execute instead of the
|
||||||
// one saved at the time of the execution.
|
// one saved at the time of the execution.
|
||||||
const workflowId = execution.workflowData.id as string;
|
const workflowId = execution.workflowData.id as string;
|
||||||
const workflowData = (await Db.collections.Workflow.findOneBy({
|
const workflowData = (await Container.get(WorkflowRepository).findOneBy({
|
||||||
id: workflowId,
|
id: workflowId,
|
||||||
})) as IWorkflowBase;
|
})) as IWorkflowBase;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import type { ILicenseReadResponse } from '@/Interfaces';
|
import type { ILicenseReadResponse } from '@/Interfaces';
|
||||||
import * as Db from '@/Db';
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
|
||||||
export class LicenseService {
|
export class LicenseService {
|
||||||
static async getActiveTriggerCount(): Promise<number> {
|
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;
|
return totalTriggerCount ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
|
||||||
import { assert, jsonStringify } from 'n8n-workflow';
|
import { assert, jsonStringify } from 'n8n-workflow';
|
||||||
import type { IPushDataType } from '@/Interfaces';
|
import type { IPushDataType } from '@/Interfaces';
|
||||||
import { Logger } from '@/Logger';
|
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.
|
* Abstract class for two-way push communication.
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { SSEPush } from './sse.push';
|
||||||
import { WebSocketPush } from './websocket.push';
|
import { WebSocketPush } from './websocket.push';
|
||||||
import type { PushResponse, SSEPushRequest, WebSocketPushRequest } from './types';
|
import type { PushResponse, SSEPushRequest, WebSocketPushRequest } from './types';
|
||||||
import type { IPushDataType } from '@/Interfaces';
|
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';
|
const useWebSockets = config.getEnv('push.backend') === 'websocket';
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Service } from 'typedi';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
import { AbstractPush } from './abstract.push';
|
import { AbstractPush } from './abstract.push';
|
||||||
import type { PushRequest, PushResponse } from './types';
|
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 };
|
type Connection = { req: PushRequest; res: PushResponse };
|
||||||
|
|
||||||
|
|
|
@ -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 { Request, Response } from 'express';
|
||||||
import type { WebSocket } from 'ws';
|
import type { WebSocket } from 'ws';
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import type WebSocket from 'ws';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
import { AbstractPush } from './abstract.push';
|
import { AbstractPush } from './abstract.push';
|
||||||
import type { User } from '@/databases/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
|
|
||||||
function heartbeat(this: WebSocket) {
|
function heartbeat(this: WebSocket) {
|
||||||
this.isAlive = true;
|
this.isAlive = true;
|
||||||
|
|
|
@ -26,9 +26,9 @@ import type { Role } from '@db/entities/Role';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import type { UserManagementMailer } from '@/UserManagement/email';
|
import type { UserManagementMailer } from '@/UserManagement/email';
|
||||||
import type { Variables } from '@db/entities/Variables';
|
import type { Variables } from '@db/entities/Variables';
|
||||||
import type { WorkflowEntity } from './databases/entities/WorkflowEntity';
|
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import type { CredentialsEntity } from './databases/entities/CredentialsEntity';
|
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
import type { WorkflowHistory } from './databases/entities/WorkflowHistory';
|
import type { WorkflowHistory } from '@db/entities/WorkflowHistory';
|
||||||
|
|
||||||
export class UserUpdatePayload implements Pick<User, 'email' | 'firstName' | 'lastName'> {
|
export class UserUpdatePayload implements Pick<User, 'email' | 'firstName' | 'lastName'> {
|
||||||
@IsEmail()
|
@IsEmail()
|
||||||
|
|
|
@ -10,8 +10,8 @@ import { InstanceSettings } from 'n8n-core';
|
||||||
import type { PackageDirectoryLoader } from 'n8n-core';
|
import type { PackageDirectoryLoader } from 'n8n-core';
|
||||||
|
|
||||||
import { toError } from '@/utils';
|
import { toError } from '@/utils';
|
||||||
import { InstalledPackagesRepository } from '@/databases/repositories/installedPackages.repository';
|
import { InstalledPackagesRepository } from '@db/repositories/installedPackages.repository';
|
||||||
import type { InstalledPackages } from '@/databases/entities/InstalledPackages';
|
import type { InstalledPackages } from '@db/entities/InstalledPackages';
|
||||||
import {
|
import {
|
||||||
NODE_PACKAGE_PREFIX,
|
NODE_PACKAGE_PREFIX,
|
||||||
NPM_COMMAND_TOKENS,
|
NPM_COMMAND_TOKENS,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
|
||||||
import { Container, Service } from 'typedi';
|
import { Container, Service } from 'typedi';
|
||||||
import type { INode, IRun, IWorkflowBase } from 'n8n-workflow';
|
import type { INode, IRun, IWorkflowBase } from 'n8n-workflow';
|
||||||
import { StatisticsNames } from '@db/entities/WorkflowStatistics';
|
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 { UserService } from '@/services/user.service';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
import { OwnershipService } from './ownership.service';
|
import { OwnershipService } from './ownership.service';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { ExecutionMetadataRepository } from '@/databases/repositories';
|
|
||||||
import { Service } from 'typedi';
|
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()
|
@Service()
|
||||||
export class ExecutionMetadataService {
|
export class ExecutionMetadataService {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { CacheService } from './cache.service';
|
import { CacheService } from './cache.service';
|
||||||
import { SharedWorkflowRepository } from '@/databases/repositories';
|
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||||
import type { User } from '@/databases/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import { RoleService } from './role.service';
|
import { RoleService } from './role.service';
|
||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
import type { Credentials, ListQuery } from '@/requests';
|
import type { Credentials, ListQuery } from '@/requests';
|
||||||
import type { Role } from '@/databases/entities/Role';
|
import type { Role } from '@db/entities/Role';
|
||||||
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
|
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class OwnershipService {
|
export class OwnershipService {
|
||||||
|
|
|
@ -6,9 +6,9 @@ import type { FindOptionsWhere } from 'typeorm';
|
||||||
|
|
||||||
import { TIME, inTest } from '@/constants';
|
import { TIME, inTest } from '@/constants';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { ExecutionRepository } from '@/databases/repositories';
|
import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
import { ExecutionEntity } from '@/databases/entities/ExecutionEntity';
|
import { ExecutionEntity } from '@db/entities/ExecutionEntity';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class PruningService {
|
export class PruningService {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { RoleRepository, SharedWorkflowRepository } from '@/databases/repositories';
|
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
|
import { RoleRepository } from '@db/repositories/role.repository';
|
||||||
|
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||||
import { CacheService } from './cache.service';
|
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 {}
|
class InvalidRoleError extends Error {}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { TagRepository } from '@/databases/repositories';
|
import { TagRepository } from '@db/repositories/tag.repository';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { validateEntity } from '@/GenericHelpers';
|
import { validateEntity } from '@/GenericHelpers';
|
||||||
import type { ITagToImport, ITagWithCountDb, IWorkflowToImport } from '@/Interfaces';
|
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 { EntityManager, FindManyOptions, FindOneOptions } from 'typeorm';
|
||||||
import type { UpsertOptions } from 'typeorm/repository/UpsertOptions';
|
import type { UpsertOptions } from 'typeorm/repository/UpsertOptions';
|
||||||
import { ExternalHooks } from '@/ExternalHooks';
|
import { ExternalHooks } from '@/ExternalHooks';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { EntityManager, FindManyOptions, FindOneOptions, FindOptionsWhere }
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import { User } from '@db/entities/User';
|
import { User } from '@db/entities/User';
|
||||||
import type { IUserSettings } from 'n8n-workflow';
|
import type { IUserSettings } from 'n8n-workflow';
|
||||||
import { UserRepository } from '@/databases/repositories';
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
||||||
import type { PublicUser } from '@/Interfaces';
|
import type { PublicUser } from '@/Interfaces';
|
||||||
import type { PostHogClient } from '@/posthog';
|
import type { PostHogClient } from '@/posthog';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { WebhookRepository } from '@/databases/repositories';
|
import { WebhookRepository } from '@db/repositories/webhook.repository';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { CacheService } from './cache.service';
|
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 { IHttpRequestMethods } from 'n8n-workflow';
|
||||||
import type { DeepPartial } from 'typeorm';
|
import type { DeepPartial } from 'typeorm';
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type express from 'express';
|
import type express from 'express';
|
||||||
import { Service } from 'typedi';
|
import Container, { Service } from 'typedi';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { jsonParse } from 'n8n-workflow';
|
||||||
import { AuthError, BadRequestError } from '@/ResponseHelper';
|
import { AuthError, BadRequestError } from '@/ResponseHelper';
|
||||||
|
@ -28,6 +27,8 @@ import type { SamlLoginBinding } from './types';
|
||||||
import { validateMetadata, validateResponse } from './samlValidator';
|
import { validateMetadata, validateResponse } from './samlValidator';
|
||||||
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
import { UserRepository } from '@db/repositories/user.repository';
|
||||||
|
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class SamlService {
|
export class SamlService {
|
||||||
|
@ -167,7 +168,7 @@ export class SamlService {
|
||||||
const attributes = await this.getAttributesFromLoginResponse(req, binding);
|
const attributes = await this.getAttributesFromLoginResponse(req, binding);
|
||||||
if (attributes.email) {
|
if (attributes.email) {
|
||||||
const lowerCasedEmail = attributes.email.toLowerCase();
|
const lowerCasedEmail = attributes.email.toLowerCase();
|
||||||
const user = await Db.collections.User.findOne({
|
const user = await Container.get(UserRepository).findOne({
|
||||||
where: { email: lowerCasedEmail },
|
where: { email: lowerCasedEmail },
|
||||||
relations: ['globalRole', 'authIdentities'],
|
relations: ['globalRole', 'authIdentities'],
|
||||||
});
|
});
|
||||||
|
@ -257,7 +258,7 @@ export class SamlService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadFromDbAndApplySamlPreferences(apply = true): Promise<SamlPreferences | undefined> {
|
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 },
|
where: { key: SAML_PREFERENCES_DB_KEY },
|
||||||
});
|
});
|
||||||
if (samlPreferences) {
|
if (samlPreferences) {
|
||||||
|
@ -275,16 +276,16 @@ export class SamlService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveSamlPreferencesToDb(): Promise<SamlPreferences | undefined> {
|
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 },
|
where: { key: SAML_PREFERENCES_DB_KEY },
|
||||||
});
|
});
|
||||||
const settingsValue = JSON.stringify(this.samlPreferences);
|
const settingsValue = JSON.stringify(this.samlPreferences);
|
||||||
let result: Settings;
|
let result: Settings;
|
||||||
if (samlPreferences) {
|
if (samlPreferences) {
|
||||||
samlPreferences.value = settingsValue;
|
samlPreferences.value = settingsValue;
|
||||||
result = await Db.collections.Settings.save(samlPreferences);
|
result = await Container.get(SettingsRepository).save(samlPreferences);
|
||||||
} else {
|
} else {
|
||||||
result = await Db.collections.Settings.save({
|
result = await Container.get(SettingsRepository).save({
|
||||||
key: SAML_PREFERENCES_DB_KEY,
|
key: SAML_PREFERENCES_DB_KEY,
|
||||||
value: settingsValue,
|
value: settingsValue,
|
||||||
loadOnStartup: true,
|
loadOnStartup: true,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||||
import { User } from '@db/entities/User';
|
import { User } from '@db/entities/User';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
|
@ -20,6 +19,8 @@ import {
|
||||||
import { getServiceProviderConfigTestReturnUrl } from './serviceProvider.ee';
|
import { getServiceProviderConfigTestReturnUrl } from './serviceProvider.ee';
|
||||||
import type { SamlConfiguration } from './types/requests';
|
import type { SamlConfiguration } from './types/requests';
|
||||||
import { RoleService } from '@/services/role.service';
|
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
|
* 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.providerId = attributes.userPrincipalName;
|
||||||
authIdentity.providerType = 'saml';
|
authIdentity.providerType = 'saml';
|
||||||
authIdentity.user = user;
|
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');
|
if (!resultAuthIdentity) throw new AuthError('Could not create AuthIdentity');
|
||||||
user.authIdentities = [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');
|
if (!resultUser) throw new AuthError('Could not create User');
|
||||||
return resultUser;
|
return resultUser;
|
||||||
}
|
}
|
||||||
|
@ -131,10 +132,10 @@ export async function updateUserFromSamlAttributes(
|
||||||
} else {
|
} else {
|
||||||
samlAuthIdentity.providerId = attributes.userPrincipalName;
|
samlAuthIdentity.providerId = attributes.userPrincipalName;
|
||||||
}
|
}
|
||||||
await Db.collections.AuthIdentity.save(samlAuthIdentity);
|
await Container.get(AuthIdentityRepository).save(samlAuthIdentity);
|
||||||
user.firstName = attributes.firstName;
|
user.firstName = attributes.firstName;
|
||||||
user.lastName = attributes.lastName;
|
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');
|
if (!resultUser) throw new AuthError('Could not create User');
|
||||||
return resultUser;
|
return resultUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||||
import type { AuthProviderType } from '@db/entities/AuthIdentity';
|
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
|
* 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,
|
authenticationMethod: AuthProviderType,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
config.set('userManagement.authenticationMethod', authenticationMethod);
|
config.set('userManagement.authenticationMethod', authenticationMethod);
|
||||||
await Db.collections.Settings.save({
|
await Container.get(SettingsRepository).save({
|
||||||
key: 'userManagement.authenticationMethod',
|
key: 'userManagement.authenticationMethod',
|
||||||
value: authenticationMethod,
|
value: authenticationMethod,
|
||||||
loadOnStartup: true,
|
loadOnStartup: true,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import type { SharedWorkflow } from '@/databases/entities/SharedWorkflow';
|
import type { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||||
import type { User } from '@/databases/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import type { WorkflowEntity } from '@/databases/entities/WorkflowEntity';
|
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||||
import type { WorkflowHistory } from '@/databases/entities/WorkflowHistory';
|
import type { WorkflowHistory } from '@db/entities/WorkflowHistory';
|
||||||
import { SharedWorkflowRepository } from '@/databases/repositories';
|
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||||
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
|
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';
|
import { isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { LessThan } from 'typeorm';
|
import { LessThan } from 'typeorm';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
|
||||||
import { WORKFLOW_HISTORY_PRUNE_INTERVAL } from './constants';
|
import { WORKFLOW_HISTORY_PRUNE_INTERVAL } from './constants';
|
||||||
import { getWorkflowHistoryPruneTime, isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';
|
import { getWorkflowHistoryPruneTime, isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { listQueryMiddleware } from '@/middlewares';
|
||||||
import { TagService } from '@/services/tag.service';
|
import { TagService } from '@/services/tag.service';
|
||||||
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
|
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
|
||||||
import { Logger } from '@/Logger';
|
import { Logger } from '@/Logger';
|
||||||
|
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||||
|
|
||||||
export const workflowsController = express.Router();
|
export const workflowsController = express.Router();
|
||||||
workflowsController.use('/', EEWorkflowController);
|
workflowsController.use('/', EEWorkflowController);
|
||||||
|
@ -205,7 +206,7 @@ workflowsController.get(
|
||||||
relations = relations.filter((relation) => relation !== 'workflow.tags');
|
relations = relations.filter((relation) => relation !== 'workflow.tags');
|
||||||
}
|
}
|
||||||
|
|
||||||
const shared = await Db.collections.SharedWorkflow.findOne({
|
const shared = await Container.get(SharedWorkflowRepository).findOne({
|
||||||
relations,
|
relations,
|
||||||
where: whereClause({
|
where: whereClause({
|
||||||
user: req.user,
|
user: req.user,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { DeleteResult, EntityManager } from 'typeorm';
|
import type { DeleteResult, EntityManager } from 'typeorm';
|
||||||
import { In, Not } from 'typeorm';
|
import { In, Not } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import * as ResponseHelper from '@/ResponseHelper';
|
import * as ResponseHelper from '@/ResponseHelper';
|
||||||
import * as WorkflowHelpers from '@/WorkflowHelpers';
|
import * as WorkflowHelpers from '@/WorkflowHelpers';
|
||||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||||
|
@ -16,7 +15,8 @@ import { CredentialsService } from '@/credentials/credentials.service';
|
||||||
import { NodeOperationError } from 'n8n-workflow';
|
import { NodeOperationError } from 'n8n-workflow';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import Container from 'typedi';
|
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 {
|
export class EEWorkflowsService extends WorkflowsService {
|
||||||
static async isOwned(
|
static async isOwned(
|
||||||
|
@ -73,7 +73,7 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
roleId: role?.id,
|
roleId: role?.id,
|
||||||
};
|
};
|
||||||
acc.push(Db.collections.SharedWorkflow.create(entity));
|
acc.push(Container.get(SharedWorkflowRepository).create(entity));
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { In, Like } from 'typeorm';
|
||||||
import pick from 'lodash/pick';
|
import pick from 'lodash/pick';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import * as ResponseHelper from '@/ResponseHelper';
|
import * as ResponseHelper from '@/ResponseHelper';
|
||||||
import * as WorkflowHelpers from '@/WorkflowHelpers';
|
import * as WorkflowHelpers from '@/WorkflowHelpers';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
@ -24,13 +23,16 @@ import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'
|
||||||
import { TestWebhooks } from '@/TestWebhooks';
|
import { TestWebhooks } from '@/TestWebhooks';
|
||||||
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import { WorkflowRepository } from '@/databases/repositories';
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import { OwnershipService } from '@/services/ownership.service';
|
import { OwnershipService } from '@/services/ownership.service';
|
||||||
import { isStringArray, isWorkflowIdValid } from '@/utils';
|
import { isStringArray, isWorkflowIdValid } from '@/utils';
|
||||||
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
|
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
|
||||||
import { BinaryDataService } from 'n8n-core';
|
import { BinaryDataService } from 'n8n-core';
|
||||||
import { Logger } from '@/Logger';
|
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 {
|
export class WorkflowsService {
|
||||||
static async getSharing(
|
static async getSharing(
|
||||||
|
@ -48,7 +50,7 @@ export class WorkflowsService {
|
||||||
where.userId = user.id;
|
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[] }) {
|
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) {
|
static async getMany(sharedWorkflowIds: string[], options?: ListQuery.Options) {
|
||||||
|
@ -186,7 +191,7 @@ export class WorkflowsService {
|
||||||
forceSave?: boolean,
|
forceSave?: boolean,
|
||||||
roles?: string[],
|
roles?: string[],
|
||||||
): Promise<WorkflowEntity> {
|
): Promise<WorkflowEntity> {
|
||||||
const shared = await Db.collections.SharedWorkflow.findOne({
|
const shared = await Container.get(SharedWorkflowRepository).findOne({
|
||||||
relations: ['workflow', 'role'],
|
relations: ['workflow', 'role'],
|
||||||
where: whereClause({
|
where: whereClause({
|
||||||
user,
|
user,
|
||||||
|
@ -282,7 +287,7 @@ export class WorkflowsService {
|
||||||
await validateEntity(workflow);
|
await validateEntity(workflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Db.collections.Workflow.update(
|
await Container.get(WorkflowRepository).update(
|
||||||
workflowId,
|
workflowId,
|
||||||
pick(workflow, [
|
pick(workflow, [
|
||||||
'name',
|
'name',
|
||||||
|
@ -297,8 +302,8 @@ export class WorkflowsService {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (tagIds && !config.getEnv('workflowTagsDisabled')) {
|
if (tagIds && !config.getEnv('workflowTagsDisabled')) {
|
||||||
await Db.collections.WorkflowTagMapping.delete({ workflowId });
|
await Container.get(WorkflowTagMappingRepository).delete({ workflowId });
|
||||||
await Db.collections.WorkflowTagMapping.insert(
|
await Container.get(WorkflowTagMappingRepository).insert(
|
||||||
tagIds.map((tagId) => ({ tagId, workflowId })),
|
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
|
// We sadly get nothing back from "update". Neither if it updated a record
|
||||||
// nor the new value. So query now the hopefully updated entry.
|
// 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 },
|
where: { id: workflowId },
|
||||||
relations,
|
relations,
|
||||||
});
|
});
|
||||||
|
@ -342,7 +347,7 @@ export class WorkflowsService {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If workflow could not be activated set it again to inactive
|
// If workflow could not be activated set it again to inactive
|
||||||
// and revert the versionId change so UI remains consistent
|
// and revert the versionId change so UI remains consistent
|
||||||
await Db.collections.Workflow.update(workflowId, {
|
await Container.get(WorkflowRepository).update(workflowId, {
|
||||||
active: false,
|
active: false,
|
||||||
versionId: shared.workflow.versionId,
|
versionId: shared.workflow.versionId,
|
||||||
});
|
});
|
||||||
|
@ -447,7 +452,7 @@ export class WorkflowsService {
|
||||||
static async delete(user: User, workflowId: string): Promise<WorkflowEntity | undefined> {
|
static async delete(user: User, workflowId: string): Promise<WorkflowEntity | undefined> {
|
||||||
await Container.get(ExternalHooks).run('workflow.delete', [workflowId]);
|
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'],
|
relations: ['workflow', 'role'],
|
||||||
where: whereClause({
|
where: whereClause({
|
||||||
user,
|
user,
|
||||||
|
@ -466,12 +471,14 @@ export class WorkflowsService {
|
||||||
await Container.get(ActiveWorkflowRunner).remove(workflowId);
|
await Container.get(ActiveWorkflowRunner).remove(workflowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const idsForDeletion = await Db.collections.Execution.find({
|
const idsForDeletion = await Container.get(ExecutionRepository)
|
||||||
select: ['id'],
|
.find({
|
||||||
where: { workflowId },
|
select: ['id'],
|
||||||
}).then((rows) => rows.map(({ id: executionId }) => ({ workflowId, executionId })));
|
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);
|
await Container.get(BinaryDataService).deleteMany(idsForDeletion);
|
||||||
|
|
||||||
void Container.get(InternalHooks).onWorkflowDeleted(user, workflowId, false);
|
void Container.get(InternalHooks).onWorkflowDeleted(user, workflowId, false);
|
||||||
|
@ -481,7 +488,7 @@ export class WorkflowsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async updateWorkflowTriggerCount(id: string, triggerCount: number): Promise<UpdateResult> {
|
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
|
return qb
|
||||||
.update()
|
.update()
|
||||||
.set({
|
.set({
|
||||||
|
@ -527,7 +534,7 @@ export class WorkflowsService {
|
||||||
* @param {IDataObject} newStaticData The static data to save
|
* @param {IDataObject} newStaticData The static data to save
|
||||||
*/
|
*/
|
||||||
static async saveStaticDataById(workflowId: string, newStaticData: IDataObject): Promise<void> {
|
static async saveStaticDataById(workflowId: string, newStaticData: IDataObject): Promise<void> {
|
||||||
await Db.collections.Workflow.update(workflowId, {
|
await Container.get(WorkflowRepository).update(workflowId, {
|
||||||
staticData: newStaticData,
|
staticData: newStaticData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,15 @@ import { WebhookService } from '@/services/webhook.service';
|
||||||
import * as WebhookHelpers from '@/WebhookHelpers';
|
import * as WebhookHelpers from '@/WebhookHelpers';
|
||||||
import * as AdditionalData from '@/WorkflowExecuteAdditionalData';
|
import * as AdditionalData from '@/WorkflowExecuteAdditionalData';
|
||||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||||
|
import type { User } from '@db/entities/User';
|
||||||
import { mockInstance, setSchedulerAsLoadedNode } from './shared/utils';
|
import type { WebhookEntity } from '@db/entities/WebhookEntity';
|
||||||
import * as testDb from './shared/testDb';
|
|
||||||
import type { User } from '@/databases/entities/User';
|
|
||||||
import type { WebhookEntity } from '@/databases/entities/WebhookEntity';
|
|
||||||
import { NodeTypes } from '@/NodeTypes';
|
import { NodeTypes } from '@/NodeTypes';
|
||||||
import { chooseRandomly } from './shared/random';
|
|
||||||
import { MultiMainInstancePublisher } from '@/services/orchestration/main/MultiMainInstance.publisher.ee';
|
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 { createOwner } from './shared/db/users';
|
||||||
import { createWorkflow } from './shared/db/workflows';
|
import { createWorkflow } from './shared/db/workflows';
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,38 @@
|
||||||
import type { SuperAgentTest } from 'supertest';
|
import type { SuperAgentTest } from 'supertest';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import * as utils from '../shared/utils/';
|
|
||||||
import type { ExternalSecretsSettings, SecretsProviderState } from '@/Interfaces';
|
import type { ExternalSecretsSettings, SecretsProviderState } from '@/Interfaces';
|
||||||
import { Cipher } from 'n8n-core';
|
import { Cipher } from 'n8n-core';
|
||||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { ExternalSecretsProviders } from '@/ExternalSecrets/ExternalSecretsProviders.ee';
|
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 {
|
import {
|
||||||
DummyProvider,
|
DummyProvider,
|
||||||
FailedProvider,
|
FailedProvider,
|
||||||
MockProviders,
|
MockProviders,
|
||||||
TestFailProvider,
|
TestFailProvider,
|
||||||
} from '../../shared/ExternalSecrets/utils';
|
} 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 authOwnerAgent: SuperAgentTest;
|
||||||
let authMemberAgent: SuperAgentTest;
|
let authMemberAgent: SuperAgentTest;
|
||||||
|
|
||||||
const licenseLike = utils.mockInstance(License, {
|
const licenseLike = mockInstance(License, {
|
||||||
isExternalSecretsEnabled: jest.fn().mockReturnValue(true),
|
isExternalSecretsEnabled: jest.fn().mockReturnValue(true),
|
||||||
isWithinUsersLimit: jest.fn().mockReturnValue(true),
|
isWithinUsersLimit: jest.fn().mockReturnValue(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockProvidersInstance = new MockProviders();
|
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';
|
const connectedDate = '2023-08-01T12:32:29.000Z';
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { audit } from '@/audit';
|
import { audit } from '@/audit';
|
||||||
import { CREDENTIALS_REPORT } from '@/audit/constants';
|
import { CREDENTIALS_REPORT } from '@/audit/constants';
|
||||||
import { getRiskSection } from './utils';
|
import { getRiskSection } from './utils';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
import { generateNanoId } from '@db/utils/generators';
|
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 () => {
|
beforeAll(async () => {
|
||||||
await testDb.init();
|
await testDb.init();
|
||||||
|
@ -46,8 +50,8 @@ test('should report credentials not in any use', async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
Db.collections.Credentials.save(credentialDetails),
|
Container.get(CredentialsRepository).save(credentialDetails),
|
||||||
Db.collections.Workflow.save(workflowDetails),
|
Container.get(WorkflowRepository).save(workflowDetails),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const testAudit = await audit(['credentials']);
|
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' }],
|
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 = {
|
const workflowDetails = {
|
||||||
id: generateNanoId(),
|
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']);
|
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' }],
|
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 = {
|
const workflowDetails = {
|
||||||
id: generateNanoId(),
|
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();
|
const date = new Date();
|
||||||
date.setDate(date.getDate() - config.getEnv('security.audit.daysAbandonedWorkflow') - 1);
|
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,
|
finished: true,
|
||||||
mode: 'manual',
|
mode: 'manual',
|
||||||
startedAt: date,
|
startedAt: date,
|
||||||
|
@ -157,7 +161,7 @@ test('should report credential in not recently executed workflow', async () => {
|
||||||
workflowId: workflow.id,
|
workflowId: workflow.id,
|
||||||
waitTill: null,
|
waitTill: null,
|
||||||
});
|
});
|
||||||
await Db.collections.ExecutionData.save({
|
await Container.get(ExecutionDataRepository).save({
|
||||||
execution: savedExecution,
|
execution: savedExecution,
|
||||||
data: '[]',
|
data: '[]',
|
||||||
workflowData: workflow,
|
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' }],
|
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 = {
|
const workflowDetails = {
|
||||||
id: generateNanoId(),
|
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();
|
const date = new Date();
|
||||||
date.setDate(date.getDate() - config.getEnv('security.audit.daysAbandonedWorkflow') + 1);
|
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,
|
finished: true,
|
||||||
mode: 'manual',
|
mode: 'manual',
|
||||||
startedAt: date,
|
startedAt: date,
|
||||||
|
@ -226,7 +230,7 @@ test('should not report credentials in recently executed workflow', async () =>
|
||||||
waitTill: null,
|
waitTill: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
await Db.collections.ExecutionData.save({
|
await Container.get(ExecutionDataRepository).save({
|
||||||
execution: savedExecution,
|
execution: savedExecution,
|
||||||
data: '[]',
|
data: '[]',
|
||||||
workflowData: workflow,
|
workflowData: workflow,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { audit } from '@/audit';
|
import { audit } from '@/audit';
|
||||||
import {
|
import {
|
||||||
DATABASE_REPORT,
|
DATABASE_REPORT,
|
||||||
|
@ -9,6 +8,8 @@ import {
|
||||||
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
|
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
import { generateNanoId } from '@db/utils/generators';
|
import { generateNanoId } from '@db/utils/generators';
|
||||||
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await testDb.init();
|
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);
|
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);
|
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);
|
await Promise.all(promises);
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { audit } from '@/audit';
|
import { audit } from '@/audit';
|
||||||
import { FILESYSTEM_INTERACTION_NODE_TYPES, FILESYSTEM_REPORT } from '@/audit/constants';
|
import { FILESYSTEM_INTERACTION_NODE_TYPES, FILESYSTEM_REPORT } from '@/audit/constants';
|
||||||
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
|
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await testDb.init();
|
await testDb.init();
|
||||||
|
@ -26,7 +27,7 @@ test('should report filesystem interaction nodes', async () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const promises = Object.entries(map).map(async ([nodeType, nodeId]) => {
|
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',
|
name: 'My Test Workflow',
|
||||||
active: false,
|
active: false,
|
||||||
connections: {},
|
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);
|
await Promise.all(promises);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { audit } from '@/audit';
|
import { audit } from '@/audit';
|
||||||
import { INSTANCE_REPORT, WEBHOOK_VALIDATOR_NODE_TYPES } from '@/audit/constants';
|
import { INSTANCE_REPORT, WEBHOOK_VALIDATOR_NODE_TYPES } from '@/audit/constants';
|
||||||
import {
|
import {
|
||||||
|
@ -13,6 +12,8 @@ import * as testDb from '../shared/testDb';
|
||||||
import { toReportTitle } from '@/audit/utils';
|
import { toReportTitle } from '@/audit/utils';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { generateNanoId } from '@db/utils/generators';
|
import { generateNanoId } from '@db/utils/generators';
|
||||||
|
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await testDb.init();
|
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']);
|
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);
|
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);
|
await Promise.all(promises);
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import * as Db from '@/Db';
|
|
||||||
import { audit } from '@/audit';
|
import { audit } from '@/audit';
|
||||||
import { OFFICIAL_RISKY_NODE_TYPES, NODES_REPORT } from '@/audit/constants';
|
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 { toReportTitle } from '@/audit/utils';
|
||||||
import { mockInstance } from '../shared/utils/';
|
|
||||||
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||||
import { NodeTypes } from '@/NodeTypes';
|
import { NodeTypes } from '@/NodeTypes';
|
||||||
import { CommunityPackagesService } from '@/services/communityPackages.service';
|
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);
|
const nodesAndCredentials = mockInstance(LoadNodesAndCredentials);
|
||||||
nodesAndCredentials.getCustomDirectories.mockReturnValue([]);
|
nodesAndCredentials.getCustomDirectories.mockReturnValue([]);
|
||||||
|
@ -37,7 +38,7 @@ test('should report risky official nodes', async () => {
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const promises = Object.entries(map).map(async ([nodeType, nodeId]) => {
|
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',
|
name: 'My Test Workflow',
|
||||||
active: false,
|
active: false,
|
||||||
connections: {},
|
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);
|
await Promise.all(promises);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue