Skip to content
5 changes: 4 additions & 1 deletion packages/cli/src/Interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { Application } from 'express';
import type {
ExecutionError,
Expand Down Expand Up @@ -85,6 +84,7 @@ export interface ICredentialsOverwrite {
[key: string]: ICredentialDataDecryptedObject;
}

/* eslint-disable @typescript-eslint/naming-convention */
export interface IDatabaseCollections {
AuthIdentity: AuthIdentityRepository;
AuthProviderSyncHistory: AuthProviderSyncHistoryRepository;
Expand All @@ -106,6 +106,7 @@ export interface IDatabaseCollections {
WorkflowStatistics: WorkflowStatisticsRepository;
WorkflowTagMapping: WorkflowTagMappingRepository;
}
/* eslint-enable @typescript-eslint/naming-convention */

// ----------------------------------
// tags
Expand Down Expand Up @@ -890,3 +891,5 @@ export interface N8nApp {
externalHooks: IExternalHooksClass;
activeWorkflowRunner: ActiveWorkflowRunner;
}

export type UserSettings = Pick<User, 'id' | 'settings'>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { UserSettings } from '@/Interfaces';

export class AddUserActivatedProperty1681134145996 implements MigrationInterface {
name = 'AddUserActivatedProperty1681134145996';

async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);

const tablePrefix = getTablePrefix();

const activatedUsers: UserSettings[] = await queryRunner.query(
`SELECT DISTINCT sw.userId AS id,
JSON_SET(COALESCE(u.settings, '{}'), '$.userActivated', true) AS settings
FROM ${tablePrefix}workflow_statistics AS ws
JOIN ${tablePrefix}shared_workflow as sw
ON ws.workflowId = sw.workflowId
JOIN ${tablePrefix}role AS r
ON r.id = sw.roleId
JOIN ${tablePrefix}user AS u
ON u.id = sw.userId
WHERE ws.name = 'production_success'
AND r.name = 'owner'
AND r.scope = 'workflow'`,
);

const updatedUsers = activatedUsers.map((user) =>
queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = '${JSON.stringify(user.settings)}' WHERE id = '${
user.id
}' `,
),
);

await Promise.all(updatedUsers);

if (!activatedUsers.length) {
await queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = JSON_SET(COALESCE(settings, '{}'), '$.userActivated', false)`,
);
} else {
const activatedUserIds = activatedUsers.map((user) => `'${user.id}'`).join(',');

await queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = JSON_SET(COALESCE(settings, '{}'), '$.userActivated', false) WHERE id NOT IN (${activatedUserIds})`,
);
}

logMigrationEnd(this.name);
}

async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = JSON_REMOVE(settings, '$.userActivated')`,
);
await queryRunner.query(`UPDATE ${tablePrefix}user SET settings = NULL WHERE settings = '{}'`);
}
}
2 changes: 2 additions & 0 deletions packages/cli/src/databases/migrations/mysqldb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { MigrateExecutionStatus1676996103000 } from './1676996103000-MigrateExec
import { UpdateRunningExecutionStatus1677236788851 } from './1677236788851-UpdateRunningExecutionStatus';
import { CreateExecutionMetadataTable1679416281779 } from './1679416281779-CreateExecutionMetadataTable';
import { CreateVariables1677501636753 } from './1677501636753-CreateVariables';
import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty';

export const mysqlMigrations = [
InitialMigration1588157391238,
Expand Down Expand Up @@ -76,4 +77,5 @@ export const mysqlMigrations = [
UpdateRunningExecutionStatus1677236788851,
CreateExecutionMetadataTable1679416281779,
CreateVariables1677501636753,
AddUserActivatedProperty1681134145996,
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { UserSettings } from '@/Interfaces';

export class AddUserActivatedProperty1681134145996 implements MigrationInterface {
name = 'AddUserActivatedProperty1681134145996';

async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);

const tablePrefix = getTablePrefix();

const activatedUsers: UserSettings[] = await queryRunner.query(
`SELECT DISTINCT sw."userId" AS id,
JSONB_SET(COALESCE(u.settings::jsonb, '{}'), '{userActivated}', 'true', true) as settings
FROM ${tablePrefix}workflow_statistics ws
JOIN ${tablePrefix}shared_workflow sw
ON ws."workflowId" = sw."workflowId"
JOIN ${tablePrefix}role r
ON r.id = sw."roleId"
JOIN "${tablePrefix}user" u
ON u.id = sw."userId"
WHERE ws.name = 'production_success'
AND r.name = 'owner'
AND r.scope = 'workflow'`,
);

const updatedUsers = activatedUsers.map((user) =>
queryRunner.query(
`UPDATE "${tablePrefix}user" SET settings = '${JSON.stringify(
user.settings,
)}' WHERE id = '${user.id}' `,
),
);

