Newer
Older
* Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
import { BlobWithFileName, createEmptyStateResource, createErrorStateResource, createStateResource, EMPTY_ARRAY, EMPTY_STRING, getMessageForInvalidParam, HttpError, HttpHeader, isNotNil, isUnprocessableEntity, isValidationFieldFileSizeExceedError, sanitizeFileName, StateResource, } from '@alfa-client/tech-shared';
import { SnackBarService } from '@alfa-client/ui';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { getUrl, Resource, ResourceUri } from '@ngxp/rest';
import { saveAs } from 'file-saver';
import { isNil } from 'lodash-es';
import { BehaviorSubject, forkJoin, Observable, of, throwError } from 'rxjs';
import { catchError, map, mergeMap, startWith, switchMap } from 'rxjs/operators';
import { BinaryFileListResource, BinaryFileResource, FileUploadType, ToUploadFile, UploadFile, UploadFilesByType, } from './binary-file.model';
import { BinaryFileRepository } from './binary-file.repository';
@Injectable({ providedIn: 'root' })
export class BinaryFileService {
uploadFiles: BehaviorSubject<UploadFilesByType> = new BehaviorSubject({});
constructor(
private repository: BinaryFileRepository,
private snackbarService: SnackBarService,
) {}
public isUploadInProgress(type: FileUploadType): Observable<boolean> {
return this.uploadFiles.asObservable().pipe(
map((files: UploadFilesByType) => files[type].map((file: UploadFile) => file.uploadedFile)),
switchMap((files: Observable<StateResource<BinaryFileResource>>[]) => forkJoin(files)),
map((files: StateResource<BinaryFileResource>[]) => files.some((s) => s.loading)),
);
public getUploadedFiles(type: FileUploadType): Observable<UploadFile[]> {
return this.uploadFiles.asObservable().pipe(map((files: UploadFilesByType) => files[type]));
public deleteUploadedFile(type: FileUploadType, key: string): void {
//Implement me
}
public clearUploadedFiles(type: FileUploadType): void {
//Implement me
}
public uploadFileNew(toUploadFile: ToUploadFile): void {
if (!(toUploadFile.uploadUrl in this.uploadFiles.value)) this.uploadFiles.value[toUploadFile.type] = EMPTY_ARRAY;
this.uploadFiles.value[toUploadFile.type].push(this._buildUploadFile(toUploadFile));
}
_buildUploadFile(toUploadFile: ToUploadFile): UploadFile {
return {
fileToUpload: toUploadFile.file,
uploadedFile: this._handleUpload(toUploadFile),
};
}
_handleUpload(toUploadFile: ToUploadFile): Observable<StateResource<BinaryFileResource>> {
return this.repository.uploadFileNew(toUploadFile.uploadUrl, toUploadFile.file).pipe(
map((binaryFileResource: BinaryFileResource) => createStateResource(binaryFileResource)),
catchError((response: any) => of(createErrorStateResource(<HttpError>response.error))),
startWith(createEmptyStateResource<BinaryFileResource>(true)),
);
}
//TODO Rename to uploadFileOld OR refactor all use cases to uploadFileNew
public uploadFile(
resource: Resource,
linkRel: string,
file: File,
showValidationErrorSnackBar: boolean = true,
): Observable<StateResource<BinaryFileResource>> {
return this.repository.uploadFile(getUrl(resource, linkRel), file).pipe(
mergeMap((response: HttpResponse<Object>) => this.getFile(response.headers.get(HttpHeader.LOCATION))),
catchError((errorResponse) => this.handleError(errorResponse.error, showValidationErrorSnackBar)),
startWith(createEmptyStateResource<BinaryFileResource>(true)),
);
}
private handleError(errorResponse: HttpErrorResponse, showValidationErrorSnackBar: boolean): Observable<StateResource<any>> {
return of(this.handleErrorByStatus(errorResponse, showValidationErrorSnackBar));
handleErrorByStatus(error: HttpErrorResponse, showValidationErrorSnackBar: boolean): StateResource<any> {
if (isUnprocessableEntity(error.status)) {
this.handleSnackBar(error, showValidationErrorSnackBar);
return createErrorStateResource(error.error);
}
throwError({ error });
}
handleSnackBar(error: HttpErrorResponse, showValidationErrorSnackBar: boolean) {
if (showValidationErrorSnackBar && isValidationFieldFileSizeExceedError(error.error)) {
this.snackbarService.showError(getMessageForInvalidParam(EMPTY_STRING, error.error.invalidParams[0]));
public downloadFile(file: BinaryFileResource, fileNamePrefix: string): Observable<StateResource<Blob>> {
return this.repository.download(file).pipe(
map((data) => this.saveBinaryFile(data, file, fileNamePrefix)),
startWith(createEmptyStateResource<Blob>(true)),
catchError(() => this.handleDownloadError()),
handleDownloadError(): Observable<StateResource<Blob>> {
this.snackbarService.showError('Die Datei konnte nicht heruntergeladen werden.');
saveBinaryFile(data: any, file: BinaryFileResource, fileNamePrefix: string): StateResource<Blob> {
if (isNil(data)) {
return createEmptyStateResource(true);
}
this.save(data, this.buildFileName(file, fileNamePrefix));
return createStateResource(data);
}
private buildFileName(file: BinaryFileResource, fileNamePrefix: string): string {
if (isNotNil(fileNamePrefix)) {
return sanitizeFileName(`${fileNamePrefix}_${file.name}`);
}
return file.name;
}
public downloadArchive(uri: ResourceUri): Observable<StateResource<Blob>> {
return this.repository.downloadArchive(uri).pipe(
map((data: BlobWithFileName) => this.saveData(data)),
startWith(createEmptyStateResource<Blob>(true)),
);
}
saveData(dataWithFileName: BlobWithFileName): StateResource<Blob> {
const data: Blob = dataWithFileName.blob;
if (isNil(data)) {
return createEmptyStateResource(true);
}
this.save(data, dataWithFileName.fileName);
return createStateResource(data);
}
save(data: any, fileName: string): void {
saveAs(data, fileName);
}
public getFile(uri: ResourceUri): Observable<StateResource<BinaryFileResource>> {
map((fileList: BinaryFileResource) => createStateResource(fileList)),
startWith(createEmptyStateResource<BinaryFileResource>(true)),
public getFiles(resource: Resource, linkRel: string): Observable<StateResource<BinaryFileListResource>> {
return this.repository.getFiles(resource, linkRel).pipe(
map((fileList: BinaryFileListResource) => createStateResource(fileList)),