Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADF-5170] [upload] not able to upload file/folder from external content service specfic path #6256

Merged
merged 2 commits into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ export interface AttachFileWidgetDialogComponentData {
context?: string;
isSelectionValid?: (entry: Node) => boolean;
showFilesInResult?: boolean;
loginOnly?: boolean;
accountIdentifier?: string;
registerExternalHost?: Function;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ContentModule, ContentNodeSelectorPanelComponent, DocumentListService } from '@alfresco/adf-content-services';
import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
import { ProcessTestingModule } from '../testing/process.testing.module';
Expand Down Expand Up @@ -44,6 +44,8 @@ describe('AttachFileWidgetDialogComponent', () => {
let siteService: SitesService;
let nodeService: NodesApiService;
let documentListService: DocumentListService;
let apiService: AlfrescoApiService;
let matDialogRef: MatDialogRef<AttachFileWidgetDialogComponent>;

let isLogged = false;
const fakeSite = new SiteEntry({ entry: { id: 'fake-site', guid: 'fake-site', title: 'fake-site', visibility: 'visible' } });
Expand All @@ -56,7 +58,8 @@ describe('AttachFileWidgetDialogComponent', () => {
],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data },
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
{ provide: MatDialogRef, useValue: { close: () => of() } }
],
schemas: [NO_ERRORS_SCHEMA]
});
Expand All @@ -69,6 +72,8 @@ describe('AttachFileWidgetDialogComponent', () => {
siteService = fixture.debugElement.injector.get(SitesService);
nodeService = fixture.debugElement.injector.get(NodesApiService);
documentListService = fixture.debugElement.injector.get(DocumentListService);
matDialogRef = fixture.debugElement.injector.get(MatDialogRef);
apiService = fixture.debugElement.injector.get(AlfrescoApiService);

spyOn(documentListService, 'getFolderNode').and.returnValue(of(<NodeEntry> { entry: { path: { elements: [] } } }));
spyOn(documentListService, 'getFolder').and.returnValue(throwError('No results for test'));
Expand Down Expand Up @@ -169,4 +174,39 @@ describe('AttachFileWidgetDialogComponent', () => {
expect(titleElement.nativeElement.innerText).toBe('ATTACH-FILE.ACTIONS.CHOOSE_ITEM');
});
});

