1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-12-23 01:27:14 +02:00

Refactor extension settings

This commit is contained in:
Patrik J. Braun 2023-12-24 08:59:36 +01:00
parent 649e7a9a7e
commit 90b620de00
7 changed files with 139 additions and 50 deletions

View File

@ -1,9 +1,9 @@
import {IConfigClass} from 'typeconfig/common';
import {ConfigProperty, IConfigClass} from 'typeconfig/common';
import {Config, PrivateConfigClass} from '../../../common/config/private/Config';
import {ConfigClassBuilder} from 'typeconfig/node';
import {IExtensionConfig} from './IExtension';
import {Utils} from '../../../common/Utils';
import {ObjectManagers} from '../ObjectManagers';
import {ServerExtensionsEntryConfig} from '../../../common/config/private/subconfigs/ServerExtensionsConfig';
/**
* Wraps to original config and makes sure all extension related config is loaded
@ -29,11 +29,29 @@ export class ExtensionConfigWrapper {
export class ExtensionConfig<C> implements IExtensionConfig<C> {
public template: new() => C;
constructor(private readonly extensionId: string) {
constructor(private readonly extensionFolder: string) {
}
private findConfig(config: PrivateConfigClass) {
let c = (config.Extensions.extensions || []).find(e => e.path === this.extensionFolder);
if (!c) {
c = new ServerExtensionsEntryConfig(this.extensionFolder);
config.Extensions.extensions.push(c);
}
if (!config.Extensions.extensions2[this.extensionFolder]) {
Object.defineProperty(config.Extensions.extensions2, this.extensionFolder,
ConfigProperty({type: ServerExtensionsEntryConfig})(config.Extensions.extensions2, this.extensionFolder));
// config.Extensions.extensions2[this.extensionFolder] = c as any;
config.Extensions.extensions2[this.extensionFolder] = c;
}
return config.Extensions.extensions2[this.extensionFolder];
}
public getConfig(): C {
return Config.Extensions.configs[this.extensionId] as C;
return this.findConfig(Config).configs as C;
}
public setTemplate(template: new() => C): void {
@ -45,8 +63,15 @@ export class ExtensionConfig<C> implements IExtensionConfig<C> {
if (!this.template) {
return;
}
const conf = ConfigClassBuilder.attachPrivateInterface(new this.template());
conf.__loadJSONObject(Utils.clone(config.Extensions.configs[this.extensionId] || {}));
config.Extensions.configs[this.extensionId] = conf;
const confTemplate = ConfigClassBuilder.attachPrivateInterface(new this.template());
const extConf = this.findConfig(config);
// confTemplate.__loadJSONObject(Utils.clone(extConf.configs || {}));
//extConf.configs = confTemplate;
Object.defineProperty(config.Extensions.extensions2[this.extensionFolder].configs, this.extensionFolder,
ConfigProperty({type: this.template})(config.Extensions.extensions2[this.extensionFolder], this.extensionFolder));
console.log(config.Extensions.extensions2[this.extensionFolder].configs);
config.Extensions.extensions2[this.extensionFolder].configs = confTemplate as any;
console.log(config.Extensions.extensions2[this.extensionFolder].configs);
}
}

View File

@ -12,6 +12,7 @@ import {SQLConnection} from '../database/SQLConnection';
import {ExtensionObject} from './ExtensionObject';
import {ExtensionDecoratorObject} from './ExtensionDecorator';
import * as util from 'util';
import {ServerExtensionsEntryConfig} from '../../../common/config/private/subconfigs/ServerExtensionsConfig';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const exec = util.promisify(require('child_process').exec);
@ -70,13 +71,23 @@ export class ExtensionManager implements IObjectManager {
return;
}
Config.Extensions.list = fs
const extList = fs
.readdirSync(ProjectPath.ExtensionFolder)
.filter((f): boolean =>
fs.statSync(path.join(ProjectPath.ExtensionFolder, f)).isDirectory()
);
Config.Extensions.list.sort();
Logger.debug(LOG_TAG, 'Extensions found ', JSON.stringify(Config.Extensions.list));
extList.sort();
// delete not existing extensions
Config.Extensions.extensions = Config.Extensions.extensions.filter(ec => extList.indexOf(ec.path) !== -1);
// Add new extensions
const ePaths = Config.Extensions.extensions.map(ec => ec.path);
extList.filter(ep => ePaths.indexOf(ep) === -1).forEach(ep =>
Config.Extensions.extensions.push(new ServerExtensionsEntryConfig(ep)));
Logger.debug(LOG_TAG, 'Extensions found ', JSON.stringify(Config.Extensions.extensions.map(ec => ec.path)));
}
private createUniqueExtensionObject(name: string, folder: string): IExtensionObject<unknown> {
@ -95,8 +106,8 @@ export class ExtensionManager implements IObjectManager {
private async initExtensions() {
for (let i = 0; i < Config.Extensions.list.length; ++i) {
const extFolder = Config.Extensions.list[i];
for (let i = 0; i < Config.Extensions.extensions.length; ++i) {
const extFolder = Config.Extensions.extensions[i].path;
let extName = extFolder;
const extPath = path.join(ProjectPath.ExtensionFolder, extFolder);
const serverExtPath = path.join(extPath, 'server.js');
@ -122,7 +133,7 @@ export class ExtensionManager implements IObjectManager {
const ext = require(serverExtPath);
if (typeof ext?.init === 'function') {
Logger.debug(LOG_TAG, 'Running init on extension: ' + extFolder);
await ext?.init(this.createUniqueExtensionObject(extName, extPath));
await ext?.init(this.createUniqueExtensionObject(extName, extFolder));
}
}
if (Config.Extensions.cleanUpUnusedTables) {

View File

@ -26,7 +26,7 @@ export class ExtensionObject<C> implements IExtensionObject<C> {
events: IExtensionEvents) {
const logger = createLoggerWrapper(`[Extension][${extensionId}]`);
this._app = new ExtensionApp();
this.config = new ExtensionConfig<C>(extensionId);
this.config = new ExtensionConfig<C>(folder);
this.db = new ExtensionDB(logger);
this.paths = ProjectPath;
this.Logger = logger;

View File

@ -11,7 +11,6 @@ import {
} from '../../entities/job/JobScheduleDTO';
import {
ClientConfig,
ClientExtensionsConfig,
ClientGPXCompressingConfig,
ClientMediaConfig,
ClientMetaFileConfig,
@ -30,7 +29,8 @@ import {SearchQueryDTO, SearchQueryTypes, TextSearch,} from '../../entities/Sear
import {SortByTypes} from '../../entities/SortingMethods';
import {UserRoles} from '../../entities/UserDTO';
import {MediaPickDTO} from '../../entities/MediaPickDTO';
import {MessagingConfig} from './MessagingConfig';
import {ServerExtensionsConfig} from './subconfigs/ServerExtensionsConfig';
import {MessagingConfig} from './subconfigs/MessagingConfig';
declare let $localize: (s: TemplateStringsArray) => string;
@ -966,35 +966,6 @@ export class ServerServiceConfig extends ClientServiceConfig {
}
@SubConfigClass<TAGS>({softReadonly: true})
export class ServerExtensionsConfig extends ClientExtensionsConfig {
@ConfigProperty({
tags: {
name: $localize`Extension folder`,
priority: ConfigPriority.underTheHood,
dockerSensitive: true
},
description: $localize`Folder where the app stores the extensions. Extensions live in their sub-folders.`,
})
folder: string = 'extensions';
@ConfigProperty({volatile: true})
list: string[] = [];
@ConfigProperty({type: 'object'})
configs: Record<string, unknown> = {};
@ConfigProperty({
tags: {
name: $localize`Clean up unused tables`,
priority: ConfigPriority.underTheHood,
},
description: $localize`Automatically removes all tables from the DB that are not used anymore.`,
})
cleanUpUnusedTables: boolean = true;
}
@SubConfigClass({softReadonly: true})
export class ServerEnvironmentConfig {
@ConfigProperty({volatile: true})

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-inferrable-types */
import {ConfigProperty, SubConfigClass} from 'typeconfig/common';
import {ConfigPriority, TAGS} from '../public/ClientConfig';
import {ConfigPriority, TAGS} from '../../public/ClientConfig';
declare let $localize: (s: TemplateStringsArray) => string;

