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

refactoring config file

fixing task setting issue
This commit is contained in:
Patrik J. Braun 2019-12-10 16:17:35 +01:00
parent 8029793ffb
commit 4208fe7f1f
9 changed files with 185 additions and 284 deletions

View File

@ -4,7 +4,7 @@ import {Utils} from '../../common/Utils';
import {Message} from '../../common/entities/Message'; import {Message} from '../../common/entities/Message';
import {SharingDTO} from '../../common/entities/SharingDTO'; import {SharingDTO} from '../../common/entities/SharingDTO';
import {Config} from '../../common/config/private/Config'; import {Config} from '../../common/config/private/Config';
import {PrivateConfigClass} from '../../common/config/private/PrivateConfigClass'; import {ConfigClass} from '../../common/config/private/PrivateConfigClass';
import {UserRoles} from '../../common/entities/UserDTO'; import {UserRoles} from '../../common/entities/UserDTO';
import {NotificationManager} from '../model/NotifocationManager'; import {NotificationManager} from '../model/NotifocationManager';
import {Logger} from '../Logger'; import {Logger} from '../Logger';
@ -55,7 +55,7 @@ export class RenderingMWs {
public static renderConfig(req: Request, res: Response, next: NextFunction) { public static renderConfig(req: Request, res: Response, next: NextFunction) {
const message = new Message<PrivateConfigClass>(null, Config.original()); const message = new Message<ConfigClass>(null, Config.original());
res.json(message); res.json(message);
} }

View File

@ -10,7 +10,7 @@ import {ClientConfig} from '../../../common/config/public/ConfigClass';
import {BasicConfigDTO} from '../../../common/entities/settings/BasicConfigDTO'; import {BasicConfigDTO} from '../../../common/entities/settings/BasicConfigDTO';
import {OtherConfigDTO} from '../../../common/entities/settings/OtherConfigDTO'; import {OtherConfigDTO} from '../../../common/entities/settings/OtherConfigDTO';
import {ProjectPath} from '../../ProjectPath'; import {ProjectPath} from '../../ProjectPath';
import {PrivateConfigClass} from '../../../common/config/private/PrivateConfigClass'; import {ConfigClass} from '../../../common/config/private/PrivateConfigClass';
import {ServerConfig} from '../../../common/config/private/IPrivateConfig'; import {ServerConfig} from '../../../common/config/private/IPrivateConfig';
const LOG_TAG = '[SettingsMWs]'; const LOG_TAG = '[SettingsMWs]';
@ -352,7 +352,7 @@ export class SettingsMWs {
Config.Client.Other.NavBar.showItemCount = settings.Client.NavBar.showItemCount; Config.Client.Other.NavBar.showItemCount = settings.Client.NavBar.showItemCount;
// only updating explicitly set config (not saving config set by the diagnostics) // only updating explicitly set config (not saving config set by the diagnostics)
const original: PrivateConfigClass = Config.original(); const original: ConfigClass = Config.original();
original.Client.Other.enableCache = settings.Client.enableCache; original.Client.Other.enableCache = settings.Client.enableCache;
original.Client.Other.captionFirstNaming = settings.Client.captionFirstNaming; original.Client.Other.captionFirstNaming = settings.Client.captionFirstNaming;
original.Client.Other.enableOnScrollRendering = settings.Client.enableOnScrollRendering; original.Client.Other.enableOnScrollRendering = settings.Client.enableOnScrollRendering;

View File

@ -1,5 +1,5 @@
import {PrivateConfigClass} from './PrivateConfigClass'; import {ConfigClass} from './ConfigClass';
export let Config = new PrivateConfigClass(); export let Config = new ConfigClass();
Config.load(); Config.load();

View File

@ -0,0 +1,72 @@
import {IPrivateConfig, ServerConfig} from './IPrivateConfig';
import * as path from 'path';
import {ConfigLoader} from 'typeconfig';
import {Utils} from '../../Utils';
import {UserRoles} from '../../entities/UserDTO';
import {PrivateConfigDefaultsClass} from './PrivateConfigDefaultsClass';
/**
* This configuration will be only at backend
*/
export class ConfigClass extends PrivateConfigDefaultsClass implements IPrivateConfig {
private static readonly CONFIG_PATH = path.join(__dirname, './../../../../config.json');
private ConfigLoader: any;
public setDatabaseType(type: ServerConfig.DatabaseType) {
this.Server.Database.type = type;
if (type === ServerConfig.DatabaseType.memory) {
this.Client.Search.enabled = false;
this.Client.Sharing.enabled = false;
}
}
public load() {
this.addComment();
ConfigLoader.loadBackendConfig(this, ConfigClass.CONFIG_PATH,
[['PORT', 'Server-port'],
['MYSQL_HOST', 'Server-Database-mysql-host'],
['MYSQL_PASSWORD', 'Server-Database-mysql-password'],
['MYSQL_USERNAME', 'Server-Database-mysql-username'],
['MYSQL_DATABASE', 'Server-Database-mysql-database']]);
this.removeComment();
if (Utils.enumToArray(UserRoles).map(r => r.key).indexOf(this.Client.unAuthenticatedUserRole) === -1) {
throw new Error('Unknown user role for Client.unAuthenticatedUserRole, found: ' + this.Client.unAuthenticatedUserRole);
}
if (Utils.enumToArray(ServerConfig.LogLevel).map(r => r.key).indexOf(this.Server.Log.level) === -1) {
throw new Error('Unknown Server.log.level, found: ' + this.Server.Log.level);
}
if (Utils.enumToArray(ServerConfig.SQLLogLevel).map(r => r.key).indexOf(this.Server.Log.sqlLevel) === -1) {
throw new Error('Unknown Server.log.level, found: ' + this.Server.Log.sqlLevel);
}
}
public save() {
try {
this.addComment();
ConfigLoader.saveConfigFile(ConfigClass.CONFIG_PATH, this);
this.removeComment();
} catch (e) {
throw new Error('Error during saving config: ' + e.toString());
}
}
public original(): ConfigClass {
const cfg = new ConfigClass();
cfg.load();
return cfg;
}
private addComment() {
(<any>this)['__NOTE'] = 'NOTE: this config is not intended for manual edit, ' +
'use the app UI instead as it has comments and descriptions.';
}
private removeComment() {
delete (<any>this)['__NOTE'];
}
}

View File

@ -1,144 +0,0 @@
import {PublicConfigClass} from '../public/ConfigClass';
import {IPrivateConfig, ServerConfig} from './IPrivateConfig';
import * as path from 'path';
import {ConfigLoader} from 'typeconfig';
import {Utils} from '../../Utils';
import {UserRoles} from '../../entities/UserDTO';
import {TaskTriggerType} from '../../entities/task/TaskScheduleDTO';
import {DefaultsTasks} from '../../entities/task/TaskDTO';
/**
* This configuration will be only at backend
*/
export class PrivateConfigClass extends PublicConfigClass implements IPrivateConfig {
private static readonly CONFIG_PATH = path.join(__dirname, './../../../../config.json');
public Server: ServerConfig.Config = {
port: 80,
host: '0.0.0.0',
imagesFolder: 'demo/images',
Thumbnail: {
folder: 'demo/TEMP',
processingLibrary: ServerConfig.ThumbnailProcessingLib.sharp,
qualityPriority: true,
personFaceMargin: 0.6
},
Log: {
level: ServerConfig.LogLevel.info,
sqlLevel: ServerConfig.SQLLogLevel.error
},
sessionTimeout: 1000 * 60 * 60 * 24 * 7,
photoMetadataSize: 512 * 1024,
Database: {
type: ServerConfig.DatabaseType.sqlite,
mysql: {
host: '',
username: '',
password: '',
database: ''
},
sqlite: {
storage: 'sqlite.db'
}
},
Sharing: {
updateTimeout: 1000 * 60 * 5
},
Threading: {
enable: true,
thumbnailThreads: 0
},
Indexing: {
folderPreviewSize: 2,
cachedFolderTimeout: 1000 * 60 * 60,
reIndexingSensitivity: ServerConfig.ReIndexingSensitivity.low,
excludeFolderList: [],
excludeFileList: []
},
Duplicates: {
listingLimit: 1000
},
Tasks: {
scheduled: [{
taskName: DefaultsTasks[DefaultsTasks['Database Reset']],
config: {},
trigger: {type: TaskTriggerType.never}
}, {
taskName: DefaultsTasks[DefaultsTasks.Indexing],
config: {},
trigger: {type: TaskTriggerType.never}
}, {
taskName: DefaultsTasks[DefaultsTasks['Video Converting']],
config: {},
trigger: {type: TaskTriggerType.never}
}]
},
Video: {
transcoding: {
bitRate: 5 * 1024 * 1024,
codec: 'libx264',
format: 'mp4',
fps: 25,
resolution: 720
}
}
};
private ConfigLoader: any;
public setDatabaseType(type: ServerConfig.DatabaseType) {
this.Server.Database.type = type;
if (type === ServerConfig.DatabaseType.memory) {
this.Client.Search.enabled = false;
this.Client.Sharing.enabled = false;
}
}
public load() {
this.addComment();
ConfigLoader.loadBackendConfig(this, PrivateConfigClass.CONFIG_PATH,
[['PORT', 'Server-port'],
['MYSQL_HOST', 'Server-Database-mysql-host'],
['MYSQL_PASSWORD', 'Server-Database-mysql-password'],
['MYSQL_USERNAME', 'Server-Database-mysql-username'],
['MYSQL_DATABASE', 'Server-Database-mysql-database']]);
this.removeComment();
if (Utils.enumToArray(UserRoles).map(r => r.key).indexOf(this.Client.unAuthenticatedUserRole) === -1) {
throw new Error('Unknown user role for Client.unAuthenticatedUserRole, found: ' + this.Client.unAuthenticatedUserRole);
}
if (Utils.enumToArray(ServerConfig.LogLevel).map(r => r.key).indexOf(this.Server.Log.level) === -1) {
throw new Error('Unknown Server.log.level, found: ' + this.Server.Log.level);
}
if (Utils.enumToArray(ServerConfig.SQLLogLevel).map(r => r.key).indexOf(this.Server.Log.sqlLevel) === -1) {
throw new Error('Unknown Server.log.level, found: ' + this.Server.Log.sqlLevel);
}
}
public save() {
try {
this.addComment();
ConfigLoader.saveConfigFile(PrivateConfigClass.CONFIG_PATH, this);
this.removeComment();
} catch (e) {
throw new Error('Error during saving config: ' + e.toString());
}
}
public original(): PrivateConfigClass {
const cfg = new PrivateConfigClass();
cfg.load();
return cfg;
}
private addComment() {
(<any>this)['__NOTE'] = 'NOTE: this config is not intended for manual edit, ' +
'use the app UI instead as it has comments and descriptions.';
}
private removeComment() {
delete (<any>this)['__NOTE'];
}
}

View File

@ -0,0 +1,83 @@
import {PublicConfigClass} from '../public/ConfigClass';
import {IPrivateConfig, ServerConfig} from './IPrivateConfig';
import {TaskTriggerType} from '../../entities/task/TaskScheduleDTO';
import {DefaultsTasks} from '../../entities/task/TaskDTO';
/**
* This configuration will be only at backend
*/
export class PrivateConfigDefaultsClass extends PublicConfigClass implements IPrivateConfig {
public Server: ServerConfig.Config = {
port: 80,
host: '0.0.0.0',
imagesFolder: 'demo/images',
Thumbnail: {
folder: 'demo/TEMP',
processingLibrary: ServerConfig.ThumbnailProcessingLib.sharp,
qualityPriority: true,
personFaceMargin: 0.6
},
Log: {
level: ServerConfig.LogLevel.info,
sqlLevel: ServerConfig.SQLLogLevel.error
},
sessionTimeout: 1000 * 60 * 60 * 24 * 7,
photoMetadataSize: 512 * 1024,
Database: {
type: ServerConfig.DatabaseType.sqlite,
mysql: {
host: '',
username: '',
password: '',
database: ''
},
sqlite: {
storage: 'sqlite.db'
}
},
Sharing: {
updateTimeout: 1000 * 60 * 5
},
Threading: {
enable: true,
thumbnailThreads: 0
},
Indexing: {
folderPreviewSize: 2,
cachedFolderTimeout: 1000 * 60 * 60,
reIndexingSensitivity: ServerConfig.ReIndexingSensitivity.low,
excludeFolderList: [],
excludeFileList: []
},
Duplicates: {
listingLimit: 1000
},
Tasks: {
scheduled: [{
taskName: DefaultsTasks[DefaultsTasks['Database Reset']],
config: {},
trigger: {type: TaskTriggerType.never}
}, {
taskName: DefaultsTasks[DefaultsTasks.Indexing],
config: {},
trigger: {type: TaskTriggerType.never}
}, {
taskName: DefaultsTasks[DefaultsTasks['Video Converting']],
config: {},
trigger: {type: TaskTriggerType.never}
}]
},
Video: {
transcoding: {
bitRate: 5 * 1024 * 1024,
codec: 'libx264',
format: 'mp4',
fps: 25,
resolution: 720
}
}
};
}

View File

@ -1,10 +1,8 @@
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {BehaviorSubject} from 'rxjs'; import {BehaviorSubject} from 'rxjs';
import {NetworkService} from '../../model/network/network.service'; import {NetworkService} from '../../model/network/network.service';
import {SortingMethods} from '../../../../common/entities/SortingMethods'; import {IPrivateConfig} from '../../../../common/config/private/IPrivateConfig';
import {UserRoles} from '../../../../common/entities/UserDTO'; import {PrivateConfigDefaultsClass} from '../../../../common/config/private/PrivateConfigDefaultsClass';
import {ClientConfig} from '../../../../common/config/public/ConfigClass';
import {IPrivateConfig, ServerConfig} from '../../../../common/config/private/IPrivateConfig';
@Injectable() @Injectable()
export class SettingsService { export class SettingsService {
@ -12,119 +10,7 @@ export class SettingsService {
private fetchingSettings = false; private fetchingSettings = false;
constructor(private _networkService: NetworkService) { constructor(private _networkService: NetworkService) {
this.settings = new BehaviorSubject<IPrivateConfig>({ this.settings = new BehaviorSubject<IPrivateConfig>(new PrivateConfigDefaultsClass());
Client: {
appVersion: '',
Search: {
enabled: true,
AutoComplete: {
enabled: true,
cacheTimeout: 1000 * 60 * 60,
maxItemsPerCategory: 5
},
instantSearchEnabled: true,
InstantSearchTimeout: 0,
searchCacheTimeout: 1000 * 60 * 60,
instantSearchCacheTimeout: 1000 * 60 * 60,
},
Thumbnail: {
concurrentThumbnailGenerations: null,
iconSize: 30,
personThumbnailSize: 200,
thumbnailSizes: []
},
Sharing: {
enabled: true,
passwordProtected: true
},
Map: {
enabled: true,
useImageMarkers: true,
mapProvider: ClientConfig.MapProviders.OpenStreetMap,
mapboxAccessToken: '',
customLayers: [{name: 'street', url: ''}]
},
RandomPhoto: {
enabled: true
},
Video: {
enabled: true
},
MetaFile: {
enabled: true
},
Other: {
captionFirstNaming: false,
enableCache: true,
enableOnScrollRendering: true,
enableOnScrollThumbnailPrioritising: true,
defaultPhotoSortingMethod: SortingMethods.ascDate,
NavBar: {
showItemCount: true
}
},
Faces: {
enabled: true,
keywordsToPersons: true,
writeAccessMinRole: UserRoles.Admin
},
urlBase: '',
publicUrl: '',
applicationTitle: '',
authenticationRequired: true,
unAuthenticatedUserRole: UserRoles.Admin,
languages: []
},
Server: {
Database: {
type: ServerConfig.DatabaseType.memory
},
Log: {
level: ServerConfig.LogLevel.info,
sqlLevel: ServerConfig.SQLLogLevel.error
},
Sharing: {
updateTimeout: 2000
},
imagesFolder: '',
port: 80,
host: '0.0.0.0',
Thumbnail: {
personFaceMargin: 0.1,
folder: '',
qualityPriority: true,
processingLibrary: ServerConfig.ThumbnailProcessingLib.sharp
},
Threading: {
enable: true,
thumbnailThreads: 0
},
sessionTimeout: 0,
Indexing: {
cachedFolderTimeout: 0,
folderPreviewSize: 0,
reIndexingSensitivity: ServerConfig.ReIndexingSensitivity.medium,
excludeFolderList: [],
excludeFileList: []
},
photoMetadataSize: 512 * 1024,
Duplicates: {
listingLimit: 1000
},
Tasks: {
scheduled: []
},
Video: {
transcoding: {
bitRate: 5 * 1024 * 1024,
codec: 'libx264',
format: 'mp4',
fps: 25,
resolution: 720
}
}
}
});
} }
public async getSettings(): Promise<void> { public async getSettings(): Promise<void> {

View File

@ -115,13 +115,13 @@
<ng-container [ngSwitch]="configEntry.type"> <ng-container [ngSwitch]="configEntry.type">
<ng-container *ngSwitchCase="'boolean'"> <ng-container *ngSwitchCase="'boolean'">
<div class="form-group row"> <div class="form-group row">
<label class="col-md-2 control-label" [for]="configEntry.id" >{{configEntry.name}}</label> <label class="col-md-2 control-label" [for]="configEntry.id+'_boolean_'+i">{{configEntry.name}}</label>
<div class="col-md-10"> <div class="col-md-10">
<bSwitch <bSwitch
id="enableThreading" id="enableThreading"
class="switch" class="switch"
[name]="configEntry.id" [name]="configEntry.id+'_boolean_'+i"
[id]="configEntry.id" [id]="configEntry.id+'_boolean_'+i"
[switch-on-color]="'primary'" [switch-on-color]="'primary'"
[switch-inverse]="true" [switch-inverse]="true"
[switch-off-text]="text.Disabled" [switch-off-text]="text.Disabled"
@ -135,18 +135,20 @@
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'string'"> <ng-container *ngSwitchCase="'string'">
<div class="form-group row" [hidden]="simplifiedMode"> <div class="form-group row" [hidden]="simplifiedMode">
<label class="col-md-2 control-label" [for]="configEntry.id">{{configEntry.name}}</label> <label class="col-md-2 control-label" [for]="configEntry.id+'_string_'+i">{{configEntry.name}}</label>
<div class="col-md-10"> <div class="col-md-10">
<input type="text" class="form-control" [name]="configEntry.id" [id]="configEntry.id" <input type="text" class="form-control" [name]="configEntry.id+'_string_'+i"
[id]="configEntry.id+'_string_'+i"
[(ngModel)]="schedule.config[configEntry.id]" required> [(ngModel)]="schedule.config[configEntry.id]" required>
</div> </div>
</div> </div>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'number'"> <ng-container *ngSwitchCase="'number'">
<div class="form-group row" [hidden]="simplifiedMode"> <div class="form-group row" [hidden]="simplifiedMode">
<label class="col-md-2 control-label" [for]="configEntry.id">{{configEntry.name}}</label> <label class="col-md-2 control-label" [for]="configEntry.id+'_number_'+i">{{configEntry.name}}</label>
<div class="col-md-10"> <div class="col-md-10">
<input type="number" class="form-control" [name]="configEntry.id" [id]="configEntry.id" <input type="number" class="form-control" [name]="configEntry.id+'_number_'+i"
[id]="configEntry.id+'_number_'+i"
[(ngModel)]="schedule.config[configEntry.id]" required> [(ngModel)]="schedule.config[configEntry.id]" required>
</div> </div>
</div> </div>

View File

@ -16,6 +16,7 @@ import {
} from '../../../../../common/entities/task/TaskScheduleDTO'; } from '../../../../../common/entities/task/TaskScheduleDTO';
import {Utils} from '../../../../../common/Utils'; import {Utils} from '../../../../../common/Utils';
import {ServerConfig} from '../../../../../common/config/private/IPrivateConfig'; import {ServerConfig} from '../../../../../common/config/private/IPrivateConfig';
import {ConfigTemplateEntry} from '../../../../../common/entities/task/TaskDTO';
@Component({ @Component({
selector: 'app-settings-tasks', selector: 'app-settings-tasks',
@ -65,14 +66,9 @@ export class TasksSettingsComponent extends SettingsComponent<ServerConfig.TaskC
this.hasAvailableSettings = !this.simplifiedMode; this.hasAvailableSettings = !this.simplifiedMode;
} }
getConfigTemplate(taskName: string) { getConfigTemplate(taskName: string): ConfigTemplateEntry[] {
const task = this._settingsService.availableTasks.value.find(t => t.Name === taskName); const task = this._settingsService.availableTasks.value.find(t => t.Name === taskName);
if (task && task.ConfigTemplate && task.ConfigTemplate.length > 0) { if (task && task.ConfigTemplate && task.ConfigTemplate.length > 0) {
const schedule = this.settings.scheduled.find(s => s.taskName === taskName);
if (schedule) {
schedule.config = schedule.config || {};
task.ConfigTemplate.forEach(ct => schedule.config[ct.id] = ct.defaultValue);
}
return task.ConfigTemplate; return task.ConfigTemplate;
} }
return null; return null;
@ -149,13 +145,19 @@ export class TasksSettingsComponent extends SettingsComponent<ServerConfig.TaskC
} }
addNewTask() { addNewTask() {
this.settings.scheduled.push({ const taskName = this._settingsService.availableTasks.value[0].Name;
taskName: this._settingsService.availableTasks.value[0].Name, const newSchedule: TaskScheduleDTO = {
config: {}, taskName: taskName,
config: <any>{},
trigger: { trigger: {
type: TaskTriggerType.never type: TaskTriggerType.never
} }
}); };
const task = this._settingsService.availableTasks.value.find(t => t.Name === taskName);
newSchedule.config = newSchedule.config || {};
task.ConfigTemplate.forEach(ct => newSchedule.config[ct.id] = ct.defaultValue);
this.settings.scheduled.push(newSchedule);
} }
taskTriggerTypeChanged(triggerType: TaskTriggerType, schedule: TaskScheduleDTO) { taskTriggerTypeChanged(triggerType: TaskTriggerType, schedule: TaskScheduleDTO) {