improving config check and setting
This commit is contained in:
parent
46af62c93f
commit
3a72f5e3d2
@ -5,6 +5,8 @@ import {Logger} from "../Logger";
|
|||||||
import {MySQLConnection} from "../model/mysql/MySQLConnection";
|
import {MySQLConnection} from "../model/mysql/MySQLConnection";
|
||||||
import {DataBaseConfig, DatabaseType} from "../../common/config/private/IPrivateConfig";
|
import {DataBaseConfig, DatabaseType} from "../../common/config/private/IPrivateConfig";
|
||||||
import {Config} from "../../common/config/private/Config";
|
import {Config} from "../../common/config/private/Config";
|
||||||
|
import {ConfigDiagnostics} from "../model/ConfigDiagnostics";
|
||||||
|
import {MapConfig} from "../../common/config/public/ConfigClass";
|
||||||
|
|
||||||
|
|
||||||
const LOG_TAG = "[AdminMWs]";
|
const LOG_TAG = "[AdminMWs]";
|
||||||
@ -13,18 +15,22 @@ export class AdminMWs {
|
|||||||
|
|
||||||
public static async updateDatabaseSettings(req: Request, res: Response, next: NextFunction) {
|
public static async updateDatabaseSettings(req: Request, res: Response, next: NextFunction) {
|
||||||
|
|
||||||
if ((typeof req.body === 'undefined') || (typeof req.body.databaseSettings === 'undefined')) {
|
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
||||||
return next(new Error(ErrorCodes.INPUT_ERROR, "databaseSettings is needed"));
|
return next(new Error(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const databaseSettings = <DataBaseConfig>req.body.databaseSettings;
|
const databaseSettings = <DataBaseConfig>req.body.settings;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (databaseSettings.type == DatabaseType.mysql) {
|
if (databaseSettings.type == DatabaseType.mysql) {
|
||||||
await MySQLConnection.tryConnection(databaseSettings);
|
await MySQLConnection.tryConnection(databaseSettings);
|
||||||
}
|
}
|
||||||
Config.Server.database = databaseSettings;
|
Config.Server.database = databaseSettings;
|
||||||
Config.save();
|
//only updating explicitly set config (not saving config set by the diagnostics)
|
||||||
|
const original = Config.original();
|
||||||
|
original.Server.database = databaseSettings;
|
||||||
|
original.save();
|
||||||
|
await ConfigDiagnostics.runDiagnostics();
|
||||||
Logger.info(LOG_TAG, "new config:");
|
Logger.info(LOG_TAG, "new config:");
|
||||||
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
|
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
|
||||||
|
|
||||||
@ -43,19 +49,55 @@ export class AdminMWs {
|
|||||||
|
|
||||||
|
|
||||||
public static async testDatabaseSettings(req: Request, res: Response, next: NextFunction) {
|
public static async testDatabaseSettings(req: Request, res: Response, next: NextFunction) {
|
||||||
if ((typeof req.body === 'undefined') || (typeof req.body.databaseSettings === 'undefined')) {
|
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
||||||
return next(new Error(ErrorCodes.INPUT_ERROR, "databaseSettings is needed"));
|
return next(new Error(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const databaseSettings = <DataBaseConfig>req.body.databaseSettings;
|
const databaseSettings = <DataBaseConfig>req.body.settings;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (databaseSettings.type == DatabaseType.mysql) {
|
if (databaseSettings.type == DatabaseType.mysql) {
|
||||||
await MySQLConnection.tryConnection(databaseSettings);
|
await ConfigDiagnostics.testDatabase(databaseSettings);
|
||||||
}
|
}
|
||||||
return next();
|
return next();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return next(new Error(ErrorCodes.SETTINGS_ERROR, "Settings error: " + JSON.stringify(err, null, ' '), err));
|
return next(new Error(ErrorCodes.SETTINGS_ERROR, "Settings error: " + JSON.stringify(err, null, ' '), err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async updateMapSettings(req: Request, res: Response, next: NextFunction) {
|
||||||
|
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
||||||
|
return next(new Error(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testMapConfig(<MapConfig>req.body.settings);
|
||||||
|
|
||||||
|
Config.Client.Map = <MapConfig>req.body.settings;
|
||||||
|
//only updating explicitly set config (not saving config set by the diagnostics)
|
||||||
|
const original = Config.original();
|
||||||
|
original.Client.Map = <MapConfig>req.body.settings;
|
||||||
|
original.save();
|
||||||
|
await ConfigDiagnostics.runDiagnostics();
|
||||||
|
Logger.info(LOG_TAG, "new config:");
|
||||||
|
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
|
||||||
|
return next();
|
||||||
|
} catch (err) {
|
||||||
|
return next(new Error(ErrorCodes.SETTINGS_ERROR, "Settings error: " + JSON.stringify(err, null, ' '), err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async testMapSettings(req: Request, res: Response, next: NextFunction) {
|
||||||
|
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
||||||
|
return next(new Error(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testMapConfig(<MapConfig>req.body.settings);
|
||||||
|
return next();
|
||||||
|
} catch (err) {
|
||||||
|
return next(new Error(ErrorCodes.SETTINGS_ERROR, "Settings error: " + JSON.stringify(err, null, ' '), err));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,7 +89,7 @@ export class GalleryMWs {
|
|||||||
|
|
||||||
|
|
||||||
public static async search(req: Request, res: Response, next: NextFunction) {
|
public static async search(req: Request, res: Response, next: NextFunction) {
|
||||||
if (Config.Client.Search.searchEnabled === false) {
|
if (Config.Client.Search.enabled === false) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {Config} from "../../common/config/private/Config";
|
|||||||
import {PrivateConfigClass} from "../../common/config/private/PrivateConfigClass";
|
import {PrivateConfigClass} 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";
|
||||||
|
|
||||||
export class RenderingMWs {
|
export class RenderingMWs {
|
||||||
|
|
||||||
@ -59,8 +60,17 @@ export class RenderingMWs {
|
|||||||
public static renderError(err: any, req: Request, res: Response, next: NextFunction): any {
|
public static renderError(err: any, req: Request, res: Response, next: NextFunction): any {
|
||||||
|
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
if (!(req.session.user && req.session.user.role >= UserRoles.Developer)) {
|
if (err.details) {
|
||||||
delete (err.details);
|
if (!(req.session.user && req.session.user.role >= UserRoles.Developer)) {
|
||||||
|
Logger.warn("Handled error:", err.details.toString() || err.details);
|
||||||
|
delete (err.details);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
err.details = err.details.toString() || err.details;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let message = new Message<any>(err, null);
|
let message = new Message<any>(err, null);
|
||||||
return res.json(message);
|
return res.json(message);
|
||||||
|
|||||||
@ -32,6 +32,24 @@ export class AuthenticationMWs {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async tryAuthenticate(req: Request, res: Response, next: NextFunction) {
|
||||||
|
if (Config.Client.authenticationRequired === false) {
|
||||||
|
req.session.user = <UserDTO>{name: "Admin", role: UserRoles.Admin};
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const user = await AuthenticationMWs.getSharingUser(req);
|
||||||
|
if (!!user) {
|
||||||
|
req.session.user = user;
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
|
||||||
|
}
|
||||||
public static async authenticate(req: Request, res: Response, next: NextFunction) {
|
public static async authenticate(req: Request, res: Response, next: NextFunction) {
|
||||||
|
|
||||||
if (Config.Client.authenticationRequired === false) {
|
if (Config.Client.authenticationRequired === false) {
|
||||||
|
|||||||
168
backend/model/ConfigDiagnostics.ts
Normal file
168
backend/model/ConfigDiagnostics.ts
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import {Config} from "../../common/config/private/Config";
|
||||||
|
import {
|
||||||
|
DataBaseConfig,
|
||||||
|
DatabaseType,
|
||||||
|
ThumbnailConfig,
|
||||||
|
ThumbnailProcessingLib
|
||||||
|
} from "../../common/config/private/IPrivateConfig";
|
||||||
|
import {Logger} from "../Logger";
|
||||||
|
import {NotificationManager} from "./NotifocationManager";
|
||||||
|
import {ProjectPath} from "../ProjectPath";
|
||||||
|
import {MySQLConnection} from "./mysql/MySQLConnection";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import {MapConfig, SearchConfig, SharingConfig} from "../../common/config/public/ConfigClass";
|
||||||
|
|
||||||
|
const LOG_TAG = "[ConfigDiagnostics]";
|
||||||
|
export class ConfigDiagnostics {
|
||||||
|
|
||||||
|
static async testDatabase(databaseConfig: DataBaseConfig) {
|
||||||
|
if (databaseConfig.type == DatabaseType.mysql) {
|
||||||
|
await MySQLConnection.tryConnection(databaseConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async testThumbnailLib(processingLibrary: ThumbnailProcessingLib) {
|
||||||
|
switch (processingLibrary) {
|
||||||
|
case ThumbnailProcessingLib.sharp:
|
||||||
|
const sharp = require("sharp");
|
||||||
|
sharp();
|
||||||
|
break;
|
||||||
|
case ThumbnailProcessingLib.gm:
|
||||||
|
const gm = require("gm");
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
gm(ProjectPath.FrontendFolder + "/assets/icon.png").size((err, value) => {
|
||||||
|
if (!err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async testThumbnailFolder(folder: string) {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
if (!fs.existsSync(folder)) {
|
||||||
|
reject("Thumbnail folder not exists: " + folder);
|
||||||
|
}
|
||||||
|
fs.access(folder, fs.constants.W_OK, function (err) {
|
||||||
|
if (err) {
|
||||||
|
reject({message: "Error during getting write access to temp folder", error: err});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static async testImageFolder(folder: string) {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
if (!fs.existsSync(folder)) {
|
||||||
|
reject("Images folder not exists: " + folder);
|
||||||
|
}
|
||||||
|
fs.access(folder, fs.constants.R_OK, function (err) {
|
||||||
|
if (err) {
|
||||||
|
reject({message: "Error during getting read access to images folder", error: err});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async testThumbnailConfig(thumbnailConfig: ThumbnailConfig) {
|
||||||
|
await ConfigDiagnostics.testThumbnailLib(thumbnailConfig.processingLibrary);
|
||||||
|
await ConfigDiagnostics.testThumbnailFolder(thumbnailConfig.folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async testSearchConfig(search: SearchConfig) {
|
||||||
|
if (search.enabled == true && Config.Server.database.type == DatabaseType.memory) {
|
||||||
|
throw "Memory Database do not support searching";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async testSharingConfig(sharing: SharingConfig) {
|
||||||
|
if (sharing.enabled == true && Config.Server.database.type == DatabaseType.memory) {
|
||||||
|
throw "Memory Database do not support sharing";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async testMapConfig(map: MapConfig) {
|
||||||
|
if (map.enabled == true && (!map.googleApiKey || map.googleApiKey.length == 0)) {
|
||||||
|
throw "Maps need a valid google api key";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async runDiagnostics() {
|
||||||
|
|
||||||
|
if (Config.Server.database.type == DatabaseType.mysql) {
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testDatabase(Config.Server.database);
|
||||||
|
} catch (err) {
|
||||||
|
Logger.warn(LOG_TAG, "[MYSQL error]", err);
|
||||||
|
Logger.warn(LOG_TAG, "Error during initializing mysql falling back to memory DB");
|
||||||
|
NotificationManager.warning("Error during initializing mysql falling back to memory DB", err);
|
||||||
|
Config.setDatabaseType(DatabaseType.memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.Server.thumbnail.processingLibrary != ThumbnailProcessingLib.Jimp) {
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testThumbnailLib(Config.Server.thumbnail.processingLibrary);
|
||||||
|
} catch (err) {
|
||||||
|
NotificationManager.warning("Thumbnail hardware acceleration is not possible." +
|
||||||
|
" '" + ThumbnailProcessingLib[Config.Server.thumbnail.processingLibrary] + "' node module is not found." +
|
||||||
|
" Falling back to JS based thumbnail generation", err);
|
||||||
|
Logger.warn(LOG_TAG, "[Thumbnail hardware acceleration] module error: ", err);
|
||||||
|
Logger.warn(LOG_TAG, "Thumbnail hardware acceleration is not possible." +
|
||||||
|
" '" + ThumbnailProcessingLib[Config.Server.thumbnail.processingLibrary] + "' node module is not found." +
|
||||||
|
" Falling back to JS based thumbnail generation");
|
||||||
|
Config.Server.thumbnail.processingLibrary = ThumbnailProcessingLib.Jimp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testThumbnailFolder(Config.Server.thumbnail.folder)
|
||||||
|
} catch (err) {
|
||||||
|
NotificationManager.error("Thumbnail folder error", err);
|
||||||
|
Logger.error(LOG_TAG, "Thumbnail folder error", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testImageFolder(Config.Server.imagesFolder)
|
||||||
|
} catch (err) {
|
||||||
|
NotificationManager.error("Images folder error", err);
|
||||||
|
Logger.error(LOG_TAG, "Images folder error", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testSearchConfig(Config.Client.Search);
|
||||||
|
} catch (err) {
|
||||||
|
NotificationManager.warning("Search is not supported with these settings, switching off..", err);
|
||||||
|
Logger.warn(LOG_TAG, "Search is not supported with these settings, switching off..", err);
|
||||||
|
Config.Client.Search.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing);
|
||||||
|
} catch (err) {
|
||||||
|
NotificationManager.warning("Sharing is not supported with these settings, switching off..", err);
|
||||||
|
Logger.warn(LOG_TAG, "Sharing is not supported with these settings, switching off..", err);
|
||||||
|
Config.Client.Sharing.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testMapConfig(Config.Client.Map);
|
||||||
|
} catch (err) {
|
||||||
|
NotificationManager.warning("Maps is not supported with these settings, switching off..", err);
|
||||||
|
Logger.warn(LOG_TAG, "Maps is not supported with these settings, switching off..", err);
|
||||||
|
Config.Client.Map.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,7 +14,8 @@ export class ObjectManagerRepository {
|
|||||||
private static _instance: ObjectManagerRepository = null;
|
private static _instance: ObjectManagerRepository = null;
|
||||||
|
|
||||||
|
|
||||||
public static InitMemoryManagers() {
|
public static async InitMemoryManagers() {
|
||||||
|
await ObjectManagerRepository.reset();
|
||||||
const GalleryManager = require("./memory/GalleryManager").GalleryManager;
|
const GalleryManager = require("./memory/GalleryManager").GalleryManager;
|
||||||
const UserManager = require("./memory/UserManager").UserManager;
|
const UserManager = require("./memory/UserManager").UserManager;
|
||||||
const SearchManager = require("./memory/SearchManager").SearchManager;
|
const SearchManager = require("./memory/SearchManager").SearchManager;
|
||||||
@ -26,6 +27,7 @@ export class ObjectManagerRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async InitMySQLManagers() {
|
public static async InitMySQLManagers() {
|
||||||
|
await ObjectManagerRepository.reset();
|
||||||
await MySQLConnection.init();
|
await MySQLConnection.init();
|
||||||
const GalleryManager = require("./mysql/GalleryManager").GalleryManager;
|
const GalleryManager = require("./mysql/GalleryManager").GalleryManager;
|
||||||
const UserManager = require("./mysql/UserManager").UserManager;
|
const UserManager = require("./mysql/UserManager").UserManager;
|
||||||
@ -45,7 +47,8 @@ export class ObjectManagerRepository {
|
|||||||
return this._instance;
|
return this._instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static reset() {
|
public static async reset() {
|
||||||
|
await MySQLConnection.close();
|
||||||
this._instance = null;
|
this._instance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,5 +4,4 @@ export interface ISearchManager {
|
|||||||
autocomplete(text: string): Promise<AutoCompleteItem[]>;
|
autocomplete(text: string): Promise<AutoCompleteItem[]>;
|
||||||
search(text: string, searchType: SearchTypes): Promise<SearchResultDTO>;
|
search(text: string, searchType: SearchTypes): Promise<SearchResultDTO>;
|
||||||
instantSearch(text: string): Promise<SearchResultDTO>;
|
instantSearch(text: string): Promise<SearchResultDTO>;
|
||||||
isSupported(): boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,5 +3,4 @@ export interface ISharingManager {
|
|||||||
findOne(filter: any): Promise<SharingDTO>;
|
findOne(filter: any): Promise<SharingDTO>;
|
||||||
createSharing(sharing: SharingDTO): Promise<SharingDTO>;
|
createSharing(sharing: SharingDTO): Promise<SharingDTO>;
|
||||||
updateSharing(sharing: SharingDTO): Promise<SharingDTO>;
|
updateSharing(sharing: SharingDTO): Promise<SharingDTO>;
|
||||||
isSupported(): boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,10 +15,4 @@ export class SearchManager implements ISearchManager {
|
|||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
isSupported(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,6 @@ import {SharingDTO} from "../../../common/entities/SharingDTO";
|
|||||||
|
|
||||||
export class SharingManager implements ISharingManager {
|
export class SharingManager implements ISharingManager {
|
||||||
|
|
||||||
isSupported(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
findOne(filter: any): Promise<SharingDTO> {
|
findOne(filter: any): Promise<SharingDTO> {
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
|
|||||||
@ -86,7 +86,7 @@ export class MySQLConnection {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async init(): Promise<void> {
|
public static async init(): Promise<void> {
|
||||||
const connection = await this.getConnection();
|
const connection = await this.getConnection();
|
||||||
let userRepository = connection.getRepository(UserEntity);
|
let userRepository = connection.getRepository(UserEntity);
|
||||||
let admins = await userRepository.find({role: UserRoles.Admin});
|
let admins = await userRepository.find({role: UserRoles.Admin});
|
||||||
@ -100,5 +100,12 @@ export class MySQLConnection {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async close() {
|
||||||
|
try {
|
||||||
|
await getConnection().close();
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,10 +8,6 @@ import {PositionMetaData} from "../../../common/entities/PhotoDTO";
|
|||||||
|
|
||||||
export class SearchManager implements ISearchManager {
|
export class SearchManager implements ISearchManager {
|
||||||
|
|
||||||
isSupported(): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async autocomplete(text: string) {
|
async autocomplete(text: string) {
|
||||||
|
|
||||||
const connection = await MySQLConnection.getConnection();
|
const connection = await MySQLConnection.getConnection();
|
||||||
|
|||||||
@ -7,10 +7,6 @@ import {PasswordHelper} from "../PasswordHelper";
|
|||||||
|
|
||||||
export class SharingManager implements ISharingManager {
|
export class SharingManager implements ISharingManager {
|
||||||
|
|
||||||
isSupported(): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async removeExpiredLink() {
|
private async removeExpiredLink() {
|
||||||
const connection = await MySQLConnection.getConnection();
|
const connection = await MySQLConnection.getConnection();
|
||||||
return connection
|
return connection
|
||||||
|
|||||||
@ -9,24 +9,21 @@ import * as exif_parser from "exif-parser";
|
|||||||
import {ProjectPath} from "../../ProjectPath";
|
import {ProjectPath} from "../../ProjectPath";
|
||||||
|
|
||||||
const LOG_TAG = "[DiskManagerTask]";
|
const LOG_TAG = "[DiskManagerTask]";
|
||||||
|
|
||||||
|
|
||||||
export class DiskMangerWorker {
|
export class DiskMangerWorker {
|
||||||
private static isImage(fullPath: string) {
|
private static isImage(fullPath: string) {
|
||||||
let imageMimeTypes = [
|
const extensions = [
|
||||||
'bmp',
|
'.bmp',
|
||||||
'gif',
|
'.gif',
|
||||||
'jpeg', 'jpg', 'jpe',
|
'.jpeg', '.jpg', '.jpe',
|
||||||
'png',
|
'.png',
|
||||||
'tiff', 'tif',
|
'.tiff', '.tif',
|
||||||
'webp',
|
'.webp',
|
||||||
'ico',
|
'.ico',
|
||||||
'tga'
|
'.tga'
|
||||||
];
|
];
|
||||||
|
|
||||||
let extension = path.extname(fullPath).toLowerCase();
|
const extension = path.extname(fullPath).toLowerCase();
|
||||||
|
return extensions.indexOf(extension) !== -1;
|
||||||
return imageMimeTypes.indexOf(extension) !== -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static loadPhotoMetadata(fullPath: string): Promise<PhotoMetadata> {
|
private static loadPhotoMetadata(fullPath: string): Promise<PhotoMetadata> {
|
||||||
|
|||||||
@ -48,6 +48,20 @@ export class AdminRouter {
|
|||||||
AdminMWs.testDatabaseSettings,
|
AdminMWs.testDatabaseSettings,
|
||||||
RenderingMWs.renderOK
|
RenderingMWs.renderOK
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.put("/api/settings/map",
|
||||||
|
AuthenticationMWs.authenticate,
|
||||||
|
AuthenticationMWs.authorise(UserRoles.Admin),
|
||||||
|
AdminMWs.updateMapSettings,
|
||||||
|
RenderingMWs.renderOK
|
||||||
|
);
|
||||||
|
|
||||||
|
app.post("/api/settings/test/map",
|
||||||
|
AuthenticationMWs.authenticate,
|
||||||
|
AuthenticationMWs.authorise(UserRoles.Admin),
|
||||||
|
AdminMWs.testMapSettings,
|
||||||
|
RenderingMWs.renderOK
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,39 +4,42 @@ import * as _path from "path";
|
|||||||
import {Utils} from "../../common/Utils";
|
import {Utils} from "../../common/Utils";
|
||||||
import {Config} from "../../common/config/private/Config";
|
import {Config} from "../../common/config/private/Config";
|
||||||
import {ProjectPath} from "../ProjectPath";
|
import {ProjectPath} from "../ProjectPath";
|
||||||
|
import {AuthenticationMWs} from "../middlewares/user/AuthenticationMWs";
|
||||||
|
|
||||||
export class PublicRouter {
|
export class PublicRouter {
|
||||||
|
|
||||||
public static route(app) {
|
public static route(app) {
|
||||||
app.use((req: Request, res: Response, next: NextFunction) => {
|
const renderIndex = (req: Request, res: Response) => {
|
||||||
res.tpl = {};
|
res.sendFile(_path.resolve(__dirname, './../../dist/index.html'));
|
||||||
|
};
|
||||||
|
|
||||||
res.tpl.user = null;
|
app.use(
|
||||||
if (req.session.user) {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
let user = Utils.clone(req.session.user);
|
res.tpl = {};
|
||||||
delete user.password;
|
|
||||||
res.tpl.user = user;
|
|
||||||
}
|
|
||||||
res.tpl.clientConfig = Config.Client;
|
|
||||||
|
|
||||||
return next();
|
res.tpl.user = null;
|
||||||
});
|
if (req.session.user) {
|
||||||
|
let user = Utils.clone(req.session.user);
|
||||||
|
delete user.password;
|
||||||
|
res.tpl.user = user;
|
||||||
|
}
|
||||||
|
res.tpl.clientConfig = Config.Client;
|
||||||
|
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/config_inject.js', (req: Request, res: Response) => {
|
app.get('/config_inject.js', (req: Request, res: Response) => {
|
||||||
res.render(_path.resolve(__dirname, './../../dist/config_inject.ejs'), res.tpl);
|
res.render(_path.resolve(__dirname, './../../dist/config_inject.ejs'), res.tpl);
|
||||||
});
|
});
|
||||||
app.get(['/', '/login', "/gallery*", "/share*", "/admin", "/search*"], (req: Request, res: Response) => {
|
app.get(['/', '/login', "/gallery*", "/share*", "/admin", "/search*"],
|
||||||
res.sendFile(_path.resolve(__dirname, './../../dist/index.html'));
|
AuthenticationMWs.tryAuthenticate,
|
||||||
});
|
renderIndex
|
||||||
|
);
|
||||||
|
|
||||||
app.use(_express.static(ProjectPath.FrontendFolder));
|
app.use(_express.static(ProjectPath.FrontendFolder));
|
||||||
app.use('/node_modules', _express.static(_path.resolve(__dirname, './../../node_modules')));
|
app.use('/node_modules', _express.static(_path.resolve(__dirname, './../../node_modules')));
|
||||||
app.use('/common', _express.static(_path.resolve(__dirname, './../../common')));
|
app.use('/common', _express.static(_path.resolve(__dirname, './../../common')));
|
||||||
|
|
||||||
const renderIndex = (req: Request, res: Response) => {
|
|
||||||
res.render(_path.resolve(__dirname, './../../dist/index.html'));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,13 +11,12 @@ import {SharingRouter} from "./routes/SharingRouter";
|
|||||||
import {ObjectManagerRepository} from "./model/ObjectManagerRepository";
|
import {ObjectManagerRepository} from "./model/ObjectManagerRepository";
|
||||||
import {Logger} from "./Logger";
|
import {Logger} from "./Logger";
|
||||||
import {Config} from "../common/config/private/Config";
|
import {Config} from "../common/config/private/Config";
|
||||||
import {DatabaseType, ThumbnailProcessingLib} from "../common/config/private/IPrivateConfig";
|
import {DatabaseType} from "../common/config/private/IPrivateConfig";
|
||||||
import {LoggerRouter} from "./routes/LoggerRouter";
|
import {LoggerRouter} from "./routes/LoggerRouter";
|
||||||
import {ProjectPath} from "./ProjectPath";
|
|
||||||
import {ThumbnailGeneratorMWs} from "./middlewares/thumbnail/ThumbnailGeneratorMWs";
|
import {ThumbnailGeneratorMWs} from "./middlewares/thumbnail/ThumbnailGeneratorMWs";
|
||||||
import {DiskManager} from "./model/DiskManger";
|
import {DiskManager} from "./model/DiskManger";
|
||||||
import {NotificationRouter} from "./routes/NotificationRouter";
|
import {NotificationRouter} from "./routes/NotificationRouter";
|
||||||
import {NotificationManager} from "./model/NotifocationManager";
|
import {ConfigDiagnostics} from "./model/ConfigDiagnostics";
|
||||||
|
|
||||||
const LOG_TAG = "[server]";
|
const LOG_TAG = "[server]";
|
||||||
export class Server {
|
export class Server {
|
||||||
@ -34,7 +33,7 @@ export class Server {
|
|||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
Logger.info(LOG_TAG, "running diagnostics...");
|
Logger.info(LOG_TAG, "running diagnostics...");
|
||||||
await this.runDiagnostics();
|
await ConfigDiagnostics.runDiagnostics();
|
||||||
Logger.info(LOG_TAG, "using config:");
|
Logger.info(LOG_TAG, "using config:");
|
||||||
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
|
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
|
||||||
|
|
||||||
@ -67,6 +66,11 @@ export class Server {
|
|||||||
|
|
||||||
DiskManager.init();
|
DiskManager.init();
|
||||||
ThumbnailGeneratorMWs.init();
|
ThumbnailGeneratorMWs.init();
|
||||||
|
if (Config.Server.database.type == DatabaseType.mysql) {
|
||||||
|
await ObjectManagerRepository.InitMySQLManagers();
|
||||||
|
} else {
|
||||||
|
await ObjectManagerRepository.InitMemoryManagers();
|
||||||
|
}
|
||||||
|
|
||||||
PublicRouter.route(this.app);
|
PublicRouter.route(this.app);
|
||||||
|
|
||||||
@ -93,87 +97,6 @@ export class Server {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async runDiagnostics() {
|
|
||||||
|
|
||||||
|
|
||||||
if (Config.Server.database.type == DatabaseType.mysql) {
|
|
||||||
try {
|
|
||||||
await ObjectManagerRepository.InitMySQLManagers();
|
|
||||||
} catch (err) {
|
|
||||||
Logger.warn(LOG_TAG, "[MYSQL error]", err);
|
|
||||||
Logger.warn(LOG_TAG, "Error during initializing mysql falling back to memory DB");
|
|
||||||
|
|
||||||
NotificationManager.warning("Error during initializing mysql falling back to memory DB", err);
|
|
||||||
Config.setDatabaseType(DatabaseType.memory);
|
|
||||||
await ObjectManagerRepository.InitMemoryManagers();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await ObjectManagerRepository.InitMemoryManagers();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.Server.thumbnail.processingLibrary == ThumbnailProcessingLib.sharp) {
|
|
||||||
try {
|
|
||||||
const sharp = require("sharp");
|
|
||||||
sharp();
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
NotificationManager.warning("Thumbnail hardware acceleration is not possible." +
|
|
||||||
" 'Sharp' node module is not found." +
|
|
||||||
" Falling back to JS based thumbnail generation", err);
|
|
||||||
Logger.warn(LOG_TAG, "[Thumbnail hardware acceleration] sharp module error: ", err);
|
|
||||||
Logger.warn(LOG_TAG, "Thumbnail hardware acceleration is not possible." +
|
|
||||||
" 'Sharp' node module is not found." +
|
|
||||||
" Falling back to JS based thumbnail generation");
|
|
||||||
Config.Server.thumbnail.processingLibrary = ThumbnailProcessingLib.Jimp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (Config.Server.thumbnail.processingLibrary == ThumbnailProcessingLib.gm) {
|
|
||||||
try {
|
|
||||||
const gm = require("gm");
|
|
||||||
gm(ProjectPath.FrontendFolder + "/assets/icon.png").size((err, value) => {
|
|
||||||
if (!err) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NotificationManager.warning("Thumbnail hardware acceleration is not possible." +
|
|
||||||
" 'gm' node module is not found." +
|
|
||||||
" Falling back to JS based thumbnail generation", err);
|
|
||||||
Logger.warn(LOG_TAG, "[Thumbnail hardware acceleration] gm module error: ", err);
|
|
||||||
Logger.warn(LOG_TAG, "Thumbnail hardware acceleration is not possible." +
|
|
||||||
" 'gm' node module is not found." +
|
|
||||||
" Falling back to JS based thumbnail generation");
|
|
||||||
Config.Server.thumbnail.processingLibrary = ThumbnailProcessingLib.Jimp;
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
NotificationManager.warning("Thumbnail hardware acceleration is not possible." +
|
|
||||||
" 'gm' node module is not found." +
|
|
||||||
" Falling back to JS based thumbnail generation", err);
|
|
||||||
Logger.warn(LOG_TAG, "[Thumbnail hardware acceleration] gm module error: ", err);
|
|
||||||
Logger.warn(LOG_TAG, "Thumbnail hardware acceleration is not possible." +
|
|
||||||
" 'gm' node module is not found." +
|
|
||||||
" Falling back to JS based thumbnail generation");
|
|
||||||
Config.Server.thumbnail.processingLibrary = ThumbnailProcessingLib.Jimp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.Client.Search.searchEnabled == true &&
|
|
||||||
ObjectManagerRepository.getInstance().SearchManager.isSupported() == false) {
|
|
||||||
|
|
||||||
NotificationManager.warning("Search is not supported with these settings, switching off..");
|
|
||||||
Logger.warn(LOG_TAG, "Search is not supported with these settings, switching off..");
|
|
||||||
Config.Client.Search.searchEnabled = false;
|
|
||||||
}
|
|
||||||
if (Config.Client.Sharing.enabled == true &&
|
|
||||||
ObjectManagerRepository.getInstance().SharingManager.isSupported() == false) {
|
|
||||||
|
|
||||||
NotificationManager.warning("Sharing is not supported with these settings, switching off..");
|
|
||||||
Logger.warn(LOG_TAG, "Sharing is not supported with these settings, switching off..");
|
|
||||||
Config.Client.Sharing.enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event listener for HTTP server "error" event.
|
* Event listener for HTTP server "error" event.
|
||||||
|
|||||||
@ -19,10 +19,10 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
|||||||
database: {
|
database: {
|
||||||
type: DatabaseType.mysql,
|
type: DatabaseType.mysql,
|
||||||
mysql: {
|
mysql: {
|
||||||
host: "localhost",
|
host: "",
|
||||||
username: "root",
|
username: "",
|
||||||
password: "root",
|
password: "",
|
||||||
database: "pigallery2"
|
database: ""
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -36,9 +36,10 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
|||||||
public setDatabaseType(type: DatabaseType) {
|
public setDatabaseType(type: DatabaseType) {
|
||||||
this.Server.database.type = type;
|
this.Server.database.type = type;
|
||||||
if (type === DatabaseType.memory) {
|
if (type === DatabaseType.memory) {
|
||||||
this.Client.Search.searchEnabled = false;
|
this.Client.Search.enabled = false;
|
||||||
this.Client.Search.instantSearchEnabled = false;
|
this.Client.Search.instantSearchEnabled = false;
|
||||||
this.Client.Search.autocompleteEnabled = false;
|
this.Client.Search.autocompleteEnabled = false;
|
||||||
|
this.Client.Sharing.enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,26 +1,31 @@
|
|||||||
interface SearchConfig {
|
export interface SearchConfig {
|
||||||
searchEnabled: boolean
|
enabled: boolean
|
||||||
instantSearchEnabled: boolean
|
instantSearchEnabled: boolean
|
||||||
autocompleteEnabled: boolean
|
autocompleteEnabled: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SharingConfig {
|
export interface SharingConfig {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
passwordProtected: boolean;
|
passwordProtected: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MapConfig {
|
||||||
|
enabled: boolean;
|
||||||
|
googleApiKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ClientConfig {
|
export interface ClientConfig {
|
||||||
applicationTitle: string;
|
applicationTitle: string;
|
||||||
iconSize: number;
|
iconSize: number;
|
||||||
thumbnailSizes: Array<number>;
|
thumbnailSizes: Array<number>;
|
||||||
Search: SearchConfig;
|
Search: SearchConfig;
|
||||||
Sharing: SharingConfig;
|
Sharing: SharingConfig;
|
||||||
|
Map: MapConfig;
|
||||||
concurrentThumbnailGenerations: number;
|
concurrentThumbnailGenerations: number;
|
||||||
enableCache: boolean;
|
enableCache: boolean;
|
||||||
enableOnScrollRendering: boolean;
|
enableOnScrollRendering: boolean;
|
||||||
enableOnScrollThumbnailPrioritising: boolean;
|
enableOnScrollThumbnailPrioritising: boolean;
|
||||||
authenticationRequired: boolean;
|
authenticationRequired: boolean;
|
||||||
googleApiKey: string;
|
|
||||||
publicUrl: string;
|
publicUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +39,7 @@ export class PublicConfigClass {
|
|||||||
thumbnailSizes: [200, 400, 600],
|
thumbnailSizes: [200, 400, 600],
|
||||||
iconSize: 30,
|
iconSize: 30,
|
||||||
Search: {
|
Search: {
|
||||||
searchEnabled: true,
|
enabled: true,
|
||||||
instantSearchEnabled: true,
|
instantSearchEnabled: true,
|
||||||
autocompleteEnabled: true
|
autocompleteEnabled: true
|
||||||
},
|
},
|
||||||
@ -42,12 +47,15 @@ export class PublicConfigClass {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
passwordProtected: true
|
passwordProtected: true
|
||||||
},
|
},
|
||||||
|
Map: {
|
||||||
|
enabled: true,
|
||||||
|
googleApiKey: ""
|
||||||
|
},
|
||||||
concurrentThumbnailGenerations: 1,
|
concurrentThumbnailGenerations: 1,
|
||||||
enableCache: false,
|
enableCache: false,
|
||||||
enableOnScrollRendering: true,
|
enableOnScrollRendering: true,
|
||||||
enableOnScrollThumbnailPrioritising: true,
|
enableOnScrollThumbnailPrioritising: true,
|
||||||
authenticationRequired: true,
|
authenticationRequired: true,
|
||||||
googleApiKey: "",
|
|
||||||
publicUrl: ""
|
publicUrl: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -23,5 +23,6 @@
|
|||||||
|
|
||||||
<settings-usermanager *ngIf="userManagementEnable"></settings-usermanager>
|
<settings-usermanager *ngIf="userManagementEnable"></settings-usermanager>
|
||||||
<settings-database></settings-database>
|
<settings-database></settings-database>
|
||||||
|
<settings-map></settings-map>
|
||||||
</div>
|
</div>
|
||||||
</app-frame>
|
</app-frame>
|
||||||
|
|||||||
@ -41,17 +41,18 @@ import {DatabaseSettingsComponent} from "./settings/database/database.settings.c
|
|||||||
import {ToastModule} from "ng2-toastr/ng2-toastr";
|
import {ToastModule} from "ng2-toastr/ng2-toastr";
|
||||||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||||
import {NotificationService} from "./model/notification.service";
|
import {NotificationService} from "./model/notification.service";
|
||||||
|
import {JWBootstrapSwitchModule} from "jw-bootstrap-switch-ng2";
|
||||||
import {ClipboardModule} from "ngx-clipboard";
|
import {ClipboardModule} from "ngx-clipboard";
|
||||||
import {NavigationService} from "./model/navigation.service";
|
import {NavigationService} from "./model/navigation.service";
|
||||||
import {InfoPanelLightboxComponent} from "./gallery/lightbox/infopanel/info-panel.lightbox.gallery.component";
|
import {InfoPanelLightboxComponent} from "./gallery/lightbox/infopanel/info-panel.lightbox.gallery.component";
|
||||||
|
import {MapSettingsComponent} from "./settings/map/map.settings.component";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GoogleMapsConfig {
|
export class GoogleMapsConfig {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.apiKey = Config.Client.googleApiKey;
|
this.apiKey = Config.Client.Map.googleApiKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ export class GoogleMapsConfig {
|
|||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
appRoutes,
|
appRoutes,
|
||||||
ClipboardModule,
|
ClipboardModule,
|
||||||
|
JWBootstrapSwitchModule,
|
||||||
ToastModule.forRoot(),
|
ToastModule.forRoot(),
|
||||||
ModalModule.forRoot(),
|
ModalModule.forRoot(),
|
||||||
AgmCoreModule.forRoot(),
|
AgmCoreModule.forRoot(),
|
||||||
@ -91,6 +93,7 @@ export class GoogleMapsConfig {
|
|||||||
//Settings
|
//Settings
|
||||||
UserMangerSettingsComponent,
|
UserMangerSettingsComponent,
|
||||||
DatabaseSettingsComponent,
|
DatabaseSettingsComponent,
|
||||||
|
MapSettingsComponent,
|
||||||
StringifyRole],
|
StringifyRole],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig},
|
{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig},
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
<ng-content select="[navbar]"></ng-content>
|
<ng-content select="[navbar]"></ng-content>
|
||||||
<li class="divider-vertical">
|
<li class="divider-vertical">
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li *ngIf="authenticationRequired">
|
||||||
<p class="navbar-text" *ngIf="user.value">
|
<p class="navbar-text" *ngIf="user.value">
|
||||||
<span class="glyphicon glyphicon-user" aria-hidden="true"></span> {{user.value.name}}</p>
|
<span class="glyphicon glyphicon-user" aria-hidden="true"></span> {{user.value.name}}</p>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@ -24,7 +24,8 @@
|
|||||||
<gallery-directory *ngFor="let directory of directories"
|
<gallery-directory *ngFor="let directory of directories"
|
||||||
[directory]="directory"></gallery-directory>
|
[directory]="directory"></gallery-directory>
|
||||||
</div>
|
</div>
|
||||||
<gallery-map *ngIf="isPhotoWithLocation" [photos]="_galleryService.content.value.directory.photos"></gallery-map>
|
<gallery-map *ngIf="isPhotoWithLocation && mapEnabled"
|
||||||
|
[photos]="_galleryService.content.value.directory.photos"></gallery-map>
|
||||||
<gallery-grid [photos]="_galleryService.content.value.directory.photos" [lightbox]="lightbox"></gallery-grid>
|
<gallery-grid [photos]="_galleryService.content.value.directory.photos" [lightbox]="lightbox"></gallery-grid>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -42,7 +43,8 @@
|
|||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<gallery-map *ngIf="isPhotoWithLocation" [photos]="_galleryService.content.value.searchResult.photos"></gallery-map>
|
<gallery-map *ngIf="isPhotoWithLocation && mapEnabled"
|
||||||
|
[photos]="_galleryService.content.value.searchResult.photos"></gallery-map>
|
||||||
|
|
||||||
<div class="directories">
|
<div class="directories">
|
||||||
<gallery-directory *ngFor="let directory of directories"
|
<gallery-directory *ngFor="let directory of directories"
|
||||||
|
|||||||
@ -34,6 +34,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
|||||||
timer: null
|
timer: null
|
||||||
};
|
};
|
||||||
public countDown = null;
|
public countDown = null;
|
||||||
|
public mapEnabled = true;
|
||||||
|
|
||||||
constructor(public _galleryService: GalleryService,
|
constructor(public _galleryService: GalleryService,
|
||||||
private _authService: AuthenticationService,
|
private _authService: AuthenticationService,
|
||||||
@ -41,6 +42,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
|||||||
private shareService: ShareService,
|
private shareService: ShareService,
|
||||||
private _route: ActivatedRoute,
|
private _route: ActivatedRoute,
|
||||||
private _navigation: NavigationService) {
|
private _navigation: NavigationService) {
|
||||||
|
this.mapEnabled = Config.Client.Map.enabled;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
return this._navigation.toLogin();
|
return this._navigation.toLogin();
|
||||||
}
|
}
|
||||||
this.showSearchBar = Config.Client.Search.searchEnabled && this._authService.isAuthorized(UserRoles.Guest);
|
this.showSearchBar = Config.Client.Search.enabled && this._authService.isAuthorized(UserRoles.Guest);
|
||||||
this.showShare = Config.Client.Sharing.enabled && this._authService.isAuthorized(UserRoles.User);
|
this.showShare = Config.Client.Sharing.enabled && this._authService.isAuthorized(UserRoles.User);
|
||||||
|
|
||||||
this.subscription.content = this._galleryService.content.subscribe(this.onContentChange);
|
this.subscription.content = this._galleryService.content.subscribe(this.onContentChange);
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit {
|
|||||||
photosToRender: Array<GridPhoto> = [];
|
photosToRender: Array<GridPhoto> = [];
|
||||||
containerWidth: number = 0;
|
containerWidth: number = 0;
|
||||||
|
|
||||||
private IMAGE_MARGIN = 2;
|
public IMAGE_MARGIN = 2;
|
||||||
private TARGET_COL_COUNT = 5;
|
private TARGET_COL_COUNT = 5;
|
||||||
private MIN_ROW_COUNT = 2;
|
private MIN_ROW_COUNT = 2;
|
||||||
private MAX_ROW_COUNT = 5;
|
private MAX_ROW_COUNT = 5;
|
||||||
|
|||||||
@ -43,7 +43,7 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, OnDestroy {
|
|||||||
|
|
||||||
constructor(private thumbnailService: ThumbnailManagerService) {
|
constructor(private thumbnailService: ThumbnailManagerService) {
|
||||||
this.SearchTypes = SearchTypes;
|
this.SearchTypes = SearchTypes;
|
||||||
this.searchEnabled = Config.Client.Search.searchEnabled;
|
this.searchEnabled = Config.Client.Search.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|||||||
@ -76,7 +76,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="map" *ngIf="hasGPS()">
|
<div id="map" *ngIf="hasGPS() && mapEnabled">
|
||||||
<agm-map
|
<agm-map
|
||||||
[disableDefaultUI]="true"
|
[disableDefaultUI]="true"
|
||||||
[zoomControl]="false"
|
[zoomControl]="false"
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import {Component, ElementRef, Input} from "@angular/core";
|
import {Component, ElementRef, Input} from "@angular/core";
|
||||||
import {PhotoDTO} from "../../../../../common/entities/PhotoDTO";
|
import {PhotoDTO} from "../../../../../common/entities/PhotoDTO";
|
||||||
|
import {Config} from "../../../../../common/config/public/Config";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'info-panel',
|
selector: 'info-panel',
|
||||||
@ -9,8 +10,10 @@ import {PhotoDTO} from "../../../../../common/entities/PhotoDTO";
|
|||||||
export class InfoPanelLightboxComponent {
|
export class InfoPanelLightboxComponent {
|
||||||
@Input() photo: PhotoDTO;
|
@Input() photo: PhotoDTO;
|
||||||
|
|
||||||
|
public mapEnabled = true;
|
||||||
|
|
||||||
constructor(public elementRef: ElementRef) {
|
constructor(public elementRef: ElementRef) {
|
||||||
|
this.mapEnabled = Config.Client.Map.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
calcMpx() {
|
calcMpx() {
|
||||||
|
|||||||
@ -61,7 +61,7 @@ export class GallerySearchComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onSearch() {
|
public onSearch() {
|
||||||
if (Config.Client.Search.searchEnabled) {
|
if (Config.Client.Search.enabled) {
|
||||||
this._galleryService.search(this.searchText);
|
this._galleryService.search(this.searchText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,9 +18,11 @@ export class AuthenticationService {
|
|||||||
constructor(private _userService: UserService) {
|
constructor(private _userService: UserService) {
|
||||||
this.user = new BehaviorSubject(null);
|
this.user = new BehaviorSubject(null);
|
||||||
|
|
||||||
|
console.log(ServerInject.user);
|
||||||
//picking up session..
|
//picking up session..
|
||||||
if (this.isAuthenticated() == false && Cookie.get('pigallery2-session') != null) {
|
if (this.isAuthenticated() == false && Cookie.get('pigallery2-session') != null) {
|
||||||
if (typeof ServerInject !== "undefined" && typeof ServerInject.user !== "undefined") {
|
if (typeof ServerInject !== "undefined" && typeof ServerInject.user !== "undefined") {
|
||||||
|
console.log(ServerInject.user);
|
||||||
this.user.next(ServerInject.user);
|
this.user.next(ServerInject.user);
|
||||||
}
|
}
|
||||||
this.getSessionUser();
|
this.getSessionUser();
|
||||||
|
|||||||
@ -0,0 +1,93 @@
|
|||||||
|
import {OnDestroy, OnInit, ViewChild} from "@angular/core";
|
||||||
|
import {AuthenticationService} from "../../model/network/authentication.service";
|
||||||
|
import {UserRoles} from "../../../../common/entities/UserDTO";
|
||||||
|
import {Utils} from "../../../../common/Utils";
|
||||||
|
import {Error} from "../../../../common/entities/Error";
|
||||||
|
import {NotificationService} from "../../model/notification.service";
|
||||||
|
import {NavigationService} from "../../model/navigation.service";
|
||||||
|
import {ISettingsService} from "./abstract.settings.service";
|
||||||
|
|
||||||
|
|
||||||
|
export abstract class SettingsComponent<T> implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@ViewChild('settingsForm') form;
|
||||||
|
public settings: T;
|
||||||
|
public inProgress = false;
|
||||||
|
private original: T;
|
||||||
|
public tested = false;
|
||||||
|
public error: string = null;
|
||||||
|
public changed: boolean = false;
|
||||||
|
private subscription;
|
||||||
|
|
||||||
|
constructor(private name,
|
||||||
|
private _authService: AuthenticationService,
|
||||||
|
private _navigation: NavigationService,
|
||||||
|
protected _settingsService: ISettingsService<T>,
|
||||||
|
private notification: NotificationService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (!this._authService.isAuthenticated() ||
|
||||||
|
this._authService.user.value.role < UserRoles.Admin) {
|
||||||
|
this._navigation.toLogin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.original = Utils.clone(this.settings);
|
||||||
|
this.getSettings();
|
||||||
|
|
||||||
|
this.subscription = this.form.valueChanges.subscribe((data) => {
|
||||||
|
this.changed = !Utils.equalsFilter(this.settings, this.original);
|
||||||
|
|
||||||
|
this.tested = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.subscription != null) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getSettings() {
|
||||||
|
const s = await this._settingsService.getSettings();
|
||||||
|
this.original = Utils.clone(s);
|
||||||
|
this.settings = s;
|
||||||
|
this.tested = false;
|
||||||
|
this.changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public reset() {
|
||||||
|
this.getSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async test() {
|
||||||
|
this.inProgress = true;
|
||||||
|
try {
|
||||||
|
this.error = "";
|
||||||
|
await this._settingsService.testSettings(this.settings);
|
||||||
|
this.tested = true;
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
if (err.message) {
|
||||||
|
this.error = (<Error>err).message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.inProgress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async save() {
|
||||||
|
if (!this.tested) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.inProgress = true;
|
||||||
|
await this._settingsService.updateSettings(this.settings);
|
||||||
|
await this.getSettings();
|
||||||
|
this.notification.success(this.name + ' settings saved', "Success");
|
||||||
|
this.inProgress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
export interface ISettingsService<T> {
|
||||||
|
getSettings(): Promise<T>;
|
||||||
|
updateSettings(settings: T): Promise<void>;
|
||||||
|
testSettings(settings: T): Promise<void> ;
|
||||||
|
}
|
||||||
@ -1,12 +1,11 @@
|
|||||||
import {Component, OnInit, ViewChild} from "@angular/core";
|
import {Component} from "@angular/core";
|
||||||
import {AuthenticationService} from "../../model/network/authentication.service";
|
import {AuthenticationService} from "../../model/network/authentication.service";
|
||||||
import {Router} from "@angular/router";
|
|
||||||
import {UserRoles} from "../../../../common/entities/UserDTO";
|
|
||||||
import {DatabaseSettingsService} from "./database.settings.service";
|
|
||||||
import {DataBaseConfig, DatabaseType} from "../../../../common/config/private/IPrivateConfig";
|
import {DataBaseConfig, DatabaseType} from "../../../../common/config/private/IPrivateConfig";
|
||||||
import {Utils} from "../../../../common/Utils";
|
import {Utils} from "../../../../common/Utils";
|
||||||
import {Error} from "../../../../common/entities/Error";
|
|
||||||
import {NotificationService} from "../../model/notification.service";
|
import {NotificationService} from "../../model/notification.service";
|
||||||
|
import {NavigationService} from "../../model/navigation.service";
|
||||||
|
import {SettingsComponent} from "../_abstract/abstract.settings.component";
|
||||||
|
import {DatabaseSettingsService} from "./database.settings.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'settings-database',
|
selector: 'settings-database',
|
||||||
@ -14,84 +13,28 @@ import {NotificationService} from "../../model/notification.service";
|
|||||||
styleUrls: ['./database.settings.component.css'],
|
styleUrls: ['./database.settings.component.css'],
|
||||||
providers: [DatabaseSettingsService],
|
providers: [DatabaseSettingsService],
|
||||||
})
|
})
|
||||||
export class DatabaseSettingsComponent implements OnInit {
|
export class DatabaseSettingsComponent extends SettingsComponent<DataBaseConfig> {
|
||||||
@ViewChild('settingsForm') form;
|
|
||||||
|
|
||||||
public settings: DataBaseConfig = <DataBaseConfig> {
|
public settings: DataBaseConfig = <DataBaseConfig> {
|
||||||
type: DatabaseType.memory,
|
type: DatabaseType.memory,
|
||||||
mysql: {}
|
mysql: {}
|
||||||
};
|
};
|
||||||
inProgress = false;
|
|
||||||
private original: DataBaseConfig;
|
|
||||||
public types: Array<any> = [];
|
public types: Array<any> = [];
|
||||||
public DatabaseType: any;
|
public DatabaseType: any;
|
||||||
public tested = false;
|
|
||||||
public error: string = null;
|
|
||||||
public changed: boolean = false;
|
|
||||||
|
|
||||||
constructor(private _authService: AuthenticationService,
|
constructor(_authService: AuthenticationService,
|
||||||
private _router: Router,
|
_navigation: NavigationService,
|
||||||
private _dbSettings: DatabaseSettingsService,
|
_dbSettings: DatabaseSettingsService,
|
||||||
private notification: NotificationService) {
|
notification: NotificationService) {
|
||||||
this.original = Utils.clone(this.settings);
|
super("Database", _authService, _navigation, _dbSettings, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (!this._authService.isAuthenticated() ||
|
super.ngOnInit();
|
||||||
this._authService.user.value.role < UserRoles.Admin) {
|
|
||||||
this._router.navigate(['login']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.types = Utils
|
this.types = Utils
|
||||||
.enumToArray(DatabaseType);
|
.enumToArray(DatabaseType);
|
||||||
this.DatabaseType = DatabaseType;
|
this.DatabaseType = DatabaseType;
|
||||||
this.getSettings();
|
|
||||||
|
|
||||||
this.form.valueChanges.subscribe((data) => {
|
|
||||||
this.changed = !Utils.equalsFilter(this.settings, this.original);
|
|
||||||
|
|
||||||
this.tested = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getSettings() {
|
|
||||||
const s = await this._dbSettings.getSettings();
|
|
||||||
this.original = Utils.clone(s);
|
|
||||||
this.settings = s;
|
|
||||||
this.tested = false;
|
|
||||||
this.changed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public reset() {
|
|
||||||
this.getSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public async test() {
|
|
||||||
this.inProgress = true;
|
|
||||||
try {
|
|
||||||
this.error = "";
|
|
||||||
await this._dbSettings.testSettings(this.settings);
|
|
||||||
this.tested = true;
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
if (err.message) {
|
|
||||||
this.error = (<Error>err).message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.inProgress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async save() {
|
|
||||||
if (typeof this.settings.type == "undefined" || !this.tested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.inProgress = true;
|
|
||||||
await this._dbSettings.updateSettings(this.settings);
|
|
||||||
await this.getSettings();
|
|
||||||
this.notification.success('Database settings saved', "Success");
|
|
||||||
this.inProgress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +1,21 @@
|
|||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {NetworkService} from "../../model/network/network.service";
|
import {NetworkService} from "../../model/network/network.service";
|
||||||
import {DataBaseConfig, IPrivateConfig} from "../../../../common/config/private/IPrivateConfig";
|
import {DataBaseConfig, IPrivateConfig} from "../../../../common/config/private/IPrivateConfig";
|
||||||
import {NavigationService} from "../../model/navigation.service";
|
|
||||||
import {UserRoles} from "../../../../common/entities/UserDTO";
|
|
||||||
import {AuthenticationService} from "../../model/network/authentication.service";
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DatabaseSettingsService {
|
export class DatabaseSettingsService {
|
||||||
|
constructor(private _networkService: NetworkService) {
|
||||||
|
|
||||||
constructor(private _networkService: NetworkService, private _authService: AuthenticationService, private _navigation: NavigationService) {
|
|
||||||
|
|
||||||
if (!this._authService.isAuthenticated() ||
|
|
||||||
this._authService.user.value.role < UserRoles.Admin) {
|
|
||||||
this._navigation.toLogin();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getSettings(): Promise<DataBaseConfig> {
|
public async getSettings(): Promise<DataBaseConfig> {
|
||||||
return (await <Promise<IPrivateConfig>>this._networkService.getJson("/settings")).Server.database;
|
return (await <Promise<IPrivateConfig>>this._networkService.getJson("/settings")).Server.database;
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateSettings(settings): Promise<void> {
|
public updateSettings(settings: DataBaseConfig): Promise<void> {
|
||||||
return this._networkService.putJson("/settings/database", {databaseSettings: settings});
|
return this._networkService.putJson("/settings/database", {settings: settings});
|
||||||
}
|
}
|
||||||
|
|
||||||
public testSettings(settings): Promise<void> {
|
public testSettings(settings: DataBaseConfig): Promise<void> {
|
||||||
return this._networkService.postJson<void>("/settings/test/database", {databaseSettings: settings});
|
return this._networkService.postJson<void>("/settings/test/database", {settings: settings});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
frontend/app/settings/map/map.settings.component.css
Normal file
11
frontend/app/settings/map/map.settings.component.css
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.title {
|
||||||
|
margin-left: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
42
frontend/app/settings/map/map.settings.component.html
Normal file
42
frontend/app/settings/map/map.settings.component.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Map settings</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||||
|
<form #settingsForm="ngForm">
|
||||||
|
<p>
|
||||||
|
<bSwitch
|
||||||
|
name="enabled"
|
||||||
|
[switch-on-color]="'success'"
|
||||||
|
[switch-inverse]="'inverse'"
|
||||||
|
[switch-off-text]="'Disabled'"
|
||||||
|
[switch-on-text]="'Enabled'"
|
||||||
|
[switch-handle-width]="'100'"
|
||||||
|
[switch-label-width]="'20'"
|
||||||
|
[(ngModel)]="settings.enabled">
|
||||||
|
</bSwitch>
|
||||||
|
</p>
|
||||||
|
<input type="text" class="form-control" placeholder="Google api key" autofocus
|
||||||
|
[(ngModel)]="settings.googleApiKey"
|
||||||
|
[disabled]="!settings.enabled"
|
||||||
|
name="googleApiKey" required>
|
||||||
|
<span class="help-block">To show the images on a map, <a
|
||||||
|
href="https://developers.google.com/maps/documentation/javascript/get-api-key">google api key</a> is need</span>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
<button class="btn btn-primary pull-right"
|
||||||
|
*ngIf="tested==false"
|
||||||
|
[disabled]="!settingsForm.form.valid || !changed || inProgress"
|
||||||
|
(click)="test()">Test
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-success pull-right"
|
||||||
|
*ngIf="tested==true"
|
||||||
|
[disabled]="!settingsForm.form.valid || !changed || inProgress"
|
||||||
|
(click)="save()">Save
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-default pull-right"
|
||||||
|
(click)="reset()">Reset
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
32
frontend/app/settings/map/map.settings.component.ts
Normal file
32
frontend/app/settings/map/map.settings.component.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import {Component} from "@angular/core";
|
||||||
|
import {MapConfig} from "../../../../common/config/public/ConfigClass";
|
||||||
|
import {MapSettingsService} from "./map.settings.service";
|
||||||
|
import {SettingsComponent} from "../_abstract/abstract.settings.component";
|
||||||
|
import {AuthenticationService} from "../../model/network/authentication.service";
|
||||||
|
import {NavigationService} from "../../model/navigation.service";
|
||||||
|
import {NotificationService} from "../../model/notification.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'settings-map',
|
||||||
|
templateUrl: './map.settings.component.html',
|
||||||
|
styleUrls: ['./map.settings.component.css'],
|
||||||
|
providers: [MapSettingsService],
|
||||||
|
})
|
||||||
|
export class MapSettingsComponent extends SettingsComponent<MapConfig> {
|
||||||
|
public settings: MapConfig = <MapConfig> {
|
||||||
|
enabled: true,
|
||||||
|
googleApiKey: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(_authService: AuthenticationService,
|
||||||
|
_navigation: NavigationService,
|
||||||
|
_settingsSettings: MapSettingsService,
|
||||||
|
notification: NotificationService) {
|
||||||
|
super("Map", _authService, _navigation, _settingsSettings, notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
22
frontend/app/settings/map/map.settings.service.ts
Normal file
22
frontend/app/settings/map/map.settings.service.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
import {NetworkService} from "../../model/network/network.service";
|
||||||
|
import {MapConfig} from "../../../../common/config/public/ConfigClass";
|
||||||
|
import {IPrivateConfig} from "../../../../common/config/private/IPrivateConfig";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MapSettingsService {
|
||||||
|
constructor(private _networkService: NetworkService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getSettings(): Promise<MapConfig> {
|
||||||
|
return (await <Promise<IPrivateConfig>>this._networkService.getJson("/settings")).Client.Map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateSettings(settings: MapConfig): Promise<void> {
|
||||||
|
return this._networkService.putJson("/settings/map", {settings: settings});
|
||||||
|
}
|
||||||
|
|
||||||
|
public testSettings(settings: MapConfig): Promise<void> {
|
||||||
|
return this._networkService.postJson<void>("/settings/test/map", {settings: settings});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,8 @@
|
|||||||
<link rel="shortcut icon" href="assets/icon.png">
|
<link rel="shortcut icon" href="assets/icon.png">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="../node_modules/ng2-toastr/bundles/ng2-toastr.min.css" rel="stylesheet"/>
|
<link href="../node_modules/ng2-toastr/bundles/ng2-toastr.min.css" rel="stylesheet"/>
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.css">
|
||||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<script type="text/javascript" src="config_inject.js"></script>
|
<script type="text/javascript" src="config_inject.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@ -7,3 +7,7 @@
|
|||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bootstrap-switch-label {
|
||||||
|
margin-right: -4px;
|
||||||
|
margin-left: -4px;
|
||||||
|
}
|
||||||
|
|||||||
@ -74,6 +74,7 @@
|
|||||||
"intl": "^1.2.5",
|
"intl": "^1.2.5",
|
||||||
"jasmine-core": "^2.6.4",
|
"jasmine-core": "^2.6.4",
|
||||||
"jasmine-spec-reporter": "~4.1.1",
|
"jasmine-spec-reporter": "~4.1.1",
|
||||||
|
"jw-bootstrap-switch-ng2": "^1.0.3",
|
||||||
"karma": "^1.7.0",
|
"karma": "^1.7.0",
|
||||||
"karma-cli": "^1.0.1",
|
"karma-cli": "^1.0.1",
|
||||||
"karma-coverage-istanbul-reporter": "^1.3.0",
|
"karma-coverage-istanbul-reporter": "^1.3.0",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user