View File

@ -0,0 +1,78 @@
/* eslint-disable @typescript-eslint/no-inferrable-types */
import {ConfigProperty, SubConfigClass} from 'typeconfig/common';
import {ClientExtensionsConfig, ConfigPriority, TAGS} from '../../public/ClientConfig';
import {IConfigClassPrivate} from '../../../../../node_modules/typeconfig/src/decorators/class/IConfigClass';
@SubConfigClass<TAGS>({softReadonly: true})
export class ServerExtensionsEntryConfig {
constructor(path: string = '') {
this.path = path;
}
@ConfigProperty({
tags: {
name: $localize`Enabled`,
priority: ConfigPriority.advanced,
},
})
enabled: boolean = true;
@ConfigProperty({
tags: {
name: $localize`Extension folder`,
priority: ConfigPriority.underTheHood,
},
description: $localize`Folder where the app stores all extensions. Individual extensions live in their own sub-folders.`,
})
path: string = '';
@ConfigProperty({
tags: {
name: $localize`Config`,
priority: ConfigPriority.advanced
}
})
configs: IConfigClassPrivate<unknown>;
}
@SubConfigClass<TAGS>({softReadonly: true})
export class ServerExtensionsConfig extends ClientExtensionsConfig {
@ConfigProperty({
tags: {
name: $localize`Extension folder`,
priority: ConfigPriority.underTheHood,
dockerSensitive: true
},
description: $localize`Folder where the app stores all extensions. Individual extensions live in their own sub-folders.`,
})
folder: string = 'extensions';
@ConfigProperty({
arrayType: ServerExtensionsEntryConfig,
tags: {
name: $localize`Installed extensions`,
priority: ConfigPriority.advanced
}
})
extensions: ServerExtensionsEntryConfig[] = [];
@ConfigProperty({
tags: {
name: $localize`Installed extensions2`,
priority: ConfigPriority.advanced
}
})
extensions2: Record<string, ServerExtensionsEntryConfig> = {};
@ConfigProperty({
tags: {
name: $localize`Clean up unused tables`,
priority: ConfigPriority.underTheHood,
},
description: $localize`Automatically removes all tables from the DB that are not used anymore.`,
})
cleanUpUnusedTables: boolean = true;
}

