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`
|
* bug free :) - `In progress`
|
||||||
|
|
||||||
|
|
||||||
## Translate the page to you own language
|
## Translate the page to your own language
|
||||||
1) download / clone the repo (the source not the packed release!)
|
1) download / clone the repo (the source not the packed release!)
|
||||||
2) add your language e.g: fr
|
2) add your language e.g: fr
|
||||||
```bash
|
```bash
|
||||||
|
@ -10,7 +10,7 @@ declare module 'winston' {
|
|||||||
export const winstonSettings = {
|
export const winstonSettings = {
|
||||||
transports: [
|
transports: [
|
||||||
new winston.transports.Console({
|
new winston.transports.Console({
|
||||||
level: process.env.NODE_ENV == 'production' ? 'info' : 'silly',
|
level: process.env.NODE_ENV === 'production' ? 'info' : 'silly',
|
||||||
handleExceptions: true,
|
handleExceptions: true,
|
||||||
json: false,
|
json: false,
|
||||||
colorize: true,
|
colorize: true,
|
||||||
|
@ -191,12 +191,14 @@ export class AdminMWs {
|
|||||||
Config.Server.port = settings.port;
|
Config.Server.port = settings.port;
|
||||||
Config.Server.imagesFolder = settings.imagesFolder;
|
Config.Server.imagesFolder = settings.imagesFolder;
|
||||||
Config.Client.publicUrl = settings.publicUrl;
|
Config.Client.publicUrl = settings.publicUrl;
|
||||||
|
Config.Client.urlBase = settings.urlBase;
|
||||||
Config.Client.applicationTitle = settings.applicationTitle;
|
Config.Client.applicationTitle = settings.applicationTitle;
|
||||||
// only updating explicitly set config (not saving config set by the diagnostics)
|
// only updating explicitly set config (not saving config set by the diagnostics)
|
||||||
const original = Config.original();
|
const original = Config.original();
|
||||||
original.Server.port = settings.port;
|
original.Server.port = settings.port;
|
||||||
original.Server.imagesFolder = settings.imagesFolder;
|
original.Server.imagesFolder = settings.imagesFolder;
|
||||||
original.Client.publicUrl = settings.publicUrl;
|
original.Client.publicUrl = settings.publicUrl;
|
||||||
|
original.Client.urlBase = settings.urlBase;
|
||||||
original.Client.applicationTitle = settings.applicationTitle;
|
original.Client.applicationTitle = settings.applicationTitle;
|
||||||
original.save();
|
original.save();
|
||||||
ProjectPath.reset();
|
ProjectPath.reset();
|
||||||
|
@ -12,8 +12,9 @@ import {Logger} from '../Logger';
|
|||||||
export class RenderingMWs {
|
export class RenderingMWs {
|
||||||
|
|
||||||
public static renderResult(req: Request, res: Response, next: NextFunction) {
|
public static renderResult(req: Request, res: Response, next: NextFunction) {
|
||||||
if (typeof req.resultPipe == 'undefined')
|
if (typeof req.resultPipe === 'undefined') {
|
||||||
return next();
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
return RenderingMWs.renderMessage(res, req.resultPipe);
|
return RenderingMWs.renderMessage(res, req.resultPipe);
|
||||||
}
|
}
|
||||||
@ -30,8 +31,9 @@ export class RenderingMWs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static renderSharing(req: Request, res: Response, next: NextFunction) {
|
public static renderSharing(req: Request, res: Response, next: NextFunction) {
|
||||||
if (!req.resultPipe)
|
if (!req.resultPipe) {
|
||||||
return next();
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
const sharing = Utils.clone<SharingDTO>(req.resultPipe);
|
const sharing = Utils.clone<SharingDTO>(req.resultPipe);
|
||||||
delete sharing.password;
|
delete sharing.password;
|
||||||
@ -39,20 +41,21 @@ export class RenderingMWs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static renderFile(req: Request, res: Response, next: NextFunction) {
|
public static renderFile(req: Request, res: Response, next: NextFunction) {
|
||||||
if (!req.resultPipe)
|
if (!req.resultPipe) {
|
||||||
return next();
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
return res.sendFile(req.resultPipe, {maxAge: 31536000});
|
return res.sendFile(req.resultPipe, {maxAge: 31536000});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static renderOK(req: Request, res: Response, next: NextFunction) {
|
public static renderOK(req: Request, res: Response, next: NextFunction) {
|
||||||
let message = new Message<string>(null, 'ok');
|
const message = new Message<string>(null, 'ok');
|
||||||
res.json(message);
|
res.json(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static renderConfig(req: Request, res: Response, next: NextFunction) {
|
public static renderConfig(req: Request, res: Response, next: NextFunction) {
|
||||||
let message = new Message<PrivateConfigClass>(null, Config.original());
|
const message = new Message<PrivateConfigClass>(null, Config.original());
|
||||||
res.json(message);
|
res.json(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +75,7 @@ export class RenderingMWs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let message = new Message<any>(err, null);
|
const message = new Message<any>(err, null);
|
||||||
return res.json(message);
|
return res.json(message);
|
||||||
}
|
}
|
||||||
NotificationManager.error('unknown server error', err);
|
NotificationManager.error('unknown server error', err);
|
||||||
@ -81,7 +84,7 @@ export class RenderingMWs {
|
|||||||
|
|
||||||
|
|
||||||
protected static renderMessage<T>(res: Response, content: T) {
|
protected static renderMessage<T>(res: Response, content: T) {
|
||||||
let message = new Message<T>(null, content);
|
const message = new Message<T>(null, content);
|
||||||
res.json(message);
|
res.json(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ export class SharingMWs {
|
|||||||
const createSharing: CreateSharingDTO = req.body.createSharing;
|
const createSharing: CreateSharingDTO = req.body.createSharing;
|
||||||
let sharingKey = SharingMWs.generateKey();
|
let sharingKey = SharingMWs.generateKey();
|
||||||
|
|
||||||
//create one not yet used
|
// create one not yet used
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
@ -52,7 +52,7 @@ export class SharingMWs {
|
|||||||
|
|
||||||
|
|
||||||
const directoryName = req.params.directory || '/';
|
const directoryName = req.params.directory || '/';
|
||||||
let sharing: SharingDTO = {
|
const sharing: SharingDTO = {
|
||||||
id: null,
|
id: null,
|
||||||
sharingKey: sharingKey,
|
sharingKey: sharingKey,
|
||||||
path: directoryName,
|
path: directoryName,
|
||||||
@ -79,7 +79,7 @@ export class SharingMWs {
|
|||||||
}
|
}
|
||||||
const updateSharing: CreateSharingDTO = req.body.updateSharing;
|
const updateSharing: CreateSharingDTO = req.body.updateSharing;
|
||||||
const directoryName = req.params.directory || '/';
|
const directoryName = req.params.directory || '/';
|
||||||
let sharing: SharingDTO = {
|
const sharing: SharingDTO = {
|
||||||
id: updateSharing.id,
|
id: updateSharing.id,
|
||||||
path: directoryName,
|
path: directoryName,
|
||||||
sharingKey: '',
|
sharingKey: '',
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
declare module Express {
|
declare module Express {
|
||||||
export interface Request {
|
export interface Request {
|
||||||
resultPipe?: any
|
resultPipe?: any;
|
||||||
body?: {
|
body?: {
|
||||||
loginCredential
|
loginCredential
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Response {
|
export interface Response {
|
||||||
tpl?: any
|
tpl?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Session {
|
export interface Session {
|
||||||
|
@ -125,7 +125,8 @@ export class ThumbnailGeneratorMWs {
|
|||||||
photos[i].readyThumbnails.push(size);
|
photos[i].readyThumbnails.push(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const iconPath = path.join(thumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(fullImagePath, Config.Client.Thumbnail.iconSize));
|
const iconPath = path.join(thumbnailFolder,
|
||||||
|
ThumbnailGeneratorMWs.generateThumbnailName(fullImagePath, Config.Client.Thumbnail.iconSize));
|
||||||
if (fs.existsSync(iconPath) === true) {
|
if (fs.existsSync(iconPath) === true) {
|
||||||
photos[i].readyIcon = true;
|
photos[i].readyIcon = true;
|
||||||
}
|
}
|
||||||
@ -133,7 +134,10 @@ export class ThumbnailGeneratorMWs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async generateImage(imagePath: string, size: number, makeSquare: boolean, req: Request, res: Response, next: NextFunction) {
|
private static async generateImage(imagePath: string,
|
||||||
|
size: number,
|
||||||
|
makeSquare: boolean,
|
||||||
|
req: Request, res: Response, next: NextFunction) {
|
||||||
// generate thumbnail path
|
// generate thumbnail path
|
||||||
const thPath = path.join(ProjectPath.ThumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(imagePath, size));
|
const thPath = path.join(ProjectPath.ThumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(imagePath, size));
|
||||||
|
|
||||||
@ -162,7 +166,7 @@ export class ThumbnailGeneratorMWs {
|
|||||||
await this.taskQue.execute(input);
|
await this.taskQue.execute(input);
|
||||||
return next();
|
return next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return next(new ErrorDTO(ErrorCodes.THUMBNAIL_GENERATION_ERROR, 'Error during generating thumbnail', error));
|
return next(new ErrorDTO(ErrorCodes.THUMBNAIL_GENERATION_ERROR, 'Error during generating thumbnail: ' + input.imagePath, error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,13 +55,13 @@ export class AuthenticationMWs {
|
|||||||
|
|
||||||
public static authoriseDirectory(req: Request, res: Response, next: NextFunction) {
|
public static authoriseDirectory(req: Request, res: Response, next: NextFunction) {
|
||||||
if (req.session.user.permissions == null ||
|
if (req.session.user.permissions == null ||
|
||||||
req.session.user.permissions.length == 0 ||
|
req.session.user.permissions.length === 0 ||
|
||||||
req.session.user.permissions[0] == '/*') {
|
req.session.user.permissions[0] === '/*') {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const directoryName = req.params.directory || '/';
|
const directoryName = req.params.directory || '/';
|
||||||
if (UserDTO.isPathAvailable(directoryName, req.session.user.permissions) == true) {
|
if (UserDTO.isPathAvailable(directoryName, req.session.user.permissions) === true) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ export class AuthenticationMWs {
|
|||||||
if (Config.Client.Sharing.enabled === false) {
|
if (Config.Client.Sharing.enabled === false) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
//not enough parameter
|
// not enough parameter
|
||||||
if ((!req.query.sk && !req.params.sharingKey)) {
|
if ((!req.query.sk && !req.params.sharingKey)) {
|
||||||
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'no sharing key provided'));
|
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'no sharing key provided'));
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ export class AuthenticationMWs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let path = sharing.path;
|
let path = sharing.path;
|
||||||
if (sharing.includeSubfolders == true) {
|
if (sharing.includeSubfolders === true) {
|
||||||
path += '*';
|
path += '*';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,13 +122,15 @@ export class AuthenticationMWs {
|
|||||||
|
|
||||||
public static async login(req: Request, res: Response, next: NextFunction) {
|
public static async login(req: Request, res: Response, next: NextFunction) {
|
||||||
|
|
||||||
//not enough parameter
|
// not enough parameter
|
||||||
if ((typeof req.body === 'undefined') || (typeof req.body.loginCredential === 'undefined') || (typeof req.body.loginCredential.username === 'undefined') ||
|
if ((typeof req.body === 'undefined') ||
|
||||||
|
(typeof req.body.loginCredential === 'undefined') ||
|
||||||
|
(typeof req.body.loginCredential.username === 'undefined') ||
|
||||||
(typeof req.body.loginCredential.password === 'undefined')) {
|
(typeof req.body.loginCredential.password === 'undefined')) {
|
||||||
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR));
|
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
//lets find the user
|
// lets find the user
|
||||||
const user = Utils.clone(await ObjectManagerRepository.getInstance().UserManager.findOne({
|
const user = Utils.clone(await ObjectManagerRepository.getInstance().UserManager.findOne({
|
||||||
name: req.body.loginCredential.username,
|
name: req.body.loginCredential.username,
|
||||||
password: req.body.loginCredential.password
|
password: req.body.loginCredential.password
|
||||||
@ -162,7 +164,7 @@ export class AuthenticationMWs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let path = sharing.path;
|
let path = sharing.path;
|
||||||
if (sharing.includeSubfolders == true) {
|
if (sharing.includeSubfolders === true) {
|
||||||
path += '*';
|
path += '*';
|
||||||
}
|
}
|
||||||
return <UserDTO>{name: 'Guest', role: UserRoles.LimitedGuest, permissions: [path]};
|
return <UserDTO>{name: 'Guest', role: UserRoles.LimitedGuest, permissions: [path]};
|
||||||
|
@ -18,7 +18,7 @@ const LOG_TAG = '[ConfigDiagnostics]';
|
|||||||
export class ConfigDiagnostics {
|
export class ConfigDiagnostics {
|
||||||
|
|
||||||
static async testDatabase(databaseConfig: DataBaseConfig) {
|
static async testDatabase(databaseConfig: DataBaseConfig) {
|
||||||
if (databaseConfig.type != DatabaseType.memory) {
|
if (databaseConfig.type !== DatabaseType.memory) {
|
||||||
await SQLConnection.tryConnection(databaseConfig);
|
await SQLConnection.tryConnection(databaseConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,43 +77,45 @@ export class ConfigDiagnostics {
|
|||||||
|
|
||||||
static async testClientThumbnailConfig(thumbnailConfig: ClientConfig.ThumbnailConfig) {
|
static async testClientThumbnailConfig(thumbnailConfig: ClientConfig.ThumbnailConfig) {
|
||||||
if (isNaN(thumbnailConfig.iconSize) || thumbnailConfig.iconSize <= 0) {
|
if (isNaN(thumbnailConfig.iconSize) || thumbnailConfig.iconSize <= 0) {
|
||||||
throw 'IconSize has to be >= 0 integer, got: ' + thumbnailConfig.iconSize;
|
throw new Error('IconSize has to be >= 0 integer, got: ' + thumbnailConfig.iconSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!thumbnailConfig.thumbnailSizes.length) {
|
if (!thumbnailConfig.thumbnailSizes.length) {
|
||||||
throw 'At least one thumbnail size is needed';
|
throw new Error('At least one thumbnail size is needed');
|
||||||
}
|
}
|
||||||
for (let i = 0; i < thumbnailConfig.thumbnailSizes.length; i++) {
|
for (let i = 0; i < thumbnailConfig.thumbnailSizes.length; i++) {
|
||||||
if (isNaN(thumbnailConfig.thumbnailSizes[i]) || thumbnailConfig.thumbnailSizes[i] <= 0) {
|
if (isNaN(thumbnailConfig.thumbnailSizes[i]) || thumbnailConfig.thumbnailSizes[i] <= 0) {
|
||||||
throw 'Thumbnail size has to be >= 0 integer, got: ' + thumbnailConfig.thumbnailSizes[i];
|
throw new Error('Thumbnail size has to be >= 0 integer, got: ' + thumbnailConfig.thumbnailSizes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static async testSearchConfig(search: ClientConfig.SearchConfig, config: IPrivateConfig) {
|
static async testSearchConfig(search: ClientConfig.SearchConfig, config: IPrivateConfig) {
|
||||||
if (search.enabled == true && config.Server.database.type == DatabaseType.memory) {
|
if (search.enabled === true &&
|
||||||
throw 'Memory Database do not support searching';
|
config.Server.database.type === DatabaseType.memory) {
|
||||||
|
throw new Error('Memory Database do not support searching');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static async testSharingConfig(sharing: ClientConfig.SharingConfig, config: IPrivateConfig) {
|
static async testSharingConfig(sharing: ClientConfig.SharingConfig, config: IPrivateConfig) {
|
||||||
if (sharing.enabled == true && config.Server.database.type == DatabaseType.memory) {
|
if (sharing.enabled === true &&
|
||||||
throw 'Memory Database do not support sharing';
|
config.Server.database.type === DatabaseType.memory) {
|
||||||
|
throw new Error('Memory Database do not support sharing');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async testMapConfig(map: ClientConfig.MapConfig) {
|
static async testMapConfig(map: ClientConfig.MapConfig) {
|
||||||
if (map.enabled == true && (!map.googleApiKey || map.googleApiKey.length == 0)) {
|
if (map.enabled === true && (!map.googleApiKey || map.googleApiKey.length === 0)) {
|
||||||
throw 'Maps need a valid google api key';
|
throw new Error('Maps need a valid google api key');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static async runDiagnostics() {
|
static async runDiagnostics() {
|
||||||
|
|
||||||
if (Config.Server.database.type != DatabaseType.memory) {
|
if (Config.Server.database.type !== DatabaseType.memory) {
|
||||||
try {
|
try {
|
||||||
await ConfigDiagnostics.testDatabase(Config.Server.database);
|
await ConfigDiagnostics.testDatabase(Config.Server.database);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -124,7 +126,7 @@ export class ConfigDiagnostics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.Server.thumbnail.processingLibrary != ThumbnailProcessingLib.Jimp) {
|
if (Config.Server.thumbnail.processingLibrary !== ThumbnailProcessingLib.Jimp) {
|
||||||
try {
|
try {
|
||||||
await ConfigDiagnostics.testThumbnailLib(Config.Server.thumbnail.processingLibrary);
|
await ConfigDiagnostics.testThumbnailLib(Config.Server.thumbnail.processingLibrary);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -164,7 +166,8 @@ export class ConfigDiagnostics {
|
|||||||
try {
|
try {
|
||||||
await ConfigDiagnostics.testSearchConfig(Config.Client.Search, Config);
|
await ConfigDiagnostics.testSearchConfig(Config.Client.Search, Config);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
NotificationManager.warning('Search is not supported with these settings. Disabling temporally. Please adjust the config properly.', err);
|
NotificationManager.warning('Search is not supported with these settings. Disabling temporally. ' +
|
||||||
|
'Please adjust the config properly.', err);
|
||||||
Logger.warn(LOG_TAG, 'Search is not supported with these settings, switching off..', err);
|
Logger.warn(LOG_TAG, 'Search is not supported with these settings, switching off..', err);
|
||||||
Config.Client.Search.enabled = false;
|
Config.Client.Search.enabled = false;
|
||||||
}
|
}
|
||||||
@ -172,7 +175,8 @@ export class ConfigDiagnostics {
|
|||||||
try {
|
try {
|
||||||
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing, Config);
|
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing, Config);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
NotificationManager.warning('Sharing is not supported with these settings. Disabling temporally. Please adjust the config properly.', err);
|
NotificationManager.warning('Sharing is not supported with these settings. Disabling temporally. ' +
|
||||||
|
'Please adjust the config properly.', err);
|
||||||
Logger.warn(LOG_TAG, 'Sharing is not supported with these settings, switching off..', err);
|
Logger.warn(LOG_TAG, 'Sharing is not supported with these settings, switching off..', err);
|
||||||
Config.Client.Sharing.enabled = false;
|
Config.Client.Sharing.enabled = false;
|
||||||
}
|
}
|
||||||
@ -180,8 +184,10 @@ export class ConfigDiagnostics {
|
|||||||
try {
|
try {
|
||||||
await ConfigDiagnostics.testMapConfig(Config.Client.Map);
|
await ConfigDiagnostics.testMapConfig(Config.Client.Map);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
NotificationManager.warning('Maps is not supported with these settings. Disabling temporally. Please adjust the config properly.', err);
|
NotificationManager.warning('Maps is not supported with these settings. Disabling temporally. ' +
|
||||||
Logger.warn(LOG_TAG, 'Maps is not supported with these settings. Disabling temporally. Please adjust the config properly.', err);
|
'Please adjust the config properly.', err);
|
||||||
|
Logger.warn(LOG_TAG, 'Maps is not supported with these settings. Disabling temporally. ' +
|
||||||
|
'Please adjust the config properly.', err);
|
||||||
Config.Client.Map.enabled = false;
|
Config.Client.Map.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ export class DiskManager {
|
|||||||
static threadPool: DiskManagerTH = null;
|
static threadPool: DiskManagerTH = null;
|
||||||
|
|
||||||
public static init() {
|
public static init() {
|
||||||
if (Config.Server.enableThreading == true) {
|
if (Config.Server.enableThreading === true) {
|
||||||
DiskManager.threadPool = new DiskManagerTH(1);
|
DiskManager.threadPool = new DiskManagerTH(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,12 +23,12 @@ export class DiskManager {
|
|||||||
|
|
||||||
let directory: DirectoryDTO = null;
|
let directory: DirectoryDTO = null;
|
||||||
|
|
||||||
if (Config.Server.enableThreading == true) {
|
if (Config.Server.enableThreading === true) {
|
||||||
directory = await DiskManager.threadPool.execute(relativeDirectoryName);
|
directory = await DiskManager.threadPool.execute(relativeDirectoryName);
|
||||||
} else {
|
} else {
|
||||||
directory = await DiskMangerWorker.scanDirectory(relativeDirectoryName);
|
directory = await DiskMangerWorker.scanDirectory(relativeDirectoryName);
|
||||||
}
|
}
|
||||||
let addDirs = (dir: DirectoryDTO) => {
|
const addDirs = (dir: DirectoryDTO) => {
|
||||||
dir.photos.forEach((ph) => {
|
dir.photos.forEach((ph) => {
|
||||||
ph.directory = dir;
|
ph.directory = dir;
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {ProjectPath} from '../ProjectPath';
|
import {ProjectPath} from '../ProjectPath';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {Config} from '../../common/config/private/Config';
|
import {Config} from '../../common/config/private/Config';
|
||||||
|
|
||||||
export class Localizations {
|
export class Localizations {
|
||||||
@ -10,8 +10,9 @@ export class Localizations {
|
|||||||
|
|
||||||
public static init() {
|
public static init() {
|
||||||
const notLanguage = ['assets'];
|
const notLanguage = ['assets'];
|
||||||
const dirCont = fs.readdirSync(ProjectPath.FrontendFolder).filter(f => fs.statSync(path.resolve(ProjectPath.FrontendFolder, f)).isDirectory());
|
const dirCont = fs.readdirSync(ProjectPath.FrontendFolder)
|
||||||
Config.Client.languages = dirCont.filter(d => notLanguage.indexOf(d) == -1);
|
.filter(f => fs.statSync(path.resolve(ProjectPath.FrontendFolder, f)).isDirectory());
|
||||||
|
Config.Client.languages = dirCont.filter(d => notLanguage.indexOf(d) === -1);
|
||||||
Config.Client.languages.push('en');
|
Config.Client.languages.push('en');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,12 +8,13 @@ import {IIndexingManager} from './interfaces/IIndexingManager';
|
|||||||
|
|
||||||
export class ObjectManagerRepository {
|
export class ObjectManagerRepository {
|
||||||
|
|
||||||
|
private static _instance: ObjectManagerRepository = null;
|
||||||
|
|
||||||
private _galleryManager: IGalleryManager;
|
private _galleryManager: IGalleryManager;
|
||||||
private _userManager: IUserManager;
|
private _userManager: IUserManager;
|
||||||
private _searchManager: ISearchManager;
|
private _searchManager: ISearchManager;
|
||||||
private _sharingManager: ISharingManager;
|
private _sharingManager: ISharingManager;
|
||||||
private _indexingManager: IIndexingManager;
|
private _indexingManager: IIndexingManager;
|
||||||
private static _instance: ObjectManagerRepository = null;
|
|
||||||
|
|
||||||
get IndexingManager(): IIndexingManager {
|
get IndexingManager(): IIndexingManager {
|
||||||
return this._indexingManager;
|
return this._indexingManager;
|
||||||
|
@ -10,12 +10,12 @@ import {ReIndexingSensitivity} from '../../../common/config/private/IPrivateConf
|
|||||||
export class GalleryManager implements IGalleryManager {
|
export class GalleryManager implements IGalleryManager {
|
||||||
|
|
||||||
public listDirectory(relativeDirectoryName: string, knownLastModified?: number, knownLastScanned?: number): Promise<DirectoryDTO> {
|
public listDirectory(relativeDirectoryName: string, knownLastModified?: number, knownLastScanned?: number): Promise<DirectoryDTO> {
|
||||||
//If it seems that the content did not changed, do not work on it
|
// If it seems that the content did not changed, do not work on it
|
||||||
if (knownLastModified && knownLastScanned) {
|
if (knownLastModified && knownLastScanned) {
|
||||||
const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
|
const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
|
||||||
const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime());
|
const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime());
|
||||||
if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout &&
|
if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout &&
|
||||||
lastModified == knownLastModified &&
|
lastModified === knownLastModified &&
|
||||||
Config.Server.indexing.reIndexingSensitivity < ReIndexingSensitivity.high) {
|
Config.Server.indexing.reIndexingSensitivity < ReIndexingSensitivity.high) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import {PasswordHelper} from '../PasswordHelper';
|
|||||||
|
|
||||||
export class UserManager implements IUserManager {
|
export class UserManager implements IUserManager {
|
||||||
private db: { users?: UserDTO[], idCounter?: number } = {};
|
private db: { users?: UserDTO[], idCounter?: number } = {};
|
||||||
private dbPath;
|
private readonly dbPath;
|
||||||
|
|
||||||
generateId(): string {
|
generateId(): string {
|
||||||
function s4() {
|
function s4() {
|
||||||
@ -33,7 +33,7 @@ export class UserManager implements IUserManager {
|
|||||||
|
|
||||||
if (!this.db.users) {
|
if (!this.db.users) {
|
||||||
this.db.users = [];
|
this.db.users = [];
|
||||||
//TODO: remove defaults
|
// TODO: remove defaults
|
||||||
this.createUser(<UserDTO>{name: 'admin', password: 'admin', role: UserRoles.Admin});
|
this.createUser(<UserDTO>{name: 'admin', password: 'admin', role: UserRoles.Admin});
|
||||||
}
|
}
|
||||||
this.saveDB();
|
this.saveDB();
|
||||||
@ -44,14 +44,14 @@ export class UserManager implements IUserManager {
|
|||||||
public async findOne(filter: any) {
|
public async findOne(filter: any) {
|
||||||
const result = await this.find(filter);
|
const result = await this.find(filter);
|
||||||
|
|
||||||
if (result.length == 0) {
|
if (result.length === 0) {
|
||||||
throw 'UserDTO not found';
|
throw new Error('UserDTO not found');
|
||||||
}
|
}
|
||||||
return result[0];
|
return result[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public async find(filter: any) {
|
public async find(filter: any) {
|
||||||
let pass = filter.password;
|
const pass = filter.password;
|
||||||
delete filter.password;
|
delete filter.password;
|
||||||
const users = this.db.users.slice();
|
const users = this.db.users.slice();
|
||||||
let i = users.length;
|
let i = users.length;
|
||||||
@ -60,7 +60,7 @@ export class UserManager implements IUserManager {
|
|||||||
users.splice(i, 1);
|
users.splice(i, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Utils.equalsFilter(users[i], filter) == false) {
|
if (Utils.equalsFilter(users[i], filter) === false) {
|
||||||
users.splice(i, 1);
|
users.splice(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,8 +76,8 @@ export class UserManager implements IUserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async deleteUser(id: number) {
|
public async deleteUser(id: number) {
|
||||||
let deleted = this.db.users.filter((u: UserDTO) => u.id == id);
|
const deleted = this.db.users.filter((u: UserDTO) => u.id === id);
|
||||||
this.db.users = this.db.users.filter((u: UserDTO) => u.id != id);
|
this.db.users = this.db.users.filter((u: UserDTO) => u.id !== id);
|
||||||
this.saveDB();
|
this.saveDB();
|
||||||
if (deleted.length > 0) {
|
if (deleted.length > 0) {
|
||||||
return deleted[0];
|
return deleted[0];
|
||||||
@ -87,7 +87,7 @@ export class UserManager implements IUserManager {
|
|||||||
|
|
||||||
public async changeRole(id: number, newRole: UserRoles): Promise<UserDTO> {
|
public async changeRole(id: number, newRole: UserRoles): Promise<UserDTO> {
|
||||||
for (let i = 0; i < this.db.users.length; i++) {
|
for (let i = 0; i < this.db.users.length; i++) {
|
||||||
if (this.db.users[i].id == id) {
|
if (this.db.users[i].id === id) {
|
||||||
this.db.users[i].role = newRole;
|
this.db.users[i].role = newRole;
|
||||||
this.saveDB();
|
this.saveDB();
|
||||||
return this.db.users[i];
|
return this.db.users[i];
|
||||||
@ -96,7 +96,7 @@ export class UserManager implements IUserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async changePassword(request: any) {
|
public async changePassword(request: any) {
|
||||||
throw new Error('not implemented'); //TODO: implement
|
throw new Error('not implemented'); // TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadDB() {
|
private loadDB() {
|
||||||
|
@ -24,7 +24,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
const connection = await SQLConnection.getConnection();
|
const connection = await SQLConnection.getConnection();
|
||||||
const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
|
const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
|
||||||
const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime());
|
const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime());
|
||||||
let dir = await connection
|
const dir = await connection
|
||||||
.getRepository(DirectoryEntity)
|
.getRepository(DirectoryEntity)
|
||||||
.createQueryBuilder('directory')
|
.createQueryBuilder('directory')
|
||||||
.where('directory.name = :name AND directory.path = :path', {
|
.where('directory.name = :name AND directory.path = :path', {
|
||||||
@ -37,16 +37,16 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
|
|
||||||
|
|
||||||
if (dir && dir.lastScanned != null) {
|
if (dir && dir.lastScanned != null) {
|
||||||
//If it seems that the content did not changed, do not work on it
|
// If it seems that the content did not changed, do not work on it
|
||||||
if (knownLastModified && knownLastScanned
|
if (knownLastModified && knownLastScanned
|
||||||
&& lastModified == knownLastModified &&
|
&& lastModified === knownLastModified &&
|
||||||
dir.lastScanned == knownLastScanned) {
|
dir.lastScanned === knownLastScanned) {
|
||||||
|
|
||||||
if (Config.Server.indexing.reIndexingSensitivity == ReIndexingSensitivity.low) {
|
if (Config.Server.indexing.reIndexingSensitivity === ReIndexingSensitivity.low) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout &&
|
if (Date.now() - knownLastScanned <= Config.Server.indexing.cachedFolderTimeout &&
|
||||||
Config.Server.indexing.reIndexingSensitivity == ReIndexingSensitivity.medium) {
|
Config.Server.indexing.reIndexingSensitivity === ReIndexingSensitivity.medium) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,15 +79,15 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (dir.lastModified != lastModified) {
|
if (dir.lastModified !== lastModified) {
|
||||||
return this.indexDirectory(relativeDirectoryName);
|
return this.indexDirectory(relativeDirectoryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//not indexed since a while, index it in a lazy manner
|
// not indexed since a while, index it in a lazy manner
|
||||||
if ((Date.now() - dir.lastScanned > Config.Server.indexing.cachedFolderTimeout &&
|
if ((Date.now() - dir.lastScanned > Config.Server.indexing.cachedFolderTimeout &&
|
||||||
Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.medium) ||
|
Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.medium) ||
|
||||||
Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.high) {
|
Config.Server.indexing.reIndexingSensitivity >= ReIndexingSensitivity.high) {
|
||||||
//on the fly reindexing
|
// on the fly reindexing
|
||||||
this.indexDirectory(relativeDirectoryName).catch((err) => {
|
this.indexDirectory(relativeDirectoryName).catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
@ -97,7 +97,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//never scanned (deep indexed), do it and return with it
|
// never scanned (deep indexed), do it and return with it
|
||||||
return this.indexDirectory(relativeDirectoryName);
|
return this.indexDirectory(relativeDirectoryName);
|
||||||
|
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
try {
|
try {
|
||||||
const scannedDirectory = await DiskManager.scanDirectory(relativeDirectoryName);
|
const scannedDirectory = await DiskManager.scanDirectory(relativeDirectoryName);
|
||||||
|
|
||||||
//returning with the result
|
// returning with the result
|
||||||
scannedDirectory.photos.forEach(p => p.readyThumbnails = []);
|
scannedDirectory.photos.forEach(p => p.readyThumbnails = []);
|
||||||
resolve(scannedDirectory);
|
resolve(scannedDirectory);
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
private async saveToDB(scannedDirectory: DirectoryDTO) {
|
private async saveToDB(scannedDirectory: DirectoryDTO) {
|
||||||
const connection = await SQLConnection.getConnection();
|
const connection = await SQLConnection.getConnection();
|
||||||
|
|
||||||
//saving to db
|
// saving to db
|
||||||
const directoryRepository = connection.getRepository(DirectoryEntity);
|
const directoryRepository = connection.getRepository(DirectoryEntity);
|
||||||
const photosRepository = connection.getRepository(PhotoEntity);
|
const photosRepository = connection.getRepository(PhotoEntity);
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
path: scannedDirectory.path
|
path: scannedDirectory.path
|
||||||
}).getOne();
|
}).getOne();
|
||||||
|
|
||||||
if (!!currentDir) {//Updated parent dir (if it was in the DB previously)
|
if (!!currentDir) {// Updated parent dir (if it was in the DB previously)
|
||||||
currentDir.lastModified = scannedDirectory.lastModified;
|
currentDir.lastModified = scannedDirectory.lastModified;
|
||||||
currentDir.lastScanned = scannedDirectory.lastScanned;
|
currentDir.lastScanned = scannedDirectory.lastScanned;
|
||||||
currentDir = await directoryRepository.save(currentDir);
|
currentDir = await directoryRepository.save(currentDir);
|
||||||
@ -147,31 +147,31 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
currentDir = await directoryRepository.save(<DirectoryEntity>scannedDirectory);
|
currentDir = await directoryRepository.save(<DirectoryEntity>scannedDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
let childDirectories = await directoryRepository.createQueryBuilder('directory')
|
const childDirectories = await directoryRepository.createQueryBuilder('directory')
|
||||||
.where('directory.parent = :dir', {
|
.where('directory.parent = :dir', {
|
||||||
dir: currentDir.id
|
dir: currentDir.id
|
||||||
}).getMany();
|
}).getMany();
|
||||||
|
|
||||||
for (let i = 0; i < scannedDirectory.directories.length; i++) {
|
for (let i = 0; i < scannedDirectory.directories.length; i++) {
|
||||||
//Was this child Dir already indexed before?
|
// Was this child Dir already indexed before?
|
||||||
let directory: DirectoryEntity = null;
|
let directory: DirectoryEntity = null;
|
||||||
for (let j = 0; j < childDirectories.length; j++) {
|
for (let j = 0; j < childDirectories.length; j++) {
|
||||||
if (childDirectories[j].name == scannedDirectory.directories[i].name) {
|
if (childDirectories[j].name === scannedDirectory.directories[i].name) {
|
||||||
directory = childDirectories[j];
|
directory = childDirectories[j];
|
||||||
childDirectories.splice(j, 1);
|
childDirectories.splice(j, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directory != null) { //update existing directory
|
if (directory != null) { // update existing directory
|
||||||
if (!directory.parent || !directory.parent.id) { //set parent if not set yet
|
if (!directory.parent || !directory.parent.id) { // set parent if not set yet
|
||||||
directory.parent = currentDir;
|
directory.parent = currentDir;
|
||||||
delete directory.photos;
|
delete directory.photos;
|
||||||
await directoryRepository.save(directory);
|
await directoryRepository.save(directory);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scannedDirectory.directories[i].parent = currentDir;
|
scannedDirectory.directories[i].parent = currentDir;
|
||||||
(<DirectoryEntity>scannedDirectory.directories[i]).lastScanned = null; //new child dir, not fully scanned yet
|
(<DirectoryEntity>scannedDirectory.directories[i]).lastScanned = null; // new child dir, not fully scanned yet
|
||||||
const d = await directoryRepository.save(<DirectoryEntity>scannedDirectory.directories[i]);
|
const d = await directoryRepository.save(<DirectoryEntity>scannedDirectory.directories[i]);
|
||||||
for (let j = 0; j < scannedDirectory.directories[i].photos.length; j++) {
|
for (let j = 0; j < scannedDirectory.directories[i].photos.length; j++) {
|
||||||
scannedDirectory.directories[i].photos[j].directory = d;
|
scannedDirectory.directories[i].photos[j].directory = d;
|
||||||
@ -181,21 +181,21 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove child Dirs that are not anymore in the parent dir
|
// Remove child Dirs that are not anymore in the parent dir
|
||||||
await directoryRepository.remove(childDirectories);
|
await directoryRepository.remove(childDirectories);
|
||||||
|
|
||||||
|
|
||||||
let indexedPhotos = await photosRepository.createQueryBuilder('photo')
|
const indexedPhotos = await photosRepository.createQueryBuilder('photo')
|
||||||
.where('photo.directory = :dir', {
|
.where('photo.directory = :dir', {
|
||||||
dir: currentDir.id
|
dir: currentDir.id
|
||||||
}).getMany();
|
}).getMany();
|
||||||
|
|
||||||
|
|
||||||
let photosToSave = [];
|
const photosToSave = [];
|
||||||
for (let i = 0; i < scannedDirectory.photos.length; i++) {
|
for (let i = 0; i < scannedDirectory.photos.length; i++) {
|
||||||
let photo = null;
|
let photo = null;
|
||||||
for (let j = 0; j < indexedPhotos.length; j++) {
|
for (let j = 0; j < indexedPhotos.length; j++) {
|
||||||
if (indexedPhotos[j].name == scannedDirectory.photos[i].name) {
|
if (indexedPhotos[j].name === scannedDirectory.photos[i].name) {
|
||||||
photo = indexedPhotos[j];
|
photo = indexedPhotos[j];
|
||||||
indexedPhotos.splice(j, 1);
|
indexedPhotos.splice(j, 1);
|
||||||
break;
|
break;
|
||||||
@ -208,10 +208,10 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
|||||||
photo.directory = currentDir;
|
photo.directory = currentDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (photo.metadata.keywords != scannedDirectory.photos[i].metadata.keywords ||
|
if (photo.metadata.keywords !== scannedDirectory.photos[i].metadata.keywords ||
|
||||||
photo.metadata.cameraData != scannedDirectory.photos[i].metadata.cameraData ||
|
photo.metadata.cameraData !== scannedDirectory.photos[i].metadata.cameraData ||
|
||||||
photo.metadata.positionData != scannedDirectory.photos[i].metadata.positionData ||
|
photo.metadata.positionData !== scannedDirectory.photos[i].metadata.positionData ||
|
||||||
photo.metadata.size != scannedDirectory.photos[i].metadata.size) {
|
photo.metadata.size !== scannedDirectory.photos[i].metadata.size) {
|
||||||
|
|
||||||
photo.metadata.keywords = scannedDirectory.photos[i].metadata.keywords;
|
photo.metadata.keywords = scannedDirectory.photos[i].metadata.keywords;
|
||||||
photo.metadata.cameraData = scannedDirectory.photos[i].metadata.cameraData;
|
photo.metadata.cameraData = scannedDirectory.photos[i].metadata.cameraData;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
import {DirectoryDTO} from '../../../common/entities/DirectoryDTO';
|
||||||
|
|
||||||
export interface ISQLGalleryManager {
|
export interface ISQLGalleryManager {
|
||||||
listDirectory(relativeDirectoryName: string,
|
listDirectory(relativeDirectoryName: string,
|
||||||
|
@ -14,7 +14,7 @@ export class IndexingManager implements IIndexingManager {
|
|||||||
indexingProgress = null;
|
indexingProgress = null;
|
||||||
enabled = false;
|
enabled = false;
|
||||||
private indexNewDirectory = async () => {
|
private indexNewDirectory = async () => {
|
||||||
if (this.directoriesToIndex.length == 0) {
|
if (this.directoriesToIndex.length === 0) {
|
||||||
this.indexingProgress = null;
|
this.indexingProgress = null;
|
||||||
if (global.gc) {
|
if (global.gc) {
|
||||||
global.gc();
|
global.gc();
|
||||||
@ -25,7 +25,7 @@ export class IndexingManager implements IIndexingManager {
|
|||||||
this.indexingProgress.current = directory;
|
this.indexingProgress.current = directory;
|
||||||
this.indexingProgress.left = this.directoriesToIndex.length;
|
this.indexingProgress.left = this.directoriesToIndex.length;
|
||||||
const scanned = await (<ISQLGalleryManager>ObjectManagerRepository.getInstance().GalleryManager).indexDirectory(directory);
|
const scanned = await (<ISQLGalleryManager>ObjectManagerRepository.getInstance().GalleryManager).indexDirectory(directory);
|
||||||
if (this.enabled == false) {
|
if (this.enabled === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.indexingProgress.indexed++;
|
this.indexingProgress.indexed++;
|
||||||
@ -36,7 +36,7 @@ export class IndexingManager implements IIndexingManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
startIndexing(): void {
|
startIndexing(): void {
|
||||||
if (this.directoriesToIndex.length == 0 && this.enabled == false) {
|
if (this.directoriesToIndex.length === 0 && this.enabled === false) {
|
||||||
Logger.info(LOG_TAG, 'Starting indexing');
|
Logger.info(LOG_TAG, 'Starting indexing');
|
||||||
this.indexingProgress = <IndexingProgressDTO>{
|
this.indexingProgress = <IndexingProgressDTO>{
|
||||||
indexed: 0,
|
indexed: 0,
|
||||||
|
@ -15,7 +15,7 @@ import {Logger} from '../../Logger';
|
|||||||
|
|
||||||
export class SQLConnection {
|
export class SQLConnection {
|
||||||
|
|
||||||
private static VERSION: number = 1;
|
private static VERSION = 1;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ export class SQLConnection {
|
|||||||
|
|
||||||
if (this.connection == null) {
|
if (this.connection == null) {
|
||||||
|
|
||||||
let options: any = this.getDriver(Config.Server.database);
|
const options: any = this.getDriver(Config.Server.database);
|
||||||
options.name = 'main';
|
options.name = 'main';
|
||||||
options.entities = [
|
options.entities = [
|
||||||
UserEntity,
|
UserEntity,
|
||||||
@ -68,10 +68,10 @@ export class SQLConnection {
|
|||||||
|
|
||||||
public static async init(): Promise<void> {
|
public static async init(): Promise<void> {
|
||||||
const connection = await this.getConnection();
|
const connection = await this.getConnection();
|
||||||
let userRepository = connection.getRepository(UserEntity);
|
const userRepository = connection.getRepository(UserEntity);
|
||||||
let admins = await userRepository.find({role: UserRoles.Admin});
|
const admins = await userRepository.find({role: UserRoles.Admin});
|
||||||
if (admins.length == 0) {
|
if (admins.length === 0) {
|
||||||
let a = new UserEntity();
|
const a = new UserEntity();
|
||||||
a.name = 'admin';
|
a.name = 'admin';
|
||||||
a.password = PasswordHelper.cryptPassword('admin');
|
a.password = PasswordHelper.cryptPassword('admin');
|
||||||
a.role = UserRoles.Admin;
|
a.role = UserRoles.Admin;
|
||||||
@ -86,7 +86,7 @@ export class SQLConnection {
|
|||||||
version = await connection.getRepository(VersionEntity).findOne();
|
version = await connection.getRepository(VersionEntity).findOne();
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
}
|
}
|
||||||
if (version && version.version == SQLConnection.VERSION) {
|
if (version && version.version === SQLConnection.VERSION) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger.info('Updating database scheme');
|
Logger.info('Updating database scheme');
|
||||||
@ -103,7 +103,7 @@ export class SQLConnection {
|
|||||||
|
|
||||||
private static getDriver(config: DataBaseConfig): ConnectionOptions {
|
private static getDriver(config: DataBaseConfig): ConnectionOptions {
|
||||||
let driver: ConnectionOptions = null;
|
let driver: ConnectionOptions = null;
|
||||||
if (config.type == DatabaseType.mysql) {
|
if (config.type === DatabaseType.mysql) {
|
||||||
driver = {
|
driver = {
|
||||||
type: 'mysql',
|
type: 'mysql',
|
||||||
host: config.mysql.host,
|
host: config.mysql.host,
|
||||||
@ -112,7 +112,7 @@ export class SQLConnection {
|
|||||||
password: config.mysql.password,
|
password: config.mysql.password,
|
||||||
database: config.mysql.database
|
database: config.mysql.database
|
||||||
};
|
};
|
||||||
} else if (config.type == DatabaseType.sqlite) {
|
} else if (config.type === DatabaseType.sqlite) {
|
||||||
driver = {
|
driver = {
|
||||||
type: 'sqlite',
|
type: 'sqlite',
|
||||||
database: ProjectPath.getAbsolutePath(config.sqlite.storage)
|
database: ProjectPath.getAbsolutePath(config.sqlite.storage)
|
||||||
|
@ -8,11 +8,12 @@ import {DirectoryEntity} from './enitites/DirectoryEntity';
|
|||||||
export class SearchManager implements ISearchManager {
|
export class SearchManager implements ISearchManager {
|
||||||
|
|
||||||
private static autoCompleteItemsUnique(array: Array<AutoCompleteItem>): Array<AutoCompleteItem> {
|
private static autoCompleteItemsUnique(array: Array<AutoCompleteItem>): Array<AutoCompleteItem> {
|
||||||
let a = array.concat();
|
const a = array.concat();
|
||||||
for (let i = 0; i < a.length; ++i) {
|
for (let i = 0; i < a.length; ++i) {
|
||||||
for (let j = i + 1; j < a.length; ++j) {
|
for (let j = i + 1; j < a.length; ++j) {
|
||||||
if (a[i].equals(a[j]))
|
if (a[i].equals(a[j])) {
|
||||||
a.splice(j--, 1);
|
a.splice(j--, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,8 +25,8 @@ export class SearchManager implements ISearchManager {
|
|||||||
const connection = await SQLConnection.getConnection();
|
const connection = await SQLConnection.getConnection();
|
||||||
|
|
||||||
let result: Array<AutoCompleteItem> = [];
|
let result: Array<AutoCompleteItem> = [];
|
||||||
let photoRepository = connection.getRepository(PhotoEntity);
|
const photoRepository = connection.getRepository(PhotoEntity);
|
||||||
let directoryRepository = connection.getRepository(DirectoryEntity);
|
const directoryRepository = connection.getRepository(DirectoryEntity);
|
||||||
|
|
||||||
|
|
||||||
(await photoRepository
|
(await photoRepository
|
||||||
@ -36,13 +37,15 @@ export class SearchManager implements ISearchManager {
|
|||||||
.getRawMany())
|
.getRawMany())
|
||||||
.map(r => <Array<string>>r.metadataKeywords.split(','))
|
.map(r => <Array<string>>r.metadataKeywords.split(','))
|
||||||
.forEach(keywords => {
|
.forEach(keywords => {
|
||||||
result = result.concat(this.encapsulateAutoComplete(keywords.filter(k => k.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.keyword));
|
result = result.concat(this.encapsulateAutoComplete(keywords
|
||||||
|
.filter(k => k.toLowerCase().indexOf(text.toLowerCase()) !== -1), SearchTypes.keyword));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
(await photoRepository
|
(await photoRepository
|
||||||
.createQueryBuilder('photo')
|
.createQueryBuilder('photo')
|
||||||
.select('photo.metadata.positionData.country as country, photo.metadata.positionData.state as state, photo.metadata.positionData.city as city')
|
.select('photo.metadata.positionData.country as country,' +
|
||||||
|
' photo.metadata.positionData.state as state, photo.metadata.positionData.city as city')
|
||||||
.where('photo.metadata.positionData.country LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
.where('photo.metadata.positionData.country LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
||||||
.orWhere('photo.metadata.positionData.state LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
.orWhere('photo.metadata.positionData.state LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
||||||
.orWhere('photo.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
.orWhere('photo.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
|
||||||
@ -52,7 +55,8 @@ export class SearchManager implements ISearchManager {
|
|||||||
.filter(pm => !!pm)
|
.filter(pm => !!pm)
|
||||||
.map(pm => <Array<string>>[pm.city || '', pm.country || '', pm.state || ''])
|
.map(pm => <Array<string>>[pm.city || '', pm.country || '', pm.state || ''])
|
||||||
.forEach(positions => {
|
.forEach(positions => {
|
||||||
result = result.concat(this.encapsulateAutoComplete(positions.filter(p => p.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.position));
|
result = result.concat(this.encapsulateAutoComplete(positions
|
||||||
|
.filter(p => p.toLowerCase().indexOf(text.toLowerCase()) !== -1), SearchTypes.position));
|
||||||
});
|
});
|
||||||
|
|
||||||
result = result.concat(this.encapsulateAutoComplete((await photoRepository
|
result = result.concat(this.encapsulateAutoComplete((await photoRepository
|
||||||
@ -86,7 +90,7 @@ export class SearchManager implements ISearchManager {
|
|||||||
resultOverflow: false
|
resultOverflow: false
|
||||||
};
|
};
|
||||||
|
|
||||||
let query = connection
|
const query = connection
|
||||||
.getRepository(PhotoEntity)
|
.getRepository(PhotoEntity)
|
||||||
.createQueryBuilder('photo')
|
.createQueryBuilder('photo')
|
||||||
.innerJoinAndSelect('photo.directory', 'directory')
|
.innerJoinAndSelect('photo.directory', 'directory')
|
||||||
@ -136,9 +140,9 @@ export class SearchManager implements ISearchManager {
|
|||||||
async instantSearch(text: string): Promise<SearchResultDTO> {
|
async instantSearch(text: string): Promise<SearchResultDTO> {
|
||||||
const connection = await SQLConnection.getConnection();
|
const connection = await SQLConnection.getConnection();
|
||||||
|
|
||||||
let result: SearchResultDTO = <SearchResultDTO>{
|
const result: SearchResultDTO = <SearchResultDTO>{
|
||||||
searchText: text,
|
searchText: text,
|
||||||
//searchType:undefined, not adding this
|
// searchType:undefined, not adding this
|
||||||
directories: [],
|
directories: [],
|
||||||
photos: [],
|
photos: [],
|
||||||
resultOverflow: false
|
resultOverflow: false
|
||||||
@ -169,7 +173,7 @@ export class SearchManager implements ISearchManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private encapsulateAutoComplete(values: Array<string>, type: SearchTypes): Array<AutoCompleteItem> {
|
private encapsulateAutoComplete(values: Array<string>, type: SearchTypes): Array<AutoCompleteItem> {
|
||||||
let res = [];
|
const res = [];
|
||||||
values.forEach((value) => {
|
values.forEach((value) => {
|
||||||
res.push(new AutoCompleteItem(value, type));
|
res.push(new AutoCompleteItem(value, type));
|
||||||
});
|
});
|
||||||
|
@ -42,7 +42,7 @@ export class SharingManager implements ISharingManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (sharing.timeStamp < Date.now() - Config.Server.sharing.updateTimeout) {
|
if (sharing.timeStamp < Date.now() - Config.Server.sharing.updateTimeout) {
|
||||||
throw 'Sharing is locked, can\'t update anymore';
|
throw new Error('Sharing is locked, can\'t update anymore');
|
||||||
}
|
}
|
||||||
if (inSharing.password == null) {
|
if (inSharing.password == null) {
|
||||||
sharing.password = null;
|
sharing.password = null;
|
||||||
|
@ -13,7 +13,7 @@ export class UserManager implements IUserManager {
|
|||||||
|
|
||||||
public async findOne(filter: any) {
|
public async findOne(filter: any) {
|
||||||
const connection = await SQLConnection.getConnection();
|
const connection = await SQLConnection.getConnection();
|
||||||
let pass = filter.password;
|
const pass = filter.password;
|
||||||
delete filter.password;
|
delete filter.password;
|
||||||
const user = (await connection.getRepository(UserEntity).findOne(filter));
|
const user = (await connection.getRepository(UserEntity).findOne(filter));
|
||||||
|
|
||||||
@ -22,11 +22,11 @@ export class UserManager implements IUserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pass && !PasswordHelper.comparePassword(pass, user.password)) {
|
if (pass && !PasswordHelper.comparePassword(pass, user.password)) {
|
||||||
throw 'No entry found';
|
throw new Error('No entry found');
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
public async find(filter: any) {
|
public async find(filter: any) {
|
||||||
const connection = await SQLConnection.getConnection();
|
const connection = await SQLConnection.getConnection();
|
||||||
@ -56,7 +56,7 @@ export class UserManager implements IUserManager {
|
|||||||
public async changeRole(id: number, newRole: UserRoles) {
|
public async changeRole(id: number, newRole: UserRoles) {
|
||||||
|
|
||||||
const connection = await SQLConnection.getConnection();
|
const connection = await SQLConnection.getConnection();
|
||||||
let userRepository = connection.getRepository(UserEntity);
|
const userRepository = connection.getRepository(UserEntity);
|
||||||
const user = await userRepository.findOne({id: id});
|
const user = await userRepository.findOne({id: id});
|
||||||
user.role = newRole;
|
user.role = newRole;
|
||||||
return await userRepository.save(user);
|
return await userRepository.save(user);
|
||||||
@ -64,7 +64,7 @@ export class UserManager implements IUserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async changePassword(request: any) {
|
public async changePassword(request: any) {
|
||||||
throw new Error('not implemented'); //TODO: implement
|
throw new Error('not implemented'); // TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,6 @@ export class PhotoEntity implements PhotoDTO {
|
|||||||
|
|
||||||
readyThumbnails: Array<number> = [];
|
readyThumbnails: Array<number> = [];
|
||||||
|
|
||||||
readyIcon: boolean = false;
|
readyIcon = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,11 @@ export class DiskMangerWorker {
|
|||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
const file = list[i];
|
const file = list[i];
|
||||||
const fullFilePath = path.normalize(path.resolve(absoluteDirectoryName, file));
|
const fullFilePath = path.normalize(path.resolve(absoluteDirectoryName, file));
|
||||||
if (photosOnly == false && fs.statSync(fullFilePath).isDirectory()) {
|
if (photosOnly === false && fs.statSync(fullFilePath).isDirectory()) {
|
||||||
const d = await DiskMangerWorker.scanDirectory(path.join(relativeDirectoryName, file),
|
const d = await DiskMangerWorker.scanDirectory(path.join(relativeDirectoryName, file),
|
||||||
Config.Server.indexing.folderPreviewSize, true
|
Config.Server.indexing.folderPreviewSize, true
|
||||||
);
|
);
|
||||||
d.lastScanned = 0; //it was not a fully scan
|
d.lastScanned = 0; // it was not a fully scan
|
||||||
d.isPartial = true;
|
d.isPartial = true;
|
||||||
directory.directories.push(d);
|
directory.directories.push(d);
|
||||||
} else if (DiskMangerWorker.isImage(fullFilePath)) {
|
} else if (DiskMangerWorker.isImage(fullFilePath)) {
|
||||||
|
@ -15,9 +15,9 @@ export interface ITaskQue {
|
|||||||
export class TaskQue implements ITaskQue {
|
export class TaskQue implements ITaskQue {
|
||||||
|
|
||||||
private tasks: QueTask[] = [];
|
private tasks: QueTask[] = [];
|
||||||
private taskInProgress: number = 0;
|
private taskInProgress = 0;
|
||||||
private run = async () => {
|
private run = async () => {
|
||||||
if (this.tasks.length == 0 || this.taskInProgress >= this.size) {
|
if (this.tasks.length === 0 || this.taskInProgress >= this.size) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.taskInProgress++;
|
this.taskInProgress++;
|
||||||
|
@ -30,33 +30,19 @@ export class ThreadPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private startWorker() {
|
private run = () => {
|
||||||
const worker = <WorkerWrapper>{poolTask: null, worker: cluster.fork()};
|
if (this.tasks.length === 0) {
|
||||||
this.workers.push(worker);
|
return;
|
||||||
worker.worker.on('online', () => {
|
}
|
||||||
ThreadPool.WorkerCount++;
|
const worker = this.getFreeWorker();
|
||||||
Logger.debug('Worker ' + worker.worker.process.pid + ' is online, worker count:', ThreadPool.WorkerCount);
|
if (worker == null) {
|
||||||
});
|
return;
|
||||||
worker.worker.on('exit', (code, signal) => {
|
}
|
||||||
ThreadPool.WorkerCount--;
|
|
||||||
Logger.warn('Worker ' + worker.worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal + ', worker count:', ThreadPool.WorkerCount);
|
|
||||||
Logger.debug('Starting a new worker');
|
|
||||||
this.startWorker();
|
|
||||||
});
|
|
||||||
|
|
||||||
worker.worker.on('message', (msg: WorkerMessage) => {
|
const poolTask = this.tasks.shift();
|
||||||
if (worker.poolTask == null) {
|
worker.poolTask = poolTask;
|
||||||
throw 'No worker task after worker task is completed';
|
worker.worker.send(poolTask.task);
|
||||||
}
|
};
|
||||||
if (msg.error) {
|
|
||||||
worker.poolTask.promise.reject(msg.error);
|
|
||||||
} else {
|
|
||||||
worker.poolTask.promise.resolve(msg.result);
|
|
||||||
}
|
|
||||||
worker.poolTask = null;
|
|
||||||
this.run();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected executeTask<T>(task: WorkerTask): Promise<T> {
|
protected executeTask<T>(task: WorkerTask): Promise<T> {
|
||||||
return new Promise((resolve: Function, reject: Function) => {
|
return new Promise((resolve: Function, reject: Function) => {
|
||||||
@ -74,19 +60,34 @@ export class ThreadPool {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private run = () => {
|
private startWorker() {
|
||||||
if (this.tasks.length == 0) {
|
const worker = <WorkerWrapper>{poolTask: null, worker: cluster.fork()};
|
||||||
return;
|
this.workers.push(worker);
|
||||||
}
|
worker.worker.on('online', () => {
|
||||||
const worker = this.getFreeWorker();
|
ThreadPool.WorkerCount++;
|
||||||
if (worker == null) {
|
Logger.debug('Worker ' + worker.worker.process.pid + ' is online, worker count:', ThreadPool.WorkerCount);
|
||||||
return;
|
});
|
||||||
}
|
worker.worker.on('exit', (code, signal) => {
|
||||||
|
ThreadPool.WorkerCount--;
|
||||||
|
Logger.warn('Worker ' + worker.worker.process.pid + ' died with code: ' + code +
|
||||||
|
', and signal: ' + signal + ', worker count:', ThreadPool.WorkerCount);
|
||||||
|
Logger.debug('Starting a new worker');
|
||||||
|
this.startWorker();
|
||||||
|
});
|
||||||
|
|
||||||
const poolTask = this.tasks.shift();
|
worker.worker.on('message', (msg: WorkerMessage) => {
|
||||||
worker.poolTask = poolTask;
|
if (worker.poolTask == null) {
|
||||||
worker.worker.send(poolTask.task);
|
throw new Error('No worker task after worker task is completed');
|
||||||
};
|
}
|
||||||
|
if (msg.error) {
|
||||||
|
worker.poolTask.promise.reject(msg.error);
|
||||||
|
} else {
|
||||||
|
worker.poolTask.promise.resolve(msg.result);
|
||||||
|
}
|
||||||
|
worker.poolTask = null;
|
||||||
|
this.run();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ export class ThumbnailWoker {
|
|||||||
private static rendererType = null;
|
private static rendererType = null;
|
||||||
|
|
||||||
public static render(input: RendererInput, renderer: ThumbnailProcessingLib): Promise<void> {
|
public static render(input: RendererInput, renderer: ThumbnailProcessingLib): Promise<void> {
|
||||||
if (ThumbnailWoker.rendererType != renderer) {
|
if (ThumbnailWoker.rendererType !== renderer) {
|
||||||
ThumbnailWoker.renderer = RendererFactory.build(renderer);
|
ThumbnailWoker.renderer = RendererFactory.build(renderer);
|
||||||
ThumbnailWoker.rendererType = renderer;
|
ThumbnailWoker.rendererType = renderer;
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ export interface RendererInput {
|
|||||||
size: number;
|
size: number;
|
||||||
makeSquare: boolean;
|
makeSquare: boolean;
|
||||||
thPath: string;
|
thPath: string;
|
||||||
qualityPriority: boolean
|
qualityPriority: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RendererFactory {
|
export class RendererFactory {
|
||||||
@ -39,13 +39,13 @@ export class RendererFactory {
|
|||||||
case ThumbnailProcessingLib.sharp:
|
case ThumbnailProcessingLib.sharp:
|
||||||
return RendererFactory.Sharp();
|
return RendererFactory.Sharp();
|
||||||
}
|
}
|
||||||
throw 'unknown renderer';
|
throw new Error('unknown renderer');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Jimp() {
|
public static Jimp() {
|
||||||
const Jimp = require('jimp');
|
const Jimp = require('jimp');
|
||||||
return async (input: RendererInput): Promise<void> => {
|
return async (input: RendererInput): Promise<void> => {
|
||||||
//generate thumbnail
|
// generate thumbnail
|
||||||
Logger.silly('[JimpThRenderer] rendering thumbnail:', input.imagePath);
|
Logger.silly('[JimpThRenderer] rendering thumbnail:', input.imagePath);
|
||||||
const image = await Jimp.read(input.imagePath);
|
const image = await Jimp.read(input.imagePath);
|
||||||
/**
|
/**
|
||||||
@ -58,9 +58,9 @@ export class RendererFactory {
|
|||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
const ratio = image.bitmap.height / image.bitmap.width;
|
const ratio = image.bitmap.height / image.bitmap.width;
|
||||||
const algo = input.qualityPriority == true ? Jimp.RESIZE_BEZIER : Jimp.RESIZE_NEAREST_NEIGHBOR;
|
const algo = input.qualityPriority === true ? Jimp.RESIZE_BEZIER : Jimp.RESIZE_NEAREST_NEIGHBOR;
|
||||||
if (input.makeSquare == false) {
|
if (input.makeSquare === false) {
|
||||||
let newWidth = Math.sqrt((input.size * input.size) / ratio);
|
const newWidth = Math.sqrt((input.size * input.size) / ratio);
|
||||||
|
|
||||||
image.resize(newWidth, Jimp.AUTO, algo);
|
image.resize(newWidth, Jimp.AUTO, algo);
|
||||||
} else {
|
} else {
|
||||||
@ -100,8 +100,8 @@ export class RendererFactory {
|
|||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
const ratio = metadata.height / metadata.width;
|
const ratio = metadata.height / metadata.width;
|
||||||
const kernel = input.qualityPriority == true ? sharp.kernel.lanczos3 : sharp.kernel.nearest;
|
const kernel = input.qualityPriority === true ? sharp.kernel.lanczos3 : sharp.kernel.nearest;
|
||||||
if (input.makeSquare == false) {
|
if (input.makeSquare === false) {
|
||||||
const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio));
|
const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio));
|
||||||
image.resize(newWidth, null, {
|
image.resize(newWidth, null, {
|
||||||
kernel: kernel
|
kernel: kernel
|
||||||
@ -141,19 +141,19 @@ export class RendererFactory {
|
|||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
const ratio = value.height / value.width;
|
const ratio = value.height / value.width;
|
||||||
const filter = input.qualityPriority == true ? 'Lanczos' : 'Point';
|
const filter = input.qualityPriority === true ? 'Lanczos' : 'Point';
|
||||||
image.filter(filter);
|
image.filter(filter);
|
||||||
|
|
||||||
if (input.makeSquare == false) {
|
if (input.makeSquare === false) {
|
||||||
const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio));
|
const newWidth = Math.round(Math.sqrt((input.size * input.size) / ratio));
|
||||||
image = image.resize(newWidth);
|
image = image.resize(newWidth);
|
||||||
} else {
|
} else {
|
||||||
image = image.resize(input.size, input.size)
|
image = image.resize(input.size, input.size)
|
||||||
.crop(input.size, input.size);
|
.crop(input.size, input.size);
|
||||||
}
|
}
|
||||||
image.write(input.thPath, (err) => {
|
image.write(input.thPath, (e) => {
|
||||||
if (err) {
|
if (e) {
|
||||||
return reject(err);
|
return reject(e);
|
||||||
}
|
}
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
|
@ -23,7 +23,7 @@ export class Worker {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Logger.error('Unknown worker task type');
|
Logger.error('Unknown worker task type');
|
||||||
throw 'Unknown worker task type';
|
throw new Error('Unknown worker task type');
|
||||||
}
|
}
|
||||||
process.send(<WorkerMessage>{
|
process.send(<WorkerMessage>{
|
||||||
error: null,
|
error: null,
|
||||||
@ -32,7 +32,6 @@ export class Worker {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
process.send({error: err, result: null});
|
process.send({error: err, result: null});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import {NextFunction, Request, Response} from 'express';
|
import {NextFunction, Request, Response} from 'express';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
import * as ejs from 'ejs';
|
||||||
import {Utils} from '../../common/Utils';
|
import {Utils} from '../../common/Utils';
|
||||||
import {Config} from '../../common/config/private/Config';
|
import {Config} from '../../common/config/private/Config';
|
||||||
import {ProjectPath} from '../ProjectPath';
|
import {ProjectPath} from '../ProjectPath';
|
||||||
import {AuthenticationMWs} from '../middlewares/user/AuthenticationMWs';
|
import {AuthenticationMWs} from '../middlewares/user/AuthenticationMWs';
|
||||||
import {CookieNames} from '../../common/CookieNames';
|
import {CookieNames} from '../../common/CookieNames';
|
||||||
|
import {ErrorDTO} from '../../common/entities/Error';
|
||||||
|
|
||||||
|
|
||||||
export class PublicRouter {
|
export class PublicRouter {
|
||||||
|
|
||||||
|
|
||||||
public static route(app) {
|
public static route(app) {
|
||||||
const setLocale = (req: Request, res: Response, next: Function) => {
|
const setLocale = (req: Request, res: Response, next: Function) => {
|
||||||
let localePath = '';
|
let localePath = '';
|
||||||
@ -27,8 +30,14 @@ export class PublicRouter {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderIndex = (req: Request, res: Response) => {
|
const renderIndex = (req: Request, res: Response, next: Function) => {
|
||||||
res.sendFile(path.resolve(ProjectPath.FrontendFolder, req['localePath'], 'index.html'), {maxAge: 31536000});
|
ejs.renderFile(path.resolve(ProjectPath.FrontendFolder, req['localePath'], 'index.html'),
|
||||||
|
res.tpl, (err, str) => {
|
||||||
|
if (err) {
|
||||||
|
return next(new ErrorDTO(err));
|
||||||
|
}
|
||||||
|
res.send(str);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -56,9 +65,6 @@ export class PublicRouter {
|
|||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/config_inject.js', (req: Request, res: Response) => {
|
|
||||||
res.render(path.resolve(ProjectPath.FrontendFolder, 'config_inject.ejs'), res.tpl);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get(['/', '/login', '/gallery*', '/share*', '/admin', '/search*'],
|
app.get(['/', '/login', '/gallery*', '/share*', '/admin', '/search*'],
|
||||||
AuthenticationMWs.tryAuthenticate,
|
AuthenticationMWs.tryAuthenticate,
|
||||||
|
@ -18,7 +18,7 @@ export class SharingRouter {
|
|||||||
AuthenticationMWs.shareLogin,
|
AuthenticationMWs.shareLogin,
|
||||||
RenderingMWs.renderSessionUser
|
RenderingMWs.renderSessionUser
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
private static addGetSharing(app) {
|
private static addGetSharing(app) {
|
||||||
app.get('/api/share/:sharingKey',
|
app.get('/api/share/:sharingKey',
|
||||||
@ -27,7 +27,7 @@ export class SharingRouter {
|
|||||||
SharingMWs.getSharing,
|
SharingMWs.getSharing,
|
||||||
RenderingMWs.renderSharing
|
RenderingMWs.renderSharing
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
private static addCreateSharing(app) {
|
private static addCreateSharing(app) {
|
||||||
app.post(['/api/share/:directory(*)', '/api/share/', '/api/share//'],
|
app.post(['/api/share/:directory(*)', '/api/share/', '/api/share//'],
|
||||||
@ -36,7 +36,7 @@ export class SharingRouter {
|
|||||||
SharingMWs.createSharing,
|
SharingMWs.createSharing,
|
||||||
RenderingMWs.renderSharing
|
RenderingMWs.renderSharing
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
private static addUpdateSharing(app) {
|
private static addUpdateSharing(app) {
|
||||||
app.put(['/api/share/:directory(*)', '/api/share/', '/api/share//'],
|
app.put(['/api/share/:directory(*)', '/api/share/', '/api/share//'],
|
||||||
@ -45,7 +45,6 @@ export class SharingRouter {
|
|||||||
SharingMWs.updateSharing,
|
SharingMWs.updateSharing,
|
||||||
RenderingMWs.renderSharing
|
RenderingMWs.renderSharing
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,44 @@ export class Server {
|
|||||||
private app: any;
|
private app: any;
|
||||||
private server: any;
|
private server: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "error" event.
|
||||||
|
*/
|
||||||
|
private onError = (error: any) => {
|
||||||
|
if (error.syscall !== 'listen') {
|
||||||
|
Logger.error(LOG_TAG, 'Server error', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bind = 'Port ' + Config.Server.port;
|
||||||
|
|
||||||
|
// handle specific listen error with friendly messages
|
||||||
|
switch (error.code) {
|
||||||
|
case 'EACCES':
|
||||||
|
Logger.error(LOG_TAG, bind + ' requires elevated privileges');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
case 'EADDRINUSE':
|
||||||
|
Logger.error(LOG_TAG, bind + ' is already in use');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "listening" event.
|
||||||
|
*/
|
||||||
|
private onListening = () => {
|
||||||
|
const addr = this.server.address();
|
||||||
|
const bind = typeof addr === 'string'
|
||||||
|
? 'pipe ' + addr
|
||||||
|
: 'port ' + addr.port;
|
||||||
|
Logger.info(LOG_TAG, 'Listening on ' + bind);
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (!(process.env.NODE_ENV == 'production')) {
|
if (!(process.env.NODE_ENV === 'production')) {
|
||||||
Logger.debug(LOG_TAG, 'Running in DEBUG mode');
|
Logger.debug(LOG_TAG, 'Running in DEBUG mode');
|
||||||
}
|
}
|
||||||
this.init();
|
this.init();
|
||||||
@ -82,7 +118,7 @@ export class Server {
|
|||||||
Localizations.init();
|
Localizations.init();
|
||||||
|
|
||||||
this.app.use(locale(Config.Client.languages, 'en'));
|
this.app.use(locale(Config.Client.languages, 'en'));
|
||||||
if (Config.Server.database.type != DatabaseType.memory) {
|
if (Config.Server.database.type !== DatabaseType.memory) {
|
||||||
await ObjectManagerRepository.InitSQLManagers();
|
await ObjectManagerRepository.InitSQLManagers();
|
||||||
} else {
|
} else {
|
||||||
await ObjectManagerRepository.InitMemoryManagers();
|
await ObjectManagerRepository.InitMemoryManagers();
|
||||||
@ -105,7 +141,7 @@ export class Server {
|
|||||||
// Create HTTP server.
|
// Create HTTP server.
|
||||||
this.server = _http.createServer(this.app);
|
this.server = _http.createServer(this.app);
|
||||||
|
|
||||||
//Listen on provided PORT, on all network interfaces.
|
// Listen on provided PORT, on all network interfaces.
|
||||||
this.server.listen(Config.Server.port);
|
this.server.listen(Config.Server.port);
|
||||||
this.server.on('error', this.onError);
|
this.server.on('error', this.onError);
|
||||||
this.server.on('listening', this.onListening);
|
this.server.on('listening', this.onListening);
|
||||||
@ -113,47 +149,6 @@ export class Server {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event listener for HTTP server "error" event.
|
|
||||||
*/
|
|
||||||
private onError = (error: any) => {
|
|
||||||
if (error.syscall !== 'listen') {
|
|
||||||
Logger.error(LOG_TAG, 'Server error', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bind = typeof Config.Server.port === 'string'
|
|
||||||
? 'Pipe ' + Config.Server.port
|
|
||||||
: 'Port ' + Config.Server.port;
|
|
||||||
|
|
||||||
// handle specific listen error with friendly messages
|
|
||||||
switch (error.code) {
|
|
||||||
case 'EACCES':
|
|
||||||
Logger.error(LOG_TAG, bind + ' requires elevated privileges');
|
|
||||||
process.exit(1);
|
|
||||||
break;
|
|
||||||
case 'EADDRINUSE':
|
|
||||||
Logger.error(LOG_TAG, bind + ' is already in use');
|
|
||||||
process.exit(1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event listener for HTTP server "listening" event.
|
|
||||||
*/
|
|
||||||
private onListening = () => {
|
|
||||||
let addr = this.server.address();
|
|
||||||
const bind = typeof addr === 'string'
|
|
||||||
? 'pipe ' + addr
|
|
||||||
: 'port ' + addr.port;
|
|
||||||
Logger.info(LOG_TAG, 'Listening on ' + bind);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export class CookieNames {
|
export class CookieNames {
|
||||||
public static lang = "pigallery2-lang";
|
public static lang = 'pigallery2-lang';
|
||||||
public static session = "pigallery2-session";
|
public static session = 'pigallery2-session';
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,14 @@ export class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static equalsFilter(object: any, filter: any): boolean {
|
static equalsFilter(object: any, filter: any): boolean {
|
||||||
if (typeof filter !== "object" || filter == null) {
|
if (typeof filter !== 'object' || filter == null) {
|
||||||
return object == filter;
|
return object === filter;
|
||||||
}
|
}
|
||||||
const keys = Object.keys(filter);
|
const keys = Object.keys(filter);
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
if (typeof filter[key] === "object") {
|
if (typeof filter[key] === 'object') {
|
||||||
if (Utils.equalsFilter(object[key], filter[key]) == false) {
|
if (Utils.equalsFilter(object[key], filter[key]) === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (object[key] !== filter[key]) {
|
} else if (object[key] !== filter[key]) {
|
||||||
@ -27,19 +27,23 @@ export class Utils {
|
|||||||
|
|
||||||
|
|
||||||
static concatUrls(...args: Array<string>) {
|
static concatUrls(...args: Array<string>) {
|
||||||
let url = "";
|
let url = '';
|
||||||
for (let i = 0; i < args.length; i++) {
|
for (let i = 0; i < args.length; i++) {
|
||||||
if (args[i] === "" || typeof args[i] === "undefined") continue;
|
if (args[i] === '' || typeof args[i] === 'undefined') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let part = args[i].replace("\\", "/");
|
const part = args[i].replace('\\', '/');
|
||||||
if (part === "/" || part === "./") continue;
|
if (part === '/' || part === './') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
url += part + "/";
|
url += part + '/';
|
||||||
}
|
}
|
||||||
url = url.replace("//", "/");
|
url = url.replace('//', '/');
|
||||||
|
|
||||||
if (url.trim() == "") {
|
if (url.trim() === '') {
|
||||||
url = "./";
|
url = './';
|
||||||
}
|
}
|
||||||
|
|
||||||
return url.substring(0, url.length - 1);
|
return url.substring(0, url.length - 1);
|
||||||
@ -47,10 +51,10 @@ export class Utils {
|
|||||||
|
|
||||||
public static updateKeys(targetObject: any, sourceObject: any) {
|
public static updateKeys(targetObject: any, sourceObject: any) {
|
||||||
Object.keys(sourceObject).forEach((key) => {
|
Object.keys(sourceObject).forEach((key) => {
|
||||||
if (typeof targetObject[key] === "undefined") {
|
if (typeof targetObject[key] === 'undefined') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (typeof targetObject[key] === "object") {
|
if (typeof targetObject[key] === 'object') {
|
||||||
Utils.updateKeys(targetObject[key], sourceObject[key]);
|
Utils.updateKeys(targetObject[key], sourceObject[key]);
|
||||||
} else {
|
} else {
|
||||||
targetObject[key] = sourceObject[key];
|
targetObject[key] = sourceObject[key];
|
||||||
@ -60,7 +64,7 @@ export class Utils {
|
|||||||
|
|
||||||
public static setKeys(targetObject: any, sourceObject: any) {
|
public static setKeys(targetObject: any, sourceObject: any) {
|
||||||
Object.keys(sourceObject).forEach((key) => {
|
Object.keys(sourceObject).forEach((key) => {
|
||||||
if (typeof targetObject[key] === "object") {
|
if (typeof targetObject[key] === 'object') {
|
||||||
Utils.setKeys(targetObject[key], sourceObject[key]);
|
Utils.setKeys(targetObject[key], sourceObject[key]);
|
||||||
} else {
|
} else {
|
||||||
targetObject[key] = sourceObject[key];
|
targetObject[key] = sourceObject[key];
|
||||||
@ -70,8 +74,8 @@ export class Utils {
|
|||||||
|
|
||||||
public static setKeysForced(targetObject: any, sourceObject: any) {
|
public static setKeysForced(targetObject: any, sourceObject: any) {
|
||||||
Object.keys(sourceObject).forEach((key) => {
|
Object.keys(sourceObject).forEach((key) => {
|
||||||
if (typeof sourceObject[key] === "object") {
|
if (typeof sourceObject[key] === 'object') {
|
||||||
if (typeof targetObject[key] === "undefined") {
|
if (typeof targetObject[key] === 'undefined') {
|
||||||
targetObject[key] = {};
|
targetObject[key] = {};
|
||||||
}
|
}
|
||||||
Utils.setKeysForced(targetObject[key], sourceObject[key]);
|
Utils.setKeysForced(targetObject[key], sourceObject[key]);
|
||||||
@ -85,12 +89,12 @@ export class Utils {
|
|||||||
key: number;
|
key: number;
|
||||||
value: string;
|
value: string;
|
||||||
}> {
|
}> {
|
||||||
let arr: Array<{ key: number; value: string; }> = [];
|
const arr: Array<{ key: number; value: string; }> = [];
|
||||||
for (let enumMember in EnumType) {
|
for (const enumMember in EnumType) {
|
||||||
if (!EnumType.hasOwnProperty(enumMember)) {
|
if (!EnumType.hasOwnProperty(enumMember)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let key = parseInt(enumMember, 10);
|
const key = parseInt(enumMember, 10);
|
||||||
if (key >= 0) {
|
if (key >= 0) {
|
||||||
arr.push({key: key, value: EnumType[enumMember]});
|
arr.push({key: key, value: EnumType[enumMember]});
|
||||||
}
|
}
|
||||||
@ -106,7 +110,7 @@ export class Utils {
|
|||||||
|
|
||||||
arr.forEach((value) => {
|
arr.forEach((value) => {
|
||||||
|
|
||||||
let newDiff = Math.abs(number - value);
|
const newDiff = Math.abs(number - value);
|
||||||
|
|
||||||
if (newDiff < diff) {
|
if (newDiff < diff) {
|
||||||
diff = newDiff;
|
diff = newDiff;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {PrivateConfigClass} from "./PrivateConfigClass";
|
import {PrivateConfigClass} from './PrivateConfigClass';
|
||||||
|
|
||||||
|
|
||||||
export let Config = new PrivateConfigClass();
|
export let Config = new PrivateConfigClass();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {ClientConfig} from "../public/ConfigClass";
|
import {ClientConfig} from '../public/ConfigClass';
|
||||||
|
|
||||||
export enum DatabaseType {
|
export enum DatabaseType {
|
||||||
memory = 0, mysql = 1, sqlite = 2
|
memory = 0, mysql = 1, sqlite = 2
|
||||||
@ -47,7 +47,7 @@ export enum ReIndexingSensitivity {
|
|||||||
|
|
||||||
export interface IndexingConfig {
|
export interface IndexingConfig {
|
||||||
folderPreviewSize: number;
|
folderPreviewSize: number;
|
||||||
cachedFolderTimeout: number;//Do not rescans the folder if seems ok
|
cachedFolderTimeout: number; // Do not rescans the folder if seems ok
|
||||||
reIndexingSensitivity: ReIndexingSensitivity;
|
reIndexingSensitivity: ReIndexingSensitivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export interface ServerConfig {
|
|||||||
database: DataBaseConfig;
|
database: DataBaseConfig;
|
||||||
enableThreading: boolean;
|
enableThreading: boolean;
|
||||||
sharing: SharingConfig;
|
sharing: SharingConfig;
|
||||||
sessionTimeout: number
|
sessionTimeout: number;
|
||||||
indexing: IndexingConfig;
|
indexing: IndexingConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
import {PublicConfigClass} from "../public/ConfigClass";
|
import {PublicConfigClass} from '../public/ConfigClass';
|
||||||
import {
|
import {DatabaseType, IPrivateConfig, ReIndexingSensitivity, ServerConfig, ThumbnailProcessingLib} from './IPrivateConfig';
|
||||||
DatabaseType,
|
import * as path from 'path';
|
||||||
IPrivateConfig,
|
import {ConfigLoader} from 'typeconfig';
|
||||||
ReIndexingSensitivity,
|
|
||||||
ServerConfig,
|
|
||||||
ThumbnailProcessingLib
|
|
||||||
} from "./IPrivateConfig";
|
|
||||||
import * as path from "path";
|
|
||||||
import {ConfigLoader} from "typeconfig";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This configuration will be only at backend
|
* This configuration will be only at backend
|
||||||
@ -16,9 +10,9 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
|||||||
|
|
||||||
public Server: ServerConfig = {
|
public Server: ServerConfig = {
|
||||||
port: 80,
|
port: 80,
|
||||||
imagesFolder: "demo/images",
|
imagesFolder: 'demo/images',
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
folder: "demo/TEMP",
|
folder: 'demo/TEMP',
|
||||||
processingLibrary: ThumbnailProcessingLib.sharp,
|
processingLibrary: ThumbnailProcessingLib.sharp,
|
||||||
qualityPriority: true
|
qualityPriority: true
|
||||||
},
|
},
|
||||||
@ -26,14 +20,14 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
|||||||
database: {
|
database: {
|
||||||
type: DatabaseType.sqlite,
|
type: DatabaseType.sqlite,
|
||||||
mysql: {
|
mysql: {
|
||||||
host: "",
|
host: '',
|
||||||
username: "",
|
username: '',
|
||||||
password: "",
|
password: '',
|
||||||
database: ""
|
database: ''
|
||||||
|
|
||||||
},
|
},
|
||||||
sqlite: {
|
sqlite: {
|
||||||
storage: "sqlite.db"
|
storage: 'sqlite.db'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sharing: {
|
sharing: {
|
||||||
@ -59,7 +53,7 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
|||||||
public load() {
|
public load() {
|
||||||
ConfigLoader.loadBackendConfig(this,
|
ConfigLoader.loadBackendConfig(this,
|
||||||
path.join(__dirname, './../../../config.json'),
|
path.join(__dirname, './../../../config.json'),
|
||||||
[["PORT", "Server-port"]]);
|
[['PORT', 'Server-port']]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +62,7 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
public original(): PrivateConfigClass {
|
public original(): PrivateConfigClass {
|
||||||
let cfg = new PrivateConfigClass();
|
const cfg = new PrivateConfigClass();
|
||||||
cfg.load();
|
cfg.load();
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {PublicConfigClass} from "./ConfigClass";
|
import {PublicConfigClass} from './ConfigClass';
|
||||||
import {WebConfigLoader} from "typeconfig/src/WebConfigLoader";
|
import {WebConfigLoader} from 'typeconfig/src/WebConfigLoader';
|
||||||
|
|
||||||
|
|
||||||
declare module ServerInject {
|
declare module ServerInject {
|
||||||
@ -9,12 +9,12 @@ declare module ServerInject {
|
|||||||
export let Config = new PublicConfigClass();
|
export let Config = new PublicConfigClass();
|
||||||
|
|
||||||
|
|
||||||
if (typeof ServerInject !== "undefined" && typeof ServerInject.ConfigInject !== "undefined") {
|
if (typeof ServerInject !== 'undefined' && typeof ServerInject.ConfigInject !== 'undefined') {
|
||||||
WebConfigLoader.loadFrontendConfig(Config.Client, ServerInject.ConfigInject);
|
WebConfigLoader.loadFrontendConfig(Config.Client, ServerInject.ConfigInject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Config.Client.publicUrl == "") {
|
if (Config.Client.publicUrl === '') {
|
||||||
Config.Client.publicUrl = location.origin;
|
Config.Client.publicUrl = location.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
export module ClientConfig {
|
export module ClientConfig {
|
||||||
export interface SearchConfig {
|
export interface SearchConfig {
|
||||||
enabled: boolean
|
enabled: boolean;
|
||||||
instantSearchEnabled: boolean
|
instantSearchEnabled: boolean;
|
||||||
autocompleteEnabled: boolean
|
autocompleteEnabled: boolean;
|
||||||
InstantSearchTimeout: number;
|
InstantSearchTimeout: number;
|
||||||
autocompleteCacheTimeout: number;
|
autocompleteCacheTimeout: number;
|
||||||
instantSearchCacheTimeout: number;
|
instantSearchCacheTimeout: number;
|
||||||
@ -36,6 +36,7 @@ export module ClientConfig {
|
|||||||
enableOnScrollThumbnailPrioritising: boolean;
|
enableOnScrollThumbnailPrioritising: boolean;
|
||||||
authenticationRequired: boolean;
|
authenticationRequired: boolean;
|
||||||
publicUrl: string;
|
publicUrl: string;
|
||||||
|
urlBase: string;
|
||||||
languages: string[];
|
languages: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ export module ClientConfig {
|
|||||||
export class PublicConfigClass {
|
export class PublicConfigClass {
|
||||||
|
|
||||||
public Client: ClientConfig.Config = {
|
public Client: ClientConfig.Config = {
|
||||||
applicationTitle: "PiGallery 2",
|
applicationTitle: 'PiGallery 2',
|
||||||
Thumbnail: {
|
Thumbnail: {
|
||||||
thumbnailSizes: [200, 400, 600],
|
thumbnailSizes: [200, 400, 600],
|
||||||
iconSize: 30
|
iconSize: 30
|
||||||
@ -67,14 +68,15 @@ export class PublicConfigClass {
|
|||||||
},
|
},
|
||||||
Map: {
|
Map: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
googleApiKey: ""
|
googleApiKey: ''
|
||||||
},
|
},
|
||||||
concurrentThumbnailGenerations: 1,
|
concurrentThumbnailGenerations: 1,
|
||||||
enableCache: true,
|
enableCache: true,
|
||||||
enableOnScrollRendering: true,
|
enableOnScrollRendering: true,
|
||||||
enableOnScrollThumbnailPrioritising: true,
|
enableOnScrollThumbnailPrioritising: true,
|
||||||
authenticationRequired: true,
|
authenticationRequired: true,
|
||||||
publicUrl: "",
|
publicUrl: '',
|
||||||
|
urlBase: '',
|
||||||
languages: []
|
languages: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {DirectoryDTO} from "./DirectoryDTO";
|
import {DirectoryDTO} from './DirectoryDTO';
|
||||||
import {SearchResultDTO} from "./SearchResultDTO";
|
import {SearchResultDTO} from './SearchResultDTO';
|
||||||
|
|
||||||
export class ContentWrapper {
|
export class ContentWrapper {
|
||||||
constructor(public directory: DirectoryDTO = null,
|
constructor(public directory: DirectoryDTO = null,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {PhotoDTO} from "./PhotoDTO";
|
import {PhotoDTO} from './PhotoDTO';
|
||||||
|
|
||||||
export interface DirectoryDTO {
|
export interface DirectoryDTO {
|
||||||
id: number;
|
id: number;
|
||||||
@ -22,5 +22,5 @@ export module DirectoryDTO {
|
|||||||
addReferences(directory);
|
addReferences(directory);
|
||||||
directory.parent = dir;
|
directory.parent = dir;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export enum ErrorCodes{
|
export enum ErrorCodes {
|
||||||
NOT_AUTHENTICATED = 0,
|
NOT_AUTHENTICATED = 0,
|
||||||
ALREADY_AUTHENTICATED = 1,
|
ALREADY_AUTHENTICATED = 1,
|
||||||
NOT_AUTHORISED = 2,
|
NOT_AUTHORISED = 2,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
export class LoginCredential {
|
export class LoginCredential {
|
||||||
constructor(public username: string = "", public password: string = "", public rememberMe: boolean = false) {
|
constructor(public username: string = '',
|
||||||
|
public password: string = '',
|
||||||
|
public rememberMe: boolean = false) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {ErrorDTO} from "./Error";
|
import {ErrorDTO} from './Error';
|
||||||
|
|
||||||
export class Message<T> {
|
export class Message<T> {
|
||||||
public error: ErrorDTO = null;
|
public error: ErrorDTO = null;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export enum NotificationType{
|
export enum NotificationType {
|
||||||
error, warning, info
|
error, warning, info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {UserModificationRequest} from "./UserModificationRequest";
|
import {UserModificationRequest} from './UserModificationRequest';
|
||||||
|
|
||||||
export class PasswordChangeRequest extends UserModificationRequest {
|
export class PasswordChangeRequest extends UserModificationRequest {
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {DirectoryDTO} from "./DirectoryDTO";
|
import {DirectoryDTO} from './DirectoryDTO';
|
||||||
|
|
||||||
export interface PhotoDTO {
|
export interface PhotoDTO {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {DirectoryDTO} from "./DirectoryDTO";
|
import {DirectoryDTO} from './DirectoryDTO';
|
||||||
import {PhotoDTO} from "./PhotoDTO";
|
import {PhotoDTO} from './PhotoDTO';
|
||||||
import {SearchTypes} from "./AutoCompleteItem";
|
import {SearchTypes} from './AutoCompleteItem';
|
||||||
|
|
||||||
export interface SearchResultDTO {
|
export interface SearchResultDTO {
|
||||||
searchText: string;
|
searchText: string;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {UserDTO} from "./UserDTO";
|
import {UserDTO} from './UserDTO';
|
||||||
|
|
||||||
export interface SharingDTO {
|
export interface SharingDTO {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {DirectoryDTO} from "./DirectoryDTO";
|
import {DirectoryDTO} from './DirectoryDTO';
|
||||||
import {Utils} from "../Utils";
|
import {Utils} from '../Utils';
|
||||||
|
|
||||||
export enum UserRoles {
|
export enum UserRoles {
|
||||||
LimitedGuest = 0,
|
LimitedGuest = 0,
|
||||||
@ -15,25 +15,25 @@ export interface UserDTO {
|
|||||||
name: string;
|
name: string;
|
||||||
password: string;
|
password: string;
|
||||||
role: UserRoles;
|
role: UserRoles;
|
||||||
permissions: string[]; //user can only see these permissions. if ends with *, its recursive
|
permissions: string[]; // user can only see these permissions. if ends with *, its recursive
|
||||||
}
|
}
|
||||||
|
|
||||||
export module UserDTO {
|
export module UserDTO {
|
||||||
|
|
||||||
export const isPathAvailable = (path: string, permissions: string[]): boolean => {
|
export const isPathAvailable = (path: string, permissions: string[]): boolean => {
|
||||||
if (permissions == null || permissions.length == 0 || permissions[0] == "/*") {
|
if (permissions == null || permissions.length === 0 || permissions[0] === '/*') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < permissions.length; i++) {
|
for (let i = 0; i < permissions.length; i++) {
|
||||||
let permission = permissions[i];
|
let permission = permissions[i];
|
||||||
if (permission[permission.length - 1] == "*") {
|
if (permission[permission.length - 1] === '*') {
|
||||||
permission = permission.slice(0, -1);
|
permission = permission.slice(0, -1);
|
||||||
if (path.startsWith(permission)) {
|
if (path.startsWith(permission)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (path == permission) {
|
} else if (path === permission) {
|
||||||
return true;
|
return true;
|
||||||
} else if (path == "." && permission == "/") {
|
} else if (path === '.' && permission === '/') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export interface BasicConfigDTO {
|
export interface BasicConfigDTO {
|
||||||
imagesFolder: string;
|
imagesFolder: string;
|
||||||
publicUrl: string;
|
publicUrl: string;
|
||||||
|
urlBase: string;
|
||||||
applicationTitle: string;
|
applicationTitle: string;
|
||||||
port: number;
|
port: number;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
function isFunction(functionToCheck: any) {
|
function isFunction(functionToCheck: any) {
|
||||||
let getType = {};
|
const getType = {};
|
||||||
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Event<T> {
|
export class Event<T> {
|
||||||
private handlers: { (data?: T): void; }[] = [];
|
private handlers: ((data?: T) => void)[] = [];
|
||||||
|
|
||||||
public on(handler: { (data?: T): void }) {
|
public on(handler: (data?: T) => void) {
|
||||||
if (!isFunction(handler)) {
|
if (!isFunction(handler)) {
|
||||||
throw new Error("Handler is not a function");
|
throw new Error('Handler is not a function');
|
||||||
}
|
}
|
||||||
this.handlers.push(handler);
|
this.handlers.push(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public off(handler: { (data?: T): void }) {
|
public off(handler: (data?: T) => void) {
|
||||||
this.handlers = this.handlers.filter(h => h !== handler);
|
this.handlers = this.handlers.filter(h => h !== handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
export class Event2Args<T, M> {
|
export class Event2Args<T, M> {
|
||||||
private handlers: { (data?: T, data2?: M): void; }[] = [];
|
private handlers: ((data?: T, data2?: M) => void)[] = [];
|
||||||
|
|
||||||
public on(handler: { (data?: T, data2?: M): void }) {
|
public on(handler: (data?: T, data2?: M) => void) {
|
||||||
this.handlers.push(handler);
|
this.handlers.push(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public off(handler: { (data?: T, data2?: M): void }) {
|
public off(handler: (data?: T, data2?: M) => void) {
|
||||||
this.handlers = this.handlers.filter(h => h !== handler);
|
this.handlers = this.handlers.filter(h => h !== handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,21 +4,21 @@ export class EventLimit<T> {
|
|||||||
|
|
||||||
private handlers: Array<EventLimitHandler<T>> = [];
|
private handlers: Array<EventLimitHandler<T>> = [];
|
||||||
|
|
||||||
public on(limit: T, handler: { (data?: T): void }) {
|
public on(limit: T, handler: (data?: T) => void) {
|
||||||
this.handlers.push(new EventLimitHandler(limit, handler));
|
this.handlers.push(new EventLimitHandler(limit, handler));
|
||||||
if (this.lastTriggerValue != null) {
|
if (this.lastTriggerValue != null) {
|
||||||
this.trigger(this.lastTriggerValue);
|
this.trigger(this.lastTriggerValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onSingle(limit: T, handler: { (data?: T): void }) {
|
public onSingle(limit: T, handler: (data?: T) => void) {
|
||||||
this.handlers.push(new SingleFireEventLimitHandler(limit, handler));
|
this.handlers.push(new SingleFireEventLimitHandler(limit, handler));
|
||||||
if (this.lastTriggerValue != null) {
|
if (this.lastTriggerValue != null) {
|
||||||
this.trigger(this.lastTriggerValue);
|
this.trigger(this.lastTriggerValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public off(limit: T, handler: { (data?: T): void }) {
|
public off(limit: T, handler: (data?: T) => void) {
|
||||||
this.handlers = this.handlers.filter(h => h.handler !== handler && h.limit !== limit);
|
this.handlers = this.handlers.filter(h => h.handler !== handler && h.limit !== limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ export class EventLimit<T> {
|
|||||||
class EventLimitHandler<T> {
|
class EventLimitHandler<T> {
|
||||||
public lastTriggerValue: T = null;
|
public lastTriggerValue: T = null;
|
||||||
|
|
||||||
constructor(public limit: T, public handler: { (data?: T): void }) {
|
constructor(public limit: T, public handler: (data?: T) => void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public fire(data?: T) {
|
public fire(data?: T) {
|
||||||
@ -54,18 +54,19 @@ class EventLimitHandler<T> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SingleFireEventLimitHandler<T> extends EventLimitHandler<T> {
|
class SingleFireEventLimitHandler<T> extends EventLimitHandler<T> {
|
||||||
public fired = false;
|
public fired = false;
|
||||||
|
|
||||||
constructor(public limit: T, public handler: { (data?: T): void }) {
|
constructor(public limit: T, public handler: (data?: T) => void) {
|
||||||
super(limit, handler);
|
super(limit, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public fire(data?: T) {
|
public fire(data?: T) {
|
||||||
if (this.fired == false) {
|
if (this.fired === false) {
|
||||||
this.handler(data);
|
this.handler(data);
|
||||||
}
|
}
|
||||||
this.fired = true
|
this.fired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isValid(): boolean {
|
public isValid(): boolean {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {PhotoDTO} from '../../../common/entities/PhotoDTO';
|
import {PhotoDTO} from '../../../common/entities/PhotoDTO';
|
||||||
import {Utils} from '../../../common/Utils';
|
import {Utils} from '../../../common/Utils';
|
||||||
|
import {Config} from '../../../common/config/public/Config';
|
||||||
|
|
||||||
export class IconPhoto {
|
export class IconPhoto {
|
||||||
|
|
||||||
@ -19,23 +20,29 @@ export class IconPhoto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getIconPath() {
|
getIconPath() {
|
||||||
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name, 'icon');
|
return Utils.concatUrls(Config.Client.urlBase,
|
||||||
|
'/api/gallery/content/',
|
||||||
|
this.photo.directory.path, this.photo.directory.name, this.photo.name, 'icon');
|
||||||
}
|
}
|
||||||
|
|
||||||
getPhotoPath() {
|
getPhotoPath() {
|
||||||
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name);
|
return Utils.concatUrls(Config.Client.urlBase,
|
||||||
|
'/api/gallery/content/',
|
||||||
|
this.photo.directory.path, this.photo.directory.name, this.photo.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
equals(other: PhotoDTO | IconPhoto): boolean {
|
equals(other: PhotoDTO | IconPhoto): boolean {
|
||||||
//is gridphoto
|
// is gridphoto
|
||||||
if (other instanceof IconPhoto) {
|
if (other instanceof IconPhoto) {
|
||||||
return this.photo.directory.path === other.photo.directory.path && this.photo.directory.name === other.photo.directory.name && this.photo.name === other.photo.name;
|
return this.photo.directory.path === other.photo.directory.path &&
|
||||||
|
this.photo.directory.name === other.photo.directory.name && this.photo.name === other.photo.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
//is photo
|
// is photo
|
||||||
if (other.directory) {
|
if (other.directory) {
|
||||||
return this.photo.directory.path === other.directory.path && this.photo.directory.name === other.directory.name && this.photo.name === other.name;
|
return this.photo.directory.path === other.directory.path &&
|
||||||
|
this.photo.directory.name === other.directory.name && this.photo.name === other.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -19,7 +19,7 @@ export class Photo extends IconPhoto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getThumbnailSize() {
|
getThumbnailSize() {
|
||||||
let renderSize = Math.sqrt(this.renderWidth * this.renderHeight);
|
const renderSize = Math.sqrt(this.renderWidth * this.renderHeight);
|
||||||
return Utils.findClosest(renderSize, Config.Client.Thumbnail.thumbnailSizes);
|
return Utils.findClosest(renderSize, Config.Client.Thumbnail.thumbnailSizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ export class Photo extends IconPhoto {
|
|||||||
if (this.replacementSizeCache === false) {
|
if (this.replacementSizeCache === false) {
|
||||||
this.replacementSizeCache = null;
|
this.replacementSizeCache = null;
|
||||||
|
|
||||||
let size = this.getThumbnailSize();
|
const size = this.getThumbnailSize();
|
||||||
if (!!this.photo.readyThumbnails) {
|
if (!!this.photo.readyThumbnails) {
|
||||||
for (let i = 0; i < this.photo.readyThumbnails.length; i++) {
|
for (let i = 0; i < this.photo.readyThumbnails.length; i++) {
|
||||||
if (this.photo.readyThumbnails[i] < size) {
|
if (this.photo.readyThumbnails[i] < size) {
|
||||||
@ -46,18 +46,22 @@ export class Photo extends IconPhoto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isThumbnailAvailable() {
|
isThumbnailAvailable() {
|
||||||
return this.photo.readyThumbnails && this.photo.readyThumbnails.indexOf(this.getThumbnailSize()) != -1;
|
return this.photo.readyThumbnails && this.photo.readyThumbnails.indexOf(this.getThumbnailSize()) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
getReplacementThumbnailPath() {
|
getReplacementThumbnailPath() {
|
||||||
let size = this.getReplacementThumbnailSize();
|
const size = this.getReplacementThumbnailSize();
|
||||||
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
|
return Utils.concatUrls(Config.Client.urlBase,
|
||||||
|
'/api/gallery/content/',
|
||||||
|
this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getThumbnailPath() {
|
getThumbnailPath() {
|
||||||
let size = this.getThumbnailSize();
|
const size = this.getThumbnailSize();
|
||||||
return Utils.concatUrls('/api/gallery/content/', this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
|
return Utils.concatUrls(Config.Client.urlBase,
|
||||||
|
'/api/gallery/content/',
|
||||||
|
this.photo.directory.path, this.photo.directory.name, this.photo.name, 'thumbnail', size.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ export class GalleryCacheService {
|
|||||||
|
|
||||||
public getSearch(text: string, type?: SearchTypes): SearchResultDTO {
|
public getSearch(text: string, type?: SearchTypes): SearchResultDTO {
|
||||||
let key = GalleryCacheService.SEARCH_PREFIX + text;
|
let key = GalleryCacheService.SEARCH_PREFIX + text;
|
||||||
if (typeof type != 'undefined') {
|
if (typeof type !== 'undefined') {
|
||||||
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
|
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
|
||||||
}
|
}
|
||||||
const tmp = localStorage.getItem(key);
|
const tmp = localStorage.getItem(key);
|
||||||
@ -89,7 +89,7 @@ export class GalleryCacheService {
|
|||||||
item: searchResult
|
item: searchResult
|
||||||
};
|
};
|
||||||
let key = GalleryCacheService.SEARCH_PREFIX + text;
|
let key = GalleryCacheService.SEARCH_PREFIX + text;
|
||||||
if (typeof type != 'undefined') {
|
if (typeof type !== 'undefined') {
|
||||||
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
|
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
|
||||||
}
|
}
|
||||||
localStorage.setItem(key, JSON.stringify(tmp));
|
localStorage.setItem(key, JSON.stringify(tmp));
|
||||||
@ -97,12 +97,12 @@ export class GalleryCacheService {
|
|||||||
|
|
||||||
|
|
||||||
public getDirectory(directoryName: string): DirectoryDTO {
|
public getDirectory(directoryName: string): DirectoryDTO {
|
||||||
if (Config.Client.enableCache == false) {
|
if (Config.Client.enableCache === false) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let value = localStorage.getItem(GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directoryName));
|
const value = localStorage.getItem(GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directoryName));
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
let directory: DirectoryDTO = JSON.parse(value);
|
const directory: DirectoryDTO = JSON.parse(value);
|
||||||
|
|
||||||
DirectoryDTO.addReferences(directory);
|
DirectoryDTO.addReferences(directory);
|
||||||
return directory;
|
return directory;
|
||||||
@ -111,12 +111,12 @@ export class GalleryCacheService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setDirectory(directory: DirectoryDTO): void {
|
public setDirectory(directory: DirectoryDTO): void {
|
||||||
if (Config.Client.enableCache == false) {
|
if (Config.Client.enableCache === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directory.path, directory.name);
|
const key = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directory.path, directory.name);
|
||||||
if (directory.isPartial == true && localStorage.getItem(key)) {
|
if (directory.isPartial === true && localStorage.getItem(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ export class GalleryCacheService {
|
|||||||
|
|
||||||
directory.directories.forEach((dir: DirectoryDTO) => {
|
directory.directories.forEach((dir: DirectoryDTO) => {
|
||||||
const sub_key = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(dir.path, dir.name);
|
const sub_key = GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(dir.path, dir.name);
|
||||||
if (localStorage.getItem(sub_key) == null) { //don't override existing
|
if (localStorage.getItem(sub_key) == null) { // don't override existing
|
||||||
localStorage.setItem(sub_key, JSON.stringify(dir));
|
localStorage.setItem(sub_key, JSON.stringify(dir));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -137,21 +137,21 @@ export class GalleryCacheService {
|
|||||||
*/
|
*/
|
||||||
public photoUpdated(photo: PhotoDTO): void {
|
public photoUpdated(photo: PhotoDTO): void {
|
||||||
|
|
||||||
if (Config.Client.enableCache == false) {
|
if (Config.Client.enableCache === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let directoryName = Utils.concatUrls(photo.directory.path, photo.directory.name);
|
const directoryName = Utils.concatUrls(photo.directory.path, photo.directory.name);
|
||||||
let value = localStorage.getItem(directoryName);
|
const value = localStorage.getItem(directoryName);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
let directory: DirectoryDTO = JSON.parse(value);
|
const directory: DirectoryDTO = JSON.parse(value);
|
||||||
directory.photos.forEach((p) => {
|
directory.photos.forEach((p) => {
|
||||||
if (p.name === photo.name) {
|
if (p.name === photo.name) {
|
||||||
//update data
|
// update data
|
||||||
p.metadata = photo.metadata;
|
p.metadata = photo.metadata;
|
||||||
p.readyThumbnails = photo.readyThumbnails;
|
p.readyThumbnails = photo.readyThumbnails;
|
||||||
|
|
||||||
//save changes
|
// save changes
|
||||||
localStorage.setItem(directoryName, JSON.stringify(directory));
|
localStorage.setItem(directoryName, JSON.stringify(directory));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,11 @@ export class GalleryDirectoryComponent implements OnInit, OnDestroy {
|
|||||||
size: number = null;
|
size: number = null;
|
||||||
|
|
||||||
getSanitizedThUrl() {
|
getSanitizedThUrl() {
|
||||||
return this._sanitizer.bypassSecurityTrustStyle('url(' + encodeURI(this.thumbnail.Src).replace(/\(/g, '%28').replace(/\)/g, '%29') + ')');
|
return this._sanitizer.bypassSecurityTrustStyle('url(' + encodeURI(this.thumbnail.Src).replace(/\(/g, '%28')
|
||||||
|
.replace(/\)/g, '%29') + ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: implement scroll
|
// TODO: implement scroll
|
||||||
isInView(): boolean {
|
isInView(): boolean {
|
||||||
return document.body.scrollTop < this.container.nativeElement.offsetTop + this.container.nativeElement.clientHeight
|
return document.body.scrollTop < this.container.nativeElement.offsetTop + this.container.nativeElement.clientHeight
|
||||||
&& document.body.scrollTop + window.innerHeight > this.container.nativeElement.offsetTop;
|
&& document.body.scrollTop + window.innerHeight > this.container.nativeElement.offsetTop;
|
||||||
|
@ -16,7 +16,7 @@ import {ContentWrapper} from '../../../common/entities/ConentWrapper';
|
|||||||
import {PageHelper} from '../model/page.helper';
|
import {PageHelper} from '../model/page.helper';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'gallery',
|
selector: 'app-gallery',
|
||||||
templateUrl: './gallery.component.html',
|
templateUrl: './gallery.component.html',
|
||||||
styleUrls: ['./gallery.component.css']
|
styleUrls: ['./gallery.component.css']
|
||||||
})
|
})
|
||||||
|
@ -36,7 +36,7 @@ export class GalleryService {
|
|||||||
this.lastRequest.directory = directoryName;
|
this.lastRequest.directory = directoryName;
|
||||||
|
|
||||||
const params = {};
|
const params = {};
|
||||||
if (Config.Client.Sharing.enabled == true) {
|
if (Config.Client.Sharing.enabled === true) {
|
||||||
if (this._shareService.isSharing()) {
|
if (this._shareService.isSharing()) {
|
||||||
params['sk'] = this._shareService.getSharingKey();
|
params['sk'] = this._shareService.getSharingKey();
|
||||||
}
|
}
|
||||||
@ -52,13 +52,13 @@ export class GalleryService {
|
|||||||
const cw = await this.networkService.getJson<ContentWrapper>('/gallery/content/' + directoryName, params);
|
const cw = await this.networkService.getJson<ContentWrapper>('/gallery/content/' + directoryName, params);
|
||||||
|
|
||||||
|
|
||||||
if (!cw || cw.notModified == true) {
|
if (!cw || cw.notModified === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.galleryCacheService.setDirectory(cw.directory); //save it before adding references
|
this.galleryCacheService.setDirectory(cw.directory); // save it before adding references
|
||||||
|
|
||||||
if (this.lastRequest.directory != directoryName) {
|
if (this.lastRequest.directory !== directoryName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ export class GalleryService {
|
|||||||
if (this.searchId != null) {
|
if (this.searchId != null) {
|
||||||
clearTimeout(this.searchId);
|
clearTimeout(this.searchId);
|
||||||
}
|
}
|
||||||
if (text === null || text === '' || text.trim() == '.') {
|
if (text === null || text === '' || text.trim() === '.') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ export class GalleryService {
|
|||||||
cw.searchResult = this.galleryCacheService.getSearch(text, type);
|
cw.searchResult = this.galleryCacheService.getSearch(text, type);
|
||||||
if (cw.searchResult == null) {
|
if (cw.searchResult == null) {
|
||||||
const params = {};
|
const params = {};
|
||||||
if (typeof type != 'undefined') {
|
if (typeof type !== 'undefined') {
|
||||||
params['type'] = type;
|
params['type'] = type;
|
||||||
}
|
}
|
||||||
cw.searchResult = (await this.networkService.getJson<ContentWrapper>('/search/' + text, params)).searchResult;
|
cw.searchResult = (await this.networkService.getJson<ContentWrapper>('/search/' + text, params)).searchResult;
|
||||||
@ -98,7 +98,7 @@ export class GalleryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async instantSearch(text: string): Promise<ContentWrapper> {
|
public async instantSearch(text: string): Promise<ContentWrapper> {
|
||||||
if (text === null || text === '' || text.trim() == '.') {
|
if (text === null || text === '' || text.trim() === '.') {
|
||||||
const content = new ContentWrapper(this.lastDirectory);
|
const content = new ContentWrapper(this.lastDirectory);
|
||||||
this.content.next(content);
|
this.content.next(content);
|
||||||
if (this.searchId != null) {
|
if (this.searchId != null) {
|
||||||
@ -119,7 +119,7 @@ export class GalleryService {
|
|||||||
cw.directory = null;
|
cw.directory = null;
|
||||||
cw.searchResult = this.galleryCacheService.getSearch(text);
|
cw.searchResult = this.galleryCacheService.getSearch(text);
|
||||||
if (cw.searchResult == null) {
|
if (cw.searchResult == null) {
|
||||||
//If result is not search cache, try to load load more
|
// If result is not search cache, try to load load more
|
||||||
this.searchId = setTimeout(() => {
|
this.searchId = setTimeout(() => {
|
||||||
this.search(text);
|
this.search(text);
|
||||||
this.searchId = null;
|
this.searchId = null;
|
||||||
@ -134,8 +134,8 @@ export class GalleryService {
|
|||||||
}
|
}
|
||||||
this.content.next(cw);
|
this.content.next(cw);
|
||||||
|
|
||||||
//if instant search do not have a result, do not do a search
|
// if instant search do not have a result, do not do a search
|
||||||
if (cw.searchResult.photos.length == 0 && cw.searchResult.directories.length == 0) {
|
if (cw.searchResult.photos.length === 0 && cw.searchResult.directories.length === 0) {
|
||||||
if (this.searchId != null) {
|
if (this.searchId != null) {
|
||||||
clearTimeout(this.searchId);
|
clearTimeout(this.searchId);
|
||||||
}
|
}
|
||||||
|
@ -63,5 +63,5 @@ export class GridRowBuilder {
|
|||||||
const height = (this.containerWidth - this.photoRow.length * (this.photoMargin * 2) - 1) / width; // cant be equal -> width-1
|
const height = (this.containerWidth - this.photoRow.length * (this.photoMargin * 2) - 1) / width; // cant be equal -> width-1
|
||||||
|
|
||||||
return height + (this.photoMargin * 2);
|
return height + (this.photoMargin * 2);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,7 @@
|
|||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-bottom-left-radius: 4px;
|
border-bottom-left-radius: 4px;
|
||||||
border-bottom-right-radius: 4px;
|
border-bottom-right-radius: 4px;
|
||||||
padding-left: 0;
|
padding: 5px 0;
|
||||||
padding-right: 0;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||||
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export class ShareService {
|
|||||||
constructor(private _networkService: NetworkService, private router: Router) {
|
constructor(private _networkService: NetworkService, private router: Router) {
|
||||||
this.sharing = new BehaviorSubject(null);
|
this.sharing = new BehaviorSubject(null);
|
||||||
this.ReadyPR = new Promise((resolve) => {
|
this.ReadyPR = new Promise((resolve) => {
|
||||||
if (this.inited == true) {
|
if (this.inited === true) {
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
this.resolve = resolve;
|
this.resolve = resolve;
|
||||||
@ -29,7 +29,7 @@ export class ShareService {
|
|||||||
if (val instanceof RoutesRecognized) {
|
if (val instanceof RoutesRecognized) {
|
||||||
this.param = val.state.root.firstChild.params['sharingKey'] || null;
|
this.param = val.state.root.firstChild.params['sharingKey'] || null;
|
||||||
this.queryParam = val.state.root.firstChild.queryParams['sk'] || null;
|
this.queryParam = val.state.root.firstChild.queryParams['sk'] || null;
|
||||||
const changed = this.sharingKey != this.param || this.queryParam;
|
const changed = this.sharingKey !== this.param || this.queryParam;
|
||||||
if (changed) {
|
if (changed) {
|
||||||
this.sharingKey = this.param || this.queryParam;
|
this.sharingKey = this.param || this.queryParam;
|
||||||
this.getSharing();
|
this.getSharing();
|
||||||
|
@ -13,142 +13,16 @@ export enum ThumbnailLoadingPriority {
|
|||||||
export class ThumbnailLoaderService {
|
export class ThumbnailLoaderService {
|
||||||
|
|
||||||
que: Array<ThumbnailTask> = [];
|
que: Array<ThumbnailTask> = [];
|
||||||
runningRequests: number = 0;
|
runningRequests = 0;
|
||||||
|
|
||||||
constructor(private galleryCacheService: GalleryCacheService) {
|
constructor(private galleryCacheService: GalleryCacheService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
removeTask(taskEntry: ThumbnailTaskEntity) {
|
|
||||||
|
|
||||||
let index = taskEntry.parentTask.taskEntities.indexOf(taskEntry);
|
|
||||||
if (index == -1) {
|
|
||||||
throw new Error('ThumbnailTaskEntity not exist on Task');
|
|
||||||
}
|
|
||||||
taskEntry.parentTask.taskEntities.splice(index, 1);
|
|
||||||
|
|
||||||
if (taskEntry.parentTask.taskEntities.length == 0
|
|
||||||
&& taskEntry.parentTask.inProgress == false) {
|
|
||||||
let i = this.que.indexOf(taskEntry.parentTask);
|
|
||||||
if (i == -1) {
|
|
||||||
throw new Error('ThumbnailTask not exist');
|
|
||||||
}
|
|
||||||
this.que.splice(i, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
loadIcon(photo: IconPhoto, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
|
|
||||||
let thTask: ThumbnailTask = null;
|
|
||||||
//is image already qued?
|
|
||||||
for (let i = 0; i < this.que.length; i++) {
|
|
||||||
if (this.que[i].path == photo.getIconPath()) {
|
|
||||||
thTask = this.que[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (thTask == null) {
|
|
||||||
thTask = {
|
|
||||||
photo: photo.photo,
|
|
||||||
inProgress: false,
|
|
||||||
taskEntities: [],
|
|
||||||
onLoaded: () => {
|
|
||||||
photo.iconLoaded();
|
|
||||||
},
|
|
||||||
path: photo.getIconPath()
|
|
||||||
};
|
|
||||||
this.que.push(thTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
let thumbnailTaskEntity = {priority: priority, listener: listener, parentTask: thTask};
|
|
||||||
thTask.taskEntities.push(thumbnailTaskEntity);
|
|
||||||
if (thTask.inProgress == true) {
|
|
||||||
listener.onStartedLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
setTimeout(this.run, 0);
|
|
||||||
return thumbnailTaskEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadImage(photo: Photo, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
|
|
||||||
|
|
||||||
let thTask: ThumbnailTask = null;
|
|
||||||
//is image already qued?
|
|
||||||
for (let i = 0; i < this.que.length; i++) {
|
|
||||||
if (this.que[i].path == photo.getThumbnailPath()) {
|
|
||||||
thTask = this.que[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (thTask == null) {
|
|
||||||
thTask = {
|
|
||||||
photo: photo.photo,
|
|
||||||
inProgress: false,
|
|
||||||
taskEntities: [],
|
|
||||||
onLoaded: () => {
|
|
||||||
photo.thumbnailLoaded();
|
|
||||||
},
|
|
||||||
path: photo.getThumbnailPath()
|
|
||||||
};
|
|
||||||
this.que.push(thTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
let thumbnailTaskEntity = {priority: priority, listener: listener, parentTask: thTask};
|
|
||||||
|
|
||||||
//add to poolTask
|
|
||||||
thTask.taskEntities.push(thumbnailTaskEntity);
|
|
||||||
if (thTask.inProgress == true) {
|
|
||||||
listener.onStartedLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(this.run, 0);
|
|
||||||
return thumbnailTaskEntity;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private getNextTask(): ThumbnailTask {
|
|
||||||
if (this.que.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let highestPriority: ThumbnailTask = null;
|
|
||||||
let currentPriority: ThumbnailLoadingPriority = Number.MAX_SAFE_INTEGER;
|
|
||||||
for (let i = 0; i < this.que.length; i++) {
|
|
||||||
for (let j = 0; j < this.que[i].taskEntities.length; j++) {
|
|
||||||
if (this.que[i].inProgress == false) {
|
|
||||||
if (highestPriority == null || currentPriority < this.que[i].taskEntities[j].priority) {
|
|
||||||
highestPriority = this.que[i];
|
|
||||||
currentPriority = this.que[i].taskEntities[j].priority;
|
|
||||||
if (currentPriority == ThumbnailLoadingPriority.extraHigh) {
|
|
||||||
return highestPriority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return highestPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
private taskReady(task: ThumbnailTask) {
|
|
||||||
let i = this.que.indexOf(task);
|
|
||||||
if (i == -1) {
|
|
||||||
if (task.taskEntities.length !== 0) {
|
|
||||||
console.error('ThumbnailLoader: can\'t find poolTask to remove');
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.que.splice(i, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
run = () => {
|
run = () => {
|
||||||
if (this.que.length === 0 || this.runningRequests >= Config.Client.concurrentThumbnailGenerations) {
|
if (this.que.length === 0 || this.runningRequests >= Config.Client.concurrentThumbnailGenerations) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let task = this.getNextTask();
|
const task = this.getNextTask();
|
||||||
|
|
||||||
if (task === null) {
|
if (task === null) {
|
||||||
return;
|
return;
|
||||||
@ -158,7 +32,7 @@ export class ThumbnailLoaderService {
|
|||||||
task.taskEntities.forEach(te => te.listener.onStartedLoading());
|
task.taskEntities.forEach(te => te.listener.onStartedLoading());
|
||||||
task.inProgress = true;
|
task.inProgress = true;
|
||||||
|
|
||||||
let curImg = new Image();
|
const curImg = new Image();
|
||||||
curImg.onload = () => {
|
curImg.onload = () => {
|
||||||
task.onLoaded();
|
task.onLoaded();
|
||||||
this.galleryCacheService.photoUpdated(task.photo);
|
this.galleryCacheService.photoUpdated(task.photo);
|
||||||
@ -179,6 +53,129 @@ export class ThumbnailLoaderService {
|
|||||||
|
|
||||||
curImg.src = task.path;
|
curImg.src = task.path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
removeTask(taskEntry: ThumbnailTaskEntity) {
|
||||||
|
|
||||||
|
const index = taskEntry.parentTask.taskEntities.indexOf(taskEntry);
|
||||||
|
if (index === -1) {
|
||||||
|
throw new Error('ThumbnailTaskEntity not exist on Task');
|
||||||
|
}
|
||||||
|
taskEntry.parentTask.taskEntities.splice(index, 1);
|
||||||
|
|
||||||
|
if (taskEntry.parentTask.taskEntities.length === 0
|
||||||
|
&& taskEntry.parentTask.inProgress === false) {
|
||||||
|
const i = this.que.indexOf(taskEntry.parentTask);
|
||||||
|
if (i === -1) {
|
||||||
|
throw new Error('ThumbnailTask not exist');
|
||||||
|
}
|
||||||
|
this.que.splice(i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
loadIcon(photo: IconPhoto, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
|
||||||
|
let thTask: ThumbnailTask = null;
|
||||||
|
// is image already qued?
|
||||||
|
for (let i = 0; i < this.que.length; i++) {
|
||||||
|
if (this.que[i].path === photo.getIconPath()) {
|
||||||
|
thTask = this.que[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (thTask == null) {
|
||||||
|
thTask = {
|
||||||
|
photo: photo.photo,
|
||||||
|
inProgress: false,
|
||||||
|
taskEntities: [],
|
||||||
|
onLoaded: () => {
|
||||||
|
photo.iconLoaded();
|
||||||
|
},
|
||||||
|
path: photo.getIconPath()
|
||||||
|
};
|
||||||
|
this.que.push(thTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
const thumbnailTaskEntity = {priority: priority, listener: listener, parentTask: thTask};
|
||||||
|
thTask.taskEntities.push(thumbnailTaskEntity);
|
||||||
|
if (thTask.inProgress === true) {
|
||||||
|
listener.onStartedLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(this.run, 0);
|
||||||
|
return thumbnailTaskEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadImage(photo: Photo, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
|
||||||
|
|
||||||
|
let thTask: ThumbnailTask = null;
|
||||||
|
// is image already qued?
|
||||||
|
for (let i = 0; i < this.que.length; i++) {
|
||||||
|
if (this.que[i].path === photo.getThumbnailPath()) {
|
||||||
|
thTask = this.que[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (thTask == null) {
|
||||||
|
thTask = {
|
||||||
|
photo: photo.photo,
|
||||||
|
inProgress: false,
|
||||||
|
taskEntities: [],
|
||||||
|
onLoaded: () => {
|
||||||
|
photo.thumbnailLoaded();
|
||||||
|
},
|
||||||
|
path: photo.getThumbnailPath()
|
||||||
|
};
|
||||||
|
this.que.push(thTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
const thumbnailTaskEntity = {priority: priority, listener: listener, parentTask: thTask};
|
||||||
|
|
||||||
|
// add to poolTask
|
||||||
|
thTask.taskEntities.push(thumbnailTaskEntity);
|
||||||
|
if (thTask.inProgress === true) {
|
||||||
|
listener.onStartedLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(this.run, 0);
|
||||||
|
return thumbnailTaskEntity;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private getNextTask(): ThumbnailTask {
|
||||||
|
if (this.que.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let highestPriority: ThumbnailTask = null;
|
||||||
|
let currentPriority: ThumbnailLoadingPriority = Number.MAX_SAFE_INTEGER;
|
||||||
|
for (let i = 0; i < this.que.length; i++) {
|
||||||
|
for (let j = 0; j < this.que[i].taskEntities.length; j++) {
|
||||||
|
if (this.que[i].inProgress === false) {
|
||||||
|
if (highestPriority == null || currentPriority < this.que[i].taskEntities[j].priority) {
|
||||||
|
highestPriority = this.que[i];
|
||||||
|
currentPriority = this.que[i].taskEntities[j].priority;
|
||||||
|
if (currentPriority === ThumbnailLoadingPriority.extraHigh) {
|
||||||
|
return highestPriority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return highestPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
private taskReady(task: ThumbnailTask) {
|
||||||
|
const i = this.que.indexOf(task);
|
||||||
|
if (i === -1) {
|
||||||
|
if (task.taskEntities.length !== 0) {
|
||||||
|
console.error('ThumbnailLoader: can\'t find poolTask to remove');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.que.splice(i, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,15 +28,15 @@ export class ThumbnailManagerService {
|
|||||||
|
|
||||||
export abstract class ThumbnailBase {
|
export abstract class ThumbnailBase {
|
||||||
|
|
||||||
protected available: boolean = false;
|
protected available = false;
|
||||||
protected src: string = null;
|
protected src: string = null;
|
||||||
protected loading: boolean = false;
|
protected loading = false;
|
||||||
protected error: boolean = false;
|
protected error = false;
|
||||||
protected onLoad: Function = null;
|
protected onLoad: Function = null;
|
||||||
protected thumbnailTask: ThumbnailTaskEntity = null;
|
protected thumbnailTask: ThumbnailTaskEntity = null;
|
||||||
|
|
||||||
|
|
||||||
constructor(protected thumbnailService: ThumbnailLoaderService) {
|
protected constructor(protected thumbnailService: ThumbnailLoaderService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract set Visible(visible: boolean);
|
abstract set Visible(visible: boolean);
|
||||||
@ -80,24 +80,28 @@ export class IconThumbnail extends ThumbnailBase {
|
|||||||
if (this.photo.isIconAvailable()) {
|
if (this.photo.isIconAvailable()) {
|
||||||
this.src = this.photo.getIconPath();
|
this.src = this.photo.getIconPath();
|
||||||
this.available = true;
|
this.available = true;
|
||||||
if (this.onLoad) this.onLoad();
|
if (this.onLoad) {
|
||||||
|
this.onLoad();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.photo.isIconAvailable()) {
|
if (!this.photo.isIconAvailable()) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
||||||
let listener: ThumbnailLoadingListener = {
|
const listener: ThumbnailLoadingListener = {
|
||||||
onStartedLoading: () => { //onLoadStarted
|
onStartedLoading: () => { // onLoadStarted
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
},
|
},
|
||||||
onLoad: () => {//onLoaded
|
onLoad: () => {// onLoaded
|
||||||
this.src = this.photo.getIconPath();
|
this.src = this.photo.getIconPath();
|
||||||
if (this.onLoad) this.onLoad();
|
if (this.onLoad) {
|
||||||
|
this.onLoad();
|
||||||
|
}
|
||||||
this.available = true;
|
this.available = true;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.thumbnailTask = null;
|
this.thumbnailTask = null;
|
||||||
},
|
},
|
||||||
onError: (error) => {//onError
|
onError: (error) => {// onError
|
||||||
this.thumbnailTask = null;
|
this.thumbnailTask = null;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.error = true;
|
this.error = true;
|
||||||
@ -112,7 +116,9 @@ export class IconThumbnail extends ThumbnailBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set Visible(visible: boolean) {
|
set Visible(visible: boolean) {
|
||||||
if (!this.thumbnailTask) return;
|
if (!this.thumbnailTask) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (visible === true) {
|
if (visible === true) {
|
||||||
this.thumbnailTask.priority = ThumbnailLoadingPriority.high;
|
this.thumbnailTask.priority = ThumbnailLoadingPriority.high;
|
||||||
} else {
|
} else {
|
||||||
@ -131,7 +137,9 @@ export class Thumbnail extends ThumbnailBase {
|
|||||||
if (this.photo.isThumbnailAvailable()) {
|
if (this.photo.isThumbnailAvailable()) {
|
||||||
this.src = this.photo.getThumbnailPath();
|
this.src = this.photo.getThumbnailPath();
|
||||||
this.available = true;
|
this.available = true;
|
||||||
if (this.onLoad) this.onLoad();
|
if (this.onLoad) {
|
||||||
|
this.onLoad();
|
||||||
|
}
|
||||||
} else if (this.photo.isReplacementThumbnailAvailable()) {
|
} else if (this.photo.isReplacementThumbnailAvailable()) {
|
||||||
this.src = this.photo.getReplacementThumbnailPath();
|
this.src = this.photo.getReplacementThumbnailPath();
|
||||||
this.available = true;
|
this.available = true;
|
||||||
@ -142,7 +150,9 @@ export class Thumbnail extends ThumbnailBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set CurrentlyWaiting(value: boolean) {
|
set CurrentlyWaiting(value: boolean) {
|
||||||
if (!this.thumbnailTask) return;
|
if (!this.thumbnailTask) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (value === true) {
|
if (value === true) {
|
||||||
if (this.photo.isReplacementThumbnailAvailable()) {
|
if (this.photo.isReplacementThumbnailAvailable()) {
|
||||||
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
|
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
|
||||||
@ -158,37 +168,10 @@ export class Thumbnail extends ThumbnailBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public load() {
|
|
||||||
if (!this.photo.isThumbnailAvailable() && this.thumbnailTask == null) {
|
|
||||||
// setTimeout(() => {
|
|
||||||
let listener: ThumbnailLoadingListener = {
|
|
||||||
onStartedLoading: () => { //onLoadStarted
|
|
||||||
this.loading = true;
|
|
||||||
},
|
|
||||||
onLoad: () => {//onLoaded
|
|
||||||
this.src = this.photo.getThumbnailPath();
|
|
||||||
if (this.onLoad) this.onLoad();
|
|
||||||
this.available = true;
|
|
||||||
this.loading = false;
|
|
||||||
this.thumbnailTask = null;
|
|
||||||
},
|
|
||||||
onError: (error) => {//onError
|
|
||||||
this.thumbnailTask = null;
|
|
||||||
this.loading = false;
|
|
||||||
this.error = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (this.photo.isReplacementThumbnailAvailable()) {
|
|
||||||
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.medium, listener);
|
|
||||||
} else {
|
|
||||||
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.high, listener);
|
|
||||||
}
|
|
||||||
// }, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set Visible(visible: boolean) {
|
set Visible(visible: boolean) {
|
||||||
if (!this.thumbnailTask) return;
|
if (!this.thumbnailTask) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (visible === true) {
|
if (visible === true) {
|
||||||
if (this.photo.isReplacementThumbnailAvailable()) {
|
if (this.photo.isReplacementThumbnailAvailable()) {
|
||||||
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
|
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
|
||||||
@ -205,5 +188,36 @@ export class Thumbnail extends ThumbnailBase {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public load() {
|
||||||
|
if (!this.photo.isThumbnailAvailable() && this.thumbnailTask == null) {
|
||||||
|
// setTimeout(() => {
|
||||||
|
const listener: ThumbnailLoadingListener = {
|
||||||
|
onStartedLoading: () => { // onLoadStarted
|
||||||
|
this.loading = true;
|
||||||
|
},
|
||||||
|
onLoad: () => {// onLoaded
|
||||||
|
this.src = this.photo.getThumbnailPath();
|
||||||
|
if (this.onLoad) {
|
||||||
|
this.onLoad();
|
||||||
|
}
|
||||||
|
this.available = true;
|
||||||
|
this.loading = false;
|
||||||
|
this.thumbnailTask = null;
|
||||||
|
},
|
||||||
|
onError: (error) => {// onError
|
||||||
|
this.thumbnailTask = null;
|
||||||
|
this.loading = false;
|
||||||
|
this.error = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (this.photo.isReplacementThumbnailAvailable()) {
|
||||||
|
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.medium, listener);
|
||||||
|
} else {
|
||||||
|
this.thumbnailTask = this.thumbnailService.loadImage(this.photo, ThumbnailLoadingPriority.high, listener);
|
||||||
|
}
|
||||||
|
// }, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,12 +32,11 @@
|
|||||||
max-width: 350px;
|
max-width: 350px;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
background-color: #F7F7F7;
|
background-color: #F7F7F7;
|
||||||
margin: 0 auto;
|
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.3);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 295px;
|
height: 295px;
|
||||||
margin-top: 0px;
|
margin: 0px auto 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Margin by pixel:*/
|
/*Margin by pixel:*/
|
||||||
|
@ -6,13 +6,13 @@ import {Config} from '../../../common/config/public/Config';
|
|||||||
import {NavigationService} from '../model/navigation.service';
|
import {NavigationService} from '../model/navigation.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'login',
|
selector: 'app-login',
|
||||||
templateUrl: './login.component.html',
|
templateUrl: './login.component.html',
|
||||||
styleUrls: ['./login.component.css'],
|
styleUrls: ['./login.component.css'],
|
||||||
})
|
})
|
||||||
export class LoginComponent implements OnInit {
|
export class LoginComponent implements OnInit {
|
||||||
loginCredential: LoginCredential;
|
loginCredential: LoginCredential;
|
||||||
loginError: boolean = false;
|
loginError = false;
|
||||||
title: string;
|
title: string;
|
||||||
inProgress = false;
|
inProgress = false;
|
||||||
|
|
||||||
|
@ -4,11 +4,13 @@ import {Message} from '../../../../common/entities/Message';
|
|||||||
import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
|
import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
|
||||||
import 'rxjs/Rx';
|
import 'rxjs/Rx';
|
||||||
import {ErrorCodes, ErrorDTO} from '../../../../common/entities/Error';
|
import {ErrorCodes, ErrorDTO} from '../../../../common/entities/Error';
|
||||||
|
import {Config} from '../../../../common/config/public/Config';
|
||||||
|
import {Utils} from '../../../../common/Utils';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NetworkService {
|
export class NetworkService {
|
||||||
|
|
||||||
_baseUrl = '/api';
|
_apiBaseUrl = Utils.concatUrls(Config.Client.urlBase, '/api');
|
||||||
private globalErrorHandlers: Array<(error: ErrorDTO) => boolean> = [];
|
private globalErrorHandlers: Array<(error: ErrorDTO) => boolean> = [];
|
||||||
|
|
||||||
constructor(private _http: HttpClient,
|
constructor(private _http: HttpClient,
|
||||||
@ -69,22 +71,22 @@ export class NetworkService {
|
|||||||
|
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'get':
|
case 'get':
|
||||||
return this._http.get<Message<T>>(this._baseUrl + url)
|
return this._http.get<Message<T>>(this._apiBaseUrl + url)
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(process)
|
.then(process)
|
||||||
.catch(err);
|
.catch(err);
|
||||||
case 'delete':
|
case 'delete':
|
||||||
return this._http.delete<Message<T>>(this._baseUrl + url)
|
return this._http.delete<Message<T>>(this._apiBaseUrl + url)
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(process)
|
.then(process)
|
||||||
.catch(err);
|
.catch(err);
|
||||||
case 'post':
|
case 'post':
|
||||||
return this._http.post<Message<T>>(this._baseUrl + url, body)
|
return this._http.post<Message<T>>(this._apiBaseUrl + url, body)
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(process)
|
.then(process)
|
||||||
.catch(err);
|
.catch(err);
|
||||||
case 'put':
|
case 'put':
|
||||||
return this._http.put<Message<T>>(this._baseUrl + url, body)
|
return this._http.put<Message<T>>(this._apiBaseUrl + url, body)
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(process)
|
.then(process)
|
||||||
.catch(err);
|
.catch(err);
|
||||||
|
@ -38,13 +38,13 @@ export abstract class SettingsComponent<T, S extends AbstractSettingsService<T>=
|
|||||||
High: 'High'
|
High: 'High'
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private name,
|
protected constructor(private name,
|
||||||
private _authService: AuthenticationService,
|
private _authService: AuthenticationService,
|
||||||
private _navigation: NavigationService,
|
private _navigation: NavigationService,
|
||||||
public _settingsService: S,
|
public _settingsService: S,
|
||||||
protected notification: NotificationService,
|
protected notification: NotificationService,
|
||||||
public i18n: I18n,
|
public i18n: I18n,
|
||||||
private sliceFN?: (s: IPrivateConfig) => T) {
|
private sliceFN?: (s: IPrivateConfig) => T) {
|
||||||
if (this.sliceFN) {
|
if (this.sliceFN) {
|
||||||
this._settingsSubscription = this._settingsService.Settings.subscribe(this.onNewSettings);
|
this._settingsSubscription = this._settingsService.Settings.subscribe(this.onNewSettings);
|
||||||
this.onNewSettings(this._settingsService._settingsService.settings.value);
|
this.onNewSettings(this._settingsService._settingsService.settings.value);
|
||||||
|
@ -2,7 +2,7 @@ import {SettingsService} from '../settings.service';
|
|||||||
|
|
||||||
export abstract class AbstractSettingsService<T> {
|
export abstract class AbstractSettingsService<T> {
|
||||||
|
|
||||||
constructor(public _settingsService: SettingsService) {
|
protected constructor(public _settingsService: SettingsService) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" [hidden]="simplifiedMode">
|
||||||
|
<label class="col-sm-2 control-label" for="urlBase" i18n>Url Base</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="url" class="form-control" placeholder="/myGallery"
|
||||||
|
id="urlBase"
|
||||||
|
[(ngModel)]="settings.urlBase"
|
||||||
|
name="urlBase">
|
||||||
|
<span class="help-block" i18n>If you access the gallery under a sub url (like: http://mydomain.com/myGallery), set it here. If not working you might miss the '/' from the beginning of the url.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-success pull-right"
|
<button class="btn btn-success pull-right"
|
||||||
[disabled]="!settingsForm.form.valid || !changed || inProgress"
|
[disabled]="!settingsForm.form.valid || !changed || inProgress"
|
||||||
(click)="save()" i18n>Save
|
(click)="save()" i18n>Save
|
||||||
|
@ -27,7 +27,8 @@ export class BasicSettingsComponent extends SettingsComponent<BasicConfigDTO> {
|
|||||||
port: s.Server.port,
|
port: s.Server.port,
|
||||||
imagesFolder: s.Server.imagesFolder,
|
imagesFolder: s.Server.imagesFolder,
|
||||||
applicationTitle: s.Client.applicationTitle,
|
applicationTitle: s.Client.applicationTitle,
|
||||||
publicUrl: s.Client.publicUrl
|
publicUrl: s.Client.publicUrl,
|
||||||
|
urlBase: s.Client.urlBase
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ export class SettingsService {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
googleApiKey: ''
|
googleApiKey: ''
|
||||||
},
|
},
|
||||||
|
urlBase: '',
|
||||||
publicUrl: '',
|
publicUrl: '',
|
||||||
applicationTitle: '',
|
applicationTitle: '',
|
||||||
enableCache: true,
|
enableCache: true,
|
||||||
|
@ -54,7 +54,7 @@ export class UserMangerSettingsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
this.userRoles = Utils
|
this.userRoles = Utils
|
||||||
.enumToArray(UserRoles)
|
.enumToArray(UserRoles)
|
||||||
.filter(r => r.key != UserRoles.LimitedGuest)
|
.filter(r => r.key !== UserRoles.LimitedGuest)
|
||||||
.filter(r => r.key <= this._authService.user.value.role)
|
.filter(r => r.key <= this._authService.user.value.role)
|
||||||
.sort((a, b) => a.key - b.key);
|
.sort((a, b) => a.key - b.key);
|
||||||
|
|
||||||
@ -62,29 +62,39 @@ export class UserMangerSettingsComponent implements OnInit {
|
|||||||
this.getUsersList();
|
this.getUsersList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getUsersList() {
|
canModifyUser(user: UserDTO): boolean {
|
||||||
try {
|
const currentUser = this._authService.user.value;
|
||||||
this.users = await this._userSettings.getUsers();
|
if (!currentUser) {
|
||||||
} catch (err) {
|
return false;
|
||||||
this.users = [];
|
|
||||||
if ((<ErrorDTO>err).code != ErrorCodes.USER_MANAGEMENT_DISABLED) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return currentUser.name !== user.name && currentUser.role >= user.role;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getSettings() {
|
private async getSettings() {
|
||||||
this.enabled = await this._userSettings.getSettings();
|
this.enabled = await this._userSettings.getSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async switched(event: { previousValue: false, currentValue: true }) {
|
||||||
canModifyUser(user: UserDTO): boolean {
|
this.inProgress = true;
|
||||||
let currentUser = this._authService.user.value;
|
this.error = '';
|
||||||
if (!currentUser) {
|
this.enabled = event.currentValue;
|
||||||
return false;
|
try {
|
||||||
|
await this._userSettings.updateSettings(this.enabled);
|
||||||
|
await this.getSettings();
|
||||||
|
if (this.enabled === true) {
|
||||||
|
this.notification.success(this.i18n('Password protection enabled'), this.i18n('Success'));
|
||||||
|
this.getUsersList();
|
||||||
|
} else {
|
||||||
|
this.notification.success(this.i18n('Password protection disabled'), this.i18n('Success'));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
if (err.message) {
|
||||||
|
this.error = (<ErrorDTO>err).message;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
this.inProgress = false;
|
||||||
return currentUser.name != user.name && currentUser.role >= user.role;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initNewUser() {
|
initNewUser() {
|
||||||
@ -110,26 +120,15 @@ export class UserMangerSettingsComponent implements OnInit {
|
|||||||
this.childModal.hide();
|
this.childModal.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
async switched(event: { previousValue: false, currentValue: true }) {
|
private async getUsersList() {
|
||||||
this.inProgress = true;
|
|
||||||
this.error = '';
|
|
||||||
this.enabled = event.currentValue;
|
|
||||||
try {
|
try {
|
||||||
await this._userSettings.updateSettings(this.enabled);
|
this.users = await this._userSettings.getUsers();
|
||||||
await this.getSettings();
|
|
||||||
if (this.enabled == true) {
|
|
||||||
this.notification.success(this.i18n('Password protection enabled'), this.i18n('Success'));
|
|
||||||
this.getUsersList();
|
|
||||||
} else {
|
|
||||||
this.notification.success(this.i18n('Password protection disabled'), this.i18n('Success'));
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
this.users = [];
|
||||||
if (err.message) {
|
if ((<ErrorDTO>err).code !== ErrorCodes.USER_MANAGEMENT_DISABLED) {
|
||||||
this.error = (<ErrorDTO>err).message;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.inProgress = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
var ServerInject = {
|
|
||||||
user: <%- JSON.stringify(user); %>,
|
|
||||||
ConfigInject: <%- JSON.stringify(clientConfig); %>
|
|
||||||
}
|
|
@ -1,17 +1,24 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<base href="/"/>
|
<base href="<%= clientConfig.urlBase %>/"/>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Loading..</title>
|
<title>Loading..</title>
|
||||||
<link rel="shortcut icon" href="assets/icon.png">
|
<link rel="shortcut icon" href="assets/icon.png">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- Latest compiled and minified CSS -->
|
|
||||||
|
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.css">
|
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.css">
|
||||||
|
|
||||||
<script type="text/javascript" src="/config_inject.js"></script>
|
<script>
|
||||||
|
var ServerInject = {user: < % -JSON.stringify(user);
|
||||||
|
%>,
|
||||||
|
ConfigInject:<
|
||||||
|
%
|
||||||
|
-JSON.stringify(clientConfig);
|
||||||
|
%>
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
import "zone.js/dist/long-stack-trace-zone";
|
import 'zone.js/dist/long-stack-trace-zone';
|
||||||
import "zone.js/dist/proxy.js";
|
import 'zone.js/dist/proxy.js';
|
||||||
import "zone.js/dist/sync-test";
|
import 'zone.js/dist/sync-test';
|
||||||
import "zone.js/dist/jasmine-patch";
|
import 'zone.js/dist/jasmine-patch';
|
||||||
import "zone.js/dist/async-test";
|
import 'zone.js/dist/async-test';
|
||||||
import "zone.js/dist/fake-async-test";
|
import 'zone.js/dist/fake-async-test';
|
||||||
import {getTestBed} from "@angular/core/testing";
|
import {getTestBed} from '@angular/core/testing';
|
||||||
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from "@angular/platform-browser-dynamic/testing";
|
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
|
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
|
||||||
declare const __karma__: any;
|
declare const __karma__: any;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<source>Please log in</source>
|
<source>Please log in</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">11</context>
|
<context context-type="linenumber">10</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>Please log in</target>
|
<target>Please log in</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
</source>
|
</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">13</context>
|
<context context-type="linenumber">12</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>
|
<target>
|
||||||
Wrong username or password
|
Wrong username or password
|
||||||
@ -26,7 +26,7 @@
|
|||||||
<source>Username</source>
|
<source>Username</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">22</context>
|
<context context-type="linenumber">21</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<source>Password</source>
|
<source>Password</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">36</context>
|
<context context-type="linenumber">37</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/sharelogin/share-login.component.ts</context>
|
<context context-type="sourcefile">app/sharelogin/share-login.component.ts</context>
|
||||||
@ -70,7 +70,7 @@
|
|||||||
<source>Remember me</source>
|
<source>Remember me</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">42</context>
|
<context context-type="linenumber">43</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>Remember me</target>
|
<target>Remember me</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -79,7 +79,7 @@
|
|||||||
</source>
|
</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">52</context>
|
<context context-type="linenumber">53</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>Login
|
<target>Login
|
||||||
</target>
|
</target>
|
||||||
@ -146,7 +146,7 @@
|
|||||||
<source>key: left arrow</source>
|
<source>key: left arrow</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
|
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
|
||||||
<context context-type="linenumber">40</context>
|
<context context-type="linenumber">41</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>key: left arrow</target>
|
<target>key: left arrow</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -154,7 +154,7 @@
|
|||||||
<source>key: right arrow</source>
|
<source>key: right arrow</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
|
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
|
||||||
<context context-type="linenumber">44</context>
|
<context context-type="linenumber">45</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>key: right arrow</target>
|
<target>key: right arrow</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -533,7 +533,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
||||||
<context context-type="linenumber">57</context>
|
<context context-type="linenumber">68</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
||||||
@ -563,7 +563,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
||||||
<context context-type="linenumber">60</context>
|
<context context-type="linenumber">71</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
||||||
@ -840,6 +840,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target>If you access the page form local network its good to know the public url for creating sharing link</target>
|
<target>If you access the page form local network its good to know the public url for creating sharing link</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="52e8e9fdcd08e89225892a7657140dbf41020b76" datatype="html">
|
||||||
|
<source>Url Base</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">56</context>
|
||||||
|
</context-group>
|
||||||
|
<target>Url Base</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8a46f66aef490af08db029240d761dd0715dea54" datatype="html">
|
||||||
|
<source>If you access the gallery under a sub url (like: http://mydomain.com/myGallery), set it here. If not working you might miss the '/' from the beginning of the url.</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">62</context>
|
||||||
|
</context-group>
|
||||||
|
<target>If you access the gallery under a sub url (like: http://mydomain.com/myGallery), set it here. If not working you might miss the '/' from the beginning of the url.</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="1e99f581a015c671d53abad7c7df6a5ad35bfe85" datatype="html">
|
<trans-unit id="1e99f581a015c671d53abad7c7df6a5ad35bfe85" datatype="html">
|
||||||
<source>Other settings</source>
|
<source>Other settings</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<source>Please log in</source>
|
<source>Please log in</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">11</context>
|
<context context-type="linenumber">10</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>Jelentkezz be</target>
|
<target>Jelentkezz be</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
</source>
|
</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">13</context>
|
<context context-type="linenumber">12</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>Rossz felhasználónév vagy jelszó</target>
|
<target>Rossz felhasználónév vagy jelszó</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<source>Username</source>
|
<source>Username</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">22</context>
|
<context context-type="linenumber">21</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/usermanager/usermanager.settings.component.ts</context>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<source>Password</source>
|
<source>Password</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">36</context>
|
<context context-type="linenumber">37</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/sharelogin/share-login.component.ts</context>
|
<context context-type="sourcefile">app/sharelogin/share-login.component.ts</context>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
<source>Remember me</source>
|
<source>Remember me</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">42</context>
|
<context context-type="linenumber">43</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>Emlékezz rám</target>
|
<target>Emlékezz rám</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -77,7 +77,7 @@
|
|||||||
</source>
|
</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/login/login.component.ts</context>
|
<context context-type="sourcefile">app/login/login.component.ts</context>
|
||||||
<context context-type="linenumber">52</context>
|
<context context-type="linenumber">53</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>Belépés</target>
|
<target>Belépés</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -140,7 +140,7 @@
|
|||||||
<source>key: left arrow</source>
|
<source>key: left arrow</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
|
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
|
||||||
<context context-type="linenumber">40</context>
|
<context context-type="linenumber">41</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>billentyű: balra nyíl</target>
|
<target>billentyű: balra nyíl</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -148,7 +148,7 @@
|
|||||||
<source>key: right arrow</source>
|
<source>key: right arrow</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
|
<context context-type="sourcefile">app/gallery/lightbox/lightbox.gallery.component.ts</context>
|
||||||
<context context-type="linenumber">44</context>
|
<context context-type="linenumber">45</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>billentyű: jobbra nyíl</target>
|
<target>billentyű: jobbra nyíl</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -516,7 +516,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
||||||
<context context-type="linenumber">57</context>
|
<context context-type="linenumber">68</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
||||||
@ -545,7 +545,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
||||||
<context context-type="linenumber">60</context>
|
<context context-type="linenumber">71</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
<context context-type="sourcefile">app/settings/other/other.settings.component.ts</context>
|
||||||
@ -816,6 +816,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target>Ha belső hálózatról nézed oldalt, jó tudni a nyilvános URL-t, a megosztási link létrehozásához</target>
|
<target>Ha belső hálózatról nézed oldalt, jó tudni a nyilvános URL-t, a megosztási link létrehozásához</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="52e8e9fdcd08e89225892a7657140dbf41020b76" datatype="html">
|
||||||
|
<source>Url Base</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">56</context>
|
||||||
|
</context-group>
|
||||||
|
<target>Al cím</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="8a46f66aef490af08db029240d761dd0715dea54" datatype="html">
|
||||||
|
<source>If you access the gallery under a sub url (like: http://mydomain.com/myGallery), set it here. If not working you might miss the '/' from the beginning of the url.</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">app/settings/basic/basic.settings.component.ts</context>
|
||||||
|
<context context-type="linenumber">62</context>
|
||||||
|
</context-group>
|
||||||
|
<target>Ha az oldalt egy al címen lehet elérni (pl: http://oldalam.hu/myGallery), akkor az alcímet itt állitsd be. Hiba esetén lehet, hogy a "/" hiányzik az url elejéről.</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="1e99f581a015c671d53abad7c7df6a5ad35bfe85" datatype="html">
|
<trans-unit id="1e99f581a015c671d53abad7c7df6a5ad35bfe85" datatype="html">
|
||||||
<source>Other settings</source>
|
<source>Other settings</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
@ -1257,4 +1273,4 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
10
gulpfile.js
10
gulpfile.js
@ -28,7 +28,9 @@ var createFrontendTask = function (type, script) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
gulp.task('build-frontend', function (done) {
|
gulp.task('build-frontend', function (done) {
|
||||||
var languages = getLanguages();
|
var languages = getLanguages().filter(function (l) {
|
||||||
|
return l !== "en";
|
||||||
|
});
|
||||||
var tasks = [];
|
var tasks = [];
|
||||||
createFrontendTask('build-frontend-release default',
|
createFrontendTask('build-frontend-release default',
|
||||||
"ng build --aot -prod --output-path=./release/dist --no-progress --locale=en" +
|
"ng build --aot -prod --output-path=./release/dist --no-progress --locale=en" +
|
||||||
@ -95,14 +97,14 @@ var getLanguages = function () {
|
|||||||
});
|
});
|
||||||
return files.map(function (f) {
|
return files.map(function (f) {
|
||||||
return f.split(".")[1]
|
return f.split(".")[1]
|
||||||
}).filter(function (l) {
|
|
||||||
return l !== "en";
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var simpleBuild = function (isProd) {
|
var simpleBuild = function (isProd) {
|
||||||
return function (done) {
|
return function (done) {
|
||||||
var languages = getLanguages();
|
var languages = getLanguages().filter(function (l) {
|
||||||
|
return l !== "en";
|
||||||
|
});
|
||||||
var tasks = [];
|
var tasks = [];
|
||||||
var cmd = "ng build --aot ";
|
var cmd = "ng build --aot ";
|
||||||
if (isProd) {
|
if (isProd) {
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "ng e2e",
|
"e2e": "ng e2e",
|
||||||
"run-dev": "ng build --aot -w --output-path=./dist --locale en --i18n-format xlf --i18n-file frontend/translate/messages.en.xlf --missing-translation warning",
|
"run-dev": "ng build --aot -w --output-path=./dist --locale en --i18n-format xlf --i18n-file frontend/translate/messages.en.xlf --missing-translation warning",
|
||||||
"build-hu": "ng build --aot --output-path=./dist/hu --locale hu --i18n-format xlf --i18n-file frontend/translate/messages.hu.xlf --missing-translation warning",
|
|
||||||
"update-translation": "gulp update-translation",
|
"update-translation": "gulp update-translation",
|
||||||
"add-translation": "gulp add-translation"
|
"add-translation": "gulp add-translation"
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user