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

adding url base, improving code quality

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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