1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2025-12-01 22:52:06 +02:00

Implement search query based sharing on the UI #1015

This commit is contained in:
Patrik J. Braun
2025-08-17 18:09:18 +02:00
parent 31ef7e8470
commit 504595fc68
12 changed files with 175 additions and 43 deletions

View File

@@ -8,7 +8,7 @@ import {QueryParams} from '../../../../common/QueryParams';
import {UserDTO, UserRoles} from '../../../../common/entities/UserDTO';
import {Utils} from '../../../../common/Utils';
import {Config} from '../../../../common/config/public/Config';
import {SearchQueryTypes, TextSearch, TextSearchQueryMatchTypes} from '../../../../common/entities/SearchQueryDTO';
import {SearchQueryDTO, SearchQueryTypes, TextSearch, TextSearchQueryMatchTypes} from '../../../../common/entities/SearchQueryDTO';
@Injectable()
@@ -106,6 +106,7 @@ export class ShareService {
password: string,
valid: number
): Promise<SharingDTO> {
// Legacy dir-based API: backend will convert to strict directory searchQuery if searchQuery not provided
return this.networkService.postJson('/share/' + dir, {
createSharing: {
valid,
@@ -114,12 +115,27 @@ export class ShareService {
});
}
public createSharingByQuery(
searchQuery: SearchQueryDTO,
password: string,
valid: number
): Promise<SharingDTO> {
return this.networkService.postJson('/share/', {
createSharing: {
valid,
...(!!password && {password: password}),
searchQuery
} as CreateSharingDTO,
});
}
public updateSharing(
dir: string,
sharingId: number,
password: string,
valid: number
): Promise<SharingDTO> {
// Legacy dir-based API: backend will convert to strict directory searchQuery if searchQuery not provided
return this.networkService.putJson('/share/' + dir, {
updateSharing: {
id: sharingId,
@@ -129,6 +145,22 @@ export class ShareService {
});
}
public updateSharingByQuery(
sharingId: number,
searchQuery: SearchQueryDTO,
password: string,
valid: number
): Promise<SharingDTO> {
return this.networkService.putJson('/share/', {
updateSharing: {
id: sharingId,
valid,
password,
searchQuery
} as CreateSharingDTO,
});
}
public getSharingKey(): string {
return this.sharingKey;
}
@@ -166,11 +198,17 @@ export class ShareService {
public async getSharingListForDir(
dir: string
): Promise<SharingDTO[]> {
return this.networkService.getJson('/share/list/' + JSON.stringify({
return this.getSharingListForQuery({
type: SearchQueryTypes.directory,
text: dir,
matchType: TextSearchQueryMatchTypes.exact_match
} as TextSearch));
} as TextSearch);
}
public async getSharingListForQuery(
query: SearchQueryDTO
): Promise<SharingDTO[]> {
return this.networkService.getJson('/share/list/' + JSON.stringify(query));
}

View File

@@ -60,27 +60,10 @@
name="sharing-dir"
id="sharing-dir"
class="full-width form-control"
[ngModel]="currentDir">
[ngModel]="galleryService.isSearchResult() ? (currentQuery | searchQuery) : sharingTarget">
</div>
</div>
<div class="row">
<div class="col-4">
<label class="control-label" for="includeSubfolders" i18n>Include subfolders:</label>
</div>
<div class="col-8">
<div class="form-check form-switch">
<input class="form-check-input"
type="checkbox"
role="switch"
id="includeSubfolders"
name="includeSubfolders"
title="Orientation"
(change)="update()"
[(ngModel)]="input.includeSubfolders">
</div>
</div>
</div>
<div class="row">
<div class="col-4">

View File

@@ -15,6 +15,8 @@ import {ContentLoaderService} from '../contentLoader.service';
import { NgIf, NgFor, DatePipe } from '@angular/common';
import { NgIconComponent } from '@ng-icons/core';
import { FormsModule } from '@angular/forms';
import { SearchQueryDTO, SearchQueryTypes, TextSearch, TextSearchQueryMatchTypes } from '../../../../../common/entities/SearchQueryDTO';
import { StringifySearchQuery } from '../../../pipes/StringifySearchQuery';
@Component({
selector: 'app-gallery-share',
@@ -27,6 +29,7 @@ import { FormsModule } from '@angular/forms';
ClipboardModule,
NgFor,
DatePipe,
StringifySearchQuery,
]
})
export class GalleryShareComponent implements OnInit, OnDestroy {
@@ -44,6 +47,8 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
password: null as string,
};
currentDir = '';
currentQuery: SearchQueryDTO = null;
sharingTarget = '';
sharing: SharingDTO = null;
contentSubscription: Subscription = null;
readonly passwordRequired = Config.Sharing.passwordRequired;
@@ -79,14 +84,30 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
this.contentSubscription = this.galleryService.content.subscribe(
async (content: ContentWrapper) => {
this.activeShares = [];
this.enabled = !!content.directory;
if (!this.enabled) {
return;
}
this.currentDir = Utils.concatUrls(
this.enabled = !!(content.directory || (content as any).searchResult);
this.currentDir = '';
this.currentQuery = null;
this.sharingTarget = '';
if ((content as any).searchResult) {
this.currentQuery = (content as any).searchResult.searchQuery as SearchQueryDTO;
this.sharingTarget = $localize`Search query`;
} else if (content.directory) {
this.currentDir = Utils.concatUrls(
content.directory.path,
content.directory.name
);
);
this.currentQuery = {
type: SearchQueryTypes.directory,
text: this.currentDir,
matchType: TextSearchQueryMatchTypes.exact_match
} as TextSearch;
this.sharingTarget = this.currentDir;
}
if (!this.enabled || !this.currentQuery) {
return;
}
await this.updateActiveSharesList();
}
);
@@ -106,7 +127,11 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
private async updateActiveSharesList() {
try {
this.activeShares = await this.sharingService.getSharingListForDir(this.currentDir);
if (!this.currentQuery) {
this.activeShares = [];
return;
}
this.activeShares = await this.sharingService.getSharingListForQuery(this.currentQuery);
} catch (e) {
this.activeShares = [];
console.error(e);
@@ -130,14 +155,14 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
}
async update(): Promise<void> {
if (this.sharing == null) {
if (this.sharing == null || !this.currentQuery) {
return;
}
this.urlValid = false;
this.url = $localize`loading..`;
this.sharing = await this.sharingService.updateSharing(
this.currentDir,
this.sharing = await this.sharingService.updateSharingByQuery(
this.sharing.id,
this.currentQuery,
this.input.password,
this.calcValidity()
);
@@ -151,10 +176,14 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
this.url = $localize`Set password.`;
return;
}
if (!this.currentQuery) {
this.url = $localize`Invalid settings`;
return;
}
this.urlValid = false;
this.url = $localize`loading..`;
this.sharing = await this.sharingService.createSharing(
this.currentDir,
this.sharing = await this.sharingService.createSharingByQuery(
this.currentQuery,
this.input.password,
this.calcValidity()
);

View File

@@ -12,7 +12,7 @@
<thead>
<tr>
<th i18n>Key</th>
<th i18n>Folder</th>
<th i18n>Sharing</th>
<th i18n>Creator</th>
<th i18n>Expires</th>
<th></th>
@@ -21,7 +21,7 @@
<tbody>
<tr *ngFor="let share of shares">
<td><a [href]="sharingService.getUrl(share)">{{share.sharingKey}}</a></td>
<td>{{share.path}}</td>
<td>{{share.searchQuery | searchQuery}}</td>
<td>{{share.creator.name}}</td>
<td>{{share.expires | date}}</td>
<td>

View File

@@ -4,12 +4,13 @@ import {SettingsService} from '../settings.service';
import {ShareService} from '../../gallery/share.service';
import { NgIf, NgFor, DatePipe } from '@angular/common';
import { NgIconComponent } from '@ng-icons/core';
import { StringifySearchQuery } from '../../../pipes/StringifySearchQuery';
@Component({
selector: 'app-settigns-sharings-list',
templateUrl: './sharings-list.component.html',
styleUrls: ['./sharings-list.component.css'],
imports: [NgIf, NgFor, NgIconComponent, DatePipe]
imports: [NgIf, NgFor, NgIconComponent, DatePipe, StringifySearchQuery]
})
export class SharingsListComponent implements OnInit {