mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-4926] fix attachments downloading (#5134)
* fix attachments downloading * update code and tests
This commit is contained in:
committed by
Eugenio Romano
parent
2def8d0557
commit
b1d0c50e88
@@ -18,7 +18,7 @@
|
||||
import { Injectable, Output, EventEmitter } from '@angular/core';
|
||||
import { Node, NodeEntry } from '@alfresco/js-api';
|
||||
import { Subject } from 'rxjs';
|
||||
import { AlfrescoApiService, ContentService, NodeDownloadDirective } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService, ContentService, NodeDownloadDirective, DownloadService } from '@alfresco/adf-core';
|
||||
import { MatDialog } from '@angular/material';
|
||||
|
||||
import { DocumentListService } from './document-list.service';
|
||||
@@ -30,17 +30,18 @@ import { ContentNodeDialogService } from '../../content-node-selector/content-no
|
||||
export class NodeActionsService {
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
error = new EventEmitter<any>();
|
||||
|
||||
constructor(private contentDialogService: ContentNodeDialogService,
|
||||
public dialogRef: MatDialog,
|
||||
public content: ContentService,
|
||||
private documentListService?: DocumentListService,
|
||||
private apiService?: AlfrescoApiService,
|
||||
private dialog?: MatDialog) {}
|
||||
private dialog?: MatDialog,
|
||||
private downloadService?: DownloadService) {}
|
||||
|
||||
downloadNode(node: NodeEntry) {
|
||||
new NodeDownloadDirective(this.apiService, this.dialog)
|
||||
new NodeDownloadDirective(this.apiService, this.downloadService, this.dialog)
|
||||
.downloadNode(node);
|
||||
}
|
||||
|
||||
@@ -50,7 +51,7 @@ export class NodeActionsService {
|
||||
* @param contentEntry node to copy
|
||||
* @param permission permission which is needed to apply the action
|
||||
*/
|
||||
public copyContent(contentEntry: Node, permission?: string): Subject<string> {
|
||||
copyContent(contentEntry: Node, permission?: string): Subject<string> {
|
||||
return this.doFileOperation('copy', 'content', contentEntry, permission);
|
||||
}
|
||||
|
||||
@@ -60,7 +61,7 @@ export class NodeActionsService {
|
||||
* @param contentEntry node to copy
|
||||
* @param permission permission which is needed to apply the action
|
||||
*/
|
||||
public copyFolder(contentEntry: Node, permission?: string): Subject<string> {
|
||||
copyFolder(contentEntry: Node, permission?: string): Subject<string> {
|
||||
return this.doFileOperation('copy', 'folder', contentEntry, permission);
|
||||
}
|
||||
|
||||
@@ -70,7 +71,7 @@ export class NodeActionsService {
|
||||
* @param contentEntry node to move
|
||||
* @param permission permission which is needed to apply the action
|
||||
*/
|
||||
public moveContent(contentEntry: Node, permission?: string): Subject<string> {
|
||||
moveContent(contentEntry: Node, permission?: string): Subject<string> {
|
||||
return this.doFileOperation('move', 'content', contentEntry, permission);
|
||||
}
|
||||
|
||||
@@ -80,7 +81,7 @@ export class NodeActionsService {
|
||||
* @param contentEntry node to move
|
||||
* @param permission permission which is needed to apply the action
|
||||
*/
|
||||
public moveFolder(contentEntry: Node, permission?: string): Subject<string> {
|
||||
moveFolder(contentEntry: Node, permission?: string): Subject<string> {
|
||||
return this.doFileOperation('move', 'folder', contentEntry, permission);
|
||||
}
|
||||
|
||||
@@ -93,7 +94,7 @@ export class NodeActionsService {
|
||||
* @param permission permission which is needed to apply the action
|
||||
*/
|
||||
private doFileOperation(action: string, type: string, contentEntry: Node, permission?: string): Subject<string> {
|
||||
const observable: Subject<string> = new Subject<string>();
|
||||
const observable = new Subject<string>();
|
||||
|
||||
this.contentDialogService
|
||||
.openCopyMoveDialog(action, contentEntry, permission)
|
||||
|
@@ -20,17 +20,18 @@ import { MatDialog } from '@angular/material';
|
||||
import { AlfrescoApiService } from '../services/alfresco-api.service';
|
||||
import { DownloadZipDialogComponent } from '../dialogs/download-zip/download-zip.dialog';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { DownloadService } from '../services/download.service';
|
||||
|
||||
/**
|
||||
* Directive selectors without adf- prefix will be deprecated on 3.0.0
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[adf-node-download], [adfNodeDownload]'
|
||||
// tslint:disable-next-line: directive-selector
|
||||
selector: '[adfNodeDownload]'
|
||||
})
|
||||
export class NodeDownloadDirective {
|
||||
|
||||
/** Nodes to download. */
|
||||
// tslint:disable-next-line:no-input-rename
|
||||
@Input('adfNodeDownload')
|
||||
nodes: NodeEntry | NodeEntry[];
|
||||
|
||||
@@ -41,6 +42,7 @@ export class NodeDownloadDirective {
|
||||
|
||||
constructor(
|
||||
private apiService: AlfrescoApiService,
|
||||
private downloadService: DownloadService,
|
||||
private dialog: MatDialog) {
|
||||
}
|
||||
|
||||
@@ -102,7 +104,7 @@ export class NodeDownloadDirective {
|
||||
const url = contentApi.getContentUrl(id, true);
|
||||
const fileName = node.entry.name;
|
||||
|
||||
this.download(url, fileName);
|
||||
this.downloadService.downloadUrl(url, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,18 +122,4 @@ export class NodeDownloadDirective {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private download(url: string, fileName: string) {
|
||||
if (url && fileName) {
|
||||
const link = document.createElement('a');
|
||||
|
||||
link.style.display = 'none';
|
||||
link.download = fileName;
|
||||
link.href = url;
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -86,4 +86,23 @@ export class DownloadService {
|
||||
downloadJSON(json: any, fileName: string): void {
|
||||
this.saveData(json, 'json', fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the download of the file by its URL address.
|
||||
* @param url Url address pointing to the file.
|
||||
* @param fileName Name of the file download.
|
||||
*/
|
||||
downloadUrl(url: string, fileName: string): void {
|
||||
if (url && fileName) {
|
||||
const link = document.createElement('a');
|
||||
|
||||
link.style.display = 'none';
|
||||
link.download = fileName;
|
||||
link.href = url;
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,8 @@ import {
|
||||
FormModel,
|
||||
FormFieldTypes,
|
||||
FormFieldMetadata,
|
||||
FormService
|
||||
FormService,
|
||||
DownloadService
|
||||
} from '@alfresco/adf-core';
|
||||
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
@@ -43,6 +44,7 @@ describe('AttachFileCloudWidgetComponent', () => {
|
||||
let contentCloudNodeSelectorService: ContentCloudNodeSelectorService;
|
||||
let processCloudContentService: ProcessCloudContentService;
|
||||
let formService: FormService;
|
||||
let downloadService: DownloadService;
|
||||
|
||||
const fakePngAnswer = {
|
||||
id: 1155,
|
||||
@@ -116,6 +118,7 @@ describe('AttachFileCloudWidgetComponent', () => {
|
||||
});
|
||||
|
||||
beforeEach(async(() => {
|
||||
downloadService = TestBed.get(DownloadService);
|
||||
fixture = TestBed.createComponent(AttachFileCloudWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
@@ -278,22 +281,29 @@ describe('AttachFileCloudWidgetComponent', () => {
|
||||
|
||||
it('should download file when download is clicked', (done) => {
|
||||
spyOn(processCloudContentService, 'getRawContentNode').and.returnValue(of(new Blob()));
|
||||
spyOn(processCloudContentService, 'downloadNodeContent').and.stub();
|
||||
spyOn(processCloudContentService, 'getAuthTicket').and.returnValue(Promise.resolve('ticket'));
|
||||
spyOn(downloadService, 'downloadUrl').and.stub();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const menuButton: HTMLButtonElement = <HTMLButtonElement> (
|
||||
fixture.debugElement.query(By.css('#file-1155-option-menu'))
|
||||
.nativeElement
|
||||
);
|
||||
|
||||
menuButton.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
const downloadOption: HTMLButtonElement = <HTMLButtonElement> (
|
||||
fixture.debugElement.query(By.css('#file-1155-download-file'))
|
||||
.nativeElement
|
||||
);
|
||||
|
||||
downloadOption.click();
|
||||
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
expect(processCloudContentService.downloadNodeContent).toHaveBeenCalled();
|
||||
expect(downloadService.downloadUrl).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@@ -23,7 +23,8 @@ import {
|
||||
LogService,
|
||||
ThumbnailService,
|
||||
ContentLinkModel,
|
||||
NotificationService
|
||||
NotificationService,
|
||||
baseHost
|
||||
} from '@alfresco/adf-core';
|
||||
import { Node, RelatedContentRepresentation } from '@alfresco/js-api';
|
||||
import { ContentCloudNodeSelectorService } from '../../services/content-cloud-node-selector.service';
|
||||
@@ -34,17 +35,7 @@ import { UploadCloudWidgetComponent } from '../upload-cloud.widget';
|
||||
selector: 'adf-cloud-attach-file-cloud-widget',
|
||||
templateUrl: './attach-file-cloud-widget.component.html',
|
||||
styleUrls: ['./attach-file-cloud-widget.component.scss'],
|
||||
host: {
|
||||
'(click)': 'event($event)',
|
||||
'(blur)': 'event($event)',
|
||||
'(change)': 'event($event)',
|
||||
'(focus)': 'event($event)',
|
||||
'(focusin)': 'event($event)',
|
||||
'(focusout)': 'event($event)',
|
||||
'(input)': 'event($event)',
|
||||
'(invalid)': 'event($event)',
|
||||
'(select)': 'event($event)'
|
||||
},
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
|
||||
@@ -52,12 +43,12 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
|
||||
static ACS_SERVICE = 'alfresco-content';
|
||||
|
||||
constructor(
|
||||
public formService: FormService,
|
||||
public logger: LogService,
|
||||
public thumbnails: ThumbnailService,
|
||||
public processCloudContentService: ProcessCloudContentService,
|
||||
public contentNodeSelectorService: ContentCloudNodeSelectorService,
|
||||
notificationService: NotificationService
|
||||
formService: FormService,
|
||||
logger: LogService,
|
||||
thumbnails: ThumbnailService,
|
||||
processCloudContentService: ProcessCloudContentService,
|
||||
notificationService: NotificationService,
|
||||
private contentNodeSelectorService: ContentCloudNodeSelectorService
|
||||
) {
|
||||
super(formService, thumbnails, processCloudContentService, notificationService, logger);
|
||||
}
|
||||
@@ -127,20 +118,9 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
|
||||
}
|
||||
|
||||
downloadContent(file: Node): void {
|
||||
this.processCloudContentService
|
||||
.getRawContentNode(file.id, this.field.form.contentHost)
|
||||
.subscribe(
|
||||
(blob: Blob) => {
|
||||
this.processCloudContentService.downloadNodeContent(
|
||||
blob,
|
||||
file.name
|
||||
);
|
||||
},
|
||||
() => {
|
||||
this.logger.error(
|
||||
'Impossible retrieve content for download'
|
||||
);
|
||||
}
|
||||
this.processCloudContentService.downloadFile(
|
||||
file.id,
|
||||
this.field.form.contentHost
|
||||
);
|
||||
}
|
||||
|
||||
@@ -148,9 +128,10 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
|
||||
this.processCloudContentService
|
||||
.getRawContentNode(file.nodeId, this.field.form.contentHost)
|
||||
.subscribe(
|
||||
(blob: Blob) => {
|
||||
blob => {
|
||||
file.contentBlob = blob;
|
||||
this.fileClicked(file);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -42,11 +42,11 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
|
||||
fileInput: ElementRef;
|
||||
|
||||
constructor(
|
||||
public formService: FormService,
|
||||
formService: FormService,
|
||||
private thumbnailService: ThumbnailService,
|
||||
public processCloudContentService: ProcessCloudContentService,
|
||||
private notificationService: NotificationService,
|
||||
private logService: LogService) {
|
||||
protected processCloudContentService: ProcessCloudContentService,
|
||||
protected notificationService: NotificationService,
|
||||
protected logService: LogService) {
|
||||
super(formService);
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,8 @@ import { catchError, map } from 'rxjs/operators';
|
||||
import {
|
||||
AlfrescoApiService,
|
||||
LogService,
|
||||
ContentService
|
||||
ContentService,
|
||||
DownloadService
|
||||
} from '@alfresco/adf-core';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
|
||||
@@ -32,7 +33,8 @@ export class ProcessCloudContentService {
|
||||
constructor(
|
||||
private apiService: AlfrescoApiService,
|
||||
private logService: LogService,
|
||||
public contentService: ContentService
|
||||
public contentService: ContentService,
|
||||
private downloadService: DownloadService
|
||||
) {}
|
||||
|
||||
createTemporaryRawRelatedContent(
|
||||
@@ -40,12 +42,7 @@ export class ProcessCloudContentService {
|
||||
nodeId: string,
|
||||
contentHost: string
|
||||
): Observable<Node> {
|
||||
const changedConfig = this.apiService.lastConfig;
|
||||
|
||||
changedConfig.provider = 'ALL';
|
||||
changedConfig.hostEcm = contentHost.replace('/alfresco', '');
|
||||
|
||||
this.apiService.getInstance().setConfig(changedConfig);
|
||||
this.updateConfig(contentHost);
|
||||
|
||||
return from(
|
||||
this.apiService
|
||||
@@ -62,11 +59,8 @@ export class ProcessCloudContentService {
|
||||
);
|
||||
}
|
||||
|
||||
getRawContentNode(nodeId: string, contentHost: string): Observable<any> {
|
||||
const changedConfig = this.apiService.lastConfig;
|
||||
changedConfig.provider = 'ALL';
|
||||
changedConfig.hostEcm = contentHost.replace('/alfresco', '');
|
||||
this.apiService.getInstance().setConfig(changedConfig);
|
||||
getRawContentNode(nodeId: string, contentHost: string): Observable<Blob> {
|
||||
this.updateConfig(contentHost);
|
||||
return this.contentService.getNodeContent(nodeId);
|
||||
}
|
||||
|
||||
@@ -74,6 +68,38 @@ export class ProcessCloudContentService {
|
||||
this.contentService.downloadBlob(blob, fileName);
|
||||
}
|
||||
|
||||
async downloadFile(nodeId: string, contentHost: string) {
|
||||
this.updateConfig(contentHost);
|
||||
|
||||
const ticket = await this.getAuthTicket();
|
||||
const url = this.contentService.getContentUrl(nodeId, true, ticket);
|
||||
|
||||
this.downloadService.downloadUrl(url, nodeId);
|
||||
}
|
||||
|
||||
async getAuthTicket(): Promise<string> {
|
||||
const { auth } = this.apiService.getInstance();
|
||||
const ticket = await auth.authenticationApi.getTicket();
|
||||
|
||||
if (ticket && ticket.entry) {
|
||||
return ticket.entry.id || '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private updateConfig(contentHost: string) {
|
||||
const changedConfig = this.apiService.lastConfig;
|
||||
|
||||
changedConfig.provider = 'ALL';
|
||||
|
||||
if (contentHost) {
|
||||
changedConfig.hostEcm = contentHost.replace('/alfresco', '');
|
||||
}
|
||||
|
||||
this.apiService.getInstance().setConfig(changedConfig);
|
||||
}
|
||||
|
||||
private handleError(error: any) {
|
||||
this.logService.error(error);
|
||||
return throwError(error || 'Server error');
|
||||
|
Reference in New Issue
Block a user