mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-01-26 05:27:35 +02:00
improving metadata config
This commit is contained in:
parent
268754127d
commit
f4f22118ab
@ -242,7 +242,11 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
|
||||
.leftJoinAndSelect('directory.directories', 'directories')
|
||||
.leftJoinAndSelect('directory.media', 'media');
|
||||
|
||||
if (Config.Client.MetaFile.enabled === true) {
|
||||
// TODO: do better filtering
|
||||
// NOTE: it should not cause an issue as it also do not shave to the DB
|
||||
if (Config.Client.MetaFile.gpx === true ||
|
||||
Config.Client.MetaFile.pg2conf === true ||
|
||||
Config.Client.MetaFile.markdown === true) {
|
||||
query.leftJoinAndSelect('directory.metaFile', 'metaFile');
|
||||
}
|
||||
|
||||
|
@ -65,8 +65,7 @@ export class ConfigDiagnostics {
|
||||
|
||||
|
||||
static async testMetaFileConfig(metaFileConfig: ClientMetaFileConfig, config: IPrivateConfig): Promise<void> {
|
||||
// TODO: now we have metadata for pg2conf files too not only gpx that also runs without map
|
||||
if (metaFileConfig.enabled === true &&
|
||||
if (metaFileConfig.gpx === true &&
|
||||
config.Client.Map.enabled === false) {
|
||||
throw new Error('*.gpx meta files are not supported without MAP');
|
||||
}
|
||||
@ -275,9 +274,9 @@ export class ConfigDiagnostics {
|
||||
await ConfigDiagnostics.testMetaFileConfig(Config.Client.MetaFile, Config);
|
||||
} catch (ex) {
|
||||
const err: Error = ex;
|
||||
NotificationManager.warning('Meta file support error, switching off..', err.toString());
|
||||
NotificationManager.warning('Meta file support error, switching off gpx..', err.toString());
|
||||
Logger.warn(LOG_TAG, 'Meta file support error, switching off..', err.toString());
|
||||
Config.Client.MetaFile.enabled = false;
|
||||
Config.Client.MetaFile.gpx = false;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -174,10 +174,11 @@ export class DiskMangerWorker {
|
||||
}
|
||||
|
||||
} else if (DiskMangerWorker.isMetaFile(fullFilePath)) {
|
||||
if (Config.Client.MetaFile.enabled === false || settings.noMetaFile === true || settings.previewOnly === true) {
|
||||
if (!DiskMangerWorker.isEnabledMetaFile(fullFilePath) ||
|
||||
settings.noMetaFile === true ||
|
||||
settings.previewOnly === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
directory.metaFile.push({
|
||||
name: file,
|
||||
directory: null,
|
||||
@ -197,6 +198,22 @@ export class DiskMangerWorker {
|
||||
return SupportedFormats.WithDots.MetaFiles.indexOf(extension) !== -1;
|
||||
}
|
||||
|
||||
private static isEnabledMetaFile(fullPath: string): boolean {
|
||||
const extension = path.extname(fullPath).toLowerCase();
|
||||
|
||||
switch (extension) {
|
||||
case '.gpx':
|
||||
return Config.Client.MetaFile.gpx;
|
||||
case '.md':
|
||||
return Config.Client.MetaFile.markdown;
|
||||
case '.pg2conf':
|
||||
return Config.Client.MetaFile.pg2conf;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export interface DirectoryScanSettings {
|
||||
|
@ -154,8 +154,12 @@ export class ClientMediaConfig {
|
||||
|
||||
@SubConfigClass()
|
||||
export class ClientMetaFileConfig {
|
||||
@ConfigProperty()
|
||||
enabled: boolean = true;
|
||||
@ConfigProperty({description: 'Reads *.gpx files and renders them on the map'})
|
||||
gpx: boolean = true;
|
||||
@ConfigProperty({description: 'Reads *.md files in a directory and shows the next to the map'})
|
||||
markdown: boolean = true;
|
||||
@ConfigProperty({description: 'Reads *.pg2conf files'})
|
||||
pg2conf: boolean = true;
|
||||
}
|
||||
|
||||
@SubConfigClass()
|
||||
|
@ -2,6 +2,7 @@ import {ClientConfig} from './ClientConfig';
|
||||
import {WebConfigClass} from 'typeconfig/src/decorators/class/WebConfigClass';
|
||||
import {WebConfigClassBuilder} from 'typeconfig/src/decorators/builders/WebConfigClassBuilder';
|
||||
import {ConfigProperty} from 'typeconfig/src/decorators/property/ConfigPropoerty';
|
||||
import {IWebConfigClass} from 'typeconfig/common';
|
||||
|
||||
|
||||
/**
|
||||
@ -20,7 +21,7 @@ declare namespace ServerInject {
|
||||
export const ConfigInject: ClientClass;
|
||||
}
|
||||
|
||||
export let Config = WebConfigClassBuilder.attachInterface(new ClientClass());
|
||||
export let Config: IWebConfigClass & ClientClass = WebConfigClassBuilder.attachInterface(new ClientClass());
|
||||
|
||||
|
||||
if (typeof ServerInject !== 'undefined' && typeof ServerInject.ConfigInject !== 'undefined') {
|
||||
|
@ -106,11 +106,12 @@ import {AlbumsService} from './ui/albums/albums.service';
|
||||
import {GallerySearchQueryBuilderComponent} from './ui/gallery/search/query-builder/query-bulder.gallery.component';
|
||||
import {SavedSearchPopupComponent} from './ui/albums/saved-search-popup/saved-search-popup.component';
|
||||
import {AlbumsSettingsComponent} from './ui/settings/albums/albums.settings.component';
|
||||
import { MarkdownModule } from 'ngx-markdown';
|
||||
import {MarkdownModule} from 'ngx-markdown';
|
||||
import {GalleryBlogComponent} from './ui/gallery/blog/blog.gallery.component';
|
||||
import {MDFilesFilterPipe} from './pipes/MDFilesFilterPipe';
|
||||
import {FileDTOToPathPipe} from './pipes/FileDTOToPathPipe';
|
||||
import {BlogService} from './ui/gallery/blog/blog.service';
|
||||
import {PhotoFilterPipe} from './pipes/PhotoFilterPipe';
|
||||
|
||||
@Injectable()
|
||||
export class MyHammerConfig extends HammerGestureConfig {
|
||||
@ -177,7 +178,7 @@ Marker.prototype.options.icon = iconDefault;
|
||||
LoadingBarModule,
|
||||
LeafletModule,
|
||||
LeafletMarkerClusterModule,
|
||||
MarkdownModule.forRoot({ loader: HttpClient }),
|
||||
MarkdownModule.forRoot({loader: HttpClient}),
|
||||
],
|
||||
declarations: [AppComponent,
|
||||
LoginComponent,
|
||||
@ -250,7 +251,8 @@ Marker.prototype.options.icon = iconDefault;
|
||||
GPXFilesFilterPipe,
|
||||
MDFilesFilterPipe,
|
||||
StringifySearchQuery,
|
||||
FileDTOToPathPipe
|
||||
FileDTOToPathPipe,
|
||||
PhotoFilterPipe
|
||||
],
|
||||
providers: [
|
||||
{provide: HTTP_INTERCEPTORS, useClass: CSRFInterceptor, multi: true},
|
||||
|
@ -1,10 +1,14 @@
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
import {FileDTO} from '../../../common/entities/FileDTO';
|
||||
import {Config} from '../../../common/config/public/Config';
|
||||
|
||||
|
||||
@Pipe({name: 'gpxFiles'})
|
||||
export class GPXFilesFilterPipe implements PipeTransform {
|
||||
transform(metaFiles: FileDTO[]): FileDTO[] | null {
|
||||
if (!Config.Client.MetaFile.gpx) {
|
||||
return [];
|
||||
}
|
||||
if (!metaFiles) {
|
||||
return null;
|
||||
}
|
||||
|
14
src/frontend/app/pipes/PhotoFilterPipe.ts
Normal file
14
src/frontend/app/pipes/PhotoFilterPipe.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
import {MediaDTO, MediaDTOUtils} from '../../../common/entities/MediaDTO';
|
||||
import {PhotoDTO} from '../../../common/entities/PhotoDTO';
|
||||
|
||||
|
||||
@Pipe({name: 'photosOnly'})
|
||||
export class PhotoFilterPipe implements PipeTransform {
|
||||
transform(media: MediaDTO[]): PhotoDTO[] | null {
|
||||
if (!media) {
|
||||
return null;
|
||||
}
|
||||
return media.filter((m: MediaDTO): boolean => MediaDTOUtils.isPhoto(m)) as PhotoDTO[];
|
||||
}
|
||||
}
|
@ -28,78 +28,52 @@
|
||||
|
||||
|
||||
<div body class="container-fluid">
|
||||
<ng-container *ngIf="galleryService.content.value.error">
|
||||
<ng-container *ngIf="ContentWrapper.error">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{{galleryService.content.value.error}}
|
||||
{{ContentWrapper.error}}
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!galleryService.content.value.error">
|
||||
<ng-container *ngIf="galleryService.content.value.directory">
|
||||
<ng-container *ngIf="!ContentWrapper.error && (ContentWrapper.searchResult || ContentWrapper.directory)">
|
||||
<!-- Show search result overflow -->
|
||||
<div class="alert alert-info" role="alert"
|
||||
*ngIf="ContentWrapper.searchResult && ContentWrapper.searchResult.resultOverflow == true" i18n>
|
||||
Too many results to show. Refine your search.
|
||||
</div>
|
||||
|
||||
<app-gallery-navbar [directory]="galleryService.content.value.directory"></app-gallery-navbar>
|
||||
|
||||
<app-gallery-directories class="directories" [directories]="directories"></app-gallery-directories>
|
||||
|
||||
<div class="blog-map-row">
|
||||
<ng-container
|
||||
*ngIf="galleryService.content.value.directory.metaFile && (galleryService.content.value.directory.metaFile | mdFiles).length>0">
|
||||
<app-gallery-blog [collapsed]="!blogOpen"
|
||||
[mdFiles]="galleryService.content.value.directory.metaFile | mdFiles"></app-gallery-blog>
|
||||
<!-- Its safe to hand over both as only one should have a value (search result or dir listing)-->
|
||||
<app-gallery-navbar [searchResult]="ContentWrapper.searchResult"
|
||||
[directory]="ContentWrapper.directory"></app-gallery-navbar>
|
||||
|
||||
|
||||
<button class="btn btn-blog-details" (click)="blogOpen=!blogOpen"><span
|
||||
class="oi oi-chevron-{{blogOpen ? 'top' : 'bottom'}}"></span>
|
||||
</button>
|
||||
</ng-container>
|
||||
<app-gallery-map *ngIf="isPhotoWithLocation && mapEnabled"
|
||||
[photos]="galleryService.content.value.directory.media"
|
||||
[gpxFiles]="galleryService.content.value.directory.metaFile | gpxFiles"></app-gallery-map>
|
||||
</div>
|
||||
<app-gallery-grid [media]="galleryService.content.value.directory.media"
|
||||
[lightbox]="lightbox"></app-gallery-grid>
|
||||
<app-gallery-directories class="directories" [directories]="directories"></app-gallery-directories>
|
||||
|
||||
<div class="blog-map-row">
|
||||
<ng-container
|
||||
*ngIf="config.Client.MetaFile.markdown && Content.metaFile && (Content.metaFile | mdFiles).length>0">
|
||||
<app-gallery-blog [collapsed]="!blogOpen"
|
||||
[mdFiles]="Content.metaFile | mdFiles"></app-gallery-blog>
|
||||
|
||||
|
||||
</ng-container>
|
||||
<!-- Search-->
|
||||
<ng-container *ngIf="galleryService.content.value.searchResult">
|
||||
<div class="alert alert-info" role="alert"
|
||||
*ngIf="galleryService.content.value.searchResult.resultOverflow == true" i18n>
|
||||
Too many results to show. Refine your search.
|
||||
</div>
|
||||
<app-gallery-navbar [searchResult]="galleryService.content.value.searchResult"></app-gallery-navbar>
|
||||
<button class="btn btn-blog-details" (click)="blogOpen=!blogOpen"><span
|
||||
class="oi oi-chevron-{{blogOpen ? 'top' : 'bottom'}}"></span>
|
||||
</button>
|
||||
</ng-container>
|
||||
<app-gallery-map *ngIf="isPhotoWithLocation && mapEnabled"
|
||||
[photos]="Content.media | photosOnly"
|
||||
[gpxFiles]="Content.metaFile | gpxFiles"></app-gallery-map>
|
||||
</div>
|
||||
<app-gallery-grid [media]="Content.media"
|
||||
[lightbox]="lightbox"></app-gallery-grid>
|
||||
|
||||
<app-gallery-directories class="directories" [directories]="directories"></app-gallery-directories>
|
||||
|
||||
<div class="blog-map-row">
|
||||
<ng-container
|
||||
*ngIf="galleryService.content.value.searchResult.metaFile && (galleryService.content.value.searchResult.metaFile | mdFiles).length>0">
|
||||
|
||||
<app-gallery-blog [collapsed]="!blogOpen"
|
||||
[mdFiles]="galleryService.content.value.searchResult.metaFile | mdFiles"></app-gallery-blog>
|
||||
|
||||
<button class="btn btn-blog-details" (click)="blogOpen=!blogOpen"><span
|
||||
class="oi oi-chevron-{{blogOpen ? 'top' : 'bottom'}}"></span>
|
||||
</button>
|
||||
</ng-container>
|
||||
<app-gallery-map *ngIf="isPhotoWithLocation && mapEnabled"
|
||||
[photos]="galleryService.content.value.searchResult.media"
|
||||
[gpxFiles]="galleryService.content.value.searchResult.metaFile | gpxFiles"></app-gallery-map>
|
||||
</div>
|
||||
|
||||
<app-gallery-grid [media]="galleryService.content.value.searchResult.media"
|
||||
[lightbox]="lightbox"></app-gallery-grid>
|
||||
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div body class="container"
|
||||
style="width: 100%; padding:0"
|
||||
*ngIf="(!galleryService.content.value.directory ||
|
||||
galleryService.content.value.directory.isPartial == true)
|
||||
&& !galleryService.content.value.searchResult
|
||||
&& !galleryService.content.value.error">
|
||||
*ngIf="(!ContentWrapper.directory ||
|
||||
ContentWrapper.directory.isPartial == true)
|
||||
&& !ContentWrapper.searchResult
|
||||
&& !ContentWrapper.error">
|
||||
<div class="spinner">
|
||||
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core';
|
||||
import {AuthenticationService} from '../../model/network/authentication.service';
|
||||
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||
import {GalleryService} from './gallery.service';
|
||||
import {ContentWrapperWithError, GalleryService} from './gallery.service';
|
||||
import {GalleryGridComponent} from './grid/grid.gallery.component';
|
||||
import {Config} from '../../../../common/config/public/Config';
|
||||
import {ParentDirectoryDTO, SubDirectoryDTO} from '../../../../common/entities/DirectoryDTO';
|
||||
@ -32,6 +32,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
public showRandomPhotoBuilder = false;
|
||||
public blogOpen = false;
|
||||
|
||||
config = Config;
|
||||
public directories: SubDirectoryDTO[] = [];
|
||||
public isPhotoWithLocation = false;
|
||||
public countDown: { day: number, hour: number, minute: number, second: number } = null;
|
||||
@ -56,6 +57,15 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
PageHelper.showScrollY();
|
||||
}
|
||||
|
||||
get Content(): SearchResultDTO | ParentDirectoryDTO {
|
||||
const cont = (this.ContentWrapper.searchResult || this.ContentWrapper.directory);
|
||||
return cont ? cont : {} as any;
|
||||
}
|
||||
|
||||
get ContentWrapper(): ContentWrapperWithError {
|
||||
return this.galleryService.content.value;
|
||||
}
|
||||
|
||||
updateTimer(t: number): void {
|
||||
if (this.shareService.sharingSubject.value == null) {
|
||||
return;
|
||||
|
@ -31,7 +31,7 @@ export class SettingsEntryComponent implements ControlValueAccessor, Validator,
|
||||
@Input() options: { key: number | string, value: number | string }[];
|
||||
@Input() simplifiedMode = false;
|
||||
@Input() allowSpaces = false;
|
||||
@Input() description: boolean;
|
||||
@Input() description: string;
|
||||
state: {
|
||||
isEnumType: boolean,
|
||||
isConfigType: boolean,
|
||||
|
@ -2,27 +2,31 @@
|
||||
<div class="card mb-4">
|
||||
<h5 class="card-header">
|
||||
{{Name}}
|
||||
<div class="switch-wrapper">
|
||||
<bSwitch
|
||||
class="switch"
|
||||
name="enabled"
|
||||
switch-on-color="success"
|
||||
switch-inverse="true"
|
||||
switch-off-text="Disabled"
|
||||
switch-on-text="Enabled"
|
||||
i18n-switch-off-text
|
||||
i18n-switch-on-text
|
||||
[switch-disabled]="inProgress"
|
||||
switch-handle-width="100"
|
||||
switch-label-width="20"
|
||||
[(ngModel)]="states.enabled.value">
|
||||
</bSwitch>
|
||||
</div>
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||
|
||||
<ng-container i18n>Reads and show *.gpx files on the map and *.md files (blogs) in the gallery.</ng-container>
|
||||
|
||||
<app-settings-entry
|
||||
name="*.gpx files"
|
||||
description="Reads *.gpx files and renders them on the map."
|
||||
i18n-description i18n-name
|
||||
[ngModel]="states.gpx">
|
||||
</app-settings-entry>
|
||||
|
||||
<app-settings-entry
|
||||
name="Markdown files"
|
||||
description="Reads *.md files in a directory and shows the next to the map."
|
||||
i18n-description i18n-name
|
||||
[ngModel]="states.markdown">
|
||||
</app-settings-entry>
|
||||
|
||||
<app-settings-entry
|
||||
name="*.pg2conf files"
|
||||
description="Reads *.md files in a directory and shows the next to the map."
|
||||
i18n-description i18n-name
|
||||
[ngModel]="states.markdown">
|
||||
</app-settings-entry>
|
||||
|
||||
|
||||
<button class="btn btn-success float-right"
|
||||
|
@ -427,10 +427,14 @@ describe('IndexingManager', (sqlHelper: DBTestHelper) => {
|
||||
const p2 = TestHelper.getRandomizedPhotoEntry(parent, 'Photo2');
|
||||
const gpx = TestHelper.getRandomizedGPXEntry(parent, 'GPX1');
|
||||
DirectoryDTOUtils.packDirectory(parent);
|
||||
Config.Client.MetaFile.enabled = true;
|
||||
Config.Client.MetaFile.gpx = true;
|
||||
Config.Client.MetaFile.markdown = true;
|
||||
Config.Client.MetaFile.pg2conf = true;
|
||||
await im.saveToDB(Utils.clone(parent) as ParentDirectoryDTO);
|
||||
|
||||
Config.Client.MetaFile.enabled = false;
|
||||
Config.Client.MetaFile.gpx = false;
|
||||
Config.Client.MetaFile.markdown = false;
|
||||
Config.Client.MetaFile.pg2conf = false;
|
||||
const conn = await SQLConnection.getConnection();
|
||||
const selected = await gm.selectParentDir(conn, parent.name, parent.path);
|
||||
await gm.fillParentDir(conn, selected);
|
||||
@ -481,7 +485,9 @@ describe('IndexingManager', (sqlHelper: DBTestHelper) => {
|
||||
const conn = await SQLConnection.getConnection();
|
||||
const gm = new GalleryManagerTest();
|
||||
const im = new IndexingManagerTest();
|
||||
Config.Client.MetaFile.enabled = true;
|
||||
Config.Client.MetaFile.gpx = true;
|
||||
Config.Client.MetaFile.markdown = true;
|
||||
Config.Client.MetaFile.pg2conf = true;
|
||||
const parent = TestHelper.getRandomizedDirectoryEntry();
|
||||
const p1 = TestHelper.getRandomizedPhotoEntry(parent, 'Photo1');
|
||||
const p2 = TestHelper.getRandomizedPhotoEntry(parent, 'Photo2');
|
||||
@ -544,7 +550,9 @@ describe('IndexingManager', (sqlHelper: DBTestHelper) => {
|
||||
const conn = await SQLConnection.getConnection();
|
||||
const gm = new GalleryManagerTest();
|
||||
const im = new IndexingManagerTest();
|
||||
Config.Client.MetaFile.enabled = true;
|
||||
Config.Client.MetaFile.gpx = true;
|
||||
Config.Client.MetaFile.markdown = true;
|
||||
Config.Client.MetaFile.pg2conf = true;
|
||||
const parent = TestHelper.getRandomizedDirectoryEntry();
|
||||
DirectoryDTOUtils.packDirectory(parent);
|
||||
await im.saveToDB(Utils.clone(parent) as ParentDirectoryDTO);
|
||||
|
Loading…
x
Reference in New Issue
Block a user