1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-12-25 02:04:15 +02:00

adding url base, improving code quality

This commit is contained in:
Patrik J. Braun 2018-05-12 12:19:51 -04:00
parent 9a90764603
commit babf2fc584
79 changed files with 732 additions and 636 deletions

View File

@ -114,7 +114,7 @@ apt-get install build-essential libkrb5-dev gcc g++
* bug free :) - `In progress` * bug free :) - `In progress`
## Translate the page to you own language ## Translate the page to your own language
1) download / clone the repo (the source not the packed release!) 1) download / clone the repo (the source not the packed release!)
2) add your language e.g: fr 2) add your language e.g: fr
```bash ```bash

View File

@ -10,7 +10,7 @@ declare module 'winston' {
export const winstonSettings = { export const winstonSettings = {
transports: [ transports: [
new winston.transports.Console({ new winston.transports.Console({
level: process.env.NODE_ENV == 'production' ? 'info' : 'silly', level: process.env.NODE_ENV === 'production' ? 'info' : 'silly',
handleExceptions: true, handleExceptions: true,
json: false, json: false,
colorize: true, colorize: true,

View File

@ -191,12 +191,14 @@ export class AdminMWs {
Config.Server.port = settings.port; Config.Server.port = settings.port;
Config.Server.imagesFolder = settings.imagesFolder; Config.Server.imagesFolder = settings.imagesFolder;
Config.Client.publicUrl = settings.publicUrl; Config.Client.publicUrl = settings.publicUrl;
Config.Client.urlBase = settings.urlBase;
Config.Client.applicationTitle = settings.applicationTitle; Config.Client.applicationTitle = settings.applicationTitle;
// only updating explicitly set config (not saving config set by the diagnostics) // only updating explicitly set config (not saving config set by the diagnostics)
const original = Config.original(); const original = Config.original();
original.Server.port = settings.port; original.Server.port = settings.port;
original.Server.imagesFolder = settings.imagesFolder; original.Server.imagesFolder = settings.imagesFolder;
original.Client.publicUrl = settings.publicUrl; original.Client.publicUrl = settings.publicUrl;
original.Client.urlBase = settings.urlBase;
original.Client.applicationTitle = settings.applicationTitle; original.Client.applicationTitle = settings.applicationTitle;
original.save(); original.save();
ProjectPath.reset(); ProjectPath.reset();

View File

@ -12,8 +12,9 @@ import {Logger} from '../Logger';
export class RenderingMWs { export class RenderingMWs {
public static renderResult(req: Request, res: Response, next: NextFunction) { public static renderResult(req: Request, res: Response, next: NextFunction) {
if (typeof req.resultPipe == 'undefined') if (typeof req.resultPipe === 'undefined') {
return next(); return next();
}
return RenderingMWs.renderMessage(res, req.resultPipe); return RenderingMWs.renderMessage(res, req.resultPipe);
} }
@ -30,8 +31,9 @@ export class RenderingMWs {
} }
public static renderSharing(req: Request, res: Response, next: NextFunction) { public static renderSharing(req: Request, res: Response, next: NextFunction) {
if (!req.resultPipe) if (!req.resultPipe) {
return next(); return next();
}
const sharing = Utils.clone<SharingDTO>(req.resultPipe); const sharing = Utils.clone<SharingDTO>(req.resultPipe);
delete sharing.password; delete sharing.password;
@ -39,20 +41,21 @@ export class RenderingMWs {
} }
public static renderFile(req: Request, res: Response, next: NextFunction) { public static renderFile(req: Request, res: Response, next: NextFunction) {
if (!req.resultPipe) if (!req.resultPipe) {
return next(); return next();
}
return res.sendFile(req.resultPipe, {maxAge: 31536000}); return res.sendFile(req.resultPipe, {maxAge: 31536000});
} }
public static renderOK(req: Request, res: Response, next: NextFunction) { public static renderOK(req: Request, res: Response, next: NextFunction) {
let message = new Message<string>(null, 'ok'); const message = new Message<string>(null, 'ok');
res.json(message); res.json(message);
} }
public static renderConfig(req: Request, res: Response, next: NextFunction) { public static renderConfig(req: Request, res: Response, next: NextFunction) {
let message = new Message<PrivateConfigClass>(null, Config.original()); const message = new Message<PrivateConfigClass>(null, Config.original());
res.json(message); res.json(message);
} }
@ -72,7 +75,7 @@ export class RenderingMWs {
} }
} }
} }
let message = new Message<any>(err, null); const message = new Message<any>(err, null);
return res.json(message); return res.json(message);
} }
NotificationManager.error('unknown server error', err); NotificationManager.error('unknown server error', err);
@ -81,7 +84,7 @@ export class RenderingMWs {
protected static renderMessage<T>(res: Response, content: T) { protected static renderMessage<T>(res: Response, content: T) {
let message = new Message<T>(null, content); const message = new Message<T>(null, content);
res.json(message); res.json(message);
} }

View File

@ -39,7 +39,7 @@ export class SharingMWs {
const createSharing: CreateSharingDTO = req.body.createSharing; const createSharing: CreateSharingDTO = req.body.createSharing;
let sharingKey = SharingMWs.generateKey(); let sharingKey = SharingMWs.generateKey();
//create one not yet used // create one not yet used
while (true) { while (true) {
try { try {
@ -52,7 +52,7 @@ export class SharingMWs {
const directoryName = req.params.directory || '/'; const directoryName = req.params.directory || '/';
let sharing: SharingDTO = { const sharing: SharingDTO = {
id: null, id: null,
sharingKey: sharingKey, sharingKey: sharingKey,
path: directoryName, path: directoryName,
@ -79,7 +79,7 @@ export class SharingMWs {
} }
const updateSharing: CreateSharingDTO = req.body.updateSharing; const updateSharing: CreateSharingDTO = req.body.updateSharing;
const directoryName = req.params.directory || '/'; const directoryName = req.params.directory || '/';
let sharing: SharingDTO = { const sharing: SharingDTO = {
id: updateSharing.id, id: updateSharing.id,
path: directoryName, path: directoryName,
sharingKey: '', sharingKey: '',

View File

@ -1,13 +1,13 @@
declare module Express { declare module Express {
export interface Request { export interface Request {
resultPipe?: any resultPipe?: any;
body?: { body?: {
loginCredential loginCredential
} };
} }
export interface Response { export interface Response {
tpl?: any tpl?: any;
} }
export interface Session { export interface Session {

View File

@ -125,7 +125,8 @@ export class ThumbnailGeneratorMWs {
photos[i].readyThumbnails.push(size); photos[i].readyThumbnails.push(size);
} }
} }
const iconPath = path.join(thumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(fullImagePath, Config.Client.Thumbnail.iconSize)); const iconPath = path.join(thumbnailFolder,
ThumbnailGeneratorMWs.generateThumbnailName(fullImagePath, Config.Client.Thumbnail.iconSize));
if (fs.existsSync(iconPath) === true) { if (fs.existsSync(iconPath) === true) {
photos[i].readyIcon = true; photos[i].readyIcon = true;
} }
@ -133,7 +134,10 @@ export class ThumbnailGeneratorMWs {
} }
} }
private static async generateImage(imagePath: string, size: number, makeSquare: boolean, req: Request, res: Response, next: NextFunction) { private static async generateImage(imagePath: string,
size: number,
makeSquare: boolean,
req: Request, res: Response, next: NextFunction) {
// generate thumbnail path // generate thumbnail path
const thPath = path.join(ProjectPath.ThumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(imagePath, size)); const thPath = path.join(ProjectPath.ThumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(imagePath, size));
@ -162,7 +166,7 @@ export class ThumbnailGeneratorMWs {
await this.taskQue.execute(input); await this.taskQue.execute(input);
return next(); return next();
} catch (error) { } catch (error) {
return next(new ErrorDTO(ErrorCodes.THUMBNAIL_GENERATION_ERROR, 'Error during generating thumbnail', error)); return next(new ErrorDTO(ErrorCodes.THUMBNAIL_GENERATION_ERROR, 'Error during generating thumbnail: ' + input.imagePath, error));
} }
} }

View File

@ -55,13 +55,13 @@ export class AuthenticationMWs {
public static authoriseDirectory(req: Request, res: Response, next: NextFunction) { public static authoriseDirectory(req: Request, res: Response, next: NextFunction) {
if (req.session.user.permissions == null || if (req.session.user.permissions == null ||
req.session.user.permissions.length == 0 || req.session.user.permissions.length === 0 ||
req.session.user.permissions[0] == '/*') { req.session.user.permissions[0] === '/*') {
return next(); return next();
} }
const directoryName = req.params.directory || '/'; const directoryName = req.params.directory || '/';
if (UserDTO.isPathAvailable(directoryName, req.session.user.permissions) == true) { if (UserDTO.isPathAvailable(directoryName, req.session.user.permissions) === true) {
return next(); return next();
} }
@ -82,7 +82,7 @@ export class AuthenticationMWs {
if (Config.Client.Sharing.enabled === false) { if (Config.Client.Sharing.enabled === false) {
return next(); return next();
} }
//not enough parameter // not enough parameter
if ((!req.query.sk && !req.params.sharingKey)) { if ((!req.query.sk && !req.params.sharingKey)) {
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'no sharing key provided')); return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'no sharing key provided'));
} }
@ -100,7 +100,7 @@ export class AuthenticationMWs {
} }
let path = sharing.path; let path = sharing.path;
if (sharing.includeSubfolders == true) { if (sharing.includeSubfolders === true) {
path += '*'; path += '*';
} }
@ -122,13 +122,15 @@ export class AuthenticationMWs {
public static async login(req: Request, res: Response, next: NextFunction) { public static async login(req: Request, res: Response, next: NextFunction) {
//not enough parameter // not enough parameter
if ((typeof req.body === 'undefined') || (typeof req.body.loginCredential === 'undefined') || (typeof req.body.loginCredential.username === 'undefined') || if ((typeof req.body === 'undefined') ||
(typeof req.body.loginCredential === 'undefined') ||
(typeof req.body.loginCredential.username === 'undefined') ||
(typeof req.body.loginCredential.password === 'undefined')) { (typeof req.body.loginCredential.password === 'undefined')) {
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR)); return next(new ErrorDTO(ErrorCodes.INPUT_ERROR));
} }
try { try {
//lets find the user // lets find the user
const user = Utils.clone(await ObjectManagerRepository.getInstance().UserManager.findOne({ const user = Utils.clone(await ObjectManagerRepository.getInstance().UserManager.findOne({
name: req.body.loginCredential.username, name: req.body.loginCredential.username,
password: req.body.loginCredential.password password: req.body.loginCredential.password
@ -162,7 +164,7 @@ export class AuthenticationMWs {
} }
let path = sharing.path; let path = sharing.path;
if (sharing.includeSubfolders == true) { if (sharing.includeSubfolders === true) {
path += '*'; path += '*';
} }
return <UserDTO>{name: 'Guest', role: UserRoles.LimitedGuest, permissions: [path]}; return <UserDTO>{name: 'Guest', role: UserRoles.LimitedGuest, permissions: [path]};

View File

@ -18,7 +18,7 @@ const LOG_TAG = '[ConfigDiagnostics]';
export class ConfigDiagnostics { export class ConfigDiagnostics {
static async testDatabase(databaseConfig: DataBaseConfig) { static async testDatabase(databaseConfig: DataBaseConfig) {
if (databaseConfig.type != DatabaseType.memory) { if (databaseConfig.type !== DatabaseType.memory) {
await SQLConnection.tryConnection(databaseConfig); await SQLConnection.tryConnection(databaseConfig);
} }
} }
@ -77,43 +77,45 @@ export class ConfigDiagnostics {
static async testClientThumbnailConfig(thumbnailConfig: ClientConfig.ThumbnailConfig) { static async testClientThumbnailConfig(thumbnailConfig: ClientConfig.ThumbnailConfig) {
if (isNaN(thumbnailConfig.iconSize) || thumbnailConfig.iconSize <= 0) { if (isNaN(thumbnailConfig.iconSize) || thumbnailConfig.iconSize <= 0) {
throw 'IconSize has to be >= 0 integer, got: ' + thumbnailConfig.iconSize; throw new Error('IconSize has to be >= 0 integer, got: ' + thumbnailConfig.iconSize);
} }
if (!thumbnailConfig.thumbnailSizes.length) { if (!thumbnailConfig.thumbnailSizes.length) {
throw 'At least one thumbnail size is needed'; throw new Error('At least one thumbnail size is needed');
} }
for (let i = 0; i < thumbnailConfig.thumbnailSizes.length; i++) { for (let i = 0; i < thumbnailConfig.thumbnailSizes.length; i++) {
if (isNaN(thumbnailConfig.thumbnailSizes[i]) || thumbnailConfig.thumbnailSizes[i] <= 0) { if (isNaN(thumbnailConfig.thumbnailSizes[i]) || thumbnailConfig.thumbnailSizes[i] <= 0) {
throw 'Thumbnail size has to be >= 0 integer, got: ' + thumbnailConfig.thumbnailSizes[i]; throw new Error('Thumbnail size has to be >= 0 integer, got: ' + thumbnailConfig.thumbnailSizes[i]);
} }
} }
} }
static async testSearchConfig(search: ClientConfig.SearchConfig, config: IPrivateConfig) { static async testSearchConfig(search: ClientConfig.SearchConfig, config: IPrivateConfig) {
if (search.enabled == true && config.Server.database.type == DatabaseType.memory) { if (search.enabled === true &&
throw 'Memory Database do not support searching'; config.Server.database.type === DatabaseType.memory) {
throw new Error('Memory Database do not support searching');
} }
} }
static async testSharingConfig(sharing: ClientConfig.SharingConfig, config: IPrivateConfig) { static async testSharingConfig(sharing: ClientConfig.SharingConfig, config: IPrivateConfig) {
if (sharing.enabled == true && config.Server.database.type == DatabaseType.memory) { if (sharing.enabled === true &&
throw 'Memory Database do not support sharing'; config.Server.database.type === DatabaseType.memory) {
throw new Error('Memory Database do not support sharing');
} }
} }
static async testMapConfig(map: ClientConfig.MapConfig) { static async testMapConfig(map: ClientConfig.MapConfig) {
if (map.enabled == true && (!map.googleApiKey || map.googleApiKey.length == 0)) { if (map.enabled === true && (!map.googleApiKey || map.googleApiKey.length === 0)) {
throw 'Maps need a valid google api key'; throw new Error('Maps need a valid google api key');
} }
} }
static async runDiagnostics() { static async runDiagnostics() {
if (Config.Server.database.type != DatabaseType.memory) { if (Config.Server.database.type !== DatabaseType.memory) {
try { try {
await ConfigDiagnostics.testDatabase(Config.Server.database); await ConfigDiagnostics.testDatabase(Config.Server.database);
} catch (err) { } catch (err) {
@ -124,7 +126,7 @@ export class ConfigDiagnostics {
} }
} }
if (Config.Server.thumbnail.processingLibrary != ThumbnailProcessingLib.Jimp) { if (Config.Server.thumbnail.processingLibrary !== ThumbnailProcessingLib.Jimp) {
try { try {
await ConfigDiagnostics.testThumbnailLib(Config.Server.thumbnail.processingLibrary); await ConfigDiagnostics.testThumbnailLib(Config.Server.thumbnail.processingLibrary);
} catch (err) { } catch (err) {
@ -164,7 +166,8 @@ export class ConfigDiagnostics {
try { try {
await ConfigDiagnostics.testSearchConfig(Config.Client.Search, Config); await ConfigDiagnostics.testSearchConfig(Config.Client.Search, Config);
} catch (err) { } catch (err) {
NotificationManager.warning('Search is not supported with these settings. Disabling temporally. Please adjust the config properly.', err); NotificationManager.warning('Search is not supported with these settings. Disabling temporally. ' +
'Please adjust the config properly.', err);
Logger.warn(LOG_TAG, '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; Config.Client.Search.enabled = false;
} }
@ -172,7 +175,8 @@ export class ConfigDiagnostics {
try { try {
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing, Config); await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing, Config);
} catch (err) { } catch (err) {
NotificationManager.warning('Sharing is not supported with these settings. Disabling temporally. Please adjust the config properly.', err); NotificationManager.warning('Sharing is not supported with these settings. Disabling temporally. ' +
'Please adjust the config properly.', err);
Logger.warn(LOG_TAG, '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; Config.Client.Sharing.enabled = false;
} }
@ -180,8 +184,10 @@ export class ConfigDiagnostics {
try { try {
await ConfigDiagnostics.testMapConfig(Config.Client.Map); await ConfigDiagnostics.testMapConfig(Config.Client.Map);
} catch (err) { } catch (err) {
NotificationManager.warning('Maps is not supported with these settings. Disabling temporally. Please adjust the config properly.', err); NotificationManager.warning('Maps is not supported with these settings. Disabling temporally. ' +
Logger.warn(LOG_TAG, 'Maps is not supported with these settings. Disabling temporally. Please adjust the config properly.', err); 'Please adjust the config properly.', err);
Logger.warn(LOG_TAG, 'Maps is not supported with these settings. Disabling temporally. ' +
'Please adjust the config properly.', err);
Config.Client.Map.enabled = false; Config.Client.Map.enabled = false;
} }

View File

@ -12,7 +12,7 @@ export class DiskManager {
static threadPool: DiskManagerTH = null; static threadPool: DiskManagerTH = null;
public static init() { public static init() {
if (Config.Server.enableThreading == true) { if (Config.Server.enableThreading === true) {
DiskManager.threadPool = new DiskManagerTH(1); DiskManager.threadPool = new DiskManagerTH(1);
} }
} }
@ -23,12 +23,12 @@ export class DiskManager {
let directory: DirectoryDTO = null; let directory: DirectoryDTO = null;
if (Config.Server.enableThreading == true) { if (Config.Server.enableThreading === true) {
directory = await DiskManager.threadPool.execute(relativeDirectoryName); directory = await DiskManager.threadPool.execute(relativeDirectoryName);
} else { } else {
directory = await DiskMangerWorker.scanDirectory(relativeDirectoryName); directory = await DiskMangerWorker.scanDirectory(relativeDirectoryName);
} }
let addDirs = (dir: DirectoryDTO) => { const addDirs = (dir: DirectoryDTO) => {
dir.photos.forEach((ph) => { dir.photos.forEach((ph) => {
ph.directory = dir; ph.directory = dir;
}); });

View File

@ -1,6 +1,6 @@
import {ProjectPath} from '../ProjectPath'; import {ProjectPath} from '../ProjectPath';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import {Config} from '../../common/config/private/Config'; import {Config} from '../../common/config/private/Config';
export class Localizations { export class Localizations {
@ -10,8 +10,9 @@ export class Localizations {
public static init() { public static init() {
const notLanguage = ['assets']; const notLanguage = ['assets'];
const dirCont = fs.readdirSync(ProjectPath.FrontendFolder).filter(f => fs.statSync(path.resolve(ProjectPath.FrontendFolder, f)).isDirectory()); const dirCont = fs.readdirSync(ProjectPath.FrontendFolder)
Config.Client.languages = dirCont.filter(d => notLanguage.indexOf(d) == -1); .filter(f => fs.statSync(path.resolve(ProjectPath.FrontendFolder, f)).isDirectory());
Config.Client.languages = dirCont.filter(d => notLanguage.indexOf(d) === -1);
Config.Client.languages.push('en'); Config.Client.languages.push('en');
} }

View File

@ -8,12 +8,13 @@ import {IIndexingManager} from './interfaces/IIndexingManager';
export class ObjectManagerRepository { export class ObjectManagerRepository {
private static _instance: ObjectManagerRepository = null;
private _galleryManager: IGalleryManager; private _galleryManager: IGalleryManager;
private _userManager: IUserManager; private _userManager: IUserManager;
private _searchManager: ISearchManager; private _searchManager: ISearchManager;
private _sharingManager: ISharingManager; private _sharingManager: ISharingManager;
private _indexingManager: IIndexingManager; private _indexingManager: IIndexingManager;
private static _instance: ObjectManagerRepository = null;
get IndexingManager(): IIndexingManager { get IndexingManager(): IIndexingManager {
return this._indexingManager; return this._indexingManager;

View File

@ -10,12 +10,12 @@ import {ReIndexingSensitivity} from '../../../common/config/private/IPrivateConf
export class GalleryManager implements IGalleryManager { export class GalleryManager implements IGalleryManager {
public listDirectory(relativeDirectoryName: string, knownLastModified?: number, knownLastScanned?: number): Promise<DirectoryDTO> { public listDirectory(relativeDirectoryName: string, knownLastModified?: number, knownLastScanned?: number): Promise<DirectoryDTO> {
//If it seems that the content did not changed, do not work on it // If it seems that the content did not changed, do not work on it
if (knownLastModified && knownLastScanned) { if (knownLastModified && knownLastScanned) {
const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName)); const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime()); const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime());
if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout && if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout &&
lastModified == knownLastModified && lastModified === knownLastModified &&
Config.Server.indexing.reIndexingSensitivity < ReIndexingSensitivity.high) { Config.Server.indexing.reIndexingSensitivity < ReIndexingSensitivity.high) {
return Promise.resolve(null); return Promise.resolve(null);
} }

View File

@ -9,7 +9,7 @@ import {PasswordHelper} from '../PasswordHelper';
export class UserManager implements IUserManager { export class UserManager implements IUserManager {
private db: { users?: UserDTO[], idCounter?: number } = {}; private db: { users?: UserDTO[], idCounter?: number } = {};
private dbPath; private readonly dbPath;
generateId(): string { generateId(): string {
function s4() { function s4() {
@ -33,7 +33,7 @@ export class UserManager implements IUserManager {
if (!this.db.users) { if (!this.db.users) {
this.db.users = []; this.db.users = [];
//TODO: remove defaults // TODO: remove defaults
this.createUser(<UserDTO>{name: 'admin', password: 'admin', role: UserRoles.Admin}); this.createUser(<UserDTO>{name: 'admin', password: 'admin', role: UserRoles.Admin});
} }
this.saveDB(); this.saveDB();
@ -44,14 +44,14 @@ export class UserManager implements IUserManager {
public async findOne(filter: any) { public async findOne(filter: any) {
const result = await this.find(filter); const result = await this.find(filter);
if (result.length == 0) { if (result.length === 0) {
throw 'UserDTO not found'; throw new Error('UserDTO not found');
} }
return result[0]; return result[0];
} }
public async find(filter: any) { public async find(filter: any) {
let pass = filter.password; const pass = filter.password;
delete filter.password; delete filter.password;
const users = this.db.users.slice(); const users = this.db.users.slice();
let i = users.length; let i = users.length;
@ -60,7 +60,7 @@ export class UserManager implements IUserManager {
users.splice(i, 1); users.splice(i, 1);
continue; continue;
} }
if (Utils.equalsFilter(users[i], filter) == false) { if (Utils.equalsFilter(users[i], filter) === false) {
users.splice(i, 1); users.splice(i, 1);
} }
} }
@ -76,8 +76,8 @@ export class UserManager implements IUserManager {
} }
public async deleteUser(id: number) { public async deleteUser(id: number) {
let deleted = this.db.users.filter((u: UserDTO) => u.id == id); const deleted = this.db.users.filter((u: UserDTO) => u.id === id);
this.db.users = this.db.users.filter((u: UserDTO) => u.id != id); this.db.users = this.db.users.filter((u: UserDTO) => u.id !== id);
this.saveDB(); this.saveDB();
if (deleted.length > 0) { if (deleted.length > 0) {
return deleted[0]; return deleted[0];
@ -87,7 +87,7 @@ export class UserManager implements IUserManager {
public async changeRole(id: number, newRole: UserRoles): Promise<UserDTO> { public async changeRole(id: number, newRole: UserRoles): Promise<UserDTO> {
for (let i = 0; i < this.db.users.length; i++) { for (let i = 0; i < this.db.users.length; i++) {
if (this.db.users[i].id == id) { if (this.db.users[i].id === id) {
this.db.users[i].role = newRole; this.db.users[i].role = newRole;
this.saveDB(); this.saveDB();
return this.db.users[i]; return this.db.users[i];
@ -96,7 +96,7 @@ export class UserManager implements IUserManager {
} }
public async changePassword(request: any) { public async changePassword(request: any) {
throw new Error('not implemented'); //TODO: implement throw new Error('not implemented'); // TODO: implement
} }
private loadDB() { private loadDB() {

View File

@ -24,7 +24,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
const connection = await SQLConnection.getConnection(); const connection = await SQLConnection.getConnection();
const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName)); const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime()); const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime());
let dir = await connection const dir = await connection
.getRepository(DirectoryEntity) .getRepository(DirectoryEntity)
.createQueryBuilder('directory') .createQueryBuilder('directory')
.where('directory.name = :name AND directory.path = :path', { .where('directory.name = :name AND directory.path = :path', {
@ -37,16 +37,16 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
if (dir && dir.lastScanned != null) { if (dir && dir.lastScanned != null) {
//If it seems that the content did not changed, do not work on it // If it seems that the content did not changed, do not work on it
if (knownLastModified && knownLastScanned if (knownLastModified && knownLastScanned
&& lastModified == knownLastModified && && lastModified === knownLastModified &&
dir.lastScanned == knownLastScanned) { dir.lastScanned === knownLastScanned) {
if (Config.Server.indexing.reIndexingSensitivity == ReIndexingSensitivity.low) { if (Config.Server.indexing.reIndexingSensitivity === ReIndexingSensitivity.low) {
return null; return null;
} }
if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout && if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout &&
Config.Server.indexing.reIndexingSensitivity == ReIndexingSensitivity.medium) { Config.Server.indexing.reIndexingSensitivity === ReIndexingSensitivity.medium) {
return null; return null;
} }
} }
@ -79,15 +79,15 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
} }
if (dir.lastModified != lastModified) { if (dir.lastModified !== lastModified) {
return this.indexDirectory(relativeDirectoryName); return this.indexDirectory(relativeDirectoryName);
} }
//not indexed since a while, index it in a lazy manner // not indexed since a while, index it in a lazy manner
if ((Date.now() - dir.lastScanned > Config.Server.indexing.cachedFolderTimeout && if ((Date.now() - dir.lastScanned > Config.Server.indexing.cachedFolderTimeout &&
Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.medium) || Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.medium) ||
Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.high) { Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.high) {
//on the fly reindexing // on the fly reindexing
this.indexDirectory(relativeDirectoryName).catch((err) => { this.indexDirectory(relativeDirectoryName).catch((err) => {
console.error(err); console.error(err);
}); });
@ -97,7 +97,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
} }
//never scanned (deep indexed), do it and return with it // never scanned (deep indexed), do it and return with it
return this.indexDirectory(relativeDirectoryName); return this.indexDirectory(relativeDirectoryName);
@ -109,7 +109,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
try { try {
const scannedDirectory = await DiskManager.scanDirectory(relativeDirectoryName); const scannedDirectory = await DiskManager.scanDirectory(relativeDirectoryName);
//returning with the result // returning with the result
scannedDirectory.photos.forEach(p => p.readyThumbnails = []); scannedDirectory.photos.forEach(p => p.readyThumbnails = []);
resolve(scannedDirectory); resolve(scannedDirectory);
@ -127,7 +127,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
private async saveToDB(scannedDirectory: DirectoryDTO) { private async saveToDB(scannedDirectory: DirectoryDTO) {
const connection = await SQLConnection.getConnection(); const connection = await SQLConnection.getConnection();
//saving to db // saving to db
const directoryRepository = connection.getRepository(DirectoryEntity); const directoryRepository = connection.getRepository(DirectoryEntity);
const photosRepository = connection.getRepository(PhotoEntity); const photosRepository = connection.getRepository(PhotoEntity);
@ -138,7 +138,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
path: scannedDirectory.path path: scannedDirectory.path
}).getOne(); }).getOne();
if (!!currentDir) {//Updated parent dir (if it was in the DB previously) if (!!currentDir) {// Updated parent dir (if it was in the DB previously)
currentDir.lastModified = scannedDirectory.lastModified; currentDir.lastModified = scannedDirectory.lastModified;
currentDir.lastScanned = scannedDirectory.lastScanned; currentDir.lastScanned = scannedDirectory.lastScanned;
currentDir = await directoryRepository.save(currentDir); currentDir = await directoryRepository.save(currentDir);
@ -147,31 +147,31 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
currentDir = await directoryRepository.save(<DirectoryEntity>scannedDirectory); currentDir = await directoryRepository.save(<DirectoryEntity>scannedDirectory);
} }
let childDirectories = await directoryRepository.createQueryBuilder('directory') const childDirectories = await directoryRepository.createQueryBuilder('directory')
.where('directory.parent = :dir', { .where('directory.parent = :dir', {
dir: currentDir.id dir: currentDir.id
}).getMany(); }).getMany();
for (let i = 0; i < scannedDirectory.directories.length; i++) { for (let i = 0; i < scannedDirectory.directories.length; i++) {
//Was this child Dir already indexed before? // Was this child Dir already indexed before?
let directory: DirectoryEntity = null; let directory: DirectoryEntity = null;
for (let j = 0; j < childDirectories.length; j++) { for (let j = 0; j < childDirectories.length; j++) {
if (childDirectories[j].name == scannedDirectory.directories[i].name) { if (childDirectories[j].name === scannedDirectory.directories[i].name) {
directory = childDirectories[j]; directory = childDirectories[j];
childDirectories.splice(j, 1); childDirectories.splice(j, 1);
break; break;
} }
} }
if (directory != null) { //update existing directory if (directory != null) { // update existing directory
if (!directory.parent || !directory.parent.id) { //set parent if not set yet if (!directory.parent || !directory.parent.id) { // set parent if not set yet
directory.parent = currentDir; directory.parent = currentDir;
delete directory.photos; delete directory.photos;
await directoryRepository.save(directory); await directoryRepository.save(directory);
} }
} else { } else {
scannedDirectory.directories[i].parent = currentDir; scannedDirectory.directories[i].parent = currentDir;
(<DirectoryEntity>scannedDirectory.directories[i]).lastScanned = null; //new child dir, not fully scanned yet (<DirectoryEntity>scannedDirectory.directories[i]).lastScanned = null; // new child dir, not fully scanned yet
const d = await directoryRepository.save(<DirectoryEntity>scannedDirectory.directories[i]); const d = await directoryRepository.save(<DirectoryEntity>scannedDirectory.directories[i]);
for (let j = 0; j < scannedDirectory.directories[i].photos.length; j++) { for (let j = 0; j < scannedDirectory.directories[i].photos.length; j++) {
scannedDirectory.directories[i].photos[j].directory = d; scannedDirectory.directories[i].photos[j].directory = d;
@ -181,21 +181,21 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
} }
} }
//Remove child Dirs that are not anymore in the parent dir // Remove child Dirs that are not anymore in the parent dir
await directoryRepository.remove(childDirectories); await directoryRepository.remove(childDirectories);
let indexedPhotos = await photosRepository.createQueryBuilder('photo') const indexedPhotos = await photosRepository.createQueryBuilder('photo')
.where('photo.directory = :dir', { .where('photo.directory = :dir', {
dir: currentDir.id dir: currentDir.id
}).getMany(); }).getMany();
let photosToSave = []; const photosToSave = [];
for (let i = 0; i < scannedDirectory.photos.length; i++) { for (let i = 0; i < scannedDirectory.photos.length; i++) {
let photo = null; let photo = null;
for (let j = 0; j < indexedPhotos.length; j++) { for (let j = 0; j < indexedPhotos.length; j++) {
if (indexedPhotos[j].name == scannedDirectory.photos[i].name) { if (indexedPhotos[j].name === scannedDirectory.photos[i].name) {
photo = indexedPhotos[j]; photo = indexedPhotos[j];
indexedPhotos.splice(j, 1); indexedPhotos.splice(j, 1);
break; break;
@ -208,10 +208,10 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
photo.directory = currentDir; photo.directory = currentDir;
} }
if (photo.metadata.keywords != scannedDirectory.photos[i].metadata.keywords || if (photo.metadata.keywords !== scannedDirectory.photos[i].metadata.keywords ||
photo.metadata.cameraData != scannedDirectory.photos[i].metadata.cameraData || photo.metadata.cameraData !== scannedDirectory.photos[i].metadata.cameraData ||
photo.metadata.positionData != scannedDirectory.photos[i].metadata.positionData || photo.metadata.positionData !== scannedDirectory.photos[i].metadata.positionData ||
photo.metadata.size != scannedDirectory.photos[i].metadata.size) { photo.metadata.size !== scannedDirectory.photos[i].metadata.size) {
photo.metadata.keywords = scannedDirectory.photos[i].metadata.keywords; photo.metadata.keywords = scannedDirectory.photos[i].metadata.keywords;
photo.metadata.cameraData = scannedDirectory.photos[i].metadata.cameraData; photo.metadata.cameraData = scannedDirectory.photos[i].metadata.cameraData;

View File

@ -1,4 +1,4 @@
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO"; import {DirectoryDTO} from '../../../common/entities/DirectoryDTO';
export interface ISQLGalleryManager { export interface ISQLGalleryManager {
listDirectory(relativeDirectoryName: string, listDirectory(relativeDirectoryName: string,

View File

@ -14,7 +14,7 @@ export class IndexingManager implements IIndexingManager {
indexingProgress = null; indexingProgress = null;
enabled = false; enabled = false;
private indexNewDirectory = async () => { private indexNewDirectory = async () => {
if (this.directoriesToIndex.length == 0) { if (this.directoriesToIndex.length === 0) {
this.indexingProgress = null; this.indexingProgress = null;
if (global.gc) { if (global.gc) {
global.gc(); global.gc();
@ -25,7 +25,7 @@ export class IndexingManager implements IIndexingManager {
this.indexingProgress.current = directory; this.indexingProgress.current = directory;
this.indexingProgress.left = this.directoriesToIndex.length; this.indexingProgress.left = this.directoriesToIndex.length;
const scanned = await (<ISQLGalleryManager>ObjectManagerRepository.getInstance().GalleryManager).indexDirectory(directory); const scanned = await (<ISQLGalleryManager>ObjectManagerRepository.getInstance().GalleryManager).indexDirectory(directory);
if (this.enabled == false) { if (this.enabled === false) {
return; return;
} }
this.indexingProgress.indexed++; this.indexingProgress.indexed++;
@ -36,7 +36,7 @@ export class IndexingManager implements IIndexingManager {
}; };
startIndexing(): void { startIndexing(): void {
if (this.directoriesToIndex.length == 0 && this.enabled == false) { if (this.directoriesToIndex.length === 0 && this.enabled === false) {
Logger.info(LOG_TAG, 'Starting indexing'); Logger.info(LOG_TAG, 'Starting indexing');
this.indexingProgress = <IndexingProgressDTO>{ this.indexingProgress = <IndexingProgressDTO>{
indexed: 0, indexed: 0,

View File

@ -15,7 +15,7 @@ import {Logger} from '../../Logger';
export class SQLConnection { export class SQLConnection {
private static VERSION: number = 1; private static VERSION = 1;
constructor() { constructor() {
} }
@ -26,7 +26,7 @@ export class SQLConnection {
if (this.connection == null) { if (this.connection == null) {
let options: any = this.getDriver(Config.Server.database); const options: any = this.getDriver(Config.Server.database);
options.name = 'main'; options.name = 'main';
options.entities = [ options.entities = [
UserEntity, UserEntity,
@ -68,10 +68,10 @@ export class SQLConnection {
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); const userRepository = connection.getRepository(UserEntity);
let admins = await userRepository.find({role: UserRoles.Admin}); const admins = await userRepository.find({role: UserRoles.Admin});
if (admins.length == 0) { if (admins.length === 0) {
let a = new UserEntity(); const a = new UserEntity();
a.name = 'admin'; a.name = 'admin';
a.password = PasswordHelper.cryptPassword('admin'); a.password = PasswordHelper.cryptPassword('admin');
a.role = UserRoles.Admin; a.role = UserRoles.Admin;
@ -86,7 +86,7 @@ export class SQLConnection {
version = await connection.getRepository(VersionEntity).findOne(); version = await connection.getRepository(VersionEntity).findOne();
} catch (ex) { } catch (ex) {
} }
if (version && version.version == SQLConnection.VERSION) { if (version && version.version === SQLConnection.VERSION) {
return; return;
} }
Logger.info('Updating database scheme'); Logger.info('Updating database scheme');
@ -103,7 +103,7 @@ export class SQLConnection {
private static getDriver(config: DataBaseConfig): ConnectionOptions { private static getDriver(config: DataBaseConfig): ConnectionOptions {
let driver: ConnectionOptions = null; let driver: ConnectionOptions = null;
if (config.type == DatabaseType.mysql) { if (config.type === DatabaseType.mysql) {
driver = { driver = {
type: 'mysql', type: 'mysql',
host: config.mysql.host, host: config.mysql.host,
@ -112,7 +112,7 @@ export class SQLConnection {
password: config.mysql.password, password: config.mysql.password,
database: config.mysql.database database: config.mysql.database
}; };
} else if (config.type == DatabaseType.sqlite) { } else if (config.type === DatabaseType.sqlite) {
driver = { driver = {
type: 'sqlite', type: 'sqlite',
database: ProjectPath.getAbsolutePath(config.sqlite.storage) database: ProjectPath.getAbsolutePath(config.sqlite.storage)

View File

@ -8,11 +8,12 @@ import {DirectoryEntity} from './enitites/DirectoryEntity';
export class SearchManager implements ISearchManager { export class SearchManager implements ISearchManager {
private static autoCompleteItemsUnique(array: Array<AutoCompleteItem>): Array<AutoCompleteItem> { private static autoCompleteItemsUnique(array: Array<AutoCompleteItem>): Array<AutoCompleteItem> {
let a = array.concat(); const a = array.concat();
for (let i = 0; i < a.length; ++i) { for (let i = 0; i < a.length; ++i) {
for (let j = i + 1; j < a.length; ++j) { for (let j = i + 1; j < a.length; ++j) {
if (a[i].equals(a[j])) if (a[i].equals(a[j])) {
a.splice(j--, 1); a.splice(j--, 1);
}
} }
} }
@ -24,8 +25,8 @@ export class SearchManager implements ISearchManager {
const connection = await SQLConnection.getConnection(); const connection = await SQLConnection.getConnection();
let result: Array<AutoCompleteItem> = []; let result: Array<AutoCompleteItem> = [];
let photoRepository = connection.getRepository(PhotoEntity); const photoRepository = connection.getRepository(PhotoEntity);
let directoryRepository = connection.getRepository(DirectoryEntity); const directoryRepository = connection.getRepository(DirectoryEntity);
(await photoRepository (await photoRepository
@ -36,13 +37,15 @@ export class SearchManager implements ISearchManager {
.getRawMany()) .getRawMany())
.map(r => <Array<string>>r.metadataKeywords.split(',')) .map(r => <Array<string>>r.metadataKeywords.split(','))
.forEach(keywords => { .forEach(keywords => {
result = result.concat(this.encapsulateAutoComplete(keywords.filter(k => k.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.keyword)); result = result.concat(this.encapsulateAutoComplete(keywords
.filter(k => k.toLowerCase().indexOf(text.toLowerCase()) !== -1), SearchTypes.keyword));
}); });
(await photoRepository (await photoRepository
.createQueryBuilder('photo') .createQueryBuilder('photo')
.select('photo.metadata.positionData.country as country, photo.metadata.positionData.state as state, photo.metadata.positionData.city as city') .select('photo.metadata.positionData.country as country,' +
' photo.metadata.positionData.state as state, photo.metadata.positionData.city as city')
.where('photo.metadata.positionData.country LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'}) .where('photo.metadata.positionData.country LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.orWhere('photo.metadata.positionData.state LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'}) .orWhere('photo.metadata.positionData.state LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.orWhere('photo.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'}) .orWhere('photo.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
@ -52,7 +55,8 @@ export class SearchManager implements ISearchManager {
.filter(pm => !!pm) .filter(pm => !!pm)
.map(pm => <Array<string>>[pm.city || '', pm.country || '', pm.state || '']) .map(pm => <Array<string>>[pm.city || '', pm.country || '', pm.state || ''])
.forEach(positions => { .forEach(positions => {
result = result.concat(this.encapsulateAutoComplete(positions.filter(p => p.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.position)); result = result.concat(this.encapsulateAutoComplete(positions
.filter(p => p.toLowerCase().indexOf(text.toLowerCase()) !== -1), SearchTypes.position));
}); });
result = result.concat(this.encapsulateAutoComplete((await photoRepository result = result.concat(this.encapsulateAutoComplete((await photoRepository
@ -86,7 +90,7 @@ export class SearchManager implements ISearchManager {
resultOverflow: false resultOverflow: false
}; };
let query = connection const query = connection
.getRepository(PhotoEntity) .getRepository(PhotoEntity)
.createQueryBuilder('photo') .createQueryBuilder('photo')
.innerJoinAndSelect('photo.directory', 'directory') .innerJoinAndSelect('photo.directory', 'directory')
@ -136,9 +140,9 @@ export class SearchManager implements ISearchManager {
async instantSearch(text: string): Promise<SearchResultDTO> { async instantSearch(text: string): Promise<SearchResultDTO> {
const connection = await SQLConnection.getConnection(); const connection = await SQLConnection.getConnection();
let result: SearchResultDTO = <SearchResultDTO>{ const result: SearchResultDTO = <SearchResultDTO>{
searchText: text, searchText: text,
//searchType:undefined, not adding this // searchType:undefined, not adding this
directories: [], directories: [],
photos: [], photos: [],
resultOverflow: false resultOverflow: false
@ -169,7 +173,7 @@ export class SearchManager implements ISearchManager {
} }
private encapsulateAutoComplete(values: Array<string>, type: SearchTypes): Array<AutoCompleteItem> { private encapsulateAutoComplete(values: Array<string>, type: SearchTypes): Array<AutoCompleteItem> {
let res = []; const res = [];
values.forEach((value) => { values.forEach((value) => {
res.push(new AutoCompleteItem(value, type)); res.push(new AutoCompleteItem(value, type));
}); });

View File

@ -42,7 +42,7 @@ export class SharingManager implements ISharingManager {
}); });
if (sharing.timeStamp < Date.now() - Config.Server.sharing.updateTimeout) { if (sharing.timeStamp < Date.now() - Config.Server.sharing.updateTimeout) {
throw 'Sharing is locked, can\'t update anymore'; throw new Error('Sharing is locked, can\'t update anymore');
} }
if (inSharing.password == null) { if (inSharing.password == null) {
sharing.password = null; sharing.password = null;

View File

@ -13,7 +13,7 @@ export class UserManager implements IUserManager {
public async findOne(filter: any) { public async findOne(filter: any) {
const connection = await SQLConnection.getConnection(); const connection = await SQLConnection.getConnection();
let pass = filter.password; const pass = filter.password;
delete filter.password; delete filter.password;
const user = (await connection.getRepository(UserEntity).findOne(filter)); const user = (await connection.getRepository(UserEntity).findOne(filter));
@ -22,11 +22,11 @@ export class UserManager implements IUserManager {
} }
if (pass && !PasswordHelper.comparePassword(pass, user.password)) { if (pass && !PasswordHelper.comparePassword(pass, user.password)) {
throw 'No entry found'; throw new Error('No entry found');
} }
return user; return user;
}; }
public async find(filter: any) { public async find(filter: any) {
const connection = await SQLConnection.getConnection(); const connection = await SQLConnection.getConnection();
@ -56,7 +56,7 @@ export class UserManager implements IUserManager {
public async changeRole(id: number, newRole: UserRoles) { public async changeRole(id: number, newRole: UserRoles) {
const connection = await SQLConnection.getConnection(); const connection = await SQLConnection.getConnection();
let userRepository = connection.getRepository(UserEntity); const userRepository = connection.getRepository(UserEntity);
const user = await userRepository.findOne({id: id}); const user = await userRepository.findOne({id: id});
user.role = newRole; user.role = newRole;
return await userRepository.save(user); return await userRepository.save(user);
@ -64,7 +64,7 @@ export class UserManager implements IUserManager {
} }
public async changePassword(request: any) { public async changePassword(request: any) {
throw new Error('not implemented'); //TODO: implement throw new Error('not implemented'); // TODO: implement
} }
} }

View File

@ -108,6 +108,6 @@ export class PhotoEntity implements PhotoDTO {
readyThumbnails: Array<number> = []; readyThumbnails: Array<number> = [];
readyIcon: boolean = false; readyIcon = false;
} }

View File

@ -53,11 +53,11 @@ export class DiskMangerWorker {
for (let i = 0; i < list.length; i++) { for (let i = 0; i < list.length; i++) {
const file = list[i]; const file = list[i];
const fullFilePath = path.normalize(path.resolve(absoluteDirectoryName, file)); const fullFilePath = path.normalize(path.resolve(absoluteDirectoryName, file));
if (photosOnly == false && fs.statSync(fullFilePath).isDirectory()) { if (photosOnly === false && fs.statSync(fullFilePath).isDirectory()) {
const d = await DiskMangerWorker.scanDirectory(path.join(relativeDirectoryName, file), const d = await DiskMangerWorker.scanDirectory(path.join(relativeDirectoryName, file),
Config.Server.indexing.folderPreviewSize, true Config.Server.indexing.folderPreviewSize, true
); );
d.lastScanned = 0; //it was not a fully scan d.lastScanned = 0; // it was not a fully scan
d.isPartial = true; d.isPartial = true;
directory.directories.push(d); directory.directories.push(d);
} else if (DiskMangerWorker.isImage(fullFilePath)) { } else if (DiskMangerWorker.isImage(fullFilePath)) {

View File

@ -15,9 +15,9 @@ export interface ITaskQue {
export class TaskQue implements ITaskQue { export class TaskQue implements ITaskQue {
private tasks: QueTask[] = []; private tasks: QueTask[] = [];
private taskInProgress: number = 0; private taskInProgress = 0;
private run = async () => { private run = async () => {
if (this.tasks.length == 0 || this.taskInProgress >= this.size) { if (this.tasks.length === 0 || this.taskInProgress >= this.size) {
return; return;
} }
this.taskInProgress++; this.taskInProgress++;

View File

@ -30,33 +30,19 @@ export class ThreadPool {
} }
} }
private startWorker() { private run = () => {
const worker = <WorkerWrapper>{poolTask: null, worker: cluster.fork()}; if (this.tasks.length === 0) {
this.workers.push(worker); return;
worker.worker.on('online', () => { }
ThreadPool.WorkerCount++; const worker = this.getFreeWorker();
Logger.debug('Worker ' + worker.worker.process.pid + ' is online, worker count:', ThreadPool.WorkerCount); if (worker == null) {
}); return;
worker.worker.on('exit', (code, signal) => { }
ThreadPool.WorkerCount--;
Logger.warn('Worker ' + worker.worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal + ', worker count:', ThreadPool.WorkerCount);
Logger.debug('Starting a new worker');
this.startWorker();
});
worker.worker.on('message', (msg: WorkerMessage) => { const poolTask = this.tasks.shift();
if (worker.poolTask == null) { worker.poolTask = poolTask;
throw 'No worker task after worker task is completed'; worker.worker.send(poolTask.task);
} };
if (msg.error) {
worker.poolTask.promise.reject(msg.error);
} else {
worker.poolTask.promise.resolve(msg.result);
}
worker.poolTask = null;
this.run();
});
}
protected executeTask<T>(task: WorkerTask): Promise<T> { protected executeTask<T>(task: WorkerTask): Promise<T> {
return new Promise((resolve: Function, reject: Function) => { return new Promise((resolve: Function, reject: Function) => {
@ -74,19 +60,34 @@ export class ThreadPool {
return null; return null;
} }
private run = () => { private startWorker() {
if (this.tasks.length == 0) { const worker = <WorkerWrapper>{poolTask: null, worker: cluster.fork()};
return; this.workers.push(worker);
} worker.worker.on('online', () => {
const worker = this.getFreeWorker(); ThreadPool.WorkerCount++;
if (worker == null) { Logger.debug('Worker ' + worker.worker.process.pid + ' is online, worker count:', ThreadPool.WorkerCount);
return; });
} worker.worker.on('exit', (code, signal) => {
ThreadPool.WorkerCount--;
Logger.warn('Worker ' + worker.worker.process.pid + ' died with code: ' + code +
', and signal: ' + signal + ', worker count:', ThreadPool.WorkerCount);
Logger.debug('Starting a new worker');
this.startWorker();
});
const poolTask = this.tasks.shift(); worker.worker.on('message', (msg: WorkerMessage) => {
worker.poolTask = poolTask; if (worker.poolTask == null) {
worker.worker.send(poolTask.task); throw new Error('No worker task after worker task is completed');
}; }
if (msg.error) {
worker.poolTask.promise.reject(msg.error);
} else {
worker.poolTask.promise.resolve(msg.result);
}
worker.poolTask = null;
this.run();
});
}
} }

View File

@ -9,7 +9,7 @@ export class ThumbnailWoker {
private static rendererType = null; private static rendererType = null;
public static render(input: RendererInput, renderer: ThumbnailProcessingLib): Promise<void> { public static render(input: RendererInput, renderer: ThumbnailProcessingLib): Promise<void> {
if (ThumbnailWoker.rendererType != renderer) { if (ThumbnailWoker.rendererType !== renderer) {
ThumbnailWoker.renderer = RendererFactory.build(renderer); ThumbnailWoker.renderer = RendererFactory.build(renderer);
ThumbnailWoker.rendererType = renderer; ThumbnailWoker.rendererType = renderer;
} }
@ -25,7 +25,7 @@ export interface RendererInput {
size: number; size: number;
makeSquare: boolean; makeSquare: boolean;
thPath: string; thPath: string;
qualityPriority: boolean qualityPriority: boolean;
} }
export class RendererFactory { export class RendererFactory {
@ -39,13 +39,13 @@ export class RendererFactory {
case ThumbnailProcessingLib.sharp: case ThumbnailProcessingLib.sharp:
return RendererFactory.Sharp(); return RendererFactory.Sharp();
} }
throw 'unknown renderer'; throw new Error('unknown renderer');
} }
public static Jimp() { public static Jimp() {
const Jimp = require('jimp'); const Jimp = require('jimp');
return async (input: RendererInput): Promise<void> => { return async (input: RendererInput): Promise<void> => {
//generate thumbnail // generate thumbnail
Logger.silly('[JimpThRenderer] rendering thumbnail:', input.imagePath); Logger.silly('[JimpThRenderer] rendering thumbnail:', input.imagePath);
const image = await Jimp.read(input.imagePath); const image = await Jimp.read(input.imagePath);
/** /**
@ -58,9 +58,9 @@ export class RendererFactory {
* @type {number} * @type {number}
*/ */
const ratio = image.bitmap.height / image.bitmap.width; const ratio = image.bitmap.height / image.bitmap.width;
const algo = input.qualityPriority == true ? Jimp.RESIZE_BEZIER : Jimp.RESIZE_NEAREST_NEIGHBOR; const algo = input.qualityPriority === true ? Jimp.RESIZE_BEZIER : Jimp.RESIZE_NEAREST_NEIGHBOR;
if (input.makeSquare == false) { if (input.makeSquare === false) {
let newWidth = Math.sqrt((input.size * input.size) / ratio); const newWidth = Math.sqrt((input.size * input.size) / ratio);
image.resize(newWidth, Jimp.AUTO, algo); image.resize(newWidth, Jimp.AUTO, algo);
} else { } else {
@ -100,8 +100,8 @@ export class RendererFactory {
* @type {number} * @type {number}
*/ */
const ratio = metadata.height / metadata.width; const ratio = metadata.height / metadata.width;
const kernel = input.qualityPriority == true ? sharp.kernel.lanczos3 : sharp.kernel.nearest; const kernel = input.qualityPriority === true ? sharp.kernel.lanczos3 : sharp.kernel.nearest;
if (input.makeSquare == false) { if (input.makeSquare === false) {
const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio)); const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio));
image.resize(newWidth, null, { image.resize(newWidth, null, {
kernel: kernel kernel: kernel
@ -141,19 +141,19 @@ export class RendererFactory {
*/ */
try { try {
const ratio = value.height / value.width; const ratio = value.height / value.width;
const filter = input.qualityPriority == true ? 'Lanczos' : 'Point'; const filter = input.qualityPriority === true ? 'Lanczos' : 'Point';
image.filter(filter); image.filter(filter);
if (input.makeSquare == false) { if (input.makeSquare === false) {
const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio)); const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio));
image = image.resize(newWidth); image = image.resize(newWidth);
} else { } else {
image = image.resize(input.size, input.size) image = image.resize(input.size, input.size)
.crop(input.size, input.size); .crop(input.size, input.size);
} }
image.write(input.thPath, (err) => { image.write(input.thPath, (e) => {
if (err) { if (e) {
return reject(err); return reject(e);
} }
return resolve(); return resolve();
}); });

View File

@ -23,7 +23,7 @@ export class Worker {
break; break;
default: default:
Logger.error('Unknown worker task type'); Logger.error('Unknown worker task type');
throw 'Unknown worker task type'; throw new Error('Unknown worker task type');
} }
process.send(<WorkerMessage>{ process.send(<WorkerMessage>{
error: null, error: null,
@ -32,7 +32,6 @@ export class Worker {
} catch (err) { } catch (err) {
process.send({error: err, result: null}); process.send({error: err, result: null});
} }
}); });
} }
} }

View File

@ -1,15 +1,18 @@
import {NextFunction, Request, Response} from 'express'; import {NextFunction, Request, Response} from 'express';
import * as path from 'path'; import * as path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
import * as ejs from 'ejs';
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'; import {AuthenticationMWs} from '../middlewares/user/AuthenticationMWs';
import {CookieNames} from '../../common/CookieNames'; import {CookieNames} from '../../common/CookieNames';
import {ErrorDTO} from '../../common/entities/Error';
export class PublicRouter { export class PublicRouter {
public static route(app) { public static route(app) {
const setLocale = (req: Request, res: Response, next: Function) => { const setLocale = (req: Request, res: Response, next: Function) => {
let localePath = ''; let localePath = '';
@ -27,8 +30,14 @@ export class PublicRouter {
next(); next();
}; };
const renderIndex = (req: Request, res: Response) => { const renderIndex = (req: Request, res: Response, next: Function) => {
res.sendFile(path.resolve(ProjectPath.FrontendFolder, req['localePath'], 'index.html'), {maxAge: 31536000}); ejs.renderFile(path.resolve(ProjectPath.FrontendFolder, req['localePath'], 'index.html'),
res.tpl, (err, str) => {
if (err) {
return next(new ErrorDTO(err));
}
res.send(str);
});
}; };
@ -56,9 +65,6 @@ export class PublicRouter {
return next(); return next();
}); });
app.get('/config_inject.js', (req: Request, res: Response) => {
res.render(path.resolve(ProjectPath.FrontendFolder, 'config_inject.ejs'), res.tpl);
});
app.get(['/', '/login', '/gallery*', '/share*', '/admin', '/search*'], app.get(['/', '/login', '/gallery*', '/share*', '/admin', '/search*'],
AuthenticationMWs.tryAuthenticate, AuthenticationMWs.tryAuthenticate,

View File

@ -18,7 +18,7 @@ export class SharingRouter {
AuthenticationMWs.shareLogin, AuthenticationMWs.shareLogin,
RenderingMWs.renderSessionUser RenderingMWs.renderSessionUser
); );
}; }
private static addGetSharing(app) { private static addGetSharing(app) {
app.get('/api/share/:sharingKey', app.get('/api/share/:sharingKey',
@ -27,7 +27,7 @@ export class SharingRouter {
SharingMWs.getSharing, SharingMWs.getSharing,
RenderingMWs.renderSharing RenderingMWs.renderSharing
); );
}; }
private static addCreateSharing(app) { private static addCreateSharing(app) {
app.post(['/api/share/:directory(*)', '/api/share/', '/api/share//'], app.post(['/api/share/:directory(*)', '/api/share/', '/api/share//'],
@ -36,7 +36,7 @@ export class SharingRouter {
SharingMWs.createSharing, SharingMWs.createSharing,
RenderingMWs.renderSharing RenderingMWs.renderSharing
); );
}; }
private static addUpdateSharing(app) { private static addUpdateSharing(app) {
app.put(['/api/share/:directory(*)', '/api/share/', '/api/share//'], app.put(['/api/share/:directory(*)', '/api/share/', '/api/share//'],
@ -45,7 +45,6 @@ export class SharingRouter {
SharingMWs.updateSharing, SharingMWs.updateSharing,
RenderingMWs.renderSharing RenderingMWs.renderSharing
); );
}; }
} }

View File

@ -30,8 +30,44 @@ export class Server {
private app: any; private app: any;
private server: any; private server: any;
/**
* Event listener for HTTP server "error" event.
*/
private onError = (error: any) => {
if (error.syscall !== 'listen') {
Logger.error(LOG_TAG, 'Server error', error);
throw error;
}
const bind = 'Port ' + Config.Server.port;
// handle specific listen error with friendly messages
switch (error.code) {
case 'EACCES':
Logger.error(LOG_TAG, bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
Logger.error(LOG_TAG, bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
};
/**
* Event listener for HTTP server "listening" event.
*/
private onListening = () => {
const addr = this.server.address();
const bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
Logger.info(LOG_TAG, 'Listening on ' + bind);
};
constructor() { constructor() {
if (!(process.env.NODE_ENV == 'production')) { if (!(process.env.NODE_ENV === 'production')) {
Logger.debug(LOG_TAG, 'Running in DEBUG mode'); Logger.debug(LOG_TAG, 'Running in DEBUG mode');
} }
this.init(); this.init();
@ -82,7 +118,7 @@ export class Server {
Localizations.init(); Localizations.init();
this.app.use(locale(Config.Client.languages, 'en')); this.app.use(locale(Config.Client.languages, 'en'));
if (Config.Server.database.type != DatabaseType.memory) { if (Config.Server.database.type !== DatabaseType.memory) {
await ObjectManagerRepository.InitSQLManagers(); await ObjectManagerRepository.InitSQLManagers();
} else { } else {
await ObjectManagerRepository.InitMemoryManagers(); await ObjectManagerRepository.InitMemoryManagers();
@ -105,7 +141,7 @@ export class Server {
// Create HTTP server. // Create HTTP server.
this.server = _http.createServer(this.app); this.server = _http.createServer(this.app);
//Listen on provided PORT, on all network interfaces. // Listen on provided PORT, on all network interfaces.
this.server.listen(Config.Server.port); this.server.listen(Config.Server.port);
this.server.on('error', this.onError); this.server.on('error', this.onError);
this.server.on('listening', this.onListening); this.server.on('listening', this.onListening);
@ -113,47 +149,6 @@ export class Server {
} }
/**
* Event listener for HTTP server "error" event.
*/
private onError = (error: any) => {
if (error.syscall !== 'listen') {
Logger.error(LOG_TAG, 'Server error', error);
throw error;
}
const bind = typeof Config.Server.port === 'string'
? 'Pipe ' + Config.Server.port
: 'Port ' + Config.Server.port;
// handle specific listen error with friendly messages
switch (error.code) {
case 'EACCES':
Logger.error(LOG_TAG, bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
Logger.error(LOG_TAG, bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
};
/**
* Event listener for HTTP server "listening" event.
*/
private onListening = () => {
let addr = this.server.address();
const bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
Logger.info(LOG_TAG, 'Listening on ' + bind);
};
} }

View File

@ -1,4 +1,4 @@
export class CookieNames { export class CookieNames {
public static lang = "pigallery2-lang"; public static lang = 'pigallery2-lang';
public static session = "pigallery2-session"; public static session = 'pigallery2-session';
} }

View File

@ -6,14 +6,14 @@ export class Utils {
} }
static equalsFilter(object: any, filter: any): boolean { static equalsFilter(object: any, filter: any): boolean {
if (typeof filter !== "object" || filter == null) { if (typeof filter !== 'object' || filter == null) {
return object == filter; return object === filter;
} }
const keys = Object.keys(filter); const keys = Object.keys(filter);
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const key = keys[i]; const key = keys[i];
if (typeof filter[key] === "object") { if (typeof filter[key] === 'object') {
if (Utils.equalsFilter(object[key], filter[key]) == false) { if (Utils.equalsFilter(object[key], filter[key]) === false) {
return false; return false;
} }
} else if (object[key] !== filter[key]) { } else if (object[key] !== filter[key]) {
@ -27,19 +27,23 @@ export class Utils {
static concatUrls(...args: Array<string>) { static concatUrls(...args: Array<string>) {
let url = ""; let url = '';
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
if (args[i] === "" || typeof args[i] === "undefined") continue; if (args[i] === '' || typeof args[i] === 'undefined') {
continue;
}
let part = args[i].replace("\\", "/"); const part = args[i].replace('\\', '/');
if (part === "/" || part === "./") continue; if (part === '/' || part === './') {
continue;
}
url += part + "/"; url += part + '/';
} }
url = url.replace("//", "/"); url = url.replace('//', '/');
if (url.trim() == "") { if (url.trim() === '') {
url = "./"; url = './';
} }
return url.substring(0, url.length - 1); return url.substring(0, url.length - 1);
@ -47,10 +51,10 @@ export class Utils {
public static updateKeys(targetObject: any, sourceObject: any) { public static updateKeys(targetObject: any, sourceObject: any) {
Object.keys(sourceObject).forEach((key) => { Object.keys(sourceObject).forEach((key) => {
if (typeof targetObject[key] === "undefined") { if (typeof targetObject[key] === 'undefined') {
return; return;
} }
if (typeof targetObject[key] === "object") { if (typeof targetObject[key] === 'object') {
Utils.updateKeys(targetObject[key], sourceObject[key]); Utils.updateKeys(targetObject[key], sourceObject[key]);
} else { } else {
targetObject[key] = sourceObject[key]; targetObject[key] = sourceObject[key];
@ -60,7 +64,7 @@ export class Utils {
public static setKeys(targetObject: any, sourceObject: any) { public static setKeys(targetObject: any, sourceObject: any) {
Object.keys(sourceObject).forEach((key) => { Object.keys(sourceObject).forEach((key) => {
if (typeof targetObject[key] === "object") { if (typeof targetObject[key] === 'object') {
Utils.setKeys(targetObject[key], sourceObject[key]); Utils.setKeys(targetObject[key], sourceObject[key]);
} else { } else {
targetObject[key] = sourceObject[key]; targetObject[key] = sourceObject[key];
@ -70,8 +74,8 @@ export class Utils {
public static setKeysForced(targetObject: any, sourceObject: any) { public static setKeysForced(targetObject: any, sourceObject: any) {
Object.keys(sourceObject).forEach((key) => { Object.keys(sourceObject).forEach((key) => {
if (typeof sourceObject[key] === "object") { if (typeof sourceObject[key] === 'object') {
if (typeof targetObject[key] === "undefined") { if (typeof targetObject[key] === 'undefined') {
targetObject[key] = {}; targetObject[key] = {};
} }
Utils.setKeysForced(targetObject[key], sourceObject[key]); Utils.setKeysForced(targetObject[key], sourceObject[key]);
@ -85,12 +89,12 @@ export class Utils {
key: number; key: number;
value: string; value: string;
}> { }> {
let arr: Array<{ key: number; value: string; }> = []; const arr: Array<{ key: number; value: string; }> = [];
for (let enumMember in EnumType) { for (const enumMember in EnumType) {
if (!EnumType.hasOwnProperty(enumMember)) { if (!EnumType.hasOwnProperty(enumMember)) {
continue; continue;
} }
let key = parseInt(enumMember, 10); const key = parseInt(enumMember, 10);
if (key >= 0) { if (key >= 0) {
arr.push({key: key, value: EnumType[enumMember]}); arr.push({key: key, value: EnumType[enumMember]});
} }
@ -106,7 +110,7 @@ export class Utils {
arr.forEach((value) => { arr.forEach((value) => {
let newDiff = Math.abs(number - value); const newDiff = Math.abs(number - value);
if (newDiff < diff) { if (newDiff < diff) {
diff = newDiff; diff = newDiff;

View File

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

View File

@ -1,4 +1,4 @@
import {ClientConfig} from "../public/ConfigClass"; import {ClientConfig} from '../public/ConfigClass';
export enum DatabaseType { export enum DatabaseType {
memory = 0, mysql = 1, sqlite = 2 memory = 0, mysql = 1, sqlite = 2
@ -47,7 +47,7 @@ export enum ReIndexingSensitivity {
export interface IndexingConfig { export interface IndexingConfig {
folderPreviewSize: number; folderPreviewSize: number;
cachedFolderTimeout: number;//Do not rescans the folder if seems ok cachedFolderTimeout: number; // Do not rescans the folder if seems ok
reIndexingSensitivity: ReIndexingSensitivity; reIndexingSensitivity: ReIndexingSensitivity;
} }
@ -58,7 +58,7 @@ export interface ServerConfig {
database: DataBaseConfig; database: DataBaseConfig;
enableThreading: boolean; enableThreading: boolean;
sharing: SharingConfig; sharing: SharingConfig;
sessionTimeout: number sessionTimeout: number;
indexing: IndexingConfig; indexing: IndexingConfig;
} }

View File

@ -1,13 +1,7 @@
import {PublicConfigClass} from "../public/ConfigClass"; import {PublicConfigClass} from '../public/ConfigClass';
import { import {DatabaseType, IPrivateConfig, ReIndexingSensitivity, ServerConfig, ThumbnailProcessingLib} from './IPrivateConfig';
DatabaseType, import * as path from 'path';
IPrivateConfig, import {ConfigLoader} from 'typeconfig';
ReIndexingSensitivity,
ServerConfig,
ThumbnailProcessingLib
} from "./IPrivateConfig";
import * as path from "path";
import {ConfigLoader} from "typeconfig";
/** /**
* This configuration will be only at backend * This configuration will be only at backend
@ -16,9 +10,9 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
public Server: ServerConfig = { public Server: ServerConfig = {
port: 80, port: 80,
imagesFolder: "demo/images", imagesFolder: 'demo/images',
thumbnail: { thumbnail: {
folder: "demo/TEMP", folder: 'demo/TEMP',
processingLibrary: ThumbnailProcessingLib.sharp, processingLibrary: ThumbnailProcessingLib.sharp,
qualityPriority: true qualityPriority: true
}, },
@ -26,14 +20,14 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
database: { database: {
type: DatabaseType.sqlite, type: DatabaseType.sqlite,
mysql: { mysql: {
host: "", host: '',
username: "", username: '',
password: "", password: '',
database: "" database: ''
}, },
sqlite: { sqlite: {
storage: "sqlite.db" storage: 'sqlite.db'
} }
}, },
sharing: { sharing: {
@ -59,7 +53,7 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
public load() { public load() {
ConfigLoader.loadBackendConfig(this, ConfigLoader.loadBackendConfig(this,
path.join(__dirname, './../../../config.json'), path.join(__dirname, './../../../config.json'),
[["PORT", "Server-port"]]); [['PORT', 'Server-port']]);
} }
@ -68,7 +62,7 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
} }
public original(): PrivateConfigClass { public original(): PrivateConfigClass {
let cfg = new PrivateConfigClass(); const cfg = new PrivateConfigClass();
cfg.load(); cfg.load();
return cfg; return cfg;
} }

View File

@ -1,5 +1,5 @@
import {PublicConfigClass} from "./ConfigClass"; import {PublicConfigClass} from './ConfigClass';
import {WebConfigLoader} from "typeconfig/src/WebConfigLoader"; import {WebConfigLoader} from 'typeconfig/src/WebConfigLoader';
declare module ServerInject { declare module ServerInject {
@ -9,12 +9,12 @@ declare module ServerInject {
export let Config = new PublicConfigClass(); export let Config = new PublicConfigClass();
if (typeof ServerInject !== "undefined" && typeof ServerInject.ConfigInject !== "undefined") { if (typeof ServerInject !== 'undefined' && typeof ServerInject.ConfigInject !== 'undefined') {
WebConfigLoader.loadFrontendConfig(Config.Client, ServerInject.ConfigInject); WebConfigLoader.loadFrontendConfig(Config.Client, ServerInject.ConfigInject);
} }
if (Config.Client.publicUrl == "") { if (Config.Client.publicUrl === '') {
Config.Client.publicUrl = location.origin; Config.Client.publicUrl = location.origin;
} }

View File

@ -1,8 +1,8 @@
export module ClientConfig { export module ClientConfig {
export interface SearchConfig { export interface SearchConfig {
enabled: boolean enabled: boolean;
instantSearchEnabled: boolean instantSearchEnabled: boolean;
autocompleteEnabled: boolean autocompleteEnabled: boolean;
InstantSearchTimeout: number; InstantSearchTimeout: number;
autocompleteCacheTimeout: number; autocompleteCacheTimeout: number;
instantSearchCacheTimeout: number; instantSearchCacheTimeout: number;
@ -36,6 +36,7 @@ export module ClientConfig {
enableOnScrollThumbnailPrioritising: boolean; enableOnScrollThumbnailPrioritising: boolean;
authenticationRequired: boolean; authenticationRequired: boolean;
publicUrl: string; publicUrl: string;
urlBase: string;
languages: string[]; languages: string[];
} }
@ -47,7 +48,7 @@ export module ClientConfig {
export class PublicConfigClass { export class PublicConfigClass {
public Client: ClientConfig.Config = { public Client: ClientConfig.Config = {
applicationTitle: "PiGallery 2", applicationTitle: 'PiGallery 2',
Thumbnail: { Thumbnail: {
thumbnailSizes: [200, 400, 600], thumbnailSizes: [200, 400, 600],
iconSize: 30 iconSize: 30
@ -67,14 +68,15 @@ export class PublicConfigClass {
}, },
Map: { Map: {
enabled: true, enabled: true,
googleApiKey: "" googleApiKey: ''
}, },
concurrentThumbnailGenerations: 1, concurrentThumbnailGenerations: 1,
enableCache: true, enableCache: true,
enableOnScrollRendering: true, enableOnScrollRendering: true,
enableOnScrollThumbnailPrioritising: true, enableOnScrollThumbnailPrioritising: true,
authenticationRequired: true, authenticationRequired: true,
publicUrl: "", publicUrl: '',
urlBase: '',
languages: [] languages: []
}; };

View File

@ -1,5 +1,5 @@
import {DirectoryDTO} from "./DirectoryDTO"; import {DirectoryDTO} from './DirectoryDTO';
import {SearchResultDTO} from "./SearchResultDTO"; import {SearchResultDTO} from './SearchResultDTO';
export class ContentWrapper { export class ContentWrapper {
constructor(public directory: DirectoryDTO = null, constructor(public directory: DirectoryDTO = null,

View File

@ -1,4 +1,4 @@
import {PhotoDTO} from "./PhotoDTO"; import {PhotoDTO} from './PhotoDTO';
export interface DirectoryDTO { export interface DirectoryDTO {
id: number; id: number;
@ -22,5 +22,5 @@ export module DirectoryDTO {
addReferences(directory); addReferences(directory);
directory.parent = dir; directory.parent = dir;
}); });
} };
} }

View File

@ -1,4 +1,4 @@
export enum ErrorCodes{ export enum ErrorCodes {
NOT_AUTHENTICATED = 0, NOT_AUTHENTICATED = 0,
ALREADY_AUTHENTICATED = 1, ALREADY_AUTHENTICATED = 1,
NOT_AUTHORISED = 2, NOT_AUTHORISED = 2,

View File

@ -1,5 +1,7 @@
export class LoginCredential { export class LoginCredential {
constructor(public username: string = "", public password: string = "", public rememberMe: boolean = false) { constructor(public username: string = '',
public password: string = '',
public rememberMe: boolean = false) {
} }
} }

View File

@ -1,4 +1,4 @@
import {ErrorDTO} from "./Error"; import {ErrorDTO} from './Error';
export class Message<T> { export class Message<T> {
public error: ErrorDTO = null; public error: ErrorDTO = null;

View File

@ -1,4 +1,4 @@
export enum NotificationType{ export enum NotificationType {
error, warning, info error, warning, info
} }

View File

@ -1,4 +1,4 @@
import {UserModificationRequest} from "./UserModificationRequest"; import {UserModificationRequest} from './UserModificationRequest';
export class PasswordChangeRequest extends UserModificationRequest { export class PasswordChangeRequest extends UserModificationRequest {

View File

@ -1,4 +1,4 @@
import {DirectoryDTO} from "./DirectoryDTO"; import {DirectoryDTO} from './DirectoryDTO';
export interface PhotoDTO { export interface PhotoDTO {
id: number; id: number;

View File

@ -1,6 +1,6 @@
import {DirectoryDTO} from "./DirectoryDTO"; import {DirectoryDTO} from './DirectoryDTO';
import {PhotoDTO} from "./PhotoDTO"; import {PhotoDTO} from './PhotoDTO';
import {SearchTypes} from "./AutoCompleteItem"; import {SearchTypes} from './AutoCompleteItem';
export interface SearchResultDTO { export interface SearchResultDTO {
searchText: string; searchText: string;

View File

@ -1,4 +1,4 @@
import {UserDTO} from "./UserDTO"; import {UserDTO} from './UserDTO';
export interface SharingDTO { export interface SharingDTO {
id: number; id: number;

View File

@ -1,5 +1,5 @@
import {DirectoryDTO} from "./DirectoryDTO"; import {DirectoryDTO} from './DirectoryDTO';
import {Utils} from "../Utils"; import {Utils} from '../Utils';
export enum UserRoles { export enum UserRoles {
LimitedGuest = 0, LimitedGuest = 0,
@ -15,25 +15,25 @@ export interface UserDTO {
name: string; name: string;
password: string; password: string;
role: UserRoles; role: UserRoles;
permissions: string[]; //user can only see these permissions. if ends with *, its recursive permissions: string[]; // user can only see these permissions. if ends with *, its recursive
} }
export module UserDTO { export module UserDTO {
export const isPathAvailable = (path: string, permissions: string[]): boolean => { export const isPathAvailable = (path: string, permissions: string[]): boolean => {
if (permissions == null || permissions.length == 0 || permissions[0] == "/*") { if (permissions == null || permissions.length === 0 || permissions[0] === '/*') {
return true; return true;
} }
for (let i = 0; i < permissions.length; i++) { for (let i = 0; i < permissions.length; i++) {
let permission = permissions[i]; let permission = permissions[i];
if (permission[permission.length - 1] == "*") { if (permission[permission.length - 1] === '*') {
permission = permission.slice(0, -1); permission = permission.slice(0, -1);
if (path.startsWith(permission)) { if (path.startsWith(permission)) {
return true; return true;
} }
} else if (path == permission) { } else if (path === permission) {
return true; return true;
} else if (path == "." && permission == "/") { } else if (path === '.' && permission === '/') {
return true; return true;
} }

View File

@ -1,6 +1,7 @@
export interface BasicConfigDTO { export interface BasicConfigDTO {
imagesFolder: string; imagesFolder: string;
publicUrl: string; publicUrl: string;
urlBase: string;
applicationTitle: string; applicationTitle: string;
port: number; port: number;
} }

View File

@ -1,19 +1,19 @@
function isFunction(functionToCheck: any) { function isFunction(functionToCheck: any) {
let getType = {}; const getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
} }
export class Event<T> { export class Event<T> {
private handlers: { (data?: T): void; }[] = []; private handlers: ((data?: T) => void)[] = [];
public on(handler: { (data?: T): void }) { public on(handler: (data?: T) => void) {
if (!isFunction(handler)) { if (!isFunction(handler)) {
throw new Error("Handler is not a function"); throw new Error('Handler is not a function');
} }
this.handlers.push(handler); this.handlers.push(handler);
} }
public off(handler: { (data?: T): void }) { public off(handler: (data?: T) => void) {
this.handlers = this.handlers.filter(h => h !== handler); this.handlers = this.handlers.filter(h => h !== handler);
} }

View File

@ -1,11 +1,11 @@
export class Event2Args<T, M> { export class Event2Args<T, M> {
private handlers: { (data?: T, data2?: M): void; }[] = []; private handlers: ((data?: T, data2?: M) => void)[] = [];
public on(handler: { (data?: T, data2?: M): void }) { public on(handler: (data?: T, data2?: M) => void) {
this.handlers.push(handler); this.handlers.push(handler);
} }
public off(handler: { (data?: T, data2?: M): void }) { public off(handler: (data?: T, data2?: M) => void) {
this.handlers = this.handlers.filter(h => h !== handler); this.handlers = this.handlers.filter(h => h !== handler);
} }

View File

@ -4,21 +4,21 @@ export class EventLimit<T> {
private handlers: Array<EventLimitHandler<T>> = []; private handlers: Array<EventLimitHandler<T>> = [];
public on(limit: T, handler: { (data?: T): void }) { public on(limit: T, handler: (data?: T) => void) {
this.handlers.push(new EventLimitHandler(limit, handler)); this.handlers.push(new EventLimitHandler(limit, handler));
if (this.lastTriggerValue != null) { if (this.lastTriggerValue != null) {
this.trigger(this.lastTriggerValue); this.trigger(this.lastTriggerValue);
} }
} }
public onSingle(limit: T, handler: { (data?: T): void }) { public onSingle(limit: T, handler: (data?: T) => void) {
this.handlers.push(new SingleFireEventLimitHandler(limit, handler)); this.handlers.push(new SingleFireEventLimitHandler(limit, handler));
if (this.lastTriggerValue != null) { if (this.lastTriggerValue != null) {
this.trigger(this.lastTriggerValue); this.trigger(this.lastTriggerValue);
} }
} }
public off(limit: T, handler: { (data?: T): void }) { public off(limit: T, handler: (data?: T) => void) {
this.handlers = this.handlers.filter(h => h.handler !== handler && h.limit !== limit); this.handlers = this.handlers.filter(h => h.handler !== handler && h.limit !== limit);
} }
@ -43,7 +43,7 @@ export class EventLimit<T> {
class EventLimitHandler<T> { class EventLimitHandler<T> {
public lastTriggerValue: T = null; public lastTriggerValue: T = null;
constructor(public limit: T, public handler: { (data?: T): void }) { constructor(public limit: T, public handler: (data?: T) => void) {
} }
public fire(data?: T) { public fire(data?: T) {
@ -54,18 +54,19 @@ class EventLimitHandler<T> {
return true; return true;
} }
} }
class SingleFireEventLimitHandler<T> extends EventLimitHandler<T> { class SingleFireEventLimitHandler<T> extends EventLimitHandler<T> {
public fired = false; public fired = false;
constructor(public limit: T, public handler: { (data?: T): void }) { constructor(public limit: T, public handler: (data?: T) => void) {
super(limit, handler); super(limit, handler);
} }
public fire(data?: T) { public fire(data?: T) {
if (this.fired == false) { if (this.fired === false) {
this.handler(data); this.handler(data);
} }
this.fired = true this.fired = true;
} }
public isValid(): boolean { public isValid(): boolean {

View File

@ -1,5 +1,6 @@
import {PhotoDTO} from '../../../common/entities/PhotoDTO'; import {PhotoDTO} from '../../../common/entities/PhotoDTO';
import {Utils} from '../../../common/Utils'; import {Utils} from '../../../common/Utils';
import {Config} from '../../../common/config/public/Config';
export class IconPhoto { export class IconPhoto {
@ -19,23 +20,29 @@ export class IconPhoto {
} }
getIconPath() { getIconPath() {
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name, 'icon'); return Utils.concatUrls(Config.Client.urlBase,
'/api/gallery/content/',
this.photo.directory.path, this.photo.directory.name, this.photo.name, 'icon');
} }
getPhotoPath() { getPhotoPath() {
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name); return Utils.concatUrls(Config.Client.urlBase,
'/api/gallery/content/',
this.photo.directory.path, this.photo.directory.name, this.photo.name);
} }
equals(other: PhotoDTO | IconPhoto): boolean { equals(other: PhotoDTO | IconPhoto): boolean {
//is gridphoto // is gridphoto
if (other instanceof IconPhoto) { if (other instanceof IconPhoto) {
return this.photo.directory.path === other.photo.directory.path && this.photo.directory.name === other.photo.directory.name && this.photo.name === other.photo.name; return this.photo.directory.path === other.photo.directory.path &&
this.photo.directory.name === other.photo.directory.name && this.photo.name === other.photo.name;
} }
//is photo // is photo
if (other.directory) { if (other.directory) {
return this.photo.directory.path === other.directory.path && this.photo.directory.name === other.directory.name && this.photo.name === other.name; return this.photo.directory.path === other.directory.path &&
this.photo.directory.name === other.directory.name && this.photo.name === other.name;
} }
return false; return false;

View File

@ -19,7 +19,7 @@ export class Photo extends IconPhoto {
} }
getThumbnailSize() { getThumbnailSize() {
let renderSize = Math.sqrt(this.renderWidth * this.renderHeight); const renderSize = Math.sqrt(this.renderWidth * this.renderHeight);
return Utils.findClosest(renderSize, Config.Client.Thumbnail.thumbnailSizes); return Utils.findClosest(renderSize, Config.Client.Thumbnail.thumbnailSizes);
} }
@ -28,7 +28,7 @@ export class Photo extends IconPhoto {
if (this.replacementSizeCache === false) { if (this.replacementSizeCache === false) {
this.replacementSizeCache = null; this.replacementSizeCache = null;
let size = this.getThumbnailSize(); const size = this.getThumbnailSize();
if (!!this.photo.readyThumbnails) { if (!!this.photo.readyThumbnails) {
for (let i = 0; i < this.photo.readyThumbnails.length; i++) { for (let i = 0; i < this.photo.readyThumbnails.length; i++) {
if (this.photo.readyThumbnails[i] < size) { if (this.photo.readyThumbnails[i] < size) {
@ -46,18 +46,22 @@ export class Photo extends IconPhoto {
} }
isThumbnailAvailable() { isThumbnailAvailable() {
return this.photo.readyThumbnails && this.photo.readyThumbnails.indexOf(this.getThumbnailSize()) != -1; return this.photo.readyThumbnails && this.photo.readyThumbnails.indexOf(this.getThumbnailSize()) !== -1;
} }
getReplacementThumbnailPath() { getReplacementThumbnailPath() {
let size = this.getReplacementThumbnailSize(); const size = this.getReplacementThumbnailSize();
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString()); return Utils.concatUrls(Config.Client.urlBase,
'/api/gallery/content/',
this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
} }
getThumbnailPath() { getThumbnailPath() {
let size = this.getThumbnailSize(); const size = this.getThumbnailSize();
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString()); return Utils.concatUrls(Config.Client.urlBase,
'/api/gallery/content/',
this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
} }

View File

@ -68,7 +68,7 @@ export class GalleryCacheService {
public getSearch(text: string, type?: SearchTypes): SearchResultDTO { public getSearch(text: string, type?: SearchTypes): SearchResultDTO {
let key = GalleryCacheService.SEARCH_PREFIX + text; let key = GalleryCacheService.SEARCH_PREFIX + text;
if (typeof type != 'undefined') { if (typeof type !== 'undefined') {
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type; key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
} }
const tmp = localStorage.getItem(key); const tmp = localStorage.getItem(key);
@ -89,7 +89,7 @@ export class GalleryCacheService {
item: searchResult item: searchResult
}; };
let key = GalleryCacheService.SEARCH_PREFIX + text; let key = GalleryCacheService.SEARCH_PREFIX + text;
if (typeof type != 'undefined') { if (typeof type !== 'undefined') {
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type; key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
} }
localStorage.setItem(key, JSON.stringify(tmp)); localStorage.setItem(key, JSON.stringify(tmp));
@ -97,12 +97,12 @@ export class GalleryCacheService {
public getDirectory(directoryName: string): DirectoryDTO { public getDirectory(directoryName: string): DirectoryDTO {
if (Config.Client.enableCache == false) { if (Config.Client.enableCache === false) {
return null; return null;
} }
let value = localStorage.getItem(GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directoryName)); const value = localStorage.getItem(GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directoryName));
if (value != null) { if (value != null) {
let directory: DirectoryDTO = JSON.parse(value); const directory: DirectoryDTO = JSON.parse(value);
DirectoryDTO.addReferences(directory); DirectoryDTO.addReferences(directory);
return directory; return directory;
@ -111,12 +111,12 @@ export class GalleryCacheService {
} }
public setDirectory(directory: DirectoryDTO): void { public setDirectory(directory: DirectoryDTO): void {
if (Config.Client.enableCache == false) { if (Config.Client.enableCache === false) {
return; return;
} }
const key = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directory.path, directory.name); const key = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directory.path, directory.name);
if (directory.isPartial == true && localStorage.getItem(key)) { if (directory.isPartial === true && localStorage.getItem(key)) {
return; return;
} }
@ -124,7 +124,7 @@ export class GalleryCacheService {
directory.directories.forEach((dir: DirectoryDTO) => { directory.directories.forEach((dir: DirectoryDTO) => {
const sub_key = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(dir.path, dir.name); const sub_key = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(dir.path, dir.name);
if (localStorage.getItem(sub_key) == null) { //don't override existing if (localStorage.getItem(sub_key) == null) { // don't override existing
localStorage.setItem(sub_key, JSON.stringify(dir)); localStorage.setItem(sub_key, JSON.stringify(dir));
} }
}); });
@ -137,21 +137,21 @@ export class GalleryCacheService {
*/ */
public photoUpdated(photo: PhotoDTO): void { public photoUpdated(photo: PhotoDTO): void {
if (Config.Client.enableCache == false) { if (Config.Client.enableCache === false) {
return; return;
} }
let directoryName = Utils.concatUrls(photo.directory.path, photo.directory.name); const directoryName = Utils.concatUrls(photo.directory.path, photo.directory.name);
let value = localStorage.getItem(directoryName); const value = localStorage.getItem(directoryName);
if (value != null) { if (value != null) {
let directory: DirectoryDTO = JSON.parse(value); const directory: DirectoryDTO = JSON.parse(value);
directory.photos.forEach((p) => { directory.photos.forEach((p) => {
if (p.name === photo.name) { if (p.name === photo.name) {
//update data // update data
p.metadata = photo.metadata; p.metadata = photo.metadata;
p.readyThumbnails = photo.readyThumbnails; p.readyThumbnails = photo.readyThumbnails;
//save changes // save changes
localStorage.setItem(directoryName, JSON.stringify(directory)); localStorage.setItem(directoryName, JSON.stringify(directory));
return; return;
} }

View File

@ -28,10 +28,11 @@ export class GalleryDirectoryComponent implements OnInit, OnDestroy {
size: number = null; size: number = null;
getSanitizedThUrl() { getSanitizedThUrl() {
return this._sanitizer.bypassSecurityTrustStyle('url(' + encodeURI(this.thumbnail.Src).replace(/\(/g, '%28').replace(/\)/g, '%29') + ')'); return this._sanitizer.bypassSecurityTrustStyle('url(' + encodeURI(this.thumbnail.Src).replace(/\(/g, '%28')
.replace(/\)/g, '%29') + ')');
} }
//TODO: implement scroll // TODO: implement scroll
isInView(): boolean { isInView(): boolean {
return document.body.scrollTop < this.container.nativeElement.offsetTop + this.container.nativeElement.clientHeight return document.body.scrollTop < this.container.nativeElement.offsetTop + this.container.nativeElement.clientHeight
&& document.body.scrollTop + window.innerHeight > this.container.nativeElement.offsetTop; && document.body.scrollTop + window.innerHeight > this.container.nativeElement.offsetTop;

View File

@ -16,7 +16,7 @@ import {ContentWrapper} from '../../../common/entities/ConentWrapper';
import {PageHelper} from '../model/page.helper'; import {PageHelper} from '../model/page.helper';
@Component({ @Component({
selector: 'gallery', selector: 'app-gallery',
templateUrl: './gallery.component.html', templateUrl: './gallery.component.html',
styleUrls: ['./gallery.component.css'] styleUrls: ['./gallery.component.css']
}) })

View File

@ -36,7 +36,7 @@ export class GalleryService {
this.lastRequest.directory = directoryName; this.lastRequest.directory = directoryName;
const params = {}; const params = {};
if (Config.Client.Sharing.enabled == true) { if (Config.Client.Sharing.enabled === true) {
if (this._shareService.isSharing()) { if (this._shareService.isSharing()) {
params['sk'] = this._shareService.getSharingKey(); params['sk'] = this._shareService.getSharingKey();
} }
@ -52,13 +52,13 @@ export class GalleryService {
const cw = await this.networkService.getJson<ContentWrapper>('/gallery/content/' + directoryName, params); const cw = await this.networkService.getJson<ContentWrapper>('/gallery/content/' + directoryName, params);
if (!cw || cw.notModified == true) { if (!cw || cw.notModified === true) {
return; return;
} }
this.galleryCacheService.setDirectory(cw.directory); //save it before adding references this.galleryCacheService.setDirectory(cw.directory); // save it before adding references
if (this.lastRequest.directory != directoryName) { if (this.lastRequest.directory !== directoryName) {
return; return;
} }
@ -78,7 +78,7 @@ export class GalleryService {
if (this.searchId != null) { if (this.searchId != null) {
clearTimeout(this.searchId); clearTimeout(this.searchId);
} }
if (text === null || text === '' || text.trim() == '.') { if (text === null || text === '' || text.trim() === '.') {
return null; return null;
} }
@ -87,7 +87,7 @@ export class GalleryService {
cw.searchResult = this.galleryCacheService.getSearch(text, type); cw.searchResult = this.galleryCacheService.getSearch(text, type);
if (cw.searchResult == null) { if (cw.searchResult == null) {
const params = {}; const params = {};
if (typeof type != 'undefined') { if (typeof type !== 'undefined') {
params['type'] = type; params['type'] = type;
} }
cw.searchResult = (await this.networkService.getJson<ContentWrapper>('/search/' + text, params)).searchResult; cw.searchResult = (await this.networkService.getJson<ContentWrapper>('/search/' + text, params)).searchResult;
@ -98,7 +98,7 @@ export class GalleryService {
} }
public async instantSearch(text: string): Promise<ContentWrapper> { public async instantSearch(text: string): Promise<ContentWrapper> {
if (text === null || text === '' || text.trim() == '.') { if (text === null || text === '' || text.trim() === '.') {
const content = new ContentWrapper(this.lastDirectory); const content = new ContentWrapper(this.lastDirectory);
this.content.next(content); this.content.next(content);
if (this.searchId != null) { if (this.searchId != null) {
@ -119,7 +119,7 @@ export class GalleryService {
cw.directory = null; cw.directory = null;
cw.searchResult = this.galleryCacheService.getSearch(text); cw.searchResult = this.galleryCacheService.getSearch(text);
if (cw.searchResult == null) { if (cw.searchResult == null) {
//If result is not search cache, try to load load more // If result is not search cache, try to load load more
this.searchId = setTimeout(() => { this.searchId = setTimeout(() => {
this.search(text); this.search(text);
this.searchId = null; this.searchId = null;
@ -134,8 +134,8 @@ export class GalleryService {
} }
this.content.next(cw); this.content.next(cw);
//if instant search do not have a result, do not do a search // if instant search do not have a result, do not do a search
if (cw.searchResult.photos.length == 0 && cw.searchResult.directories.length == 0) { if (cw.searchResult.photos.length === 0 && cw.searchResult.directories.length === 0) {
if (this.searchId != null) { if (this.searchId != null) {
clearTimeout(this.searchId); clearTimeout(this.searchId);
} }

View File

@ -63,5 +63,5 @@ export class GridRowBuilder {
const height = (this.containerWidth - this.photoRow.length * (this.photoMargin * 2) - 1) / width; // cant be equal -> width-1 const height = (this.containerWidth - this.photoRow.length * (this.photoMargin * 2) - 1) / width; // cant be equal -> width-1
return height + (this.photoMargin * 2); return height + (this.photoMargin * 2);
}; }
} }

View File

@ -7,10 +7,7 @@
border: 1px solid #ccc; border: 1px solid #ccc;
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
padding-left: 0; padding: 5px 0;
padding-right: 0;
padding-top: 5px;
padding-bottom: 5px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
box-shadow: 0 6px 12px rgba(0, 0, 0, .175); box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
} }

View File

@ -19,7 +19,7 @@ export class ShareService {
constructor(private _networkService: NetworkService, private router: Router) { constructor(private _networkService: NetworkService, private router: Router) {
this.sharing = new BehaviorSubject(null); this.sharing = new BehaviorSubject(null);
this.ReadyPR = new Promise((resolve) => { this.ReadyPR = new Promise((resolve) => {
if (this.inited == true) { if (this.inited === true) {
return resolve(); return resolve();
} }
this.resolve = resolve; this.resolve = resolve;
@ -29,7 +29,7 @@ export class ShareService {
if (val instanceof RoutesRecognized) { if (val instanceof RoutesRecognized) {
this.param = val.state.root.firstChild.params['sharingKey'] || null; this.param = val.state.root.firstChild.params['sharingKey'] || null;
this.queryParam = val.state.root.firstChild.queryParams['sk'] || null; this.queryParam = val.state.root.firstChild.queryParams['sk'] || null;
const changed = this.sharingKey != this.param || this.queryParam; const changed = this.sharingKey !== this.param || this.queryParam;
if (changed) { if (changed) {
this.sharingKey = this.param || this.queryParam; this.sharingKey = this.param || this.queryParam;
this.getSharing(); this.getSharing();

View File

@ -13,142 +13,16 @@ export enum ThumbnailLoadingPriority {
export class ThumbnailLoaderService { export class ThumbnailLoaderService {
que: Array<ThumbnailTask> = []; que: Array<ThumbnailTask> = [];
runningRequests: number = 0; runningRequests = 0;
constructor(private galleryCacheService: GalleryCacheService) { constructor(private galleryCacheService: GalleryCacheService) {
} }
removeTask(taskEntry: ThumbnailTaskEntity) {
let index = taskEntry.parentTask.taskEntities.indexOf(taskEntry);
if (index == -1) {
throw new Error('ThumbnailTaskEntity not exist on Task');
}
taskEntry.parentTask.taskEntities.splice(index, 1);
if (taskEntry.parentTask.taskEntities.length == 0
&& taskEntry.parentTask.inProgress == false) {
let i = this.que.indexOf(taskEntry.parentTask);
if (i == -1) {
throw new Error('ThumbnailTask not exist');
}
this.que.splice(i, 1);
}
}
loadIcon(photo: IconPhoto, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
let thTask: ThumbnailTask = null;
//is image already qued?
for (let i = 0; i < this.que.length; i++) {
if (this.que[i].path == photo.getIconPath()) {
thTask = this.que[i];
break;
}
}
if (thTask == null) {
thTask = {
photo: photo.photo,
inProgress: false,
taskEntities: [],
onLoaded: () => {
photo.iconLoaded();
},
path: photo.getIconPath()
};
this.que.push(thTask);
}
let thumbnailTaskEntity = {priority: priority, listener: listener, parentTask: thTask};
thTask.taskEntities.push(thumbnailTaskEntity);
if (thTask.inProgress == true) {
listener.onStartedLoading();
}
setTimeout(this.run, 0);
return thumbnailTaskEntity;
}
loadImage(photo: Photo, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
let thTask: ThumbnailTask = null;
//is image already qued?
for (let i = 0; i < this.que.length; i++) {
if (this.que[i].path == photo.getThumbnailPath()) {
thTask = this.que[i];
break;
}
}
if (thTask == null) {
thTask = {
photo: photo.photo,
inProgress: false,
taskEntities: [],
onLoaded: () => {
photo.thumbnailLoaded();
},
path: photo.getThumbnailPath()
};
this.que.push(thTask);
}
let thumbnailTaskEntity = {priority: priority, listener: listener, parentTask: thTask};
//add to poolTask
thTask.taskEntities.push(thumbnailTaskEntity);
if (thTask.inProgress == true) {
listener.onStartedLoading();
}
setTimeout(this.run, 0);
return thumbnailTaskEntity;
}
private getNextTask(): ThumbnailTask {
if (this.que.length === 0) {
return null;
}
let highestPriority: ThumbnailTask = null;
let currentPriority: ThumbnailLoadingPriority = Number.MAX_SAFE_INTEGER;
for (let i = 0; i < this.que.length; i++) {
for (let j = 0; j < this.que[i].taskEntities.length; j++) {
if (this.que[i].inProgress == false) {
if (highestPriority == null || currentPriority < this.que[i].taskEntities[j].priority) {
highestPriority = this.que[i];
currentPriority = this.que[i].taskEntities[j].priority;
if (currentPriority == ThumbnailLoadingPriority.extraHigh) {
return highestPriority;
}
}
}
}
}
return highestPriority;
}
private taskReady(task: ThumbnailTask) {
let i = this.que.indexOf(task);
if (i == -1) {
if (task.taskEntities.length !== 0) {
console.error('ThumbnailLoader: can\'t find poolTask to remove');
}
return;
}
this.que.splice(i, 1);
}
run = () => { run = () => {
if (this.que.length === 0 || this.runningRequests >= Config.Client.concurrentThumbnailGenerations) { if (this.que.length === 0 || this.runningRequests >= Config.Client.concurrentThumbnailGenerations) {
return; return;
} }
let task = this.getNextTask(); const task = this.getNextTask();
if (task === null) { if (task === null) {
return; return;
@ -158,7 +32,7 @@ export class ThumbnailLoaderService {
task.taskEntities.forEach(te => te.listener.onStartedLoading()); task.taskEntities.forEach(te => te.listener.onStartedLoading());
task.inProgress = true; task.inProgress = true;
let curImg = new Image(); const curImg = new Image();
curImg.onload = () => { curImg.onload = () => {
task.onLoaded(); task.onLoaded();
this.galleryCacheService.photoUpdated(task.photo); this.galleryCacheService.photoUpdated(task.photo);
@ -179,6 +53,129 @@ export class ThumbnailLoaderService {
curImg.src = task.path; curImg.src = task.path;
}; };
removeTask(taskEntry: ThumbnailTaskEntity) {
const index = taskEntry.parentTask.taskEntities.indexOf(taskEntry);
if (index === -1) {
throw new Error('ThumbnailTaskEntity not exist on Task');
}
taskEntry.parentTask.taskEntities.splice(index, 1);
if (taskEntry.parentTask.taskEntities.length === 0
&& taskEntry.parentTask.inProgress === false) {
const i = this.que.indexOf(taskEntry.parentTask);
if (i === -1) {
throw new Error('ThumbnailTask not exist');
}
this.que.splice(i, 1);
}
}
loadIcon(photo: IconPhoto, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
let thTask: ThumbnailTask = null;
// is image already qued?
for (let i = 0; i < this.que.length; i++) {
if (this.que[i].path === photo.getIconPath()) {
thTask = this.que[i];
break;
}
}
if (thTask == null) {
thTask = {
photo: photo.photo,
inProgress: false,
taskEntities: [],
onLoaded: () => {
photo.iconLoaded();
},
path: photo.getIconPath()
};
this.que.push(thTask);
}
const thumbnailTaskEntity = {priority: priority, listener: listener, parentTask: thTask};
thTask.taskEntities.push(thumbnailTaskEntity);
if (thTask.inProgress === true) {
listener.onStartedLoading();
}
setTimeout(this.run, 0);
return thumbnailTaskEntity;
}
loadImage(photo: Photo, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
let thTask: ThumbnailTask = null;
// is image already qued?
for (let i = 0; i < this.que.length; i++) {
if (this.que[i].path === photo.getThumbnailPath()) {
thTask = this.que[i];
break;
}
}
if (thTask == null) {
thTask = {
photo: photo.photo,
inProgress: false,
taskEntities: [],
onLoaded: () => {
photo.thumbnailLoaded();
},
path: photo.getThumbnailPath()
};
this.que.push(thTask);
}
const thumbnailTaskEntity = {priority: priority, listener: listener, parentTask: thTask};
// add to poolTask
thTask.taskEntities.push(thumbnailTaskEntity);
if (thTask.inProgress === true) {
listener.onStartedLoading();
}
setTimeout(this.run, 0);
return thumbnailTaskEntity;
}
private getNextTask(): ThumbnailTask {
if (this.que.length === 0) {
return null;
}
let highestPriority: ThumbnailTask = null;
let currentPriority: ThumbnailLoadingPriority = Number.MAX_SAFE_INTEGER;
for (let i = 0; i < this.que.length; i++) {
for (let j = 0; j < this.que[i].taskEntities.length; j++) {
if (this.que[i].inProgress === false) {
if (highestPriority == null || currentPriority < this.que[i].taskEntities[j].priority) {
highestPriority = this.que[i];
currentPriority = this.que[i].taskEntities[j].priority;
if (currentPriority === ThumbnailLoadingPriority.extraHigh) {
return highestPriority;
}
}
}
}
}
return highestPriority;
}
private taskReady(task: ThumbnailTask) {
const i = this.que.indexOf(task);
if (i === -1) {
if (task.taskEntities.length !== 0) {
console.error('ThumbnailLoader: can\'t find poolTask to remove');
}
return;
}
this.que.splice(i, 1);
}
} }

View File

@ -28,15 +28,15 @@ export class ThumbnailManagerService {
export abstract class ThumbnailBase { export abstract class ThumbnailBase {
protected available: boolean = false; protected available = false;
protected src: string = null; protected src: string = null;
protected loading: boolean = false; protected loading = false;
protected error: boolean = false; protected error = false;
protected onLoad: Function = null; protected onLoad: Function = null;
protected thumbnailTask: ThumbnailTaskEntity = null; protected thumbnailTask: ThumbnailTaskEntity = null;
constructor(protected thumbnailService: ThumbnailLoaderService) { protected constructor(protected thumbnailService: ThumbnailLoaderService) {
} }
abstract set Visible(visible: boolean); abstract set Visible(visible: boolean);
@ -80,24 +80,28 @@ export class IconThumbnail extends ThumbnailBase {
if (this.photo.isIconAvailable()) { if (this.photo.isIconAvailable()) {
this.src = this.photo.getIconPath(); this.src = this.photo.getIconPath();
this.available = true; this.available = true;
if (this.onLoad) this.onLoad(); if (this.onLoad) {
this.onLoad();
}
} }
if (!this.photo.isIconAvailable()) { if (!this.photo.isIconAvailable()) {
setTimeout(() => { setTimeout(() => {
let listener: ThumbnailLoadingListener = { const listener: ThumbnailLoadingListener = {
onStartedLoading: () => { //onLoadStarted onStartedLoading: () => { // onLoadStarted
this.loading = true; this.loading = true;
}, },
onLoad: () => {//onLoaded onLoad: () => {// onLoaded
this.src = this.photo.getIconPath(); this.src = this.photo.getIconPath();
if (this.onLoad) this.onLoad(); if (this.onLoad) {
this.onLoad();
}
this.available = true; this.available = true;
this.loading = false; this.loading = false;
this.thumbnailTask = null; this.thumbnailTask = null;
}, },
onError: (error) => {//onError onError: (error) => {// onError
this.thumbnailTask = null; this.thumbnailTask = null;
this.loading = false; this.loading = false;
this.error = true; this.error = true;
@ -112,7 +116,9 @@ export class IconThumbnail extends ThumbnailBase {
} }
set Visible(visible: boolean) { set Visible(visible: boolean) {
if (!this.thumbnailTask) return; if (!this.thumbnailTask) {
return;
}
if (visible === true) { if (visible === true) {
this.thumbnailTask.priority = ThumbnailLoadingPriority.high; this.thumbnailTask.priority = ThumbnailLoadingPriority.high;
} else { } else {
@ -131,7 +137,9 @@ export class Thumbnail extends ThumbnailBase {
if (this.photo.isThumbnailAvailable()) { if (this.photo.isThumbnailAvailable()) {
this.src = this.photo.getThumbnailPath(); this.src = this.photo.getThumbnailPath();
this.available = true; this.available = true;
if (this.onLoad) this.onLoad(); if (this.onLoad) {
this.onLoad();
}
} else if (this.photo.isReplacementThumbnailAvailable()) { } else if (this.photo.isReplacementThumbnailAvailable()) {
this.src = this.photo.getReplacementThumbnailPath(); this.src = this.photo.getReplacementThumbnailPath();
this.available = true; this.available = true;
@ -142,7 +150,9 @@ export class Thumbnail extends ThumbnailBase {
} }
set CurrentlyWaiting(value: boolean) { set CurrentlyWaiting(value: boolean) {
if (!this.thumbnailTask) return; if (!this.thumbnailTask) {
return;
}
if (value === true) { if (value === true) {
if (this.photo.isReplacementThumbnailAvailable()) { if (this.photo.isReplacementThumbnailAvailable()) {
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium; this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
@ -158,37 +168,10 @@ export class Thumbnail extends ThumbnailBase {
} }
} }
public load() {
if (!this.photo.isThumbnailAvailable() && this.thumbnailTask == null) {
// setTimeout(() => {
let listener: ThumbnailLoadingListener = {
onStartedLoading: () => { //onLoadStarted
this.loading = true;
},
onLoad: () => {//onLoaded
this.src = this.photo.getThumbnailPath();
if (this.onLoad) this.onLoad();
this.available = true;
this.loading = false;
this.thumbnailTask = null;
},
onError: (error) => {//onError
this.thumbnailTask = null;
this.loading = false;
this.error = true;
}
};
if (this.photo.isReplacementThumbnailAvailable()) {
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.medium, listener);
} else {
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.high, listener);
}
// }, 0);
}
}
set Visible(visible: boolean) { set Visible(visible: boolean) {
if (!this.thumbnailTask) return; if (!this.thumbnailTask) {
return;
}
if (visible === true) { if (visible === true) {
if (this.photo.isReplacementThumbnailAvailable()) { if (this.photo.isReplacementThumbnailAvailable()) {
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium; this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
@ -205,5 +188,36 @@ export class Thumbnail extends ThumbnailBase {
} }
public load() {
if (!this.photo.isThumbnailAvailable() && this.thumbnailTask == null) {
// setTimeout(() => {
const listener: ThumbnailLoadingListener = {
onStartedLoading: () => { // onLoadStarted
this.loading = true;
},
onLoad: () => {// onLoaded
this.src = this.photo.getThumbnailPath();
if (this.onLoad) {
this.onLoad();
}
this.available = true;
this.loading = false;
this.thumbnailTask = null;
},
onError: (error) => {// onError
this.thumbnailTask = null;
this.loading = false;
this.error = true;
}
};
if (this.photo.isReplacementThumbnailAvailable()) {
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.medium, listener);
} else {
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.high, listener);
}
// }, 0);
}
}
} }

View File

@ -32,12 +32,11 @@
max-width: 350px; max-width: 350px;
width: 100% !important; width: 100% !important;
background-color: #F7F7F7; background-color: #F7F7F7;
margin: 0 auto;
border-radius: 2px; border-radius: 2px;
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); box-shadow: 0 2px 2px rgba(0, 0, 0, 0.3);
overflow: hidden; overflow: hidden;
height: 295px; height: 295px;
margin-top: 0px; margin: 0px auto 0;
} }
/*Margin by pixel:*/ /*Margin by pixel:*/

View File

@ -6,13 +6,13 @@ import {Config} from '../../../common/config/public/Config';
import {NavigationService} from '../model/navigation.service'; import {NavigationService} from '../model/navigation.service';
@Component({ @Component({
selector: 'login', selector: 'app-login',
templateUrl: './login.component.html', templateUrl: './login.component.html',
styleUrls: ['./login.component.css'], styleUrls: ['./login.component.css'],
}) })
export class LoginComponent implements OnInit { export class LoginComponent implements OnInit {
loginCredential: LoginCredential; loginCredential: LoginCredential;
loginError: boolean = false; loginError = false;
title: string; title: string;
inProgress = false; inProgress = false;

View File

@ -4,11 +4,13 @@ import {Message} from '../../../../common/entities/Message';
import {SlimLoadingBarService} from 'ng2-slim-loading-bar'; import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
import 'rxjs/Rx'; import 'rxjs/Rx';
import {ErrorCodes, ErrorDTO} from '../../../../common/entities/Error'; import {ErrorCodes, ErrorDTO} from '../../../../common/entities/Error';
import {Config} from '../../../../common/config/public/Config';
import {Utils} from '../../../../common/Utils';
@Injectable() @Injectable()
export class NetworkService { export class NetworkService {
_baseUrl = '/api'; _apiBaseUrl = Utils.concatUrls(Config.Client.urlBase, '/api');
private globalErrorHandlers: Array<(error: ErrorDTO) => boolean> = []; private globalErrorHandlers: Array<(error: ErrorDTO) => boolean> = [];
constructor(private _http: HttpClient, constructor(private _http: HttpClient,
@ -69,22 +71,22 @@ export class NetworkService {
switch (method) { switch (method) {
case 'get': case 'get':
return this._http.get<Message<T>>(this._baseUrl + url) return this._http.get<Message<T>>(this._apiBaseUrl + url)
.toPromise() .toPromise()
.then(process) .then(process)
.catch(err); .catch(err);
case 'delete': case 'delete':
return this._http.delete<Message<T>>(this._baseUrl + url) return this._http.delete<Message<T>>(this._apiBaseUrl + url)
.toPromise() .toPromise()
.then(process) .then(process)
.catch(err); .catch(err);
case 'post': case 'post':
return this._http.post<Message<T>>(this._baseUrl + url, body) return this._http.post<Message<T>>(this._apiBaseUrl + url, body)
.toPromise() .toPromise()
.then(process) .then(process)
.catch(err); .catch(err);
case 'put': case 'put':
return this._http.put<Message<T>>(this._baseUrl + url, body) return this._http.put<Message<T>>(this._apiBaseUrl + url, body)
.toPromise() .toPromise()
.then(process) .then(process)
.catch(err); .catch(err);

View File

@ -38,13 +38,13 @@ export abstract class SettingsComponent<T, S extends AbstractSettingsService<T>=
High: 'High' High: 'High'
}; };
constructor(private name, protected constructor(private name,
private _authService: AuthenticationService, private _authService: AuthenticationService,
private _navigation: NavigationService, private _navigation: NavigationService,
public _settingsService: S, public _settingsService: S,
protected notification: NotificationService, protected notification: NotificationService,
public i18n: I18n, public i18n: I18n,
private sliceFN?: (s: IPrivateConfig) => T) { private sliceFN?: (s: IPrivateConfig) => T) {
if (this.sliceFN) { if (this.sliceFN) {
this._settingsSubscription = this._settingsService.Settings.subscribe(this.onNewSettings); this._settingsSubscription = this._settingsService.Settings.subscribe(this.onNewSettings);
this.onNewSettings(this._settingsService._settingsService.settings.value); this.onNewSettings(this._settingsService._settingsService.settings.value);

View File

@ -2,7 +2,7 @@ import {SettingsService} from '../settings.service';
export abstract class AbstractSettingsService<T> { export abstract class AbstractSettingsService<T> {
constructor(public _settingsService: SettingsService) { protected constructor(public _settingsService: SettingsService) {
} }

View File

@ -52,6 +52,17 @@
</div> </div>
</div> </div>
<div class="form-group" [hidden]="simplifiedMode">
<label class="col-sm-2 control-label" for="urlBase" i18n>Url Base</label>
<div class="col-sm-10">
<input type="url" class="form-control" placeholder="/myGallery"
id="urlBase"
[(ngModel)]="settings.urlBase"
name="urlBase">
<span class="help-block" i18n>If you access the gallery under a sub url (like: http://mydomain.com/myGallery), set it here. If not working you might miss the '/' from the beginning of the url.</span>
</div>
</div>
<button class="btn btn-success pull-right" <button class="btn btn-success pull-right"
[disabled]="!settingsForm.form.valid || !changed || inProgress" [disabled]="!settingsForm.form.valid || !changed || inProgress"
(click)="save()" i18n>Save (click)="save()" i18n>Save

View File

@ -27,7 +27,8 @@ export class BasicSettingsComponent extends SettingsComponent<BasicConfigDTO> {
port: s.Server.port, port: s.Server.port,
imagesFolder: s.Server.imagesFolder, imagesFolder: s.Server.imagesFolder,
applicationTitle: s.Client.applicationTitle, applicationTitle: s.Client.applicationTitle,
publicUrl: s.Client.publicUrl publicUrl: s.Client.publicUrl,
urlBase: s.Client.urlBase
})); }));
} }

View File

@ -32,6 +32,7 @@ export class SettingsService {
enabled: true, enabled: true,
googleApiKey: '' googleApiKey: ''
}, },
urlBase: '',
publicUrl: '', publicUrl: '',
applicationTitle: '', applicationTitle: '',
enableCache: true, enableCache: true,

View File

@ -54,7 +54,7 @@ export class UserMangerSettingsComponent implements OnInit {
} }
this.userRoles = Utils this.userRoles = Utils
.enumToArray(UserRoles) .enumToArray(UserRoles)
.filter(r => r.key != UserRoles.LimitedGuest) .filter(r => r.key !== UserRoles.LimitedGuest)
.filter(r => r.key <= this._authService.user.value.role) .filter(r => r.key <= this._authService.user.value.role)
.sort((a, b) => a.key - b.key); .sort((a, b) => a.key - b.key);
@ -62,29 +62,39 @@ export class UserMangerSettingsComponent implements OnInit {
this.getUsersList(); this.getUsersList();
} }
private async getUsersList() { canModifyUser(user: UserDTO): boolean {
try { const currentUser = this._authService.user.value;
this.users = await this._userSettings.getUsers(); if (!currentUser) {
} catch (err) { return false;
this.users = [];
if ((<ErrorDTO>err).code != ErrorCodes.USER_MANAGEMENT_DISABLED) {
throw err;
}
} }
return currentUser.name !== user.name && currentUser.role >= user.role;
} }
private async getSettings() { private async getSettings() {
this.enabled = await this._userSettings.getSettings(); this.enabled = await this._userSettings.getSettings();
} }
async switched(event: { previousValue: false, currentValue: true }) {
canModifyUser(user: UserDTO): boolean { this.inProgress = true;
let currentUser = this._authService.user.value; this.error = '';
if (!currentUser) { this.enabled = event.currentValue;
return false; try {
await this._userSettings.updateSettings(this.enabled);
await this.getSettings();
if (this.enabled === true) {
this.notification.success(this.i18n('Password protection enabled'), this.i18n('Success'));
this.getUsersList();
} else {
this.notification.success(this.i18n('Password protection disabled'), this.i18n('Success'));
}
} catch (err) {
console.log(err);
if (err.message) {
this.error = (<ErrorDTO>err).message;
}
} }
this.inProgress = false;
return currentUser.name != user.name && currentUser.role >= user.role;
} }
initNewUser() { initNewUser() {
@ -110,26 +120,15 @@ export class UserMangerSettingsComponent implements OnInit {
this.childModal.hide(); this.childModal.hide();
} }
async switched(event: { previousValue: false, currentValue: true }) { private async getUsersList() {
this.inProgress = true;
this.error = '';
this.enabled = event.currentValue;
try { try {
await this._userSettings.updateSettings(this.enabled); this.users = await this._userSettings.getUsers();
await this.getSettings();
if (this.enabled == true) {
this.notification.success(this.i18n('Password protection enabled'), this.i18n('Success'));
this.getUsersList();
} else {
this.notification.success(this.i18n('Password protection disabled'), this.i18n('Success'));
}
} catch (err) { } catch (err) {
console.log(err); this.users = [];
if (err.message) { if ((<ErrorDTO>err).code !== ErrorCodes.USER_MANAGEMENT_DISABLED) {
this.error = (<ErrorDTO>err).message; throw err;
} }
} }
this.inProgress = false;
} }
} }

View File

@ -1,4 +0,0 @@
var ServerInject = {
user: <%- JSON.stringify(user); %>,
ConfigInject: <%- JSON.stringify(clientConfig); %>
}

View File

@ -1,17 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<base href="/"/> <base href="<%= clientConfig.urlBase %>/"/>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Loading..</title> <title>Loading..</title>
<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">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" <link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.css"> href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.css">
<script type="text/javascript" src="/config_inject.js"></script> <script>
var ServerInject = {user: < % -JSON.stringify(user);
%>,
ConfigInject:<
%
-JSON.stringify(clientConfig);
%>
}
</script>
</head> </head>

View File

@ -1,13 +1,13 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files // This file is required by karma.conf.js and loads recursively all the .spec and framework files
import "zone.js/dist/long-stack-trace-zone"; import 'zone.js/dist/long-stack-trace-zone';
import "zone.js/dist/proxy.js"; import 'zone.js/dist/proxy.js';
import "zone.js/dist/sync-test"; import 'zone.js/dist/sync-test';
import "zone.js/dist/jasmine-patch"; import 'zone.js/dist/jasmine-patch';
import "zone.js/dist/async-test"; import 'zone.js/dist/async-test';
import "zone.js/dist/fake-async-test"; import 'zone.js/dist/fake-async-test';
import {getTestBed} from "@angular/core/testing"; import {getTestBed} from '@angular/core/testing';
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from "@angular/platform-browser-dynamic/testing"; import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare const __karma__: any; declare const __karma__: any;

View File

@ -6,7 +6,7 @@
<source>Please log in</source> <source>Please log in</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">11</context> <context context-type="linenumber">10</context>
</context-group> </context-group>
<target>Please log in</target> <target>Please log in</target>
</trans-unit> </trans-unit>
@ -16,7 +16,7 @@
</source> </source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">12</context>
</context-group> </context-group>
<target> <target>
Wrong username or password Wrong username or password
@ -26,7 +26,7 @@
<source>Username</source> <source>Username</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">22</context> <context context-type="linenumber">21</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context> <context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context>
@ -42,7 +42,7 @@
<source>Password</source> <source>Password</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">36</context> <context context-type="linenumber">37</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/sharelogin/share-login.component.ts</context> <context context-type="sourcefile">app/sharelogin/share-login.component.ts</context>
@ -70,7 +70,7 @@
<source>Remember me</source> <source>Remember me</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">42</context> <context context-type="linenumber">43</context>
</context-group> </context-group>
<target>Remember me</target> <target>Remember me</target>
</trans-unit> </trans-unit>
@ -79,7 +79,7 @@
</source> </source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">52</context> <context context-type="linenumber">53</context>
</context-group> </context-group>
<target>Login <target>Login
</target> </target>
@ -146,7 +146,7 @@
<source>key: left arrow</source> <source>key: left arrow</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context> <context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
<context context-type="linenumber">40</context> <context context-type="linenumber">41</context>
</context-group> </context-group>
<target>key: left arrow</target> <target>key: left arrow</target>
</trans-unit> </trans-unit>
@ -154,7 +154,7 @@
<source>key: right arrow</source> <source>key: right arrow</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context> <context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
<context context-type="linenumber">44</context> <context context-type="linenumber">45</context>
</context-group> </context-group>
<target>key: right arrow</target> <target>key: right arrow</target>
</trans-unit> </trans-unit>
@ -533,7 +533,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context> <context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
<context context-type="linenumber">57</context> <context context-type="linenumber">68</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context> <context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
@ -563,7 +563,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context> <context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
<context context-type="linenumber">60</context> <context context-type="linenumber">71</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context> <context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
@ -840,6 +840,22 @@
</context-group> </context-group>
<target>If you access the page form local network its good to know the public url for creating sharing link</target> <target>If you access the page form local network its good to know the public url for creating sharing link</target>
</trans-unit> </trans-unit>
<trans-unit id="52e8e9fdcd08e89225892a7657140dbf41020b76" datatype="html">
<source>Url Base</source>
<context-group purpose="location">
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
<context context-type="linenumber">56</context>
</context-group>
<target>Url Base</target>
</trans-unit>
<trans-unit id="8a46f66aef490af08db029240d761dd0715dea54" datatype="html">
<source>If you access the gallery under a sub url (like: http://mydomain.com/myGallery), set it here. If not working you might miss the '/' from the beginning of the url.</source>
<context-group purpose="location">
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
<context context-type="linenumber">62</context>
</context-group>
<target>If you access the gallery under a sub url (like: http://mydomain.com/myGallery), set it here. If not working you might miss the '/' from the beginning of the url.</target>
</trans-unit>
<trans-unit id="1e99f581a015c671d53abad7c7df6a5ad35bfe85" datatype="html"> <trans-unit id="1e99f581a015c671d53abad7c7df6a5ad35bfe85" datatype="html">
<source>Other settings</source> <source>Other settings</source>
<context-group purpose="location"> <context-group purpose="location">

View File

@ -6,7 +6,7 @@
<source>Please log in</source> <source>Please log in</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">11</context> <context context-type="linenumber">10</context>
</context-group> </context-group>
<target>Jelentkezz be</target> <target>Jelentkezz be</target>
</trans-unit> </trans-unit>
@ -16,7 +16,7 @@
</source> </source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">12</context>
</context-group> </context-group>
<target>Rossz felhasználónév vagy jelszó</target> <target>Rossz felhasználónév vagy jelszó</target>
</trans-unit> </trans-unit>
@ -24,7 +24,7 @@
<source>Username</source> <source>Username</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">22</context> <context context-type="linenumber">21</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context> <context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context>
@ -40,7 +40,7 @@
<source>Password</source> <source>Password</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">36</context> <context context-type="linenumber">37</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/sharelogin/share-login.component.ts</context> <context context-type="sourcefile">app/sharelogin/share-login.component.ts</context>
@ -68,7 +68,7 @@
<source>Remember me</source> <source>Remember me</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">42</context> <context context-type="linenumber">43</context>
</context-group> </context-group>
<target>Emlékezz rám</target> <target>Emlékezz rám</target>
</trans-unit> </trans-unit>
@ -77,7 +77,7 @@
</source> </source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/login/login.component.ts</context> <context context-type="sourcefile">app/login/login.component.ts</context>
<context context-type="linenumber">52</context> <context context-type="linenumber">53</context>
</context-group> </context-group>
<target>Belépés</target> <target>Belépés</target>
</trans-unit> </trans-unit>
@ -140,7 +140,7 @@
<source>key: left arrow</source> <source>key: left arrow</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context> <context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
<context context-type="linenumber">40</context> <context context-type="linenumber">41</context>
</context-group> </context-group>
<target>billentyű: balra nyíl</target> <target>billentyű: balra nyíl</target>
</trans-unit> </trans-unit>
@ -148,7 +148,7 @@
<source>key: right arrow</source> <source>key: right arrow</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context> <context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
<context context-type="linenumber">44</context> <context context-type="linenumber">45</context>
</context-group> </context-group>
<target>billentyű: jobbra nyíl</target> <target>billentyű: jobbra nyíl</target>
</trans-unit> </trans-unit>
@ -516,7 +516,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context> <context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
<context context-type="linenumber">57</context> <context context-type="linenumber">68</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context> <context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
@ -545,7 +545,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context> <context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
<context context-type="linenumber">60</context> <context context-type="linenumber">71</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context> <context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
@ -816,6 +816,22 @@
</context-group> </context-group>
<target>Ha belső hálózatról nézed oldalt, jó tudni a nyilvános URL-t, a megosztási link létrehozásához</target> <target>Ha belső hálózatról nézed oldalt, jó tudni a nyilvános URL-t, a megosztási link létrehozásához</target>
</trans-unit> </trans-unit>
<trans-unit id="52e8e9fdcd08e89225892a7657140dbf41020b76" datatype="html">
<source>Url Base</source>
<context-group purpose="location">
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
<context context-type="linenumber">56</context>
</context-group>
<target>Al cím</target>
</trans-unit>
<trans-unit id="8a46f66aef490af08db029240d761dd0715dea54" datatype="html">
<source>If you access the gallery under a sub url (like: http://mydomain.com/myGallery), set it here. If not working you might miss the '/' from the beginning of the url.</source>
<context-group purpose="location">
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
<context context-type="linenumber">62</context>
</context-group>
<target>Ha az oldalt egy al címen lehet elérni (pl: http://oldalam.hu/myGallery), akkor az alcímet itt állitsd be. Hiba esetén lehet, hogy a "/" hiányzik az url elejéről.</target>
</trans-unit>
<trans-unit id="1e99f581a015c671d53abad7c7df6a5ad35bfe85" datatype="html"> <trans-unit id="1e99f581a015c671d53abad7c7df6a5ad35bfe85" datatype="html">
<source>Other settings</source> <source>Other settings</source>
<context-group purpose="location"> <context-group purpose="location">
@ -1257,4 +1273,4 @@
</trans-unit> </trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -28,7 +28,9 @@ var createFrontendTask = function (type, script) {
}; };
gulp.task('build-frontend', function (done) { gulp.task('build-frontend', function (done) {
var languages = getLanguages(); var languages = getLanguages().filter(function (l) {
return l !== "en";
});
var tasks = []; var tasks = [];
createFrontendTask('build-frontend-release default', createFrontendTask('build-frontend-release default',
"ng build --aot -prod --output-path=./release/dist --no-progress --locale=en" + "ng build --aot -prod --output-path=./release/dist --no-progress --locale=en" +
@ -95,14 +97,14 @@ var getLanguages = function () {
}); });
return files.map(function (f) { return files.map(function (f) {
return f.split(".")[1] return f.split(".")[1]
}).filter(function (l) {
return l !== "en";
}); });
}; };
var simpleBuild = function (isProd) { var simpleBuild = function (isProd) {
return function (done) { return function (done) {
var languages = getLanguages(); var languages = getLanguages().filter(function (l) {
return l !== "en";
});
var tasks = []; var tasks = [];
var cmd = "ng build --aot "; var cmd = "ng build --aot ";
if (isProd) { if (isProd) {

View File

@ -17,7 +17,6 @@
"lint": "ng lint", "lint": "ng lint",
"e2e": "ng e2e", "e2e": "ng e2e",
"run-dev": "ng build --aot -w --output-path=./dist --locale en --i18n-format xlf --i18n-file frontend/translate/messages.en.xlf --missing-translation warning", "run-dev": "ng build --aot -w --output-path=./dist --locale en --i18n-format xlf --i18n-file frontend/translate/messages.en.xlf --missing-translation warning",
"build-hu": "ng build --aot --output-path=./dist/hu --locale hu --i18n-format xlf --i18n-file frontend/translate/messages.hu.xlf --missing-translation warning",
"update-translation": "gulp update-translation", "update-translation": "gulp update-translation",
"add-translation": "gulp add-translation" "add-translation": "gulp add-translation"
}, },