Merge pull request #5505 from tsiegleauq/multiple-file-download
Download mutliple files as zip
This commit is contained in:
commit
c6abbb629e
@ -59,6 +59,7 @@
|
||||
"css-element-queries": "^1.2.3",
|
||||
"exceljs": "1.15.0",
|
||||
"file-saver": "^2.0.2",
|
||||
"jszip": "^3.5.0",
|
||||
"lz4js": "^0.2.0",
|
||||
"material-icon-font": "git+https://github.com/petergng/materialIconFont.git",
|
||||
"moment": "^2.24.0",
|
||||
|
@ -273,4 +273,26 @@ export class HttpService {
|
||||
public async delete<T>(path: string, data?: any, queryParams?: QueryParams, header?: HttpHeaders): Promise<T> {
|
||||
return await this.send<T>(path, HTTPMethod.DELETE, data, queryParams, header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a binary file from the url and returns a base64 value
|
||||
*
|
||||
* @param url file url
|
||||
* @returns a promise with a base64 string
|
||||
*/
|
||||
public async downloadAsBase64(url: string): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
const headers = new HttpHeaders();
|
||||
const file = await this.get<Blob>(url, {}, {}, headers, 'blob');
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => {
|
||||
const resultStr: string = reader.result as string;
|
||||
resolve(resultStr.split(',')[1]);
|
||||
};
|
||||
reader.onerror = error => {
|
||||
reject(error);
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@ -100,7 +99,7 @@ export class PdfDocumentService {
|
||||
);
|
||||
|
||||
const promises = fontPathList.map(fontPath => {
|
||||
return this.convertUrlToBase64(fontPath).then(base64 => {
|
||||
return this.httpService.downloadAsBase64(fontPath).then(base64 => {
|
||||
return {
|
||||
[fontPath.split('/').pop()]: base64
|
||||
};
|
||||
@ -117,29 +116,6 @@ export class PdfDocumentService {
|
||||
return vfs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a binary file from the url and returns a base64 value
|
||||
*
|
||||
* @param url file url
|
||||
* @returns a promise with a base64 string
|
||||
*/
|
||||
private async convertUrlToBase64(url: string): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const headers = new HttpHeaders();
|
||||
this.httpService.get<Blob>(url, {}, {}, headers, 'blob').then(file => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => {
|
||||
const resultStr: string = reader.result as string;
|
||||
resolve(resultStr.split(',')[1]);
|
||||
};
|
||||
reader.onerror = error => {
|
||||
reject(error);
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a font from the value of the given
|
||||
* config variable.
|
||||
@ -665,7 +641,7 @@ export class PdfDocumentService {
|
||||
}
|
||||
|
||||
if (!vfs[url]) {
|
||||
const base64 = await this.convertUrlToBase64(url);
|
||||
const base64 = await this.httpService.downloadAsBase64(url);
|
||||
vfs[url] = base64;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ import { HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { saveAs } from 'file-saver';
|
||||
import * as JSZip from 'jszip';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
|
||||
@ -136,6 +138,18 @@ export class MediafileRepositoryService extends BaseIsListOfSpeakersContentObjec
|
||||
return this.httpService.post<Identifiable>('/rest/mediafiles/mediafile/', file, {}, emptyHeader);
|
||||
}
|
||||
|
||||
public async downloadArchive(archiveName: string, files: ViewMediafile[]): Promise<void> {
|
||||
const zip = new JSZip();
|
||||
for (const file of files) {
|
||||
if (!file.is_directory) {
|
||||
const base64Data = await this.httpService.downloadAsBase64(file.url);
|
||||
zip.file(file.filename, base64Data, { base64: true });
|
||||
}
|
||||
}
|
||||
const archive = await zip.generateAsync({ type: 'blob' });
|
||||
saveAs(archive, archiveName);
|
||||
}
|
||||
|
||||
public getDirectoryBehaviorSubject(): BehaviorSubject<ViewMediafile[]> {
|
||||
return this.directoryBehaviorSubject;
|
||||
}
|
||||
|
@ -229,12 +229,20 @@
|
||||
<!-- Menu for Mediafiles -->
|
||||
<mat-menu #mediafilesMenu="matMenu">
|
||||
<div *ngIf="!isMultiSelect">
|
||||
<button mat-menu-item (click)="downloadMultiple()">
|
||||
<mat-icon>cloud_download</mat-icon>
|
||||
<span>{{ 'Download folder' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item *osPerms="'mediafiles.can_manage'" (click)="toggleMultiSelect()">
|
||||
<mat-icon>library_add</mat-icon>
|
||||
<span>{{ 'Multiselect' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="isMultiSelect">
|
||||
<button mat-menu-item [disabled]="!selectedRows.length" (click)="downloadMultiple(selectedRows)">
|
||||
<mat-icon>cloud_download</mat-icon>
|
||||
<span>{{ 'Download selected' | translate }}</span>
|
||||
</button>
|
||||
<button mat-menu-item [disabled]="!selectedRows.length" (click)="move(moveDialog, selectedRows)">
|
||||
<mat-icon>near_me</mat-icon>
|
||||
<span>{{ 'Move' | translate }}</span>
|
||||
|
@ -23,6 +23,7 @@ import { OperatorService, Permission } from 'app/core/core-services/operator.ser
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { MediaManageService } from 'app/core/ui-services/media-manage.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||
@ -202,7 +203,8 @@ export class MediafileListComponent extends BaseListViewComponent<ViewMediafile>
|
||||
private fb: FormBuilder,
|
||||
private formBuilder: FormBuilder,
|
||||
private groupRepo: GroupRepositoryService,
|
||||
private cd: ChangeDetectorRef
|
||||
private cd: ChangeDetectorRef,
|
||||
private configService: ConfigService
|
||||
) {
|
||||
super(titleService, translate, matSnackBar, storage);
|
||||
this.canMultiSelect = true;
|
||||
@ -459,6 +461,16 @@ export class MediafileListComponent extends BaseListViewComponent<ViewMediafile>
|
||||
});
|
||||
}
|
||||
|
||||
public downloadMultiple(mediafiles: ViewMediafile[] = this.dataSource.source): void {
|
||||
/**
|
||||
* TODO: naming the files is discussable
|
||||
*/
|
||||
const eventName = this.configService.instant<string>('general_event_name');
|
||||
const dirName = this.directory?.filename ?? this.translate.instant('Files');
|
||||
const archiveName = `${eventName} - ${dirName}`.trim();
|
||||
this.repo.downloadArchive(archiveName, mediafiles);
|
||||
}
|
||||
|
||||
public move(templateRef: TemplateRef<string>, mediafiles: ViewMediafile[]): void {
|
||||
this.moveForm.reset();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user