Skip to content

Commit

Permalink
fix: allows to download original asset (DEV-4402) (#1953)
Browse files Browse the repository at this point in the history
  • Loading branch information
irmastnt authored Dec 2, 2024
1 parent 9c1ebab commit 517bceb
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #more="matMenu" class="representation-menu">
<button
class="menu-content"
mat-menu-item
(click)="download(src.fileValue.fileUrl)"
data-cy="download-file-button">
<button class="menu-content" mat-menu-item (click)="download()" data-cy="download-file-button">
Download file
</button>
<button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ export class ArchiveComponent implements OnChanges {
}
}

download(url: string) {
this._rs.downloadFile(url);
download() {
this._rs.downloadProjectFile(this.src.fileValue, this.parentResource);
}

openReplaceFileDialog() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class AudioMoreButtonComponent {
}

download(url: string) {
this._rs.downloadFile(url);
this._rs.downloadProjectFile(this.src.fileValue, this.parentResource);
}

private _replaceFile(file: UpdateFileValue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #more="matMenu" class="representation-menu">
<button class="menu-content" mat-menu-item (click)="download(src.fileValue.fileUrl)">Download file</button>
<button class="menu-content" mat-menu-item (click)="download(src.fileValue)">Download file</button>
<button [disabled]="!usercanEdit" class="menu-content" mat-menu-item (click)="openReplaceFileDialog()">
Replace file
</button>
Expand Down Expand Up @@ -111,7 +111,7 @@
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #more="matMenu" class="mat-menu-custom-black">
<button class="menu-content" mat-menu-item (click)="download(src.fileValue.fileUrl)" [disabled]="failedToLoad">
<button class="menu-content" mat-menu-item (click)="download(src.fileValue)" [disabled]="failedToLoad">
Download file
</button>
<button [disabled]="!usercanEdit" class="menu-content" mat-menu-item (click)="openReplaceFileDialog()">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ export class DocumentComponent implements OnChanges {
}
}

download(url: string) {
this._rs.downloadFile(url);
download(fileValue: ReadDocumentFileValue) {
this._rs.downloadProjectFile(fileValue, this.parentResource);
}

openReplaceFileDialog() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import { HttpClient } from '@angular/common/http';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ReadProject, ReadResource } from '@dasch-swiss/dsp-js';
import {
ReadArchiveFileValue,
ReadAudioFileValue,
ReadDocumentFileValue,
ReadMovingImageFileValue,
ReadProject,
ReadResource,
ReadStillImageExternalFileValue,
ReadStillImageFileValue,
} from '@dasch-swiss/dsp-js';
import { ResourceUtil } from '@dasch-swiss/vre/shared/app-common';
import { AppConfigService } from '@dasch-swiss/vre/shared/app-config';
import { AppError } from '@dasch-swiss/vre/shared/app-error-handler';
import { AccessTokenService } from '@dasch-swiss/vre/shared/app-session';
import { IKeyValuePairs, ResourceSelectors } from '@dasch-swiss/vre/shared/app-state';
import { IKeyValuePairs, ResourceSelectors, UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';
Expand All @@ -30,6 +41,16 @@ export class RepresentationService {
return this._http.get<FileInfo>(url);
}

getIiifFileInfo(fileName: string, projectShort: string): Observable<FileInfo> {
const url = `${this._appConfigService.dspIiifConfig.iiifUrl}/${projectShort}/${fileName}/knora.json`;
return this._http.get<FileInfo>(url);
}

getIngestFileUrl(projectShort: string, assetId: string): string {
const url = `${this._appConfigService.dspIngestConfig.url}/projects/${projectShort}/assets/${assetId}`;
return url;
}

getAttachedProject(parentResource: ReadResource): ReadProject | undefined {
const attachedProjects = this._store.selectSnapshot(ResourceSelectors.attachedProjects);
return this.getParentResourceAttachedProject(attachedProjects, parentResource);
Expand All @@ -41,24 +62,61 @@ export class RepresentationService {
: undefined;
}

downloadFile(url: string, fileName?: string, withCredentials = true) {
userCanView(fileValue: ReadDocumentFileValue) {
return fileValue && ResourceUtil.userCanView(fileValue);
}

downloadProjectFile(
fileValue:
| ReadAudioFileValue
| ReadDocumentFileValue
| ReadMovingImageFileValue
| ReadStillImageFileValue
| ReadStillImageExternalFileValue
| ReadArchiveFileValue,
resource: ReadResource
) {
const attachedProject = this.getParentResourceAttachedProject(
this._store.selectSnapshot(ResourceSelectors.attachedProjects),
resource
)!;
if (!attachedProject) {
throw new AppError('Project is not present');
}

const assetId = fileValue.filename.split('.')[0] || '';
const ingestFileUrl = this.getIngestFileUrl(attachedProject.shortcode, assetId);
this.downloadFile(ingestFileUrl, this.userCanView(fileValue));
}

private downloadFile(url: string, userCanView = true) {
let headers = {};
const isLoggedIn = this._store.selectSnapshot(UserSelectors.isLoggedIn);
const withCredentials = isLoggedIn && userCanView;
if (withCredentials) {
const authToken = this._accessTokenService.getAccessToken();
headers = { Authorization: `Bearer ${authToken}` };
headers = {
Authorization: `Bearer ${authToken}`,
};
}

this._http
.get(url, {
.get(userCanView ? `${url}/original` : url, {
responseType: 'blob',
withCredentials,
headers,
observe: 'response',
})
.pipe(take(1))
.subscribe(res => {
.subscribe((res: HttpResponse<Blob>) => {
const contentDisposition = res.headers.get('content-disposition');
const fileNameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = fileNameRegex.exec(contentDisposition || '');
const fileName =
contentDisposition && matches != null && matches[1] ? matches[1].replace(/['"]/g, '') : url.split('/').pop()!;
const a = document.createElement('a');
a.href = window.URL.createObjectURL(res);
a.download = fileName || url.split('/').pop()!;
a.href = window.URL.createObjectURL(res.body!);
a.download = fileName;
a.click();
window.URL.revokeObjectURL(a.href);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { DomSanitizer } from '@angular/platform-browser';
import {
Constants,
KnoraApiConnection,
ReadProject,
ReadResource,
ReadStillImageExternalFileValue,
ReadStillImageFileValue,
Expand All @@ -17,8 +16,6 @@ import { DspApiConnectionToken, DspDialogConfig } from '@dasch-swiss/vre/shared/
import { AppError } from '@dasch-swiss/vre/shared/app-error-handler';
import { ProjectService } from '@dasch-swiss/vre/shared/app-helper-services';
import { NotificationService } from '@dasch-swiss/vre/shared/app-notification';
import { UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Store } from '@ngxs/store';
import { filter, switchMap } from 'rxjs/operators';
import { EditThirdPartyIiifFormComponent } from '../edit-third-party-iiif-form/edit-third-party-iiif-form.component';
import { ThirdPartyIiifProps } from '../edit-third-party-iiif-form/edit-third-party-iiif-types';
Expand Down Expand Up @@ -51,7 +48,6 @@ export class StillImageToolbarComponent {
@Input({ required: true }) resource!: ReadResource;
@Input({ required: true }) compoundMode!: boolean;
@Input({ required: true }) isPng!: boolean;
@Input() attachedProject: ReadProject | undefined;
@Output() imageIsPng = new EventEmitter<boolean>();

get imageFileValue() {
Expand Down Expand Up @@ -82,7 +78,6 @@ export class StillImageToolbarComponent {
public notification: NotificationService,
@Inject(DspApiConnectionToken)
private _dspApiConnection: KnoraApiConnection,
private _store: Store,
public resourceFetcherService: ResourceFetcherService,
private _rs: RepresentationService,
private _dialog: MatDialog,
Expand All @@ -98,21 +93,7 @@ export class StillImageToolbarComponent {
}

download() {
const projectShort = this.attachedProject?.shortcode;
const assetId = this.imageFileValue.filename.split('.')[0] || '';

if (!projectShort) {
throw new AppError('Error with project shortcode');
}

const isLoggedIn = this._store.selectSnapshot(UserSelectors.isLoggedIn);
if (isLoggedIn && this.userCanView) {
this._rs.getIngestFileInfo(projectShort, assetId).subscribe(response => {
this._rs.downloadFile(this.imageFileValue.fileUrl, response.originalFilename);
});
} else {
this._rs.downloadFile(this.imageFileValue.fileUrl, this.imageFileValue.filename, false);
}
this._rs.downloadProjectFile(this.imageFileValue, this.resource);
}

replaceImage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import { StillImageHelper } from './still-image-helper';
<app-still-image-toolbar
*ngIf="isViewInitialized"
[resource]="resource"
[attachedProject]="attachedProject$ | async"
[compoundMode]="compoundMode"
[isPng]="isPng"
(imageIsPng)="afterFormatChange($event)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { MatDialog } from '@angular/material/dialog';
import {
Constants,
KnoraApiConnection,
ReadProject,
ReadResource,
ReadTextFileValue,
UpdateFileValue,
Expand All @@ -13,6 +12,8 @@ import {
} from '@dasch-swiss/dsp-js';
import { ResourceUtil } from '@dasch-swiss/vre/shared/app-common';
import { DspApiConnectionToken } from '@dasch-swiss/vre/shared/app-config';
import { ResourceSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Store } from '@ngxs/store';
import { mergeMap } from 'rxjs/operators';
import { FileRepresentation } from '../file-representation';
import {
Expand All @@ -28,7 +29,6 @@ import { RepresentationService } from '../representation.service';
})
export class TextComponent implements OnChanges {
@Input() src: FileRepresentation;
@Input() attachedProject: ReadProject | undefined;
@Input() parentResource: ReadResource;

originalFilename: string;
Expand All @@ -43,7 +43,8 @@ export class TextComponent implements OnChanges {
@Inject(DspApiConnectionToken)
private _dspApiConnection: KnoraApiConnection,
private _dialog: MatDialog,
private _rs: RepresentationService
private _rs: RepresentationService,
private _store: Store
) {}

ngOnChanges(): void {
Expand All @@ -58,17 +59,21 @@ export class TextComponent implements OnChanges {
}

download(url: string) {
this._rs.downloadFile(url);
this._rs.downloadProjectFile(this.src.fileValue, this.parentResource);
}

openReplaceFileDialog() {
const attachedProject = this._rs.getParentResourceAttachedProject(
this._store.selectSnapshot(ResourceSelectors.attachedProjects),
this.parentResource
)!;
this._dialog
.open<ReplaceFileDialogComponent, ReplaceFileDialogProps>(ReplaceFileDialogComponent, {
data: {
title: 'Text (csv, txt, xml)',
subtitle: 'Update the text file of this resource',
representation: Constants.HasTextFileValue,
projectUuid: this.attachedProject!.id,
projectUuid: attachedProject!.id,
propId: this.parentResource.properties[Constants.HasTextFileValue][0].id,
},
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { HttpClient } from '@angular/common/http';
import { Component, Inject, Input } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import {
Expand Down Expand Up @@ -61,8 +60,7 @@ export class VideoMoreButtonComponent {
private _dialog: MatDialog,
@Inject(DspApiConnectionToken)
private _dspApiConnection: KnoraApiConnection,
private _rs: RepresentationService,
private readonly _http: HttpClient
private _rs: RepresentationService
) {}

openVideoInNewTab(url: string) {
Expand All @@ -74,8 +72,7 @@ export class VideoMoreButtonComponent {
}

async downloadVideo(url: string) {
const res = await this._http.get(url, { responseType: 'blob', withCredentials: true }).toPromise();
this._downloadFile(res);
this._rs.downloadProjectFile(this.src.fileValue, this.parentResource);
}

openReplaceFileDialog() {
Expand Down Expand Up @@ -127,20 +124,4 @@ export class VideoMoreButtonComponent {
window.location.reload();
});
}

private _downloadFile(data: Blob) {
const url = window.URL.createObjectURL(data);
const linkElement = document.createElement('a');
linkElement.href = url;

if (this.fileInfo?.originalFilename === undefined) {
linkElement.download = url.substring(url.lastIndexOf('/') + 1);
} else {
linkElement.download = this.fileInfo.originalFilename;
}

document.body.appendChild(linkElement);
linkElement.click();
document.body.removeChild(linkElement);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { Component, Input, OnChanges } from '@angular/core';
import { ReadProject } from '@dasch-swiss/dsp-js';
import {
FileRepresentation,
getFileValue,
RepresentationConstants,
RepresentationService,
getFileValue,
} from '@dasch-swiss/vre/resource-editor/representations';
import { DspResource } from '@dasch-swiss/vre/shared/app-common';
import { ProjectService } from '@dasch-swiss/vre/shared/app-helper-services';
import { ResourceSelectors, UserSelectors } from '@dasch-swiss/vre/shared/app-state';
import { Store } from '@ngxs/store';
import { combineLatest, Observable } from 'rxjs';
import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';

@Component({
Expand Down Expand Up @@ -62,17 +62,15 @@ import { map } from 'rxjs/operators';
class="dsp-representation archive"
*ngSwitchCase="representationConstants.archive"
[src]="representationToDisplay"
[parentResource]="resource.res"
[attachedProject]="attachedProject$ | async">
[parentResource]="resource.res">
</app-archive>
<app-text
#text
class="dsp-representation text"
*ngSwitchCase="representationConstants.text"
[src]="representationToDisplay"
[parentResource]="resource.res"
[attachedProject]="attachedProject$ | async">
[parentResource]="resource.res">
</app-text>
</div>`,
})
Expand Down

0 comments on commit 517bceb

Please sign in to comment.