mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
refactor: Upgrade typeorm to 0.3.x (#5151)
This commit is contained in:
parent
6608e69457
commit
0a5ab560b1
|
@ -161,7 +161,7 @@
|
||||||
"lodash.uniqby": "^4.7.0",
|
"lodash.uniqby": "^4.7.0",
|
||||||
"lodash.unset": "^4.5.2",
|
"lodash.unset": "^4.5.2",
|
||||||
"luxon": "^3.1.0",
|
"luxon": "^3.1.0",
|
||||||
"mysql2": "~2.3.0",
|
"mysql2": "~2.3.3",
|
||||||
"n8n-core": "~0.151.0",
|
"n8n-core": "~0.151.0",
|
||||||
"n8n-editor-ui": "~0.177.0",
|
"n8n-editor-ui": "~0.177.0",
|
||||||
"n8n-nodes-base": "~0.209.0",
|
"n8n-nodes-base": "~0.209.0",
|
||||||
|
@ -175,7 +175,7 @@
|
||||||
"passport": "^0.6.0",
|
"passport": "^0.6.0",
|
||||||
"passport-cookie": "^1.0.9",
|
"passport-cookie": "^1.0.9",
|
||||||
"passport-jwt": "^4.0.0",
|
"passport-jwt": "^4.0.0",
|
||||||
"pg": "^8.3.0",
|
"pg": "^8.8.0",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"posthog-node": "^2.2.2",
|
"posthog-node": "^2.2.2",
|
||||||
"prom-client": "^13.1.0",
|
"prom-client": "^13.1.0",
|
||||||
|
@ -184,12 +184,12 @@
|
||||||
"semver": "^7.3.8",
|
"semver": "^7.3.8",
|
||||||
"shelljs": "^0.8.5",
|
"shelljs": "^0.8.5",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"sqlite3": "^5.1.2",
|
"sqlite3": "^5.1.4",
|
||||||
"sse-channel": "^4.0.0",
|
"sse-channel": "^4.0.0",
|
||||||
"swagger-ui-express": "^4.3.0",
|
"swagger-ui-express": "^4.3.0",
|
||||||
"syslog-client": "^1.1.1",
|
"syslog-client": "^1.1.1",
|
||||||
"tslib": "1.14.1",
|
"tslib": "1.14.1",
|
||||||
"typeorm": "0.2.45",
|
"typeorm": "0.3.11",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"validator": "13.7.0",
|
"validator": "13.7.0",
|
||||||
"winston": "^3.3.3",
|
"winston": "^3.3.3",
|
||||||
|
|
|
@ -6,7 +6,6 @@ import bodyParser from 'body-parser';
|
||||||
import bodyParserXml from 'body-parser-xml';
|
import bodyParserXml from 'body-parser-xml';
|
||||||
import compression from 'compression';
|
import compression from 'compression';
|
||||||
import parseUrl from 'parseurl';
|
import parseUrl from 'parseurl';
|
||||||
import { getConnectionManager } from 'typeorm';
|
|
||||||
import type { RedisOptions } from 'ioredis';
|
import type { RedisOptions } from 'ioredis';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -162,10 +161,10 @@ export abstract class AbstractServer {
|
||||||
this.app.get('/healthz', async (req, res) => {
|
this.app.get('/healthz', async (req, res) => {
|
||||||
Logger.debug('Health check started!');
|
Logger.debug('Health check started!');
|
||||||
|
|
||||||
const connection = getConnectionManager().get();
|
const connection = Db.getConnection();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!connection.isConnected) {
|
if (!connection.isInitialized) {
|
||||||
// Connection is not active
|
// Connection is not active
|
||||||
throw new ServiceUnavailableError('No active database connection!');
|
throw new ServiceUnavailableError('No active database connection!');
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,18 +200,18 @@ export class ActiveWorkflowRunner {
|
||||||
path = path.slice(0, -1);
|
path = path.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let webhook = await Db.collections.Webhook.findOne({
|
let webhook = await Db.collections.Webhook.findOneBy({
|
||||||
webhookPath: path,
|
webhookPath: path,
|
||||||
method: httpMethod,
|
method: httpMethod,
|
||||||
});
|
});
|
||||||
let webhookId: string | undefined;
|
let webhookId: string | undefined;
|
||||||
|
|
||||||
// check if path is dynamic
|
// check if path is dynamic
|
||||||
if (webhook === undefined) {
|
if (webhook === null) {
|
||||||
// check if a dynamic webhook path exists
|
// check if a dynamic webhook path exists
|
||||||
const pathElements = path.split('/');
|
const pathElements = path.split('/');
|
||||||
webhookId = pathElements.shift();
|
webhookId = pathElements.shift();
|
||||||
const dynamicWebhooks = await Db.collections.Webhook.find({
|
const dynamicWebhooks = await Db.collections.Webhook.findBy({
|
||||||
webhookId,
|
webhookId,
|
||||||
method: httpMethod,
|
method: httpMethod,
|
||||||
pathLength: pathElements.length,
|
pathLength: pathElements.length,
|
||||||
|
@ -243,7 +243,7 @@ export class ActiveWorkflowRunner {
|
||||||
webhook = dynamicWebhook;
|
webhook = dynamicWebhook;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (webhook === undefined) {
|
if (webhook === null) {
|
||||||
throw new ResponseHelper.NotFoundError(
|
throw new ResponseHelper.NotFoundError(
|
||||||
`The requested webhook "${httpMethod} ${path}" is not registered.`,
|
`The requested webhook "${httpMethod} ${path}" is not registered.`,
|
||||||
WEBHOOK_PROD_UNREGISTERED_HINT,
|
WEBHOOK_PROD_UNREGISTERED_HINT,
|
||||||
|
@ -263,10 +263,11 @@ export class ActiveWorkflowRunner {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflowData = await Db.collections.Workflow.findOne(webhook.workflowId, {
|
const workflowData = await Db.collections.Workflow.findOne({
|
||||||
|
where: { id: webhook.workflowId },
|
||||||
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
||||||
});
|
});
|
||||||
if (workflowData === undefined) {
|
if (workflowData === null) {
|
||||||
throw new ResponseHelper.NotFoundError(
|
throw new ResponseHelper.NotFoundError(
|
||||||
`Could not find workflow with id "${webhook.workflowId}"`,
|
`Could not find workflow with id "${webhook.workflowId}"`,
|
||||||
);
|
);
|
||||||
|
@ -331,20 +332,19 @@ export class ActiveWorkflowRunner {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all request methods associated with a single webhook
|
* Gets all request methods associated with a single webhook
|
||||||
*
|
|
||||||
* @param {string} path webhook path
|
|
||||||
*/
|
*/
|
||||||
async getWebhookMethods(path: string): Promise<string[]> {
|
async getWebhookMethods(path: string): Promise<string[]> {
|
||||||
const webhooks = await Db.collections.Webhook.find({ webhookPath: path });
|
const webhooks = await Db.collections.Webhook.find({
|
||||||
|
select: ['method'],
|
||||||
|
where: { webhookPath: path },
|
||||||
|
});
|
||||||
|
|
||||||
// Gather all request methods in string array
|
// Gather all request methods in string array
|
||||||
const webhookMethods: string[] = webhooks.map((webhook) => webhook.method);
|
return webhooks.map((webhook) => webhook.method);
|
||||||
return webhookMethods;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ids of the currently active workflows
|
* Returns the ids of the currently active workflows
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
async getActiveWorkflows(user?: User): Promise<IWorkflowDb[]> {
|
async getActiveWorkflows(user?: User): Promise<IWorkflowDb[]> {
|
||||||
let activeWorkflows: WorkflowEntity[] = [];
|
let activeWorkflows: WorkflowEntity[] = [];
|
||||||
|
@ -378,7 +378,10 @@ export class ActiveWorkflowRunner {
|
||||||
* @param {string} id The id of the workflow to check
|
* @param {string} id The id of the workflow to check
|
||||||
*/
|
*/
|
||||||
async isActive(id: string): Promise<boolean> {
|
async isActive(id: string): Promise<boolean> {
|
||||||
const workflow = await Db.collections.Workflow.findOne(id);
|
const workflow = await Db.collections.Workflow.findOne({
|
||||||
|
select: ['active'],
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
return !!workflow?.active;
|
return !!workflow?.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,6 +437,7 @@ export class ActiveWorkflowRunner {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
// TODO: this should happen in a transaction, that way we don't need to manually remove this in `catch`
|
||||||
await Db.collections.Webhook.insert(webhook);
|
await Db.collections.Webhook.insert(webhook);
|
||||||
const webhookExists = await workflow.runWebhookMethod(
|
const webhookExists = await workflow.runWebhookMethod(
|
||||||
'checkExists',
|
'checkExists',
|
||||||
|
@ -503,10 +507,11 @@ export class ActiveWorkflowRunner {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
async removeWorkflowWebhooks(workflowId: string): Promise<void> {
|
async removeWorkflowWebhooks(workflowId: string): Promise<void> {
|
||||||
const workflowData = await Db.collections.Workflow.findOne(workflowId, {
|
const workflowData = await Db.collections.Workflow.findOne({
|
||||||
|
where: { id: workflowId },
|
||||||
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
||||||
});
|
});
|
||||||
if (workflowData === undefined) {
|
if (workflowData === null) {
|
||||||
throw new Error(`Could not find workflow with id "${workflowId}"`);
|
throw new Error(`Could not find workflow with id "${workflowId}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +777,8 @@ export class ActiveWorkflowRunner {
|
||||||
let workflowInstance: Workflow;
|
let workflowInstance: Workflow;
|
||||||
try {
|
try {
|
||||||
if (workflowData === undefined) {
|
if (workflowData === undefined) {
|
||||||
workflowData = (await Db.collections.Workflow.findOne(workflowId, {
|
workflowData = (await Db.collections.Workflow.findOne({
|
||||||
|
where: { id: workflowId },
|
||||||
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
relations: ['shared', 'shared.user', 'shared.user.globalRole'],
|
||||||
})) as IWorkflowDb;
|
})) as IWorkflowDb;
|
||||||
}
|
}
|
||||||
|
@ -883,7 +889,7 @@ export class ActiveWorkflowRunner {
|
||||||
/**
|
/**
|
||||||
* Add a workflow to the activation queue.
|
* Add a workflow to the activation queue.
|
||||||
* Meaning it will keep on trying to activate it in regular
|
* Meaning it will keep on trying to activate it in regular
|
||||||
* amounts indefinetly.
|
* amounts indefinitely.
|
||||||
*/
|
*/
|
||||||
addQueuedWorkflowActivation(
|
addQueuedWorkflowActivation(
|
||||||
activationMode: WorkflowActivateMode,
|
activationMode: WorkflowActivateMode,
|
||||||
|
@ -962,6 +968,7 @@ export class ActiveWorkflowRunner {
|
||||||
*
|
*
|
||||||
* @param {string} workflowId The id of the workflow to deactivate
|
* @param {string} workflowId The id of the workflow to deactivate
|
||||||
*/
|
*/
|
||||||
|
// TODO: this should happen in a transaction
|
||||||
async remove(workflowId: string): Promise<void> {
|
async remove(workflowId: string): Promise<void> {
|
||||||
if (this.activeWorkflows !== null) {
|
if (this.activeWorkflows !== null) {
|
||||||
// Remove all the webhooks of the workflow
|
// Remove all the webhooks of the workflow
|
||||||
|
|
|
@ -3,10 +3,11 @@ import * as Db from '@/Db';
|
||||||
import { InstalledNodes } from '@db/entities/InstalledNodes';
|
import { InstalledNodes } from '@db/entities/InstalledNodes';
|
||||||
import { InstalledPackages } from '@db/entities/InstalledPackages';
|
import { InstalledPackages } from '@db/entities/InstalledPackages';
|
||||||
|
|
||||||
export async function findInstalledPackage(
|
export async function findInstalledPackage(packageName: string): Promise<InstalledPackages | null> {
|
||||||
packageName: string,
|
return Db.collections.InstalledPackages.findOne({
|
||||||
): Promise<InstalledPackages | undefined> {
|
where: { packageName },
|
||||||
return Db.collections.InstalledPackages.findOne(packageName, { relations: ['installedNodes'] });
|
relations: ['installedNodes'],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isPackageInstalled(packageName: string): Promise<boolean> {
|
export async function isPackageInstalled(packageName: string): Promise<boolean> {
|
||||||
|
|
|
@ -270,7 +270,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||||
relations: ['credentials'],
|
relations: ['credentials'],
|
||||||
where: { credentials: { id: nodeCredential.id, type }, userId },
|
where: { credentials: { id: nodeCredential.id, type }, userId },
|
||||||
}).then((shared) => shared.credentials)
|
}).then((shared) => shared.credentials)
|
||||||
: await Db.collections.Credentials.findOneOrFail({ id: nodeCredential.id, type });
|
: await Db.collections.Credentials.findOneByOrFail({ id: nodeCredential.id, type });
|
||||||
|
|
||||||
if (!credential) {
|
if (!credential) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -765,8 +765,8 @@ export async function getCredentialForUser(
|
||||||
*/
|
*/
|
||||||
export async function getCredentialWithoutUser(
|
export async function getCredentialWithoutUser(
|
||||||
credentialId: string,
|
credentialId: string,
|
||||||
): Promise<ICredentialsDb | undefined> {
|
): Promise<ICredentialsDb | null> {
|
||||||
return Db.collections.Credentials.findOne(credentialId);
|
return Db.collections.Credentials.findOneBy({ id: credentialId });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createCredentialsFromCredentialsEntity(
|
export function createCredentialsFromCredentialsEntity(
|
||||||
|
|
|
@ -4,12 +4,10 @@
|
||||||
/* eslint-disable no-case-declarations */
|
/* eslint-disable no-case-declarations */
|
||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import {
|
import {
|
||||||
Connection,
|
DataSource as Connection,
|
||||||
ConnectionOptions,
|
DataSourceOptions as ConnectionOptions,
|
||||||
createConnection,
|
|
||||||
EntityManager,
|
EntityManager,
|
||||||
EntityTarget,
|
EntityTarget,
|
||||||
getRepository,
|
|
||||||
LoggerOptions,
|
LoggerOptions,
|
||||||
ObjectLiteral,
|
ObjectLiteral,
|
||||||
Repository,
|
Repository,
|
||||||
|
@ -34,6 +32,8 @@ export const collections = {} as IDatabaseCollections;
|
||||||
|
|
||||||
export let connection: Connection;
|
export let connection: Connection;
|
||||||
|
|
||||||
|
export const getConnection = () => connection!;
|
||||||
|
|
||||||
export async function transaction<T>(fn: (entityManager: EntityManager) => Promise<T>): Promise<T> {
|
export async function transaction<T>(fn: (entityManager: EntityManager) => Promise<T>): Promise<T> {
|
||||||
return connection.transaction(fn);
|
return connection.transaction(fn);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ export async function transaction<T>(fn: (entityManager: EntityManager) => Promi
|
||||||
export function linkRepository<Entity extends ObjectLiteral>(
|
export function linkRepository<Entity extends ObjectLiteral>(
|
||||||
entityClass: EntityTarget<Entity>,
|
entityClass: EntityTarget<Entity>,
|
||||||
): Repository<Entity> {
|
): Repository<Entity> {
|
||||||
return getRepository(entityClass, connection.name);
|
return connection.getRepository(entityClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getConnectionOptions(dbType: DatabaseType): Promise<ConnectionOptions> {
|
export async function getConnectionOptions(dbType: DatabaseType): Promise<ConnectionOptions> {
|
||||||
|
@ -124,7 +124,8 @@ export async function init(
|
||||||
migrationsTransactionMode: 'each',
|
migrationsTransactionMode: 'each',
|
||||||
});
|
});
|
||||||
|
|
||||||
connection = await createConnection(connectionOptions);
|
connection = new Connection(connectionOptions);
|
||||||
|
await connection.initialize();
|
||||||
|
|
||||||
if (!testConnectionOptions && dbType === 'sqlite') {
|
if (!testConnectionOptions && dbType === 'sqlite') {
|
||||||
// This specific migration changes database metadata.
|
// This specific migration changes database metadata.
|
||||||
|
@ -146,8 +147,9 @@ export async function init(
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||||
if (migrations.length === 0) {
|
if (migrations.length === 0) {
|
||||||
await connection.close();
|
await connection.destroy();
|
||||||
connection = await createConnection(connectionOptions);
|
connection = new Connection(connectionOptions);
|
||||||
|
await connection.initialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ async function createApiRouter(
|
||||||
_scopes: unknown,
|
_scopes: unknown,
|
||||||
schema: OpenAPIV3.ApiKeySecurityScheme,
|
schema: OpenAPIV3.ApiKeySecurityScheme,
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
const apiKey = req.headers[schema.name.toLowerCase()];
|
const apiKey = req.headers[schema.name.toLowerCase()] as string;
|
||||||
const user = await Db.collections.User.findOne({
|
const user = await Db.collections.User.findOne({
|
||||||
where: { apiKey },
|
where: { apiKey },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import type { FindConditions } from 'typeorm';
|
|
||||||
import { UserSettings, Credentials } from 'n8n-core';
|
import { UserSettings, Credentials } from 'n8n-core';
|
||||||
import { IDataObject, INodeProperties, INodePropertyOptions } from 'n8n-workflow';
|
import { IDataObject, INodeProperties, INodePropertyOptions } from 'n8n-workflow';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
|
@ -10,17 +9,22 @@ import { ExternalHooks } from '@/ExternalHooks';
|
||||||
import { IDependency, IJsonSchema } from '../../../types';
|
import { IDependency, IJsonSchema } from '../../../types';
|
||||||
import { CredentialRequest } from '@/requests';
|
import { CredentialRequest } from '@/requests';
|
||||||
|
|
||||||
export async function getCredentials(credentialId: string): Promise<ICredentialsDb | undefined> {
|
export async function getCredentials(credentialId: string): Promise<ICredentialsDb | null> {
|
||||||
return Db.collections.Credentials.findOne(credentialId);
|
return Db.collections.Credentials.findOneBy({ id: credentialId });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSharedCredentials(
|
export async function getSharedCredentials(
|
||||||
userId: string,
|
userId: string,
|
||||||
credentialId: string,
|
credentialId: string,
|
||||||
relations?: string[],
|
relations?: string[],
|
||||||
): Promise<SharedCredentials | undefined> {
|
): Promise<SharedCredentials | null> {
|
||||||
const where: FindConditions<SharedCredentials> = { userId, credentialsId: credentialId };
|
return Db.collections.SharedCredentials.findOne({
|
||||||
return Db.collections.SharedCredentials.findOne({ where, relations });
|
where: {
|
||||||
|
userId,
|
||||||
|
credentialsId: credentialId,
|
||||||
|
},
|
||||||
|
relations,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createCredential(
|
export async function createCredential(
|
||||||
|
@ -53,7 +57,7 @@ export async function saveCredential(
|
||||||
user: User,
|
user: User,
|
||||||
encryptedData: ICredentialsDb,
|
encryptedData: ICredentialsDb,
|
||||||
): Promise<CredentialsEntity> {
|
): Promise<CredentialsEntity> {
|
||||||
const role = await Db.collections.Role.findOneOrFail({
|
const role = await Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'credential',
|
scope: 'credential',
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import { parse } from 'flatted';
|
import { parse } from 'flatted';
|
||||||
import { In, Not, Raw, LessThan, IsNull, FindOperator } from 'typeorm';
|
import { In, Not, Raw, LessThan, IsNull, FindOptionsWhere } from 'typeorm';
|
||||||
|
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import type { IExecutionFlattedDb, IExecutionResponseApi } from '@/Interfaces';
|
import type { IExecutionFlattedDb, IExecutionResponseApi } from '@/Interfaces';
|
||||||
import { ExecutionEntity } from '@db/entities/ExecutionEntity';
|
import type { ExecutionStatus } from '@/PublicApi/types';
|
||||||
import { ExecutionStatus } from '@/PublicApi/types';
|
|
||||||
|
|
||||||
function prepareExecutionData(
|
function prepareExecutionData(
|
||||||
execution: IExecutionFlattedDb | undefined,
|
execution: IExecutionFlattedDb | null,
|
||||||
): IExecutionResponseApi | undefined {
|
): IExecutionResponseApi | undefined {
|
||||||
if (!execution) return undefined;
|
if (!execution) return undefined;
|
||||||
|
|
||||||
|
@ -21,11 +20,10 @@ function prepareExecutionData(
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatusCondition(status: ExecutionStatus) {
|
function getStatusCondition(status: ExecutionStatus) {
|
||||||
const condition: {
|
const condition: Pick<
|
||||||
finished?: boolean;
|
FindOptionsWhere<IExecutionFlattedDb>,
|
||||||
waitTill?: FindOperator<ExecutionEntity>;
|
'finished' | 'waitTill' | 'stoppedAt'
|
||||||
stoppedAt?: FindOperator<ExecutionEntity>;
|
> = {};
|
||||||
} = {};
|
|
||||||
|
|
||||||
if (status === 'success') {
|
if (status === 'success') {
|
||||||
condition.finished = true;
|
condition.finished = true;
|
||||||
|
@ -65,12 +63,7 @@ export async function getExecutions(params: {
|
||||||
status?: ExecutionStatus;
|
status?: ExecutionStatus;
|
||||||
excludedExecutionsIds?: string[];
|
excludedExecutionsIds?: string[];
|
||||||
}): Promise<IExecutionResponseApi[]> {
|
}): Promise<IExecutionResponseApi[]> {
|
||||||
type WhereClause = Record<
|
let where: FindOptionsWhere<IExecutionFlattedDb> = {};
|
||||||
string,
|
|
||||||
string | boolean | FindOperator<string | Partial<ExecutionEntity>>
|
|
||||||
>;
|
|
||||||
|
|
||||||
let where: WhereClause = {};
|
|
||||||
|
|
||||||
if (params.lastId && params.excludedExecutionsIds?.length) {
|
if (params.lastId && params.excludedExecutionsIds?.length) {
|
||||||
where.id = Raw((id) => `${id} < :lastId AND ${id} NOT IN (:...excludedExecutionsIds)`, {
|
where.id = Raw((id) => `${id} < :lastId AND ${id} NOT IN (:...excludedExecutionsIds)`, {
|
||||||
|
|
|
@ -7,7 +7,7 @@ export function isInstanceOwner(user: User): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getWorkflowOwnerRole(): Promise<Role> {
|
export async function getWorkflowOwnerRole(): Promise<Role> {
|
||||||
return Db.collections.Role.findOneOrFail({
|
return Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'workflow',
|
scope: 'workflow',
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
|
||||||
import { FindConditions, FindManyOptions, In } from 'typeorm';
|
import { FindManyOptions, FindOptionsWhere, In } from 'typeorm';
|
||||||
|
|
||||||
import * as ActiveWorkflowRunner from '@/ActiveWorkflowRunner';
|
import * as ActiveWorkflowRunner from '@/ActiveWorkflowRunner';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
@ -100,7 +100,7 @@ export = {
|
||||||
let workflows: WorkflowEntity[];
|
let workflows: WorkflowEntity[];
|
||||||
let count: number;
|
let count: number;
|
||||||
|
|
||||||
const where: FindConditions<WorkflowEntity> = {
|
const where: FindOptionsWhere<WorkflowEntity> = {
|
||||||
...(active !== undefined && { active }),
|
...(active !== undefined && { active }),
|
||||||
};
|
};
|
||||||
const query: FindManyOptions<WorkflowEntity> = {
|
const query: FindManyOptions<WorkflowEntity> = {
|
||||||
|
|
|
@ -17,7 +17,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 sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
||||||
where: { user },
|
where: { userId: user.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
return sharedWorkflows.map(({ workflowId }) => workflowId);
|
return sharedWorkflows.map(({ workflowId }) => workflowId);
|
||||||
|
@ -26,10 +26,10 @@ export async function getSharedWorkflowIds(user: User): Promise<string[]> {
|
||||||
export async function getSharedWorkflow(
|
export async function getSharedWorkflow(
|
||||||
user: User,
|
user: User,
|
||||||
workflowId?: string | undefined,
|
workflowId?: string | undefined,
|
||||||
): Promise<SharedWorkflow | undefined> {
|
): Promise<SharedWorkflow | null> {
|
||||||
return Db.collections.SharedWorkflow.findOne({
|
return Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
...(!isInstanceOwner(user) && { user }),
|
...(!isInstanceOwner(user) && { userId: user.id }),
|
||||||
...(workflowId && { workflowId }),
|
...(workflowId && { workflowId }),
|
||||||
},
|
},
|
||||||
relations: [...insertIf(!config.getEnv('workflowTagsDisabled'), ['workflow.tags']), 'workflow'],
|
relations: [...insertIf(!config.getEnv('workflowTagsDisabled'), ['workflow.tags']), 'workflow'],
|
||||||
|
@ -45,14 +45,14 @@ export async function getSharedWorkflows(
|
||||||
): Promise<SharedWorkflow[]> {
|
): Promise<SharedWorkflow[]> {
|
||||||
return Db.collections.SharedWorkflow.find({
|
return Db.collections.SharedWorkflow.find({
|
||||||
where: {
|
where: {
|
||||||
...(!isInstanceOwner(user) && { user }),
|
...(!isInstanceOwner(user) && { userId: user.id }),
|
||||||
...(options.workflowIds && { workflowId: In(options.workflowIds) }),
|
...(options.workflowIds && { workflowId: In(options.workflowIds) }),
|
||||||
},
|
},
|
||||||
...(options.relations && { relations: options.relations }),
|
...(options.relations && { relations: options.relations }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getWorkflowById(id: string): Promise<WorkflowEntity | undefined> {
|
export async function getWorkflowById(id: string): Promise<WorkflowEntity | null> {
|
||||||
return Db.collections.Workflow.findOne({
|
return Db.collections.Workflow.findOne({
|
||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
|
|
|
@ -1246,9 +1246,9 @@ class Server extends AbstractServer {
|
||||||
await queue.stopJob(job);
|
await queue.stopJob(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
const executionDb = (await Db.collections.Execution.findOne(
|
const executionDb = (await Db.collections.Execution.findOneBy({
|
||||||
req.params.id,
|
id: req.params.id,
|
||||||
)) as IExecutionFlattedDb;
|
})) as IExecutionFlattedDb;
|
||||||
const fullExecutionData = ResponseHelper.unflattenExecutionData(executionDb);
|
const fullExecutionData = ResponseHelper.unflattenExecutionData(executionDb);
|
||||||
|
|
||||||
const returnData: IExecutionsStopData = {
|
const returnData: IExecutionsStopData = {
|
||||||
|
@ -1452,9 +1452,10 @@ export async function start(): Promise<void> {
|
||||||
// Set up event handling
|
// Set up event handling
|
||||||
initEvents();
|
initEvents();
|
||||||
|
|
||||||
const workflow = await Db.collections.Workflow!.findOne({
|
const workflow = await Db.collections.Workflow.findOne({
|
||||||
select: ['createdAt'],
|
select: ['createdAt'],
|
||||||
order: { createdAt: 'ASC' },
|
order: { createdAt: 'ASC' },
|
||||||
|
where: {},
|
||||||
});
|
});
|
||||||
await InternalHooksManager.getInstance().onServerStarted(diagnosticInfo, workflow?.createdAt);
|
await InternalHooksManager.getInstance().onServerStarted(diagnosticInfo, workflow?.createdAt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { EntityManager, getConnection } from 'typeorm';
|
import type { EntityManager } from 'typeorm';
|
||||||
|
|
||||||
|
import { getConnection } from '@/Db';
|
||||||
import { TagEntity } from '@db/entities/TagEntity';
|
import { TagEntity } from '@db/entities/TagEntity';
|
||||||
|
import type { ITagToImport, ITagWithCountDb, IWorkflowToImport } from '@/Interfaces';
|
||||||
import { ITagToImport, ITagWithCountDb, IWorkflowToImport } from '@/Interfaces';
|
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// utils
|
// utils
|
||||||
|
|
|
@ -5,11 +5,11 @@ import {
|
||||||
Workflow,
|
Workflow,
|
||||||
WorkflowOperationError,
|
WorkflowOperationError,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { FindConditions, In } from 'typeorm';
|
import { FindOptionsWhere, In } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
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 { getRole, getWorkflowOwner, isSharingEnabled } from './UserManagementHelper';
|
import { getRoleId, getWorkflowOwner, isSharingEnabled } from './UserManagementHelper';
|
||||||
import { WorkflowsService } from '@/workflows/workflows.services';
|
import { WorkflowsService } from '@/workflows/workflows.services';
|
||||||
import { UserService } from '@/user/user.service';
|
import { UserService } from '@/user/user.service';
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@ export class PermissionChecker {
|
||||||
|
|
||||||
// allow if requesting user is instance owner
|
// allow if requesting user is instance owner
|
||||||
|
|
||||||
const user = await Db.collections.User.findOneOrFail(userId, {
|
const user = await Db.collections.User.findOneOrFail({
|
||||||
|
where: { id: userId },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -47,11 +48,11 @@ export class PermissionChecker {
|
||||||
workflowUserIds = workflowSharings.map((s) => s.userId);
|
workflowUserIds = workflowSharings.map((s) => s.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const credentialsWhere: FindConditions<SharedCredentials> = { userId: In(workflowUserIds) };
|
const credentialsWhere: FindOptionsWhere<SharedCredentials> = { userId: In(workflowUserIds) };
|
||||||
|
|
||||||
if (!isSharingEnabled()) {
|
if (!isSharingEnabled()) {
|
||||||
// If credential sharing is not enabled, get only credentials owned by this user
|
// If credential sharing is not enabled, get only credentials owned by this user
|
||||||
credentialsWhere.role = await getRole('credential', 'owner');
|
credentialsWhere.roleId = await getRoleId('credential', 'owner');
|
||||||
}
|
}
|
||||||
|
|
||||||
const credentialSharings = await Db.collections.SharedCredentials.find({
|
const credentialSharings = await Db.collections.SharedCredentials.find({
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||||
import { INode, NodeOperationError, Workflow } from 'n8n-workflow';
|
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { compare, genSaltSync, hash } from 'bcryptjs';
|
import { compare, genSaltSync, hash } from 'bcryptjs';
|
||||||
|
@ -21,7 +20,7 @@ export async function getWorkflowOwner(workflowId: string): Promise<User> {
|
||||||
const workflowOwnerRole = await RoleService.get({ name: 'owner', scope: 'workflow' });
|
const workflowOwnerRole = await RoleService.get({ name: 'owner', scope: 'workflow' });
|
||||||
|
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOneOrFail({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOneOrFail({
|
||||||
where: { workflowId, role: workflowOwnerRole },
|
where: { workflowId, roleId: workflowOwnerRole?.id ?? undefined },
|
||||||
relations: ['user', 'user.globalRole'],
|
relations: ['user', 'user.globalRole'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -59,35 +58,26 @@ export function isUserManagementDisabled(): boolean {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getInstanceOwnerRole(): Promise<Role> {
|
export async function getRoleId(scope: Role['scope'], name: Role['name']): Promise<Role['id']> {
|
||||||
const ownerRole = await Db.collections.Role.findOneOrFail({
|
|
||||||
where: {
|
|
||||||
name: 'owner',
|
|
||||||
scope: 'global',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return ownerRole;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getInstanceOwner(): Promise<User> {
|
|
||||||
const ownerRole = await getInstanceOwnerRole();
|
|
||||||
|
|
||||||
const owner = await Db.collections.User.findOneOrFail({
|
|
||||||
relations: ['globalRole'],
|
|
||||||
where: {
|
|
||||||
globalRole: ownerRole,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getRole(scope: Role['scope'], name: Role['name']): Promise<Role> {
|
|
||||||
return Db.collections.Role.findOneOrFail({
|
return Db.collections.Role.findOneOrFail({
|
||||||
|
select: ['id'],
|
||||||
where: {
|
where: {
|
||||||
name,
|
name,
|
||||||
scope,
|
scope,
|
||||||
},
|
},
|
||||||
|
}).then((role) => role.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getInstanceOwner(): Promise<User> {
|
||||||
|
const ownerRoleId = await getRoleId('global', 'owner');
|
||||||
|
|
||||||
|
const owner = await Db.collections.User.findOneOrFail({
|
||||||
|
relations: ['globalRole'],
|
||||||
|
where: {
|
||||||
|
globalRoleId: ownerRoleId,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -168,7 +158,8 @@ export function addInviteLinktoUser(user: PublicUser, inviterId: string): Public
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserById(userId: string): Promise<User> {
|
export async function getUserById(userId: string): Promise<User> {
|
||||||
const user = await Db.collections.User.findOneOrFail(userId, {
|
const user = await Db.collections.User.findOneOrFail({
|
||||||
|
where: { id: userId },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
});
|
});
|
||||||
return user;
|
return user;
|
||||||
|
|
|
@ -36,7 +36,8 @@ export function issueJWT(user: User): JwtToken {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveJwtContent(jwtPayload: JwtPayload): Promise<User> {
|
export async function resolveJwtContent(jwtPayload: JwtPayload): Promise<User> {
|
||||||
const user = await Db.collections.User.findOne(jwtPayload.id, {
|
const user = await Db.collections.User.findOne({
|
||||||
|
where: { id: jwtPayload.id },
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -30,14 +30,12 @@ export function authenticationMethods(this: N8nApp): void {
|
||||||
throw new Error('Password is required to log in');
|
throw new Error('Password is required to log in');
|
||||||
}
|
}
|
||||||
|
|
||||||
let user: User | undefined;
|
let user: User | null;
|
||||||
try {
|
try {
|
||||||
user = await Db.collections.User.findOne(
|
user = await Db.collections.User.findOne({
|
||||||
{ email },
|
where: { email },
|
||||||
{
|
relations: ['globalRole'],
|
||||||
relations: ['globalRole'],
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error('Unable to access database.');
|
throw new Error('Unable to access database.');
|
||||||
}
|
}
|
||||||
|
@ -77,7 +75,7 @@ export function authenticationMethods(this: N8nApp): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
user = await Db.collections.User.findOneOrFail({ relations: ['globalRole'] });
|
user = await Db.collections.User.findOneOrFail({ relations: ['globalRole'], where: {} });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ResponseHelper.InternalServerError(
|
throw new ResponseHelper.InternalServerError(
|
||||||
'No users found in database - did you wipe the users table? Create at least one user.',
|
'No users found in database - did you wipe the users table? Create at least one user.',
|
||||||
|
|
|
@ -54,12 +54,10 @@ export function addRoutes(this: N8nApp, ignoredEndpoints: string[], restEndpoint
|
||||||
|
|
||||||
// skip authentication if user management is disabled
|
// skip authentication if user management is disabled
|
||||||
if (isUserManagementDisabled()) {
|
if (isUserManagementDisabled()) {
|
||||||
req.user = await Db.collections.User.findOneOrFail(
|
req.user = await Db.collections.User.findOneOrFail({
|
||||||
{},
|
relations: ['globalRole'],
|
||||||
{
|
where: {},
|
||||||
relations: ['globalRole'],
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,9 @@ export function ownerNamespace(this: N8nApp): void {
|
||||||
throw new ResponseHelper.BadRequestError('First and last names are mandatory');
|
throw new ResponseHelper.BadRequestError('First and last names are mandatory');
|
||||||
}
|
}
|
||||||
|
|
||||||
let owner = await Db.collections.User.findOne(userId, {
|
let owner = await Db.collections.User.findOne({
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
|
where: { id: userId },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!owner || (owner.globalRole.scope === 'global' && owner.globalRole.name !== 'owner')) {
|
if (!owner || (owner.globalRole.scope === 'global' && owner.globalRole.name !== 'owner')) {
|
||||||
|
|
|
@ -52,7 +52,7 @@ export function passwordResetNamespace(this: N8nApp): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// User should just be able to reset password if one is already present
|
// User should just be able to reset password if one is already present
|
||||||
const user = await Db.collections.User.findOne({ email, password: Not(IsNull()) });
|
const user = await Db.collections.User.findOneBy({ email, password: Not(IsNull()) });
|
||||||
|
|
||||||
if (!user?.password) {
|
if (!user?.password) {
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
|
@ -133,7 +133,7 @@ export function passwordResetNamespace(this: N8nApp): void {
|
||||||
// Timestamp is saved in seconds
|
// Timestamp is saved in seconds
|
||||||
const currentTimestamp = Math.floor(Date.now() / 1000);
|
const currentTimestamp = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
const user = await Db.collections.User.findOne({
|
const user = await Db.collections.User.findOneBy({
|
||||||
id,
|
id,
|
||||||
resetPasswordToken,
|
resetPasswordToken,
|
||||||
resetPasswordTokenExpiration: MoreThanOrEqual(currentTimestamp),
|
resetPasswordTokenExpiration: MoreThanOrEqual(currentTimestamp),
|
||||||
|
@ -184,7 +184,7 @@ export function passwordResetNamespace(this: N8nApp): void {
|
||||||
// Timestamp is saved in seconds
|
// Timestamp is saved in seconds
|
||||||
const currentTimestamp = Math.floor(Date.now() / 1000);
|
const currentTimestamp = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
const user = await Db.collections.User.findOne({
|
const user = await Db.collections.User.findOneBy({
|
||||||
id: userId,
|
id: userId,
|
||||||
resetPasswordToken,
|
resetPasswordToken,
|
||||||
resetPasswordTokenExpiration: MoreThanOrEqual(currentTimestamp),
|
resetPasswordTokenExpiration: MoreThanOrEqual(currentTimestamp),
|
||||||
|
|
|
@ -85,7 +85,7 @@ export function usersNamespace(this: N8nApp): void {
|
||||||
createUsers[invite.email.toLowerCase()] = null;
|
createUsers[invite.email.toLowerCase()] = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
const role = await Db.collections.Role.findOne({ scope: 'global', name: 'member' });
|
const role = await Db.collections.Role.findOneBy({ scope: 'global', name: 'member' });
|
||||||
|
|
||||||
if (!role) {
|
if (!role) {
|
||||||
Logger.error(
|
Logger.error(
|
||||||
|
@ -434,7 +434,7 @@ export function usersNamespace(this: N8nApp): void {
|
||||||
.getRepository(SharedWorkflow)
|
.getRepository(SharedWorkflow)
|
||||||
.find({
|
.find({
|
||||||
select: ['workflowId'],
|
select: ['workflowId'],
|
||||||
where: { userId: userToDelete.id, role: workflowOwnerRole },
|
where: { userId: userToDelete.id, roleId: workflowOwnerRole?.id },
|
||||||
})
|
})
|
||||||
.then((sharedWorkflows) => sharedWorkflows.map(({ workflowId }) => workflowId));
|
.then((sharedWorkflows) => sharedWorkflows.map(({ workflowId }) => workflowId));
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ export function usersNamespace(this: N8nApp): void {
|
||||||
.getRepository(SharedCredentials)
|
.getRepository(SharedCredentials)
|
||||||
.find({
|
.find({
|
||||||
select: ['credentialsId'],
|
select: ['credentialsId'],
|
||||||
where: { user: userToDelete, role: credentialOwnerRole },
|
where: { userId: userToDelete.id, roleId: credentialOwnerRole?.id },
|
||||||
})
|
})
|
||||||
.then((sharedCredentials) =>
|
.then((sharedCredentials) =>
|
||||||
sharedCredentials.map(({ credentialsId }) => credentialsId),
|
sharedCredentials.map(({ credentialsId }) => credentialsId),
|
||||||
|
@ -495,11 +495,11 @@ export function usersNamespace(this: N8nApp): void {
|
||||||
const [ownedSharedWorkflows, ownedSharedCredentials] = await Promise.all([
|
const [ownedSharedWorkflows, ownedSharedCredentials] = await Promise.all([
|
||||||
Db.collections.SharedWorkflow.find({
|
Db.collections.SharedWorkflow.find({
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
where: { user: userToDelete, role: workflowOwnerRole },
|
where: { userId: userToDelete.id, roleId: workflowOwnerRole?.id },
|
||||||
}),
|
}),
|
||||||
Db.collections.SharedCredentials.find({
|
Db.collections.SharedCredentials.find({
|
||||||
relations: ['credentials'],
|
relations: ['credentials'],
|
||||||
where: { user: userToDelete, role: credentialOwnerRole },
|
where: { userId: userToDelete.id, roleId: credentialOwnerRole?.id },
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -546,7 +546,7 @@ export function usersNamespace(this: N8nApp): void {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const reinvitee = await Db.collections.User.findOne({ id: idToReinvite });
|
const reinvitee = await Db.collections.User.findOneBy({ id: idToReinvite });
|
||||||
|
|
||||||
if (!reinvitee) {
|
if (!reinvitee) {
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
|
|
|
@ -107,9 +107,9 @@ export class WaitTrackerClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check in database
|
// Also check in database
|
||||||
const execution = await Db.collections.Execution.findOne(executionId);
|
const execution = await Db.collections.Execution.findOneBy({ id: executionId });
|
||||||
|
|
||||||
if (execution === undefined || !execution.waitTill) {
|
if (execution === null || !execution.waitTill) {
|
||||||
throw new Error(`The execution ID "${executionId}" could not be found.`);
|
throw new Error(`The execution ID "${executionId}" could not be found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,9 +146,11 @@ export class WaitTrackerClass {
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
// Get the data to execute
|
// Get the data to execute
|
||||||
const fullExecutionDataFlatted = await Db.collections.Execution.findOne(executionId);
|
const fullExecutionDataFlatted = await Db.collections.Execution.findOneBy({
|
||||||
|
id: executionId,
|
||||||
|
});
|
||||||
|
|
||||||
if (fullExecutionDataFlatted === undefined) {
|
if (fullExecutionDataFlatted === null) {
|
||||||
throw new Error(`The execution with the id "${executionId}" does not exist.`);
|
throw new Error(`The execution with the id "${executionId}" does not exist.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,9 @@ export class WaitingWebhooks {
|
||||||
const executionId = pathParts.shift();
|
const executionId = pathParts.shift();
|
||||||
const path = pathParts.join('/');
|
const path = pathParts.join('/');
|
||||||
|
|
||||||
const execution = await Db.collections.Execution.findOne(executionId);
|
const execution = await Db.collections.Execution.findOneBy({ id: executionId });
|
||||||
|
|
||||||
if (execution === undefined) {
|
if (execution === null) {
|
||||||
throw new ResponseHelper.NotFoundError(`The execution "${executionId} does not exist.`);
|
throw new ResponseHelper.NotFoundError(`The execution "${executionId} does not exist.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ export async function WorkflowCredentials(nodes: INode[]): Promise<IWorkflowCred
|
||||||
|
|
||||||
if (!returnCredentials[type][nodeCredentials.id]) {
|
if (!returnCredentials[type][nodeCredentials.id]) {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
foundCredentials = await Db.collections.Credentials.findOne({
|
foundCredentials = await Db.collections.Credentials.findOneBy({
|
||||||
id: nodeCredentials.id,
|
id: nodeCredentials.id,
|
||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
|
|
|
@ -402,9 +402,9 @@ export function hookFunctionsPreExecute(parentProcessMode?: string): IWorkflowEx
|
||||||
{ executionId: this.executionId, nodeName },
|
{ executionId: this.executionId, nodeName },
|
||||||
);
|
);
|
||||||
|
|
||||||
const execution = await Db.collections.Execution.findOne(this.executionId);
|
const execution = await Db.collections.Execution.findOneBy({ id: this.executionId });
|
||||||
|
|
||||||
if (execution === undefined) {
|
if (execution === null) {
|
||||||
// Something went badly wrong if this happens.
|
// Something went badly wrong if this happens.
|
||||||
// This check is here mostly to make typescript happy.
|
// This check is here mostly to make typescript happy.
|
||||||
return;
|
return;
|
||||||
|
@ -829,7 +829,7 @@ export async function getWorkflowData(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let workflowData: IWorkflowBase | undefined;
|
let workflowData: IWorkflowBase | null;
|
||||||
if (workflowInfo.id !== undefined) {
|
if (workflowInfo.id !== undefined) {
|
||||||
if (!Db.isInitialized) {
|
if (!Db.isInitialized) {
|
||||||
// The first time executeWorkflow gets called the Database has
|
// The first time executeWorkflow gets called the Database has
|
||||||
|
@ -845,7 +845,7 @@ export async function getWorkflowData(
|
||||||
throw new Error(`The workflow with the id "${workflowInfo.id}" does not exist.`);
|
throw new Error(`The workflow with the id "${workflowInfo.id}" does not exist.`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
workflowData = workflowInfo.code;
|
workflowData = workflowInfo.code ?? null;
|
||||||
if (workflowData) {
|
if (workflowData) {
|
||||||
if (!workflowData.id) {
|
if (!workflowData.id) {
|
||||||
workflowData.id = parentWorkflowId;
|
workflowData.id = parentWorkflowId;
|
||||||
|
|
|
@ -88,7 +88,7 @@ export async function executeErrorWorkflow(
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// 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 {
|
||||||
let workflowData;
|
let workflowData: WorkflowEntity | null = null;
|
||||||
if (workflowId !== workflowErrorData.workflow.id) {
|
if (workflowId !== workflowErrorData.workflow.id) {
|
||||||
// To make this code easier to understand, we split it in 2 parts:
|
// To make this code easier to understand, we split it in 2 parts:
|
||||||
// 1) Fetch the owner of the errored workflows and then
|
// 1) Fetch the owner of the errored workflows and then
|
||||||
|
@ -99,7 +99,7 @@ export async function executeErrorWorkflow(
|
||||||
const user = await getWorkflowOwner(workflowErrorData.workflow.id!);
|
const user = await getWorkflowOwner(workflowErrorData.workflow.id!);
|
||||||
|
|
||||||
if (user.globalRole.name === 'owner') {
|
if (user.globalRole.name === 'owner') {
|
||||||
workflowData = await Db.collections.Workflow.findOne({ id: workflowId });
|
workflowData = await Db.collections.Workflow.findOneBy({ id: workflowId });
|
||||||
} else {
|
} else {
|
||||||
const sharedWorkflowData = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflowData = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: { workflowId, userId: user.id },
|
where: { workflowId, userId: user.id },
|
||||||
|
@ -110,10 +110,10 @@ export async function executeErrorWorkflow(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
workflowData = await Db.collections.Workflow.findOne({ id: workflowId });
|
workflowData = await Db.collections.Workflow.findOneBy({ id: workflowId });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workflowData === undefined) {
|
if (workflowData === null) {
|
||||||
// The error workflow could not be found
|
// The error workflow could not be found
|
||||||
Logger.error(
|
Logger.error(
|
||||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||||
|
@ -254,21 +254,13 @@ export async function saveStaticDataById(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the static data of workflow
|
* Returns the static data of workflow
|
||||||
*
|
|
||||||
* @param {(string)} workflowId The id of the workflow to get static data of
|
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
||||||
export async function getStaticDataById(workflowId: string) {
|
export async function getStaticDataById(workflowId: string) {
|
||||||
const workflowData = await Db.collections.Workflow.findOne(workflowId, {
|
const workflowData = await Db.collections.Workflow.findOne({
|
||||||
select: ['staticData'],
|
select: ['staticData'],
|
||||||
|
where: { id: workflowId },
|
||||||
});
|
});
|
||||||
|
return workflowData?.staticData ?? {};
|
||||||
if (workflowData === undefined) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
||||||
return workflowData.staticData || {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -312,7 +304,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.find({
|
const credentials = await Db.collections.Credentials.findBy({
|
||||||
name,
|
name,
|
||||||
type: nodeCredentialType,
|
type: nodeCredentialType,
|
||||||
});
|
});
|
||||||
|
@ -348,7 +340,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.findOne({
|
const credentials = await Db.collections.Credentials.findOneBy({
|
||||||
id: nodeCredentials.id,
|
id: nodeCredentials.id,
|
||||||
type: nodeCredentialType,
|
type: nodeCredentialType,
|
||||||
});
|
});
|
||||||
|
@ -362,7 +354,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.find({
|
const credsByName = await Db.collections.Credentials.findBy({
|
||||||
name: nodeCredentials.name,
|
name: nodeCredentials.name,
|
||||||
type: nodeCredentialType,
|
type: nodeCredentialType,
|
||||||
});
|
});
|
||||||
|
@ -414,14 +406,17 @@ export async function isBelowOnboardingThreshold(user: User): Promise<boolean> {
|
||||||
let belowThreshold = true;
|
let belowThreshold = true;
|
||||||
const skippedTypes = ['n8n-nodes-base.start', 'n8n-nodes-base.stickyNote'];
|
const skippedTypes = ['n8n-nodes-base.start', 'n8n-nodes-base.stickyNote'];
|
||||||
|
|
||||||
const workflowOwnerRole = await Db.collections.Role.findOne({
|
const workflowOwnerRoleId = await Db.collections.Role.findOne({
|
||||||
name: 'owner',
|
select: ['id'],
|
||||||
scope: 'workflow',
|
where: {
|
||||||
});
|
name: 'owner',
|
||||||
|
scope: 'workflow',
|
||||||
|
},
|
||||||
|
}).then((role) => role?.id);
|
||||||
const ownedWorkflowsIds = await Db.collections.SharedWorkflow.find({
|
const ownedWorkflowsIds = await Db.collections.SharedWorkflow.find({
|
||||||
where: {
|
where: {
|
||||||
user,
|
userId: user.id,
|
||||||
role: workflowOwnerRole,
|
roleId: workflowOwnerRoleId,
|
||||||
},
|
},
|
||||||
select: ['workflowId'],
|
select: ['workflowId'],
|
||||||
}).then((ownedWorkflows) => ownedWorkflows.map(({ workflowId }) => workflowId));
|
}).then((ownedWorkflows) => ownedWorkflows.map(({ workflowId }) => workflowId));
|
||||||
|
|
|
@ -527,9 +527,9 @@ export class WorkflowRunner {
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const executionDb = (await Db.collections.Execution.findOne(
|
const executionDb = (await Db.collections.Execution.findOneBy({
|
||||||
executionId,
|
id: executionId,
|
||||||
)) as IExecutionFlattedDb;
|
})) as IExecutionFlattedDb;
|
||||||
const fullExecutionData = ResponseHelper.unflattenExecutionData(executionDb);
|
const fullExecutionData = ResponseHelper.unflattenExecutionData(executionDb);
|
||||||
const runData = {
|
const runData = {
|
||||||
data: fullExecutionData.data,
|
data: fullExecutionData.data,
|
||||||
|
|
|
@ -99,11 +99,14 @@ e2eController.post('/db/setup-owner', bodyParser.json(), async (req, res) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalRole = await Db.collections.Role.findOneOrFail({
|
const globalRole = await Db.collections.Role.findOneOrFail({
|
||||||
name: 'owner',
|
select: ['id'],
|
||||||
scope: 'global',
|
where: {
|
||||||
|
name: 'owner',
|
||||||
|
scope: 'global',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const owner = await Db.collections.User.findOneOrFail({ globalRole });
|
const owner = await Db.collections.User.findOneByOrFail({ globalRoleId: globalRole.id });
|
||||||
|
|
||||||
await Db.collections.User.update(owner.id, {
|
await Db.collections.User.update(owner.id, {
|
||||||
email: req.body.email,
|
email: req.body.email,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { MoreThanOrEqual } from 'typeorm';
|
import { FindOperator, MoreThanOrEqual } from 'typeorm';
|
||||||
import { DateUtils } from 'typeorm/util/DateUtils';
|
import { DateUtils } from 'typeorm/util/DateUtils';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
@ -46,7 +46,7 @@ async function getExecutionsInPastDays(days: number) {
|
||||||
return Db.collections.Execution.find({
|
return Db.collections.Execution.find({
|
||||||
select: ['workflowData'],
|
select: ['workflowData'],
|
||||||
where: {
|
where: {
|
||||||
startedAt: MoreThanOrEqual(utcDate),
|
startedAt: MoreThanOrEqual(utcDate) as unknown as FindOperator<Date>,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,12 +38,12 @@ export abstract class BaseCommand extends Command {
|
||||||
};
|
};
|
||||||
|
|
||||||
async getInstanceOwner(): Promise<User> {
|
async getInstanceOwner(): Promise<User> {
|
||||||
const globalRole = await Db.collections.Role.findOneOrFail({
|
const globalRole = await Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'global',
|
scope: 'global',
|
||||||
});
|
});
|
||||||
|
|
||||||
const owner = await Db.collections.User.findOne({ globalRole });
|
const owner = await Db.collections.User.findOneBy({ globalRoleId: globalRole.id });
|
||||||
|
|
||||||
if (owner) return owner;
|
if (owner) return owner;
|
||||||
|
|
||||||
|
@ -53,6 +53,6 @@ export abstract class BaseCommand extends Command {
|
||||||
|
|
||||||
await Db.collections.User.save(user);
|
await Db.collections.User.save(user);
|
||||||
|
|
||||||
return Db.collections.User.findOneOrFail({ globalRole });
|
return Db.collections.User.findOneByOrFail({ globalRoleId: globalRole.id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import { Command, flags } from '@oclif/command';
|
import { Command, flags } from '@oclif/command';
|
||||||
import { Connection, ConnectionOptions, createConnection } from 'typeorm';
|
import { DataSource as Connection, DataSourceOptions as ConnectionOptions } from 'typeorm';
|
||||||
import { LoggerProxy } from 'n8n-workflow';
|
import { LoggerProxy } from 'n8n-workflow';
|
||||||
|
|
||||||
import { getLogger } from '@/Logger';
|
import { getLogger } from '@/Logger';
|
||||||
|
@ -34,11 +34,12 @@ export class DbRevertMigrationCommand extends Command {
|
||||||
dropSchema: false,
|
dropSchema: false,
|
||||||
logging: ['query', 'error', 'schema'],
|
logging: ['query', 'error', 'schema'],
|
||||||
};
|
};
|
||||||
connection = await createConnection(connectionOptions);
|
connection = new Connection(connectionOptions);
|
||||||
|
await connection.initialize();
|
||||||
await connection.undoLastMigration();
|
await connection.undoLastMigration();
|
||||||
await connection.close();
|
await connection.destroy();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (connection) await connection.close();
|
if (connection?.isInitialized) await connection.destroy();
|
||||||
|
|
||||||
console.error('Error reverting last migration. See log messages for details.');
|
console.error('Error reverting last migration. See log messages for details.');
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
|
|
|
@ -72,7 +72,7 @@ export class Execute extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
let workflowId: string | undefined;
|
let workflowId: string | undefined;
|
||||||
let workflowData: IWorkflowBase | undefined;
|
let workflowData: IWorkflowBase | null = null;
|
||||||
if (flags.file) {
|
if (flags.file) {
|
||||||
// Path to workflow is given
|
// Path to workflow is given
|
||||||
try {
|
try {
|
||||||
|
@ -91,7 +91,7 @@ export class Execute extends Command {
|
||||||
// Do a basic check if the data in the file looks right
|
// Do a basic check if the data in the file looks right
|
||||||
// TODO: Later check with the help of TypeScript data if it is valid or not
|
// TODO: Later check with the help of TypeScript data if it is valid or not
|
||||||
if (
|
if (
|
||||||
workflowData === undefined ||
|
workflowData === null ||
|
||||||
workflowData.nodes === undefined ||
|
workflowData.nodes === undefined ||
|
||||||
workflowData.connections === undefined
|
workflowData.connections === undefined
|
||||||
) {
|
) {
|
||||||
|
@ -108,8 +108,8 @@ export class Execute extends Command {
|
||||||
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.findOne(workflowId);
|
workflowData = await Db.collections.Workflow.findOneBy({ id: workflowId });
|
||||||
if (workflowData === undefined) {
|
if (workflowData === null) {
|
||||||
console.info(`The workflow with the id "${workflowId}" does not exist.`);
|
console.info(`The workflow with the id "${workflowId}" does not exist.`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { LoggerProxy } from 'n8n-workflow';
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import glob from 'fast-glob';
|
import glob from 'fast-glob';
|
||||||
import { EntityManager, getConnection } from 'typeorm';
|
import type { EntityManager } from 'typeorm';
|
||||||
import { getLogger } from '@/Logger';
|
import { getLogger } from '@/Logger';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import { User } from '@db/entities/User';
|
import { User } from '@db/entities/User';
|
||||||
|
@ -100,7 +100,7 @@ export class ImportCredentialsCommand extends Command {
|
||||||
|
|
||||||
totalImported = files.length;
|
totalImported = files.length;
|
||||||
|
|
||||||
await getConnection().transaction(async (transactionManager) => {
|
await Db.getConnection().transaction(async (transactionManager) => {
|
||||||
this.transactionManager = transactionManager;
|
this.transactionManager = transactionManager;
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const credential = JSON.parse(fs.readFileSync(file, { encoding: 'utf8' }));
|
const credential = JSON.parse(fs.readFileSync(file, { encoding: 'utf8' }));
|
||||||
|
@ -128,7 +128,7 @@ export class ImportCredentialsCommand extends Command {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await getConnection().transaction(async (transactionManager) => {
|
await Db.getConnection().transaction(async (transactionManager) => {
|
||||||
this.transactionManager = transactionManager;
|
this.transactionManager = transactionManager;
|
||||||
for (const credential of credentials) {
|
for (const credential of credentials) {
|
||||||
if (typeof credential.data === 'object') {
|
if (typeof credential.data === 'object') {
|
||||||
|
@ -187,7 +187,9 @@ export class ImportCredentialsCommand extends Command {
|
||||||
where: { name: 'owner', scope: 'global' },
|
where: { name: 'owner', scope: 'global' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const owner = await Db.collections.User.findOne({ globalRole: ownerGlobalRole });
|
const owner =
|
||||||
|
ownerGlobalRole &&
|
||||||
|
(await Db.collections.User.findOneBy({ globalRoleId: ownerGlobalRole.id }));
|
||||||
|
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
throw new Error(`Failed to find owner. ${FIX_INSTRUCTION}`);
|
throw new Error(`Failed to find owner. ${FIX_INSTRUCTION}`);
|
||||||
|
@ -197,7 +199,7 @@ export class ImportCredentialsCommand extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAssignee(userId: string) {
|
private async getAssignee(userId: string) {
|
||||||
const user = await Db.collections.User.findOne(userId);
|
const user = await Db.collections.User.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}`);
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { INode, INodeCredentialsDetails, LoggerProxy } from 'n8n-workflow';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import glob from 'fast-glob';
|
import glob from 'fast-glob';
|
||||||
import { UserSettings } from 'n8n-core';
|
import { UserSettings } from 'n8n-core';
|
||||||
import { EntityManager, getConnection } from 'typeorm';
|
import type { EntityManager } from 'typeorm';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { getLogger } from '@/Logger';
|
import { getLogger } from '@/Logger';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
|
@ -123,7 +123,7 @@ export class ImportWorkflowsCommand extends Command {
|
||||||
|
|
||||||
totalImported = files.length;
|
totalImported = files.length;
|
||||||
|
|
||||||
await getConnection().transaction(async (transactionManager) => {
|
await Db.getConnection().transaction(async (transactionManager) => {
|
||||||
this.transactionManager = transactionManager;
|
this.transactionManager = transactionManager;
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
|
@ -158,7 +158,7 @@ export class ImportWorkflowsCommand extends Command {
|
||||||
|
|
||||||
totalImported = workflows.length;
|
totalImported = workflows.length;
|
||||||
|
|
||||||
await getConnection().transaction(async (transactionManager) => {
|
await Db.getConnection().transaction(async (transactionManager) => {
|
||||||
this.transactionManager = transactionManager;
|
this.transactionManager = transactionManager;
|
||||||
|
|
||||||
for (const workflow of workflows) {
|
for (const workflow of workflows) {
|
||||||
|
@ -229,7 +229,9 @@ export class ImportWorkflowsCommand extends Command {
|
||||||
where: { name: 'owner', scope: 'global' },
|
where: { name: 'owner', scope: 'global' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const owner = await Db.collections.User.findOne({ globalRole: ownerGlobalRole });
|
const owner =
|
||||||
|
ownerGlobalRole &&
|
||||||
|
(await Db.collections.User.findOneBy({ globalRoleId: ownerGlobalRole?.id }));
|
||||||
|
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
throw new Error(`Failed to find owner. ${FIX_INSTRUCTION}`);
|
throw new Error(`Failed to find owner. ${FIX_INSTRUCTION}`);
|
||||||
|
@ -239,7 +241,7 @@ export class ImportWorkflowsCommand extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAssignee(userId: string) {
|
private async getAssignee(userId: string) {
|
||||||
const user = await Db.collections.User.findOne(userId);
|
const user = await Db.collections.User.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}`);
|
||||||
|
|
|
@ -304,7 +304,7 @@ export class Start extends Command {
|
||||||
await UserSettings.getEncryptionKey();
|
await UserSettings.getEncryptionKey();
|
||||||
|
|
||||||
// Load settings from database and set them to config.
|
// Load settings from database and set them to config.
|
||||||
const databaseSettings = await Db.collections.Settings.find({ loadOnStartup: true });
|
const databaseSettings = await Db.collections.Settings.findBy({ loadOnStartup: true });
|
||||||
databaseSettings.forEach((setting) => {
|
databaseSettings.forEach((setting) => {
|
||||||
config.set(setting.key, JSON.parse(setting.value));
|
config.set(setting.key, JSON.parse(setting.value));
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,23 +9,23 @@ export class Reset extends BaseCommand {
|
||||||
async run(): Promise<void> {
|
async run(): Promise<void> {
|
||||||
const owner = await this.getInstanceOwner();
|
const owner = await this.getInstanceOwner();
|
||||||
|
|
||||||
const ownerWorkflowRole = await Db.collections.Role.findOneOrFail({
|
const ownerWorkflowRole = await Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'workflow',
|
scope: 'workflow',
|
||||||
});
|
});
|
||||||
|
|
||||||
const ownerCredentialRole = await Db.collections.Role.findOneOrFail({
|
const ownerCredentialRole = await Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'credential',
|
scope: 'credential',
|
||||||
});
|
});
|
||||||
|
|
||||||
await Db.collections.SharedWorkflow.update(
|
await Db.collections.SharedWorkflow.update(
|
||||||
{ user: { id: Not(owner.id) }, role: ownerWorkflowRole },
|
{ userId: Not(owner.id), roleId: ownerWorkflowRole.id },
|
||||||
{ user: owner },
|
{ user: owner },
|
||||||
);
|
);
|
||||||
|
|
||||||
await Db.collections.SharedCredentials.update(
|
await Db.collections.SharedCredentials.update(
|
||||||
{ user: { id: Not(owner.id) }, role: ownerCredentialRole },
|
{ userId: Not(owner.id), roleId: ownerCredentialRole.id },
|
||||||
{ user: owner },
|
{ user: owner },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,6 @@ import {
|
||||||
sleep,
|
sleep,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import { FindOneOptions, getConnectionManager } from 'typeorm';
|
|
||||||
|
|
||||||
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
|
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
|
||||||
import { CredentialTypes } from '@/CredentialTypes';
|
import { CredentialTypes } from '@/CredentialTypes';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
|
@ -125,7 +123,7 @@ export class Worker extends Command {
|
||||||
|
|
||||||
async runJob(job: Queue.Job, nodeTypes: INodeTypes): Promise<Queue.JobResponse> {
|
async runJob(job: Queue.Job, nodeTypes: INodeTypes): Promise<Queue.JobResponse> {
|
||||||
const { executionId, loadStaticData } = job.data;
|
const { executionId, loadStaticData } = job.data;
|
||||||
const executionDb = await Db.collections.Execution.findOne(executionId);
|
const executionDb = await Db.collections.Execution.findOneBy({ id: executionId });
|
||||||
|
|
||||||
if (!executionDb) {
|
if (!executionDb) {
|
||||||
LoggerProxy.error(
|
LoggerProxy.error(
|
||||||
|
@ -145,14 +143,13 @@ export class Worker extends Command {
|
||||||
|
|
||||||
let { staticData } = currentExecutionDb.workflowData;
|
let { staticData } = currentExecutionDb.workflowData;
|
||||||
if (loadStaticData) {
|
if (loadStaticData) {
|
||||||
const findOptions = {
|
const workflowData = await Db.collections.Workflow.findOne({
|
||||||
select: ['id', 'staticData'],
|
select: ['id', 'staticData'],
|
||||||
} as FindOneOptions;
|
where: {
|
||||||
const workflowData = await Db.collections.Workflow.findOne(
|
id: currentExecutionDb.workflowData.id,
|
||||||
currentExecutionDb.workflowData.id,
|
},
|
||||||
findOptions,
|
});
|
||||||
);
|
if (workflowData === null) {
|
||||||
if (workflowData === undefined) {
|
|
||||||
LoggerProxy.error(
|
LoggerProxy.error(
|
||||||
'Worker execution failed because workflow could not be found in database.',
|
'Worker execution failed because workflow could not be found in database.',
|
||||||
{
|
{
|
||||||
|
@ -384,10 +381,10 @@ export class Worker extends Command {
|
||||||
async (req: express.Request, res: express.Response) => {
|
async (req: express.Request, res: express.Response) => {
|
||||||
LoggerProxy.debug('Health check started!');
|
LoggerProxy.debug('Health check started!');
|
||||||
|
|
||||||
const connection = getConnectionManager().get();
|
const connection = Db.getConnection();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!connection.isConnected) {
|
if (!connection.isInitialized) {
|
||||||
// Connection is not active
|
// Connection is not active
|
||||||
throw new Error('No active database connection!');
|
throw new Error('No active database connection!');
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,7 @@ credentialsController.patch(
|
||||||
|
|
||||||
const responseData = await CredentialsService.update(credentialId, newCredentialData);
|
const responseData = await CredentialsService.update(credentialId, newCredentialData);
|
||||||
|
|
||||||
if (responseData === undefined) {
|
if (responseData === null) {
|
||||||
throw new ResponseHelper.NotFoundError(
|
throw new ResponseHelper.NotFoundError(
|
||||||
`Credential ID "${credentialId}" could not be found to be updated.`,
|
`Credential ID "${credentialId}" could not be found to be updated.`,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import { DeleteResult, EntityManager, FindConditions, In, Not } from 'typeorm';
|
import { DeleteResult, EntityManager, FindOptionsWhere, In, Not } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import { RoleService } from '@/role/role.service';
|
import { RoleService } from '@/role/role.service';
|
||||||
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
|
@ -33,14 +33,14 @@ export class EECredentialsService extends CredentialsService {
|
||||||
credentialId: string,
|
credentialId: string,
|
||||||
relations: string[] = ['credentials'],
|
relations: string[] = ['credentials'],
|
||||||
{ allowGlobalOwner } = { allowGlobalOwner: true },
|
{ allowGlobalOwner } = { allowGlobalOwner: true },
|
||||||
): Promise<SharedCredentials | undefined> {
|
): Promise<SharedCredentials | null> {
|
||||||
const where: FindConditions<SharedCredentials> = { credentialsId: credentialId };
|
const where: FindOptionsWhere<SharedCredentials> = { credentialsId: credentialId };
|
||||||
|
|
||||||
// Omit user from where if the requesting user is the global
|
// Omit user from where if the requesting user is the global
|
||||||
// owner. This allows the global owner to view and delete
|
// owner. This allows the global owner to view and delete
|
||||||
// credentials they don't own.
|
// credentials they don't own.
|
||||||
if (!allowGlobalOwner || user.globalRole.name !== 'owner') {
|
if (!allowGlobalOwner || user.globalRole.name !== 'owner') {
|
||||||
where.user = { id: user.id };
|
where.userId = user.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Db.collections.SharedCredentials.findOne({
|
return Db.collections.SharedCredentials.findOne({
|
||||||
|
@ -65,7 +65,7 @@ export class EECredentialsService extends CredentialsService {
|
||||||
credentialId: string,
|
credentialId: string,
|
||||||
userIds: string[],
|
userIds: string[],
|
||||||
): Promise<DeleteResult> {
|
): Promise<DeleteResult> {
|
||||||
const conditions: FindConditions<SharedCredentials> = {
|
const conditions: FindOptionsWhere<SharedCredentials> = {
|
||||||
credentialsId: credentialId,
|
credentialsId: credentialId,
|
||||||
userId: Not(In(userIds)),
|
userId: Not(In(userIds)),
|
||||||
};
|
};
|
||||||
|
@ -86,9 +86,9 @@ export class EECredentialsService extends CredentialsService {
|
||||||
.filter((user) => !user.isPending)
|
.filter((user) => !user.isPending)
|
||||||
.map((user) =>
|
.map((user) =>
|
||||||
Db.collections.SharedCredentials.create({
|
Db.collections.SharedCredentials.create({
|
||||||
credentials: credential,
|
credentialsId: credential.id,
|
||||||
user,
|
userId: user.id,
|
||||||
role,
|
roleId: role?.id,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
LoggerProxy,
|
LoggerProxy,
|
||||||
NodeHelpers,
|
NodeHelpers,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { FindConditions, FindManyOptions, In } from 'typeorm';
|
import { FindManyOptions, FindOptionsWhere, In } from 'typeorm';
|
||||||
|
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import * as ResponseHelper from '@/ResponseHelper';
|
import * as ResponseHelper from '@/ResponseHelper';
|
||||||
|
@ -28,11 +28,12 @@ import { CredentialTypes } from '@/CredentialTypes';
|
||||||
|
|
||||||
export class CredentialsService {
|
export class CredentialsService {
|
||||||
static async get(
|
static async get(
|
||||||
credential: Partial<ICredentialsDb>,
|
where: FindOptionsWhere<ICredentialsDb>,
|
||||||
options?: { relations: string[] },
|
options?: { relations: string[] },
|
||||||
): Promise<ICredentialsDb | undefined> {
|
): Promise<ICredentialsDb | null> {
|
||||||
return Db.collections.Credentials.findOne(credential, {
|
return Db.collections.Credentials.findOne({
|
||||||
relations: options?.relations,
|
relations: options?.relations,
|
||||||
|
where,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,8 +89,8 @@ export class CredentialsService {
|
||||||
credentialId: string,
|
credentialId: string,
|
||||||
relations: string[] = ['credentials'],
|
relations: string[] = ['credentials'],
|
||||||
{ allowGlobalOwner } = { allowGlobalOwner: true },
|
{ allowGlobalOwner } = { allowGlobalOwner: true },
|
||||||
): Promise<SharedCredentials | undefined> {
|
): Promise<SharedCredentials | null> {
|
||||||
const where: FindConditions<SharedCredentials> = { credentialsId: credentialId };
|
const where: FindOptionsWhere<SharedCredentials> = { credentialsId: credentialId };
|
||||||
|
|
||||||
// Omit user from where if the requesting user is the global
|
// Omit user from where if the requesting user is the global
|
||||||
// owner. This allows the global owner to view and delete
|
// owner. This allows the global owner to view and delete
|
||||||
|
@ -204,7 +205,7 @@ export class CredentialsService {
|
||||||
static async update(
|
static async update(
|
||||||
credentialId: string,
|
credentialId: string,
|
||||||
newCredentialData: ICredentialsDb,
|
newCredentialData: ICredentialsDb,
|
||||||
): Promise<ICredentialsDb | undefined> {
|
): Promise<ICredentialsDb | null> {
|
||||||
await ExternalHooks().run('credentials.update', [newCredentialData]);
|
await ExternalHooks().run('credentials.update', [newCredentialData]);
|
||||||
|
|
||||||
// Update the credentials in DB
|
// Update the credentials in DB
|
||||||
|
@ -212,7 +213,7 @@ export class CredentialsService {
|
||||||
|
|
||||||
// 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.findOne(credentialId);
|
return Db.collections.Credentials.findOneBy({ id: credentialId });
|
||||||
}
|
}
|
||||||
|
|
||||||
static async save(
|
static async save(
|
||||||
|
@ -226,7 +227,7 @@ export class CredentialsService {
|
||||||
|
|
||||||
await ExternalHooks().run('credentials.create', [encryptedData]);
|
await ExternalHooks().run('credentials.create', [encryptedData]);
|
||||||
|
|
||||||
const role = await Db.collections.Role.findOneOrFail({
|
const role = await Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'credential',
|
scope: 'credential',
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { Column, Entity, OneToMany, PrimaryGeneratedColumn, Unique } from 'typeorm';
|
import { Column, Entity, OneToMany, PrimaryColumn, Unique } from 'typeorm';
|
||||||
import { IsString, Length } from 'class-validator';
|
import { IsString, Length } from 'class-validator';
|
||||||
|
|
||||||
import type { User } from './User';
|
import type { User } from './User';
|
||||||
import type { SharedWorkflow } from './SharedWorkflow';
|
import type { SharedWorkflow } from './SharedWorkflow';
|
||||||
import type { SharedCredentials } from './SharedCredentials';
|
import type { SharedCredentials } from './SharedCredentials';
|
||||||
import { AbstractEntity } from './AbstractEntity';
|
import { AbstractEntity } from './AbstractEntity';
|
||||||
|
import { idStringifier } from '../utils/transformers';
|
||||||
|
|
||||||
export type RoleNames = 'owner' | 'member' | 'user' | 'editor';
|
export type RoleNames = 'owner' | 'member' | 'user' | 'editor';
|
||||||
export type RoleScopes = 'global' | 'workflow' | 'credential';
|
export type RoleScopes = 'global' | 'workflow' | 'credential';
|
||||||
|
@ -12,8 +13,8 @@ export type RoleScopes = 'global' | 'workflow' | 'credential';
|
||||||
@Entity()
|
@Entity()
|
||||||
@Unique(['scope', 'name'])
|
@Unique(['scope', 'name'])
|
||||||
export class Role extends AbstractEntity {
|
export class Role extends AbstractEntity {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryColumn({ transformer: idStringifier })
|
||||||
id: number;
|
id: string;
|
||||||
|
|
||||||
@Column({ length: 32 })
|
@Column({ length: 32 })
|
||||||
@IsString({ message: 'Role name must be of type string.' })
|
@IsString({ message: 'Role name must be of type string.' })
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Entity, ManyToOne, PrimaryColumn, RelationId } from 'typeorm';
|
import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';
|
||||||
import type { CredentialsEntity } from './CredentialsEntity';
|
import type { CredentialsEntity } from './CredentialsEntity';
|
||||||
import type { User } from './User';
|
import type { User } from './User';
|
||||||
import type { Role } from './Role';
|
import type { Role } from './Role';
|
||||||
|
@ -10,20 +10,18 @@ export class SharedCredentials extends AbstractEntity {
|
||||||
@ManyToOne('Role', 'sharedCredentials', { nullable: false })
|
@ManyToOne('Role', 'sharedCredentials', { nullable: false })
|
||||||
role: Role;
|
role: Role;
|
||||||
|
|
||||||
@ManyToOne('User', 'sharedCredentials', { primary: true })
|
@Column()
|
||||||
|
roleId: string;
|
||||||
|
|
||||||
|
@ManyToOne('User', 'sharedCredentials')
|
||||||
user: User;
|
user: User;
|
||||||
|
|
||||||
@PrimaryColumn()
|
@PrimaryColumn()
|
||||||
@RelationId((sharedCredential: SharedCredentials) => sharedCredential.user)
|
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
||||||
@ManyToOne('CredentialsEntity', 'shared', {
|
@ManyToOne('CredentialsEntity', 'shared')
|
||||||
primary: true,
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
credentials: CredentialsEntity;
|
credentials: CredentialsEntity;
|
||||||
|
|
||||||
@PrimaryColumn({ transformer: idStringifier })
|
@PrimaryColumn({ transformer: idStringifier })
|
||||||
@RelationId((sharedCredential: SharedCredentials) => sharedCredential.credentials)
|
|
||||||
credentialsId: string;
|
credentialsId: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Entity, ManyToOne, PrimaryColumn, RelationId } from 'typeorm';
|
import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';
|
||||||
import type { WorkflowEntity } from './WorkflowEntity';
|
import type { WorkflowEntity } from './WorkflowEntity';
|
||||||
import type { User } from './User';
|
import type { User } from './User';
|
||||||
import type { Role } from './Role';
|
import type { Role } from './Role';
|
||||||
|
@ -10,20 +10,18 @@ export class SharedWorkflow extends AbstractEntity {
|
||||||
@ManyToOne('Role', 'sharedWorkflows', { nullable: false })
|
@ManyToOne('Role', 'sharedWorkflows', { nullable: false })
|
||||||
role: Role;
|
role: Role;
|
||||||
|
|
||||||
@ManyToOne('User', 'sharedWorkflows', { primary: true })
|
@Column()
|
||||||
|
roleId: string;
|
||||||
|
|
||||||
|
@ManyToOne('User', 'sharedWorkflows')
|
||||||
user: User;
|
user: User;
|
||||||
|
|
||||||
@PrimaryColumn()
|
@PrimaryColumn()
|
||||||
@RelationId((sharedWorkflow: SharedWorkflow) => sharedWorkflow.user)
|
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
||||||
@ManyToOne('WorkflowEntity', 'shared', {
|
@ManyToOne('WorkflowEntity', 'shared')
|
||||||
primary: true,
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
workflow: WorkflowEntity;
|
workflow: WorkflowEntity;
|
||||||
|
|
||||||
@PrimaryColumn({ transformer: idStringifier })
|
@PrimaryColumn({ transformer: idStringifier })
|
||||||
@RelationId((sharedWorkflow: SharedWorkflow) => sharedWorkflow.workflow)
|
|
||||||
workflowId: string;
|
workflowId: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,12 +74,12 @@ export class User extends AbstractEntity implements IUser {
|
||||||
})
|
})
|
||||||
settings: IUserSettings | null;
|
settings: IUserSettings | null;
|
||||||
|
|
||||||
@ManyToOne('Role', 'globalForUsers', {
|
@ManyToOne('Role', 'globalForUsers', { nullable: false })
|
||||||
cascade: true,
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
globalRole: Role;
|
globalRole: Role;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
globalRoleId: string;
|
||||||
|
|
||||||
@OneToMany('SharedWorkflow', 'user')
|
@OneToMany('SharedWorkflow', 'user')
|
||||||
sharedWorkflows: SharedWorkflow[];
|
sharedWorkflows: SharedWorkflow[];
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Column, Entity, RelationId, ManyToOne, PrimaryColumn } from 'typeorm';
|
import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';
|
||||||
import { idStringifier } from '../utils/transformers';
|
import { idStringifier } from '../utils/transformers';
|
||||||
import { datetimeColumnType } from './AbstractEntity';
|
import { datetimeColumnType } from './AbstractEntity';
|
||||||
import type { WorkflowEntity } from './WorkflowEntity';
|
import type { WorkflowEntity } from './WorkflowEntity';
|
||||||
|
@ -22,13 +22,9 @@ export class WorkflowStatistics {
|
||||||
@PrimaryColumn({ length: 128 })
|
@PrimaryColumn({ length: 128 })
|
||||||
name: StatisticsNames;
|
name: StatisticsNames;
|
||||||
|
|
||||||
@ManyToOne('WorkflowEntity', 'shared', {
|
@ManyToOne('WorkflowEntity', 'shared')
|
||||||
primary: true,
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
workflow: WorkflowEntity;
|
workflow: WorkflowEntity;
|
||||||
|
|
||||||
@PrimaryColumn({ transformer: idStringifier })
|
@PrimaryColumn({ transformer: idStringifier })
|
||||||
@RelationId((workflowStatistics: WorkflowStatistics) => workflowStatistics.workflow)
|
|
||||||
workflowId: string;
|
workflowId: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { LoggerProxy, MessageEventBusDestinationOptions } from 'n8n-workflow';
|
import { LoggerProxy, MessageEventBusDestinationOptions } from 'n8n-workflow';
|
||||||
import { DeleteResult } from 'typeorm';
|
import type { DeleteResult } from 'typeorm';
|
||||||
import { EventMessageTypes } from '../EventMessageClasses/';
|
import { EventMessageTypes } from '../EventMessageClasses/';
|
||||||
import type { MessageEventBusDestination } from '../MessageEventBusDestination/MessageEventBusDestination.ee';
|
import type { MessageEventBusDestination } from '../MessageEventBusDestination/MessageEventBusDestination.ee';
|
||||||
import { MessageEventBusLogWriter } from '../MessageEventBusWriter/MessageEventBusLogWriter';
|
import { MessageEventBusLogWriter } from '../MessageEventBusWriter/MessageEventBusLogWriter';
|
||||||
|
|
|
@ -9,7 +9,7 @@ import * as Db from '@/Db';
|
||||||
import { AbstractEventMessage } from '../EventMessageClasses/AbstractEventMessage';
|
import { AbstractEventMessage } from '../EventMessageClasses/AbstractEventMessage';
|
||||||
import { EventMessageTypes } from '../EventMessageClasses';
|
import { EventMessageTypes } from '../EventMessageClasses';
|
||||||
import { eventBus } from '..';
|
import { eventBus } from '..';
|
||||||
import { DeleteResult, InsertResult } from 'typeorm';
|
import type { DeleteResult, InsertResult } from 'typeorm';
|
||||||
|
|
||||||
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.
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
jsonParse,
|
jsonParse,
|
||||||
Workflow,
|
Workflow,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { FindConditions, FindOperator, In, IsNull, LessThanOrEqual, Not, Raw } from 'typeorm';
|
import { FindOperator, FindOptionsWhere, In, IsNull, LessThanOrEqual, Not, Raw } from 'typeorm';
|
||||||
import * as ActiveExecutions from '@/ActiveExecutions';
|
import * as ActiveExecutions from '@/ActiveExecutions';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import type { User } from '@/databases/entities/User';
|
import type { User } from '@/databases/entities/User';
|
||||||
|
@ -200,7 +200,7 @@ export class ExecutionsService {
|
||||||
.map(({ id }) => id),
|
.map(({ id }) => id),
|
||||||
);
|
);
|
||||||
|
|
||||||
const findWhere: FindConditions<ExecutionEntity> = { workflowId: In(sharedWorkflowIds) };
|
const findWhere: FindOptionsWhere<ExecutionEntity> = { workflowId: In(sharedWorkflowIds) };
|
||||||
|
|
||||||
const rangeQuery: string[] = [];
|
const rangeQuery: string[] = [];
|
||||||
const rangeQueryParams: {
|
const rangeQueryParams: {
|
||||||
|
@ -370,7 +370,9 @@ 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 = fullExecutionData.workflowData.id as string;
|
const workflowId = fullExecutionData.workflowData.id as string;
|
||||||
const workflowData = (await Db.collections.Workflow.findOne(workflowId)) as IWorkflowBase;
|
const workflowData = (await Db.collections.Workflow.findOneBy({
|
||||||
|
id: workflowId,
|
||||||
|
})) as IWorkflowBase;
|
||||||
|
|
||||||
if (workflowData === undefined) {
|
if (workflowData === undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -453,7 +455,7 @@ export class ExecutionsService {
|
||||||
throw new Error('Either "deleteBefore" or "ids" must be present in the request body');
|
throw new Error('Either "deleteBefore" or "ids" must be present in the request body');
|
||||||
}
|
}
|
||||||
|
|
||||||
const where: FindConditions<ExecutionEntity> = { workflowId: In(sharedWorkflowIds) };
|
const where: FindOptionsWhere<ExecutionEntity> = { workflowId: In(sharedWorkflowIds) };
|
||||||
|
|
||||||
if (deleteBefore) {
|
if (deleteBefore) {
|
||||||
// delete executions by date, if user may access the underlying workflows
|
// delete executions by date, if user may access the underlying workflows
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { EntityManager } from 'typeorm';
|
import type { EntityManager, FindOptionsWhere } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import { Role } from '@db/entities/Role';
|
import { Role } from '@db/entities/Role';
|
||||||
|
|
||||||
export class RoleService {
|
export class RoleService {
|
||||||
static async get(role: Partial<Role>): Promise<Role | undefined> {
|
static async get(role: FindOptionsWhere<Role>): Promise<Role | null> {
|
||||||
return Db.collections.Role.findOne(role);
|
return Db.collections.Role.findOneBy(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async trxGet(transaction: EntityManager, role: Partial<Role>) {
|
static async trxGet(transaction: EntityManager, role: FindOptionsWhere<Role>) {
|
||||||
return transaction.findOne(Role, role);
|
return transaction.findOneBy(Role, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getUserRoleForWorkflow(userId: string, workflowId: string) {
|
static async getUserRoleForWorkflow(userId: string, workflowId: string) {
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { EntityManager, In } from 'typeorm';
|
import { EntityManager, FindOptionsWhere, In } from 'typeorm';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import { User } from '@db/entities/User';
|
import { User } from '@db/entities/User';
|
||||||
|
|
||||||
export class UserService {
|
export class UserService {
|
||||||
static async get(user: Partial<User>): Promise<User | undefined> {
|
static async get(where: FindOptionsWhere<User>): Promise<User | null> {
|
||||||
return Db.collections.User.findOne(user, {
|
return Db.collections.User.findOne({
|
||||||
relations: ['globalRole'],
|
relations: ['globalRole'],
|
||||||
|
where,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getByIds(transaction: EntityManager, ids: string[]) {
|
static async getByIds(transaction: EntityManager, ids: string[]) {
|
||||||
return transaction.find(User, { id: In(ids) });
|
return transaction.find(User, { where: { id: In(ids) } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import * as TagHelpers from '@/TagHelpers';
|
||||||
import { EECredentialsService as EECredentials } from '../credentials/credentials.service.ee';
|
import { EECredentialsService as EECredentials } from '../credentials/credentials.service.ee';
|
||||||
import { IExecutionPushResponse } from '@/Interfaces';
|
import { IExecutionPushResponse } from '@/Interfaces';
|
||||||
import * as GenericHelpers from '@/GenericHelpers';
|
import * as GenericHelpers from '@/GenericHelpers';
|
||||||
|
import { In } from 'typeorm';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
export const EEWorkflowController = express.Router();
|
export const EEWorkflowController = express.Router();
|
||||||
|
@ -130,8 +131,11 @@ EEWorkflowController.post(
|
||||||
const { tags: tagIds } = req.body;
|
const { tags: tagIds } = req.body;
|
||||||
|
|
||||||
if (tagIds?.length && !config.getEnv('workflowTagsDisabled')) {
|
if (tagIds?.length && !config.getEnv('workflowTagsDisabled')) {
|
||||||
newWorkflow.tags = await Db.collections.Tag.findByIds(tagIds, {
|
newWorkflow.tags = await Db.collections.Tag.find({
|
||||||
select: ['id', 'name'],
|
select: ['id', 'name'],
|
||||||
|
where: {
|
||||||
|
id: In(tagIds),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +161,7 @@ EEWorkflowController.post(
|
||||||
await Db.transaction(async (transactionManager) => {
|
await Db.transaction(async (transactionManager) => {
|
||||||
savedWorkflow = await transactionManager.save<WorkflowEntity>(newWorkflow);
|
savedWorkflow = await transactionManager.save<WorkflowEntity>(newWorkflow);
|
||||||
|
|
||||||
const role = await Db.collections.Role.findOneOrFail({
|
const role = await Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'workflow',
|
scope: 'workflow',
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { isBelowOnboardingThreshold } from '@/WorkflowHelpers';
|
||||||
import { EEWorkflowController } from './workflows.controller.ee';
|
import { EEWorkflowController } from './workflows.controller.ee';
|
||||||
import { WorkflowsService } from './workflows.services';
|
import { WorkflowsService } from './workflows.services';
|
||||||
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
import { whereClause } from '@/UserManagement/UserManagementHelper';
|
||||||
|
import { In } from 'typeorm';
|
||||||
|
|
||||||
export const workflowsController = express.Router();
|
export const workflowsController = express.Router();
|
||||||
|
|
||||||
|
@ -61,8 +62,11 @@ workflowsController.post(
|
||||||
const { tags: tagIds } = req.body;
|
const { tags: tagIds } = req.body;
|
||||||
|
|
||||||
if (tagIds?.length && !config.getEnv('workflowTagsDisabled')) {
|
if (tagIds?.length && !config.getEnv('workflowTagsDisabled')) {
|
||||||
newWorkflow.tags = await Db.collections.Tag.findByIds(tagIds, {
|
newWorkflow.tags = await Db.collections.Tag.find({
|
||||||
select: ['id', 'name'],
|
select: ['id', 'name'],
|
||||||
|
where: {
|
||||||
|
id: In(tagIds),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +79,7 @@ workflowsController.post(
|
||||||
await Db.transaction(async (transactionManager) => {
|
await Db.transaction(async (transactionManager) => {
|
||||||
savedWorkflow = await transactionManager.save<WorkflowEntity>(newWorkflow);
|
savedWorkflow = await transactionManager.save<WorkflowEntity>(newWorkflow);
|
||||||
|
|
||||||
const role = await Db.collections.Role.findOneOrFail({
|
const role = await Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'workflow',
|
scope: 'workflow',
|
||||||
});
|
});
|
||||||
|
|
|
@ -74,13 +74,12 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||||
if (user.isPending) {
|
if (user.isPending) {
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
acc.push(
|
const entity: Partial<SharedWorkflow> = {
|
||||||
Db.collections.SharedWorkflow.create({
|
workflowId: workflow.id,
|
||||||
workflow,
|
userId: user.id,
|
||||||
user,
|
roleId: role?.id,
|
||||||
role,
|
};
|
||||||
}),
|
acc.push(Db.collections.SharedWorkflow.create(entity));
|
||||||
);
|
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { validate as jsonSchemaValidate } from 'jsonschema';
|
import { validate as jsonSchemaValidate } from 'jsonschema';
|
||||||
import { INode, IPinData, JsonObject, jsonParse, LoggerProxy, Workflow } from 'n8n-workflow';
|
import { INode, IPinData, JsonObject, jsonParse, LoggerProxy, Workflow } from 'n8n-workflow';
|
||||||
import { FindConditions, In } from 'typeorm';
|
import { FindOptionsWhere, In } 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 * as ActiveWorkflowRunner from '@/ActiveWorkflowRunner';
|
import * as ActiveWorkflowRunner from '@/ActiveWorkflowRunner';
|
||||||
|
@ -48,8 +48,8 @@ export class WorkflowsService {
|
||||||
workflowId: string,
|
workflowId: string,
|
||||||
relations: string[] = ['workflow'],
|
relations: string[] = ['workflow'],
|
||||||
{ allowGlobalOwner } = { allowGlobalOwner: true },
|
{ allowGlobalOwner } = { allowGlobalOwner: true },
|
||||||
): Promise<SharedWorkflow | undefined> {
|
): Promise<SharedWorkflow | null> {
|
||||||
const where: FindConditions<SharedWorkflow> = { workflowId };
|
const where: FindOptionsWhere<SharedWorkflow> = { workflowId };
|
||||||
|
|
||||||
// Omit user from where if the requesting user is the global
|
// Omit user from where if the requesting user is the global
|
||||||
// owner. This allows the global owner to view and delete
|
// owner. This allows the global owner to view and delete
|
||||||
|
@ -103,8 +103,8 @@ export class WorkflowsService {
|
||||||
return pinnedTriggers.find((pt) => pt.name === checkNodeName) ?? null; // partial execution
|
return pinnedTriggers.find((pt) => pt.name === checkNodeName) ?? null; // partial execution
|
||||||
}
|
}
|
||||||
|
|
||||||
static async get(workflow: Partial<WorkflowEntity>, options?: { relations: string[] }) {
|
static async get(workflow: FindOptionsWhere<WorkflowEntity>, options?: { relations: string[] }) {
|
||||||
return Db.collections.Workflow.findOne(workflow, options);
|
return Db.collections.Workflow.findOne({ where: workflow, relations: options?.relations });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning: this function is overridden by EE to disregard role list.
|
// Warning: this function is overridden by EE to disregard role list.
|
||||||
|
@ -299,9 +299,12 @@ 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(workflowId, { relations });
|
const updatedWorkflow = await Db.collections.Workflow.findOne({
|
||||||
|
where: { id: workflowId },
|
||||||
|
relations,
|
||||||
|
});
|
||||||
|
|
||||||
if (updatedWorkflow === undefined) {
|
if (updatedWorkflow === null) {
|
||||||
throw new ResponseHelper.BadRequestError(
|
throw new ResponseHelper.BadRequestError(
|
||||||
`Workflow with ID "${workflowId}" could not be found to be updated.`,
|
`Workflow with ID "${workflowId}" could not be found to be updated.`,
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,19 +6,16 @@ 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';
|
||||||
|
|
||||||
let testDbName = '';
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['Workflow', 'Credentials', 'Execution'], testDbName);
|
await testDb.truncate(['Workflow', 'Credentials', 'Execution']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should report credentials not in any use', async () => {
|
test('should report credentials not in any use', async () => {
|
||||||
|
|
|
@ -9,19 +9,16 @@ import {
|
||||||
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
|
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
|
|
||||||
let testDbName = '';
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['Workflow'], testDbName);
|
await testDb.truncate(['Workflow']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should report expressions in queries', async () => {
|
test('should report expressions in queries', async () => {
|
||||||
|
|
|
@ -5,19 +5,16 @@ import { FILESYSTEM_INTERACTION_NODE_TYPES, FILESYSTEM_REPORT } from '@/audit/co
|
||||||
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
|
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
|
|
||||||
let testDbName = '';
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['Workflow'], testDbName);
|
await testDb.truncate(['Workflow']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should report filesystem interaction nodes', async () => {
|
test('should report filesystem interaction nodes', async () => {
|
||||||
|
|
|
@ -13,21 +13,18 @@ import * as testDb from '../shared/testDb';
|
||||||
import { toReportTitle } from '@/audit/utils';
|
import { toReportTitle } from '@/audit/utils';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
|
||||||
let testDbName = '';
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
simulateUpToDateInstance();
|
simulateUpToDateInstance();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['Workflow'], testDbName);
|
await testDb.truncate(['Workflow']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should report webhook lacking authentication', async () => {
|
test('should report webhook lacking authentication', async () => {
|
||||||
|
|
|
@ -7,19 +7,16 @@ import { getRiskSection, MOCK_PACKAGE, saveManualTriggerWorkflow } from './utils
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
import { toReportTitle } from '@/audit/utils';
|
import { toReportTitle } from '@/audit/utils';
|
||||||
|
|
||||||
let testDbName = '';
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['Workflow'], testDbName);
|
await testDb.truncate(['Workflow']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should report risky official nodes', async () => {
|
test('should report risky official nodes', async () => {
|
||||||
|
|
|
@ -11,15 +11,13 @@ import type { AuthAgent } from './shared/types';
|
||||||
import * as utils from './shared/utils';
|
import * as utils from './shared/utils';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let authAgent: AuthAgent;
|
let authAgent: AuthAgent;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['auth'], applyAuth: true });
|
app = await utils.initTestServer({ endpointGroups: ['auth'], applyAuth: true });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||||
|
@ -31,7 +29,7 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User'], testDbName);
|
await testDb.truncate(['User']);
|
||||||
|
|
||||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||||
|
|
||||||
|
@ -42,7 +40,7 @@ beforeEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /login should log user in', async () => {
|
test('POST /login should log user in', async () => {
|
||||||
|
|
|
@ -12,7 +12,6 @@ import type { AuthAgent } from './shared/types';
|
||||||
import * as utils from './shared/utils';
|
import * as utils from './shared/utils';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let authAgent: AuthAgent;
|
let authAgent: AuthAgent;
|
||||||
|
|
||||||
|
@ -21,8 +20,7 @@ beforeAll(async () => {
|
||||||
applyAuth: true,
|
applyAuth: true,
|
||||||
endpointGroups: ['me', 'auth', 'owner', 'users'],
|
endpointGroups: ['me', 'auth', 'owner', 'users'],
|
||||||
});
|
});
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||||
|
|
||||||
|
@ -33,7 +31,7 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
ROUTES_REQUIRING_AUTHENTICATION.concat(ROUTES_REQUIRING_AUTHORIZATION).forEach((route) => {
|
ROUTES_REQUIRING_AUTHENTICATION.concat(ROUTES_REQUIRING_AUTHORIZATION).forEach((route) => {
|
||||||
|
|
|
@ -7,23 +7,21 @@ import * as utils from '../shared/utils';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['owner'], applyAuth: true });
|
app = await utils.initTestServer({ endpointGroups: ['owner'], applyAuth: true });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User'], testDbName);
|
await testDb.truncate(['User']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('user-management:reset should reset DB to default user state', async () => {
|
test('user-management:reset should reset DB to default user state', async () => {
|
||||||
|
@ -31,7 +29,7 @@ test('user-management:reset should reset DB to default user state', async () =>
|
||||||
|
|
||||||
await Reset.run();
|
await Reset.run();
|
||||||
|
|
||||||
const user = await Db.collections.User.findOne({ globalRole: globalOwnerRole });
|
const user = await Db.collections.User.findOneBy({ globalRoleId: globalOwnerRole.id });
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
fail('No owner found after DB reset to default user state');
|
fail('No owner found after DB reset to default user state');
|
||||||
|
|
|
@ -14,7 +14,6 @@ import * as utils from './shared/utils';
|
||||||
import type { IUser } from 'n8n-workflow';
|
import type { IUser } from 'n8n-workflow';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let credentialOwnerRole: Role;
|
let credentialOwnerRole: Role;
|
||||||
|
@ -27,8 +26,7 @@ beforeAll(async () => {
|
||||||
endpointGroups: ['credentials'],
|
endpointGroups: ['credentials'],
|
||||||
applyAuth: true,
|
applyAuth: true,
|
||||||
});
|
});
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
utils.initConfigFile();
|
utils.initConfigFile();
|
||||||
|
|
||||||
|
@ -46,11 +44,11 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User', 'SharedCredentials', 'Credentials'], testDbName);
|
await testDb.truncate(['User', 'SharedCredentials', 'Credentials']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
@ -380,7 +378,7 @@ test('PUT /credentials/:id/share should share the credential with the provided u
|
||||||
|
|
||||||
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
||||||
relations: ['role'],
|
relations: ['role'],
|
||||||
where: { credentials: savedCredential },
|
where: { credentialsId: savedCredential.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
// check that sharings have been removed/added correctly
|
// check that sharings have been removed/added correctly
|
||||||
|
@ -420,7 +418,7 @@ test('PUT /credentials/:id/share should share the credential with the provided u
|
||||||
// check that sharings got correctly set in DB
|
// check that sharings got correctly set in DB
|
||||||
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
||||||
relations: ['role'],
|
relations: ['role'],
|
||||||
where: { credentials: savedCredential, user: { id: In([...memberIds]) } },
|
where: { credentialsId: savedCredential.id, userId: In([...memberIds]) },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredentials.length).toBe(memberIds.length);
|
expect(sharedCredentials.length).toBe(memberIds.length);
|
||||||
|
@ -433,7 +431,7 @@ test('PUT /credentials/:id/share should share the credential with the provided u
|
||||||
// check that owner still exists
|
// check that owner still exists
|
||||||
const ownerSharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
const ownerSharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
||||||
relations: ['role'],
|
relations: ['role'],
|
||||||
where: { credentials: savedCredential, user: owner },
|
where: { credentialsId: savedCredential.id, userId: owner.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(ownerSharedCredential.role.name).toBe('owner');
|
expect(ownerSharedCredential.role.name).toBe('owner');
|
||||||
|
@ -475,7 +473,7 @@ test('PUT /credentials/:id/share should ignore pending sharee', async () => {
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
||||||
where: { credentials: savedCredential },
|
where: { credentialsId: savedCredential.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredentials).toHaveLength(1);
|
expect(sharedCredentials).toHaveLength(1);
|
||||||
|
@ -493,7 +491,7 @@ test('PUT /credentials/:id/share should ignore non-existing sharee', async () =>
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
||||||
where: { credentials: savedCredential },
|
where: { credentialsId: savedCredential.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredentials).toHaveLength(1);
|
expect(sharedCredentials).toHaveLength(1);
|
||||||
|
@ -535,7 +533,7 @@ test('PUT /credentials/:id/share should unshare the credential', async () => {
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
const sharedCredentials = await Db.collections.SharedCredentials.find({
|
||||||
where: { credentials: savedCredential },
|
where: { credentialsId: savedCredential.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredentials).toHaveLength(1);
|
expect(sharedCredentials).toHaveLength(1);
|
||||||
|
|
|
@ -19,7 +19,6 @@ const mockIsCredentialsSharingEnabled = jest.spyOn(UserManagementHelpers, 'isSha
|
||||||
mockIsCredentialsSharingEnabled.mockReturnValue(false);
|
mockIsCredentialsSharingEnabled.mockReturnValue(false);
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let saveCredential: SaveCredentialFunction;
|
let saveCredential: SaveCredentialFunction;
|
||||||
|
@ -30,8 +29,7 @@ beforeAll(async () => {
|
||||||
endpointGroups: ['credentials'],
|
endpointGroups: ['credentials'],
|
||||||
applyAuth: true,
|
applyAuth: true,
|
||||||
});
|
});
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
utils.initConfigFile();
|
utils.initConfigFile();
|
||||||
|
|
||||||
|
@ -48,11 +46,11 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User', 'SharedCredentials', 'Credentials'], testDbName);
|
await testDb.truncate(['User', 'SharedCredentials', 'Credentials']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
@ -124,7 +122,7 @@ test('POST /credentials should create cred', async () => {
|
||||||
expect(nodesAccess[0].nodeType).toBe(payload.nodesAccess[0].nodeType);
|
expect(nodesAccess[0].nodeType).toBe(payload.nodesAccess[0].nodeType);
|
||||||
expect(encryptedData).not.toBe(payload.data);
|
expect(encryptedData).not.toBe(payload.data);
|
||||||
|
|
||||||
const credential = await Db.collections.Credentials.findOneOrFail(id);
|
const credential = await Db.collections.Credentials.findOneByOrFail({ id });
|
||||||
|
|
||||||
expect(credential.name).toBe(payload.name);
|
expect(credential.name).toBe(payload.name);
|
||||||
expect(credential.type).toBe(payload.type);
|
expect(credential.type).toBe(payload.type);
|
||||||
|
@ -133,7 +131,7 @@ test('POST /credentials should create cred', async () => {
|
||||||
|
|
||||||
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
||||||
relations: ['user', 'credentials'],
|
relations: ['user', 'credentials'],
|
||||||
where: { credentials: credential },
|
where: { credentialsId: credential.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredential.user.id).toBe(ownerShell.id);
|
expect(sharedCredential.user.id).toBe(ownerShell.id);
|
||||||
|
@ -191,13 +189,13 @@ test('DELETE /credentials/:id should delete owned cred for owner', async () => {
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
expect(response.body).toEqual({ data: true });
|
expect(response.body).toEqual({ data: true });
|
||||||
|
|
||||||
const deletedCredential = await Db.collections.Credentials.findOne(savedCredential.id);
|
const deletedCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(deletedCredential).toBeUndefined(); // deleted
|
expect(deletedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials.findOne();
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOneBy({});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeUndefined(); // deleted
|
expect(deletedSharedCredential).toBeNull(); // deleted
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /credentials/:id should delete non-owned cred for owner', async () => {
|
test('DELETE /credentials/:id should delete non-owned cred for owner', async () => {
|
||||||
|
@ -210,13 +208,13 @@ test('DELETE /credentials/:id should delete non-owned cred for owner', async ()
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
expect(response.body).toEqual({ data: true });
|
expect(response.body).toEqual({ data: true });
|
||||||
|
|
||||||
const deletedCredential = await Db.collections.Credentials.findOne(savedCredential.id);
|
const deletedCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(deletedCredential).toBeUndefined(); // deleted
|
expect(deletedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials.findOne();
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOneBy({});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeUndefined(); // deleted
|
expect(deletedSharedCredential).toBeNull(); // deleted
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /credentials/:id should delete owned cred for member', async () => {
|
test('DELETE /credentials/:id should delete owned cred for member', async () => {
|
||||||
|
@ -228,13 +226,13 @@ test('DELETE /credentials/:id should delete owned cred for member', async () =>
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
expect(response.body).toEqual({ data: true });
|
expect(response.body).toEqual({ data: true });
|
||||||
|
|
||||||
const deletedCredential = await Db.collections.Credentials.findOne(savedCredential.id);
|
const deletedCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(deletedCredential).toBeUndefined(); // deleted
|
expect(deletedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials.findOne();
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOneBy({});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeUndefined(); // deleted
|
expect(deletedSharedCredential).toBeNull(); // deleted
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /credentials/:id should not delete non-owned cred for member', async () => {
|
test('DELETE /credentials/:id should not delete non-owned cred for member', async () => {
|
||||||
|
@ -246,11 +244,11 @@ test('DELETE /credentials/:id should not delete non-owned cred for member', asyn
|
||||||
|
|
||||||
expect(response.statusCode).toBe(404);
|
expect(response.statusCode).toBe(404);
|
||||||
|
|
||||||
const shellCredential = await Db.collections.Credentials.findOne(savedCredential.id);
|
const shellCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(shellCredential).toBeDefined(); // not deleted
|
expect(shellCredential).toBeDefined(); // not deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials.findOne();
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOneBy({});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeDefined(); // not deleted
|
expect(deletedSharedCredential).toBeDefined(); // not deleted
|
||||||
});
|
});
|
||||||
|
@ -285,7 +283,7 @@ test('PATCH /credentials/:id should update owned cred for owner', async () => {
|
||||||
|
|
||||||
expect(encryptedData).not.toBe(patchPayload.data);
|
expect(encryptedData).not.toBe(patchPayload.data);
|
||||||
|
|
||||||
const credential = await Db.collections.Credentials.findOneOrFail(id);
|
const credential = await Db.collections.Credentials.findOneByOrFail({ id });
|
||||||
|
|
||||||
expect(credential.name).toBe(patchPayload.name);
|
expect(credential.name).toBe(patchPayload.name);
|
||||||
expect(credential.type).toBe(patchPayload.type);
|
expect(credential.type).toBe(patchPayload.type);
|
||||||
|
@ -294,7 +292,7 @@ test('PATCH /credentials/:id should update owned cred for owner', async () => {
|
||||||
|
|
||||||
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
||||||
relations: ['credentials'],
|
relations: ['credentials'],
|
||||||
where: { credentials: credential },
|
where: { credentialsId: credential.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredential.credentials.name).toBe(patchPayload.name); // updated
|
expect(sharedCredential.credentials.name).toBe(patchPayload.name); // updated
|
||||||
|
@ -324,7 +322,7 @@ test('PATCH /credentials/:id should update non-owned cred for owner', async () =
|
||||||
|
|
||||||
expect(encryptedData).not.toBe(patchPayload.data);
|
expect(encryptedData).not.toBe(patchPayload.data);
|
||||||
|
|
||||||
const credential = await Db.collections.Credentials.findOneOrFail(id);
|
const credential = await Db.collections.Credentials.findOneByOrFail({ id });
|
||||||
|
|
||||||
expect(credential.name).toBe(patchPayload.name);
|
expect(credential.name).toBe(patchPayload.name);
|
||||||
expect(credential.type).toBe(patchPayload.type);
|
expect(credential.type).toBe(patchPayload.type);
|
||||||
|
@ -333,7 +331,7 @@ test('PATCH /credentials/:id should update non-owned cred for owner', async () =
|
||||||
|
|
||||||
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
||||||
relations: ['credentials'],
|
relations: ['credentials'],
|
||||||
where: { credentials: credential },
|
where: { credentialsId: credential.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredential.credentials.name).toBe(patchPayload.name); // updated
|
expect(sharedCredential.credentials.name).toBe(patchPayload.name); // updated
|
||||||
|
@ -362,7 +360,7 @@ test('PATCH /credentials/:id should update owned cred for member', async () => {
|
||||||
|
|
||||||
expect(encryptedData).not.toBe(patchPayload.data);
|
expect(encryptedData).not.toBe(patchPayload.data);
|
||||||
|
|
||||||
const credential = await Db.collections.Credentials.findOneOrFail(id);
|
const credential = await Db.collections.Credentials.findOneByOrFail({ id });
|
||||||
|
|
||||||
expect(credential.name).toBe(patchPayload.name);
|
expect(credential.name).toBe(patchPayload.name);
|
||||||
expect(credential.type).toBe(patchPayload.type);
|
expect(credential.type).toBe(patchPayload.type);
|
||||||
|
@ -371,7 +369,7 @@ test('PATCH /credentials/:id should update owned cred for member', async () => {
|
||||||
|
|
||||||
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
||||||
relations: ['credentials'],
|
relations: ['credentials'],
|
||||||
where: { credentials: credential },
|
where: { credentialsId: credential.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredential.credentials.name).toBe(patchPayload.name); // updated
|
expect(sharedCredential.credentials.name).toBe(patchPayload.name); // updated
|
||||||
|
@ -389,7 +387,9 @@ test('PATCH /credentials/:id should not update non-owned cred for member', async
|
||||||
|
|
||||||
expect(response.statusCode).toBe(404);
|
expect(response.statusCode).toBe(404);
|
||||||
|
|
||||||
const shellCredential = await Db.collections.Credentials.findOneOrFail(savedCredential.id);
|
const shellCredential = await Db.collections.Credentials.findOneByOrFail({
|
||||||
|
id: savedCredential.id,
|
||||||
|
});
|
||||||
|
|
||||||
expect(shellCredential.name).not.toBe(patchPayload.name); // not updated
|
expect(shellCredential.name).not.toBe(patchPayload.name); // not updated
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,11 +16,11 @@ import {
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { eventBus } from '@/eventbus';
|
import { eventBus } from '@/eventbus';
|
||||||
import { SuperAgentTest } from 'supertest';
|
import { SuperAgentTest } from 'supertest';
|
||||||
import { EventMessageGeneric } from '../../src/eventbus/EventMessageClasses/EventMessageGeneric';
|
import { EventMessageGeneric } from '@/eventbus/EventMessageClasses/EventMessageGeneric';
|
||||||
import { MessageEventBusDestinationSyslog } from '../../src/eventbus/MessageEventBusDestination/MessageEventBusDestinationSyslog.ee';
|
import { MessageEventBusDestinationSyslog } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationSyslog.ee';
|
||||||
import { MessageEventBusDestinationWebhook } from '../../src/eventbus/MessageEventBusDestination/MessageEventBusDestinationWebhook.ee';
|
import { MessageEventBusDestinationWebhook } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationWebhook.ee';
|
||||||
import { MessageEventBusDestinationSentry } from '../../src/eventbus/MessageEventBusDestination/MessageEventBusDestinationSentry.ee';
|
import { MessageEventBusDestinationSentry } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationSentry.ee';
|
||||||
import { EventMessageAudit } from '../../src/eventbus/EventMessageClasses/EventMessageAudit';
|
import { EventMessageAudit } from '@/eventbus/EventMessageClasses/EventMessageAudit';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
jest.unmock('@/eventbus/MessageEventBus/MessageEventBus');
|
jest.unmock('@/eventbus/MessageEventBus/MessageEventBus');
|
||||||
|
@ -30,7 +30,6 @@ jest.mock('syslog-client');
|
||||||
const mockedSyslog = syslog as jest.Mocked<typeof syslog>;
|
const mockedSyslog = syslog as jest.Mocked<typeof syslog>;
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let owner: User;
|
let owner: User;
|
||||||
let unAuthOwnerAgent: SuperAgentTest;
|
let unAuthOwnerAgent: SuperAgentTest;
|
||||||
|
@ -82,8 +81,7 @@ async function confirmIdSent(id: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||||
|
|
||||||
|
@ -121,7 +119,7 @@ beforeEach(async () => {
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
jest.mock('@/eventbus/MessageEventBus/MessageEventBus');
|
jest.mock('@/eventbus/MessageEventBus/MessageEventBus');
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
await eventBus.close();
|
await eventBus.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ const MOCK_RENEW_OFFSET = 259200;
|
||||||
const MOCK_INSTANCE_ID = 'instance-id';
|
const MOCK_INSTANCE_ID = 'instance-id';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let authAgent: AuthAgent;
|
let authAgent: AuthAgent;
|
||||||
|
@ -21,8 +20,7 @@ let license: License;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['license'], applyAuth: true });
|
app = await utils.initTestServer({ endpointGroups: ['license'], applyAuth: true });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||||
|
@ -43,11 +41,11 @@ beforeEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await testDb.truncate(['Settings'], testDbName);
|
await testDb.truncate(['Settings']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /license should return license information to the instance owner', async () => {
|
test('GET /license should return license information to the instance owner', async () => {
|
||||||
|
|
|
@ -18,15 +18,13 @@ import type { AuthAgent } from './shared/types';
|
||||||
import * as utils from './shared/utils';
|
import * as utils from './shared/utils';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let authAgent: AuthAgent;
|
let authAgent: AuthAgent;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['me'], applyAuth: true });
|
app = await utils.initTestServer({ endpointGroups: ['me'], applyAuth: true });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||||
|
@ -38,12 +36,12 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Owner shell', () => {
|
describe('Owner shell', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User'], testDbName);
|
await testDb.truncate(['User']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /me should return sanitized owner shell', async () => {
|
test('GET /me should return sanitized owner shell', async () => {
|
||||||
|
@ -113,7 +111,7 @@ describe('Owner shell', () => {
|
||||||
expect(globalRole.scope).toBe('global');
|
expect(globalRole.scope).toBe('global');
|
||||||
expect(apiKey).toBeUndefined();
|
expect(apiKey).toBeUndefined();
|
||||||
|
|
||||||
const storedOwnerShell = await Db.collections.User.findOneOrFail(id);
|
const storedOwnerShell = await Db.collections.User.findOneByOrFail({ id });
|
||||||
|
|
||||||
expect(storedOwnerShell.email).toBe(validPayload.email.toLowerCase());
|
expect(storedOwnerShell.email).toBe(validPayload.email.toLowerCase());
|
||||||
expect(storedOwnerShell.firstName).toBe(validPayload.firstName);
|
expect(storedOwnerShell.firstName).toBe(validPayload.firstName);
|
||||||
|
@ -129,7 +127,7 @@ describe('Owner shell', () => {
|
||||||
const response = await authOwnerShellAgent.patch('/me').send(invalidPayload);
|
const response = await authOwnerShellAgent.patch('/me').send(invalidPayload);
|
||||||
expect(response.statusCode).toBe(400);
|
expect(response.statusCode).toBe(400);
|
||||||
|
|
||||||
const storedOwnerShell = await Db.collections.User.findOneOrFail();
|
const storedOwnerShell = await Db.collections.User.findOneByOrFail({});
|
||||||
expect(storedOwnerShell.email).toBeNull();
|
expect(storedOwnerShell.email).toBeNull();
|
||||||
expect(storedOwnerShell.firstName).toBeNull();
|
expect(storedOwnerShell.firstName).toBeNull();
|
||||||
expect(storedOwnerShell.lastName).toBeNull();
|
expect(storedOwnerShell.lastName).toBeNull();
|
||||||
|
@ -152,7 +150,7 @@ describe('Owner shell', () => {
|
||||||
const response = await authOwnerShellAgent.patch('/me/password').send(payload);
|
const response = await authOwnerShellAgent.patch('/me/password').send(payload);
|
||||||
expect([400, 500].includes(response.statusCode)).toBe(true);
|
expect([400, 500].includes(response.statusCode)).toBe(true);
|
||||||
|
|
||||||
const storedMember = await Db.collections.User.findOneOrFail();
|
const storedMember = await Db.collections.User.findOneByOrFail({});
|
||||||
|
|
||||||
if (payload.newPassword) {
|
if (payload.newPassword) {
|
||||||
expect(storedMember.password).not.toBe(payload.newPassword);
|
expect(storedMember.password).not.toBe(payload.newPassword);
|
||||||
|
@ -164,7 +162,7 @@ describe('Owner shell', () => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const storedOwnerShell = await Db.collections.User.findOneOrFail();
|
const storedOwnerShell = await Db.collections.User.findOneByOrFail({});
|
||||||
expect(storedOwnerShell.password).toBeNull();
|
expect(storedOwnerShell.password).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -241,7 +239,7 @@ describe('Member', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await testDb.truncate(['User'], testDbName);
|
await testDb.truncate(['User']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /me should return sanitized member', async () => {
|
test('GET /me should return sanitized member', async () => {
|
||||||
|
@ -311,7 +309,7 @@ describe('Member', () => {
|
||||||
expect(globalRole.scope).toBe('global');
|
expect(globalRole.scope).toBe('global');
|
||||||
expect(apiKey).toBeUndefined();
|
expect(apiKey).toBeUndefined();
|
||||||
|
|
||||||
const storedMember = await Db.collections.User.findOneOrFail(id);
|
const storedMember = await Db.collections.User.findOneByOrFail({ id });
|
||||||
|
|
||||||
expect(storedMember.email).toBe(validPayload.email.toLowerCase());
|
expect(storedMember.email).toBe(validPayload.email.toLowerCase());
|
||||||
expect(storedMember.firstName).toBe(validPayload.firstName);
|
expect(storedMember.firstName).toBe(validPayload.firstName);
|
||||||
|
@ -327,7 +325,7 @@ describe('Member', () => {
|
||||||
const response = await authMemberAgent.patch('/me').send(invalidPayload);
|
const response = await authMemberAgent.patch('/me').send(invalidPayload);
|
||||||
expect(response.statusCode).toBe(400);
|
expect(response.statusCode).toBe(400);
|
||||||
|
|
||||||
const storedMember = await Db.collections.User.findOneOrFail();
|
const storedMember = await Db.collections.User.findOneByOrFail({});
|
||||||
expect(storedMember.email).toBe(member.email);
|
expect(storedMember.email).toBe(member.email);
|
||||||
expect(storedMember.firstName).toBe(member.firstName);
|
expect(storedMember.firstName).toBe(member.firstName);
|
||||||
expect(storedMember.lastName).toBe(member.lastName);
|
expect(storedMember.lastName).toBe(member.lastName);
|
||||||
|
@ -350,7 +348,7 @@ describe('Member', () => {
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
expect(response.body).toEqual(SUCCESS_RESPONSE_BODY);
|
expect(response.body).toEqual(SUCCESS_RESPONSE_BODY);
|
||||||
|
|
||||||
const storedMember = await Db.collections.User.findOneOrFail();
|
const storedMember = await Db.collections.User.findOneByOrFail({});
|
||||||
expect(storedMember.password).not.toBe(member.password);
|
expect(storedMember.password).not.toBe(member.password);
|
||||||
expect(storedMember.password).not.toBe(validPayload.newPassword);
|
expect(storedMember.password).not.toBe(validPayload.newPassword);
|
||||||
});
|
});
|
||||||
|
@ -363,7 +361,7 @@ describe('Member', () => {
|
||||||
const response = await authMemberAgent.patch('/me/password').send(payload);
|
const response = await authMemberAgent.patch('/me/password').send(payload);
|
||||||
expect([400, 500].includes(response.statusCode)).toBe(true);
|
expect([400, 500].includes(response.statusCode)).toBe(true);
|
||||||
|
|
||||||
const storedMember = await Db.collections.User.findOneOrFail();
|
const storedMember = await Db.collections.User.findOneByOrFail({});
|
||||||
|
|
||||||
if (payload.newPassword) {
|
if (payload.newPassword) {
|
||||||
expect(storedMember.password).not.toBe(payload.newPassword);
|
expect(storedMember.password).not.toBe(payload.newPassword);
|
||||||
|
@ -385,7 +383,9 @@ describe('Member', () => {
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
expect(response.body).toEqual(SUCCESS_RESPONSE_BODY);
|
expect(response.body).toEqual(SUCCESS_RESPONSE_BODY);
|
||||||
|
|
||||||
const { personalizationAnswers: storedAnswers } = await Db.collections.User.findOneOrFail();
|
const { personalizationAnswers: storedAnswers } = await Db.collections.User.findOneByOrFail(
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
expect(storedAnswers).toEqual(validPayload);
|
expect(storedAnswers).toEqual(validPayload);
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,7 @@ describe('Member', () => {
|
||||||
expect(response.body.data.apiKey).toBeDefined();
|
expect(response.body.data.apiKey).toBeDefined();
|
||||||
expect(response.body.data.apiKey).not.toBeNull();
|
expect(response.body.data.apiKey).not.toBeNull();
|
||||||
|
|
||||||
const storedMember = await Db.collections.User.findOneOrFail(member.id);
|
const storedMember = await Db.collections.User.findOneByOrFail({ id: member.id });
|
||||||
|
|
||||||
expect(storedMember.apiKey).toEqual(response.body.data.apiKey);
|
expect(storedMember.apiKey).toEqual(response.body.data.apiKey);
|
||||||
});
|
});
|
||||||
|
@ -430,7 +430,7 @@ describe('Member', () => {
|
||||||
|
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
const storedMember = await Db.collections.User.findOneOrFail(member.id);
|
const storedMember = await Db.collections.User.findOneByOrFail({ id: member.id });
|
||||||
|
|
||||||
expect(storedMember.apiKey).toBeNull();
|
expect(storedMember.apiKey).toBeNull();
|
||||||
});
|
});
|
||||||
|
@ -442,7 +442,7 @@ describe('Owner', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await testDb.truncate(['User'], testDbName);
|
await testDb.truncate(['User']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /me should return sanitized owner', async () => {
|
test('GET /me should return sanitized owner', async () => {
|
||||||
|
@ -512,7 +512,7 @@ describe('Owner', () => {
|
||||||
expect(globalRole.scope).toBe('global');
|
expect(globalRole.scope).toBe('global');
|
||||||
expect(apiKey).toBeUndefined();
|
expect(apiKey).toBeUndefined();
|
||||||
|
|
||||||
const storedOwner = await Db.collections.User.findOneOrFail(id);
|
const storedOwner = await Db.collections.User.findOneByOrFail({ id });
|
||||||
|
|
||||||
expect(storedOwner.email).toBe(validPayload.email.toLowerCase());
|
expect(storedOwner.email).toBe(validPayload.email.toLowerCase());
|
||||||
expect(storedOwner.firstName).toBe(validPayload.firstName);
|
expect(storedOwner.firstName).toBe(validPayload.firstName);
|
||||||
|
|
|
@ -43,14 +43,12 @@ jest.mock('@/CommunityNodes/packageModel', () => {
|
||||||
const mockedEmptyPackage = mocked(utils.emptyPackage);
|
const mockedEmptyPackage = mocked(utils.emptyPackage);
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let authAgent: AuthAgent;
|
let authAgent: AuthAgent;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['nodes'], applyAuth: true });
|
app = await utils.initTestServer({ endpointGroups: ['nodes'], applyAuth: true });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
|
|
||||||
|
@ -62,14 +60,14 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['InstalledNodes', 'InstalledPackages', 'User'], testDbName);
|
await testDb.truncate(['InstalledNodes', 'InstalledPackages', 'User']);
|
||||||
|
|
||||||
mocked(executeCommand).mockReset();
|
mocked(executeCommand).mockReset();
|
||||||
mocked(findInstalledPackage).mockReset();
|
mocked(findInstalledPackage).mockReset();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,14 +15,12 @@ import type { AuthAgent } from './shared/types';
|
||||||
import * as utils from './shared/utils';
|
import * as utils from './shared/utils';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let authAgent: AuthAgent;
|
let authAgent: AuthAgent;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['owner'], applyAuth: true });
|
app = await utils.initTestServer({ endpointGroups: ['owner'], applyAuth: true });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
|
|
||||||
|
@ -37,11 +35,11 @@ beforeEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await testDb.truncate(['User'], testDbName);
|
await testDb.truncate(['User']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /owner should create owner and enable isInstanceOwnerSetUp', async () => {
|
test('POST /owner should create owner and enable isInstanceOwnerSetUp', async () => {
|
||||||
|
@ -83,7 +81,7 @@ test('POST /owner should create owner and enable isInstanceOwnerSetUp', async ()
|
||||||
expect(globalRole.scope).toBe('global');
|
expect(globalRole.scope).toBe('global');
|
||||||
expect(apiKey).toBeUndefined();
|
expect(apiKey).toBeUndefined();
|
||||||
|
|
||||||
const storedOwner = await Db.collections.User.findOneOrFail(id);
|
const storedOwner = await Db.collections.User.findOneByOrFail({ id });
|
||||||
expect(storedOwner.password).not.toBe(newOwnerData.password);
|
expect(storedOwner.password).not.toBe(newOwnerData.password);
|
||||||
expect(storedOwner.email).toBe(newOwnerData.email);
|
expect(storedOwner.email).toBe(newOwnerData.email);
|
||||||
expect(storedOwner.firstName).toBe(newOwnerData.firstName);
|
expect(storedOwner.firstName).toBe(newOwnerData.firstName);
|
||||||
|
@ -115,7 +113,7 @@ test('POST /owner should create owner with lowercased email', async () => {
|
||||||
expect(id).toBe(ownerShell.id);
|
expect(id).toBe(ownerShell.id);
|
||||||
expect(email).toBe(newOwnerData.email.toLowerCase());
|
expect(email).toBe(newOwnerData.email.toLowerCase());
|
||||||
|
|
||||||
const storedOwner = await Db.collections.User.findOneOrFail(id);
|
const storedOwner = await Db.collections.User.findOneByOrFail({ id });
|
||||||
expect(storedOwner.email).toBe(newOwnerData.email.toLowerCase());
|
expect(storedOwner.email).toBe(newOwnerData.email.toLowerCase());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -141,7 +139,7 @@ test('POST /owner/skip-setup should persist skipping setup to the DB', async ()
|
||||||
const skipConfig = config.getEnv('userManagement.skipInstanceOwnerSetup');
|
const skipConfig = config.getEnv('userManagement.skipInstanceOwnerSetup');
|
||||||
expect(skipConfig).toBe(true);
|
expect(skipConfig).toBe(true);
|
||||||
|
|
||||||
const { value } = await Db.collections.Settings.findOneOrFail({
|
const { value } = await Db.collections.Settings.findOneByOrFail({
|
||||||
key: 'userManagement.skipInstanceOwnerSetup',
|
key: 'userManagement.skipInstanceOwnerSetup',
|
||||||
});
|
});
|
||||||
expect(value).toBe('true');
|
expect(value).toBe('true');
|
||||||
|
|
|
@ -17,14 +17,12 @@ import type { Role } from '@db/entities/Role';
|
||||||
jest.mock('@/UserManagement/email/NodeMailer');
|
jest.mock('@/UserManagement/email/NodeMailer');
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['passwordReset'], applyAuth: true });
|
app = await utils.initTestServer({ endpointGroups: ['passwordReset'], applyAuth: true });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||||
|
@ -34,7 +32,7 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User'], testDbName);
|
await testDb.truncate(['User']);
|
||||||
|
|
||||||
jest.mock('@/config');
|
jest.mock('@/config');
|
||||||
|
|
||||||
|
@ -43,7 +41,7 @@ beforeEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /forgot-password should send password reset email', async () => {
|
test('POST /forgot-password should send password reset email', async () => {
|
||||||
|
@ -64,7 +62,7 @@ test('POST /forgot-password should send password reset email', async () => {
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
expect(response.body).toEqual({});
|
expect(response.body).toEqual({});
|
||||||
|
|
||||||
const user = await Db.collections.User.findOneOrFail({ email: payload.email });
|
const user = await Db.collections.User.findOneByOrFail({ email: payload.email });
|
||||||
expect(user.resetPasswordToken).toBeDefined();
|
expect(user.resetPasswordToken).toBeDefined();
|
||||||
expect(user.resetPasswordTokenExpiration).toBeGreaterThan(Math.ceil(Date.now() / 1000));
|
expect(user.resetPasswordTokenExpiration).toBeGreaterThan(Math.ceil(Date.now() / 1000));
|
||||||
}),
|
}),
|
||||||
|
@ -80,7 +78,7 @@ test('POST /forgot-password should fail if emailing is not set up', async () =>
|
||||||
|
|
||||||
expect(response.statusCode).toBe(500);
|
expect(response.statusCode).toBe(500);
|
||||||
|
|
||||||
const storedOwner = await Db.collections.User.findOneOrFail({ email: owner.email });
|
const storedOwner = await Db.collections.User.findOneByOrFail({ email: owner.email });
|
||||||
expect(storedOwner.resetPasswordToken).toBeNull();
|
expect(storedOwner.resetPasswordToken).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -104,7 +102,7 @@ test('POST /forgot-password should fail with invalid inputs', async () => {
|
||||||
const response = await authlessAgent.post('/forgot-password').send(invalidPayload);
|
const response = await authlessAgent.post('/forgot-password').send(invalidPayload);
|
||||||
expect(response.statusCode).toBe(400);
|
expect(response.statusCode).toBe(400);
|
||||||
|
|
||||||
const storedOwner = await Db.collections.User.findOneOrFail({ email: owner.email });
|
const storedOwner = await Db.collections.User.findOneByOrFail({ email: owner.email });
|
||||||
expect(storedOwner.resetPasswordToken).toBeNull();
|
expect(storedOwner.resetPasswordToken).toBeNull();
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -218,7 +216,7 @@ test('POST /change-password should succeed with valid inputs', async () => {
|
||||||
const authToken = utils.getAuthToken(response);
|
const authToken = utils.getAuthToken(response);
|
||||||
expect(authToken).toBeDefined();
|
expect(authToken).toBeDefined();
|
||||||
|
|
||||||
const { password: storedPassword } = await Db.collections.User.findOneOrFail(owner.id);
|
const { password: storedPassword } = await Db.collections.User.findOneByOrFail({ id: owner.id });
|
||||||
|
|
||||||
const comparisonResult = await compare(passwordToStore, storedPassword);
|
const comparisonResult = await compare(passwordToStore, storedPassword);
|
||||||
expect(comparisonResult).toBe(true);
|
expect(comparisonResult).toBe(true);
|
||||||
|
@ -262,7 +260,7 @@ test('POST /change-password should fail with invalid inputs', async () => {
|
||||||
const response = await authlessAgent.post('/change-password').query(invalidPayload);
|
const response = await authlessAgent.post('/change-password').query(invalidPayload);
|
||||||
expect(response.statusCode).toBe(400);
|
expect(response.statusCode).toBe(400);
|
||||||
|
|
||||||
const { password: storedPassword } = await Db.collections.User.findOneOrFail();
|
const { password: storedPassword } = await Db.collections.User.findOneByOrFail({});
|
||||||
expect(owner.password).toBe(storedPassword);
|
expect(owner.password).toBe(storedPassword);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,7 +11,6 @@ import type { CredentialPayload, SaveCredentialFunction } from '../shared/types'
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let credentialOwnerRole: Role;
|
let credentialOwnerRole: Role;
|
||||||
|
@ -20,8 +19,7 @@ let saveCredential: SaveCredentialFunction;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['publicApi'], applyAuth: false });
|
app = await utils.initTestServer({ endpointGroups: ['publicApi'], applyAuth: false });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
utils.initConfigFile();
|
utils.initConfigFile();
|
||||||
|
|
||||||
|
@ -40,11 +38,11 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User', 'SharedCredentials', 'Credentials'], testDbName);
|
await testDb.truncate(['User', 'SharedCredentials', 'Credentials']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /credentials should create credentials', async () => {
|
test('POST /credentials should create credentials', async () => {
|
||||||
|
@ -76,15 +74,15 @@ test('POST /credentials should create credentials', async () => {
|
||||||
expect(name).toBe(payload.name);
|
expect(name).toBe(payload.name);
|
||||||
expect(type).toBe(payload.type);
|
expect(type).toBe(payload.type);
|
||||||
|
|
||||||
const credential = await Db.collections.Credentials!.findOneOrFail(id);
|
const credential = await Db.collections.Credentials.findOneByOrFail({ id });
|
||||||
|
|
||||||
expect(credential.name).toBe(payload.name);
|
expect(credential.name).toBe(payload.name);
|
||||||
expect(credential.type).toBe(payload.type);
|
expect(credential.type).toBe(payload.type);
|
||||||
expect(credential.data).not.toBe(payload.data);
|
expect(credential.data).not.toBe(payload.data);
|
||||||
|
|
||||||
const sharedCredential = await Db.collections.SharedCredentials!.findOneOrFail({
|
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
||||||
relations: ['user', 'credentials', 'role'],
|
relations: ['user', 'credentials', 'role'],
|
||||||
where: { credentials: credential, user: ownerShell },
|
where: { credentialsId: credential.id, userId: ownerShell.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredential.role).toEqual(credentialOwnerRole);
|
expect(sharedCredential.role).toEqual(credentialOwnerRole);
|
||||||
|
@ -153,13 +151,13 @@ test('DELETE /credentials/:id should delete owned cred for owner', async () => {
|
||||||
expect(name).toBe(savedCredential.name);
|
expect(name).toBe(savedCredential.name);
|
||||||
expect(type).toBe(savedCredential.type);
|
expect(type).toBe(savedCredential.type);
|
||||||
|
|
||||||
const deletedCredential = await Db.collections.Credentials!.findOne(savedCredential.id);
|
const deletedCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(deletedCredential).toBeUndefined(); // deleted
|
expect(deletedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials!.findOne();
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOneBy({});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeUndefined(); // deleted
|
expect(deletedSharedCredential).toBeNull(); // deleted
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /credentials/:id should delete non-owned cred for owner', async () => {
|
test('DELETE /credentials/:id should delete non-owned cred for owner', async () => {
|
||||||
|
@ -181,13 +179,13 @@ test('DELETE /credentials/:id should delete non-owned cred for owner', async ()
|
||||||
|
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
const deletedCredential = await Db.collections.Credentials!.findOne(savedCredential.id);
|
const deletedCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(deletedCredential).toBeUndefined(); // deleted
|
expect(deletedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials!.findOne();
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOneBy({});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeUndefined(); // deleted
|
expect(deletedSharedCredential).toBeNull(); // deleted
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /credentials/:id should delete owned cred for member', async () => {
|
test('DELETE /credentials/:id should delete owned cred for member', async () => {
|
||||||
|
@ -211,13 +209,13 @@ test('DELETE /credentials/:id should delete owned cred for member', async () =>
|
||||||
expect(name).toBe(savedCredential.name);
|
expect(name).toBe(savedCredential.name);
|
||||||
expect(type).toBe(savedCredential.type);
|
expect(type).toBe(savedCredential.type);
|
||||||
|
|
||||||
const deletedCredential = await Db.collections.Credentials!.findOne(savedCredential.id);
|
const deletedCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(deletedCredential).toBeUndefined(); // deleted
|
expect(deletedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials!.findOne();
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOneBy({});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeUndefined(); // deleted
|
expect(deletedSharedCredential).toBeNull(); // deleted
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /credentials/:id should delete owned cred for member but leave others untouched', async () => {
|
test('DELETE /credentials/:id should delete owned cred for member but leave others untouched', async () => {
|
||||||
|
@ -244,27 +242,27 @@ test('DELETE /credentials/:id should delete owned cred for member but leave othe
|
||||||
expect(name).toBe(savedCredential.name);
|
expect(name).toBe(savedCredential.name);
|
||||||
expect(type).toBe(savedCredential.type);
|
expect(type).toBe(savedCredential.type);
|
||||||
|
|
||||||
const deletedCredential = await Db.collections.Credentials!.findOne(savedCredential.id);
|
const deletedCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(deletedCredential).toBeUndefined(); // deleted
|
expect(deletedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials!.findOne({
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOne({
|
||||||
where: {
|
where: {
|
||||||
credentials: savedCredential,
|
credentialsId: savedCredential.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeUndefined(); // deleted
|
expect(deletedSharedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
[notToBeChangedCredential, notToBeChangedCredential2].map(async (credential) => {
|
[notToBeChangedCredential, notToBeChangedCredential2].map(async (credential) => {
|
||||||
const untouchedCredential = await Db.collections.Credentials!.findOne(credential.id);
|
const untouchedCredential = await Db.collections.Credentials.findOneBy({ id: credential.id });
|
||||||
|
|
||||||
expect(untouchedCredential).toEqual(credential); // not deleted
|
expect(untouchedCredential).toEqual(credential); // not deleted
|
||||||
|
|
||||||
const untouchedSharedCredential = await Db.collections.SharedCredentials!.findOne({
|
const untouchedSharedCredential = await Db.collections.SharedCredentials.findOne({
|
||||||
where: {
|
where: {
|
||||||
credentials: credential,
|
credentialsId: credential.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -289,11 +287,11 @@ test('DELETE /credentials/:id should not delete non-owned cred for member', asyn
|
||||||
|
|
||||||
expect(response.statusCode).toBe(404);
|
expect(response.statusCode).toBe(404);
|
||||||
|
|
||||||
const shellCredential = await Db.collections.Credentials!.findOne(savedCredential.id);
|
const shellCredential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
|
|
||||||
expect(shellCredential).toBeDefined(); // not deleted
|
expect(shellCredential).toBeDefined(); // not deleted
|
||||||
|
|
||||||
const deletedSharedCredential = await Db.collections.SharedCredentials!.findOne();
|
const deletedSharedCredential = await Db.collections.SharedCredentials.findOneBy({});
|
||||||
|
|
||||||
expect(deletedSharedCredential).toBeDefined(); // not deleted
|
expect(deletedSharedCredential).toBeDefined(); // not deleted
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,14 +9,12 @@ import * as utils from '../shared/utils';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let workflowRunner: ActiveWorkflowRunner;
|
let workflowRunner: ActiveWorkflowRunner;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['publicApi'], applyAuth: false });
|
app = await utils.initTestServer({ endpointGroups: ['publicApi'], applyAuth: false });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
|
|
||||||
|
@ -30,18 +28,15 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(
|
await testDb.truncate([
|
||||||
[
|
'SharedCredentials',
|
||||||
'SharedCredentials',
|
'SharedWorkflow',
|
||||||
'SharedWorkflow',
|
'User',
|
||||||
'User',
|
'Workflow',
|
||||||
'Workflow',
|
'Credentials',
|
||||||
'Credentials',
|
'Execution',
|
||||||
'Execution',
|
'Settings',
|
||||||
'Settings',
|
]);
|
||||||
],
|
|
||||||
testDbName,
|
|
||||||
);
|
|
||||||
|
|
||||||
config.set('userManagement.disabled', false);
|
config.set('userManagement.disabled', false);
|
||||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||||
|
@ -52,7 +47,7 @@ afterEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /executions/:id should fail due to missing API Key', async () => {
|
test('GET /executions/:id should fail due to missing API Key', async () => {
|
||||||
|
|
|
@ -11,7 +11,6 @@ import * as utils from '../shared/utils';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let workflowOwnerRole: Role;
|
let workflowOwnerRole: Role;
|
||||||
|
@ -19,8 +18,7 @@ let workflowRunner: ActiveWorkflowRunner;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['publicApi'], applyAuth: false });
|
app = await utils.initTestServer({ endpointGroups: ['publicApi'], applyAuth: false });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
const [fetchedGlobalOwnerRole, fetchedGlobalMemberRole, fetchedWorkflowOwnerRole] =
|
const [fetchedGlobalOwnerRole, fetchedGlobalMemberRole, fetchedWorkflowOwnerRole] =
|
||||||
await testDb.getAllRoles();
|
await testDb.getAllRoles();
|
||||||
|
@ -37,10 +35,14 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(
|
await testDb.truncate([
|
||||||
['SharedCredentials', 'SharedWorkflow', 'Tag', 'User', 'Workflow', 'Credentials'],
|
'SharedCredentials',
|
||||||
testDbName,
|
'SharedWorkflow',
|
||||||
);
|
'Tag',
|
||||||
|
'User',
|
||||||
|
'Workflow',
|
||||||
|
'Credentials',
|
||||||
|
]);
|
||||||
|
|
||||||
config.set('userManagement.disabled', false);
|
config.set('userManagement.disabled', false);
|
||||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||||
|
@ -51,7 +53,7 @@ afterEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /workflows should fail due to missing API Key', async () => {
|
test('GET /workflows should fail due to missing API Key', async () => {
|
||||||
|
@ -537,11 +539,11 @@ test('DELETE /workflows/:id should delete the workflow', async () => {
|
||||||
expect(updatedAt).toEqual(workflow.updatedAt.toISOString());
|
expect(updatedAt).toEqual(workflow.updatedAt.toISOString());
|
||||||
|
|
||||||
// make sure the workflow actually deleted from the db
|
// make sure the workflow actually deleted from the db
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOneBy({
|
||||||
workflow,
|
workflowId: workflow.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedWorkflow).toBeUndefined();
|
expect(sharedWorkflow).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /workflows/:id should delete non-owned workflow when owner', async () => {
|
test('DELETE /workflows/:id should delete non-owned workflow when owner', async () => {
|
||||||
|
@ -576,11 +578,11 @@ test('DELETE /workflows/:id should delete non-owned workflow when owner', async
|
||||||
expect(updatedAt).toEqual(workflow.updatedAt.toISOString());
|
expect(updatedAt).toEqual(workflow.updatedAt.toISOString());
|
||||||
|
|
||||||
// make sure the workflow actually deleted from the db
|
// make sure the workflow actually deleted from the db
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOneBy({
|
||||||
workflow,
|
workflowId: workflow.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedWorkflow).toBeUndefined();
|
expect(sharedWorkflow).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /workflows/:id/activate should fail due to missing API Key', async () => {
|
test('POST /workflows/:id/activate should fail due to missing API Key', async () => {
|
||||||
|
@ -679,8 +681,8 @@ test('POST /workflows/:id/activate should set workflow as active', async () => {
|
||||||
// check whether the workflow is on the database
|
// check whether the workflow is on the database
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: member,
|
userId: member.id,
|
||||||
workflow,
|
workflowId: workflow.id,
|
||||||
},
|
},
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
});
|
});
|
||||||
|
@ -724,17 +726,17 @@ test('POST /workflows/:id/activate should set non-owned workflow as active when
|
||||||
// check whether the workflow is on the database
|
// check whether the workflow is on the database
|
||||||
const sharedOwnerWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedOwnerWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: owner,
|
userId: owner.id,
|
||||||
workflow,
|
workflowId: workflow.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedOwnerWorkflow).toBeUndefined();
|
expect(sharedOwnerWorkflow).toBeNull();
|
||||||
|
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: member,
|
userId: member.id,
|
||||||
workflow,
|
workflowId: workflow.id,
|
||||||
},
|
},
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
});
|
});
|
||||||
|
@ -824,8 +826,8 @@ test('POST /workflows/:id/deactivate should deactivate workflow', async () => {
|
||||||
// get the workflow after it was deactivated
|
// get the workflow after it was deactivated
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: member,
|
userId: member.id,
|
||||||
workflow,
|
workflowId: workflow.id,
|
||||||
},
|
},
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
});
|
});
|
||||||
|
@ -869,17 +871,17 @@ test('POST /workflows/:id/deactivate should deactivate non-owned workflow when o
|
||||||
// check whether the workflow is deactivated in the database
|
// check whether the workflow is deactivated in the database
|
||||||
const sharedOwnerWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedOwnerWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: owner,
|
userId: owner.id,
|
||||||
workflow,
|
workflowId: workflow.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedOwnerWorkflow).toBeUndefined();
|
expect(sharedOwnerWorkflow).toBeNull();
|
||||||
|
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: member,
|
userId: member.id,
|
||||||
workflow,
|
workflowId: workflow.id,
|
||||||
},
|
},
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
});
|
});
|
||||||
|
@ -990,8 +992,8 @@ test('POST /workflows should create workflow', async () => {
|
||||||
// check if created workflow in DB
|
// check if created workflow in DB
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: member,
|
userId: member.id,
|
||||||
workflow: response.body,
|
workflowId: response.body.id,
|
||||||
},
|
},
|
||||||
relations: ['workflow', 'role'],
|
relations: ['workflow', 'role'],
|
||||||
});
|
});
|
||||||
|
@ -1170,8 +1172,8 @@ test('PUT /workflows/:id should update workflow', async () => {
|
||||||
// check updated workflow in DB
|
// check updated workflow in DB
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: member,
|
userId: member.id,
|
||||||
workflow: response.body,
|
workflowId: response.body.id,
|
||||||
},
|
},
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
});
|
});
|
||||||
|
@ -1247,17 +1249,17 @@ test('PUT /workflows/:id should update non-owned workflow if owner', async () =>
|
||||||
// check updated workflow in DB
|
// check updated workflow in DB
|
||||||
const sharedOwnerWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedOwnerWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: owner,
|
userId: owner.id,
|
||||||
workflow: response.body,
|
workflowId: response.body.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedOwnerWorkflow).toBeUndefined();
|
expect(sharedOwnerWorkflow).toBeNull();
|
||||||
|
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
where: {
|
where: {
|
||||||
user: member,
|
userId: member.id,
|
||||||
workflow: response.body,
|
workflowId: response.body.id,
|
||||||
},
|
},
|
||||||
relations: ['workflow', 'role'],
|
relations: ['workflow', 'role'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import superagent = require('superagent');
|
import superagent = require('superagent');
|
||||||
import { ObjectLiteral } from 'typeorm';
|
import type { ObjectLiteral } from 'typeorm';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make `SuperTest<T>` string-indexable.
|
* Make `SuperTest<T>` string-indexable.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { UserSettings } from 'n8n-core';
|
import { UserSettings } from 'n8n-core';
|
||||||
import { Connection, ConnectionOptions, createConnection, getConnection } from 'typeorm';
|
import { DataSource as Connection, DataSourceOptions as ConnectionOptions } from 'typeorm';
|
||||||
|
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
|
@ -50,7 +50,7 @@ export async function init() {
|
||||||
// no bootstrap connection required
|
// no bootstrap connection required
|
||||||
const testDbName = `n8n_test_sqlite_${randomString(6, 10)}_${Date.now()}`;
|
const testDbName = `n8n_test_sqlite_${randomString(6, 10)}_${Date.now()}`;
|
||||||
await Db.init(getSqliteOptions({ name: testDbName }));
|
await Db.init(getSqliteOptions({ name: testDbName }));
|
||||||
await getConnection(testDbName).runMigrations({ transaction: 'none' });
|
await Db.getConnection().runMigrations({ transaction: 'none' });
|
||||||
|
|
||||||
return { testDbName };
|
return { testDbName };
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ export async function init() {
|
||||||
const pgOptions = getBootstrapDBOptions('postgres');
|
const pgOptions = getBootstrapDBOptions('postgres');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bootstrapPostgres = await createConnection(pgOptions);
|
bootstrapPostgres = await new Connection(pgOptions).initialize();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const pgConfig = getPostgresSchemaSection();
|
const pgConfig = getPostgresSchemaSection();
|
||||||
|
|
||||||
|
@ -82,15 +82,15 @@ export async function init() {
|
||||||
|
|
||||||
const testDbName = `postgres_${randomString(6, 10)}_${Date.now()}_n8n_test`;
|
const testDbName = `postgres_${randomString(6, 10)}_${Date.now()}_n8n_test`;
|
||||||
await bootstrapPostgres.query(`CREATE DATABASE ${testDbName}`);
|
await bootstrapPostgres.query(`CREATE DATABASE ${testDbName}`);
|
||||||
await bootstrapPostgres.close();
|
await bootstrapPostgres.destroy();
|
||||||
|
|
||||||
const dbOptions = getDBOptions('postgres', testDbName);
|
const dbOptions = getDBOptions('postgres', testDbName);
|
||||||
|
|
||||||
if (dbOptions.schema !== 'public') {
|
if (dbOptions.schema !== 'public') {
|
||||||
const { schema, migrations, ...options } = dbOptions;
|
const { schema, migrations, ...options } = dbOptions;
|
||||||
const connection = await createConnection(options);
|
const connection = await new Connection(options).initialize();
|
||||||
await connection.query(`CREATE SCHEMA IF NOT EXISTS "${schema}"`);
|
await connection.query(`CREATE SCHEMA IF NOT EXISTS "${schema}"`);
|
||||||
await connection.close();
|
await connection.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await Db.init(dbOptions);
|
await Db.init(dbOptions);
|
||||||
|
@ -99,11 +99,11 @@ export async function init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dbType === 'mysqldb') {
|
if (dbType === 'mysqldb') {
|
||||||
const bootstrapMysql = await createConnection(getBootstrapDBOptions('mysql'));
|
const bootstrapMysql = await new Connection(getBootstrapDBOptions('mysql')).initialize();
|
||||||
|
|
||||||
const testDbName = `mysql_${randomString(6, 10)}_${Date.now()}_n8n_test`;
|
const testDbName = `mysql_${randomString(6, 10)}_${Date.now()}_n8n_test`;
|
||||||
await bootstrapMysql.query(`CREATE DATABASE ${testDbName}`);
|
await bootstrapMysql.query(`CREATE DATABASE ${testDbName}`);
|
||||||
await bootstrapMysql.close();
|
await bootstrapMysql.destroy();
|
||||||
|
|
||||||
await Db.init(getDBOptions('mysql', testDbName));
|
await Db.init(getDBOptions('mysql', testDbName));
|
||||||
|
|
||||||
|
@ -116,8 +116,8 @@ export async function init() {
|
||||||
/**
|
/**
|
||||||
* Drop test DB, closing bootstrap connection if existing.
|
* Drop test DB, closing bootstrap connection if existing.
|
||||||
*/
|
*/
|
||||||
export async function terminate(testDbName: string) {
|
export async function terminate() {
|
||||||
await getConnection(testDbName).close();
|
await Db.getConnection().destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function truncateMappingTables(
|
async function truncateMappingTables(
|
||||||
|
@ -171,9 +171,9 @@ async function truncateMappingTables(
|
||||||
* @param collections Array of entity names whose tables to truncate.
|
* @param collections Array of entity names whose tables to truncate.
|
||||||
* @param testDbName Name of the test DB to truncate tables in.
|
* @param testDbName Name of the test DB to truncate tables in.
|
||||||
*/
|
*/
|
||||||
export async function truncate(collections: Array<CollectionName>, testDbName: string) {
|
export async function truncate(collections: Array<CollectionName>) {
|
||||||
const dbType = config.getEnv('database.type');
|
const dbType = config.getEnv('database.type');
|
||||||
const testDb = getConnection(testDbName);
|
const testDb = Db.getConnection();
|
||||||
|
|
||||||
if (dbType === 'sqlite') {
|
if (dbType === 'sqlite') {
|
||||||
await testDb.query('PRAGMA foreign_keys=OFF');
|
await testDb.query('PRAGMA foreign_keys=OFF');
|
||||||
|
@ -287,12 +287,12 @@ export async function saveCredential(
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function shareCredentialWithUsers(credential: CredentialsEntity, users: User[]) {
|
export async function shareCredentialWithUsers(credential: CredentialsEntity, users: User[]) {
|
||||||
const role = await Db.collections.Role.findOne({ scope: 'credential', name: 'user' });
|
const role = await Db.collections.Role.findOneBy({ scope: 'credential', name: 'user' });
|
||||||
const newSharedCredentials = users.map((user) =>
|
const newSharedCredentials = users.map((user) =>
|
||||||
Db.collections.SharedCredentials.create({
|
Db.collections.SharedCredentials.create({
|
||||||
user,
|
userId: user.id,
|
||||||
credentials: credential,
|
credentialsId: credential.id,
|
||||||
role,
|
roleId: role?.id,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return Db.collections.SharedCredentials.save(newSharedCredentials);
|
return Db.collections.SharedCredentials.save(newSharedCredentials);
|
||||||
|
@ -333,7 +333,7 @@ export function createUserShell(globalRole: Role): Promise<User> {
|
||||||
throw new Error(`Invalid role received: ${JSON.stringify(globalRole)}`);
|
throw new Error(`Invalid role received: ${JSON.stringify(globalRole)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const shell: Partial<User> = { globalRole };
|
const shell: Partial<User> = { globalRoleId: globalRole.id };
|
||||||
|
|
||||||
if (globalRole.name !== 'owner') {
|
if (globalRole.name !== 'owner') {
|
||||||
shell.email = randomEmail();
|
shell.email = randomEmail();
|
||||||
|
@ -405,35 +405,35 @@ export function addApiKey(user: User): Promise<User> {
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
export function getGlobalOwnerRole() {
|
export function getGlobalOwnerRole() {
|
||||||
return Db.collections.Role.findOneOrFail({
|
return Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'global',
|
scope: 'global',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getGlobalMemberRole() {
|
export function getGlobalMemberRole() {
|
||||||
return Db.collections.Role.findOneOrFail({
|
return Db.collections.Role.findOneByOrFail({
|
||||||
name: 'member',
|
name: 'member',
|
||||||
scope: 'global',
|
scope: 'global',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWorkflowOwnerRole() {
|
export function getWorkflowOwnerRole() {
|
||||||
return Db.collections.Role.findOneOrFail({
|
return Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'workflow',
|
scope: 'workflow',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWorkflowEditorRole() {
|
export function getWorkflowEditorRole() {
|
||||||
return Db.collections.Role.findOneOrFail({
|
return Db.collections.Role.findOneByOrFail({
|
||||||
name: 'editor',
|
name: 'editor',
|
||||||
scope: 'workflow',
|
scope: 'workflow',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCredentialOwnerRole() {
|
export function getCredentialOwnerRole() {
|
||||||
return Db.collections.Role.findOneOrFail({
|
return Db.collections.Role.findOneByOrFail({
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
scope: 'credential',
|
scope: 'credential',
|
||||||
});
|
});
|
||||||
|
@ -641,10 +641,8 @@ export async function createWorkflowWithTrigger(
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
export async function getWorkflowSharing(workflow: WorkflowEntity) {
|
export async function getWorkflowSharing(workflow: WorkflowEntity) {
|
||||||
return Db.collections.SharedWorkflow.find({
|
return Db.collections.SharedWorkflow.findBy({
|
||||||
where: {
|
workflowId: workflow.id,
|
||||||
workflow,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -646,7 +646,7 @@ export function getAuthToken(response: request.Response, authCookieName = AUTH_C
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
export async function isInstanceOwnerSetUp() {
|
export async function isInstanceOwnerSetUp() {
|
||||||
const { value } = await Db.collections.Settings.findOneOrFail({
|
const { value } = await Db.collections.Settings.findOneByOrFail({
|
||||||
key: 'userManagement.isInstanceOwnerSetUp',
|
key: 'userManagement.isInstanceOwnerSetUp',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ import { NodeMailer } from '@/UserManagement/email/NodeMailer';
|
||||||
jest.mock('@/UserManagement/email/NodeMailer');
|
jest.mock('@/UserManagement/email/NodeMailer');
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let workflowOwnerRole: Role;
|
let workflowOwnerRole: Role;
|
||||||
|
@ -34,8 +33,7 @@ let authAgent: AuthAgent;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
app = await utils.initTestServer({ endpointGroups: ['users'], applyAuth: true });
|
app = await utils.initTestServer({ endpointGroups: ['users'], applyAuth: true });
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
const [
|
const [
|
||||||
fetchedGlobalOwnerRole,
|
fetchedGlobalOwnerRole,
|
||||||
|
@ -56,10 +54,7 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(
|
await testDb.truncate(['User', 'SharedCredentials', 'SharedWorkflow', 'Workflow', 'Credentials']);
|
||||||
['User', 'SharedCredentials', 'SharedWorkflow', 'Workflow', 'Credentials'],
|
|
||||||
testDbName,
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.mock('@/config');
|
jest.mock('@/config');
|
||||||
|
|
||||||
|
@ -70,7 +65,7 @@ beforeEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /users should return all users', async () => {
|
test('GET /users should return all users', async () => {
|
||||||
|
@ -156,28 +151,28 @@ test('DELETE /users/:id should delete the user', async () => {
|
||||||
expect(response.statusCode).toBe(200);
|
expect(response.statusCode).toBe(200);
|
||||||
expect(response.body).toEqual(SUCCESS_RESPONSE_BODY);
|
expect(response.body).toEqual(SUCCESS_RESPONSE_BODY);
|
||||||
|
|
||||||
const user = await Db.collections.User.findOne(userToDelete.id);
|
const user = await Db.collections.User.findOneBy({ id: userToDelete.id });
|
||||||
expect(user).toBeUndefined(); // deleted
|
expect(user).toBeNull(); // deleted
|
||||||
|
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOne({
|
||||||
relations: ['user'],
|
relations: ['user'],
|
||||||
where: { user: userToDelete, role: workflowOwnerRole },
|
where: { userId: userToDelete.id, roleId: workflowOwnerRole.id },
|
||||||
});
|
});
|
||||||
expect(sharedWorkflow).toBeUndefined(); // deleted
|
expect(sharedWorkflow).toBeNull(); // deleted
|
||||||
|
|
||||||
const sharedCredential = await Db.collections.SharedCredentials.findOne({
|
const sharedCredential = await Db.collections.SharedCredentials.findOne({
|
||||||
relations: ['user'],
|
relations: ['user'],
|
||||||
where: { user: userToDelete, role: credentialOwnerRole },
|
where: { userId: userToDelete.id, roleId: credentialOwnerRole.id },
|
||||||
});
|
});
|
||||||
expect(sharedCredential).toBeUndefined(); // deleted
|
expect(sharedCredential).toBeNull(); // deleted
|
||||||
|
|
||||||
const workflow = await Db.collections.Workflow.findOne(savedWorkflow.id);
|
const workflow = await Db.collections.Workflow.findOneBy({ id: savedWorkflow.id });
|
||||||
expect(workflow).toBeUndefined(); // deleted
|
expect(workflow).toBeNull(); // deleted
|
||||||
|
|
||||||
// TODO: Include active workflow and check whether webhook has been removed
|
// TODO: Include active workflow and check whether webhook has been removed
|
||||||
|
|
||||||
const credential = await Db.collections.Credentials.findOne(savedCredential.id);
|
const credential = await Db.collections.Credentials.findOneBy({ id: savedCredential.id });
|
||||||
expect(credential).toBeUndefined(); // deleted
|
expect(credential).toBeNull(); // deleted
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /users/:id should fail to delete self', async () => {
|
test('DELETE /users/:id should fail to delete self', async () => {
|
||||||
|
@ -187,7 +182,7 @@ test('DELETE /users/:id should fail to delete self', async () => {
|
||||||
|
|
||||||
expect(response.statusCode).toBe(400);
|
expect(response.statusCode).toBe(400);
|
||||||
|
|
||||||
const user = await Db.collections.User.findOne(owner.id);
|
const user = await Db.collections.User.findOneBy({ id: owner.id });
|
||||||
expect(user).toBeDefined();
|
expect(user).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -202,7 +197,7 @@ test('DELETE /users/:id should fail if user to delete is transferee', async () =
|
||||||
|
|
||||||
expect(response.statusCode).toBe(400);
|
expect(response.statusCode).toBe(400);
|
||||||
|
|
||||||
const user = await Db.collections.User.findOne(idToDelete);
|
const user = await Db.collections.User.findOneBy({ id: idToDelete });
|
||||||
expect(user).toBeDefined();
|
expect(user).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -226,7 +221,7 @@ test('DELETE /users/:id with transferId should perform transfer', async () => {
|
||||||
|
|
||||||
const sharedWorkflow = await Db.collections.SharedWorkflow.findOneOrFail({
|
const sharedWorkflow = await Db.collections.SharedWorkflow.findOneOrFail({
|
||||||
relations: ['workflow'],
|
relations: ['workflow'],
|
||||||
where: { user: owner },
|
where: { userId: owner.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedWorkflow.workflow).toBeDefined();
|
expect(sharedWorkflow.workflow).toBeDefined();
|
||||||
|
@ -234,15 +229,15 @@ test('DELETE /users/:id with transferId should perform transfer', async () => {
|
||||||
|
|
||||||
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
const sharedCredential = await Db.collections.SharedCredentials.findOneOrFail({
|
||||||
relations: ['credentials'],
|
relations: ['credentials'],
|
||||||
where: { user: owner },
|
where: { userId: owner.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(sharedCredential.credentials).toBeDefined();
|
expect(sharedCredential.credentials).toBeDefined();
|
||||||
expect(sharedCredential.credentials.id).toBe(savedCredential.id);
|
expect(sharedCredential.credentials.id).toBe(savedCredential.id);
|
||||||
|
|
||||||
const deletedUser = await Db.collections.User.findOne(userToDelete);
|
const deletedUser = await Db.collections.User.findOneBy({ id: userToDelete.id });
|
||||||
|
|
||||||
expect(deletedUser).toBeUndefined();
|
expect(deletedUser).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /resolve-signup-token should validate invite token', async () => {
|
test('GET /resolve-signup-token should validate invite token', async () => {
|
||||||
|
@ -342,7 +337,7 @@ test('POST /users/:id should fill out a user shell', async () => {
|
||||||
const authToken = utils.getAuthToken(response);
|
const authToken = utils.getAuthToken(response);
|
||||||
expect(authToken).toBeDefined();
|
expect(authToken).toBeDefined();
|
||||||
|
|
||||||
const member = await Db.collections.User.findOneOrFail(memberShell.id);
|
const member = await Db.collections.User.findOneByOrFail({ id: memberShell.id });
|
||||||
expect(member.firstName).toBe(memberData.firstName);
|
expect(member.firstName).toBe(memberData.firstName);
|
||||||
expect(member.lastName).toBe(memberData.lastName);
|
expect(member.lastName).toBe(memberData.lastName);
|
||||||
expect(member.password).not.toBe(memberData.password);
|
expect(member.password).not.toBe(memberData.password);
|
||||||
|
@ -487,7 +482,7 @@ test('POST /users should email invites and create user shells but ignore existin
|
||||||
expect(error).toBe('Email could not be sent');
|
expect(error).toBe('Email could not be sent');
|
||||||
}
|
}
|
||||||
|
|
||||||
const storedUser = await Db.collections.User.findOneOrFail(id);
|
const storedUser = await Db.collections.User.findOneByOrFail({ id });
|
||||||
const { firstName, lastName, personalizationAnswers, password, resetPasswordToken } =
|
const { firstName, lastName, personalizationAnswers, password, resetPasswordToken } =
|
||||||
storedUser;
|
storedUser;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ import { randomCredentialPayload } from './shared/random';
|
||||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
let globalMemberRole: Role;
|
let globalMemberRole: Role;
|
||||||
let credentialOwnerRole: Role;
|
let credentialOwnerRole: Role;
|
||||||
|
@ -29,8 +28,7 @@ beforeAll(async () => {
|
||||||
endpointGroups: ['workflows'],
|
endpointGroups: ['workflows'],
|
||||||
applyAuth: true,
|
applyAuth: true,
|
||||||
});
|
});
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||||
|
@ -53,11 +51,11 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User', 'Workflow', 'SharedWorkflow'], testDbName);
|
await testDb.truncate(['User', 'Workflow', 'SharedWorkflow']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Router should switch dynamically', async () => {
|
test('Router should switch dynamically', async () => {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import type { IPinData } from 'n8n-workflow';
|
||||||
import { makeWorkflow, MOCK_PINDATA } from './shared/utils';
|
import { makeWorkflow, MOCK_PINDATA } from './shared/utils';
|
||||||
|
|
||||||
let app: express.Application;
|
let app: express.Application;
|
||||||
let testDbName = '';
|
|
||||||
let globalOwnerRole: Role;
|
let globalOwnerRole: Role;
|
||||||
|
|
||||||
// mock whether sharing is enabled or not
|
// mock whether sharing is enabled or not
|
||||||
|
@ -20,8 +19,7 @@ beforeAll(async () => {
|
||||||
endpointGroups: ['workflows'],
|
endpointGroups: ['workflows'],
|
||||||
applyAuth: true,
|
applyAuth: true,
|
||||||
});
|
});
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
|
|
||||||
|
@ -30,11 +28,11 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['User', 'Workflow', 'SharedWorkflow'], testDbName);
|
await testDb.truncate(['User', 'Workflow', 'SharedWorkflow']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('POST /workflows should store pin data for node in workflow', async () => {
|
test('POST /workflows should store pin data for node in workflow', async () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'tsconfig-paths/register';
|
import 'tsconfig-paths/register';
|
||||||
import { createConnection } from 'typeorm';
|
import { DataSource as Connection } from 'typeorm';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { getBootstrapDBOptions } from './integration/shared/testDb';
|
import { getBootstrapDBOptions } from './integration/shared/testDb';
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@ export default async () => {
|
||||||
const dbType = config.getEnv('database.type').replace(/db$/, '');
|
const dbType = config.getEnv('database.type').replace(/db$/, '');
|
||||||
if (dbType !== 'postgres' && dbType !== 'mysql') return;
|
if (dbType !== 'postgres' && dbType !== 'mysql') return;
|
||||||
|
|
||||||
const connection = await createConnection(getBootstrapDBOptions(dbType));
|
const connection = new Connection(getBootstrapDBOptions(dbType));
|
||||||
|
await connection.initialize();
|
||||||
|
|
||||||
const query =
|
const query =
|
||||||
dbType === 'postgres' ? 'SELECT datname as "Database" FROM pg_database' : 'SHOW DATABASES';
|
dbType === 'postgres' ? 'SELECT datname as "Database" FROM pg_database' : 'SHOW DATABASES';
|
||||||
|
@ -20,5 +21,5 @@ export default async () => {
|
||||||
|
|
||||||
const promises = databases.map((dbName) => connection.query(`DROP DATABASE ${dbName};`));
|
const promises = databases.map((dbName) => connection.query(`DROP DATABASE ${dbName};`));
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
await connection.close();
|
await connection.destroy();
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,15 +25,13 @@ import type { SaveCredentialFunction } from '../integration/shared/types';
|
||||||
import { User } from '@/databases/entities/User';
|
import { User } from '@/databases/entities/User';
|
||||||
import { SharedWorkflow } from '@/databases/entities/SharedWorkflow';
|
import { SharedWorkflow } from '@/databases/entities/SharedWorkflow';
|
||||||
|
|
||||||
let testDbName = '';
|
|
||||||
let mockNodeTypes: INodeTypes;
|
let mockNodeTypes: INodeTypes;
|
||||||
let credentialOwnerRole: Role;
|
let credentialOwnerRole: Role;
|
||||||
let workflowOwnerRole: Role;
|
let workflowOwnerRole: Role;
|
||||||
let saveCredential: SaveCredentialFunction;
|
let saveCredential: SaveCredentialFunction;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const initResult = await testDb.init();
|
await testDb.init();
|
||||||
testDbName = initResult.testDbName;
|
|
||||||
|
|
||||||
mockNodeTypes = MockNodeTypes({
|
mockNodeTypes = MockNodeTypes({
|
||||||
loaded: {
|
loaded: {
|
||||||
|
@ -51,12 +49,12 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['SharedWorkflow', 'SharedCredentials'], testDbName);
|
await testDb.truncate(['SharedWorkflow', 'SharedCredentials']);
|
||||||
await testDb.truncate(['User', 'Workflow', 'Credentials'], testDbName);
|
await testDb.truncate(['User', 'Workflow', 'Credentials']);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await testDb.terminate(testDbName);
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('PermissionChecker.check()', () => {
|
describe('PermissionChecker.check()', () => {
|
||||||
|
|
|
@ -39,7 +39,7 @@ describe('Telemetry', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyTrack.mockClear();
|
spyTrack.mockClear();
|
||||||
telemetry = new Telemetry(instanceId, n8nVersion);
|
telemetry = new Telemetry(instanceId);
|
||||||
(telemetry as any).rudderStack = {
|
(telemetry as any).rudderStack = {
|
||||||
flush: () => {},
|
flush: () => {},
|
||||||
identify: () => {},
|
identify: () => {},
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { INode, IWorkflowCredentials } from 'n8n-workflow';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
import { WorkflowCredentials } from '@/WorkflowCredentials';
|
import { WorkflowCredentials } from '@/WorkflowCredentials';
|
||||||
|
|
||||||
// Define a function used to mock the findOne function
|
// Define a function used to mock the findOneBy function
|
||||||
async function mockFind({
|
async function mockFind({
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
|
@ -33,7 +33,7 @@ jest.mock('@/Db', () => {
|
||||||
return {
|
return {
|
||||||
collections: {
|
collections: {
|
||||||
Credentials: {
|
Credentials: {
|
||||||
findOne: jest.fn(mockFind),
|
findOneBy: jest.fn(mockFind),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -54,7 +54,7 @@ describe('WorkflowCredentials', () => {
|
||||||
`Credentials with name "${credentials.name}" for type "test" miss an ID.`,
|
`Credentials with name "${credentials.name}" for type "test" miss an ID.`,
|
||||||
);
|
);
|
||||||
expect(WorkflowCredentials([noIdNode])).rejects.toEqual(expectedError);
|
expect(WorkflowCredentials([noIdNode])).rejects.toEqual(expectedError);
|
||||||
expect(mocked(Db.collections.Credentials.findOne)).toHaveBeenCalledTimes(0);
|
expect(mocked(Db.collections.Credentials.findOneBy)).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should return an error if credentials cannot be found in the DB', () => {
|
test('Should return an error if credentials cannot be found in the DB', () => {
|
||||||
|
@ -63,7 +63,7 @@ describe('WorkflowCredentials', () => {
|
||||||
`Could not find credentials for type "test" with ID "${credentials.id}".`,
|
`Could not find credentials for type "test" with ID "${credentials.id}".`,
|
||||||
);
|
);
|
||||||
expect(WorkflowCredentials([notFoundNode])).rejects.toEqual(expectedError);
|
expect(WorkflowCredentials([notFoundNode])).rejects.toEqual(expectedError);
|
||||||
expect(mocked(Db.collections.Credentials.findOne)).toHaveBeenCalledTimes(1);
|
expect(mocked(Db.collections.Credentials.findOneBy)).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should ignore duplicates', async () => {
|
test('Should ignore duplicates', async () => {
|
||||||
|
|
|
@ -184,7 +184,7 @@ importers:
|
||||||
lodash.uniqby: ^4.7.0
|
lodash.uniqby: ^4.7.0
|
||||||
lodash.unset: ^4.5.2
|
lodash.unset: ^4.5.2
|
||||||
luxon: ^3.1.0
|
luxon: ^3.1.0
|
||||||
mysql2: ~2.3.0
|
mysql2: ~2.3.3
|
||||||
n8n-core: ~0.151.0
|
n8n-core: ~0.151.0
|
||||||
n8n-editor-ui: ~0.177.0
|
n8n-editor-ui: ~0.177.0
|
||||||
n8n-nodes-base: ~0.209.0
|
n8n-nodes-base: ~0.209.0
|
||||||
|
@ -199,7 +199,7 @@ importers:
|
||||||
passport: ^0.6.0
|
passport: ^0.6.0
|
||||||
passport-cookie: ^1.0.9
|
passport-cookie: ^1.0.9
|
||||||
passport-jwt: ^4.0.0
|
passport-jwt: ^4.0.0
|
||||||
pg: ^8.3.0
|
pg: ^8.8.0
|
||||||
picocolors: ^1.0.0
|
picocolors: ^1.0.0
|
||||||
posthog-node: ^2.2.2
|
posthog-node: ^2.2.2
|
||||||
prom-client: ^13.1.0
|
prom-client: ^13.1.0
|
||||||
|
@ -209,7 +209,7 @@ importers:
|
||||||
semver: ^7.3.8
|
semver: ^7.3.8
|
||||||
shelljs: ^0.8.5
|
shelljs: ^0.8.5
|
||||||
source-map-support: ^0.5.21
|
source-map-support: ^0.5.21
|
||||||
sqlite3: ^5.1.2
|
sqlite3: ^5.1.4
|
||||||
sse-channel: ^4.0.0
|
sse-channel: ^4.0.0
|
||||||
supertest: ^6.2.2
|
supertest: ^6.2.2
|
||||||
swagger-ui-express: ^4.3.0
|
swagger-ui-express: ^4.3.0
|
||||||
|
@ -218,7 +218,7 @@ importers:
|
||||||
tsc-alias: ^1.7.0
|
tsc-alias: ^1.7.0
|
||||||
tsconfig-paths: ^3.14.1
|
tsconfig-paths: ^3.14.1
|
||||||
tslib: 1.14.1
|
tslib: 1.14.1
|
||||||
typeorm: 0.2.45
|
typeorm: 0.3.11
|
||||||
uuid: ^8.3.2
|
uuid: ^8.3.2
|
||||||
validator: 13.7.0
|
validator: 13.7.0
|
||||||
winston: ^3.3.3
|
winston: ^3.3.3
|
||||||
|
@ -299,12 +299,12 @@ importers:
|
||||||
semver: 7.3.8
|
semver: 7.3.8
|
||||||
shelljs: 0.8.5
|
shelljs: 0.8.5
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
sqlite3: 5.1.2
|
sqlite3: 5.1.4
|
||||||
sse-channel: 4.0.0
|
sse-channel: 4.0.0
|
||||||
swagger-ui-express: 4.5.0_express@4.18.2
|
swagger-ui-express: 4.5.0_express@4.18.2
|
||||||
syslog-client: 1.1.1
|
syslog-client: 1.1.1
|
||||||
tslib: 1.14.1
|
tslib: 1.14.1
|
||||||
typeorm: 0.2.45_b2izk5tn6tm5xb65gvog337urq
|
typeorm: 0.3.11_a77gzgdqnod3rkvxniiwirlqsi
|
||||||
uuid: 8.3.2
|
uuid: 8.3.2
|
||||||
validator: 13.7.0
|
validator: 13.7.0
|
||||||
winston: 3.8.2
|
winston: 3.8.2
|
||||||
|
@ -3481,6 +3481,7 @@ packages:
|
||||||
/@npmcli/move-file/1.1.2:
|
/@npmcli/move-file/1.1.2:
|
||||||
resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==}
|
resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
deprecated: This functionality has been moved to @npmcli/fs
|
||||||
dependencies:
|
dependencies:
|
||||||
mkdirp: 1.0.4
|
mkdirp: 1.0.4
|
||||||
rimraf: 3.0.2
|
rimraf: 3.0.2
|
||||||
|
@ -6407,10 +6408,6 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@types/zen-observable/0.8.3:
|
|
||||||
resolution: {integrity: sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@typescript-eslint/eslint-plugin/5.45.0_psz44bhp76u27vmulntnlx26h4:
|
/@typescript-eslint/eslint-plugin/5.45.0_psz44bhp76u27vmulntnlx26h4:
|
||||||
resolution: {integrity: sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==}
|
resolution: {integrity: sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
@ -7378,7 +7375,6 @@ packages:
|
||||||
|
|
||||||
/arg/4.1.3:
|
/arg/4.1.3:
|
||||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/argparse/1.0.10:
|
/argparse/1.0.10:
|
||||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||||
|
@ -9707,7 +9703,6 @@ packages:
|
||||||
|
|
||||||
/create-require/1.1.1:
|
/create-require/1.1.1:
|
||||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/crelt/1.0.5:
|
/crelt/1.0.5:
|
||||||
resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==}
|
resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==}
|
||||||
|
@ -9998,7 +9993,6 @@ packages:
|
||||||
/date-fns/2.29.3:
|
/date-fns/2.29.3:
|
||||||
resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
|
resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
|
||||||
engines: {node: '>=0.11'}
|
engines: {node: '>=0.11'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/date-now/0.1.4:
|
/date-now/0.1.4:
|
||||||
resolution: {integrity: sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==}
|
resolution: {integrity: sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==}
|
||||||
|
@ -10307,7 +10301,6 @@ packages:
|
||||||
/diff/4.0.2:
|
/diff/4.0.2:
|
||||||
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
|
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
|
||||||
engines: {node: '>=0.3.1'}
|
engines: {node: '>=0.3.1'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/diffie-hellman/5.0.3:
|
/diffie-hellman/5.0.3:
|
||||||
resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==}
|
resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==}
|
||||||
|
@ -10460,7 +10453,6 @@ packages:
|
||||||
/dotenv/16.0.3:
|
/dotenv/16.0.3:
|
||||||
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
|
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/dotenv/8.6.0:
|
/dotenv/8.6.0:
|
||||||
resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
|
resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
|
||||||
|
@ -19609,8 +19601,8 @@ packages:
|
||||||
resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
|
resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/sqlite3/5.1.2:
|
/sqlite3/5.1.4:
|
||||||
resolution: {integrity: sha512-D0Reg6pRWAFXFUnZKsszCI67tthFD8fGPewRddDCX6w4cYwz3MbvuwRICbL+YQjBAh9zbw+lJ/V9oC8nG5j6eg==}
|
resolution: {integrity: sha512-i0UlWAzPlzX3B5XP2cYuhWQJsTtlMD6obOa1PgeEQ4DHEXUuyJkgv50I3isqZAP5oFc2T8OFvakmDh2W6I+YpA==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
node-gyp:
|
node-gyp:
|
||||||
|
@ -20732,7 +20724,6 @@ packages:
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
typescript: 4.8.4
|
typescript: 4.8.4
|
||||||
yn: 3.1.1
|
yn: 3.1.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/ts-pnp/1.2.0_typescript@4.8.4:
|
/ts-pnp/1.2.0_typescript@4.8.4:
|
||||||
resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
|
resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
|
||||||
|
@ -20935,26 +20926,31 @@ packages:
|
||||||
/typedarray/0.0.6:
|
/typedarray/0.0.6:
|
||||||
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||||
|
|
||||||
/typeorm/0.2.45_b2izk5tn6tm5xb65gvog337urq:
|
/typeorm/0.3.11_a77gzgdqnod3rkvxniiwirlqsi:
|
||||||
resolution: {integrity: sha512-c0rCO8VMJ3ER7JQ73xfk0zDnVv0WDjpsP6Q1m6CVKul7DB9iVdWLRjPzc8v2eaeBuomsbZ2+gTaYr8k1gm3bYA==}
|
resolution: {integrity: sha512-pzdOyWbVuz/z8Ww6gqvBW4nylsM0KLdUCDExr2gR20/x1khGSVxQkjNV/3YqliG90jrWzrknYbYscpk8yxFJVg==}
|
||||||
|
engines: {node: '>= 12.9.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@sap/hana-client': ^2.11.14
|
'@google-cloud/spanner': ^5.18.0
|
||||||
better-sqlite3: ^7.1.2
|
'@sap/hana-client': ^2.12.25
|
||||||
|
better-sqlite3: ^7.1.2 || ^8.0.0
|
||||||
hdb-pool: ^0.1.6
|
hdb-pool: ^0.1.6
|
||||||
ioredis: ^4.28.3
|
ioredis: ^5.0.4
|
||||||
mongodb: ^3.6.0
|
mongodb: ^3.6.0
|
||||||
mssql: ^6.3.1
|
mssql: ^7.3.0
|
||||||
mysql2: ^2.2.5
|
mysql2: ^2.2.5
|
||||||
oracledb: ^5.1.0
|
oracledb: ^5.1.0
|
||||||
pg: ^8.5.1
|
pg: ^8.5.1
|
||||||
pg-native: ^3.0.0
|
pg-native: ^3.0.0
|
||||||
pg-query-stream: ^4.0.0
|
pg-query-stream: ^4.0.0
|
||||||
redis: ^3.1.1
|
redis: ^3.1.1 || ^4.0.0
|
||||||
sql.js: ^1.4.0
|
sql.js: ^1.4.0
|
||||||
sqlite3: ^5.0.2
|
sqlite3: ^5.0.3
|
||||||
|
ts-node: ^10.7.0
|
||||||
typeorm-aurora-data-api-driver: ^2.0.0
|
typeorm-aurora-data-api-driver: ^2.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
|
'@google-cloud/spanner':
|
||||||
|
optional: true
|
||||||
'@sap/hana-client':
|
'@sap/hana-client':
|
||||||
optional: true
|
optional: true
|
||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
|
@ -20983,6 +20979,8 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
sqlite3:
|
sqlite3:
|
||||||
optional: true
|
optional: true
|
||||||
|
ts-node:
|
||||||
|
optional: true
|
||||||
typeorm-aurora-data-api-driver:
|
typeorm-aurora-data-api-driver:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -20991,8 +20989,9 @@ packages:
|
||||||
buffer: 6.0.3
|
buffer: 6.0.3
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cli-highlight: 2.1.11
|
cli-highlight: 2.1.11
|
||||||
|
date-fns: 2.29.3
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
dotenv: 8.6.0
|
dotenv: 16.0.3
|
||||||
glob: 7.2.3
|
glob: 7.2.3
|
||||||
ioredis: 5.2.4
|
ioredis: 5.2.4
|
||||||
js-yaml: 4.1.0
|
js-yaml: 4.1.0
|
||||||
|
@ -21001,12 +21000,12 @@ packages:
|
||||||
pg: 8.8.0
|
pg: 8.8.0
|
||||||
reflect-metadata: 0.1.13
|
reflect-metadata: 0.1.13
|
||||||
sha.js: 2.4.11
|
sha.js: 2.4.11
|
||||||
sqlite3: 5.1.2
|
sqlite3: 5.1.4
|
||||||
|
ts-node: 9.1.1_typescript@4.8.4
|
||||||
tslib: 2.4.0
|
tslib: 2.4.0
|
||||||
uuid: 8.3.2
|
uuid: 8.3.2
|
||||||
xml2js: 0.4.23
|
xml2js: 0.4.23
|
||||||
yargs: 17.6.0
|
yargs: 17.6.0
|
||||||
zen-observable-ts: 1.1.0
|
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -22715,7 +22714,6 @@ packages:
|
||||||
/yn/3.1.1:
|
/yn/3.1.1:
|
||||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/yocto-queue/0.1.0:
|
/yocto-queue/0.1.0:
|
||||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
|
@ -22747,17 +22745,6 @@ packages:
|
||||||
commander: 2.20.3
|
commander: 2.20.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/zen-observable-ts/1.1.0:
|
|
||||||
resolution: {integrity: sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==}
|
|
||||||
dependencies:
|
|
||||||
'@types/zen-observable': 0.8.3
|
|
||||||
zen-observable: 0.8.15
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/zen-observable/0.8.15:
|
|
||||||
resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/zwitch/1.0.5:
|
/zwitch/1.0.5:
|
||||||
resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==}
|
resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
Loading…
Reference in a new issue