diff --git a/lib/content-services/document-list/services/node-actions.service.ts b/lib/content-services/document-list/services/node-actions.service.ts index a72d8d0eff..e7b4f7071d 100644 --- a/lib/content-services/document-list/services/node-actions.service.ts +++ b/lib/content-services/document-list/services/node-actions.service.ts @@ -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 = new EventEmitter(); + error = new EventEmitter(); 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 { + copyContent(contentEntry: Node, permission?: string): Subject { 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 { + copyFolder(contentEntry: Node, permission?: string): Subject { 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 { + moveContent(contentEntry: Node, permission?: string): Subject { 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 { + moveFolder(contentEntry: Node, permission?: string): Subject { 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 { - const observable: Subject = new Subject(); + const observable = new Subject(); this.contentDialogService .openCopyMoveDialog(action, contentEntry, permission) diff --git a/lib/core/directives/node-download.directive.ts b/lib/core/directives/node-download.directive.ts index dfeeadd6a5..5f91742cdc 100755 --- a/lib/core/directives/node-download.directive.ts +++ b/lib/core/directives/node-download.directive.ts @@ -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); - } - } } diff --git a/lib/core/services/download.service.ts b/lib/core/services/download.service.ts index 22cb62e9d1..f728230f98 100644 --- a/lib/core/services/download.service.ts +++ b/lib/core/services/download.service.ts @@ -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); + } + } } diff --git a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.spec.ts index 787bd9f2f3..e6e7f679ed 100644 --- a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.spec.ts @@ -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 = ( fixture.debugElement.query(By.css('#file-1155-option-menu')) .nativeElement ); + menuButton.click(); fixture.detectChanges(); + const downloadOption: 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(); }); }); diff --git a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.ts b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.ts index 7da0b012cf..0982dc2f9e 100644 --- a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.ts +++ b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.ts @@ -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,30 +118,20 @@ 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 + ); } onAttachFileClicked(file: ContentLinkModel) { this.processCloudContentService - .getRawContentNode(file.nodeId, this.field.form.contentHost) - .subscribe( - (blob: Blob) => { - file.contentBlob = blob; - this.fileClicked(file); - }); + .getRawContentNode(file.nodeId, this.field.form.contentHost) + .subscribe( + blob => { + file.contentBlob = blob; + this.fileClicked(file); + } + ); } } diff --git a/lib/process-services-cloud/src/lib/form/components/upload-cloud.widget.ts b/lib/process-services-cloud/src/lib/form/components/upload-cloud.widget.ts index 95af89b081..75a59fe3ef 100644 --- a/lib/process-services-cloud/src/lib/form/components/upload-cloud.widget.ts +++ b/lib/process-services-cloud/src/lib/form/components/upload-cloud.widget.ts @@ -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); } diff --git a/lib/process-services-cloud/src/lib/form/services/process-cloud-content.service.ts b/lib/process-services-cloud/src/lib/form/services/process-cloud-content.service.ts index dc0ef92402..ef799543c9 100644 --- a/lib/process-services-cloud/src/lib/form/services/process-cloud-content.service.ts +++ b/lib/process-services-cloud/src/lib/form/services/process-cloud-content.service.ts @@ -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 { - 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 { - const changedConfig = this.apiService.lastConfig; - changedConfig.provider = 'ALL'; - changedConfig.hostEcm = contentHost.replace('/alfresco', ''); - this.apiService.getInstance().setConfig(changedConfig); + getRawContentNode(nodeId: string, contentHost: string): Observable { + 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 { + 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');