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:
parent
9a90764603
commit
babf2fc584
@ -114,7 +114,7 @@ apt-get install build-essential libkrb5-dev gcc g++
|
||||
* 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!)
|
||||
2) add your language e.g: fr
|
||||
```bash
|
||||
|
@ -10,7 +10,7 @@ declare module 'winston' {
|
||||
export const winstonSettings = {
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
level: process.env.NODE_ENV == 'production' ? 'info' : 'silly',
|
||||
level: process.env.NODE_ENV === 'production' ? 'info' : 'silly',
|
||||
handleExceptions: true,
|
||||
json: false,
|
||||
colorize: true,
|
||||
|
@ -191,12 +191,14 @@ export class AdminMWs {
|
||||
Config.Server.port = settings.port;
|
||||
Config.Server.imagesFolder = settings.imagesFolder;
|
||||
Config.Client.publicUrl = settings.publicUrl;
|
||||
Config.Client.urlBase = settings.urlBase;
|
||||
Config.Client.applicationTitle = settings.applicationTitle;
|
||||
// only updating explicitly set config (not saving config set by the diagnostics)
|
||||
const original = Config.original();
|
||||
original.Server.port = settings.port;
|
||||
original.Server.imagesFolder = settings.imagesFolder;
|
||||
original.Client.publicUrl = settings.publicUrl;
|
||||
original.Client.urlBase = settings.urlBase;
|
||||
original.Client.applicationTitle = settings.applicationTitle;
|
||||
original.save();
|
||||
ProjectPath.reset();
|
||||
|
@ -12,8 +12,9 @@ import {Logger} from '../Logger';
|
||||
export class RenderingMWs {
|
||||
|
||||
public static renderResult(req: Request, res: Response, next: NextFunction) {
|
||||
if (typeof req.resultPipe == 'undefined')
|
||||
if (typeof req.resultPipe === 'undefined') {
|
||||
return next();
|
||||
}
|
||||
|
||||
return RenderingMWs.renderMessage(res, req.resultPipe);
|
||||
}
|
||||
@ -30,8 +31,9 @@ export class RenderingMWs {
|
||||
}
|
||||
|
||||
public static renderSharing(req: Request, res: Response, next: NextFunction) {
|
||||
if (!req.resultPipe)
|
||||
if (!req.resultPipe) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const sharing = Utils.clone<SharingDTO>(req.resultPipe);
|
||||
delete sharing.password;
|
||||
@ -39,20 +41,21 @@ export class RenderingMWs {
|
||||
}
|
||||
|
||||
public static renderFile(req: Request, res: Response, next: NextFunction) {
|
||||
if (!req.resultPipe)
|
||||
if (!req.resultPipe) {
|
||||
return next();
|
||||
}
|
||||
|
||||
return res.sendFile(req.resultPipe, {maxAge: 31536000});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
NotificationManager.error('unknown server error', err);
|
||||
@ -81,7 +84,7 @@ export class RenderingMWs {
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ export class SharingMWs {
|
||||
const createSharing: CreateSharingDTO = req.body.createSharing;
|
||||
let sharingKey = SharingMWs.generateKey();
|
||||
|
||||
//create one not yet used
|
||||
// create one not yet used
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
@ -52,7 +52,7 @@ export class SharingMWs {
|
||||
|
||||
|
||||
const directoryName = req.params.directory || '/';
|
||||
let sharing: SharingDTO = {
|
||||
const sharing: SharingDTO = {
|
||||
id: null,
|
||||
sharingKey: sharingKey,
|
||||
path: directoryName,
|
||||
@ -79,7 +79,7 @@ export class SharingMWs {
|
||||
}
|
||||
const updateSharing: CreateSharingDTO = req.body.updateSharing;
|
||||
const directoryName = req.params.directory || '/';
|
||||
let sharing: SharingDTO = {
|
||||
const sharing: SharingDTO = {
|
||||
id: updateSharing.id,
|
||||
path: directoryName,
|
||||
sharingKey: '',
|
||||
|
@ -1,13 +1,13 @@
|
||||
declare module Express {
|
||||
export interface Request {
|
||||
resultPipe?: any
|
||||
resultPipe?: any;
|
||||
body?: {
|
||||
loginCredential
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
tpl?: any
|
||||
tpl?: any;
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
|
@ -125,7 +125,8 @@ export class ThumbnailGeneratorMWs {
|
||||
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) {
|
||||
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
|
||||
const thPath = path.join(ProjectPath.ThumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(imagePath, size));
|
||||
|
||||
@ -162,7 +166,7 @@ export class ThumbnailGeneratorMWs {
|
||||
await this.taskQue.execute(input);
|
||||
return next();
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,13 +55,13 @@ export class AuthenticationMWs {
|
||||
|
||||
public static authoriseDirectory(req: Request, res: Response, next: NextFunction) {
|
||||
if (req.session.user.permissions == null ||
|
||||
req.session.user.permissions.length == 0 ||
|
||||
req.session.user.permissions[0] == '/*') {
|
||||
req.session.user.permissions.length === 0 ||
|
||||
req.session.user.permissions[0] === '/*') {
|
||||
return next();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ export class AuthenticationMWs {
|
||||
if (Config.Client.Sharing.enabled === false) {
|
||||
return next();
|
||||
}
|
||||
//not enough parameter
|
||||
// not enough parameter
|
||||
if ((!req.query.sk && !req.params.sharingKey)) {
|
||||
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'no sharing key provided'));
|
||||
}
|
||||
@ -100,7 +100,7 @@ export class AuthenticationMWs {
|
||||
}
|
||||
|
||||
let path = sharing.path;
|
||||
if (sharing.includeSubfolders == true) {
|
||||
if (sharing.includeSubfolders === true) {
|
||||
path += '*';
|
||||
}
|
||||
|
||||
@ -122,13 +122,15 @@ export class AuthenticationMWs {
|
||||
|
||||
public static async login(req: Request, res: Response, next: NextFunction) {
|
||||
|
||||
//not enough parameter
|
||||
if ((typeof req.body === 'undefined') || (typeof req.body.loginCredential === 'undefined') || (typeof req.body.loginCredential.username === 'undefined') ||
|
||||
// not enough parameter
|
||||
if ((typeof req.body === 'undefined') ||
|
||||
(typeof req.body.loginCredential === 'undefined') ||
|
||||
(typeof req.body.loginCredential.username === 'undefined') ||
|
||||
(typeof req.body.loginCredential.password === 'undefined')) {
|
||||
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR));
|
||||
}
|
||||
try {
|
||||
//lets find the user
|
||||
// lets find the user
|
||||
const user = Utils.clone(await ObjectManagerRepository.getInstance().UserManager.findOne({
|
||||
name: req.body.loginCredential.username,
|
||||
password: req.body.loginCredential.password
|
||||
@ -162,7 +164,7 @@ export class AuthenticationMWs {
|
||||
}
|
||||
|
||||
let path = sharing.path;
|
||||
if (sharing.includeSubfolders == true) {
|
||||
if (sharing.includeSubfolders === true) {
|
||||
path += '*';
|
||||
}
|
||||
return <UserDTO>{name: 'Guest', role: UserRoles.LimitedGuest, permissions: [path]};
|
||||
|
@ -18,7 +18,7 @@ const LOG_TAG = '[ConfigDiagnostics]';
|
||||
export class ConfigDiagnostics {
|
||||
|
||||
static async testDatabase(databaseConfig: DataBaseConfig) {
|
||||
if (databaseConfig.type != DatabaseType.memory) {
|
||||
if (databaseConfig.type !== DatabaseType.memory) {
|
||||
await SQLConnection.tryConnection(databaseConfig);
|
||||
}
|
||||
}
|
||||
@ -77,43 +77,45 @@ export class ConfigDiagnostics {
|
||||
|
||||
static async testClientThumbnailConfig(thumbnailConfig: ClientConfig.ThumbnailConfig) {
|
||||
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) {
|
||||
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++) {
|
||||
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) {
|
||||
if (search.enabled == true && config.Server.database.type == DatabaseType.memory) {
|
||||
throw 'Memory Database do not support searching';
|
||||
if (search.enabled === true &&
|
||||
config.Server.database.type === DatabaseType.memory) {
|
||||
throw new Error('Memory Database do not support searching');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static async testSharingConfig(sharing: ClientConfig.SharingConfig, config: IPrivateConfig) {
|
||||
if (sharing.enabled == true && config.Server.database.type == DatabaseType.memory) {
|
||||
throw 'Memory Database do not support sharing';
|
||||
if (sharing.enabled === true &&
|
||||
config.Server.database.type === DatabaseType.memory) {
|
||||
throw new Error('Memory Database do not support sharing');
|
||||
}
|
||||
}
|
||||
|
||||
static async testMapConfig(map: ClientConfig.MapConfig) {
|
||||
if (map.enabled == true && (!map.googleApiKey || map.googleApiKey.length == 0)) {
|
||||
throw 'Maps need a valid google api key';
|
||||
if (map.enabled === true && (!map.googleApiKey || map.googleApiKey.length === 0)) {
|
||||
throw new Error('Maps need a valid google api key');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static async runDiagnostics() {
|
||||
|
||||
if (Config.Server.database.type != DatabaseType.memory) {
|
||||
if (Config.Server.database.type !== DatabaseType.memory) {
|
||||
try {
|
||||
await ConfigDiagnostics.testDatabase(Config.Server.database);
|
||||
} catch (err) {
|
||||
@ -124,7 +126,7 @@ export class ConfigDiagnostics {
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.Server.thumbnail.processingLibrary != ThumbnailProcessingLib.Jimp) {
|
||||
if (Config.Server.thumbnail.processingLibrary !== ThumbnailProcessingLib.Jimp) {
|
||||
try {
|
||||
await ConfigDiagnostics.testThumbnailLib(Config.Server.thumbnail.processingLibrary);
|
||||
} catch (err) {
|
||||
@ -164,7 +166,8 @@ export class ConfigDiagnostics {
|
||||
try {
|
||||
await ConfigDiagnostics.testSearchConfig(Config.Client.Search, Config);
|
||||
} 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);
|
||||
Config.Client.Search.enabled = false;
|
||||
}
|
||||
@ -172,7 +175,8 @@ export class ConfigDiagnostics {
|
||||
try {
|
||||
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing, Config);
|
||||
} 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);
|
||||
Config.Client.Sharing.enabled = false;
|
||||
}
|
||||
@ -180,8 +184,10 @@ export class ConfigDiagnostics {
|
||||
try {
|
||||
await ConfigDiagnostics.testMapConfig(Config.Client.Map);
|
||||
} catch (err) {
|
||||
NotificationManager.warning('Maps is not supported with these settings. Disabling temporally. 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);
|
||||
NotificationManager.warning('Maps is not supported with these settings. Disabling temporally. ' +
|
||||
'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;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ export class DiskManager {
|
||||
static threadPool: DiskManagerTH = null;
|
||||
|
||||
public static init() {
|
||||
if (Config.Server.enableThreading == true) {
|
||||
if (Config.Server.enableThreading === true) {
|
||||
DiskManager.threadPool = new DiskManagerTH(1);
|
||||
}
|
||||
}
|
||||
@ -23,12 +23,12 @@ export class DiskManager {
|
||||
|
||||
let directory: DirectoryDTO = null;
|
||||
|
||||
if (Config.Server.enableThreading == true) {
|
||||
if (Config.Server.enableThreading === true) {
|
||||
directory = await DiskManager.threadPool.execute(relativeDirectoryName);
|
||||
} else {
|
||||
directory = await DiskMangerWorker.scanDirectory(relativeDirectoryName);
|
||||
}
|
||||
let addDirs = (dir: DirectoryDTO) => {
|
||||
const addDirs = (dir: DirectoryDTO) => {
|
||||
dir.photos.forEach((ph) => {
|
||||
ph.directory = dir;
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {ProjectPath} from '../ProjectPath';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import {Config} from '../../common/config/private/Config';
|
||||
|
||||
export class Localizations {
|
||||
@ -10,8 +10,9 @@ export class Localizations {
|
||||
|
||||
public static init() {
|
||||
const notLanguage = ['assets'];
|
||||
const dirCont = fs.readdirSync(ProjectPath.FrontendFolder).filter(f => fs.statSync(path.resolve(ProjectPath.FrontendFolder, f)).isDirectory());
|
||||
Config.Client.languages = dirCont.filter(d => notLanguage.indexOf(d) == -1);
|
||||
const dirCont = fs.readdirSync(ProjectPath.FrontendFolder)
|
||||
.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');
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,13 @@ import {IIndexingManager} from './interfaces/IIndexingManager';
|
||||
|
||||
export class ObjectManagerRepository {
|
||||
|
||||
private static _instance: ObjectManagerRepository = null;
|
||||
|
||||
private _galleryManager: IGalleryManager;
|
||||
private _userManager: IUserManager;
|
||||
private _searchManager: ISearchManager;
|
||||
private _sharingManager: ISharingManager;
|
||||
private _indexingManager: IIndexingManager;
|
||||
private static _instance: ObjectManagerRepository = null;
|
||||
|
||||
get IndexingManager(): IIndexingManager {
|
||||
return this._indexingManager;
|
||||
|
@ -10,12 +10,12 @@ import {ReIndexingSensitivity} from '../../../common/config/private/IPrivateConf
|
||||
export class GalleryManager implements IGalleryManager {
|
||||
|
||||
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) {
|
||||
const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
|
||||
const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime());
|
||||
if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout &&
|
||||
lastModified == knownLastModified &&
|
||||
lastModified === knownLastModified &&
|
||||
Config.Server.indexing.reIndexingSensitivity < ReIndexingSensitivity.high) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import {PasswordHelper} from '../PasswordHelper';
|
||||
|
||||
export class UserManager implements IUserManager {
|
||||
private db: { users?: UserDTO[], idCounter?: number } = {};
|
||||
private dbPath;
|
||||
private readonly dbPath;
|
||||
|
||||
generateId(): string {
|
||||
function s4() {
|
||||
@ -33,7 +33,7 @@ export class UserManager implements IUserManager {
|
||||
|
||||
if (!this.db.users) {
|
||||
this.db.users = [];
|
||||
//TODO: remove defaults
|
||||
// TODO: remove defaults
|
||||
this.createUser(<UserDTO>{name: 'admin', password: 'admin', role: UserRoles.Admin});
|
||||
}
|
||||
this.saveDB();
|
||||
@ -44,14 +44,14 @@ export class UserManager implements IUserManager {
|
||||
public async findOne(filter: any) {
|
||||
const result = await this.find(filter);
|
||||
|
||||
if (result.length == 0) {
|
||||
throw 'UserDTO not found';
|
||||
if (result.length === 0) {
|
||||
throw new Error('UserDTO not found');
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
public async find(filter: any) {
|
||||
let pass = filter.password;
|
||||
const pass = filter.password;
|
||||
delete filter.password;
|
||||
const users = this.db.users.slice();
|
||||
let i = users.length;
|
||||
@ -60,7 +60,7 @@ export class UserManager implements IUserManager {
|
||||
users.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
if (Utils.equalsFilter(users[i], filter) == false) {
|
||||
if (Utils.equalsFilter(users[i], filter) === false) {
|
||||
users.splice(i, 1);
|
||||
}
|
||||
}
|
||||
@ -76,8 +76,8 @@ export class UserManager implements IUserManager {
|
||||
}
|
||||
|
||||
public async deleteUser(id: number) {
|
||||
let deleted = this.db.users.filter((u: UserDTO) => u.id == id);
|
||||
this.db.users = 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.saveDB();
|
||||
if (deleted.length > 0) {
|
||||
return deleted[0];
|
||||
@ -87,7 +87,7 @@ export class UserManager implements IUserManager {
|
||||
|
||||
public async changeRole(id: number, newRole: UserRoles): Promise<UserDTO> {
|
||||
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.saveDB();
|
||||
return this.db.users[i];
|
||||
@ -96,7 +96,7 @@ export class UserManager implements IUserManager {
|
||||
}
|
||||
|
||||
public async changePassword(request: any) {
|
||||
throw new Error('not implemented'); //TODO: implement
|
||||
throw new Error('not implemented'); // TODO: implement
|
||||
}
|
||||
|
||||
private loadDB() {
|
||||
|
@ -24,7 +24,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
|
||||
const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime());
|
||||
let dir = await connection
|
||||
const dir = await connection
|
||||
.getRepository(DirectoryEntity)
|
||||
.createQueryBuilder('directory')
|
||||
.where('directory.name = :name AND directory.path = :path', {
|
||||
@ -37,16 +37,16 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
|
||||
|
||||
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
|
||||
&& lastModified == knownLastModified &&
|
||||
dir.lastScanned == knownLastScanned) {
|
||||
&& lastModified === knownLastModified &&
|
||||
dir.lastScanned === knownLastScanned) {
|
||||
|
||||
if (Config.Server.indexing.reIndexingSensitivity == ReIndexingSensitivity.low) {
|
||||
if (Config.Server.indexing.reIndexingSensitivity === ReIndexingSensitivity.low) {
|
||||
return null;
|
||||
}
|
||||
if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout &&
|
||||
Config.Server.indexing.reIndexingSensitivity == ReIndexingSensitivity.medium) {
|
||||
Config.Server.indexing.reIndexingSensitivity === ReIndexingSensitivity.medium) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -79,15 +79,15 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
}
|
||||
|
||||
|
||||
if (dir.lastModified != lastModified) {
|
||||
if (dir.lastModified !== lastModified) {
|
||||
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 &&
|
||||
Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.medium) ||
|
||||
Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.high) {
|
||||
//on the fly reindexing
|
||||
// on the fly reindexing
|
||||
this.indexDirectory(relativeDirectoryName).catch((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);
|
||||
|
||||
|
||||
@ -109,7 +109,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
try {
|
||||
const scannedDirectory = await DiskManager.scanDirectory(relativeDirectoryName);
|
||||
|
||||
//returning with the result
|
||||
// returning with the result
|
||||
scannedDirectory.photos.forEach(p => p.readyThumbnails = []);
|
||||
resolve(scannedDirectory);
|
||||
|
||||
@ -127,7 +127,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
private async saveToDB(scannedDirectory: DirectoryDTO) {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
|
||||
//saving to db
|
||||
// saving to db
|
||||
const directoryRepository = connection.getRepository(DirectoryEntity);
|
||||
const photosRepository = connection.getRepository(PhotoEntity);
|
||||
|
||||
@ -138,7 +138,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
path: scannedDirectory.path
|
||||
}).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.lastScanned = scannedDirectory.lastScanned;
|
||||
currentDir = await directoryRepository.save(currentDir);
|
||||
@ -147,31 +147,31 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
currentDir = await directoryRepository.save(<DirectoryEntity>scannedDirectory);
|
||||
}
|
||||
|
||||
let childDirectories = await directoryRepository.createQueryBuilder('directory')
|
||||
const childDirectories = await directoryRepository.createQueryBuilder('directory')
|
||||
.where('directory.parent = :dir', {
|
||||
dir: currentDir.id
|
||||
}).getMany();
|
||||
|
||||
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;
|
||||
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];
|
||||
childDirectories.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (directory != null) { //update existing directory
|
||||
if (!directory.parent || !directory.parent.id) { //set parent if not set yet
|
||||
if (directory != null) { // update existing directory
|
||||
if (!directory.parent || !directory.parent.id) { // set parent if not set yet
|
||||
directory.parent = currentDir;
|
||||
delete directory.photos;
|
||||
await directoryRepository.save(directory);
|
||||
}
|
||||
} else {
|
||||
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]);
|
||||
for (let j = 0; j < scannedDirectory.directories[i].photos.length; j++) {
|
||||
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);
|
||||
|
||||
|
||||
let indexedPhotos = await photosRepository.createQueryBuilder('photo')
|
||||
const indexedPhotos = await photosRepository.createQueryBuilder('photo')
|
||||
.where('photo.directory = :dir', {
|
||||
dir: currentDir.id
|
||||
}).getMany();
|
||||
|
||||
|
||||
let photosToSave = [];
|
||||
const photosToSave = [];
|
||||
for (let i = 0; i < scannedDirectory.photos.length; i++) {
|
||||
let photo = null;
|
||||
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];
|
||||
indexedPhotos.splice(j, 1);
|
||||
break;
|
||||
@ -208,10 +208,10 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
photo.directory = currentDir;
|
||||
}
|
||||
|
||||
if (photo.metadata.keywords != scannedDirectory.photos[i].metadata.keywords ||
|
||||
photo.metadata.cameraData != scannedDirectory.photos[i].metadata.cameraData ||
|
||||
photo.metadata.positionData != scannedDirectory.photos[i].metadata.positionData ||
|
||||
photo.metadata.size != scannedDirectory.photos[i].metadata.size) {
|
||||
if (photo.metadata.keywords !== scannedDirectory.photos[i].metadata.keywords ||
|
||||
photo.metadata.cameraData !== scannedDirectory.photos[i].metadata.cameraData ||
|
||||
photo.metadata.positionData !== scannedDirectory.photos[i].metadata.positionData ||
|
||||
photo.metadata.size !== scannedDirectory.photos[i].metadata.size) {
|
||||
|
||||
photo.metadata.keywords = scannedDirectory.photos[i].metadata.keywords;
|
||||
photo.metadata.cameraData = scannedDirectory.photos[i].metadata.cameraData;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
import {DirectoryDTO} from '../../../common/entities/DirectoryDTO';
|
||||
|
||||
export interface ISQLGalleryManager {
|
||||
listDirectory(relativeDirectoryName: string,
|
||||
|
@ -14,7 +14,7 @@ export class IndexingManager implements IIndexingManager {
|
||||
indexingProgress = null;
|
||||
enabled = false;
|
||||
private indexNewDirectory = async () => {
|
||||
if (this.directoriesToIndex.length == 0) {
|
||||
if (this.directoriesToIndex.length === 0) {
|
||||
this.indexingProgress = null;
|
||||
if (global.gc) {
|
||||
global.gc();
|
||||
@ -25,7 +25,7 @@ export class IndexingManager implements IIndexingManager {
|
||||
this.indexingProgress.current = directory;
|
||||
this.indexingProgress.left = this.directoriesToIndex.length;
|
||||
const scanned = await (<ISQLGalleryManager>ObjectManagerRepository.getInstance().GalleryManager).indexDirectory(directory);
|
||||
if (this.enabled == false) {
|
||||
if (this.enabled === false) {
|
||||
return;
|
||||
}
|
||||
this.indexingProgress.indexed++;
|
||||
@ -36,7 +36,7 @@ export class IndexingManager implements IIndexingManager {
|
||||
};
|
||||
|
||||
startIndexing(): void {
|
||||
if (this.directoriesToIndex.length == 0 && this.enabled == false) {
|
||||
if (this.directoriesToIndex.length === 0 && this.enabled === false) {
|
||||
Logger.info(LOG_TAG, 'Starting indexing');
|
||||
this.indexingProgress = <IndexingProgressDTO>{
|
||||
indexed: 0,
|
||||
|
@ -15,7 +15,7 @@ import {Logger} from '../../Logger';
|
||||
|
||||
export class SQLConnection {
|
||||
|
||||
private static VERSION: number = 1;
|
||||
private static VERSION = 1;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
@ -26,7 +26,7 @@ export class SQLConnection {
|
||||
|
||||
if (this.connection == null) {
|
||||
|
||||
let options: any = this.getDriver(Config.Server.database);
|
||||
const options: any = this.getDriver(Config.Server.database);
|
||||
options.name = 'main';
|
||||
options.entities = [
|
||||
UserEntity,
|
||||
@ -68,10 +68,10 @@ export class SQLConnection {
|
||||
|
||||
public static async init(): Promise<void> {
|
||||
const connection = await this.getConnection();
|
||||
let userRepository = connection.getRepository(UserEntity);
|
||||
let admins = await userRepository.find({role: UserRoles.Admin});
|
||||
if (admins.length == 0) {
|
||||
let a = new UserEntity();
|
||||
const userRepository = connection.getRepository(UserEntity);
|
||||
const admins = await userRepository.find({role: UserRoles.Admin});
|
||||
if (admins.length === 0) {
|
||||
const a = new UserEntity();
|
||||
a.name = 'admin';
|
||||
a.password = PasswordHelper.cryptPassword('admin');
|
||||
a.role = UserRoles.Admin;
|
||||
@ -86,7 +86,7 @@ export class SQLConnection {
|
||||
version = await connection.getRepository(VersionEntity).findOne();
|
||||
} catch (ex) {
|
||||
}
|
||||
if (version && version.version == SQLConnection.VERSION) {
|
||||
if (version && version.version === SQLConnection.VERSION) {
|
||||
return;
|
||||
}
|
||||
Logger.info('Updating database scheme');
|
||||
@ -103,7 +103,7 @@ export class SQLConnection {
|
||||
|
||||
private static getDriver(config: DataBaseConfig): ConnectionOptions {
|
||||
let driver: ConnectionOptions = null;
|
||||
if (config.type == DatabaseType.mysql) {
|
||||
if (config.type === DatabaseType.mysql) {
|
||||
driver = {
|
||||
type: 'mysql',
|
||||
host: config.mysql.host,
|
||||
@ -112,7 +112,7 @@ export class SQLConnection {
|
||||
password: config.mysql.password,
|
||||
database: config.mysql.database
|
||||
};
|
||||
} else if (config.type == DatabaseType.sqlite) {
|
||||
} else if (config.type === DatabaseType.sqlite) {
|
||||
driver = {
|
||||
type: 'sqlite',
|
||||
database: ProjectPath.getAbsolutePath(config.sqlite.storage)
|
||||
|
@ -8,11 +8,12 @@ import {DirectoryEntity} from './enitites/DirectoryEntity';
|
||||
export class SearchManager implements ISearchManager {
|
||||
|
||||
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 j = i + 1; j < a.length; ++j) {
|
||||
if (a[i].equals(a[j]))
|
||||
if (a[i].equals(a[j])) {
|
||||
a.splice(j--, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,8 +25,8 @@ export class SearchManager implements ISearchManager {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
|
||||
let result: Array<AutoCompleteItem> = [];
|
||||
let photoRepository = connection.getRepository(PhotoEntity);
|
||||
let directoryRepository = connection.getRepository(DirectoryEntity);
|
||||
const photoRepository = connection.getRepository(PhotoEntity);
|
||||
const directoryRepository = connection.getRepository(DirectoryEntity);
|
||||
|
||||
|
||||
(await photoRepository
|
||||
@ -36,13 +37,15 @@ export class SearchManager implements ISearchManager {
|
||||
.getRawMany())
|
||||
.map(r => <Array<string>>r.metadataKeywords.split(','))
|
||||
.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
|
||||
.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 + '%'})
|
||||
.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 + '%'})
|
||||
@ -52,7 +55,8 @@ export class SearchManager implements ISearchManager {
|
||||
.filter(pm => !!pm)
|
||||
.map(pm => <Array<string>>[pm.city || '', pm.country || '', pm.state || ''])
|
||||
.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
|
||||
@ -86,7 +90,7 @@ export class SearchManager implements ISearchManager {
|
||||
resultOverflow: false
|
||||
};
|
||||
|
||||
let query = connection
|
||||
const query = connection
|
||||
.getRepository(PhotoEntity)
|
||||
.createQueryBuilder('photo')
|
||||
.innerJoinAndSelect('photo.directory', 'directory')
|
||||
@ -136,9 +140,9 @@ export class SearchManager implements ISearchManager {
|
||||
async instantSearch(text: string): Promise<SearchResultDTO> {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
|
||||
let result: SearchResultDTO = <SearchResultDTO>{
|
||||
const result: SearchResultDTO = <SearchResultDTO>{
|
||||
searchText: text,
|
||||
//searchType:undefined, not adding this
|
||||
// searchType:undefined, not adding this
|
||||
directories: [],
|
||||
photos: [],
|
||||
resultOverflow: false
|
||||
@ -169,7 +173,7 @@ export class SearchManager implements ISearchManager {
|
||||
}
|
||||
|
||||
private encapsulateAutoComplete(values: Array<string>, type: SearchTypes): Array<AutoCompleteItem> {
|
||||
let res = [];
|
||||
const res = [];
|
||||
values.forEach((value) => {
|
||||
res.push(new AutoCompleteItem(value, type));
|
||||
});
|
||||
|
@ -42,7 +42,7 @@ export class SharingManager implements ISharingManager {
|
||||
});
|
||||
|
||||
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) {
|
||||
sharing.password = null;
|
||||
|
@ -13,7 +13,7 @@ export class UserManager implements IUserManager {
|
||||
|
||||
public async findOne(filter: any) {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
let pass = filter.password;
|
||||
const pass = filter.password;
|
||||
delete filter.password;
|
||||
const user = (await connection.getRepository(UserEntity).findOne(filter));
|
||||
|
||||
@ -22,11 +22,11 @@ export class UserManager implements IUserManager {
|
||||
}
|
||||
|
||||
if (pass && !PasswordHelper.comparePassword(pass, user.password)) {
|
||||
throw 'No entry found';
|
||||
throw new Error('No entry found');
|
||||
}
|
||||
return user;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public async find(filter: any) {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
@ -56,7 +56,7 @@ export class UserManager implements IUserManager {
|
||||
public async changeRole(id: number, newRole: UserRoles) {
|
||||
|
||||
const connection = await SQLConnection.getConnection();
|
||||
let userRepository = connection.getRepository(UserEntity);
|
||||
const userRepository = connection.getRepository(UserEntity);
|
||||
const user = await userRepository.findOne({id: id});
|
||||
user.role = newRole;
|
||||
return await userRepository.save(user);
|
||||
@ -64,7 +64,7 @@ export class UserManager implements IUserManager {
|
||||
}
|
||||
|
||||
public async changePassword(request: any) {
|
||||
throw new Error('not implemented'); //TODO: implement
|
||||
throw new Error('not implemented'); // TODO: implement
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -108,6 +108,6 @@ export class PhotoEntity implements PhotoDTO {
|
||||
|
||||
readyThumbnails: Array<number> = [];
|
||||
|
||||
readyIcon: boolean = false;
|
||||
readyIcon = false;
|
||||
|
||||
}
|
||||
|
@ -53,11 +53,11 @@ export class DiskMangerWorker {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const file = list[i];
|
||||
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),
|
||||
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;
|
||||
directory.directories.push(d);
|
||||
} else if (DiskMangerWorker.isImage(fullFilePath)) {
|
||||
|
@ -15,9 +15,9 @@ export interface ITaskQue {
|
||||
export class TaskQue implements ITaskQue {
|
||||
|
||||
private tasks: QueTask[] = [];
|
||||
private taskInProgress: number = 0;
|
||||
private taskInProgress = 0;
|
||||
private run = async () => {
|
||||
if (this.tasks.length == 0 || this.taskInProgress >= this.size) {
|
||||
if (this.tasks.length === 0 || this.taskInProgress >= this.size) {
|
||||
return;
|
||||
}
|
||||
this.taskInProgress++;
|
||||
|
@ -30,33 +30,19 @@ export class ThreadPool {
|
||||
}
|
||||
}
|
||||
|
||||
private startWorker() {
|
||||
const worker = <WorkerWrapper>{poolTask: null, worker: cluster.fork()};
|
||||
this.workers.push(worker);
|
||||
worker.worker.on('online', () => {
|
||||
ThreadPool.WorkerCount++;
|
||||
Logger.debug('Worker ' + worker.worker.process.pid + ' is online, worker count:', ThreadPool.WorkerCount);
|
||||
});
|
||||
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();
|
||||
});
|
||||
private run = () => {
|
||||
if (this.tasks.length === 0) {
|
||||
return;
|
||||
}
|
||||
const worker = this.getFreeWorker();
|
||||
if (worker == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
worker.worker.on('message', (msg: WorkerMessage) => {
|
||||
if (worker.poolTask == null) {
|
||||
throw '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();
|
||||
});
|
||||
}
|
||||
const poolTask = this.tasks.shift();
|
||||
worker.poolTask = poolTask;
|
||||
worker.worker.send(poolTask.task);
|
||||
};
|
||||
|
||||
protected executeTask<T>(task: WorkerTask): Promise<T> {
|
||||
return new Promise((resolve: Function, reject: Function) => {
|
||||
@ -74,19 +60,34 @@ export class ThreadPool {
|
||||
return null;
|
||||
}
|
||||
|
||||
private run = () => {
|
||||
if (this.tasks.length == 0) {
|
||||
return;
|
||||
}
|
||||
const worker = this.getFreeWorker();
|
||||
if (worker == null) {
|
||||
return;
|
||||
}
|
||||
private startWorker() {
|
||||
const worker = <WorkerWrapper>{poolTask: null, worker: cluster.fork()};
|
||||
this.workers.push(worker);
|
||||
worker.worker.on('online', () => {
|
||||
ThreadPool.WorkerCount++;
|
||||
Logger.debug('Worker ' + worker.worker.process.pid + ' is online, worker count:', ThreadPool.WorkerCount);
|
||||
});
|
||||
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.poolTask = poolTask;
|
||||
worker.worker.send(poolTask.task);
|
||||
};
|
||||
worker.worker.on('message', (msg: WorkerMessage) => {
|
||||
if (worker.poolTask == null) {
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ export class ThumbnailWoker {
|
||||
private static rendererType = null;
|
||||
|
||||
public static render(input: RendererInput, renderer: ThumbnailProcessingLib): Promise<void> {
|
||||
if (ThumbnailWoker.rendererType != renderer) {
|
||||
if (ThumbnailWoker.rendererType !== renderer) {
|
||||
ThumbnailWoker.renderer = RendererFactory.build(renderer);
|
||||
ThumbnailWoker.rendererType = renderer;
|
||||
}
|
||||
@ -25,7 +25,7 @@ export interface RendererInput {
|
||||
size: number;
|
||||
makeSquare: boolean;
|
||||
thPath: string;
|
||||
qualityPriority: boolean
|
||||
qualityPriority: boolean;
|
||||
}
|
||||
|
||||
export class RendererFactory {
|
||||
@ -39,13 +39,13 @@ export class RendererFactory {
|
||||
case ThumbnailProcessingLib.sharp:
|
||||
return RendererFactory.Sharp();
|
||||
}
|
||||
throw 'unknown renderer';
|
||||
throw new Error('unknown renderer');
|
||||
}
|
||||
|
||||
public static Jimp() {
|
||||
const Jimp = require('jimp');
|
||||
return async (input: RendererInput): Promise<void> => {
|
||||
//generate thumbnail
|
||||
// generate thumbnail
|
||||
Logger.silly('[JimpThRenderer] rendering thumbnail:', input.imagePath);
|
||||
const image = await Jimp.read(input.imagePath);
|
||||
/**
|
||||
@ -58,9 +58,9 @@ export class RendererFactory {
|
||||
* @type {number}
|
||||
*/
|
||||
const ratio = image.bitmap.height / image.bitmap.width;
|
||||
const algo = input.qualityPriority == true ? Jimp.RESIZE_BEZIER : Jimp.RESIZE_NEAREST_NEIGHBOR;
|
||||
if (input.makeSquare == false) {
|
||||
let newWidth = Math.sqrt((input.size * input.size) / ratio);
|
||||
const algo = input.qualityPriority === true ? Jimp.RESIZE_BEZIER : Jimp.RESIZE_NEAREST_NEIGHBOR;
|
||||
if (input.makeSquare === false) {
|
||||
const newWidth = Math.sqrt((input.size * input.size) / ratio);
|
||||
|
||||
image.resize(newWidth, Jimp.AUTO, algo);
|
||||
} else {
|
||||
@ -100,8 +100,8 @@ export class RendererFactory {
|
||||
* @type {number}
|
||||
*/
|
||||
const ratio = metadata.height / metadata.width;
|
||||
const kernel = input.qualityPriority == true ? sharp.kernel.lanczos3 : sharp.kernel.nearest;
|
||||
if (input.makeSquare == false) {
|
||||
const kernel = input.qualityPriority === true ? sharp.kernel.lanczos3 : sharp.kernel.nearest;
|
||||
if (input.makeSquare === false) {
|
||||
const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio));
|
||||
image.resize(newWidth, null, {
|
||||
kernel: kernel
|
||||
@ -141,19 +141,19 @@ export class RendererFactory {
|
||||
*/
|
||||
try {
|
||||
const ratio = value.height / value.width;
|
||||
const filter = input.qualityPriority == true ? 'Lanczos' : 'Point';
|
||||
const filter = input.qualityPriority === true ? 'Lanczos' : 'Point';
|
||||
image.filter(filter);
|
||||
|
||||
if (input.makeSquare == false) {
|
||||
if (input.makeSquare === false) {
|
||||
const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio));
|
||||
image = image.resize(newWidth);
|
||||
} else {
|
||||
image = image.resize(input.size, input.size)
|
||||
.crop(input.size, input.size);
|
||||
}
|
||||
image.write(input.thPath, (err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
image.write(input.thPath, (e) => {
|
||||
if (e) {
|
||||
return reject(e);
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
|
@ -23,7 +23,7 @@ export class Worker {
|
||||
break;
|
||||
default:
|
||||
Logger.error('Unknown worker task type');
|
||||
throw 'Unknown worker task type';
|
||||
throw new Error('Unknown worker task type');
|
||||
}
|
||||
process.send(<WorkerMessage>{
|
||||
error: null,
|
||||
@ -32,7 +32,6 @@ export class Worker {
|
||||
} catch (err) {
|
||||
process.send({error: err, result: null});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
import {NextFunction, Request, Response} from 'express';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as ejs from 'ejs';
|
||||
import {Utils} from '../../common/Utils';
|
||||
import {Config} from '../../common/config/private/Config';
|
||||
import {ProjectPath} from '../ProjectPath';
|
||||
import {AuthenticationMWs} from '../middlewares/user/AuthenticationMWs';
|
||||
import {CookieNames} from '../../common/CookieNames';
|
||||
import {ErrorDTO} from '../../common/entities/Error';
|
||||
|
||||
|
||||
export class PublicRouter {
|
||||
|
||||
|
||||
public static route(app) {
|
||||
const setLocale = (req: Request, res: Response, next: Function) => {
|
||||
let localePath = '';
|
||||
@ -27,8 +30,14 @@ export class PublicRouter {
|
||||
next();
|
||||
};
|
||||
|
||||
const renderIndex = (req: Request, res: Response) => {
|
||||
res.sendFile(path.resolve(ProjectPath.FrontendFolder, req['localePath'], 'index.html'), {maxAge: 31536000});
|
||||
const renderIndex = (req: Request, res: Response, next: Function) => {
|
||||
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();
|
||||
});
|
||||
|
||||
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*'],
|
||||
AuthenticationMWs.tryAuthenticate,
|
||||
|
@ -18,7 +18,7 @@ export class SharingRouter {
|
||||
AuthenticationMWs.shareLogin,
|
||||
RenderingMWs.renderSessionUser
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
private static addGetSharing(app) {
|
||||
app.get('/api/share/:sharingKey',
|
||||
@ -27,7 +27,7 @@ export class SharingRouter {
|
||||
SharingMWs.getSharing,
|
||||
RenderingMWs.renderSharing
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
private static addCreateSharing(app) {
|
||||
app.post(['/api/share/:directory(*)', '/api/share/', '/api/share//'],
|
||||
@ -36,7 +36,7 @@ export class SharingRouter {
|
||||
SharingMWs.createSharing,
|
||||
RenderingMWs.renderSharing
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
private static addUpdateSharing(app) {
|
||||
app.put(['/api/share/:directory(*)', '/api/share/', '/api/share//'],
|
||||
@ -45,7 +45,6 @@ export class SharingRouter {
|
||||
SharingMWs.updateSharing,
|
||||
RenderingMWs.renderSharing
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,8 +30,44 @@ export class Server {
|
||||
private app: 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() {
|
||||
if (!(process.env.NODE_ENV == 'production')) {
|
||||
if (!(process.env.NODE_ENV === 'production')) {
|
||||
Logger.debug(LOG_TAG, 'Running in DEBUG mode');
|
||||
}
|
||||
this.init();
|
||||
@ -82,7 +118,7 @@ export class Server {
|
||||
Localizations.init();
|
||||
|
||||
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();
|
||||
} else {
|
||||
await ObjectManagerRepository.InitMemoryManagers();
|
||||
@ -105,7 +141,7 @@ export class Server {
|
||||
// Create HTTP server.
|
||||
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.on('error', this.onError);
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
export class CookieNames {
|
||||
public static lang = "pigallery2-lang";
|
||||
public static session = "pigallery2-session";
|
||||
public static lang = 'pigallery2-lang';
|
||||
public static session = 'pigallery2-session';
|
||||
}
|
||||
|
@ -6,14 +6,14 @@ export class Utils {
|
||||
}
|
||||
|
||||
static equalsFilter(object: any, filter: any): boolean {
|
||||
if (typeof filter !== "object" || filter == null) {
|
||||
return object == filter;
|
||||
if (typeof filter !== 'object' || filter == null) {
|
||||
return object === filter;
|
||||
}
|
||||
const keys = Object.keys(filter);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if (typeof filter[key] === "object") {
|
||||
if (Utils.equalsFilter(object[key], filter[key]) == false) {
|
||||
if (typeof filter[key] === 'object') {
|
||||
if (Utils.equalsFilter(object[key], filter[key]) === false) {
|
||||
return false;
|
||||
}
|
||||
} else if (object[key] !== filter[key]) {
|
||||
@ -27,19 +27,23 @@ export class Utils {
|
||||
|
||||
|
||||
static concatUrls(...args: Array<string>) {
|
||||
let url = "";
|
||||
let url = '';
|
||||
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("\\", "/");
|
||||
if (part === "/" || part === "./") continue;
|
||||
const part = args[i].replace('\\', '/');
|
||||
if (part === '/' || part === './') {
|
||||
continue;
|
||||
}
|
||||
|
||||
url += part + "/";
|
||||
url += part + '/';
|
||||
}
|
||||
url = url.replace("//", "/");
|
||||
url = url.replace('//', '/');
|
||||
|
||||
if (url.trim() == "") {
|
||||
url = "./";
|
||||
if (url.trim() === '') {
|
||||
url = './';
|
||||
}
|
||||
|
||||
return url.substring(0, url.length - 1);
|
||||
@ -47,10 +51,10 @@ export class Utils {
|
||||
|
||||
public static updateKeys(targetObject: any, sourceObject: any) {
|
||||
Object.keys(sourceObject).forEach((key) => {
|
||||
if (typeof targetObject[key] === "undefined") {
|
||||
if (typeof targetObject[key] === 'undefined') {
|
||||
return;
|
||||
}
|
||||
if (typeof targetObject[key] === "object") {
|
||||
if (typeof targetObject[key] === 'object') {
|
||||
Utils.updateKeys(targetObject[key], sourceObject[key]);
|
||||
} else {
|
||||
targetObject[key] = sourceObject[key];
|
||||
@ -60,7 +64,7 @@ export class Utils {
|
||||
|
||||
public static setKeys(targetObject: any, sourceObject: any) {
|
||||
Object.keys(sourceObject).forEach((key) => {
|
||||
if (typeof targetObject[key] === "object") {
|
||||
if (typeof targetObject[key] === 'object') {
|
||||
Utils.setKeys(targetObject[key], sourceObject[key]);
|
||||
} else {
|
||||
targetObject[key] = sourceObject[key];
|
||||
@ -70,8 +74,8 @@ export class Utils {
|
||||
|
||||
public static setKeysForced(targetObject: any, sourceObject: any) {
|
||||
Object.keys(sourceObject).forEach((key) => {
|
||||
if (typeof sourceObject[key] === "object") {
|
||||
if (typeof targetObject[key] === "undefined") {
|
||||
if (typeof sourceObject[key] === 'object') {
|
||||
if (typeof targetObject[key] === 'undefined') {
|
||||
targetObject[key] = {};
|
||||
}
|
||||
Utils.setKeysForced(targetObject[key], sourceObject[key]);
|
||||
@ -85,12 +89,12 @@ export class Utils {
|
||||
key: number;
|
||||
value: string;
|
||||
}> {
|
||||
let arr: Array<{ key: number; value: string; }> = [];
|
||||
for (let enumMember in EnumType) {
|
||||
const arr: Array<{ key: number; value: string; }> = [];
|
||||
for (const enumMember in EnumType) {
|
||||
if (!EnumType.hasOwnProperty(enumMember)) {
|
||||
continue;
|
||||
}
|
||||
let key = parseInt(enumMember, 10);
|
||||
const key = parseInt(enumMember, 10);
|
||||
if (key >= 0) {
|
||||
arr.push({key: key, value: EnumType[enumMember]});
|
||||
}
|
||||
@ -106,7 +110,7 @@ export class Utils {
|
||||
|
||||
arr.forEach((value) => {
|
||||
|
||||
let newDiff = Math.abs(number - value);
|
||||
const newDiff = Math.abs(number - value);
|
||||
|
||||
if (newDiff < diff) {
|
||||
diff = newDiff;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {PrivateConfigClass} from "./PrivateConfigClass";
|
||||
import {PrivateConfigClass} from './PrivateConfigClass';
|
||||
|
||||
|
||||
export let Config = new PrivateConfigClass();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {ClientConfig} from "../public/ConfigClass";
|
||||
import {ClientConfig} from '../public/ConfigClass';
|
||||
|
||||
export enum DatabaseType {
|
||||
memory = 0, mysql = 1, sqlite = 2
|
||||
@ -47,7 +47,7 @@ export enum ReIndexingSensitivity {
|
||||
|
||||
export interface IndexingConfig {
|
||||
folderPreviewSize: number;
|
||||
cachedFolderTimeout: number;//Do not rescans the folder if seems ok
|
||||
cachedFolderTimeout: number; // Do not rescans the folder if seems ok
|
||||
reIndexingSensitivity: ReIndexingSensitivity;
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ export interface ServerConfig {
|
||||
database: DataBaseConfig;
|
||||
enableThreading: boolean;
|
||||
sharing: SharingConfig;
|
||||
sessionTimeout: number
|
||||
sessionTimeout: number;
|
||||
indexing: IndexingConfig;
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,7 @@
|
||||
import {PublicConfigClass} from "../public/ConfigClass";
|
||||
import {
|
||||
DatabaseType,
|
||||
IPrivateConfig,
|
||||
ReIndexingSensitivity,
|
||||
ServerConfig,
|
||||
ThumbnailProcessingLib
|
||||
} from "./IPrivateConfig";
|
||||
import * as path from "path";
|
||||
import {ConfigLoader} from "typeconfig";
|
||||
import {PublicConfigClass} from '../public/ConfigClass';
|
||||
import {DatabaseType, IPrivateConfig, ReIndexingSensitivity, ServerConfig, ThumbnailProcessingLib} from './IPrivateConfig';
|
||||
import * as path from 'path';
|
||||
import {ConfigLoader} from 'typeconfig';
|
||||
|
||||
/**
|
||||
* This configuration will be only at backend
|
||||
@ -16,9 +10,9 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
||||
|
||||
public Server: ServerConfig = {
|
||||
port: 80,
|
||||
imagesFolder: "demo/images",
|
||||
imagesFolder: 'demo/images',
|
||||
thumbnail: {
|
||||
folder: "demo/TEMP",
|
||||
folder: 'demo/TEMP',
|
||||
processingLibrary: ThumbnailProcessingLib.sharp,
|
||||
qualityPriority: true
|
||||
},
|
||||
@ -26,14 +20,14 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
||||
database: {
|
||||
type: DatabaseType.sqlite,
|
||||
mysql: {
|
||||
host: "",
|
||||
username: "",
|
||||
password: "",
|
||||
database: ""
|
||||
host: '',
|
||||
username: '',
|
||||
password: '',
|
||||
database: ''
|
||||
|
||||
},
|
||||
sqlite: {
|
||||
storage: "sqlite.db"
|
||||
storage: 'sqlite.db'
|
||||
}
|
||||
},
|
||||
sharing: {
|
||||
@ -59,7 +53,7 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
||||
public load() {
|
||||
ConfigLoader.loadBackendConfig(this,
|
||||
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 {
|
||||
let cfg = new PrivateConfigClass();
|
||||
const cfg = new PrivateConfigClass();
|
||||
cfg.load();
|
||||
return cfg;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {PublicConfigClass} from "./ConfigClass";
|
||||
import {WebConfigLoader} from "typeconfig/src/WebConfigLoader";
|
||||
import {PublicConfigClass} from './ConfigClass';
|
||||
import {WebConfigLoader} from 'typeconfig/src/WebConfigLoader';
|
||||
|
||||
|
||||
declare module ServerInject {
|
||||
@ -9,12 +9,12 @@ declare module ServerInject {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
if (Config.Client.publicUrl == "") {
|
||||
if (Config.Client.publicUrl === '') {
|
||||
Config.Client.publicUrl = location.origin;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
export module ClientConfig {
|
||||
export interface SearchConfig {
|
||||
enabled: boolean
|
||||
instantSearchEnabled: boolean
|
||||
autocompleteEnabled: boolean
|
||||
enabled: boolean;
|
||||
instantSearchEnabled: boolean;
|
||||
autocompleteEnabled: boolean;
|
||||
InstantSearchTimeout: number;
|
||||
autocompleteCacheTimeout: number;
|
||||
instantSearchCacheTimeout: number;
|
||||
@ -36,6 +36,7 @@ export module ClientConfig {
|
||||
enableOnScrollThumbnailPrioritising: boolean;
|
||||
authenticationRequired: boolean;
|
||||
publicUrl: string;
|
||||
urlBase: string;
|
||||
languages: string[];
|
||||
}
|
||||
|
||||
@ -47,7 +48,7 @@ export module ClientConfig {
|
||||
export class PublicConfigClass {
|
||||
|
||||
public Client: ClientConfig.Config = {
|
||||
applicationTitle: "PiGallery 2",
|
||||
applicationTitle: 'PiGallery 2',
|
||||
Thumbnail: {
|
||||
thumbnailSizes: [200, 400, 600],
|
||||
iconSize: 30
|
||||
@ -67,14 +68,15 @@ export class PublicConfigClass {
|
||||
},
|
||||
Map: {
|
||||
enabled: true,
|
||||
googleApiKey: ""
|
||||
googleApiKey: ''
|
||||
},
|
||||
concurrentThumbnailGenerations: 1,
|
||||
enableCache: true,
|
||||
enableOnScrollRendering: true,
|
||||
enableOnScrollThumbnailPrioritising: true,
|
||||
authenticationRequired: true,
|
||||
publicUrl: "",
|
||||
publicUrl: '',
|
||||
urlBase: '',
|
||||
languages: []
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {SearchResultDTO} from "./SearchResultDTO";
|
||||
import {DirectoryDTO} from './DirectoryDTO';
|
||||
import {SearchResultDTO} from './SearchResultDTO';
|
||||
|
||||
export class ContentWrapper {
|
||||
constructor(public directory: DirectoryDTO = null,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {PhotoDTO} from "./PhotoDTO";
|
||||
import {PhotoDTO} from './PhotoDTO';
|
||||
|
||||
export interface DirectoryDTO {
|
||||
id: number;
|
||||
@ -22,5 +22,5 @@ export module DirectoryDTO {
|
||||
addReferences(directory);
|
||||
directory.parent = dir;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export enum ErrorCodes{
|
||||
export enum ErrorCodes {
|
||||
NOT_AUTHENTICATED = 0,
|
||||
ALREADY_AUTHENTICATED = 1,
|
||||
NOT_AUTHORISED = 2,
|
||||
|
@ -1,5 +1,7 @@
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {ErrorDTO} from "./Error";
|
||||
import {ErrorDTO} from './Error';
|
||||
|
||||
export class Message<T> {
|
||||
public error: ErrorDTO = null;
|
||||
|
@ -1,4 +1,4 @@
|
||||
export enum NotificationType{
|
||||
export enum NotificationType {
|
||||
error, warning, info
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {UserModificationRequest} from "./UserModificationRequest";
|
||||
import {UserModificationRequest} from './UserModificationRequest';
|
||||
|
||||
export class PasswordChangeRequest extends UserModificationRequest {
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {DirectoryDTO} from './DirectoryDTO';
|
||||
|
||||
export interface PhotoDTO {
|
||||
id: number;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {PhotoDTO} from "./PhotoDTO";
|
||||
import {SearchTypes} from "./AutoCompleteItem";
|
||||
import {DirectoryDTO} from './DirectoryDTO';
|
||||
import {PhotoDTO} from './PhotoDTO';
|
||||
import {SearchTypes} from './AutoCompleteItem';
|
||||
|
||||
export interface SearchResultDTO {
|
||||
searchText: string;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {UserDTO} from "./UserDTO";
|
||||
import {UserDTO} from './UserDTO';
|
||||
|
||||
export interface SharingDTO {
|
||||
id: number;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {Utils} from "../Utils";
|
||||
import {DirectoryDTO} from './DirectoryDTO';
|
||||
import {Utils} from '../Utils';
|
||||
|
||||
export enum UserRoles {
|
||||
LimitedGuest = 0,
|
||||
@ -15,25 +15,25 @@ export interface UserDTO {
|
||||
name: string;
|
||||
password: string;
|
||||
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 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;
|
||||
}
|
||||
for (let i = 0; i < permissions.length; i++) {
|
||||
let permission = permissions[i];
|
||||
if (permission[permission.length - 1] == "*") {
|
||||
if (permission[permission.length - 1] === '*') {
|
||||
permission = permission.slice(0, -1);
|
||||
if (path.startsWith(permission)) {
|
||||
return true;
|
||||
}
|
||||
} else if (path == permission) {
|
||||
} else if (path === permission) {
|
||||
return true;
|
||||
} else if (path == "." && permission == "/") {
|
||||
} else if (path === '.' && permission === '/') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
export interface BasicConfigDTO {
|
||||
imagesFolder: string;
|
||||
publicUrl: string;
|
||||
urlBase: string;
|
||||
applicationTitle: string;
|
||||
port: number;
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
function isFunction(functionToCheck: any) {
|
||||
let getType = {};
|
||||
const getType = {};
|
||||
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
||||
}
|
||||
|
||||
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)) {
|
||||
throw new Error("Handler is not a function");
|
||||
throw new Error('Handler is not a function');
|
||||
}
|
||||
this.handlers.push(handler);
|
||||
}
|
||||
|
||||
public off(handler: { (data?: T): void }) {
|
||||
public off(handler: (data?: T) => void) {
|
||||
this.handlers = this.handlers.filter(h => h !== handler);
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
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);
|
||||
}
|
||||
|
||||
public off(handler: { (data?: T, data2?: M): void }) {
|
||||
public off(handler: (data?: T, data2?: M) => void) {
|
||||
this.handlers = this.handlers.filter(h => h !== handler);
|
||||
}
|
||||
|
||||
|
@ -4,21 +4,21 @@ export class EventLimit<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));
|
||||
if (this.lastTriggerValue != null) {
|
||||
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));
|
||||
if (this.lastTriggerValue != null) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ export class EventLimit<T> {
|
||||
class EventLimitHandler<T> {
|
||||
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) {
|
||||
@ -54,18 +54,19 @@ class EventLimitHandler<T> {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class SingleFireEventLimitHandler<T> extends EventLimitHandler<T> {
|
||||
public fired = false;
|
||||
|
||||
constructor(public limit: T, public handler: { (data?: T): void }) {
|
||||
constructor(public limit: T, public handler: (data?: T) => void) {
|
||||
super(limit, handler);
|
||||
}
|
||||
|
||||
public fire(data?: T) {
|
||||
if (this.fired == false) {
|
||||
if (this.fired === false) {
|
||||
this.handler(data);
|
||||
}
|
||||
this.fired = true
|
||||
this.fired = true;
|
||||
}
|
||||
|
||||
public isValid(): boolean {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {PhotoDTO} from '../../../common/entities/PhotoDTO';
|
||||
import {Utils} from '../../../common/Utils';
|
||||
import {Config} from '../../../common/config/public/Config';
|
||||
|
||||
export class IconPhoto {
|
||||
|
||||
@ -19,23 +20,29 @@ export class IconPhoto {
|
||||
}
|
||||
|
||||
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() {
|
||||
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 {
|
||||
//is gridphoto
|
||||
// is gridphoto
|
||||
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) {
|
||||
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;
|
||||
|
@ -19,7 +19,7 @@ export class Photo extends IconPhoto {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ export class Photo extends IconPhoto {
|
||||
if (this.replacementSizeCache === false) {
|
||||
this.replacementSizeCache = null;
|
||||
|
||||
let size = this.getThumbnailSize();
|
||||
const size = this.getThumbnailSize();
|
||||
if (!!this.photo.readyThumbnails) {
|
||||
for (let i = 0; i < this.photo.readyThumbnails.length; i++) {
|
||||
if (this.photo.readyThumbnails[i] < size) {
|
||||
@ -46,18 +46,22 @@ export class Photo extends IconPhoto {
|
||||
}
|
||||
|
||||
isThumbnailAvailable() {
|
||||
return this.photo.readyThumbnails && this.photo.readyThumbnails.indexOf(this.getThumbnailSize()) != -1;
|
||||
return this.photo.readyThumbnails && this.photo.readyThumbnails.indexOf(this.getThumbnailSize()) !== -1;
|
||||
}
|
||||
|
||||
getReplacementThumbnailPath() {
|
||||
let size = this.getReplacementThumbnailSize();
|
||||
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
|
||||
const size = this.getReplacementThumbnailSize();
|
||||
return Utils.concatUrls(Config.Client.urlBase,
|
||||
'/api/gallery/content/',
|
||||
this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
|
||||
|
||||
}
|
||||
|
||||
getThumbnailPath() {
|
||||
let size = this.getThumbnailSize();
|
||||
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
|
||||
const size = this.getThumbnailSize();
|
||||
return Utils.concatUrls(Config.Client.urlBase,
|
||||
'/api/gallery/content/',
|
||||
this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,7 +68,7 @@ export class GalleryCacheService {
|
||||
|
||||
public getSearch(text: string, type?: SearchTypes): SearchResultDTO {
|
||||
let key = GalleryCacheService.SEARCH_PREFIX + text;
|
||||
if (typeof type != 'undefined') {
|
||||
if (typeof type !== 'undefined') {
|
||||
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
|
||||
}
|
||||
const tmp = localStorage.getItem(key);
|
||||
@ -89,7 +89,7 @@ export class GalleryCacheService {
|
||||
item: searchResult
|
||||
};
|
||||
let key = GalleryCacheService.SEARCH_PREFIX + text;
|
||||
if (typeof type != 'undefined') {
|
||||
if (typeof type !== 'undefined') {
|
||||
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
|
||||
}
|
||||
localStorage.setItem(key, JSON.stringify(tmp));
|
||||
@ -97,12 +97,12 @@ export class GalleryCacheService {
|
||||
|
||||
|
||||
public getDirectory(directoryName: string): DirectoryDTO {
|
||||
if (Config.Client.enableCache == false) {
|
||||
if (Config.Client.enableCache === false) {
|
||||
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) {
|
||||
let directory: DirectoryDTO = JSON.parse(value);
|
||||
const directory: DirectoryDTO = JSON.parse(value);
|
||||
|
||||
DirectoryDTO.addReferences(directory);
|
||||
return directory;
|
||||
@ -111,12 +111,12 @@ export class GalleryCacheService {
|
||||
}
|
||||
|
||||
public setDirectory(directory: DirectoryDTO): void {
|
||||
if (Config.Client.enableCache == false) {
|
||||
if (Config.Client.enableCache === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ export class GalleryCacheService {
|
||||
|
||||
directory.directories.forEach((dir: DirectoryDTO) => {
|
||||
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));
|
||||
}
|
||||
});
|
||||
@ -137,21 +137,21 @@ export class GalleryCacheService {
|
||||
*/
|
||||
public photoUpdated(photo: PhotoDTO): void {
|
||||
|
||||
if (Config.Client.enableCache == false) {
|
||||
if (Config.Client.enableCache === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
let directoryName = Utils.concatUrls(photo.directory.path, photo.directory.name);
|
||||
let value = localStorage.getItem(directoryName);
|
||||
const directoryName = Utils.concatUrls(photo.directory.path, photo.directory.name);
|
||||
const value = localStorage.getItem(directoryName);
|
||||
if (value != null) {
|
||||
let directory: DirectoryDTO = JSON.parse(value);
|
||||
const directory: DirectoryDTO = JSON.parse(value);
|
||||
directory.photos.forEach((p) => {
|
||||
if (p.name === photo.name) {
|
||||
//update data
|
||||
// update data
|
||||
p.metadata = photo.metadata;
|
||||
p.readyThumbnails = photo.readyThumbnails;
|
||||
|
||||
//save changes
|
||||
// save changes
|
||||
localStorage.setItem(directoryName, JSON.stringify(directory));
|
||||
return;
|
||||
}
|
||||
|
@ -28,10 +28,11 @@ export class GalleryDirectoryComponent implements OnInit, OnDestroy {
|
||||
size: number = null;
|
||||
|
||||
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 {
|
||||
return document.body.scrollTop < this.container.nativeElement.offsetTop + this.container.nativeElement.clientHeight
|
||||
&& document.body.scrollTop + window.innerHeight > this.container.nativeElement.offsetTop;
|
||||
|
@ -16,7 +16,7 @@ import {ContentWrapper} from '../../../common/entities/ConentWrapper';
|
||||
import {PageHelper} from '../model/page.helper';
|
||||
|
||||
@Component({
|
||||
selector: 'gallery',
|
||||
selector: 'app-gallery',
|
||||
templateUrl: './gallery.component.html',
|
||||
styleUrls: ['./gallery.component.css']
|
||||
})
|
||||
|
@ -36,7 +36,7 @@ export class GalleryService {
|
||||
this.lastRequest.directory = directoryName;
|
||||
|
||||
const params = {};
|
||||
if (Config.Client.Sharing.enabled == true) {
|
||||
if (Config.Client.Sharing.enabled === true) {
|
||||
if (this._shareService.isSharing()) {
|
||||
params['sk'] = this._shareService.getSharingKey();
|
||||
}
|
||||
@ -52,13 +52,13 @@ export class GalleryService {
|
||||
const cw = await this.networkService.getJson<ContentWrapper>('/gallery/content/' + directoryName, params);
|
||||
|
||||
|
||||
if (!cw || cw.notModified == true) {
|
||||
if (!cw || cw.notModified === true) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ export class GalleryService {
|
||||
if (this.searchId != null) {
|
||||
clearTimeout(this.searchId);
|
||||
}
|
||||
if (text === null || text === '' || text.trim() == '.') {
|
||||
if (text === null || text === '' || text.trim() === '.') {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ export class GalleryService {
|
||||
cw.searchResult = this.galleryCacheService.getSearch(text, type);
|
||||
if (cw.searchResult == null) {
|
||||
const params = {};
|
||||
if (typeof type != 'undefined') {
|
||||
if (typeof type !== 'undefined') {
|
||||
params['type'] = type;
|
||||
}
|
||||
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> {
|
||||
if (text === null || text === '' || text.trim() == '.') {
|
||||
if (text === null || text === '' || text.trim() === '.') {
|
||||
const content = new ContentWrapper(this.lastDirectory);
|
||||
this.content.next(content);
|
||||
if (this.searchId != null) {
|
||||
@ -119,7 +119,7 @@ export class GalleryService {
|
||||
cw.directory = null;
|
||||
cw.searchResult = this.galleryCacheService.getSearch(text);
|
||||
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.search(text);
|
||||
this.searchId = null;
|
||||
@ -134,8 +134,8 @@ export class GalleryService {
|
||||
}
|
||||
this.content.next(cw);
|
||||
|
||||
//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 instant search do not have a result, do not do a search
|
||||
if (cw.searchResult.photos.length === 0 && cw.searchResult.directories.length === 0) {
|
||||
if (this.searchId != null) {
|
||||
clearTimeout(this.searchId);
|
||||
}
|
||||
|
@ -63,5 +63,5 @@ export class GridRowBuilder {
|
||||
const height = (this.containerWidth - this.photoRow.length * (this.photoMargin * 2) - 1) / width; // cant be equal -> width-1
|
||||
|
||||
return height + (this.photoMargin * 2);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,7 @@
|
||||
border: 1px solid #ccc;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding: 5px 0;
|
||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export class ShareService {
|
||||
constructor(private _networkService: NetworkService, private router: Router) {
|
||||
this.sharing = new BehaviorSubject(null);
|
||||
this.ReadyPR = new Promise((resolve) => {
|
||||
if (this.inited == true) {
|
||||
if (this.inited === true) {
|
||||
return resolve();
|
||||
}
|
||||
this.resolve = resolve;
|
||||
@ -29,7 +29,7 @@ export class ShareService {
|
||||
if (val instanceof RoutesRecognized) {
|
||||
this.param = val.state.root.firstChild.params['sharingKey'] || 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) {
|
||||
this.sharingKey = this.param || this.queryParam;
|
||||
this.getSharing();
|
||||
|
@ -13,142 +13,16 @@ export enum ThumbnailLoadingPriority {
|
||||
export class ThumbnailLoaderService {
|
||||
|
||||
que: Array<ThumbnailTask> = [];
|
||||
runningRequests: number = 0;
|
||||
runningRequests = 0;
|
||||
|
||||
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 = () => {
|
||||
if (this.que.length === 0 || this.runningRequests >= Config.Client.concurrentThumbnailGenerations) {
|
||||
return;
|
||||
}
|
||||
let task = this.getNextTask();
|
||||
const task = this.getNextTask();
|
||||
|
||||
if (task === null) {
|
||||
return;
|
||||
@ -158,7 +32,7 @@ export class ThumbnailLoaderService {
|
||||
task.taskEntities.forEach(te => te.listener.onStartedLoading());
|
||||
task.inProgress = true;
|
||||
|
||||
let curImg = new Image();
|
||||
const curImg = new Image();
|
||||
curImg.onload = () => {
|
||||
task.onLoaded();
|
||||
this.galleryCacheService.photoUpdated(task.photo);
|
||||
@ -179,6 +53,129 @@ export class ThumbnailLoaderService {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,15 +28,15 @@ export class ThumbnailManagerService {
|
||||
|
||||
export abstract class ThumbnailBase {
|
||||
|
||||
protected available: boolean = false;
|
||||
protected available = false;
|
||||
protected src: string = null;
|
||||
protected loading: boolean = false;
|
||||
protected error: boolean = false;
|
||||
protected loading = false;
|
||||
protected error = false;
|
||||
protected onLoad: Function = null;
|
||||
protected thumbnailTask: ThumbnailTaskEntity = null;
|
||||
|
||||
|
||||
constructor(protected thumbnailService: ThumbnailLoaderService) {
|
||||
protected constructor(protected thumbnailService: ThumbnailLoaderService) {
|
||||
}
|
||||
|
||||
abstract set Visible(visible: boolean);
|
||||
@ -80,24 +80,28 @@ export class IconThumbnail extends ThumbnailBase {
|
||||
if (this.photo.isIconAvailable()) {
|
||||
this.src = this.photo.getIconPath();
|
||||
this.available = true;
|
||||
if (this.onLoad) this.onLoad();
|
||||
if (this.onLoad) {
|
||||
this.onLoad();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.photo.isIconAvailable()) {
|
||||
setTimeout(() => {
|
||||
|
||||
let listener: ThumbnailLoadingListener = {
|
||||
onStartedLoading: () => { //onLoadStarted
|
||||
const listener: ThumbnailLoadingListener = {
|
||||
onStartedLoading: () => { // onLoadStarted
|
||||
this.loading = true;
|
||||
},
|
||||
onLoad: () => {//onLoaded
|
||||
onLoad: () => {// onLoaded
|
||||
this.src = this.photo.getIconPath();
|
||||
if (this.onLoad) this.onLoad();
|
||||
if (this.onLoad) {
|
||||
this.onLoad();
|
||||
}
|
||||
this.available = true;
|
||||
this.loading = false;
|
||||
this.thumbnailTask = null;
|
||||
},
|
||||
onError: (error) => {//onError
|
||||
onError: (error) => {// onError
|
||||
this.thumbnailTask = null;
|
||||
this.loading = false;
|
||||
this.error = true;
|
||||
@ -112,7 +116,9 @@ export class IconThumbnail extends ThumbnailBase {
|
||||
}
|
||||
|
||||
set Visible(visible: boolean) {
|
||||
if (!this.thumbnailTask) return;
|
||||
if (!this.thumbnailTask) {
|
||||
return;
|
||||
}
|
||||
if (visible === true) {
|
||||
this.thumbnailTask.priority = ThumbnailLoadingPriority.high;
|
||||
} else {
|
||||
@ -131,7 +137,9 @@ export class Thumbnail extends ThumbnailBase {
|
||||
if (this.photo.isThumbnailAvailable()) {
|
||||
this.src = this.photo.getThumbnailPath();
|
||||
this.available = true;
|
||||
if (this.onLoad) this.onLoad();
|
||||
if (this.onLoad) {
|
||||
this.onLoad();
|
||||
}
|
||||
} else if (this.photo.isReplacementThumbnailAvailable()) {
|
||||
this.src = this.photo.getReplacementThumbnailPath();
|
||||
this.available = true;
|
||||
@ -142,7 +150,9 @@ export class Thumbnail extends ThumbnailBase {
|
||||
}
|
||||
|
||||
set CurrentlyWaiting(value: boolean) {
|
||||
if (!this.thumbnailTask) return;
|
||||
if (!this.thumbnailTask) {
|
||||
return;
|
||||
}
|
||||
if (value === true) {
|
||||
if (this.photo.isReplacementThumbnailAvailable()) {
|
||||
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) {
|
||||
if (!this.thumbnailTask) return;
|
||||
if (!this.thumbnailTask) {
|
||||
return;
|
||||
}
|
||||
if (visible === true) {
|
||||
if (this.photo.isReplacementThumbnailAvailable()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -32,12 +32,11 @@
|
||||
max-width: 350px;
|
||||
width: 100% !important;
|
||||
background-color: #F7F7F7;
|
||||
margin: 0 auto;
|
||||
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;
|
||||
height: 295px;
|
||||
margin-top: 0px;
|
||||
margin: 0px auto 0;
|
||||
}
|
||||
|
||||
/*Margin by pixel:*/
|
||||
|
@ -6,13 +6,13 @@ import {Config} from '../../../common/config/public/Config';
|
||||
import {NavigationService} from '../model/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector: 'login',
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.css'],
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
loginCredential: LoginCredential;
|
||||
loginError: boolean = false;
|
||||
loginError = false;
|
||||
title: string;
|
||||
inProgress = false;
|
||||
|
||||
|
@ -4,11 +4,13 @@ import {Message} from '../../../../common/entities/Message';
|
||||
import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
|
||||
import 'rxjs/Rx';
|
||||
import {ErrorCodes, ErrorDTO} from '../../../../common/entities/Error';
|
||||
import {Config} from '../../../../common/config/public/Config';
|
||||
import {Utils} from '../../../../common/Utils';
|
||||
|
||||
@Injectable()
|
||||
export class NetworkService {
|
||||
|
||||
_baseUrl = '/api';
|
||||
_apiBaseUrl = Utils.concatUrls(Config.Client.urlBase, '/api');
|
||||
private globalErrorHandlers: Array<(error: ErrorDTO) => boolean> = [];
|
||||
|
||||
constructor(private _http: HttpClient,
|
||||
@ -69,22 +71,22 @@ export class NetworkService {
|
||||
|
||||
switch (method) {
|
||||
case 'get':
|
||||
return this._http.get<Message<T>>(this._baseUrl + url)
|
||||
return this._http.get<Message<T>>(this._apiBaseUrl + url)
|
||||
.toPromise()
|
||||
.then(process)
|
||||
.catch(err);
|
||||
case 'delete':
|
||||
return this._http.delete<Message<T>>(this._baseUrl + url)
|
||||
return this._http.delete<Message<T>>(this._apiBaseUrl + url)
|
||||
.toPromise()
|
||||
.then(process)
|
||||
.catch(err);
|
||||
case 'post':
|
||||
return this._http.post<Message<T>>(this._baseUrl + url, body)
|
||||
return this._http.post<Message<T>>(this._apiBaseUrl + url, body)
|
||||
.toPromise()
|
||||
.then(process)
|
||||
.catch(err);
|
||||
case 'put':
|
||||
return this._http.put<Message<T>>(this._baseUrl + url, body)
|
||||
return this._http.put<Message<T>>(this._apiBaseUrl + url, body)
|
||||
.toPromise()
|
||||
.then(process)
|
||||
.catch(err);
|
||||
|
@ -38,13 +38,13 @@ export abstract class SettingsComponent<T, S extends AbstractSettingsService<T>=
|
||||
High: 'High'
|
||||
};
|
||||
|
||||
constructor(private name,
|
||||
private _authService: AuthenticationService,
|
||||
private _navigation: NavigationService,
|
||||
public _settingsService: S,
|
||||
protected notification: NotificationService,
|
||||
public i18n: I18n,
|
||||
private sliceFN?: (s: IPrivateConfig) => T) {
|
||||
protected constructor(private name,
|
||||
private _authService: AuthenticationService,
|
||||
private _navigation: NavigationService,
|
||||
public _settingsService: S,
|
||||
protected notification: NotificationService,
|
||||
public i18n: I18n,
|
||||
private sliceFN?: (s: IPrivateConfig) => T) {
|
||||
if (this.sliceFN) {
|
||||
this._settingsSubscription = this._settingsService.Settings.subscribe(this.onNewSettings);
|
||||
this.onNewSettings(this._settingsService._settingsService.settings.value);
|
||||
|
@ -2,7 +2,7 @@ import {SettingsService} from '../settings.service';
|
||||
|
||||
export abstract class AbstractSettingsService<T> {
|
||||
|
||||
constructor(public _settingsService: SettingsService) {
|
||||
protected constructor(public _settingsService: SettingsService) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,17 @@
|
||||
</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"
|
||||
[disabled]="!settingsForm.form.valid || !changed || inProgress"
|
||||
(click)="save()" i18n>Save
|
||||
|
@ -27,7 +27,8 @@ export class BasicSettingsComponent extends SettingsComponent<BasicConfigDTO> {
|
||||
port: s.Server.port,
|
||||
imagesFolder: s.Server.imagesFolder,
|
||||
applicationTitle: s.Client.applicationTitle,
|
||||
publicUrl: s.Client.publicUrl
|
||||
publicUrl: s.Client.publicUrl,
|
||||
urlBase: s.Client.urlBase
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ export class SettingsService {
|
||||
enabled: true,
|
||||
googleApiKey: ''
|
||||
},
|
||||
urlBase: '',
|
||||
publicUrl: '',
|
||||
applicationTitle: '',
|
||||
enableCache: true,
|
||||
|
@ -54,7 +54,7 @@ export class UserMangerSettingsComponent implements OnInit {
|
||||
}
|
||||
this.userRoles = Utils
|
||||
.enumToArray(UserRoles)
|
||||
.filter(r => r.key != UserRoles.LimitedGuest)
|
||||
.filter(r => r.key !== UserRoles.LimitedGuest)
|
||||
.filter(r => r.key <= this._authService.user.value.role)
|
||||
.sort((a, b) => a.key - b.key);
|
||||
|
||||
@ -62,29 +62,39 @@ export class UserMangerSettingsComponent implements OnInit {
|
||||
this.getUsersList();
|
||||
}
|
||||
|
||||
private async getUsersList() {
|
||||
try {
|
||||
this.users = await this._userSettings.getUsers();
|
||||
} catch (err) {
|
||||
this.users = [];
|
||||
if ((<ErrorDTO>err).code != ErrorCodes.USER_MANAGEMENT_DISABLED) {
|
||||
throw err;
|
||||
}
|
||||
canModifyUser(user: UserDTO): boolean {
|
||||
const currentUser = this._authService.user.value;
|
||||
if (!currentUser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return currentUser.name !== user.name && currentUser.role >= user.role;
|
||||
}
|
||||
|
||||
private async getSettings() {
|
||||
this.enabled = await this._userSettings.getSettings();
|
||||
}
|
||||
|
||||
|
||||
canModifyUser(user: UserDTO): boolean {
|
||||
let currentUser = this._authService.user.value;
|
||||
if (!currentUser) {
|
||||
return false;
|
||||
async switched(event: { previousValue: false, currentValue: true }) {
|
||||
this.inProgress = true;
|
||||
this.error = '';
|
||||
this.enabled = event.currentValue;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return currentUser.name != user.name && currentUser.role >= user.role;
|
||||
this.inProgress = false;
|
||||
}
|
||||
|
||||
initNewUser() {
|
||||
@ -110,26 +120,15 @@ export class UserMangerSettingsComponent implements OnInit {
|
||||
this.childModal.hide();
|
||||
}
|
||||
|
||||
async switched(event: { previousValue: false, currentValue: true }) {
|
||||
this.inProgress = true;
|
||||
this.error = '';
|
||||
this.enabled = event.currentValue;
|
||||
private async getUsersList() {
|
||||
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'));
|
||||
}
|
||||
this.users = await this._userSettings.getUsers();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
if (err.message) {
|
||||
this.error = (<ErrorDTO>err).message;
|
||||
this.users = [];
|
||||
if ((<ErrorDTO>err).code !== ErrorCodes.USER_MANAGEMENT_DISABLED) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
this.inProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
var ServerInject = {
|
||||
user: <%- JSON.stringify(user); %>,
|
||||
ConfigInject: <%- JSON.stringify(clientConfig); %>
|
||||
}
|
@ -1,17 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/"/>
|
||||
<base href="<%= clientConfig.urlBase %>/"/>
|
||||
<meta charset="UTF-8">
|
||||
<title>Loading..</title>
|
||||
<link rel="shortcut icon" href="assets/icon.png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
|
||||
<link rel="stylesheet"
|
||||
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>
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
// 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/proxy.js";
|
||||
import "zone.js/dist/sync-test";
|
||||
import "zone.js/dist/jasmine-patch";
|
||||
import "zone.js/dist/async-test";
|
||||
import "zone.js/dist/fake-async-test";
|
||||
import {getTestBed} from "@angular/core/testing";
|
||||
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from "@angular/platform-browser-dynamic/testing";
|
||||
import 'zone.js/dist/long-stack-trace-zone';
|
||||
import 'zone.js/dist/proxy.js';
|
||||
import 'zone.js/dist/sync-test';
|
||||
import 'zone.js/dist/jasmine-patch';
|
||||
import 'zone.js/dist/async-test';
|
||||
import 'zone.js/dist/fake-async-test';
|
||||
import {getTestBed} from '@angular/core/testing';
|
||||
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
|
||||
declare const __karma__: any;
|
||||
|
@ -6,7 +6,7 @@
|
||||
<source>Please log in</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||
<context context-type="linenumber">11</context>
|
||||
<context context-type="linenumber">10</context>
|
||||
</context-group>
|
||||
<target>Please log in</target>
|
||||
</trans-unit>
|
||||
@ -16,7 +16,7 @@
|
||||
</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||
<context context-type="linenumber">13</context>
|
||||
<context context-type="linenumber">12</context>
|
||||
</context-group>
|
||||
<target>
|
||||
Wrong username or password
|
||||
@ -26,7 +26,7 @@
|
||||
<source>Username</source>
|
||||
<context-group purpose="location">
|
||||
<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 purpose="location">
|
||||
<context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context>
|
||||
@ -42,7 +42,7 @@
|
||||
<source>Password</source>
|
||||
<context-group purpose="location">
|
||||
<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 purpose="location">
|
||||
<context context-type="sourcefile">app/sharelogin/share-login.component.ts</context>
|
||||
@ -70,7 +70,7 @@
|
||||
<source>Remember me</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||
<context context-type="linenumber">42</context>
|
||||
<context context-type="linenumber">43</context>
|
||||
</context-group>
|
||||
<target>Remember me</target>
|
||||
</trans-unit>
|
||||
@ -79,7 +79,7 @@
|
||||
</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||
<context context-type="linenumber">52</context>
|
||||
<context context-type="linenumber">53</context>
|
||||
</context-group>
|
||||
<target>Login
|
||||
</target>
|
||||
@ -146,7 +146,7 @@
|
||||
<source>key: left arrow</source>
|
||||
<context-group purpose="location">
|
||||
<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>
|
||||
<target>key: left arrow</target>
|
||||
</trans-unit>
|
||||
@ -154,7 +154,7 @@
|
||||
<source>key: right arrow</source>
|
||||
<context-group purpose="location">
|
||||
<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>
|
||||
<target>key: right arrow</target>
|
||||
</trans-unit>
|
||||
@ -533,7 +533,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<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 purpose="location">
|
||||
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
||||
@ -563,7 +563,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<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 purpose="location">
|
||||
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
||||
@ -840,6 +840,22 @@
|
||||
</context-group>
|
||||
<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 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">
|
||||
<source>Other settings</source>
|
||||
<context-group purpose="location">
|
||||
|
@ -6,7 +6,7 @@
|
||||
<source>Please log in</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||
<context context-type="linenumber">11</context>
|
||||
<context context-type="linenumber">10</context>
|
||||
</context-group>
|
||||
<target>Jelentkezz be</target>
|
||||
</trans-unit>
|
||||
@ -16,7 +16,7 @@
|
||||
</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||
<context context-type="linenumber">13</context>
|
||||
<context context-type="linenumber">12</context>
|
||||
</context-group>
|
||||
<target>Rossz felhasználónév vagy jelszó</target>
|
||||
</trans-unit>
|
||||
@ -24,7 +24,7 @@
|
||||
<source>Username</source>
|
||||
<context-group purpose="location">
|
||||
<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 purpose="location">
|
||||
<context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context>
|
||||
@ -40,7 +40,7 @@
|
||||
<source>Password</source>
|
||||
<context-group purpose="location">
|
||||
<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 purpose="location">
|
||||
<context context-type="sourcefile">app/sharelogin/share-login.component.ts</context>
|
||||
@ -68,7 +68,7 @@
|
||||
<source>Remember me</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||
<context context-type="linenumber">42</context>
|
||||
<context context-type="linenumber">43</context>
|
||||
</context-group>
|
||||
<target>Emlékezz rám</target>
|
||||
</trans-unit>
|
||||
@ -77,7 +77,7 @@
|
||||
</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||
<context context-type="linenumber">52</context>
|
||||
<context context-type="linenumber">53</context>
|
||||
</context-group>
|
||||
<target>Belépés</target>
|
||||
</trans-unit>
|
||||
@ -140,7 +140,7 @@
|
||||
<source>key: left arrow</source>
|
||||
<context-group purpose="location">
|
||||
<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>
|
||||
<target>billentyű: balra nyíl</target>
|
||||
</trans-unit>
|
||||
@ -148,7 +148,7 @@
|
||||
<source>key: right arrow</source>
|
||||
<context-group purpose="location">
|
||||
<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>
|
||||
<target>billentyű: jobbra nyíl</target>
|
||||
</trans-unit>
|
||||
@ -516,7 +516,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<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 purpose="location">
|
||||
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
||||
@ -545,7 +545,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<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 purpose="location">
|
||||
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
||||
@ -816,6 +816,22 @@
|
||||
</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>
|
||||
</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">
|
||||
<source>Other settings</source>
|
||||
<context-group purpose="location">
|
||||
@ -1257,4 +1273,4 @@
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
</xliff>
|
||||
|
10
gulpfile.js
10
gulpfile.js
@ -28,7 +28,9 @@ var createFrontendTask = function (type, script) {
|
||||
};
|
||||
|
||||
gulp.task('build-frontend', function (done) {
|
||||
var languages = getLanguages();
|
||||
var languages = getLanguages().filter(function (l) {
|
||||
return l !== "en";
|
||||
});
|
||||
var tasks = [];
|
||||
createFrontendTask('build-frontend-release default',
|
||||
"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 f.split(".")[1]
|
||||
}).filter(function (l) {
|
||||
return l !== "en";
|
||||
});
|
||||
};
|
||||
|
||||
var simpleBuild = function (isProd) {
|
||||
return function (done) {
|
||||
var languages = getLanguages();
|
||||
var languages = getLanguages().filter(function (l) {
|
||||
return l !== "en";
|
||||
});
|
||||
var tasks = [];
|
||||
var cmd = "ng build --aot ";
|
||||
if (isProd) {
|
||||
|
@ -17,7 +17,6 @@
|
||||
"lint": "ng lint",
|
||||
"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",
|
||||
"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",
|
||||
"add-translation": "gulp add-translation"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user