From 75faadaef081686bac1f9707d4bb8e60f50bf3b1 Mon Sep 17 00:00:00 2001 From: Braun Patrik Date: Fri, 7 Jul 2017 22:54:18 +0200 Subject: [PATCH] creating navbar design --- backend/model/interfaces/ISearchManager.ts | 3 +- backend/model/interfaces/ISharingManager.ts | 1 + backend/model/memory/SearchManager.ts | 23 +- backend/model/memory/SharingManager.ts | 4 + backend/model/mysql/SearchManager.ts | 319 +++++++++--------- backend/model/mysql/SharingManager.ts | 4 + backend/model/mysql/enitites/UserEntity.ts | 2 +- backend/server.ts | 13 + frontend/app/app.component.ts | 2 +- frontend/app/frame/frame.component.css | 31 ++ frontend/app/frame/frame.component.html | 35 +- frontend/app/frame/frame.component.ts | 12 +- frontend/app/gallery/gallery.component.html | 13 +- .../search/search.gallery.component.css | 6 +- .../search/search.gallery.component.html | 45 ++- .../gallery/share/share.gallery.component.css | 4 + .../share/share.gallery.component.html | 13 +- frontend/app/model/network/user.service.ts | 1 - frontend/index.html | 7 - frontend/styles.css | 4 + 20 files changed, 315 insertions(+), 227 deletions(-) diff --git a/backend/model/interfaces/ISearchManager.ts b/backend/model/interfaces/ISearchManager.ts index 5ccfc24a..e082b0a9 100644 --- a/backend/model/interfaces/ISearchManager.ts +++ b/backend/model/interfaces/ISearchManager.ts @@ -4,4 +4,5 @@ export interface ISearchManager { autocomplete(text: string, cb: (error: any, result: Array) => void): void; search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResultDTO) => void): void; instantSearch(text: string, cb: (error: any, result: SearchResultDTO) => void): void; -} \ No newline at end of file + isSupported(): boolean; +} diff --git a/backend/model/interfaces/ISharingManager.ts b/backend/model/interfaces/ISharingManager.ts index 2ee39f2c..84ade18f 100644 --- a/backend/model/interfaces/ISharingManager.ts +++ b/backend/model/interfaces/ISharingManager.ts @@ -3,4 +3,5 @@ export interface ISharingManager { findOne(filter: any): Promise; createSharing(sharing: SharingDTO): Promise; updateSharing(sharing: SharingDTO): Promise; + isSupported(): boolean; } diff --git a/backend/model/memory/SearchManager.ts b/backend/model/memory/SearchManager.ts index 18255b06..526a8a0e 100644 --- a/backend/model/memory/SearchManager.ts +++ b/backend/model/memory/SearchManager.ts @@ -4,18 +4,21 @@ import {SearchResultDTO} from "../../../common/entities/SearchResult"; export class SearchManager implements ISearchManager { + isSupported(): boolean { + return false; + } - autocomplete(text: string, cb: (error: any, result: Array) => void) { - throw new Error("not implemented"); - } + autocomplete(text: string, cb: (error: any, result: Array) => void) { + throw new Error("not implemented"); + } - search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResultDTO) => void) { - throw new Error("not implemented"); - } + search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResultDTO) => void) { + throw new Error("not implemented"); + } - instantSearch(text: string, cb: (error: any, result: SearchResultDTO) => void) { - throw new Error("not implemented"); - } + instantSearch(text: string, cb: (error: any, result: SearchResultDTO) => void) { + throw new Error("not implemented"); + } -} \ No newline at end of file +} diff --git a/backend/model/memory/SharingManager.ts b/backend/model/memory/SharingManager.ts index 5ab8fcf5..cd444d04 100644 --- a/backend/model/memory/SharingManager.ts +++ b/backend/model/memory/SharingManager.ts @@ -3,6 +3,10 @@ import {SharingDTO} from "../../../common/entities/SharingDTO"; export class SharingManager implements ISharingManager { + isSupported(): boolean { + return false; + } + findOne(filter: any): Promise { throw new Error("not implemented"); } diff --git a/backend/model/mysql/SearchManager.ts b/backend/model/mysql/SearchManager.ts index 03aba103..24240cd6 100644 --- a/backend/model/mysql/SearchManager.ts +++ b/backend/model/mysql/SearchManager.ts @@ -8,184 +8,187 @@ import {PositionMetaData} from "../../../common/entities/PhotoDTO"; export class SearchManager implements ISearchManager { + isSupported(): boolean { + return true; + } - autocomplete(text: string, cb: (error: any, result: Array) => void) { + autocomplete(text: string, cb: (error: any, result: Array) => void) { - MySQLConnection.getConnection().then(async connection => { - try { - let result: Array = []; - let photoRepository = connection.getRepository(PhotoEntity); - let directoryRepository = connection.getRepository(DirectoryEntity); + MySQLConnection.getConnection().then(async connection => { + try { + let result: Array = []; + let photoRepository = connection.getRepository(PhotoEntity); + let directoryRepository = connection.getRepository(DirectoryEntity); - (await photoRepository - .createQueryBuilder('photo') - .select('DISTINCT(photo.metadataKeywords)') - .where('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .setLimit(5) - .getRawMany()) - .map(r => >JSON.parse(r.metadataKeywords)) - .forEach(keywords => { - result = result.concat(this.encapsulateAutoComplete(keywords.filter(k => k.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.keyword)); - }); + (await photoRepository + .createQueryBuilder('photo') + .select('DISTINCT(photo.metadataKeywords)') + .where('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .setLimit(5) + .getRawMany()) + .map(r => >JSON.parse(r.metadataKeywords)) + .forEach(keywords => { + result = result.concat(this.encapsulateAutoComplete(keywords.filter(k => k.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.keyword)); + }); - (await photoRepository - .createQueryBuilder('photo') - .select('DISTINCT(photo.metadataPositionData)') - .where('photo.metadata.positionData LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .setLimit(5) - .getRawMany()) - .map(r => JSON.parse(r.metadataPositionData)) - .map(pm => >[pm.city || "", pm.country || "", pm.state || ""]) - .forEach(positions => { - result = result.concat(this.encapsulateAutoComplete(positions.filter(p => p.toLowerCase().indexOf(text.toLowerCase()) != -1), SearchTypes.position)); - }); + (await photoRepository + .createQueryBuilder('photo') + .select('DISTINCT(photo.metadataPositionData)') + .where('photo.metadata.positionData LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .setLimit(5) + .getRawMany()) + .map(r => JSON.parse(r.metadataPositionData)) + .map(pm => >[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((await photoRepository - .createQueryBuilder('photo') - .select('DISTINCT(photo.name)') - .where('photo.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .setLimit(5) - .getRawMany()) - .map(r => r.name), SearchTypes.image)); + result = result.concat(this.encapsulateAutoComplete((await photoRepository + .createQueryBuilder('photo') + .select('DISTINCT(photo.name)') + .where('photo.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .setLimit(5) + .getRawMany()) + .map(r => r.name), SearchTypes.image)); - result = result.concat(this.encapsulateAutoComplete((await directoryRepository - .createQueryBuilder('dir') - .select('DISTINCT(dir.name)') - .where('dir.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .setLimit(5) - .getRawMany()) - .map(r => r.name), SearchTypes.directory)); + result = result.concat(this.encapsulateAutoComplete((await directoryRepository + .createQueryBuilder('dir') + .select('DISTINCT(dir.name)') + .where('dir.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .setLimit(5) + .getRawMany()) + .map(r => r.name), SearchTypes.directory)); - return cb(null, this.autoCompleteItemsUnique(result)); - } catch (error) { - return cb(error, null); - } + return cb(null, this.autoCompleteItemsUnique(result)); + } catch (error) { + return cb(error, null); + } - }).catch((error) => { - return cb(error, null); - }); - } + }).catch((error) => { + return cb(error, null); + }); + } - search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResultDTO) => void) { - MySQLConnection.getConnection().then(async connection => { + search(text: string, searchType: SearchTypes, cb: (error: any, result: SearchResultDTO) => void) { + MySQLConnection.getConnection().then(async connection => { - let result: SearchResultDTO = { - searchText: text, - searchType: searchType, - directories: [], - photos: [] - }; + let result: SearchResultDTO = { + searchText: text, + searchType: searchType, + directories: [], + photos: [] + }; - let query = connection - .getRepository(PhotoEntity) - .createQueryBuilder("photo"); + let query = connection + .getRepository(PhotoEntity) + .createQueryBuilder("photo"); - if (!searchType || searchType === SearchTypes.image) { - query.orWhere('photo.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}); - } + if (!searchType || searchType === SearchTypes.image) { + query.orWhere('photo.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}); + } - if (!searchType || searchType === SearchTypes.position) { - query.orWhere('photo.metadata.positionData LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}); - } - if (!searchType || searchType === SearchTypes.keyword) { - query.orWhere('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}); - } - let photos = await query - .innerJoinAndSelect("photo.directory", "directory") - .getMany(); + if (!searchType || searchType === SearchTypes.position) { + query.orWhere('photo.metadata.positionData LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}); + } + if (!searchType || searchType === SearchTypes.keyword) { + query.orWhere('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}); + } + let photos = await query + .innerJoinAndSelect("photo.directory", "directory") + .getMany(); - if (photos) { - for (let i = 0; i < photos.length; i++) { - photos[i].metadata.keywords = JSON.parse(photos[i].metadata.keywords); - photos[i].metadata.cameraData = JSON.parse(photos[i].metadata.cameraData); - photos[i].metadata.positionData = JSON.parse(photos[i].metadata.positionData); - photos[i].metadata.size = JSON.parse(photos[i].metadata.size); - } - result.photos = photos; - } - - result.directories = await connection - .getRepository(DirectoryEntity) - .createQueryBuilder("dir") - .where('dir.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .getMany(); - - - return cb(null, result); - }).catch((error) => { - return cb(error, null); - }); - } - - instantSearch(text: string, cb: (error: any, result: SearchResultDTO) => void) { - MySQLConnection.getConnection().then(async connection => { - - let result: SearchResultDTO = { - searchText: text, - directories: [], - photos: [] - }; - - let photos = await connection - .getRepository(PhotoEntity) - .createQueryBuilder("photo") - .where('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .orWhere('photo.metadata.positionData LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .orWhere('photo.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .innerJoinAndSelect("photo.directory", "directory") - .setLimit(10) - .getMany(); - - - if (photos) { - for (let i = 0; i < photos.length; i++) { - photos[i].metadata.keywords = JSON.parse(photos[i].metadata.keywords); - photos[i].metadata.cameraData = JSON.parse(photos[i].metadata.cameraData); - photos[i].metadata.positionData = JSON.parse(photos[i].metadata.positionData); - photos[i].metadata.size = JSON.parse(photos[i].metadata.size); - } - result.photos = photos; - } - - let directories = await connection - .getRepository(DirectoryEntity) - .createQueryBuilder("dir") - .where('dir.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) - .setLimit(10) - .getMany(); - - result.directories = directories; - - return cb(null, result); - }).catch((error) => { - return cb(error, null); - }); - } - - private encapsulateAutoComplete(values: Array, type: SearchTypes) { - let res = []; - values.forEach((value) => { - res.push(new AutoCompleteItem(value, type)); - }); - return res; - } - - - private autoCompleteItemsUnique(array: Array) { - let 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])) - a.splice(j--, 1); - } + if (photos) { + for (let i = 0; i < photos.length; i++) { + photos[i].metadata.keywords = JSON.parse(photos[i].metadata.keywords); + photos[i].metadata.cameraData = JSON.parse(photos[i].metadata.cameraData); + photos[i].metadata.positionData = JSON.parse(photos[i].metadata.positionData); + photos[i].metadata.size = JSON.parse(photos[i].metadata.size); } + result.photos = photos; + } - return a; + result.directories = await connection + .getRepository(DirectoryEntity) + .createQueryBuilder("dir") + .where('dir.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .getMany(); + + + return cb(null, result); + }).catch((error) => { + return cb(error, null); + }); + } + + instantSearch(text: string, cb: (error: any, result: SearchResultDTO) => void) { + MySQLConnection.getConnection().then(async connection => { + + let result: SearchResultDTO = { + searchText: text, + directories: [], + photos: [] + }; + + let photos = await connection + .getRepository(PhotoEntity) + .createQueryBuilder("photo") + .where('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .orWhere('photo.metadata.positionData LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .orWhere('photo.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .innerJoinAndSelect("photo.directory", "directory") + .setLimit(10) + .getMany(); + + + if (photos) { + for (let i = 0; i < photos.length; i++) { + photos[i].metadata.keywords = JSON.parse(photos[i].metadata.keywords); + photos[i].metadata.cameraData = JSON.parse(photos[i].metadata.cameraData); + photos[i].metadata.positionData = JSON.parse(photos[i].metadata.positionData); + photos[i].metadata.size = JSON.parse(photos[i].metadata.size); + } + result.photos = photos; + } + + let directories = await connection + .getRepository(DirectoryEntity) + .createQueryBuilder("dir") + .where('dir.name LIKE :text COLLATE utf8_general_ci', {text: "%" + text + "%"}) + .setLimit(10) + .getMany(); + + result.directories = directories; + + return cb(null, result); + }).catch((error) => { + return cb(error, null); + }); + } + + private encapsulateAutoComplete(values: Array, type: SearchTypes) { + let res = []; + values.forEach((value) => { + res.push(new AutoCompleteItem(value, type)); + }); + return res; + } + + + private autoCompleteItemsUnique(array: Array) { + let 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])) + a.splice(j--, 1); + } } -} \ No newline at end of file + + return a; + } +} diff --git a/backend/model/mysql/SharingManager.ts b/backend/model/mysql/SharingManager.ts index 02b81487..06810d88 100644 --- a/backend/model/mysql/SharingManager.ts +++ b/backend/model/mysql/SharingManager.ts @@ -6,6 +6,10 @@ import {Config} from "../../../common/config/private/Config"; export class SharingManager implements ISharingManager { + isSupported(): boolean { + return true; + } + private async removeExpiredLink() { const connection = await MySQLConnection.getConnection(); return connection diff --git a/backend/model/mysql/enitites/UserEntity.ts b/backend/model/mysql/enitites/UserEntity.ts index 8003d618..8bf0d282 100644 --- a/backend/model/mysql/enitites/UserEntity.ts +++ b/backend/model/mysql/enitites/UserEntity.ts @@ -20,7 +20,7 @@ export class UserEntity implements UserDTO { @Column("int") role: UserRoles; - @Column("string") + @Column("string", {nullable: true}) permissions: string[]; } diff --git a/backend/server.ts b/backend/server.ts index 8d0d61d6..2c98ee75 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -143,6 +143,19 @@ export class Server { Config.Server.thumbnail.processingLibrary = ThumbnailProcessingLib.Jimp; } } + + if (Config.Client.Search.searchEnabled == true && + ObjectManagerRepository.getInstance().SearchManager.isSupported() == false) { + + Logger.warn(LOG_TAG, "Search is not supported with these settings, switching off.."); + Config.Client.Search.searchEnabled = false; + } + if (Config.Client.Sharing.enabled == true && + ObjectManagerRepository.getInstance().SharingManager.isSupported() == false) { + + Logger.warn(LOG_TAG, "Sharing is not supported with these settings, switching off.."); + Config.Client.Sharing.enabled = false; + } } diff --git a/frontend/app/app.component.ts b/frontend/app/app.component.ts index f5924508..936b045b 100644 --- a/frontend/app/app.component.ts +++ b/frontend/app/app.component.ts @@ -22,7 +22,7 @@ export class AppComponent implements OnInit { this._router.navigate(["gallery", ""]); } } else { - if (this._router.isActive('login', true)) { + if (!this._router.isActive('login', true)) { console.log("routing"); this._router.navigate(["login"]); } diff --git a/frontend/app/frame/frame.component.css b/frontend/app/frame/frame.component.css index d55eeacf..9874daa7 100644 --- a/frontend/app/frame/frame.component.css +++ b/frontend/app/frame/frame.component.css @@ -7,3 +7,34 @@ ng2-slim-loading-bar { display: block; } +.container { + width: 100%; +} + +.admin-link { + padding-bottom: 0; + padding-left: 0; + font-size: 20px; +} + +.divider-vertical:first-child { + display: none; +} + +.navbar .divider-vertical { + height: 30px; + margin: 10px 1px 10px 10px; + border-right: 1px solid #ffffff; + border-left: 1px solid #f2f2f2; +} + +.navbar-inverse .divider-vertical { + border-right-color: #5d5d5d; + border-left-color: #3d3d3d; +} + +@media (max-width: 767px) { + .navbar-collapse .nav > .divider-vertical { + display: none; + } +} diff --git a/frontend/app/frame/frame.component.html b/frontend/app/frame/frame.component.html index 5b703325..52dcb90d 100644 --- a/frontend/app/frame/frame.component.html +++ b/frontend/app/frame/frame.component.html @@ -1,32 +1,45 @@