View File

@ -19,6 +19,7 @@ import {enumToTranslatedArray} from '../../../EnumTranslations';
import {BsModalService} from 'ngx-bootstrap/modal';
import {CustomSettingsEntries} from '../CustomSettingsEntries';
import {GroupByTypes, SortByTypes} from '../../../../../../common/entities/SortingMethods';
import { ServerExtensionsEntryConfig } from '../../../../../../common/config/private/subconfigs/ServerExtensionsConfig';
interface IState {
shouldHide(): boolean;
@ -232,6 +233,8 @@ export class SettingsEntryComponent
this.arrayType = 'MapPathGroupThemeConfig';
} else if (this.state.arrayType === UserConfig) {
this.arrayType = 'UserConfig';
} else if (this.state.arrayType === ServerExtensionsEntryConfig) {
this.arrayType = 'ServerExtensionsEntryConfig';
} else if (this.state.arrayType === JobScheduleConfig) {
this.arrayType = 'JobScheduleConfig';
} else {
@ -253,6 +256,7 @@ export class SettingsEntryComponent
this.arrayType !== 'MapLayers' &&
this.arrayType !== 'NavigationLinkConfig' &&
this.arrayType !== 'MapPathGroupConfig' &&
this.arrayType !== 'ServerExtensionsEntryConfig' &&
this.arrayType !== 'MapPathGroupThemeConfig' &&
this.arrayType !== 'JobScheduleConfig' &&
this.arrayType !== 'UserConfig') {