mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
refactor(core): Move settings repository to @n8n/db (#15310)
This commit is contained in:
committed by
GitHub
parent
8cc5a5da3b
commit
41179f71c1
@@ -19,6 +19,7 @@ export { LicenseMetricsRepository } from './license-metrics.repository';
|
||||
export { ProjectRelationRepository } from './project-relation.repository';
|
||||
export { ProjectRepository } from './project.repository';
|
||||
export { ProcessedDataRepository } from './processed-data.repository';
|
||||
export { SettingsRepository } from './settings.repository';
|
||||
export { TagRepository } from './tag.repository';
|
||||
export { TestCaseExecutionRepository } from './test-case-execution.repository.ee';
|
||||
export { TestDefinitionRepository } from './test-definition.repository.ee';
|
||||
|
||||
15
packages/@n8n/db/src/repositories/settings.repository.ts
Normal file
15
packages/@n8n/db/src/repositories/settings.repository.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Service } from '@n8n/di';
|
||||
import { DataSource, Repository } from '@n8n/typeorm';
|
||||
|
||||
import { Settings } from '../entities';
|
||||
|
||||
@Service()
|
||||
export class SettingsRepository extends Repository<Settings> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(Settings, dataSource.manager);
|
||||
}
|
||||
|
||||
async findByKey(key: string): Promise<Settings | null> {
|
||||
return await this.findOneBy({ key });
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
import type { GlobalConfig } from '@n8n/config';
|
||||
import type { CredentialsRepository } from '@n8n/db';
|
||||
import type { CredentialsRepository, SettingsRepository } from '@n8n/db';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { ErrorReporter, Logger } from 'n8n-core';
|
||||
import type { IWorkflowBase } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import type { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import type { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
AuthProviderSyncHistoryRepository,
|
||||
ProjectRelationRepository,
|
||||
ProjectRepository,
|
||||
SettingsRepository,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
} from '@n8n/db';
|
||||
@@ -14,7 +15,6 @@ import { UserError } from 'n8n-workflow';
|
||||
|
||||
import { UM_FIX_INSTRUCTION } from '@/constants';
|
||||
import { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/ldap.ee/constants';
|
||||
import { WorkflowService } from '@/workflows/workflow.service';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
import { LICENSE_FEATURES } from '@n8n/constants';
|
||||
import { ExecutionRepository } from '@n8n/db';
|
||||
import { ExecutionRepository, SettingsRepository } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { Flags } from '@oclif/core';
|
||||
import glob from 'fast-glob';
|
||||
@@ -16,7 +16,6 @@ import { ActiveExecutions } from '@/active-executions';
|
||||
import { ActiveWorkflowManager } from '@/active-workflow-manager';
|
||||
import config from '@/config';
|
||||
import { EDITOR_UI_DIST_DIR } from '@/constants';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error';
|
||||
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
|
||||
import { EventService } from '@/events/event.service';
|
||||
|
||||
@@ -3,12 +3,12 @@ import {
|
||||
User,
|
||||
CredentialsRepository,
|
||||
ProjectRepository,
|
||||
SettingsRepository,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
} from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
|
||||
import { BaseCommand } from '../base-command';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { DismissBannerRequestDto, OwnerSetupRequestDto } from '@n8n/api-types';
|
||||
import type { User } from '@n8n/db';
|
||||
import type { PublicUser } from '@n8n/db';
|
||||
import type { PublicUser, SettingsRepository } from '@n8n/db';
|
||||
import type { Response } from 'express';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { Logger } from 'n8n-core';
|
||||
@@ -8,11 +8,11 @@ import type { Logger } from 'n8n-core';
|
||||
import type { AuthService } from '@/auth/auth.service';
|
||||
import config from '@/config';
|
||||
import { OwnerController } from '@/controllers/owner.controller';
|
||||
import type { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import type { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import type { EventService } from '@/events/event.service';
|
||||
import type { AuthenticatedRequest } from '@/requests';
|
||||
import type { BannerService } from '@/services/banner.service';
|
||||
import type { PasswordUtility } from '@/services/password.utility';
|
||||
import type { UserService } from '@/services/user.service';
|
||||
|
||||
@@ -23,6 +23,7 @@ describe('OwnerController', () => {
|
||||
const logger = mock<Logger>();
|
||||
const eventService = mock<EventService>();
|
||||
const authService = mock<AuthService>();
|
||||
const bannerService = mock<BannerService>();
|
||||
const userService = mock<UserService>();
|
||||
const userRepository = mock<UserRepository>();
|
||||
const settingsRepository = mock<SettingsRepository>();
|
||||
@@ -33,6 +34,7 @@ describe('OwnerController', () => {
|
||||
eventService,
|
||||
settingsRepository,
|
||||
authService,
|
||||
bannerService,
|
||||
userService,
|
||||
passwordUtility,
|
||||
mock(),
|
||||
@@ -100,7 +102,7 @@ describe('OwnerController', () => {
|
||||
|
||||
const result = await controller.dismissBanner(mock(), mock(), payload);
|
||||
|
||||
expect(settingsRepository.dismissBanner).not.toHaveBeenCalled();
|
||||
expect(bannerService.dismissBanner).not.toHaveBeenCalled();
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -109,7 +111,7 @@ describe('OwnerController', () => {
|
||||
|
||||
await controller.dismissBanner(mock(), mock(), payload);
|
||||
|
||||
expect(settingsRepository.dismissBanner).toHaveBeenCalledWith({ bannerName: 'TRIAL' });
|
||||
expect(bannerService.dismissBanner).toHaveBeenCalledWith('TRIAL');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PushMessage } from '@n8n/api-types';
|
||||
import type { BooleanLicenseFeature, NumericLicenseFeature } from '@n8n/constants';
|
||||
import { LICENSE_FEATURES, LICENSE_QUOTAS, UNLIMITED_LICENSE_QUOTA } from '@n8n/constants';
|
||||
import { AuthUserRepository } from '@n8n/db';
|
||||
import { AuthUserRepository, SettingsRepository } from '@n8n/db';
|
||||
import { Patch, Post, RestController } from '@n8n/decorators';
|
||||
import { Container } from '@n8n/di';
|
||||
import { Request } from 'express';
|
||||
@@ -11,7 +11,6 @@ import { v4 as uuid } from 'uuid';
|
||||
import { ActiveWorkflowManager } from '@/active-workflow-manager';
|
||||
import config from '@/config';
|
||||
import { inE2ETests } from '@/constants';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
|
||||
import type { FeatureReturnType } from '@/license';
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { DismissBannerRequestDto, OwnerSetupRequestDto } from '@n8n/api-types';
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import { Body, GlobalScope, Post, RestController } from '@n8n/decorators';
|
||||
import { Response } from 'express';
|
||||
import { Logger } from 'n8n-core';
|
||||
|
||||
import { AuthService } from '@/auth/auth.service';
|
||||
import config from '@/config';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { validateEntity } from '@/generic-helpers';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { AuthenticatedRequest } from '@/requests';
|
||||
import { BannerService } from '@/services/banner.service';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
import { UserService } from '@/services/user.service';
|
||||
|
||||
@@ -22,6 +23,7 @@ export class OwnerController {
|
||||
private readonly eventService: EventService,
|
||||
private readonly settingsRepository: SettingsRepository,
|
||||
private readonly authService: AuthService,
|
||||
private readonly bannerService: BannerService,
|
||||
private readonly userService: UserService,
|
||||
private readonly passwordUtility: PasswordUtility,
|
||||
private readonly postHog: PostHogClient,
|
||||
@@ -83,6 +85,6 @@ export class OwnerController {
|
||||
) {
|
||||
const bannerName = payload.banner;
|
||||
if (!bannerName) return;
|
||||
return await this.settingsRepository.dismissBanner({ bannerName });
|
||||
await this.bannerService.dismissBanner(bannerName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import { Settings } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import { DataSource, Repository } from '@n8n/typeorm';
|
||||
import { ErrorReporter } from 'n8n-core';
|
||||
|
||||
import config from '@/config';
|
||||
import { EXTERNAL_SECRETS_DB_KEY } from '@/external-secrets.ee/constants';
|
||||
|
||||
@Service()
|
||||
export class SettingsRepository extends Repository<Settings> {
|
||||
constructor(
|
||||
dataSource: DataSource,
|
||||
private readonly errorReporter: ErrorReporter,
|
||||
) {
|
||||
super(Settings, dataSource.manager);
|
||||
}
|
||||
|
||||
async getEncryptedSecretsProviderSettings(): Promise<string | null> {
|
||||
return (await this.findByKey(EXTERNAL_SECRETS_DB_KEY))?.value ?? null;
|
||||
}
|
||||
|
||||
async findByKey(key: string): Promise<Settings | null> {
|
||||
return await this.findOneBy({ key });
|
||||
}
|
||||
|
||||
async saveEncryptedSecretsProviderSettings(data: string): Promise<void> {
|
||||
await this.upsert(
|
||||
{
|
||||
key: EXTERNAL_SECRETS_DB_KEY,
|
||||
value: data,
|
||||
loadOnStartup: false,
|
||||
},
|
||||
['key'],
|
||||
);
|
||||
}
|
||||
|
||||
async dismissBanner({ bannerName }: { bannerName: string }): Promise<{ success: boolean }> {
|
||||
const key = 'ui.banners.dismissed';
|
||||
const dismissedBannersSetting = await this.findOneBy({ key });
|
||||
try {
|
||||
let value: string;
|
||||
if (dismissedBannersSetting) {
|
||||
const dismissedBanners = JSON.parse(dismissedBannersSetting.value) as string[];
|
||||
const updatedValue = [...new Set([...dismissedBanners, bannerName].sort())];
|
||||
value = JSON.stringify(updatedValue);
|
||||
await this.update({ key }, { value, loadOnStartup: true });
|
||||
} else {
|
||||
value = JSON.stringify([bannerName]);
|
||||
await this.save({ key, value, loadOnStartup: true }, { transaction: false });
|
||||
}
|
||||
config.set(key, value);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
this.errorReporter.error(error);
|
||||
}
|
||||
return { success: false };
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import type { ValidationError } from 'class-validator';
|
||||
import { validate } from 'class-validator';
|
||||
@@ -7,8 +8,6 @@ import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
import { writeFile, chmod, readFile } from 'node:fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
|
||||
import {
|
||||
SOURCE_CONTROL_SSH_FOLDER,
|
||||
SOURCE_CONTROL_GIT_FOLDER,
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { FrontendSettings, UserUpdateRequestDto } from '@n8n/api-types';
|
||||
import type { ClientOAuth2Options } from '@n8n/client-oauth2';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import type { TagEntity, User, ICredentialsDb, PublicUser } from '@n8n/db';
|
||||
import { CredentialsRepository } from '@n8n/db';
|
||||
import { CredentialsRepository, SettingsRepository } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import { ErrorReporter, Logger } from 'n8n-core';
|
||||
import type { IRun, IWorkflowBase, Workflow, WorkflowExecuteMode } from 'n8n-workflow';
|
||||
@@ -11,7 +11,6 @@ import type clientOAuth1 from 'oauth-1.0a';
|
||||
|
||||
import type { AbstractServer } from '@/abstract-server';
|
||||
import type { Config } from '@/config';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { Settings, SettingsRepository } from '@n8n/db';
|
||||
import { captor, mock } from 'jest-mock-extended';
|
||||
|
||||
import type { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import type { License } from '@/license';
|
||||
import {
|
||||
AnotherDummyProvider,
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from '@test/external-secrets/utils';
|
||||
import { mockCipher, mockLogger } from '@test/mocking';
|
||||
|
||||
import { EXTERNAL_SECRETS_DB_KEY } from '../constants';
|
||||
import { ExternalSecretsManager } from '../external-secrets-manager.ee';
|
||||
import type { ExternalSecretsSettings } from '../types';
|
||||
|
||||
@@ -44,9 +45,9 @@ describe('External Secrets Manager', () => {
|
||||
});
|
||||
|
||||
license.isExternalSecretsEnabled.mockReturnValue(true);
|
||||
settingsRepo.getEncryptedSecretsProviderSettings.mockImplementation(async () =>
|
||||
JSON.stringify(settings),
|
||||
);
|
||||
settingsRepo.findByKey
|
||||
.calledWith(EXTERNAL_SECRETS_DB_KEY)
|
||||
.mockImplementation(async () => mock<Settings>({ value: JSON.stringify(settings) }));
|
||||
|
||||
manager = new ExternalSecretsManager(
|
||||
mockLogger(),
|
||||
@@ -251,7 +252,7 @@ describe('External Secrets Manager', () => {
|
||||
|
||||
describe('setProviderSettings', () => {
|
||||
test('should save provider settings', async () => {
|
||||
const settingsSpy = jest.spyOn(settingsRepo, 'saveEncryptedSecretsProviderSettings');
|
||||
const settingsSpy = jest.spyOn(settingsRepo, 'upsert');
|
||||
|
||||
await manager.init();
|
||||
|
||||
@@ -259,7 +260,9 @@ describe('External Secrets Manager', () => {
|
||||
test: 'value',
|
||||
});
|
||||
|
||||
expect(JSON.parse(settingsSpy.mock.calls[0][0])).toEqual(
|
||||
const settingsCaptor = captor<Settings>();
|
||||
expect(settingsSpy).toHaveBeenCalledWith(settingsCaptor, ['key']);
|
||||
expect(JSON.parse(settingsCaptor.value.value)).toEqual(
|
||||
expect.objectContaining({
|
||||
dummy: {
|
||||
connected: true,
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import { OnShutdown } from '@n8n/decorators';
|
||||
import { Service } from '@n8n/di';
|
||||
import { Cipher, Logger } from 'n8n-core';
|
||||
import { jsonParse, type IDataObject, ensureError, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { License } from '@/license';
|
||||
import { Publisher } from '@/scaling/pubsub/publisher.service';
|
||||
|
||||
import { EXTERNAL_SECRETS_INITIAL_BACKOFF, EXTERNAL_SECRETS_MAX_BACKOFF } from './constants';
|
||||
import {
|
||||
EXTERNAL_SECRETS_DB_KEY,
|
||||
EXTERNAL_SECRETS_INITIAL_BACKOFF,
|
||||
EXTERNAL_SECRETS_MAX_BACKOFF,
|
||||
} from './constants';
|
||||
import { ExternalSecretsProviders } from './external-secrets-providers.ee';
|
||||
import { ExternalSecretsConfig } from './external-secrets.config';
|
||||
import type { ExternalSecretsSettings, SecretsProvider, SecretsProviderSettings } from './types';
|
||||
@@ -89,8 +93,9 @@ export class ExternalSecretsManager {
|
||||
void this.publisher.publishCommand({ command: 'reload-external-secrets-providers' });
|
||||
}
|
||||
|
||||
private async getDecryptedSettings(): Promise<ExternalSecretsSettings | null> {
|
||||
const encryptedSettings = await this.settingsRepo.getEncryptedSecretsProviderSettings();
|
||||
async getDecryptedSettings(): Promise<ExternalSecretsSettings | null> {
|
||||
const encryptedSettings =
|
||||
(await this.settingsRepo.findByKey(EXTERNAL_SECRETS_DB_KEY))?.value ?? null;
|
||||
if (encryptedSettings === null) {
|
||||
return null;
|
||||
}
|
||||
@@ -324,7 +329,14 @@ export class ExternalSecretsManager {
|
||||
|
||||
async saveAndSetSettings(settings: ExternalSecretsSettings) {
|
||||
const encryptedSettings = this.encryptSecretsSettings(settings);
|
||||
await this.settingsRepo.saveEncryptedSecretsProviderSettings(encryptedSettings);
|
||||
await this.settingsRepo.upsert(
|
||||
{
|
||||
key: EXTERNAL_SECRETS_DB_KEY,
|
||||
value: encryptedSettings,
|
||||
loadOnStartup: false,
|
||||
},
|
||||
['key'],
|
||||
);
|
||||
}
|
||||
|
||||
async testProviderSettings(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Settings } from '@n8n/db';
|
||||
import { AuthIdentityRepository } from '@n8n/db';
|
||||
import { AuthIdentityRepository, SettingsRepository } from '@n8n/db';
|
||||
import { QueryFailedError } from '@n8n/typeorm';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { Client } from 'ldapts';
|
||||
@@ -7,7 +7,6 @@ import type { Cipher } from 'n8n-core';
|
||||
import { randomString } from 'n8n-workflow';
|
||||
|
||||
import config from '@/config';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import type { EventService } from '@/events/event.service';
|
||||
import { mockInstance, mockLogger } from '@test/mocking';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import type { User, RunningMode, SyncStatus } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
|
||||
@@ -9,7 +10,6 @@ import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
import type { ConnectionOptions } from 'tls';
|
||||
|
||||
import config from '@/config';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { EventService } from '@/events/event.service';
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type BooleanLicenseFeature,
|
||||
type NumericLicenseFeature,
|
||||
} from '@n8n/constants';
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import { OnLeaderStepdown, OnLeaderTakeover, OnShutdown } from '@n8n/decorators';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
import type { TEntitlement, TFeatures, TLicenseBlock } from '@n8n_io/license-sdk';
|
||||
@@ -14,7 +15,6 @@ import { LicenseManager } from '@n8n_io/license-sdk';
|
||||
import { InstanceSettings, Logger } from 'n8n-core';
|
||||
|
||||
import config from '@/config';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { LicenseMetricsService } from '@/metrics/license-metrics.service';
|
||||
|
||||
import { N8N_VERSION, SETTINGS_LICENSE_CERT_KEY, Time } from './constants';
|
||||
|
||||
59
packages/cli/src/services/__tests__/banner.service.test.ts
Normal file
59
packages/cli/src/services/__tests__/banner.service.test.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import type { BannerName } from '@n8n/api-types';
|
||||
import type { SettingsRepository } from '@n8n/db';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { ErrorReporter } from 'n8n-core';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { BannerService } from '@/services/banner.service';
|
||||
|
||||
describe('BannerService', () => {
|
||||
const settingsRepo = mock<SettingsRepository>();
|
||||
const errorReporter = mock<ErrorReporter>();
|
||||
const bannerService = new BannerService(settingsRepo, errorReporter);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('dismissBanner', () => {
|
||||
const key = 'ui.banners.dismissed';
|
||||
const bannerName: BannerName = 'TRIAL';
|
||||
|
||||
it('should save the banner name to settings if no banners are dismissed yet', async () => {
|
||||
settingsRepo.findOneBy.mockResolvedValue(null);
|
||||
|
||||
await bannerService.dismissBanner(bannerName);
|
||||
|
||||
expect(settingsRepo.save).toHaveBeenCalledWith(
|
||||
{ key, value: JSON.stringify([bannerName]), loadOnStartup: true },
|
||||
{ transaction: false },
|
||||
);
|
||||
});
|
||||
|
||||
it('should update settings with the new banner name if banners are already dismissed', async () => {
|
||||
const dismissedBanners = ['TRIAL_OVER'];
|
||||
settingsRepo.findOneBy.mockResolvedValue({
|
||||
key,
|
||||
value: JSON.stringify(dismissedBanners),
|
||||
loadOnStartup: false,
|
||||
});
|
||||
|
||||
await bannerService.dismissBanner(bannerName);
|
||||
|
||||
expect(settingsRepo.update).toHaveBeenCalledWith(
|
||||
{ key },
|
||||
{ value: JSON.stringify([bannerName, 'TRIAL_OVER']), loadOnStartup: true },
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle errors when saving settings', async () => {
|
||||
const error = new UnexpectedError('Test error');
|
||||
settingsRepo.findOneBy.mockResolvedValue(null);
|
||||
settingsRepo.save.mockRejectedValue(error);
|
||||
|
||||
await bannerService.dismissBanner(bannerName);
|
||||
|
||||
expect(errorReporter.error).toHaveBeenCalledWith(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AuthUser } from '@n8n/db';
|
||||
import type { AuthUser, SettingsRepository } from '@n8n/db';
|
||||
import type { AuthUserRepository } from '@n8n/db';
|
||||
import type { CredentialsRepository } from '@n8n/db';
|
||||
import RudderStack from '@rudderstack/rudder-sdk-node';
|
||||
@@ -6,7 +6,6 @@ import type { Response } from 'express';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
|
||||
import type { AuthService } from '@/auth/auth.service';
|
||||
import type { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import type { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import type { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import type { Invitation } from '@/interfaces';
|
||||
|
||||
37
packages/cli/src/services/banner.service.ts
Normal file
37
packages/cli/src/services/banner.service.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { BannerName } from '@n8n/api-types';
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import { ErrorReporter } from 'n8n-core';
|
||||
|
||||
import config from '@/config';
|
||||
|
||||
@Service()
|
||||
export class BannerService {
|
||||
constructor(
|
||||
private readonly settingsRepository: SettingsRepository,
|
||||
private readonly errorReporter: ErrorReporter,
|
||||
) {}
|
||||
|
||||
async dismissBanner(bannerName: BannerName) {
|
||||
const key = 'ui.banners.dismissed';
|
||||
const dismissedBannersSetting = await this.settingsRepository.findOneBy({ key });
|
||||
try {
|
||||
let value: string;
|
||||
if (dismissedBannersSetting) {
|
||||
const dismissedBanners = JSON.parse(dismissedBannersSetting.value) as string[];
|
||||
const updatedValue = [...new Set([...dismissedBanners, bannerName].sort())];
|
||||
value = JSON.stringify(updatedValue);
|
||||
await this.settingsRepository.update({ key }, { value, loadOnStartup: true });
|
||||
} else {
|
||||
value = JSON.stringify([bannerName]);
|
||||
await this.settingsRepository.save(
|
||||
{ key, value, loadOnStartup: true },
|
||||
{ transaction: false },
|
||||
);
|
||||
}
|
||||
config.set(key, value);
|
||||
} catch (error) {
|
||||
this.errorReporter.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Settings, CredentialsEntity, User, WorkflowEntity, AuthUser } from '@n8n/db';
|
||||
import { AuthUserRepository, CredentialsRepository } from '@n8n/db';
|
||||
import { AuthUserRepository, CredentialsRepository, SettingsRepository } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
|
||||
import type { FindManyOptions, FindOneOptions, FindOptionsWhere } from '@n8n/typeorm';
|
||||
@@ -8,7 +8,6 @@ import RudderStack, { type constructorOptions } from '@rudderstack/rudder-sdk-no
|
||||
import type { NextFunction, Response } from 'express';
|
||||
|
||||
import { AuthService } from '@/auth/auth.service';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import type { Invitation } from '@/interfaces';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import type express from 'express';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { IdentityProviderInstance, ServiceProviderInstance } from 'samlify';
|
||||
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import * as samlHelpers from '@/sso.ee/saml/saml-helpers';
|
||||
import { SamlService } from '@/sso.ee/saml/saml.service.ee';
|
||||
import { mockInstance } from '@test/mocking';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { SamlPreferences } from '@n8n/api-types';
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import type { Settings, User } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import axios from 'axios';
|
||||
@@ -9,7 +10,6 @@ import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
import type { IdentityProviderInstance, ServiceProviderInstance } from 'samlify';
|
||||
import type { BindingContext, PostBindingContext } from 'samlify/types/src/entity';
|
||||
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { AuthError } from '@/errors/response-errors/auth.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { AuthProviderType } from '@n8n/db';
|
||||
import { SettingsRepository, type AuthProviderType } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
|
||||
import config from '@/config';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
|
||||
/**
|
||||
* Only one authentication method can be active at a time. This function sets
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { CredentialsEntity } from '@n8n/db';
|
||||
import { CredentialsEntity, SettingsRepository } from '@n8n/db';
|
||||
import { CredentialsRepository } from '@n8n/db';
|
||||
import { SharedCredentialsRepository } from '@n8n/db';
|
||||
import { SharedWorkflowRepository } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
|
||||
import { Reset } from '@/commands/user-management/reset';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { Cipher } from 'n8n-core';
|
||||
import { jsonParse, type IDataObject } from 'n8n-workflow';
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
|
||||
import config from '@/config';
|
||||
import { CREDENTIAL_BLANKING_VALUE } from '@/constants';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import type { EventService } from '@/events/event.service';
|
||||
import { ExternalSecretsManager } from '@/external-secrets.ee/external-secrets-manager.ee';
|
||||
import { ExternalSecretsProviders } from '@/external-secrets.ee/external-secrets-providers.ee';
|
||||
@@ -37,17 +37,11 @@ const testServer = setupTestServer({
|
||||
const connectedDate = '2023-08-01T12:32:29.000Z';
|
||||
|
||||
async function setExternalSecretsSettings(settings: ExternalSecretsSettings) {
|
||||
return await Container.get(SettingsRepository).saveEncryptedSecretsProviderSettings(
|
||||
Container.get(Cipher).encrypt(settings),
|
||||
);
|
||||
await Container.get(ExternalSecretsManager).saveAndSetSettings(settings);
|
||||
}
|
||||
|
||||
async function getExternalSecretsSettings(): Promise<ExternalSecretsSettings | null> {
|
||||
const encSettings = await Container.get(SettingsRepository).getEncryptedSecretsProviderSettings();
|
||||
if (encSettings === null) {
|
||||
return null;
|
||||
}
|
||||
return await jsonParse(Container.get(Cipher).decrypt(encSettings));
|
||||
return await Container.get(ExternalSecretsManager).getDecryptedSettings();
|
||||
}
|
||||
|
||||
const eventService = mock<EventService>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SettingsRepository } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { jsonParse } from 'n8n-workflow';
|
||||
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/ldap.ee/constants';
|
||||
import type { LdapConfig } from '@/ldap.ee/types';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkflowEntity } from '@n8n/db';
|
||||
import { SettingsRepository, WorkflowEntity } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import {
|
||||
@@ -21,7 +21,6 @@ import { v4 as uuid } from 'uuid';
|
||||
|
||||
import config from '@/config';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { ExecutionService } from '@/executions/execution.service';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { Push } from '@/push';
|
||||
|
||||
Reference in New Issue
Block a user