mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
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 {DataBaseConfig, DatabaseType} from "../../common/config/private/IPrivateConfig";
|
||||
import {Config} from "../../common/config/private/Config";
|
||||
import {ConfigDiagnostics} from "../model/ConfigDiagnostics";
|
||||
import {MapConfig} from "../../common/config/public/ConfigClass";
|
||||
|
||||
|
||||
const LOG_TAG = "[AdminMWs]";
|
||||
@ -13,18 +15,22 @@ export class AdminMWs {
|
||||
|
||||
public static async updateDatabaseSettings(req: Request, res: Response, next: NextFunction) {
|
||||
|
||||
if ((typeof req.body === 'undefined') || (typeof req.body.databaseSettings === 'undefined')) {
|
||||
return next(new Error(ErrorCodes.INPUT_ERROR, "databaseSettings is needed"));
|
||||
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
||||
return next(new Error(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
||||
}
|
||||
|
||||
const databaseSettings = <DataBaseConfig>req.body.databaseSettings;
|
||||
const databaseSettings = <DataBaseConfig>req.body.settings;
|
||||
|
||||
try {
|
||||
if (databaseSettings.type == DatabaseType.mysql) {
|
||||
await MySQLConnection.tryConnection(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, JSON.stringify(Config, null, '\t'));
|
||||
|
||||
@ -43,19 +49,55 @@ export class AdminMWs {
|
||||
|
||||
|
||||
public static async testDatabaseSettings(req: Request, res: Response, next: NextFunction) {
|
||||
if ((typeof req.body === 'undefined') || (typeof req.body.databaseSettings === 'undefined')) {
|
||||
return next(new Error(ErrorCodes.INPUT_ERROR, "databaseSettings is needed"));
|
||||
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
||||
return next(new Error(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
||||
}
|
||||
|
||||
const databaseSettings = <DataBaseConfig>req.body.databaseSettings;
|
||||
const databaseSettings = <DataBaseConfig>req.body.settings;
|
||||
|
||||
try {
|
||||
if (databaseSettings.type == DatabaseType.mysql) {
|
||||
await MySQLConnection.tryConnection(databaseSettings);
|
||||
await ConfigDiagnostics.testDatabase(databaseSettings);
|
||||
}
|
||||
return next();
|
||||
} catch (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) {
|
||||
if (Config.Client.Search.searchEnabled === false) {
|
||||
if (Config.Client.Search.enabled === false) {
|
||||
return next();
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import {Config} from "../../common/config/private/Config";
|
||||
import {PrivateConfigClass} from "../../common/config/private/PrivateConfigClass";
|
||||
import {UserRoles} from "../../common/entities/UserDTO";
|
||||
import {NotificationManager} from "../model/NotifocationManager";
|
||||
import {Logger} from "../Logger";
|
||||
|
||||
export class RenderingMWs {
|
||||
|
||||
@ -59,8 +60,17 @@ export class RenderingMWs {
|
||||
public static renderError(err: any, req: Request, res: Response, next: NextFunction): any {
|
||||
|
||||
if (err instanceof Error) {
|
||||
if (!(req.session.user && req.session.user.role >= UserRoles.Developer)) {
|
||||
delete (err.details);
|
||||
if (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);
|
||||
return res.json(message);
|
||||
|
@ -32,6 +32,24 @@ export class AuthenticationMWs {
|
||||
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) {
|
||||
|
||||
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;
|
||||
|
||||
|
||||
public static InitMemoryManagers() {
|
||||
public static async InitMemoryManagers() {
|
||||
await ObjectManagerRepository.reset();
|
||||
const GalleryManager = require("./memory/GalleryManager").GalleryManager;
|
||||
const UserManager = require("./memory/UserManager").UserManager;
|
||||
const SearchManager = require("./memory/SearchManager").SearchManager;
|
||||
@ -26,6 +27,7 @@ export class ObjectManagerRepository {
|
||||
}
|
||||
|
||||
public static async InitMySQLManagers() {
|
||||
await ObjectManagerRepository.reset();
|
||||
await MySQLConnection.init();
|
||||
const GalleryManager = require("./mysql/GalleryManager").GalleryManager;
|
||||
const UserManager = require("./mysql/UserManager").UserManager;
|
||||
@ -45,7 +47,8 @@ export class ObjectManagerRepository {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
public static reset() {
|
||||
public static async reset() {
|
||||
await MySQLConnection.close();
|
||||
this._instance = null;
|
||||
}
|
||||
|
||||
|
@ -4,5 +4,4 @@ export interface ISearchManager {
|
||||
autocomplete(text: string): Promise<AutoCompleteItem[]>;
|
||||
search(text: string, searchType: SearchTypes): Promise<SearchResultDTO>;
|
||||
instantSearch(text: string): Promise<SearchResultDTO>;
|
||||
isSupported(): boolean;
|
||||
}
|
||||
|
@ -3,5 +3,4 @@ export interface ISharingManager {
|
||||
findOne(filter: any): Promise<SharingDTO>;
|
||||
createSharing(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.");
|
||||
}
|
||||
|
||||
isSupported(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -3,9 +3,6 @@ import {SharingDTO} from "../../../common/entities/SharingDTO";
|
||||
|
||||
export class SharingManager implements ISharingManager {
|
||||
|
||||
isSupported(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
findOne(filter: any): Promise<SharingDTO> {
|
||||
throw new Error("not implemented");
|
||||
|
@ -86,7 +86,7 @@ export class MySQLConnection {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async init(): Promise<void> {
|
||||
public static async init(): Promise<void> {
|
||||
const connection = await this.getConnection();
|
||||
let userRepository = connection.getRepository(UserEntity);
|
||||
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 {
|
||||
|
||||
isSupported(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
async autocomplete(text: string) {
|
||||
|
||||
const connection = await MySQLConnection.getConnection();
|
||||
|
@ -7,10 +7,6 @@ import {PasswordHelper} from "../PasswordHelper";
|
||||
|
||||
export class SharingManager implements ISharingManager {
|
||||
|
||||
isSupported(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
private async removeExpiredLink() {
|
||||
const connection = await MySQLConnection.getConnection();
|
||||
return connection
|
||||
|
@ -9,24 +9,21 @@ import * as exif_parser from "exif-parser";
|
||||
import {ProjectPath} from "../../ProjectPath";
|
||||
|
||||
const LOG_TAG = "[DiskManagerTask]";
|
||||
|
||||
|
||||
export class DiskMangerWorker {
|
||||
private static isImage(fullPath: string) {
|
||||
let imageMimeTypes = [
|
||||
'bmp',
|
||||
'gif',
|
||||
'jpeg', 'jpg', 'jpe',
|
||||
'png',
|
||||
'tiff', 'tif',
|
||||
'webp',
|
||||
'ico',
|
||||
'tga'
|
||||
const extensions = [
|
||||
'.bmp',
|
||||
'.gif',
|
||||
'.jpeg', '.jpg', '.jpe',
|
||||
'.png',
|
||||
'.tiff', '.tif',
|
||||
'.webp',
|
||||
'.ico',
|
||||
'.tga'
|
||||
];
|
||||
|
||||
let extension = path.extname(fullPath).toLowerCase();
|
||||
|
||||
return imageMimeTypes.indexOf(extension) !== -1;
|
||||
const extension = path.extname(fullPath).toLowerCase();
|
||||
return extensions.indexOf(extension) !== -1;
|
||||
}
|
||||
|
||||
private static loadPhotoMetadata(fullPath: string): Promise<PhotoMetadata> {
|
||||
|
@ -48,6 +48,20 @@ export class AdminRouter {
|
||||
AdminMWs.testDatabaseSettings,
|
||||
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 {Config} from "../../common/config/private/Config";
|
||||
import {ProjectPath} from "../ProjectPath";
|
||||
import {AuthenticationMWs} from "../middlewares/user/AuthenticationMWs";
|
||||
|
||||
export class PublicRouter {
|
||||
|
||||
public static route(app) {
|
||||
app.use((req: Request, res: Response, next: NextFunction) => {
|
||||
res.tpl = {};
|
||||
const renderIndex = (req: Request, res: Response) => {
|
||||
res.sendFile(_path.resolve(__dirname, './../../dist/index.html'));
|
||||
};
|
||||
|
||||
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;
|
||||
app.use(
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
res.tpl = {};
|
||||
|
||||
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) => {
|
||||
res.render(_path.resolve(__dirname, './../../dist/config_inject.ejs'), res.tpl);
|
||||
});
|
||||
app.get(['/', '/login', "/gallery*", "/share*", "/admin", "/search*"], (req: Request, res: Response) => {
|
||||
res.sendFile(_path.resolve(__dirname, './../../dist/index.html'));
|
||||
});
|
||||
app.get(['/', '/login', "/gallery*", "/share*", "/admin", "/search*"],
|
||||
AuthenticationMWs.tryAuthenticate,
|
||||
renderIndex
|
||||
);
|
||||
|
||||
app.use(_express.static(ProjectPath.FrontendFolder));
|
||||
app.use('/node_modules', _express.static(_path.resolve(__dirname, './../../node_modules')));
|
||||
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 {Logger} from "./Logger";
|
||||
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 {ProjectPath} from "./ProjectPath";
|
||||
import {ThumbnailGeneratorMWs} from "./middlewares/thumbnail/ThumbnailGeneratorMWs";
|
||||
import {DiskManager} from "./model/DiskManger";
|
||||
import {NotificationRouter} from "./routes/NotificationRouter";
|
||||
import {NotificationManager} from "./model/NotifocationManager";
|
||||
import {ConfigDiagnostics} from "./model/ConfigDiagnostics";
|
||||
|
||||
const LOG_TAG = "[server]";
|
||||
export class Server {
|
||||
@ -34,7 +33,7 @@ export class Server {
|
||||
|
||||
async init() {
|
||||
Logger.info(LOG_TAG, "running diagnostics...");
|
||||
await this.runDiagnostics();
|
||||
await ConfigDiagnostics.runDiagnostics();
|
||||
Logger.info(LOG_TAG, "using config:");
|
||||
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
|
||||
|
||||
@ -67,6 +66,11 @@ export class Server {
|
||||
|
||||
DiskManager.init();
|
||||
ThumbnailGeneratorMWs.init();
|
||||
if (Config.Server.database.type == DatabaseType.mysql) {
|
||||
await ObjectManagerRepository.InitMySQLManagers();
|
||||
} else {
|
||||
await ObjectManagerRepository.InitMemoryManagers();
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -19,10 +19,10 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
||||
database: {
|
||||
type: DatabaseType.mysql,
|
||||
mysql: {
|
||||
host: "localhost",
|
||||
username: "root",
|
||||
password: "root",
|
||||
database: "pigallery2"
|
||||
host: "",
|
||||
username: "",
|
||||
password: "",
|
||||
database: ""
|
||||
|
||||
}
|
||||
},
|
||||
@ -36,9 +36,10 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
||||
public setDatabaseType(type: DatabaseType) {
|
||||
this.Server.database.type = type;
|
||||
if (type === DatabaseType.memory) {
|
||||
this.Client.Search.searchEnabled = false;
|
||||
this.Client.Search.enabled = false;
|
||||
this.Client.Search.instantSearchEnabled = false;
|
||||
this.Client.Search.autocompleteEnabled = false;
|
||||
this.Client.Sharing.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,31 @@
|
||||
interface SearchConfig {
|
||||
searchEnabled: boolean
|
||||
export interface SearchConfig {
|
||||
enabled: boolean
|
||||
instantSearchEnabled: boolean
|
||||
autocompleteEnabled: boolean
|
||||
}
|
||||
|
||||
interface SharingConfig {
|
||||
export interface SharingConfig {
|
||||
enabled: boolean;
|
||||
passwordProtected: boolean;
|
||||
}
|
||||
|
||||
export interface MapConfig {
|
||||
enabled: boolean;
|
||||
googleApiKey: string;
|
||||
}
|
||||
|
||||
export interface ClientConfig {
|
||||
applicationTitle: string;
|
||||
iconSize: number;
|
||||
thumbnailSizes: Array<number>;
|
||||
Search: SearchConfig;
|
||||
Sharing: SharingConfig;
|
||||
Map: MapConfig;
|
||||
concurrentThumbnailGenerations: number;
|
||||
enableCache: boolean;
|
||||
enableOnScrollRendering: boolean;
|
||||
enableOnScrollThumbnailPrioritising: boolean;
|
||||
authenticationRequired: boolean;
|
||||
googleApiKey: string;
|
||||
publicUrl: string;
|
||||
}
|
||||
|
||||
@ -34,7 +39,7 @@ export class PublicConfigClass {
|
||||
thumbnailSizes: [200, 400, 600],
|
||||
iconSize: 30,
|
||||
Search: {
|
||||
searchEnabled: true,
|
||||
enabled: true,
|
||||
instantSearchEnabled: true,
|
||||
autocompleteEnabled: true
|
||||
},
|
||||
@ -42,12 +47,15 @@ export class PublicConfigClass {
|
||||
enabled: true,
|
||||
passwordProtected: true
|
||||
},
|
||||
Map: {
|
||||
enabled: true,
|
||||
googleApiKey: ""
|
||||
},
|
||||
concurrentThumbnailGenerations: 1,
|
||||
enableCache: false,
|
||||
enableOnScrollRendering: true,
|
||||
enableOnScrollThumbnailPrioritising: true,
|
||||
authenticationRequired: true,
|
||||
googleApiKey: "",
|
||||
publicUrl: ""
|
||||
};
|
||||
|
||||
|
@ -23,5 +23,6 @@
|
||||
|
||||
<settings-usermanager *ngIf="userManagementEnable"></settings-usermanager>
|
||||
<settings-database></settings-database>
|
||||
<settings-map></settings-map>
|
||||
</div>
|
||||
</app-frame>
|
||||
|
@ -41,17 +41,18 @@ import {DatabaseSettingsComponent} from "./settings/database/database.settings.c
|
||||
import {ToastModule} from "ng2-toastr/ng2-toastr";
|
||||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||
import {NotificationService} from "./model/notification.service";
|
||||
|
||||
import {JWBootstrapSwitchModule} from "jw-bootstrap-switch-ng2";
|
||||
import {ClipboardModule} from "ngx-clipboard";
|
||||
import {NavigationService} from "./model/navigation.service";
|
||||
import {InfoPanelLightboxComponent} from "./gallery/lightbox/infopanel/info-panel.lightbox.gallery.component";
|
||||
import {MapSettingsComponent} from "./settings/map/map.settings.component";
|
||||
|
||||
@Injectable()
|
||||
export class GoogleMapsConfig {
|
||||
apiKey: string;
|
||||
|
||||
constructor() {
|
||||
this.apiKey = Config.Client.googleApiKey;
|
||||
this.apiKey = Config.Client.Map.googleApiKey;
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,6 +64,7 @@ export class GoogleMapsConfig {
|
||||
BrowserAnimationsModule,
|
||||
appRoutes,
|
||||
ClipboardModule,
|
||||
JWBootstrapSwitchModule,
|
||||
ToastModule.forRoot(),
|
||||
ModalModule.forRoot(),
|
||||
AgmCoreModule.forRoot(),
|
||||
@ -91,6 +93,7 @@ export class GoogleMapsConfig {
|
||||
//Settings
|
||||
UserMangerSettingsComponent,
|
||||
DatabaseSettingsComponent,
|
||||
MapSettingsComponent,
|
||||
StringifyRole],
|
||||
providers: [
|
||||
{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig},
|
||||
|
@ -22,7 +22,7 @@
|
||||
<ng-content select="[navbar]"></ng-content>
|
||||
<li class="divider-vertical">
|
||||
</li>
|
||||
<li>
|
||||
<li *ngIf="authenticationRequired">
|
||||
<p class="navbar-text" *ngIf="user.value">
|
||||
<span class="glyphicon glyphicon-user" aria-hidden="true"></span> {{user.value.name}}</p>
|
||||
</li>
|
||||
|
@ -24,7 +24,8 @@
|
||||
<gallery-directory *ngFor="let directory of directories"
|
||||
[directory]="directory"></gallery-directory>
|
||||
</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>
|
||||
</div>
|
||||
|
||||
@ -42,7 +43,8 @@
|
||||
</li>
|
||||
</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">
|
||||
<gallery-directory *ngFor="let directory of directories"
|
||||
|
@ -34,6 +34,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
timer: null
|
||||
};
|
||||
public countDown = null;
|
||||
public mapEnabled = true;
|
||||
|
||||
constructor(public _galleryService: GalleryService,
|
||||
private _authService: AuthenticationService,
|
||||
@ -41,6 +42,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
private shareService: ShareService,
|
||||
private _route: ActivatedRoute,
|
||||
private _navigation: NavigationService) {
|
||||
this.mapEnabled = Config.Client.Map.enabled;
|
||||
|
||||
}
|
||||
|
||||
@ -67,7 +69,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
|
||||
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.subscription.content = this._galleryService.content.subscribe(this.onContentChange);
|
||||
|
@ -34,7 +34,7 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit {
|
||||
photosToRender: Array<GridPhoto> = [];
|
||||
containerWidth: number = 0;
|
||||
|
||||
private IMAGE_MARGIN = 2;
|
||||
public IMAGE_MARGIN = 2;
|
||||
private TARGET_COL_COUNT = 5;
|
||||
private MIN_ROW_COUNT = 2;
|
||||
private MAX_ROW_COUNT = 5;
|
||||
|
@ -43,7 +43,7 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, OnDestroy {
|
||||
|
||||
constructor(private thumbnailService: ThumbnailManagerService) {
|
||||
this.SearchTypes = SearchTypes;
|
||||
this.searchEnabled = Config.Client.Search.searchEnabled;
|
||||
this.searchEnabled = Config.Client.Search.enabled;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -76,7 +76,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="map" *ngIf="hasGPS()">
|
||||
<div id="map" *ngIf="hasGPS() && mapEnabled">
|
||||
<agm-map
|
||||
[disableDefaultUI]="true"
|
||||
[zoomControl]="false"
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {Component, ElementRef, Input} from "@angular/core";
|
||||
import {PhotoDTO} from "../../../../../common/entities/PhotoDTO";
|
||||
import {Config} from "../../../../../common/config/public/Config";
|
||||
|
||||
@Component({
|
||||
selector: 'info-panel',
|
||||
@ -9,8 +10,10 @@ import {PhotoDTO} from "../../../../../common/entities/PhotoDTO";
|
||||
export class InfoPanelLightboxComponent {
|
||||
@Input() photo: PhotoDTO;
|
||||
|
||||
public mapEnabled = true;
|
||||
|
||||
constructor(public elementRef: ElementRef) {
|
||||
this.mapEnabled = Config.Client.Map.enabled;
|
||||
}
|
||||
|
||||
calcMpx() {
|
||||
|
@ -61,7 +61,7 @@ export class GallerySearchComponent {
|
||||
}
|
||||
|
||||
public onSearch() {
|
||||
if (Config.Client.Search.searchEnabled) {
|
||||
if (Config.Client.Search.enabled) {
|
||||
this._galleryService.search(this.searchText);
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,11 @@ export class AuthenticationService {
|
||||
constructor(private _userService: UserService) {
|
||||
this.user = new BehaviorSubject(null);
|
||||
|
||||
console.log(ServerInject.user);
|
||||
//picking up session..
|
||||
if (this.isAuthenticated() == false && Cookie.get('pigallery2-session') != null) {
|
||||
if (typeof ServerInject !== "undefined" && typeof ServerInject.user !== "undefined") {
|
||||
console.log(ServerInject.user);
|
||||
this.user.next(ServerInject.user);
|
||||
}
|
||||
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 {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 {Utils} from "../../../../common/Utils";
|
||||
import {Error} from "../../../../common/entities/Error";
|
||||
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({
|
||||
selector: 'settings-database',
|
||||
@ -14,84 +13,28 @@ import {NotificationService} from "../../model/notification.service";
|
||||
styleUrls: ['./database.settings.component.css'],
|
||||
providers: [DatabaseSettingsService],
|
||||
})
|
||||
export class DatabaseSettingsComponent implements OnInit {
|
||||
@ViewChild('settingsForm') form;
|
||||
|
||||
export class DatabaseSettingsComponent extends SettingsComponent<DataBaseConfig> {
|
||||
public settings: DataBaseConfig = <DataBaseConfig> {
|
||||
type: DatabaseType.memory,
|
||||
mysql: {}
|
||||
};
|
||||
inProgress = false;
|
||||
private original: DataBaseConfig;
|
||||
public types: Array<any> = [];
|
||||
public DatabaseType: any;
|
||||
public tested = false;
|
||||
public error: string = null;
|
||||
public changed: boolean = false;
|
||||
|
||||
constructor(private _authService: AuthenticationService,
|
||||
private _router: Router,
|
||||
private _dbSettings: DatabaseSettingsService,
|
||||
private notification: NotificationService) {
|
||||
this.original = Utils.clone(this.settings);
|
||||
constructor(_authService: AuthenticationService,
|
||||
_navigation: NavigationService,
|
||||
_dbSettings: DatabaseSettingsService,
|
||||
notification: NotificationService) {
|
||||
super("Database", _authService, _navigation, _dbSettings, notification);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this._authService.isAuthenticated() ||
|
||||
this._authService.user.value.role < UserRoles.Admin) {
|
||||
this._router.navigate(['login']);
|
||||
return;
|
||||
}
|
||||
super.ngOnInit();
|
||||
this.types = Utils
|
||||
.enumToArray(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 {NetworkService} from "../../model/network/network.service";
|
||||
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()
|
||||
export class DatabaseSettingsService {
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
constructor(private _networkService: NetworkService) {
|
||||
}
|
||||
|
||||
public async getSettings(): Promise<DataBaseConfig> {
|
||||
return (await <Promise<IPrivateConfig>>this._networkService.getJson("/settings")).Server.database;
|
||||
}
|
||||
|
||||
public updateSettings(settings): Promise<void> {
|
||||
return this._networkService.putJson("/settings/database", {databaseSettings: settings});
|
||||
public updateSettings(settings: DataBaseConfig): Promise<void> {
|
||||
return this._networkService.putJson("/settings/database", {settings: settings});
|
||||
}
|
||||
|
||||
public testSettings(settings): Promise<void> {
|
||||
return this._networkService.postJson<void>("/settings/test/database", {databaseSettings: settings});
|
||||
public testSettings(settings: DataBaseConfig): Promise<void> {
|
||||
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">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<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">
|
||||
<script type="text/javascript" src="config_inject.js"></script>
|
||||
</head>
|
||||
|
@ -7,3 +7,7 @@
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.bootstrap-switch-label {
|
||||
margin-right: -4px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
@ -74,6 +74,7 @@
|
||||
"intl": "^1.2.5",
|
||||
"jasmine-core": "^2.6.4",
|
||||
"jasmine-spec-reporter": "~4.1.1",
|
||||
"jw-bootstrap-switch-ng2": "^1.0.3",
|
||||
"karma": "^1.7.0",
|
||||
"karma-cli": "^1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "^1.3.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user