await Promise.all(updatedUsers);

if (!activatedUsers.length) {
await queryRunner.query(
`UPDATE "${tablePrefix}user" SET settings = JSONB_SET(COALESCE(settings::jsonb, '{}'), '{userActivated}', 'false', true)`,
);
} else {
const activatedUserIds = activatedUsers.map((user) => `'${user.id}'`).join(',');

await queryRunner.query(
`UPDATE "${tablePrefix}user" SET settings = JSONB_SET(COALESCE(settings::jsonb, '{}'), '{userActivated}', 'false', true) WHERE id NOT IN (${activatedUserIds})`,
);
}

logMigrationEnd(this.name);
}

async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query(
`UPDATE "${tablePrefix}user" SET settings = settings::jsonb - 'userActivated'`,
);
await queryRunner.query(
`UPDATE "${tablePrefix}user" SET settings = NULL WHERE settings::jsonb = '{}'::jsonb`,
);
}
}
2 changes: 2 additions & 0 deletions packages/cli/src/databases/migrations/postgresdb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { MigrateExecutionStatus1676996103000 } from './1676996103000-MigrateExec
import { UpdateRunningExecutionStatus1677236854063 } from './1677236854063-UpdateRunningExecutionStatus';
import { CreateExecutionMetadataTable1679416281778 } from './1679416281778-CreateExecutionMetadataTable';
import { CreateVariables1677501636754 } from './1677501636754-CreateVariables';
import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty';

export const postgresMigrations = [
InitialMigration1587669153312,
Expand Down Expand Up @@ -72,4 +73,5 @@ export const postgresMigrations = [
UpdateRunningExecutionStatus1677236854063,
CreateExecutionMetadataTable1679416281778,
CreateVariables1677501636754,
AddUserActivatedProperty1681134145996,
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { UserSettings } from '@/Interfaces';

export class AddUserActivatedProperty1681134145996 implements MigrationInterface {
name = 'AddUserActivatedProperty1681134145996';

async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);

const tablePrefix = getTablePrefix();

const activatedUsers: UserSettings[] = await queryRunner.query(
`SELECT DISTINCT sw.userId AS id,
JSON_SET(COALESCE(u.settings, '{}'), '$.userActivated', JSON('true')) AS settings
FROM ${tablePrefix}workflow_statistics AS ws
JOIN ${tablePrefix}shared_workflow AS sw
ON ws.workflowId = sw.workflowId
JOIN ${tablePrefix}role AS r
ON r.id = sw.roleId
JOIN ${tablePrefix}user AS u
ON u.id = sw.userId
WHERE ws.name = 'production_success'
AND r.name = 'owner'
AND r.scope = "workflow"`,
);

const updatedUsers = activatedUsers.map((user) =>
queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = '${user.settings}' WHERE id = '${user.id}' `,
),
);

await Promise.all(updatedUsers);

if (!activatedUsers.length) {
await queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = JSON_SET(COALESCE(settings, '{}'), '$.userActivated', JSON('false'))`,
);
} else {
const activatedUserIds = activatedUsers.map((user) => `'${user.id}'`).join(',');
await queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = JSON_SET(COALESCE(settings, '{}'), '$.userActivated', JSON('false')) WHERE id NOT IN (${activatedUserIds})`,
);
}

logMigrationEnd(this.name);
}

async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = JSON_REMOVE(settings, '$.userActivated')`,
);
await queryRunner.query(`UPDATE ${tablePrefix}user SET settings = NULL WHERE settings = '{}'`);
}
}
2 changes: 2 additions & 0 deletions packages/cli/src/databases/migrations/sqlite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { MigrateExecutionStatus1676996103000 } from './1676996103000-MigrateExec
import { UpdateRunningExecutionStatus1677237073720 } from './1677237073720-UpdateRunningExecutionStatus';
import { CreateExecutionMetadataTable1679416281777 } from './1679416281777-CreateExecutionMetadataTable';
import { CreateVariables1677501636752 } from './1677501636752-CreateVariables';
import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty';

const sqliteMigrations = [
InitialMigration1588102412422,
Expand Down Expand Up @@ -70,6 +71,7 @@ const sqliteMigrations = [
UpdateRunningExecutionStatus1677237073720,
CreateVariables1677501636752,
CreateExecutionMetadataTable1679416281777,
AddUserActivatedProperty1681134145996,
];

export { sqliteMigrations };