mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-23 10:32:17 -08:00
refactor(core): Use injectable classes for db repositories (part-1) (no-changelog) (#5953)
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
This commit is contained in:
parent
323e26acfd
commit
10f8c35dbb
|
@ -3,14 +3,8 @@
|
|||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable no-case-declarations */
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import type {
|
||||
DataSourceOptions as ConnectionOptions,
|
||||
EntityManager,
|
||||
EntityTarget,
|
||||
LoggerOptions,
|
||||
ObjectLiteral,
|
||||
Repository,
|
||||
} from 'typeorm';
|
||||
import { Container } from 'typedi';
|
||||
import type { DataSourceOptions as ConnectionOptions, EntityManager, LoggerOptions } from 'typeorm';
|
||||
import { DataSource as Connection } from 'typeorm';
|
||||
import type { TlsOptions } from 'tls';
|
||||
import type { DatabaseType, IDatabaseCollections } from '@/Interfaces';
|
||||
|
@ -25,11 +19,31 @@ import {
|
|||
getPostgresConnectionOptions,
|
||||
getSqliteConnectionOptions,
|
||||
} from '@db/config';
|
||||
import {
|
||||
AuthIdentityRepository,
|
||||
AuthProviderSyncHistoryRepository,
|
||||
CredentialsRepository,
|
||||
EventDestinationsRepository,
|
||||
ExecutionMetadataRepository,
|
||||
ExecutionRepository,
|
||||
InstalledNodesRepository,
|
||||
InstalledPackagesRepository,
|
||||
RoleRepository,
|
||||
SettingsRepository,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
TagRepository,
|
||||
UserRepository,
|
||||
WebhookRepository,
|
||||
WorkflowRepository,
|
||||
WorkflowStatisticsRepository,
|
||||
WorkflowTagMappingRepository,
|
||||
} from '@db/repositories';
|
||||
|
||||
export let isInitialized = false;
|
||||
export const collections = {} as IDatabaseCollections;
|
||||
|
||||
export let connection: Connection;
|
||||
let connection: Connection;
|
||||
|
||||
export const getConnection = () => connection!;
|
||||
|
||||
|
@ -37,12 +51,6 @@ export async function transaction<T>(fn: (entityManager: EntityManager) => Promi
|
|||
return connection.transaction(fn);
|
||||
}
|
||||
|
||||
export function linkRepository<Entity extends ObjectLiteral>(
|
||||
entityClass: EntityTarget<Entity>,
|
||||
): Repository<Entity> {
|
||||
return connection.getRepository(entityClass);
|
||||
}
|
||||
|
||||
export function getConnectionOptions(dbType: DatabaseType): ConnectionOptions {
|
||||
switch (dbType) {
|
||||
case 'postgresdb':
|
||||
|
@ -114,6 +122,7 @@ export async function init(
|
|||
});
|
||||
|
||||
connection = new Connection(connectionOptions);
|
||||
Container.set(Connection, connection);
|
||||
await connection.initialize();
|
||||
|
||||
if (dbType === 'postgresdb') {
|
||||
|
@ -148,31 +157,31 @@ export async function init(
|
|||
if (migrations.length === 0) {
|
||||
await connection.destroy();
|
||||
connection = new Connection(connectionOptions);
|
||||
Container.set(Connection, connection);
|
||||
await connection.initialize();
|
||||
}
|
||||
} else {
|
||||
await connection.runMigrations({ transaction: 'each' });
|
||||
}
|
||||
|
||||
collections.Credentials = linkRepository(entities.CredentialsEntity);
|
||||
collections.Execution = linkRepository(entities.ExecutionEntity);
|
||||
collections.Workflow = linkRepository(entities.WorkflowEntity);
|
||||
collections.Webhook = linkRepository(entities.WebhookEntity);
|
||||
collections.Tag = linkRepository(entities.TagEntity);
|
||||
collections.WorkflowTagMapping = linkRepository(entities.WorkflowTagMapping);
|
||||
collections.Role = linkRepository(entities.Role);
|
||||
collections.User = linkRepository(entities.User);
|
||||
collections.AuthIdentity = linkRepository(entities.AuthIdentity);
|
||||
collections.AuthProviderSyncHistory = linkRepository(entities.AuthProviderSyncHistory);
|
||||
collections.SharedCredentials = linkRepository(entities.SharedCredentials);
|
||||
collections.SharedWorkflow = linkRepository(entities.SharedWorkflow);
|
||||
collections.Settings = linkRepository(entities.Settings);
|
||||
collections.InstalledPackages = linkRepository(entities.InstalledPackages);
|
||||
collections.InstalledNodes = linkRepository(entities.InstalledNodes);
|
||||
collections.WorkflowStatistics = linkRepository(entities.WorkflowStatistics);
|
||||
collections.ExecutionMetadata = linkRepository(entities.ExecutionMetadata);
|
||||
|
||||
collections.EventDestinations = linkRepository(entities.EventDestinations);
|
||||
collections.AuthIdentity = Container.get(AuthIdentityRepository);
|
||||
collections.AuthProviderSyncHistory = Container.get(AuthProviderSyncHistoryRepository);
|
||||
collections.Credentials = Container.get(CredentialsRepository);
|
||||
collections.EventDestinations = Container.get(EventDestinationsRepository);
|
||||
collections.Execution = Container.get(ExecutionRepository);
|
||||
collections.ExecutionMetadata = Container.get(ExecutionMetadataRepository);
|
||||
collections.InstalledNodes = Container.get(InstalledNodesRepository);
|
||||
collections.InstalledPackages = Container.get(InstalledPackagesRepository);
|
||||
collections.Role = Container.get(RoleRepository);
|
||||
collections.Settings = Container.get(SettingsRepository);
|
||||
collections.SharedCredentials = Container.get(SharedCredentialsRepository);
|
||||
collections.SharedWorkflow = Container.get(SharedWorkflowRepository);
|
||||
collections.Tag = Container.get(TagRepository);
|
||||
collections.User = Container.get(UserRepository);
|
||||
collections.Webhook = Container.get(WebhookRepository);
|
||||
collections.Workflow = Container.get(WorkflowRepository);
|
||||
collections.WorkflowStatistics = Container.get(WorkflowStatisticsRepository);
|
||||
collections.WorkflowTagMapping = Container.get(WorkflowTagMappingRepository);
|
||||
|
||||
isInitialized = true;
|
||||
|
||||
|
|
|
@ -32,26 +32,35 @@ import type { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
|||
import type { WorkflowExecute } from 'n8n-core';
|
||||
|
||||
import type PCancelable from 'p-cancelable';
|
||||
import type { FindOperator, Repository } from 'typeorm';
|
||||
import type { FindOperator } from 'typeorm';
|
||||
|
||||
import type { ChildProcess } from 'child_process';
|
||||
|
||||
import type { AuthIdentity, AuthProviderType } from '@db/entities/AuthIdentity';
|
||||
import type { AuthProviderSyncHistory } from '@db/entities/AuthProviderSyncHistory';
|
||||
import type { InstalledNodes } from '@db/entities/InstalledNodes';
|
||||
import type { InstalledPackages } from '@db/entities/InstalledPackages';
|
||||
import type { AuthProviderType } from '@db/entities/AuthIdentity';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { Settings } from '@db/entities/Settings';
|
||||
import type { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||
import type { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import type { TagEntity } from '@db/entities/TagEntity';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { WebhookEntity } from '@db/entities/WebhookEntity';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type { WorkflowStatistics } from '@db/entities/WorkflowStatistics';
|
||||
import type { WorkflowTagMapping } from '@db/entities/WorkflowTagMapping';
|
||||
import type { EventDestinations } from '@db/entities/MessageEventBusDestinationEntity';
|
||||
import type { ExecutionMetadata } from '@db/entities/ExecutionMetadata';
|
||||
import type {
|
||||
AuthIdentityRepository,
|
||||
AuthProviderSyncHistoryRepository,
|
||||
CredentialsRepository,
|
||||
EventDestinationsRepository,
|
||||
ExecutionMetadataRepository,
|
||||
ExecutionRepository,
|
||||
InstalledNodesRepository,
|
||||
InstalledPackagesRepository,
|
||||
RoleRepository,
|
||||
SettingsRepository,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
TagRepository,
|
||||
UserRepository,
|
||||
WebhookRepository,
|
||||
WorkflowRepository,
|
||||
WorkflowStatisticsRepository,
|
||||
WorkflowTagMappingRepository,
|
||||
} from '@db/repositories';
|
||||
|
||||
export interface IActivationError {
|
||||
time: number;
|
||||
|
@ -76,24 +85,24 @@ export interface ICredentialsOverwrite {
|
|||
}
|
||||
|
||||
export interface IDatabaseCollections {
|
||||
AuthIdentity: Repository<AuthIdentity>;
|
||||
AuthProviderSyncHistory: Repository<AuthProviderSyncHistory>;
|
||||
Credentials: Repository<ICredentialsDb>;
|
||||
Execution: Repository<IExecutionFlattedDb>;
|
||||
Workflow: Repository<WorkflowEntity>;
|
||||
Webhook: Repository<WebhookEntity>;
|
||||
Tag: Repository<TagEntity>;
|
||||
WorkflowTagMapping: Repository<WorkflowTagMapping>;
|
||||
Role: Repository<Role>;
|
||||
User: Repository<User>;
|
||||
SharedCredentials: Repository<SharedCredentials>;
|
||||
SharedWorkflow: Repository<SharedWorkflow>;
|
||||
Settings: Repository<Settings>;
|
||||
InstalledPackages: Repository<InstalledPackages>;
|
||||
InstalledNodes: Repository<InstalledNodes>;
|
||||
WorkflowStatistics: Repository<WorkflowStatistics>;
|
||||
EventDestinations: Repository<EventDestinations>;
|
||||
ExecutionMetadata: Repository<ExecutionMetadata>;
|
||||
AuthIdentity: AuthIdentityRepository;
|
||||
AuthProviderSyncHistory: AuthProviderSyncHistoryRepository;
|
||||
Credentials: CredentialsRepository;
|
||||
EventDestinations: EventDestinationsRepository;
|
||||
Execution: ExecutionRepository;
|
||||
ExecutionMetadata: ExecutionMetadataRepository;
|
||||
InstalledNodes: InstalledNodesRepository;
|
||||
InstalledPackages: InstalledPackagesRepository;
|
||||
Role: RoleRepository;
|
||||
Settings: SettingsRepository;
|
||||
SharedCredentials: SharedCredentialsRepository;
|
||||
SharedWorkflow: SharedWorkflowRepository;
|
||||
Tag: TagRepository;
|
||||
User: UserRepository;
|
||||
Webhook: WebhookRepository;
|
||||
Workflow: WorkflowRepository;
|
||||
WorkflowStatistics: WorkflowStatisticsRepository;
|
||||
WorkflowTagMapping: WorkflowTagMappingRepository;
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
|
|
|
@ -51,7 +51,11 @@ function userToPayload(user: User): {
|
|||
export class InternalHooks implements IInternalHooksClass {
|
||||
private instanceId: string;
|
||||
|
||||
constructor(private telemetry: Telemetry, private nodeTypes: NodeTypes) {}
|
||||
constructor(
|
||||
private telemetry: Telemetry,
|
||||
private nodeTypes: NodeTypes,
|
||||
private roleService: RoleService,
|
||||
) {}
|
||||
|
||||
async init(instanceId: string) {
|
||||
this.instanceId = instanceId;
|
||||
|
@ -155,7 +159,7 @@ export class InternalHooks implements IInternalHooksClass {
|
|||
|
||||
let userRole: 'owner' | 'sharee' | undefined = undefined;
|
||||
if (user.id && workflow.id) {
|
||||
const role = await RoleService.getUserRoleForWorkflow(user.id, workflow.id);
|
||||
const role = await this.roleService.getUserRoleForWorkflow(user.id, workflow.id);
|
||||
if (role) {
|
||||
userRole = role.name === 'owner' ? 'owner' : 'sharee';
|
||||
}
|
||||
|
@ -342,8 +346,7 @@ export class InternalHooks implements IInternalHooksClass {
|
|||
|
||||
let userRole: 'owner' | 'sharee' | undefined = undefined;
|
||||
if (userId) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
const role = await RoleService.getUserRoleForWorkflow(userId, workflow.id);
|
||||
const role = await this.roleService.getUserRoleForWorkflow(userId, workflow.id);
|
||||
if (role) {
|
||||
userRole = role.name === 'owner' ? 'owner' : 'sharee';
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import config from '@/config';
|
|||
import type { Role } from '@db/entities/Role';
|
||||
import { User } from '@db/entities/User';
|
||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import type { AuthProviderSyncHistory } from '@db/entities/AuthProviderSyncHistory';
|
||||
import { isUserManagementEnabled } from '@/UserManagement/UserManagementHelper';
|
||||
import { LdapManager } from './LdapManager.ee';
|
||||
|
@ -93,7 +94,7 @@ export const randomPassword = (): string => {
|
|||
* Return the user role to be assigned to LDAP users
|
||||
*/
|
||||
export const getLdapUserRole = async (): Promise<Role> => {
|
||||
return Db.collections.Role.findOneByOrFail({ scope: 'global', name: 'member' });
|
||||
return Container.get(RoleRepository).findGlobalMemberRoleOrFail();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,7 @@ import type { ICredentialsDb } from '@/Interfaces';
|
|||
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import type { IDependency, IJsonSchema } from '../../../types';
|
||||
import type { CredentialRequest } from '@/requests';
|
||||
|
@ -58,10 +59,7 @@ export async function saveCredential(
|
|||
user: User,
|
||||
encryptedData: ICredentialsDb,
|
||||
): Promise<CredentialsEntity> {
|
||||
const role = await Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'credential',
|
||||
});
|
||||
const role = await Container.get(RoleRepository).findCredentialOwnerRoleOrFail();
|
||||
|
||||
await Container.get(ExternalHooks).run('credentials.create', [encryptedData]);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import * as Db from '@/Db';
|
||||
import { Container } from 'typedi';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { User } from '@db/entities/User';
|
||||
|
||||
|
@ -7,8 +8,5 @@ export function isInstanceOwner(user: User): boolean {
|
|||
}
|
||||
|
||||
export async function getWorkflowOwnerRole(): Promise<Role> {
|
||||
return Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'workflow',
|
||||
});
|
||||
return Container.get(RoleRepository).findWorkflowOwnerRoleOrFail();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import { In } from 'typeorm';
|
||||
import type express from 'express';
|
||||
import { compare, genSaltSync, hash } from 'bcryptjs';
|
||||
import Container from 'typedi';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import * as Db from '@/Db';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
|
@ -11,15 +11,15 @@ import type { CurrentUser, PublicUser, WhereClause } from '@/Interfaces';
|
|||
import type { User } from '@db/entities/User';
|
||||
import { MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH } from '@db/entities/User';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import type { AuthenticatedRequest } from '@/requests';
|
||||
import config from '@/config';
|
||||
import { getWebhookBaseUrl } from '@/WebhookHelpers';
|
||||
import { License } from '@/License';
|
||||
import { RoleService } from '@/role/role.service';
|
||||
import type { PostHogClient } from '@/posthog';
|
||||
|
||||
export async function getWorkflowOwner(workflowId: string): Promise<User> {
|
||||
const workflowOwnerRole = await RoleService.get({ name: 'owner', scope: 'workflow' });
|
||||
const workflowOwnerRole = await Container.get(RoleRepository).findWorkflowOwnerRole();
|
||||
|
||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOneOrFail({
|
||||
where: { workflowId, roleId: workflowOwnerRole?.id ?? undefined },
|
||||
|
@ -61,13 +61,9 @@ export function isSharingEnabled(): boolean {
|
|||
}
|
||||
|
||||
export async function getRoleId(scope: Role['scope'], name: Role['name']): Promise<Role['id']> {
|
||||
return Db.collections.Role.findOneOrFail({
|
||||
select: ['id'],
|
||||
where: {
|
||||
name,
|
||||
scope,
|
||||
},
|
||||
}).then((role) => role.id);
|
||||
return Container.get(RoleRepository)
|
||||
.findRoleOrFail(scope, name)
|
||||
.then((role) => role.id);
|
||||
}
|
||||
|
||||
export async function getInstanceOwner(): Promise<User> {
|
||||
|
|
|
@ -131,7 +131,7 @@ export class WaitTracker {
|
|||
executionId,
|
||||
ResponseHelper.flattenExecutionData({
|
||||
...fullExecutionData,
|
||||
}),
|
||||
}) as IExecutionFlattedDb,
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
@ -71,7 +71,7 @@ import { PermissionChecker } from './UserManagement/PermissionChecker';
|
|||
import { WorkflowsService } from './workflows/workflows.services';
|
||||
import { Container } from 'typedi';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import type { ExecutionMetadata } from './databases/entities/ExecutionMetadata';
|
||||
import type { ExecutionMetadata } from '@db/entities/ExecutionMetadata';
|
||||
|
||||
const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType');
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import { WorkflowRunner } from '@/WorkflowRunner';
|
|||
import config from '@/config';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
||||
import omit from 'lodash.omit';
|
||||
import { PermissionChecker } from './UserManagement/PermissionChecker';
|
||||
|
@ -389,17 +390,11 @@ export async function isBelowOnboardingThreshold(user: User): Promise<boolean> {
|
|||
let belowThreshold = true;
|
||||
const skippedTypes = ['n8n-nodes-base.start', 'n8n-nodes-base.stickyNote'];
|
||||
|
||||
const workflowOwnerRoleId = await Db.collections.Role.findOne({
|
||||
select: ['id'],
|
||||
where: {
|
||||
name: 'owner',
|
||||
scope: 'workflow',
|
||||
},
|
||||
}).then((role) => role?.id);
|
||||
const workflowOwnerRole = await Container.get(RoleRepository).findWorkflowOwnerRole();
|
||||
const ownedWorkflowsIds = await Db.collections.SharedWorkflow.find({
|
||||
where: {
|
||||
userId: user.id,
|
||||
roleId: workflowOwnerRoleId,
|
||||
roleId: workflowOwnerRole?.id,
|
||||
},
|
||||
select: ['workflowId'],
|
||||
}).then((ownedWorkflows) => ownedWorkflows.map(({ workflowId }) => workflowId));
|
||||
|
|
|
@ -117,6 +117,9 @@ class WorkflowRunnerProcess {
|
|||
const externalHooks = Container.get(ExternalHooks);
|
||||
await externalHooks.init();
|
||||
|
||||
// Init db since we need to read the license.
|
||||
await Db.init();
|
||||
|
||||
const instanceId = userSettings.instanceId ?? '';
|
||||
await Container.get(PostHogClient).init(instanceId);
|
||||
await Container.get(InternalHooks).init(instanceId);
|
||||
|
@ -124,9 +127,6 @@ class WorkflowRunnerProcess {
|
|||
const binaryDataConfig = config.getEnv('binaryDataManager');
|
||||
await BinaryDataManager.init(binaryDataConfig);
|
||||
|
||||
// Init db since we need to read the license.
|
||||
await Db.init();
|
||||
|
||||
const license = Container.get(License);
|
||||
await license.init(instanceId);
|
||||
|
||||
|
|
|
@ -8,12 +8,13 @@ import { Router } from 'express';
|
|||
import type { Request } from 'express';
|
||||
import bodyParser from 'body-parser';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { Container } from 'typedi';
|
||||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { hashPassword } from '@/UserManagement/UserManagementHelper';
|
||||
import { eventBus } from '@/eventbus/MessageEventBus/MessageEventBus';
|
||||
import Container from 'typedi';
|
||||
import { License } from '../License';
|
||||
import { LICENSE_FEATURES } from '@/constants';
|
||||
|
||||
|
@ -55,7 +56,7 @@ const tablesToTruncate = [
|
|||
];
|
||||
|
||||
const truncateAll = async () => {
|
||||
const { connection } = Db;
|
||||
const connection = Db.getConnection();
|
||||
for (const table of tablesToTruncate) {
|
||||
await connection.query(
|
||||
`DELETE FROM ${table}; DELETE FROM sqlite_sequence WHERE name=${table};`,
|
||||
|
@ -64,7 +65,7 @@ const truncateAll = async () => {
|
|||
};
|
||||
|
||||
const setupUserManagement = async () => {
|
||||
const { connection } = Db;
|
||||
const connection = Db.getConnection();
|
||||
await connection.query('INSERT INTO role (name, scope) VALUES ("owner", "global");');
|
||||
const instanceOwnerRole = (await connection.query(
|
||||
'SELECT last_insert_rowid() as insertId',
|
||||
|
@ -116,13 +117,7 @@ e2eController.post('/db/setup-owner', bodyParser.json(), async (req, res) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const globalRole = await Db.collections.Role.findOneOrFail({
|
||||
select: ['id'],
|
||||
where: {
|
||||
name: 'owner',
|
||||
scope: 'global',
|
||||
},
|
||||
});
|
||||
const globalRole = await Container.get(RoleRepository).findGlobalOwnerRoleOrFail();
|
||||
|
||||
const owner = await Db.collections.User.findOneByOrFail({ globalRoleId: globalRole.id });
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import type {
|
|||
IWorkflowStatisticsDataLoaded,
|
||||
IWorkflowStatisticsTimestamps,
|
||||
} from '@/Interfaces';
|
||||
import { StatisticsNames } from '../databases/entities/WorkflowStatistics';
|
||||
import { StatisticsNames } from '@db/entities/WorkflowStatistics';
|
||||
import { getLogger } from '../Logger';
|
||||
import type { ExecutionRequest } from '../requests';
|
||||
|
||||
|
|
|
@ -51,13 +51,13 @@ export abstract class BaseCommand extends Command {
|
|||
const credentialTypes = Container.get(CredentialTypes);
|
||||
CredentialsOverwrites(credentialTypes);
|
||||
|
||||
this.instanceId = this.userSettings.instanceId ?? '';
|
||||
await Container.get(PostHogClient).init(this.instanceId);
|
||||
await Container.get(InternalHooks).init(this.instanceId);
|
||||
|
||||
await Db.init().catch(async (error: Error) =>
|
||||
this.exitWithCrash('There was an error initializing DB', error),
|
||||
);
|
||||
|
||||
this.instanceId = this.userSettings.instanceId ?? '';
|
||||
await Container.get(PostHogClient).init(this.instanceId);
|
||||
await Container.get(InternalHooks).init(this.instanceId);
|
||||
}
|
||||
|
||||
protected async stopProcess() {
|
||||
|
@ -96,7 +96,7 @@ export abstract class BaseCommand extends Command {
|
|||
if (inTest || this.id === 'start') return;
|
||||
if (Db.isInitialized) {
|
||||
await sleep(100); // give any in-flight query some time to finish
|
||||
await Db.connection.destroy();
|
||||
await Db.getConnection().destroy();
|
||||
}
|
||||
const exitCode = error instanceof ExitError ? error.oclif.exit : error ? 1 : 0;
|
||||
this.exit(exitCode);
|
||||
|
|
|
@ -110,7 +110,7 @@ export class ExportCredentialsCommand extends BaseCommand {
|
|||
findQuery.id = flags.id;
|
||||
}
|
||||
|
||||
const credentials = await Db.collections.Credentials.findBy(findQuery);
|
||||
const credentials: ICredentialsDb[] = await Db.collections.Credentials.findBy(findQuery);
|
||||
|
||||
if (flags.decrypted) {
|
||||
const encryptionKey = await UserSettings.getEncryptionKey();
|
||||
|
|
|
@ -2,6 +2,7 @@ import { flags } from '@oclif/command';
|
|||
import { Credentials } from 'n8n-core';
|
||||
import fs from 'fs';
|
||||
import glob from 'fast-glob';
|
||||
import { Container } from 'typedi';
|
||||
import type { EntityManager } from 'typeorm';
|
||||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
|
@ -9,6 +10,7 @@ import type { User } from '@db/entities/User';
|
|||
import { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { disableAutoGeneratedIds } from '@db/utils/commandHelpers';
|
||||
import { BaseCommand, UM_FIX_INSTRUCTION } from '../BaseCommand';
|
||||
import type { ICredentialsEncrypted } from 'n8n-workflow';
|
||||
|
@ -146,9 +148,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
private async initOwnerCredentialRole() {
|
||||
const ownerCredentialRole = await Db.collections.Role.findOne({
|
||||
where: { name: 'owner', scope: 'credential' },
|
||||
});
|
||||
const ownerCredentialRole = await Container.get(RoleRepository).findCredentialOwnerRole();
|
||||
|
||||
if (!ownerCredentialRole) {
|
||||
throw new Error(`Failed to find owner credential role. ${UM_FIX_INSTRUCTION}`);
|
||||
|
@ -177,9 +177,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
private async getOwner() {
|
||||
const ownerGlobalRole = await Db.collections.Role.findOne({
|
||||
where: { name: 'owner', scope: 'global' },
|
||||
});
|
||||
const ownerGlobalRole = await Container.get(RoleRepository).findGlobalOwnerRole();
|
||||
|
||||
const owner =
|
||||
ownerGlobalRole &&
|
||||
|
|
|
@ -3,6 +3,7 @@ import type { INode, INodeCredentialsDetails } from 'n8n-workflow';
|
|||
import { jsonParse } from 'n8n-workflow';
|
||||
import fs from 'fs';
|
||||
import glob from 'fast-glob';
|
||||
import { Container } from 'typedi';
|
||||
import type { EntityManager } from 'typeorm';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import config from '@/config';
|
||||
|
@ -12,8 +13,9 @@ import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
|||
import type { Role } from '@db/entities/Role';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { setTagsForImport } from '@/TagHelpers';
|
||||
import type { ICredentialsDb, IWorkflowToImport } from '@/Interfaces';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { disableAutoGeneratedIds } from '@db/utils/commandHelpers';
|
||||
import type { ICredentialsDb, IWorkflowToImport } from '@/Interfaces';
|
||||
import { replaceInvalidCredentials } from '@/WorkflowHelpers';
|
||||
import { BaseCommand, UM_FIX_INSTRUCTION } from '../BaseCommand';
|
||||
|
||||
|
@ -205,9 +207,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
private async initOwnerWorkflowRole() {
|
||||
const ownerWorkflowRole = await Db.collections.Role.findOne({
|
||||
where: { name: 'owner', scope: 'workflow' },
|
||||
});
|
||||
const ownerWorkflowRole = await Container.get(RoleRepository).findWorkflowOwnerRole();
|
||||
|
||||
if (!ownerWorkflowRole) {
|
||||
throw new Error(`Failed to find owner workflow role. ${UM_FIX_INSTRUCTION}`);
|
||||
|
@ -236,9 +236,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
private async getOwner() {
|
||||
const ownerGlobalRole = await Db.collections.Role.findOne({
|
||||
where: { name: 'owner', scope: 'global' },
|
||||
});
|
||||
const ownerGlobalRole = await Container.get(RoleRepository).findGlobalOwnerRole();
|
||||
|
||||
const owner =
|
||||
ownerGlobalRole &&
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { Container } from 'typedi';
|
||||
import { Not } from 'typeorm';
|
||||
import * as Db from '@/Db';
|
||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import { User } from '@db/entities/User';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { BaseCommand } from '../BaseCommand';
|
||||
|
||||
const defaultUserProps = {
|
||||
|
@ -20,15 +22,8 @@ export class Reset extends BaseCommand {
|
|||
async run(): Promise<void> {
|
||||
const owner = await this.getInstanceOwner();
|
||||
|
||||
const ownerWorkflowRole = await Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'workflow',
|
||||
});
|
||||
|
||||
const ownerCredentialRole = await Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'credential',
|
||||
});
|
||||
const ownerWorkflowRole = await Container.get(RoleRepository).findWorkflowOwnerRoleOrFail();
|
||||
const ownerCredentialRole = await Container.get(RoleRepository).findCredentialOwnerRoleOrFail();
|
||||
|
||||
await Db.collections.SharedWorkflow.update(
|
||||
{ userId: Not(owner.id), roleId: ownerWorkflowRole.id },
|
||||
|
@ -44,10 +39,10 @@ export class Reset extends BaseCommand {
|
|||
await Db.collections.User.save(Object.assign(owner, defaultUserProps));
|
||||
|
||||
const danglingCredentials: CredentialsEntity[] =
|
||||
(await Db.collections.Credentials.createQueryBuilder('credentials')
|
||||
await Db.collections.Credentials.createQueryBuilder('credentials')
|
||||
.leftJoinAndSelect('credentials.shared', 'shared')
|
||||
.where('shared.credentialsId is null')
|
||||
.getMany()) as CredentialsEntity[];
|
||||
.getMany();
|
||||
const newSharedCredentials = danglingCredentials.map((credentials) =>
|
||||
Db.collections.SharedCredentials.create({
|
||||
credentials,
|
||||
|
@ -70,10 +65,7 @@ export class Reset extends BaseCommand {
|
|||
}
|
||||
|
||||
async getInstanceOwner(): Promise<User> {
|
||||
const globalRole = await Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'global',
|
||||
});
|
||||
const globalRole = await Container.get(RoleRepository).findGlobalOwnerRoleOrFail();
|
||||
|
||||
const owner = await Db.collections.User.findOneBy({ globalRoleId: globalRole.id });
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import { Request, Response } from 'express';
|
|||
import type { ILogger } from 'n8n-workflow';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { LoginRequest, UserRequest } from '@/requests';
|
||||
import type { Repository } from 'typeorm';
|
||||
import { In } from 'typeorm';
|
||||
import type { Config } from '@/config';
|
||||
import type {
|
||||
|
@ -23,6 +22,7 @@ import {
|
|||
isLdapCurrentAuthenticationMethod,
|
||||
isSamlCurrentAuthenticationMethod,
|
||||
} from '@/sso/ssoHelpers';
|
||||
import type { UserRepository } from '@db/repositories';
|
||||
|
||||
@RestController()
|
||||
export class AuthController {
|
||||
|
@ -32,7 +32,7 @@ export class AuthController {
|
|||
|
||||
private readonly internalHooks: IInternalHooksClass;
|
||||
|
||||
private readonly userRepository: Repository<User>;
|
||||
private readonly userRepository: UserRepository;
|
||||
|
||||
private readonly postHog?: PostHogClient;
|
||||
|
||||
|
|
|
@ -8,11 +8,11 @@ import {
|
|||
validatePassword,
|
||||
} from '@/UserManagement/UserManagementHelper';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { UserRepository } from '@db/repositories';
|
||||
import { Response } from 'express';
|
||||
import type { Repository } from 'typeorm';
|
||||
import type { ILogger } from 'n8n-workflow';
|
||||
import {
|
||||
AuthenticatedRequest,
|
||||
|
@ -38,7 +38,7 @@ export class MeController {
|
|||
|
||||
private readonly internalHooks: IInternalHooksClass;
|
||||
|
||||
private readonly userRepository: Repository<User>;
|
||||
private readonly userRepository: UserRepository;
|
||||
|
||||
constructor({
|
||||
logger,
|
||||
|
|
|
@ -9,14 +9,16 @@ import {
|
|||
} from '@/UserManagement/UserManagementHelper';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
import { Response } from 'express';
|
||||
import type { Repository } from 'typeorm';
|
||||
import type { ILogger } from 'n8n-workflow';
|
||||
import type { Config } from '@/config';
|
||||
import { OwnerRequest } from '@/requests';
|
||||
import type { IDatabaseCollections, IInternalHooksClass, ICredentialsDb } from '@/Interfaces';
|
||||
import type { Settings } from '@db/entities/Settings';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type { IDatabaseCollections, IInternalHooksClass } from '@/Interfaces';
|
||||
import type {
|
||||
CredentialsRepository,
|
||||
SettingsRepository,
|
||||
UserRepository,
|
||||
WorkflowRepository,
|
||||
} from '@db/repositories';
|
||||
|
||||
@RestController('/owner')
|
||||
export class OwnerController {
|
||||
|
@ -26,13 +28,13 @@ export class OwnerController {
|
|||
|
||||
private readonly internalHooks: IInternalHooksClass;
|
||||
|
||||
private readonly userRepository: Repository<User>;
|
||||
private readonly userRepository: UserRepository;
|
||||
|
||||
private readonly settingsRepository: Repository<Settings>;
|
||||
private readonly settingsRepository: SettingsRepository;
|
||||
|
||||
private readonly credentialsRepository: Repository<ICredentialsDb>;
|
||||
private readonly credentialsRepository: CredentialsRepository;
|
||||
|
||||
private readonly workflowsRepository: Repository<WorkflowEntity>;
|
||||
private readonly workflowsRepository: WorkflowRepository;
|
||||
|
||||
constructor({
|
||||
config,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import type { Repository } from 'typeorm';
|
||||
import { IsNull, MoreThanOrEqual, Not } from 'typeorm';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import validator from 'validator';
|
||||
|
@ -20,7 +19,7 @@ import type { UserManagementMailer } from '@/UserManagement/email';
|
|||
import { Response } from 'express';
|
||||
import type { ILogger } from 'n8n-workflow';
|
||||
import type { Config } from '@/config';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { UserRepository } from '@db/repositories';
|
||||
import { PasswordResetRequest } from '@/requests';
|
||||
import type { IDatabaseCollections, IExternalHooksClass, IInternalHooksClass } from '@/Interfaces';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
|
@ -39,7 +38,7 @@ export class PasswordResetController {
|
|||
|
||||
private readonly mailer: UserManagementMailer;
|
||||
|
||||
private readonly userRepository: Repository<User>;
|
||||
private readonly userRepository: UserRepository;
|
||||
|
||||
constructor({
|
||||
config,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Request, Response, NextFunction } from 'express';
|
||||
import type { Repository } from 'typeorm';
|
||||
import type { Config } from '@/config';
|
||||
import { Delete, Get, Middleware, Patch, Post, RestController } from '@/decorators';
|
||||
import type { IDatabaseCollections, IExternalHooksClass, ITagWithCountDb } from '@/Interfaces';
|
||||
import { TagEntity } from '@db/entities/TagEntity';
|
||||
import type { TagRepository } from '@db/repositories';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { BadRequestError, UnauthorizedError } from '@/ResponseHelper';
|
||||
import { TagsRequest } from '@/requests';
|
||||
|
@ -14,7 +14,7 @@ export class TagsController {
|
|||
|
||||
private externalHooks: IExternalHooksClass;
|
||||
|
||||
private tagsRepository: Repository<TagEntity>;
|
||||
private tagsRepository: TagRepository;
|
||||
|
||||
constructor({
|
||||
config,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import validator from 'validator';
|
||||
import type { Repository } from 'typeorm';
|
||||
import { In } from 'typeorm';
|
||||
import type { ILogger } from 'n8n-workflow';
|
||||
import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow';
|
||||
|
@ -23,7 +22,6 @@ import { Response } from 'express';
|
|||
import type { Config } from '@/config';
|
||||
import { UserRequest } from '@/requests';
|
||||
import type { UserManagementMailer } from '@/UserManagement/email';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type {
|
||||
PublicUser,
|
||||
IDatabaseCollections,
|
||||
|
@ -36,6 +34,12 @@ import { AuthIdentity } from '@db/entities/AuthIdentity';
|
|||
import type { PostHogClient } from '@/posthog';
|
||||
import { userManagementEnabledMiddleware } from '../middlewares/userManagementEnabled';
|
||||
import { isSamlLicensedAndEnabled } from '../sso/saml/samlHelpers';
|
||||
import type {
|
||||
RoleRepository,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
UserRepository,
|
||||
} from '@db/repositories';
|
||||
|
||||
@RestController('/users')
|
||||
export class UsersController {
|
||||
|
@ -47,13 +51,13 @@ export class UsersController {
|
|||
|
||||
private internalHooks: IInternalHooksClass;
|
||||
|
||||
private userRepository: Repository<User>;
|
||||
private userRepository: UserRepository;
|
||||
|
||||
private roleRepository: Repository<Role>;
|
||||
private roleRepository: RoleRepository;
|
||||
|
||||
private sharedCredentialsRepository: Repository<SharedCredentials>;
|
||||
private sharedCredentialsRepository: SharedCredentialsRepository;
|
||||
|
||||
private sharedWorkflowRepository: Repository<SharedWorkflow>;
|
||||
private sharedWorkflowRepository: SharedWorkflowRepository;
|
||||
|
||||
private activeWorkflowRunner: ActiveWorkflowRunner;
|
||||
|
||||
|
@ -147,7 +151,7 @@ export class UsersController {
|
|||
createUsers[invite.email.toLowerCase()] = null;
|
||||
});
|
||||
|
||||
const role = await this.roleRepository.findOneBy({ scope: 'global', name: 'member' });
|
||||
const role = await this.roleRepository.findGlobalMemberRole();
|
||||
|
||||
if (!role) {
|
||||
this.logger.error(
|
||||
|
@ -396,8 +400,8 @@ export class UsersController {
|
|||
}
|
||||
|
||||
const [workflowOwnerRole, credentialOwnerRole] = await Promise.all([
|
||||
this.roleRepository.findOneBy({ name: 'owner', scope: 'workflow' }),
|
||||
this.roleRepository.findOneBy({ name: 'owner', scope: 'credential' }),
|
||||
this.roleRepository.findWorkflowOwnerRole(),
|
||||
this.roleRepository.findCredentialOwnerRole(),
|
||||
]);
|
||||
|
||||
if (transferId) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import type {
|
|||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
import { deepCopy, LoggerProxy, NodeHelpers } from 'n8n-workflow';
|
||||
import { Container } from 'typedi';
|
||||
import type { FindManyOptions, FindOptionsWhere } from 'typeorm';
|
||||
import { In } from 'typeorm';
|
||||
|
||||
|
@ -20,11 +21,10 @@ import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
|||
import { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
|
||||
import type { User } from '@db/entities/User';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import type { CredentialRequest } from '@/requests';
|
||||
import { CredentialTypes } from '@/CredentialTypes';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
export class CredentialsService {
|
||||
static async get(
|
||||
|
@ -116,9 +116,7 @@ export class CredentialsService {
|
|||
|
||||
// This saves us a merge but requires some type casting. These
|
||||
// types are compatible for this case.
|
||||
const newCredentials = Db.collections.Credentials.create(
|
||||
rest as ICredentialsDb,
|
||||
) as CredentialsEntity;
|
||||
const newCredentials = Db.collections.Credentials.create(rest as ICredentialsDb);
|
||||
|
||||
await validateEntity(newCredentials);
|
||||
|
||||
|
@ -140,10 +138,8 @@ export class CredentialsService {
|
|||
}
|
||||
|
||||
// This saves us a merge but requires some type casting. These
|
||||
// types are compatiable for this case.
|
||||
const updateData = Db.collections.Credentials.create(
|
||||
mergedData as ICredentialsDb,
|
||||
) as CredentialsEntity;
|
||||
// types are compatible for this case.
|
||||
const updateData = Db.collections.Credentials.create(mergedData as ICredentialsDb);
|
||||
|
||||
await validateEntity(updateData);
|
||||
|
||||
|
@ -227,10 +223,7 @@ export class CredentialsService {
|
|||
|
||||
await Container.get(ExternalHooks).run('credentials.create', [encryptedData]);
|
||||
|
||||
const role = await Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'credential',
|
||||
});
|
||||
const role = await Container.get(RoleRepository).findCredentialOwnerRoleOrFail();
|
||||
|
||||
const result = await Db.transaction(async (transactionManager) => {
|
||||
const savedCredential = await transactionManager.save<CredentialsEntity>(newCredential);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { AuthIdentity } from './AuthIdentity';
|
||||
import { AuthProviderSyncHistory } from './AuthProviderSyncHistory';
|
||||
import { CredentialsEntity } from './CredentialsEntity';
|
||||
import { EventDestinations } from './MessageEventBusDestinationEntity';
|
||||
import { EventDestinations } from './EventDestinations';
|
||||
import { ExecutionEntity } from './ExecutionEntity';
|
||||
import { InstalledNodes } from './InstalledNodes';
|
||||
import { InstalledPackages } from './InstalledPackages';
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { AuthIdentity } from '../entities/AuthIdentity';
|
||||
|
||||
@Service()
|
||||
export class AuthIdentityRepository extends Repository<AuthIdentity> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(AuthIdentity, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { AuthProviderSyncHistory } from '../entities/AuthProviderSyncHistory';
|
||||
|
||||
@Service()
|
||||
export class AuthProviderSyncHistoryRepository extends Repository<AuthProviderSyncHistory> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(AuthProviderSyncHistory, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { CredentialsEntity } from '../entities/CredentialsEntity';
|
||||
|
||||
@Service()
|
||||
export class CredentialsRepository extends Repository<CredentialsEntity> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(CredentialsEntity, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { EventDestinations } from '../entities/EventDestinations';
|
||||
|
||||
@Service()
|
||||
export class EventDestinationsRepository extends Repository<EventDestinations> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(EventDestinations, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { ExecutionEntity } from '../entities/ExecutionEntity';
|
||||
|
||||
@Service()
|
||||
export class ExecutionRepository extends Repository<ExecutionEntity> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(ExecutionEntity, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { ExecutionMetadata } from '../entities/ExecutionMetadata';
|
||||
|
||||
@Service()
|
||||
export class ExecutionMetadataRepository extends Repository<ExecutionMetadata> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(ExecutionMetadata, dataSource.manager);
|
||||
}
|
||||
}
|
18
packages/cli/src/databases/repositories/index.ts
Normal file
18
packages/cli/src/databases/repositories/index.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
export { AuthIdentityRepository } from './authIdentity.repository';
|
||||
export { AuthProviderSyncHistoryRepository } from './authProviderSyncHistory.repository';
|
||||
export { CredentialsRepository } from './credentials.repository';
|
||||
export { EventDestinationsRepository } from './eventDestinations.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 { WebhookRepository } from './webhook.repository';
|
||||
export { WorkflowRepository } from './workflow.repository';
|
||||
export { WorkflowStatisticsRepository } from './workflowStatistics.repository';
|
||||
export { WorkflowTagMappingRepository } from './workflowTagMapping.repository';
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { InstalledNodes } from '../entities/InstalledNodes';
|
||||
|
||||
@Service()
|
||||
export class InstalledNodesRepository extends Repository<InstalledNodes> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(InstalledNodes, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { InstalledPackages } from '../entities/InstalledPackages';
|
||||
|
||||
@Service()
|
||||
export class InstalledPackagesRepository extends Repository<InstalledPackages> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(InstalledPackages, dataSource.manager);
|
||||
}
|
||||
}
|
59
packages/cli/src/databases/repositories/role.repository.ts
Normal file
59
packages/cli/src/databases/repositories/role.repository.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import type { RoleNames, RoleScopes } from '../entities/Role';
|
||||
import { Role } from '../entities/Role';
|
||||
|
||||
@Service()
|
||||
export class RoleRepository extends Repository<Role> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(Role, dataSource.manager);
|
||||
}
|
||||
|
||||
async findGlobalOwnerRole(): Promise<Role | null> {
|
||||
return this.findRole('global', 'owner');
|
||||
}
|
||||
|
||||
async findGlobalOwnerRoleOrFail(): Promise<Role> {
|
||||
return this.findRoleOrFail('global', 'owner');
|
||||
}
|
||||
|
||||
async findGlobalMemberRole(): Promise<Role | null> {
|
||||
return this.findRole('global', 'member');
|
||||
}
|
||||
|
||||
async findGlobalMemberRoleOrFail(): Promise<Role> {
|
||||
return this.findRoleOrFail('global', 'member');
|
||||
}
|
||||
|
||||
async findWorkflowOwnerRole(): Promise<Role | null> {
|
||||
return this.findRole('workflow', 'owner');
|
||||
}
|
||||
|
||||
async findWorkflowOwnerRoleOrFail(): Promise<Role> {
|
||||
return this.findRoleOrFail('workflow', 'owner');
|
||||
}
|
||||
|
||||
async findWorkflowEditorRoleOrFail(): Promise<Role> {
|
||||
return this.findRoleOrFail('workflow', 'editor');
|
||||
}
|
||||
|
||||
async findCredentialOwnerRole(): Promise<Role | null> {
|
||||
return this.findRole('credential', 'owner');
|
||||
}
|
||||
|
||||
async findCredentialOwnerRoleOrFail(): Promise<Role> {
|
||||
return this.findRoleOrFail('credential', 'owner');
|
||||
}
|
||||
|
||||
async findCredentialUserRole(): Promise<Role | null> {
|
||||
return this.findRole('credential', 'user');
|
||||
}
|
||||
|
||||
async findRole(scope: RoleScopes, name: RoleNames): Promise<Role | null> {
|
||||
return this.findOne({ where: { scope, name } });
|
||||
}
|
||||
|
||||
async findRoleOrFail(scope: RoleScopes, name: RoleNames): Promise<Role> {
|
||||
return this.findOneOrFail({ where: { scope, name } });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Settings } from '../entities/Settings';
|
||||
|
||||
@Service()
|
||||
export class SettingsRepository extends Repository<Settings> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(Settings, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { SharedCredentials } from '../entities/SharedCredentials';
|
||||
|
||||
@Service()
|
||||
export class SharedCredentialsRepository extends Repository<SharedCredentials> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(SharedCredentials, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { SharedWorkflow } from '../entities/SharedWorkflow';
|
||||
|
||||
@Service()
|
||||
export class SharedWorkflowRepository extends Repository<SharedWorkflow> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(SharedWorkflow, dataSource.manager);
|
||||
}
|
||||
}
|
10
packages/cli/src/databases/repositories/tag.repository.ts
Normal file
10
packages/cli/src/databases/repositories/tag.repository.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { TagEntity } from '../entities/TagEntity';
|
||||
|
||||
@Service()
|
||||
export class TagRepository extends Repository<TagEntity> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(TagEntity, dataSource.manager);
|
||||
}
|
||||
}
|
10
packages/cli/src/databases/repositories/user.repository.ts
Normal file
10
packages/cli/src/databases/repositories/user.repository.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { User } from '../entities/User';
|
||||
|
||||
@Service()
|
||||
export class UserRepository extends Repository<User> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(User, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { WebhookEntity } from '../entities/WebhookEntity';
|
||||
|
||||
@Service()
|
||||
export class WebhookRepository extends Repository<WebhookEntity> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(WebhookEntity, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { WorkflowEntity } from '../entities/WorkflowEntity';
|
||||
|
||||
@Service()
|
||||
export class WorkflowRepository extends Repository<WorkflowEntity> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(WorkflowEntity, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { WorkflowStatistics } from '../entities/WorkflowStatistics';
|
||||
|
||||
@Service()
|
||||
export class WorkflowStatisticsRepository extends Repository<WorkflowStatistics> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(WorkflowStatistics, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { WorkflowTagMapping } from '../entities/WorkflowTagMapping';
|
||||
|
||||
@Service()
|
||||
export class WorkflowTagMappingRepository extends Repository<WorkflowTagMapping> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(WorkflowTagMapping, dataSource.manager);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import type { EventDestinations } from '@/databases/entities/MessageEventBusDestinationEntity';
|
||||
import type { EventDestinations } from '@db/entities/EventDestinations';
|
||||
import { promClient } from '@/metrics';
|
||||
import {
|
||||
EventMessageTypeNames,
|
||||
|
|
|
@ -39,7 +39,7 @@ import {
|
|||
getStatusUsingPreviousExecutionStatusMethod,
|
||||
isAdvancedExecutionFiltersEnabled,
|
||||
} from './executionHelpers';
|
||||
import { ExecutionMetadata } from '@/databases/entities/ExecutionMetadata';
|
||||
import { ExecutionMetadata } from '@db/entities/ExecutionMetadata';
|
||||
import { DateUtils } from 'typeorm/util/DateUtils';
|
||||
|
||||
interface IGetExecutionsQueryFilter {
|
||||
|
|
|
@ -16,9 +16,8 @@ import {
|
|||
isPostUsersId,
|
||||
isUserManagementEnabled,
|
||||
} from '@/UserManagement/UserManagementHelper';
|
||||
import type { Repository } from 'typeorm';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { SamlUrls } from '@/sso/saml/constants';
|
||||
import type { UserRepository } from '@db/repositories';
|
||||
|
||||
const jwtFromRequest = (req: Request) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
|
@ -74,7 +73,7 @@ export const setupAuthMiddlewares = (
|
|||
app: Application,
|
||||
ignoredEndpoints: Readonly<string[]>,
|
||||
restEndpoint: string,
|
||||
userRepository: Repository<User>,
|
||||
userRepository: UserRepository,
|
||||
) => {
|
||||
// needed for testing; not adding overhead since it directly returns if req.cookies exists
|
||||
app.use(cookieParser());
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { Service } from 'typedi';
|
||||
import type { EntityManager, FindOptionsWhere } from 'typeorm';
|
||||
import * as Db from '@/Db';
|
||||
import { Role } from '@db/entities/Role';
|
||||
import { SharedWorkflowRepository } from '@db/repositories';
|
||||
|
||||
@Service()
|
||||
export class RoleService {
|
||||
static async get(role: FindOptionsWhere<Role>): Promise<Role | null> {
|
||||
return Db.collections.Role.findOneBy(role);
|
||||
}
|
||||
constructor(private sharedWorkflowRepository: SharedWorkflowRepository) {}
|
||||
|
||||
static async trxGet(transaction: EntityManager, role: FindOptionsWhere<Role>) {
|
||||
return transaction.findOneBy(Role, role);
|
||||
}
|
||||
|
||||
static async getUserRoleForWorkflow(userId: string, workflowId: string) {
|
||||
const shared = await Db.collections.SharedWorkflow.findOne({
|
||||
async getUserRoleForWorkflow(userId: string, workflowId: string) {
|
||||
const shared = await this.sharedWorkflowRepository.findOne({
|
||||
where: { workflowId, userId },
|
||||
relations: ['role'],
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type express from 'express';
|
||||
import { Service } from 'typedi';
|
||||
import * as Db from '@/Db';
|
||||
import type { User } from '@/databases/entities/User';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { jsonParse, LoggerProxy } from 'n8n-workflow';
|
||||
import { AuthError, BadRequestError } from '@/ResponseHelper';
|
||||
import { getServiceProviderInstance } from './serviceProvider.ee';
|
||||
|
@ -20,7 +20,7 @@ import {
|
|||
setSamlLoginLabel,
|
||||
updateUserFromSamlAttributes,
|
||||
} from './samlHelpers';
|
||||
import type { Settings } from '@/databases/entities/Settings';
|
||||
import type { Settings } from '@db/entities/Settings';
|
||||
import axios from 'axios';
|
||||
import https from 'https';
|
||||
import type { SamlLoginBinding } from './types';
|
||||
|
|
|
@ -3,6 +3,7 @@ import config from '@/config';
|
|||
import * as Db from '@/Db';
|
||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||
import { User } from '@db/entities/User';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { License } from '@/License';
|
||||
import { AuthError, InternalServerError } from '@/ResponseHelper';
|
||||
import { hashPassword, isUserManagementEnabled } from '@/UserManagement/UserManagementHelper';
|
||||
|
@ -98,9 +99,7 @@ export async function createUserFromSamlAttributes(attributes: SamlUserAttribute
|
|||
user.email = attributes.email;
|
||||
user.firstName = attributes.firstName;
|
||||
user.lastName = attributes.lastName;
|
||||
user.globalRole = await Db.collections.Role.findOneOrFail({
|
||||
where: { name: 'member', scope: 'global' },
|
||||
});
|
||||
user.globalRole = await Container.get(RoleRepository).findGlobalMemberRoleOrFail();
|
||||
// generates a password that is not used or known to the user
|
||||
user.password = await hashPassword(generatePassword());
|
||||
authIdentity.providerId = attributes.userPrincipalName;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
import type { AuthProviderType } from '@/databases/entities/AuthIdentity';
|
||||
import type { AuthProviderType } from '@db/entities/AuthIdentity';
|
||||
|
||||
/**
|
||||
* Only one authentication method can be active at a time. This function sets the current authentication method
|
||||
|
|
|
@ -11,6 +11,7 @@ import { isSharingEnabled, rightDiff } from '@/UserManagement/UserManagementHelp
|
|||
import { EEWorkflowsService as EEWorkflows } from './workflows.services.ee';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { LoggerProxy } from 'n8n-workflow';
|
||||
import * as TagHelpers from '@/TagHelpers';
|
||||
import { EECredentialsService as EECredentials } from '../credentials/credentials.service.ee';
|
||||
|
@ -162,10 +163,7 @@ EEWorkflowController.post(
|
|||
await Db.transaction(async (transactionManager) => {
|
||||
savedWorkflow = await transactionManager.save<WorkflowEntity>(newWorkflow);
|
||||
|
||||
const role = await Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'workflow',
|
||||
});
|
||||
const role = await Container.get(RoleRepository).findWorkflowOwnerRoleOrFail();
|
||||
|
||||
const newSharedWorkflow = new SharedWorkflow();
|
||||
|
||||
|
@ -206,10 +204,7 @@ EEWorkflowController.get(
|
|||
ResponseHelper.send(async (req: WorkflowRequest.GetAll) => {
|
||||
const [workflows, workflowOwnerRole] = await Promise.all([
|
||||
EEWorkflows.getMany(req.user, req.query.filter),
|
||||
Db.collections.Role.findOneOrFail({
|
||||
select: ['id'],
|
||||
where: { name: 'owner', scope: 'workflow' },
|
||||
}),
|
||||
Container.get(RoleRepository).findWorkflowOwnerRoleOrFail(),
|
||||
]);
|
||||
|
||||
return workflows.map((workflow) => {
|
||||
|
|
|
@ -14,6 +14,7 @@ import config from '@/config';
|
|||
import * as TagHelpers from '@/TagHelpers';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { getLogger } from '@/Logger';
|
||||
|
@ -80,10 +81,7 @@ workflowsController.post(
|
|||
await Db.transaction(async (transactionManager) => {
|
||||
savedWorkflow = await transactionManager.save<WorkflowEntity>(newWorkflow);
|
||||
|
||||
const role = await Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'workflow',
|
||||
});
|
||||
const role = await Container.get(RoleRepository).findWorkflowOwnerRoleOrFail();
|
||||
|
||||
const newSharedWorkflow = new SharedWorkflow();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import config from '@/config';
|
|||
import axios from 'axios';
|
||||
import syslog from 'syslog-client';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import Container from 'typedi';
|
||||
import { Container } from 'typedi';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import * as utils from './shared/utils';
|
||||
import * as testDb from './shared/testDb';
|
||||
|
@ -112,7 +112,6 @@ beforeAll(async () => {
|
|||
|
||||
afterAll(async () => {
|
||||
jest.mock('@/eventbus/MessageEventBus/MessageEventBus');
|
||||
Container.reset();
|
||||
await testDb.terminate();
|
||||
await eventBus.close();
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import express from 'express';
|
||||
import type { Entry as LdapUser } from 'ldapts';
|
||||
import { Not } from 'typeorm';
|
||||
import Container from 'typedi';
|
||||
import { Container } from 'typedi';
|
||||
import { jsonParse } from 'n8n-workflow';
|
||||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
|
@ -83,7 +83,6 @@ beforeEach(async () => {
|
|||
});
|
||||
|
||||
afterAll(async () => {
|
||||
Container.reset();
|
||||
await testDb.terminate();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import Container from 'typedi';
|
||||
import { Container } from 'typedi';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { setSamlLoginEnabled } from '@/sso/saml/samlHelpers';
|
||||
|
@ -24,7 +24,6 @@ beforeAll(async () => {
|
|||
});
|
||||
|
||||
afterAll(async () => {
|
||||
Container.reset();
|
||||
await testDb.terminate();
|
||||
});
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ export function randomApiKey() {
|
|||
|
||||
const chooseRandomly = <T>(array: T[]) => array[Math.floor(Math.random() * array.length)];
|
||||
|
||||
export const randomInteger = (max = 1000) => Math.floor(Math.random() * max);
|
||||
|
||||
export const randomDigit = () => Math.floor(Math.random() * 10);
|
||||
|
||||
export const randomPositiveDigit = (): number => {
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import { UserSettings } from 'n8n-core';
|
||||
import {
|
||||
DataSource as Connection,
|
||||
DataSourceOptions as ConnectionOptions,
|
||||
Repository,
|
||||
} from 'typeorm';
|
||||
import { DataSource as Connection, DataSourceOptions as ConnectionOptions } from 'typeorm';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
|
@ -14,7 +11,7 @@ import { mysqlMigrations } from '@db/migrations/mysqldb';
|
|||
import { postgresMigrations } from '@db/migrations/postgresdb';
|
||||
import { sqliteMigrations } from '@db/migrations/sqlite';
|
||||
import { hashPassword } from '@/UserManagement/UserManagementHelper';
|
||||
import { AuthIdentity } from '@/databases/entities/AuthIdentity';
|
||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||
import type { ExecutionEntity } from '@db/entities/ExecutionEntity';
|
||||
import { InstalledNodes } from '@db/entities/InstalledNodes';
|
||||
import { InstalledPackages } from '@db/entities/InstalledPackages';
|
||||
|
@ -22,6 +19,7 @@ import type { Role } from '@db/entities/Role';
|
|||
import type { TagEntity } from '@db/entities/TagEntity';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { RoleRepository } from '@db/repositories';
|
||||
import { ICredentialsDb } from '@/Interfaces';
|
||||
|
||||
import { DB_INITIALIZATION_TIMEOUT } from './constants';
|
||||
|
@ -104,8 +102,7 @@ export async function terminate() {
|
|||
*/
|
||||
export async function truncate(collections: CollectionName[]) {
|
||||
for (const collection of collections) {
|
||||
const repository: Repository<any> = Db.collections[collection];
|
||||
await repository.delete({});
|
||||
await Db.collections[collection].clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +139,7 @@ export async function saveCredential(
|
|||
}
|
||||
|
||||
export async function shareCredentialWithUsers(credential: CredentialsEntity, users: User[]) {
|
||||
const role = await Db.collections.Role.findOneBy({ scope: 'credential', name: 'user' });
|
||||
const role = await Container.get(RoleRepository).findCredentialUserRole();
|
||||
const newSharedCredentials = users.map((user) =>
|
||||
Db.collections.SharedCredentials.create({
|
||||
userId: user.id,
|
||||
|
@ -266,38 +263,23 @@ export async function addApiKey(user: User): Promise<User> {
|
|||
// ----------------------------------
|
||||
|
||||
export async function getGlobalOwnerRole() {
|
||||
return Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'global',
|
||||
});
|
||||
return Container.get(RoleRepository).findGlobalOwnerRoleOrFail();
|
||||
}
|
||||
|
||||
export async function getGlobalMemberRole() {
|
||||
return Db.collections.Role.findOneByOrFail({
|
||||
name: 'member',
|
||||
scope: 'global',
|
||||
});
|
||||
return Container.get(RoleRepository).findGlobalMemberRoleOrFail();
|
||||
}
|
||||
|
||||
export async function getWorkflowOwnerRole() {
|
||||
return Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'workflow',
|
||||
});
|
||||
return Container.get(RoleRepository).findWorkflowOwnerRoleOrFail();
|
||||
}
|
||||
|
||||
export async function getWorkflowEditorRole() {
|
||||
return Db.collections.Role.findOneByOrFail({
|
||||
name: 'editor',
|
||||
scope: 'workflow',
|
||||
});
|
||||
return Container.get(RoleRepository).findWorkflowEditorRoleOrFail();
|
||||
}
|
||||
|
||||
export async function getCredentialOwnerRole() {
|
||||
return Db.collections.Role.findOneByOrFail({
|
||||
name: 'owner',
|
||||
scope: 'credential',
|
||||
});
|
||||
return Container.get(RoleRepository).findCredentialOwnerRoleOrFail();
|
||||
}
|
||||
|
||||
export async function getAllRoles() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import Container from 'typedi';
|
||||
import { Container } from 'typedi';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import type { INode } from 'n8n-workflow';
|
||||
|
@ -51,7 +51,6 @@ beforeEach(async () => {
|
|||
});
|
||||
|
||||
afterAll(async () => {
|
||||
Container.reset();
|
||||
await testDb.terminate();
|
||||
});
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@ import {
|
|||
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
import * as Db from '@/Db';
|
||||
import { WorkflowEntity } from '@/databases/entities/WorkflowEntity';
|
||||
import { SharedWorkflow } from '@/databases/entities/SharedWorkflow';
|
||||
import { Role } from '@/databases/entities/Role';
|
||||
import { User } from '@/databases/entities/User';
|
||||
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { Role } from '@db/entities/Role';
|
||||
import { User } from '@db/entities/User';
|
||||
import { getLogger } from '@/Logger';
|
||||
import { randomEmail, randomName } from '../integration/shared/random';
|
||||
import * as Helpers from './Helpers';
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { IRun, LoggerProxy, WorkflowExecuteMode } from 'n8n-workflow';
|
||||
import { QueryFailedError, Repository } from 'typeorm';
|
||||
import { QueryFailedError } from 'typeorm';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
|
||||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
import { User } from '@db/entities/User';
|
||||
import { WorkflowStatistics } from '@db/entities/WorkflowStatistics';
|
||||
import { WorkflowStatisticsRepository } from '@db/repositories';
|
||||
import { nodeFetchedData, workflowExecutionCompleted } from '@/events/WorkflowStatistics';
|
||||
import * as UserManagementHelper from '@/UserManagement/UserManagementHelper';
|
||||
import { getLogger } from '@/Logger';
|
||||
|
@ -14,7 +15,6 @@ import { InternalHooks } from '@/InternalHooks';
|
|||
import { mockInstance } from '../integration/shared/utils';
|
||||
import { UserService } from '@/user/user.service';
|
||||
|
||||
type WorkflowStatisticsRepository = Repository<WorkflowStatistics>;
|
||||
jest.mock('@/Db', () => {
|
||||
return {
|
||||
collections: {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { mock, anyObject, captor } from 'jest-mock-extended';
|
|||
import type { ILogger } from 'n8n-workflow';
|
||||
import type { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { UserRepository } from '@db/repositories';
|
||||
import { MeController } from '@/controllers';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
|
@ -15,7 +16,7 @@ describe('MeController', () => {
|
|||
const logger = mock<ILogger>();
|
||||
const externalHooks = mock<IExternalHooksClass>();
|
||||
const internalHooks = mock<IInternalHooksClass>();
|
||||
const userRepository = mock<Repository<User>>();
|
||||
const userRepository = mock<UserRepository>();
|
||||
const controller = new MeController({
|
||||
logger,
|
||||
externalHooks,
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import type { Repository } from 'typeorm';
|
||||
import type { CookieOptions, Response } from 'express';
|
||||
import { anyObject, captor, mock } from 'jest-mock-extended';
|
||||
import type { ILogger } from 'n8n-workflow';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import type { ICredentialsDb, IInternalHooksClass } from '@/Interfaces';
|
||||
import type { IInternalHooksClass } from '@/Interfaces';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { Settings } from '@db/entities/Settings';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type {
|
||||
CredentialsRepository,
|
||||
SettingsRepository,
|
||||
UserRepository,
|
||||
WorkflowRepository,
|
||||
} from '@db/repositories';
|
||||
import type { Config } from '@/config';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { OwnerRequest } from '@/requests';
|
||||
|
@ -18,10 +21,10 @@ describe('OwnerController', () => {
|
|||
const config = mock<Config>();
|
||||
const logger = mock<ILogger>();
|
||||
const internalHooks = mock<IInternalHooksClass>();
|
||||
const userRepository = mock<Repository<User>>();
|
||||
const settingsRepository = mock<Repository<Settings>>();
|
||||
const credentialsRepository = mock<Repository<ICredentialsDb>>();
|
||||
const workflowsRepository = mock<Repository<WorkflowEntity>>();
|
||||
const userRepository = mock<UserRepository>();
|
||||
const settingsRepository = mock<SettingsRepository>();
|
||||
const credentialsRepository = mock<CredentialsRepository>();
|
||||
const workflowsRepository = mock<WorkflowRepository>();
|
||||
const controller = new OwnerController({
|
||||
config,
|
||||
logger,
|
||||
|
|
47
packages/cli/test/unit/repositories/role.repository.test.ts
Normal file
47
packages/cli/test/unit/repositories/role.repository.test.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { Container } from 'typedi';
|
||||
import { DataSource, EntityManager } from 'typeorm';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { Role, RoleNames, RoleScopes } from '@db/entities/Role';
|
||||
import { RoleRepository } from '@db/repositories/role.repository';
|
||||
import { mockInstance } from '../../integration/shared/utils';
|
||||
import { randomInteger } from '../../integration/shared/random';
|
||||
|
||||
describe('RoleRepository', () => {
|
||||
const entityManager = mockInstance(EntityManager);
|
||||
const dataSource = mockInstance(DataSource, { manager: entityManager });
|
||||
dataSource.getMetadata.mockReturnValue(mock());
|
||||
Object.assign(entityManager, { connection: dataSource });
|
||||
const roleRepository = Container.get(RoleRepository);
|
||||
|
||||
describe('findRole', () => {
|
||||
test('should return the role when present', async () => {
|
||||
entityManager.findOne.mockResolvedValueOnce(createRole('global', 'owner'));
|
||||
const role = await roleRepository.findRole('global', 'owner');
|
||||
expect(role?.name).toEqual('owner');
|
||||
expect(role?.scope).toEqual('global');
|
||||
});
|
||||
|
||||
test('should return null otherwise', async () => {
|
||||
entityManager.findOne.mockResolvedValueOnce(null);
|
||||
const role = await roleRepository.findRole('global', 'owner');
|
||||
expect(role).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findRoleOrFail', () => {
|
||||
test('should return the role when present', async () => {
|
||||
entityManager.findOneOrFail.mockResolvedValueOnce(createRole('global', 'owner'));
|
||||
const role = await roleRepository.findRoleOrFail('global', 'owner');
|
||||
expect(role?.name).toEqual('owner');
|
||||
expect(role?.scope).toEqual('global');
|
||||
});
|
||||
|
||||
test('should throw otherwise', async () => {
|
||||
entityManager.findOneOrFail.mockRejectedValueOnce(new Error());
|
||||
expect(() => roleRepository.findRoleOrFail('global', 'owner')).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
const createRole = (scope: RoleScopes, name: RoleNames) =>
|
||||
Object.assign(new Role(), { name, scope, id: `${randomInteger()}` });
|
||||
});
|
28
packages/cli/test/unit/services/role.service.test.ts
Normal file
28
packages/cli/test/unit/services/role.service.test.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||
import { Role } from '@db/entities/Role';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { RoleService } from '@/role/role.service';
|
||||
import { mockInstance } from '../../integration/shared/utils';
|
||||
|
||||
describe('RoleService', () => {
|
||||
const sharedWorkflowRepository = mockInstance(SharedWorkflowRepository);
|
||||
const roleService = new RoleService(sharedWorkflowRepository);
|
||||
|
||||
const userId = '1';
|
||||
const workflowId = '42';
|
||||
|
||||
describe('getUserRoleForWorkflow', () => {
|
||||
test('should return the role if a shared workflow is found', async () => {
|
||||
const sharedWorkflow = Object.assign(new SharedWorkflow(), { role: new Role() });
|
||||
sharedWorkflowRepository.findOne.mockResolvedValueOnce(sharedWorkflow);
|
||||
const role = await roleService.getUserRoleForWorkflow(userId, workflowId);
|
||||
expect(role).toBe(sharedWorkflow.role);
|
||||
});
|
||||
|
||||
test('should return undefined if no shared workflow is found', async () => {
|
||||
sharedWorkflowRepository.findOne.mockResolvedValueOnce(null);
|
||||
const role = await roleService.getUserRoleForWorkflow(userId, workflowId);
|
||||
expect(role).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue