mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-12-23 01:27:14 +02:00
Add users panel to users #569
This commit is contained in:
parent
82bc7ab280
commit
a6e60c7c19
@ -3,7 +3,7 @@ import * as path from 'path';
|
|||||||
import { ConfigClass, ConfigClassBuilder } from 'typeconfig/node';
|
import { ConfigClass, ConfigClassBuilder } from 'typeconfig/node';
|
||||||
import { ConfigProperty, SubConfigClass } from 'typeconfig/common';
|
import { ConfigProperty, SubConfigClass } from 'typeconfig/common';
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class BenchmarksConfig {
|
export class BenchmarksConfig {
|
||||||
@ConfigProperty()
|
@ConfigProperty()
|
||||||
bmScanDirectory: boolean = true;
|
bmScanDirectory: boolean = true;
|
||||||
|
@ -91,7 +91,7 @@ export type videoResolutionType =
|
|||||||
| 4320;
|
| 4320;
|
||||||
export type videoFormatType = 'mp4' | 'webm';
|
export type videoFormatType = 'mp4' | 'webm';
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class MySQLConfig {
|
export class MySQLConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
envAlias: 'MYSQL_HOST',
|
envAlias: 'MYSQL_HOST',
|
||||||
@ -140,7 +140,7 @@ export class MySQLConfig {
|
|||||||
password: string = '';
|
password: string = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class SQLiteConfig {
|
export class SQLiteConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -153,7 +153,7 @@ export class SQLiteConfig {
|
|||||||
DBFileName: string = 'sqlite.db';
|
DBFileName: string = 'sqlite.db';
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class UserConfig {
|
export class UserConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -216,7 +216,7 @@ export class UserConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerDataBaseConfig {
|
export class ServerDataBaseConfig {
|
||||||
@ConfigProperty<DatabaseType, ServerConfig>({
|
@ConfigProperty<DatabaseType, ServerConfig>({
|
||||||
type: DatabaseType,
|
type: DatabaseType,
|
||||||
@ -262,7 +262,7 @@ export class ServerDataBaseConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerUserConfig extends ClientUserConfig {
|
export class ServerUserConfig extends ClientUserConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
arrayType: UserConfig,
|
arrayType: UserConfig,
|
||||||
@ -273,13 +273,13 @@ export class ServerUserConfig extends ClientUserConfig {
|
|||||||
uiOptional: true,
|
uiOptional: true,
|
||||||
githubIssue: 575
|
githubIssue: 575
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
description: $localize`Creates these users in the DB if they do not exist. If a user with this name exist, it won't be overwritten, even if the role is different.`,
|
description: $localize`Creates these users in the DB during startup if they do not exist. If a user with this name exist, it won't be overwritten, even if the role is different.`,
|
||||||
})
|
})
|
||||||
enforcedUsers: UserConfig[] = [];
|
enforcedUsers: UserConfig[] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerThumbnailConfig extends ClientThumbnailConfig {
|
export class ServerThumbnailConfig extends ClientThumbnailConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -312,7 +312,7 @@ export class ServerThumbnailConfig extends ClientThumbnailConfig {
|
|||||||
personFaceMargin: number = 0.6; // in ration [0-1]
|
personFaceMargin: number = 0.6; // in ration [0-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerGPXCompressingConfig extends ClientGPXCompressingConfig {
|
export class ServerGPXCompressingConfig extends ClientGPXCompressingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -350,7 +350,7 @@ export class ServerGPXCompressingConfig extends ClientGPXCompressingConfig {
|
|||||||
minTimeDistance: number = 5000;
|
minTimeDistance: number = 5000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerMetaFileConfig extends ClientMetaFileConfig {
|
export class ServerMetaFileConfig extends ClientMetaFileConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -367,7 +367,7 @@ export class ServerMetaFileConfig extends ClientMetaFileConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerSharingConfig extends ClientSharingConfig {
|
export class ServerSharingConfig extends ClientSharingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'unsignedInt',
|
type: 'unsignedInt',
|
||||||
@ -382,7 +382,7 @@ export class ServerSharingConfig extends ClientSharingConfig {
|
|||||||
updateTimeout: number = 1000 * 60 * 5;
|
updateTimeout: number = 1000 * 60 * 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerIndexingConfig {
|
export class ServerIndexingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'unsignedInt',
|
type: 'unsignedInt',
|
||||||
@ -431,7 +431,7 @@ export class ServerIndexingConfig {
|
|||||||
excludeFileList: string[] = [];
|
excludeFileList: string[] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerThreadingConfig {
|
export class ServerThreadingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -453,7 +453,7 @@ export class ServerThreadingConfig {
|
|||||||
thumbnailThreads: number = 0; // if zero-> CPU count -1
|
thumbnailThreads: number = 0; // if zero-> CPU count -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerDuplicatesConfig {
|
export class ServerDuplicatesConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'unsignedInt',
|
type: 'unsignedInt',
|
||||||
@ -467,7 +467,7 @@ export class ServerDuplicatesConfig {
|
|||||||
listingLimit: number = 1000;
|
listingLimit: number = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerLogConfig {
|
export class ServerLogConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: LogLevel,
|
type: LogLevel,
|
||||||
@ -497,13 +497,13 @@ export class ServerLogConfig {
|
|||||||
logServerTiming: boolean = false;
|
logServerTiming: boolean = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class NeverJobTriggerConfig implements NeverJobTrigger {
|
export class NeverJobTriggerConfig implements NeverJobTrigger {
|
||||||
@ConfigProperty({type: JobTriggerType})
|
@ConfigProperty({type: JobTriggerType})
|
||||||
readonly type = JobTriggerType.never;
|
readonly type = JobTriggerType.never;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ScheduledJobTriggerConfig implements ScheduledJobTrigger {
|
export class ScheduledJobTriggerConfig implements ScheduledJobTrigger {
|
||||||
@ConfigProperty({type: JobTriggerType})
|
@ConfigProperty({type: JobTriggerType})
|
||||||
readonly type = JobTriggerType.scheduled;
|
readonly type = JobTriggerType.scheduled;
|
||||||
@ -512,7 +512,7 @@ export class ScheduledJobTriggerConfig implements ScheduledJobTrigger {
|
|||||||
time: number; // data time
|
time: number; // data time
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class PeriodicJobTriggerConfig implements PeriodicJobTrigger {
|
export class PeriodicJobTriggerConfig implements PeriodicJobTrigger {
|
||||||
@ConfigProperty({type: JobTriggerType})
|
@ConfigProperty({type: JobTriggerType})
|
||||||
readonly type = JobTriggerType.periodic;
|
readonly type = JobTriggerType.periodic;
|
||||||
@ -522,7 +522,7 @@ export class PeriodicJobTriggerConfig implements PeriodicJobTrigger {
|
|||||||
atTime: number | undefined = 0; // day time
|
atTime: number | undefined = 0; // day time
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class AfterJobTriggerConfig implements AfterJobTrigger {
|
export class AfterJobTriggerConfig implements AfterJobTrigger {
|
||||||
@ConfigProperty({type: JobTriggerType})
|
@ConfigProperty({type: JobTriggerType})
|
||||||
readonly type = JobTriggerType.after;
|
readonly type = JobTriggerType.after;
|
||||||
@ -534,7 +534,7 @@ export class AfterJobTriggerConfig implements AfterJobTrigger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class JobScheduleConfig implements JobScheduleDTO {
|
export class JobScheduleConfig implements JobScheduleDTO {
|
||||||
@ConfigProperty()
|
@ConfigProperty()
|
||||||
name: string;
|
name: string;
|
||||||
@ -586,7 +586,7 @@ export class JobScheduleConfig implements JobScheduleDTO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerJobConfig {
|
export class ServerJobConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'unsignedInt',
|
type: 'unsignedInt',
|
||||||
@ -661,7 +661,7 @@ export class ServerJobConfig {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class VideoTranscodingConfig {
|
export class VideoTranscodingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'unsignedInt',
|
type: 'unsignedInt',
|
||||||
@ -761,7 +761,7 @@ export class VideoTranscodingConfig {
|
|||||||
customOptions: string[] = [];
|
customOptions: string[] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerVideoConfig extends ClientVideoConfig {
|
export class ServerVideoConfig extends ClientVideoConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -774,7 +774,7 @@ export class ServerVideoConfig extends ClientVideoConfig {
|
|||||||
transcoding: VideoTranscodingConfig = new VideoTranscodingConfig();
|
transcoding: VideoTranscodingConfig = new VideoTranscodingConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class PhotoConvertingConfig extends ClientPhotoConvertingConfig {
|
export class PhotoConvertingConfig extends ClientPhotoConvertingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -802,7 +802,7 @@ export class PhotoConvertingConfig extends ClientPhotoConvertingConfig {
|
|||||||
resolution: videoResolutionType = 1080;
|
resolution: videoResolutionType = 1080;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerPhotoConfig extends ClientPhotoConfig {
|
export class ServerPhotoConfig extends ClientPhotoConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -813,7 +813,7 @@ export class ServerPhotoConfig extends ClientPhotoConfig {
|
|||||||
Converting: PhotoConvertingConfig = new PhotoConvertingConfig();
|
Converting: PhotoConvertingConfig = new PhotoConvertingConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerPreviewConfig {
|
export class ServerPreviewConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -842,7 +842,7 @@ export class ServerPreviewConfig {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerMediaConfig extends ClientMediaConfig {
|
export class ServerMediaConfig extends ClientMediaConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -914,7 +914,7 @@ export class ServerMediaConfig extends ClientMediaConfig {
|
|||||||
Thumbnail: ServerThumbnailConfig = new ServerThumbnailConfig();
|
Thumbnail: ServerThumbnailConfig = new ServerThumbnailConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerServiceConfig extends ClientServiceConfig {
|
export class ServerServiceConfig extends ClientServiceConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
arrayType: 'string',
|
arrayType: 'string',
|
||||||
@ -974,7 +974,7 @@ export class ServerServiceConfig extends ClientServiceConfig {
|
|||||||
Log: ServerLogConfig = new ServerLogConfig();
|
Log: ServerLogConfig = new ServerLogConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass()
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerEnvironmentConfig {
|
export class ServerEnvironmentConfig {
|
||||||
@ConfigProperty({volatile: true})
|
@ConfigProperty({volatile: true})
|
||||||
upTime: string | undefined;
|
upTime: string | undefined;
|
||||||
@ -988,7 +988,7 @@ export class ServerEnvironmentConfig {
|
|||||||
isDocker: boolean | undefined;
|
isDocker: boolean | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass<TAGS>()
|
@SubConfigClass<TAGS>({softReadonly: true})
|
||||||
export class ServerConfig extends ClientConfig {
|
export class ServerConfig extends ClientConfig {
|
||||||
|
|
||||||
@ConfigProperty({volatile: true})
|
@ConfigProperty({volatile: true})
|
||||||
|
@ -13,7 +13,6 @@ if (typeof $localize === 'undefined') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export enum MapProviders {
|
export enum MapProviders {
|
||||||
OpenStreetMap = 1,
|
OpenStreetMap = 1,
|
||||||
Mapbox = 2,
|
Mapbox = 2,
|
||||||
@ -49,7 +48,7 @@ export type TAGS = {
|
|||||||
}[]
|
}[]
|
||||||
};
|
};
|
||||||
|
|
||||||
@SubConfigClass<TAGS>({tags: {client: true}})
|
@SubConfigClass<TAGS>({tags: {client: true}, softReadonly: true})
|
||||||
export class AutoCompleteConfig {
|
export class AutoCompleteConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -93,7 +92,7 @@ export class AutoCompleteConfig {
|
|||||||
cacheTimeout: number = 1000 * 60 * 60;
|
cacheTimeout: number = 1000 * 60 * 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientSearchConfig {
|
export class ClientSearchConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -162,7 +161,7 @@ export class ClientSearchConfig {
|
|||||||
listMetafiles: boolean = true;
|
listMetafiles: boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientAlbumConfig {
|
export class ClientAlbumConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -174,7 +173,7 @@ export class ClientAlbumConfig {
|
|||||||
enabled: boolean = true;
|
enabled: boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientSharingConfig {
|
export class ClientSharingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -196,7 +195,7 @@ export class ClientSharingConfig {
|
|||||||
passwordProtected: boolean = true;
|
passwordProtected: boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientRandomPhotoConfig {
|
export class ClientRandomPhotoConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -209,7 +208,7 @@ export class ClientRandomPhotoConfig {
|
|||||||
enabled: boolean = true;
|
enabled: boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class MapLayers {
|
export class MapLayers {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags:
|
tags:
|
||||||
@ -230,7 +229,7 @@ export class MapLayers {
|
|||||||
url: string = '';
|
url: string = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientMapConfig {
|
export class ClientMapConfig {
|
||||||
@ConfigProperty<boolean, ClientConfig, TAGS>({
|
@ConfigProperty<boolean, ClientConfig, TAGS>({
|
||||||
onNewValue: (value, config) => {
|
onNewValue: (value, config) => {
|
||||||
@ -293,7 +292,7 @@ export class ClientMapConfig {
|
|||||||
maxPreviewMarkers: number = 50;
|
maxPreviewMarkers: number = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientThumbnailConfig {
|
export class ClientThumbnailConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'unsignedInt', max: 100,
|
type: 'unsignedInt', max: 100,
|
||||||
@ -351,7 +350,7 @@ export enum NavigationLinkTypes {
|
|||||||
gallery = 1, faces, albums, search, url
|
gallery = 1, faces, albums, search, url
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class NavigationLinkConfig {
|
export class NavigationLinkConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: NavigationLinkTypes,
|
type: NavigationLinkTypes,
|
||||||
@ -400,7 +399,7 @@ export class NavigationLinkConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass<TAGS>({tags: {client: true}})
|
@SubConfigClass<TAGS>({tags: {client: true}, softReadonly: true})
|
||||||
export class NavBarConfig {
|
export class NavBarConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -427,7 +426,7 @@ export class NavBarConfig {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass<TAGS>({tags: {client: true, priority: ConfigPriority.advanced}})
|
@SubConfigClass<TAGS>({tags: {client: true, priority: ConfigPriority.advanced}, softReadonly: true})
|
||||||
export class ClientGalleryConfig {
|
export class ClientGalleryConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -528,7 +527,7 @@ export class ClientGalleryConfig {
|
|||||||
defaultSlideshowSpeed: number = 5;
|
defaultSlideshowSpeed: number = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientVideoConfig {
|
export class ClientVideoConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -562,7 +561,7 @@ export class ClientVideoConfig {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientPhotoConvertingConfig {
|
export class ClientPhotoConvertingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -584,7 +583,7 @@ export class ClientPhotoConvertingConfig {
|
|||||||
loadFullImageOnZoom: boolean = true;
|
loadFullImageOnZoom: boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientPhotoConfig {
|
export class ClientPhotoConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -605,7 +604,7 @@ export class ClientPhotoConfig {
|
|||||||
supportedFormats: string[] = ['gif', 'jpeg', 'jpg', 'jpe', 'png', 'webp', 'svg'];
|
supportedFormats: string[] = ['gif', 'jpeg', 'jpg', 'jpe', 'png', 'webp', 'svg'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientGPXCompressingConfig {
|
export class ClientGPXCompressingConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -619,7 +618,7 @@ export class ClientGPXCompressingConfig {
|
|||||||
enabled: boolean = true;
|
enabled: boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientMediaConfig {
|
export class ClientMediaConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -644,7 +643,7 @@ export class ClientMediaConfig {
|
|||||||
Photo: ClientPhotoConfig = new ClientPhotoConfig();
|
Photo: ClientPhotoConfig = new ClientPhotoConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientMetaFileConfig {
|
export class ClientMetaFileConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -693,7 +692,7 @@ export class ClientMetaFileConfig {
|
|||||||
supportedFormats: string[] = ['gpx', 'pg2conf', 'md'];
|
supportedFormats: string[] = ['gpx', 'pg2conf', 'md'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientFacesConfig {
|
export class ClientFacesConfig {
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
@ -728,7 +727,7 @@ export class ClientFacesConfig {
|
|||||||
readAccessMinRole: UserRoles = UserRoles.User;
|
readAccessMinRole: UserRoles = UserRoles.User;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientServiceConfig {
|
export class ClientServiceConfig {
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
@ -783,7 +782,7 @@ export class ClientServiceConfig {
|
|||||||
customHTMLHead: string = '';
|
customHTMLHead: string = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubConfigClass({tags: {client: true}})
|
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientUserConfig {
|
export class ClientUserConfig {
|
||||||
|
|
||||||
@ConfigProperty<boolean, ClientConfig>({
|
@ConfigProperty<boolean, ClientConfig>({
|
||||||
@ -794,7 +793,6 @@ export class ClientUserConfig {
|
|||||||
},
|
},
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Password protection`,
|
name: $localize`Password protection`,
|
||||||
priority: ConfigPriority.advanced,
|
|
||||||
},
|
},
|
||||||
description: $localize`Enables user management with login to password protect the gallery.`,
|
description: $localize`Enables user management with login to password protect the gallery.`,
|
||||||
})
|
})
|
||||||
@ -812,7 +810,7 @@ export class ClientUserConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SubConfigClass<TAGS>({tags: {client: true}})
|
@SubConfigClass<TAGS>({tags: {client: true}, softReadonly: true})
|
||||||
export class ClientConfig {
|
export class ClientConfig {
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty()
|
||||||
|
@ -103,6 +103,7 @@ import {GalleryStatisticComponent} from './ui/settings/gallery-statistic/gallery
|
|||||||
import { JobButtonComponent } from './ui/settings/workflow/button/job-button.settings.component';
|
import { JobButtonComponent } from './ui/settings/workflow/button/job-button.settings.component';
|
||||||
import { JobProgressComponent } from './ui/settings/workflow/progress/job-progress.settings.component';
|
import { JobProgressComponent } from './ui/settings/workflow/progress/job-progress.settings.component';
|
||||||
import {SettingsEntryComponent} from './ui/settings/template/settings-entry/settings-entry.component';
|
import {SettingsEntryComponent} from './ui/settings/template/settings-entry/settings-entry.component';
|
||||||
|
import { UsersComponent } from './ui/settings/users/users.component';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MyHammerConfig extends HammerGestureConfig {
|
export class MyHammerConfig extends HammerGestureConfig {
|
||||||
@ -236,6 +237,7 @@ Marker.prototype.options.icon = iconDefault;
|
|||||||
StringifySearchQuery,
|
StringifySearchQuery,
|
||||||
FileDTOToPathPipe,
|
FileDTOToPathPipe,
|
||||||
PhotoFilterPipe,
|
PhotoFilterPipe,
|
||||||
|
UsersComponent,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: HTTP_INTERCEPTORS, useClass: CSRFInterceptor, multi: true},
|
{provide: HTTP_INTERCEPTORS, useClass: CSRFInterceptor, multi: true},
|
||||||
|
@ -76,17 +76,17 @@
|
|||||||
<div class="py-md-1 px-md-0"
|
<div class="py-md-1 px-md-0"
|
||||||
*ngFor="let s of contents;"
|
*ngFor="let s of contents;"
|
||||||
[hidden]="!s.HasAvailableSettings">
|
[hidden]="!s.HasAvailableSettings">
|
||||||
<button class="btn btn-link nav-link text-start p-0"
|
<button class="btn btn-link nav-link text-start p-0"
|
||||||
(click)="viewportScroller.scrollToAnchor(s.ConfigPath)"
|
(click)="viewportScroller.scrollToAnchor(s.ConfigPath)"
|
||||||
>
|
>
|
||||||
<span class="oi oi-{{s.icon}}"></span> {{s.Name}}
|
<span class="oi oi-{{s.icon}}"></span> {{s.Name}}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-link nav-link text-start ms-3 p-0"
|
<button class="btn btn-link nav-link text-start ms-3 p-0"
|
||||||
*ngFor="let n of s.nestedConfigs;"
|
*ngFor="let n of s.nestedConfigs;"
|
||||||
[hidden]="!n.visible()"
|
[hidden]="!n.visible()"
|
||||||
(click)="viewportScroller.scrollToAnchor(n.id)">
|
(click)="viewportScroller.scrollToAnchor(n.id)">
|
||||||
<span class="oi oi-{{n.icon}}"></span> {{n.name}}
|
<span class="oi oi-{{n.icon}}"></span> {{n.name}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -107,6 +107,7 @@
|
|||||||
<hr class="mt-2"/>
|
<hr class="mt-2"/>
|
||||||
<app-settings-gallery-statistic></app-settings-gallery-statistic>
|
<app-settings-gallery-statistic></app-settings-gallery-statistic>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<app-settings-users *ngIf="cp=='Users'"></app-settings-users>
|
||||||
</app-settings-template>
|
</app-settings-template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
81
src/frontend/app/ui/settings/users/users.component.html
Normal file
81
src/frontend/app/ui/settings/users/users.component.html
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<ng-container *ngIf="Enabled">
|
||||||
|
<div class="row mt-2">
|
||||||
|
<div class="col-auto">
|
||||||
|
<h5 i18n>User list</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<hr/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||||
|
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th i18n>Name</th>
|
||||||
|
<th i18n>Role</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let user of users">
|
||||||
|
<td>{{user.name}}</td>
|
||||||
|
<td *ngIf="canModifyUser(user)">
|
||||||
|
<select class="form-select" [(ngModel)]="user.role" (change)="updateRole(user)" required>
|
||||||
|
<option *ngFor="let repository of userRoles" [value]="repository.key">
|
||||||
|
{{repository.value}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td *ngIf="!canModifyUser(user)">
|
||||||
|
{{user.role | stringifyRole}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button [disabled]="!canModifyUser(user)" (click)="deleteUser(user)"
|
||||||
|
[ngClass]="canModifyUser(user)? 'btn-danger':'btn-secondary'"
|
||||||
|
class="btn float-end">
|
||||||
|
<span class="oi oi-trash" aria-hidden="true" aria-label="Delete"></span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button class="btn btn-primary float-end"
|
||||||
|
(click)="initNewUser()" i18n>+ Add user
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<div bsModal #userModal="bs-modal" class="modal fade" id="userModal" tabindex="-1" role="dialog"
|
||||||
|
aria-labelledby="userModalLabel">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="userModalLabel" i18n>Add new User</h5>
|
||||||
|
<button type="button" class="btn-close" (click)="userModal.hide()" data-dismiss="modal" aria-label="Close">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form #NewUserForm="ngForm">
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="text" class="form-control" i18n-placeholder placeholder="Username"
|
||||||
|
[(ngModel)]="newUser.name" name="name" required>
|
||||||
|
<input type="password" class="form-control" i18n-placeholder placeholder="Password"
|
||||||
|
[(ngModel)]="newUser.password" name="password" autocomplete="off" required>
|
||||||
|
<select class="form-select" [(ngModel)]="newUser.role" name="role" required>
|
||||||
|
<option *ngFor="let repository of userRoles" [value]="repository.key">{{repository.value}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" (click)="userModal.hide()" i18n>Close</button>
|
||||||
|
<button type="button" class="btn btn-primary" data-dismiss="modal"
|
||||||
|
(click)="addNewUser()"
|
||||||
|
[disabled]="!NewUserForm.form.valid" i18n>Add User
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
110
src/frontend/app/ui/settings/users/users.component.ts
Normal file
110
src/frontend/app/ui/settings/users/users.component.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import {Component, OnInit, ViewChild} from '@angular/core';
|
||||||
|
import {ModalDirective} from 'ngx-bootstrap/modal';
|
||||||
|
import {UserDTO, UserRoles} from '../../../../../common/entities/UserDTO';
|
||||||
|
import {AuthenticationService} from '../../../model/network/authentication.service';
|
||||||
|
import {NavigationService} from '../../../model/navigation.service';
|
||||||
|
import {NotificationService} from '../../../model/notification.service';
|
||||||
|
import {Utils} from '../../../../../common/Utils';
|
||||||
|
import {ErrorCodes, ErrorDTO} from '../../../../../common/entities/Error';
|
||||||
|
import {UsersSettingsService} from './users.service';
|
||||||
|
import {SettingsService} from '../settings.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-settings-users',
|
||||||
|
templateUrl: './users.component.html',
|
||||||
|
styleUrls: ['./users.component.css']
|
||||||
|
})
|
||||||
|
export class UsersComponent implements OnInit {
|
||||||
|
|
||||||
|
@ViewChild('userModal', {static: false}) public childModal: ModalDirective;
|
||||||
|
public newUser = {} as UserDTO;
|
||||||
|
public userRoles: { key: number; value: string }[] = [];
|
||||||
|
public users: UserDTO[] = [];
|
||||||
|
public error: string = null;
|
||||||
|
public inProgress = false;
|
||||||
|
Changed = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private authService: AuthenticationService,
|
||||||
|
private navigation: NavigationService,
|
||||||
|
private userSettings: UsersSettingsService,
|
||||||
|
private settingsService: SettingsService,
|
||||||
|
private notification: NotificationService
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
if (
|
||||||
|
!this.authService.isAuthenticated() ||
|
||||||
|
this.authService.user.value.role < UserRoles.Admin
|
||||||
|
) {
|
||||||
|
this.navigation.toLogin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.userRoles = Utils.enumToArray(UserRoles)
|
||||||
|
.filter((r) => r.key !== UserRoles.LimitedGuest)
|
||||||
|
.filter((r) => r.key <= this.authService.user.value.role)
|
||||||
|
.sort((a, b) => a.key - b.key);
|
||||||
|
|
||||||
|
this.getUsersList();
|
||||||
|
}
|
||||||
|
|
||||||
|
canModifyUser(user: UserDTO): boolean {
|
||||||
|
const currentUser = this.authService.user.value;
|
||||||
|
if (!currentUser) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentUser.name !== user.name && currentUser.role >= user.role;
|
||||||
|
}
|
||||||
|
|
||||||
|
get Enabled():boolean{
|
||||||
|
return this.settingsService.settings.value.Users.authenticationRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
initNewUser(): void {
|
||||||
|
this.newUser = {role: UserRoles.User} as UserDTO;
|
||||||
|
this.childModal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
async addNewUser(): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.userSettings.createUser(this.newUser);
|
||||||
|
await this.getUsersList();
|
||||||
|
this.childModal.hide();
|
||||||
|
} catch (e) {
|
||||||
|
const err: ErrorDTO = e;
|
||||||
|
this.notification.error(
|
||||||
|
err.message + ', ' + err.details,
|
||||||
|
$localize`User creation error!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateRole(user: UserDTO): Promise<void> {
|
||||||
|
await this.userSettings.updateRole(user);
|
||||||
|
await this.getUsersList();
|
||||||
|
this.childModal.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteUser(user: UserDTO): Promise<void> {
|
||||||
|
await this.userSettings.deleteUser(user);
|
||||||
|
await this.getUsersList();
|
||||||
|
this.childModal.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getUsersList(): Promise<void> {
|
||||||
|
try {
|
||||||
|
this.users = await this.userSettings.getUsers();
|
||||||
|
} catch (err) {
|
||||||
|
this.users = [];
|
||||||
|
if ((err as ErrorDTO).code !== ErrorCodes.USER_MANAGEMENT_DISABLED) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
src/frontend/app/ui/settings/users/users.service.ts
Normal file
31
src/frontend/app/ui/settings/users/users.service.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {UserDTO} from '../../../../../common/entities/UserDTO';
|
||||||
|
import {NetworkService} from '../../../model/network/network.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class UsersSettingsService {
|
||||||
|
|
||||||
|
constructor(private networkService: NetworkService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public createUser(user: UserDTO): Promise<string> {
|
||||||
|
return this.networkService.putJson('/user', {newUser: user});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public getUsers(): Promise<Array<UserDTO>> {
|
||||||
|
return this.networkService.getJson('/user/list');
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteUser(user: UserDTO): Promise<void> {
|
||||||
|
return this.networkService.deleteJson('/user/' + user.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateRole(user: UserDTO): Promise<void> {
|
||||||
|
return this.networkService.postJson('/user/' + user.id + '/role', {
|
||||||
|
newRole: user.role,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user