describe('login only', () => {
beforeEach(async(() => {
spyOn(authService, 'login').and.returnValue(of({ type: 'type', ticket: 'ticket'}));
spyOn(matDialogRef, 'close').and.callThrough();
fixture.detectChanges();
widget.data.loginOnly = true;
widget.data.registerExternalHost = () => {};
isLogged = false;
}));

it('should close the dialog once user loggedIn', () => {
fixture.detectChanges();
isLogged = true;
const loginButton: HTMLButtonElement = element.querySelector('button[data-automation-id="attach-file-dialog-actions-login"]');
const usernameInput: HTMLInputElement = element.querySelector('#username');
const passwordInput: HTMLInputElement = element.querySelector('#password');
usernameInput.value = 'fake-user';
passwordInput.value = 'fake-user';
usernameInput.dispatchEvent(new Event('input'));
passwordInput.dispatchEvent(new Event('input'));
loginButton.click();
authService.onLogin.next('logged In');
fixture.detectChanges();
expect(matDialogRef.close).toHaveBeenCalled();
});

it('should close the dialog immediately if user already loggedIn', () => {
isLogged = true;
fixture.detectChanges();
spyOn(apiService, 'getInstance').and.returnValue({ isLoggedIn: () => true });
widget.updateExternalHost();
expect(matDialogRef.close).toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/

import { Component, Inject, ViewEncapsulation, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ExternalAlfrescoApiService, AlfrescoApiService, LoginDialogPanelComponent, SearchService, TranslationService, AuthenticationService, SitesService } from '@alfresco/adf-core';
import { AttachFileWidgetDialogComponentData } from './attach-file-widget-dialog-component.interface';
import { DocumentListService, ContentNodeSelectorService } from '@alfresco/adf-content-services';
Expand All @@ -33,7 +33,7 @@ import { Node } from '@alfresco/js-api';
SitesService,
ContentNodeSelectorService,
SearchService,
{ provide: AlfrescoApiService, useClass: ExternalAlfrescoApiService} ]
{ provide: AlfrescoApiService, useClass: ExternalAlfrescoApiService } ]
})
export class AttachFileWidgetDialogComponent {

Expand All @@ -47,11 +47,29 @@ export class AttachFileWidgetDialogComponent {

constructor(private translation: TranslationService,
@Inject(MAT_DIALOG_DATA) public data: AttachFileWidgetDialogComponentData,
private externalApiService: AlfrescoApiService) {
private externalApiService: AlfrescoApiService,
private authenticationService: AuthenticationService,
private matDialogRef: MatDialogRef<AttachFileWidgetDialogComponent>) {
(<any> externalApiService).init(data.ecmHost, data.context);
this.action = data.actionName ? data.actionName.toUpperCase() : 'CHOOSE';
this.buttonActionName = `ATTACH-FILE.ACTIONS.${this.action}`;
this.updateTitle('DROPDOWN.MY_FILES_OPTION');
this.updateExternalHost();
}

updateExternalHost() {
this.authenticationService.onLogin.subscribe(() => this.registerAndClose());
if (this.externalApiService.getInstance().isLoggedIn()) {
this.registerAndClose();
}
}

private registerAndClose() {
this.data.registerExternalHost(this.data.accountIdentifier, this.externalApiService);
if (this.data.loginOnly) {
this.data.selected.complete();
this.matDialogRef.close();
}
}

isLoggedIn() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('AttachFileWidgetDialogService', () => {
});

it('should be able to open the dialog when node has permission', () => {
service.openLogin('fake-title', 'fake-action');
service.openLogin({ id: 1, name: 'fake-title', repositoryUrl: 'http://fakeurl.com/alfresco' }, 'fake-action');
expect(spyOnDialogOpen).toHaveBeenCalled();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@

import { MatDialog } from '@angular/material/dialog';
import { EventEmitter, Injectable, Output } from '@angular/core';
import { TranslationService } from '@alfresco/adf-core';
import { Subject, Observable } from 'rxjs';
import { AlfrescoApiService, TranslationService } from '@alfresco/adf-core';
import { Observable, of, Subject } from 'rxjs';
import { AttachFileWidgetDialogComponentData } from './attach-file-widget-dialog-component.interface';
import { Node } from '@alfresco/js-api';
import { AlfrescoEndpointRepresentation, Node } from '@alfresco/js-api';
import { AttachFileWidgetDialogComponent } from './attach-file-widget-dialog.component';
import { switchMap } from 'rxjs/operators';

@Injectable({
providedIn: 'root'
})
// tslint:disable-next-line: directive-class-suffix
export class AttachFileWidgetDialogService {
private externalApis: { [key: string]: AlfrescoApiService } = {};

/** Emitted when an error occurs. */
@Output()
Expand All @@ -39,25 +41,20 @@ export class AttachFileWidgetDialogService {

/**
* Opens a dialog to choose a file to upload.
* @param action Name of the action to show in the title
* @param contentEntry Item to upload
* @param repository Alfresco endpoint that represents the content service
* @param currentFolderId Upload file from specific folder
* @returns Information about the chosen file(s)
*/
openLogin(ecmHost: string, actionName?: string, context?: string): Observable<Node[]> {
const selected = new Subject<Node[]>();
selected.subscribe({
complete: this.close.bind(this)
});

openLogin(repository: AlfrescoEndpointRepresentation, currentFolderId = '-my-'): Observable<Node[]> {
const { title, ecmHost, selected, registerExternalHost } = this.constructPayload(repository);
const data: AttachFileWidgetDialogComponentData = {
title : this.getLoginTitleTranslation(ecmHost),
actionName,
title,
selected,
ecmHost,
currentFolderId: '-my-',
context,
currentFolderId,
isSelectionValid: (entry: Node) => entry.isFile,
showFilesInResult: true
showFilesInResult: true,
registerExternalHost
};

this.openLoginDialog(data, 'adf-attach-file-widget-dialog', '630px');
Expand All @@ -68,6 +65,45 @@ export class AttachFileWidgetDialogService {
this.dialog.open(AttachFileWidgetDialogComponent, { data, panelClass: currentPanelClass, width: chosenWidth });
}

private showExternalHostLoginDialog(repository: AlfrescoEndpointRepresentation): Observable<AlfrescoApiService> {
const data = {
...this.constructPayload(repository),
loginOnly: true
};
return this.dialog.open(AttachFileWidgetDialogComponent, { data, panelClass: 'adf-attach-file-widget-dialog', width: '630px' })
.afterClosed();
}

downloadURL(repository: AlfrescoEndpointRepresentation, sourceId: string): Observable<string> {
const { accountIdentifier } = this.constructPayload(repository);

if (this.externalApis[accountIdentifier]?.getInstance()?.isLoggedIn()) {
return of(this.externalApis[accountIdentifier].contentApi.getContentUrl(sourceId));
}

return this.showExternalHostLoginDialog(repository).pipe(
switchMap(() => of(this.externalApis[accountIdentifier].getInstance().content.getContentUrl(sourceId)))
);
}

private constructPayload(repository: AlfrescoEndpointRepresentation) {
const accountIdentifier = 'alfresco-' + repository.id + '-' + repository.name;
const ecmHost = repository.repositoryUrl.replace('/alfresco', '');
const selected = new Subject<Node[]>();
selected.subscribe({
complete: this.close.bind(this)
});
const title = this.getLoginTitleTranslation(ecmHost);
const registerExternalHost = this.addService.bind(this);
return { ecmHost, accountIdentifier, selected, title, registerExternalHost };
}

addService(accountIdentifier: string, apiService: AlfrescoApiService) {
if (!this.externalApis[accountIdentifier]) {
this.externalApis[accountIdentifier] = apiService;
}
}

/** Closes the currently open dialog. */
close() {
this.dialog.closeAll();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { of } from 'rxjs';
import { Node } from '@alfresco/js-api';
import { ProcessTestingModule } from '../testing/process.testing.module';
import { TranslateModule } from '@ngx-translate/core';
import { AttachFileWidgetDialogService } from './attach-file-widget-dialog.service';

const fakeRepositoryListAnswer = [
{
Expand All @@ -50,7 +51,16 @@ const fakeRepositoryListAnswer = [
'metaDataAllowed': true,
'name': 'GOKUSHARE',
'repositoryUrl': 'http://localhost:0000/GOKUSHARE'
}];
},
{
'authorized': true,
'serviceId': 'alfresco-2000-external',
'metaDataAllowed': true,
'name': 'external',
'repositoryUrl': 'http://externalhost.com/alfresco',
'id': 2000
}
];

const onlyLocalParams = {
fileSource: {
Expand Down Expand Up @@ -82,6 +92,16 @@ const definedSourceParams = {
}
};

const externalDefinedSourceParams = {
fileSource: {
serviceId: 'external-sources',
name: 'external',
selectedFolder: {
accountId: 'external-account-id'
}
}
};

const fakeMinimalNode: Node = <Node> {
id: 'fake',
name: 'fake-name',
Expand Down Expand Up @@ -130,6 +150,7 @@ describe('AttachFileWidgetComponent', () => {
let processContentService: ProcessContentService;
let downloadService: DownloadService;
let formService: FormService;
let attachFileWidgetDialogService: AttachFileWidgetDialogService;

setupTestBed({
imports: [
Expand All @@ -148,6 +169,7 @@ describe('AttachFileWidgetComponent', () => {
processContentService = TestBed.inject(ProcessContentService);
downloadService = TestBed.inject(DownloadService);
formService = TestBed.inject(FormService);
attachFileWidgetDialogService = TestBed.inject(AttachFileWidgetDialogService);
}));

afterEach(() => {
Expand Down Expand Up @@ -532,4 +554,23 @@ describe('AttachFileWidgetComponent', () => {
expect(showOption.disabled).toBeTruthy();
});
});

it('should be able to upload files when a defined folder from external content service', async(() => {
widget.field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.UPLOAD, value: [] });
widget.field.id = 'attach-external-file-attach';
widget.field.params = <FormFieldMetadata> externalDefinedSourceParams;
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of(fakeRepositoryListAnswer));
spyOn(activitiContentService, 'applyAlfrescoNode').and.returnValue(of(fakePngAnswer));
spyOn(attachFileWidgetDialogService, 'openLogin').and.returnValue(of([fakeMinimalNode]));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const attachButton: HTMLButtonElement = element.querySelector('#attach-external-file-attach');
attachButton.click();
fixture.detectChanges();
fixture.debugElement.query(By.css('#attach-external')).nativeElement.click();
fixture.detectChanges();
expect(element.querySelector('#file-1155-icon')).not.toBeNull();
});
}));
});
Loading