diff --git a/lib/core/form/components/widgets/core/index.ts b/lib/core/form/components/widgets/core/index.ts index 28a50483a6..dd2d3d0bc7 100644 --- a/lib/core/form/components/widgets/core/index.ts +++ b/lib/core/form/components/widgets/core/index.ts @@ -39,3 +39,4 @@ export * from './group.model'; export * from './form-variable.model'; export * from './process-variable.model'; export * from './upload-widget-content-link.model'; +export * from './form-field-file-source'; diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts index a2055e96e4..e0b57bebbc 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts @@ -38,17 +38,13 @@ import { mockNodeId, fakeLocalPngResponse, onlyLocalParams, - allSourceWithRootParams, allSourceWithWrongAliasParams, allSourceWithNoAliasParams, - allSourceWithoutDestinationFolderPath, - allSourceWithoutValueProperty, fakeNodeWithProperties, menuTestSourceParam, expectedValues, fakeLocalPngAnswer, allSourceWithStringTypeEmptyValue, - allSourceWithFolderTypeEmptyValue, mockNodeIdBasedOnStringVariableValue, mockAllFileSourceWithStringVariablePathType, mockAllFileSourceWithFolderVariablePathType, @@ -57,7 +53,6 @@ import { formVariables, processVariables, mockAllFileSourceWithRenamedFolderVariablePathType, - allSourceParamsWithWrongRelativePath, allSourceParamsWithRelativePath, fakeLocalPhysicalRecordResponse } from '../../../mocks/attach-file-cloud-widget.mock'; @@ -165,7 +160,7 @@ describe('AttachFileCloudWidgetComponent', () => { }); it('should be able to attach files coming from all files source', async () => { - spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(mockNodeId); + spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeId); createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceParams); fixture.detectChanges(); await fixture.whenStable(); @@ -205,7 +200,7 @@ describe('AttachFileCloudWidgetComponent', () => { describe('destinationFolderPath', () => { it('should be able to fetch nodeId if destinationFolderPath is defined', async () => { - const fetchNodeIdFromRelativePathSpy = spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(mockNodeId); + const getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeId); createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceParams); fixture.detectChanges(); @@ -215,37 +210,15 @@ describe('AttachFileCloudWidgetComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const alias = '-root-'; - const opt = { relativePath: '/myfiles' }; + const mockDestinationPath = { alias: '-root-', path: '/myfiles' }; - expect(fetchNodeIdFromRelativePathSpy).toHaveBeenCalledWith(alias, opt); + expect(getNodeIdFromPathSpy).toHaveBeenCalledWith(mockDestinationPath); expect(widget.field.params.fileSource.destinationFolderPath.value).toBe('-root-/myfiles'); expect(widget.rootNodeId).toEqual('mock-node-id'); }); - it('should be able to fetch nodeId based on given alias if the relative path is wrong', async () => { - const fetchNodeIdFromRelativePathSpy = spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(new Promise((reject) => reject(undefined))); - const fetchAliasNodeIdSpy = spyOn(contentCloudNodeSelectorService, 'fetchAliasNodeId').and.returnValue(mockNodeId); - - createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceParamsWithWrongRelativePath); - fixture.detectChanges(); - await fixture.whenStable(); - - clickOnAttachFileWidget('attach-file-alfresco'); - fixture.detectChanges(); - await fixture.whenStable(); - - const alias = '-shared-'; - const opt = { relativePath: '/wrongRelativePath' }; - - expect(fetchNodeIdFromRelativePathSpy).toHaveBeenCalledWith(alias, opt); - expect(fetchAliasNodeIdSpy).toHaveBeenCalledWith(alias); - expect(widget.rootNodeId).toEqual('mock-node-id'); - }); - it('should be able to fetch relativePath nodeId if the given relative path is correct', async () => { - const fetchNodeIdFromRelativePathSpy = spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(mockNodeId); - const fetchAliasNodeIdSpy = spyOn(contentCloudNodeSelectorService, 'fetchAliasNodeId'); + const getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeId); createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceParamsWithRelativePath); fixture.detectChanges(); @@ -255,16 +228,14 @@ describe('AttachFileCloudWidgetComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const alias = '-shared-'; - const opt = { relativePath: '/myfiles' }; + const mockDestinationPath = { alias: '-shared-', path: '/myfiles' }; - expect(fetchNodeIdFromRelativePathSpy).toHaveBeenCalledWith(alias, opt); - expect(fetchAliasNodeIdSpy).not.toHaveBeenCalledWith(alias); + expect(getNodeIdFromPathSpy).toHaveBeenCalledWith(mockDestinationPath); expect(widget.rootNodeId).toEqual('mock-node-id'); }); it('should be able to use mapped string variable value if the destinationFolderPath set to string type variable', async () => { - const fetchNodeIdFromRelativePathSpy = spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(mockNodeIdBasedOnStringVariableValue); + const getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeIdBasedOnStringVariableValue); const form = new FormModel({ formVariables, processVariables}); createUploadWidgetField(form, 'attach-file-alfresco', [], mockAllFileSourceWithStringVariablePathType); @@ -274,15 +245,14 @@ describe('AttachFileCloudWidgetComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const alias = '-root-'; - const opt = { relativePath: '/pathBasedOnStringvariablevalue' }; + const mockDestinationPath = { alias: '-root-', path: '/pathBasedOnStringvariablevalue' }; - expect(fetchNodeIdFromRelativePathSpy).toHaveBeenCalledWith(alias, opt); + expect(getNodeIdFromPathSpy).toHaveBeenCalledWith(mockDestinationPath); expect(widget.rootNodeId).toEqual('mock-string-value-node-id'); }); it('should be able to use default location if mapped string variable value is undefined/empty', async () => { - const fetchAliasNodeIdSpy = spyOn(contentCloudNodeSelectorService, 'fetchAliasNodeId').and.returnValue(mockNodeId); + const getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeId); createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceWithStringTypeEmptyValue); fixture.detectChanges(); await fixture.whenStable(); @@ -291,15 +261,15 @@ describe('AttachFileCloudWidgetComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const alias = '-my-'; + const mockDestinationPath = { alias: '-my-', path: undefined }; - expect(fetchAliasNodeIdSpy).toHaveBeenCalledWith(alias); + expect(getNodeIdFromPathSpy).toHaveBeenCalledWith(mockDestinationPath); expect(widget.rootNodeId).toEqual('mock-node-id'); }); it('should be able to use mapped folder variable value if destinationFolderPath set to folder type variable', async () => { - const fetchNodeIdFromRelativePathSpy = spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath'); - const form = new FormModel({ formVariables, processVariables}); + const verifyFolderSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromFolderVariableValue').and.returnValue(mockNodeId); + const form = new FormModel({ formVariables, processVariables }); createUploadWidgetField(form, 'attach-file-alfresco', [], mockAllFileSourceWithFolderVariablePathType); fixture.detectChanges(); await fixture.whenStable(); @@ -307,38 +277,10 @@ describe('AttachFileCloudWidgetComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - expect(fetchNodeIdFromRelativePathSpy).not.toHaveBeenCalled(); - expect(widget.rootNodeId).toBe('mock-folder-id'); - }); - - it('should be able to use default location if the mapped folder variable value is undefined/empty', async () => { - const fetchAliasNodeIdSpy = spyOn(contentCloudNodeSelectorService, 'fetchAliasNodeId').and.returnValue(mockNodeId); - - createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceWithFolderTypeEmptyValue); - fixture.detectChanges(); - await fixture.whenStable(); - clickOnAttachFileWidget('attach-file-alfresco'); - fixture.detectChanges(); - await fixture.whenStable(); - - const alias = '-my-'; - - expect(fetchAliasNodeIdSpy).toHaveBeenCalledWith(alias); + expect(verifyFolderSpy).toHaveBeenCalled(); expect(widget.rootNodeId).toBe('mock-node-id'); }); - it('Should be able to set given alias as rootNodeId if the nodeId of the alias is not fetched from the api', async () => { - createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceWithRootParams); - fixture.detectChanges(); - await fixture.whenStable(); - clickOnAttachFileWidget('attach-file-alfresco'); - fixture.detectChanges(); - await fixture.whenStable(); - - expect(widget.rootNodeId).toEqual('-root-'); - expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-root-', 'single', true, true); - }); - it('Should set default user alias (-my-) as rootNodeId if destinationFolderPath contains wrong alias and single upload for Alfresco Content + Locale', async () => { createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceWithWrongAliasParams, false); fixture.detectChanges(); @@ -376,32 +318,6 @@ describe('AttachFileCloudWidgetComponent', () => { expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-my-', 'multiple', true, true); }); - it('Should set default user alias (-my-) as rootNodeId if destinationFolderPath is not defined', async () => { - const getAliasAndPathSpy = spyOn(widget, 'getAliasAndRelativePathFromDestinationFolderPath').and.callThrough(); - createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceWithoutDestinationFolderPath); - fixture.detectChanges(); - await fixture.whenStable(); - clickOnAttachFileWidget('attach-file-alfresco'); - fixture.detectChanges(); - await fixture.whenStable(); - - expect(getAliasAndPathSpy).not.toHaveBeenCalled(); - expect(widget.rootNodeId).toEqual('-my-'); - }); - - it('Should set default user alias (-my-) as rootNodeId if value property missing from destinationFolderPath', async () => { - const getAliasAndPathSpy = spyOn(widget, 'getAliasAndRelativePathFromDestinationFolderPath').and.callThrough(); - createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], allSourceWithoutValueProperty); - fixture.detectChanges(); - await fixture.whenStable(); - clickOnAttachFileWidget('attach-file-alfresco'); - fixture.detectChanges(); - await fixture.whenStable(); - - expect(getAliasAndPathSpy).not.toHaveBeenCalled(); - expect(widget.rootNodeId).toEqual('-my-'); - }); - it('should return the application name in case -appname- placeholder is present', () => { appConfigService.config = Object.assign(appConfigService.config, { 'alfresco-deployed-apps': [ @@ -420,7 +336,7 @@ describe('AttachFileCloudWidgetComponent', () => { describe('FilesSource', () => { it('Should be able to fetch nodeId of default user alias (-my-) if fileSource set only to Alfresco Content', async () => { - const fetchAliasNodeIdSpy = spyOn(contentCloudNodeSelectorService, 'fetchAliasNodeId').and.returnValue(mockNodeId); + const getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeId); createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], contentSourceParam, false); fixture.detectChanges(); await fixture.whenStable(); @@ -428,15 +344,15 @@ describe('AttachFileCloudWidgetComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const alias = '-my-'; + const mockDestinationPath = { alias: '-my-', path: undefined }; - expect(fetchAliasNodeIdSpy).toHaveBeenCalledWith(alias); + expect(getNodeIdFromPathSpy).toHaveBeenCalledWith(mockDestinationPath); expect(widget.rootNodeId).toEqual('mock-node-id'); expect(openUploadFileDialogSpy).toHaveBeenCalledWith('mock-node-id', 'single', false, true); }); it('Should be able to fetch nodeId of default user alias (-my-) if fileSource set to multiple upload for Alfresco Content', async () => { - const fetchAliasNodeIdSpy = spyOn(contentCloudNodeSelectorService, 'fetchAliasNodeId').and.returnValue(mockNodeId); + const getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeId); createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [], contentSourceParam, true); fixture.detectChanges(); @@ -445,9 +361,9 @@ describe('AttachFileCloudWidgetComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const alias = '-my-'; + const mockDestinationPath = { alias: '-my-', path: undefined }; - expect(fetchAliasNodeIdSpy).toHaveBeenCalledWith(alias); + expect(getNodeIdFromPathSpy).toHaveBeenCalledWith(mockDestinationPath); expect(widget.rootNodeId).toEqual('mock-node-id'); expect(openUploadFileDialogSpy).toHaveBeenCalledWith('mock-node-id', 'multiple', false, true); }); @@ -531,7 +447,7 @@ describe('AttachFileCloudWidgetComponent', () => { describe('when a file is uploaded', () => { beforeEach(async () => { apiServiceSpy = spyOn(widget['nodesApi'], 'getNode').and.returnValue(new Promise(resolve => resolve({entry: fakeNodeWithProperties}))); - spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(new Promise(resolve => resolve('fake-properties'))); + spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(new Promise(resolve => resolve('fake-properties'))); openUploadFileDialogSpy.and.returnValue(of([fakeNodeWithProperties])); widget.field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.UPLOAD, diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts index bc93acd1c2..16a17a14bc 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts @@ -27,7 +27,8 @@ import { ContentLinkModel, AppConfigService, AlfrescoApiService, - UploadWidgetContentLinkModel + UploadWidgetContentLinkModel, + DestinationFolderPath } from '@alfresco/adf-core'; import { Node, NodesApi, RelatedContentRepresentation } from '@alfresco/js-api'; import { ContentCloudNodeSelectorService } from '../../../services/content-cloud-node-selector.service'; @@ -143,37 +144,44 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent i private async getDestinationFolderNodeId(): Promise { let rootNodeId: string; - let destinationFolderPath = { alias: AttachFileCloudWidgetComponent.ALIAS_USER_FOLDER, path: '' }; - if (this.isAlfrescoAndLocal() && this.hasDestinationFolder()) { - if (this.isPathVariableType(DestinationFolderPathType.STRING_TYPE) || this.isPathStaticType()) { - destinationFolderPath = this.getAliasAndRelativePathFromDestinationFolderPath(this.field.params.fileSource.destinationFolderPath.value); - destinationFolderPath.path = this.replaceAppNameAliasWithValue(destinationFolderPath.path); - } - if (this.isPathVariableType(DestinationFolderPathType.FOLDER_TYPE)) { - rootNodeId = this.field.params.fileSource.destinationFolderPath.value; - } - } - - if (!rootNodeId) { - try { - const nodeId = await this.getNodeIdBasedOnPath(destinationFolderPath); - rootNodeId = nodeId ? nodeId : destinationFolderPath.alias; - } catch (error) { - this.logService.error(error); - } + switch (this.field?.params?.fileSource?.destinationFolderPath?.type) { + case DestinationFolderPathType.STATIC_TYPE: + rootNodeId = await this.getNodeIdFromPath(this.field.params.fileSource.destinationFolderPath); + break; + case DestinationFolderPathType.STRING_TYPE: + rootNodeId = await this.getNodeIdFromPath(this.field.params.fileSource.destinationFolderPath); + break; + case DestinationFolderPathType.FOLDER_TYPE: + rootNodeId = await this.getNodeIdFromFolderVariableValue(this.field.params.fileSource.destinationFolderPath); + break; + default: + rootNodeId = await this.getNodeIdFromPath({ type: '', value: AttachFileCloudWidgetComponent.ALIAS_USER_FOLDER }); + break; } return rootNodeId; } - private async getNodeIdBasedOnPath(destinationFolderPath: DestinationFolderPathModel) { + async getNodeIdFromPath(destinationFolderPath: DestinationFolderPath): Promise { let nodeId: string; - if (destinationFolderPath.path) { - nodeId = await this.contentNodeSelectorService.fetchNodeIdFromRelativePath(destinationFolderPath.alias, { relativePath: destinationFolderPath.path }); + const destinationPath = this.getAliasAndRelativePathFromDestinationFolderPath(destinationFolderPath.value); + destinationPath.path = this.replaceAppNameAliasWithValue(destinationPath.path); + try { + nodeId = await this.contentNodeSelectorService.getNodeIdFromPath(destinationPath); + } catch (error) { + this.logService.error(error); } - if (!nodeId) { - nodeId = await this.contentNodeSelectorService.fetchAliasNodeId(destinationFolderPath.alias); + + return nodeId; + } + + async getNodeIdFromFolderVariableValue(destinationFolderPath: DestinationFolderPath): Promise { + let nodeId: string; + try { + nodeId = await this.contentNodeSelectorService.getNodeIdFromFolderVariableValue(destinationFolderPath.value, AttachFileCloudWidgetComponent.ALIAS_USER_FOLDER); + } catch (error) { + this.logService.error(error); } return nodeId; @@ -251,10 +259,6 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent i return alias && AttachFileCloudWidgetComponent.VALID_ALIAS.includes(alias); } - private hasDestinationFolder(): boolean { - return !!this.field?.params?.fileSource?.destinationFolderPath?.value; - } - ngOnDestroy() { this.contentNodeSelectorPanelService.customModels = []; } diff --git a/lib/process-services-cloud/src/lib/form/mocks/attach-file-cloud-widget.mock.ts b/lib/process-services-cloud/src/lib/form/mocks/attach-file-cloud-widget.mock.ts index 142a1c61e7..5e60618dca 100644 --- a/lib/process-services-cloud/src/lib/form/mocks/attach-file-cloud-widget.mock.ts +++ b/lib/process-services-cloud/src/lib/form/mocks/attach-file-cloud-widget.mock.ts @@ -95,17 +95,6 @@ export const menuTestSourceParam = { } }; -export const allSourceParamsWithWrongRelativePath = { - fileSource: { - name: 'all file sources', - serviceId: FileSourceTypes.ALL_FILE_SOURCES_SERVICE_ID, - destinationFolderPath: { - value: '-shared-/wrongRelativePath', - type: DestinationFolderPathType.STATIC_TYPE - } - } -}; - export const allSourceParamsWithRelativePath = { fileSource: { name: 'all file sources', diff --git a/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.spec.ts b/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.spec.ts new file mode 100644 index 0000000000..adeebad85a --- /dev/null +++ b/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.spec.ts @@ -0,0 +1,195 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TestBed } from '@angular/core/testing'; +import { AlfrescoApiService, AlfrescoApiServiceMock, NotificationService, setupTestBed } from '@alfresco/adf-core'; +import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; +import { TranslateModule } from '@ngx-translate/core'; +import { ContentCloudNodeSelectorService } from 'process-services-cloud'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { of, Subject } from 'rxjs'; + +describe('ContentCloudNodeSelectorService', () => { + let service: ContentCloudNodeSelectorService; + let notificationService: NotificationService; + let getNodeSpy: jasmine.Spy; + let dialog: MatDialog; + let openDialogSpy: jasmine.Spy; + let showWarningSpy: jasmine.Spy; + + const relativePathNodeResponseBody = { + entry: { + id: 'mock-relative-path-node-id' + } + }; + + const aliasNodeResponseBody = { + entry: { + id: 'mock-alias-node-id' + } + }; + + const folderVariableValueResponseBody = { + entry: { + id: 'mock-folder-id' + } + }; + + setupTestBed({ + imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule, MatDialogModule], + providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + ] + }); + + beforeEach(() => { + service = TestBed.inject(ContentCloudNodeSelectorService); + notificationService = TestBed.inject(NotificationService); + dialog = TestBed.inject(MatDialog); + + showWarningSpy = spyOn(notificationService, 'showWarning'); + openDialogSpy = spyOn(dialog, 'open').and.returnValue({ + afterOpened: () => of({}), + afterClosed: () => of({}), + componentInstance: { + error: new Subject() + } + }); + getNodeSpy = spyOn(service.nodesApi, 'getNode'); + }); + + it('should be able to fetch nodeId from given relative path', async () => { + getNodeSpy.and.returnValue(Promise.resolve(relativePathNodeResponseBody)); + const relativePathNodeEntry = await service.getNodeIdFromPath({ alias: 'mock-alias', path: 'mock-relativePath' }); + + expect(relativePathNodeEntry).toBe(relativePathNodeResponseBody.entry.id); + expect(getNodeSpy).toHaveBeenCalledWith('mock-alias', { + relativePath: 'mock-relativePath' + }); + }); + + it('should fetch nodeId based on alias if the relative path is undefined', async () => { + getNodeSpy.and.returnValue(Promise.resolve(aliasNodeResponseBody)); + const aliasNodeId = await service.getNodeIdFromPath({ alias: 'mock-alias', path: undefined }); + + expect(getNodeSpy).toHaveBeenCalledWith('mock-alias', undefined); + expect(aliasNodeId).toEqual('mock-alias-node-id'); + }); + + it('should be able to verify and return nodeId from given folderId', async () => { + getNodeSpy.and.returnValue(Promise.resolve(folderVariableValueResponseBody)); + const relativePathNodeEntry = await service.getNodeIdFromFolderVariableValue('mock-folder-id', '-my-'); + + expect(relativePathNodeEntry).toBe('mock-folder-id'); + expect(getNodeSpy).toHaveBeenCalledWith('mock-folder-id', undefined); + }); + + it('should return defined alias nodeId if the relative path does not exist', async () => { + getNodeSpy.and.returnValues(Promise.reject('Relative does not exists'), Promise.resolve(aliasNodeResponseBody)); + const aliasNodeId = await service.getNodeIdFromPath({ alias: 'mock-alias', path: 'mock-relativePath' }); + + expect(getNodeSpy).toHaveBeenCalledTimes(2); + expect(aliasNodeId).toEqual('mock-alias-node-id'); + }); + + it('should fetch default nodeId if the folderId is not defined', async () => { + getNodeSpy.and.returnValue(Promise.resolve(aliasNodeResponseBody)); + await service.getNodeIdFromFolderVariableValue('', '-my-'); + + expect(getNodeSpy).toHaveBeenCalledWith('-my-', undefined); + }); + + it('should return default nodeId if the given folder does not exist', async () => { + getNodeSpy.and.returnValues(Promise.reject('Folder does not exists'), Promise.resolve(aliasNodeResponseBody)); + const aliasNodeId = await service.getNodeIdFromFolderVariableValue('mock-folder-id', '-my-'); + + expect(getNodeSpy).toHaveBeenCalledTimes(2); + expect(aliasNodeId).toEqual('mock-alias-node-id'); + }); + + it('should be able to fetch nodeId from given alias', async () => { + getNodeSpy.and.returnValue(Promise.resolve(aliasNodeResponseBody)); + const aliasNodeId = await service.getNodeIdFromPath({ alias: 'mock-alias', path: undefined }); + + expect(getNodeSpy).toHaveBeenCalledWith('mock-alias', undefined); + expect(aliasNodeId).toEqual('mock-alias-node-id'); + }); + + it('should be able to open the content node selector panel dialog', () => { + service.openUploadFileDialog('nodeId', 'single', true, true); + + expect(openDialogSpy).toHaveBeenCalled(); + }); + + it('should show a warning notification if the relative path is invalid/deleted', async () => { + getNodeSpy.and.returnValue(Promise.reject('Relative path does not exists')); + + try { + expect(service.sourceNodeNotFound).toBe(false); + + await service.getNodeIdFromPath({ alias: 'mock-alias', path: 'mock-relativePath' }); + fail('An error should have been thrown'); + } catch (error) { + expect(error).toEqual('Relative path does not exists'); + expect(service.sourceNodeNotFound).toBe(true); + } + + await service.openUploadFileDialog('nodeId', 'single', true, true); + + expect(openDialogSpy).toHaveBeenCalled(); + expect(showWarningSpy).toHaveBeenCalledWith('ADF_CLOUD_TASK_FORM.ERROR.DESTINATION_FOLDER_PATH_ERROR'); + }); + + it('should show a warning notification if the defined folderVariable value is invalid/deleted', async () => { + getNodeSpy.and.returnValue(Promise.reject('Folder does not exists')); + + try { + expect(service.sourceNodeNotFound).toBe(false); + + await service.getNodeIdFromFolderVariableValue('mock-folder-id', '-my-'); + fail('An error should have been thrown'); + } catch (error) { + expect(error).toEqual('Folder does not exists'); + expect(service.sourceNodeNotFound).toBe(true); + } + + await service.openUploadFileDialog('nodeId', 'single', true, true); + + expect(openDialogSpy).toHaveBeenCalled(); + expect(showWarningSpy).toHaveBeenCalledWith('ADF_CLOUD_TASK_FORM.ERROR.DESTINATION_FOLDER_PATH_ERROR'); + }); + + it('should not show a notification if the relative path is valid', async () => { + getNodeSpy.and.returnValue(Promise.resolve(relativePathNodeResponseBody)); + await service.getNodeIdFromPath({ alias: 'mock-alias', path: 'mock-relativePath' }); + service.openUploadFileDialog('nodeId', 'single', true, true); + + expect(openDialogSpy).toHaveBeenCalled(); + expect(service.sourceNodeNotFound).toBe(false); + expect(showWarningSpy).not.toHaveBeenCalled(); + }); + + it('should not show a notification if the given folderVariable value is valid', async () => { + getNodeSpy.and.returnValue(Promise.resolve(folderVariableValueResponseBody)); + await service.getNodeIdFromFolderVariableValue('mock-folder-id'); + service.openUploadFileDialog('nodeId', 'single', true, true); + + expect(openDialogSpy).toHaveBeenCalled(); + expect(service.sourceNodeNotFound).toBe(false); + expect(showWarningSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts b/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts index 8f43a9771a..6b0633b8b1 100644 --- a/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts +++ b/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts @@ -16,22 +16,24 @@ */ import { Injectable } from '@angular/core'; -import { AlfrescoApiService, NotificationService } from '@alfresco/adf-core'; +import { AlfrescoApiService, LogService, NotificationService } from '@alfresco/adf-core'; import { MatDialog } from '@angular/material/dialog'; import { ContentNodeSelectorComponent, ContentNodeSelectorComponentData, NodeAction } from '@alfresco/adf-content-services'; -import { Node, NodesApi } from '@alfresco/js-api'; -import { Observable, Subject, throwError } from 'rxjs'; +import { Node, NodeEntry, NodesApi } from '@alfresco/js-api'; +import { from, Observable, Subject, throwError } from 'rxjs'; +import { catchError, map, mapTo } from 'rxjs/operators'; +import { DestinationFolderPathModel } from '../models/form-cloud-representation.model'; @Injectable({ providedIn: 'root' }) export class ContentCloudNodeSelectorService { - _nodesApi: NodesApi; + private _nodesApi: NodesApi; get nodesApi(): NodesApi { this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); return this._nodesApi; @@ -42,6 +44,7 @@ export class ContentCloudNodeSelectorService { constructor( private apiService: AlfrescoApiService, private notificationService: NotificationService, + private logService: LogService, private dialog: MatDialog) { } @@ -64,21 +67,47 @@ export class ContentCloudNodeSelectorService { return select; } - async fetchNodeIdFromRelativePath(alias: string, opts: { relativePath: string }): Promise { - const relativePathNodeEntry: any = await this.nodesApi - .getNode(alias, opts) - .catch((err) => { - this.sourceNodeNotFound = true; - return this.handleError(err); - }); - return relativePathNodeEntry?.entry?.id; + async getNodeIdFromPath(destinationFolderPath: DestinationFolderPathModel): Promise { + if (destinationFolderPath.alias && destinationFolderPath.path) { + try { + return await this.getNodeId(destinationFolderPath.alias, destinationFolderPath.path).toPromise(); + } catch (error) { + this.logService.error(error); + } + } + + return this.getNodeId(destinationFolderPath.alias).toPromise(); } - async fetchAliasNodeId(alias: string): Promise { - const aliasNodeEntry: any = await this.nodesApi - .getNode(alias) - .catch((err) => this.handleError(err)); - return aliasNodeEntry?.entry?.id; + async getNodeIdFromFolderVariableValue(variableValue: string, defaultAlias?: string): Promise { + const isExistingNode = await this.isExistingNode(variableValue); + return isExistingNode ? variableValue : this.getNodeId(defaultAlias).toPromise(); + } + + async isExistingNode(nodeId: string): Promise { + let isExistingNode = false; + if (nodeId) { + try { + isExistingNode = await this.getNodeId(nodeId).pipe(mapTo(true)).toPromise(); + } catch (error) { + this.logService.error(error); + } + } + return isExistingNode; + } + + private getNodeId(nodeId: string, relativePath?: string): Observable { + let opts: any; + if (relativePath) { + opts = { relativePath }; + } + return from(this.nodesApi.getNode(nodeId, opts)).pipe( + map((nodeEntry: NodeEntry) => nodeEntry.entry.id), + catchError((error) => { + this.sourceNodeNotFound = true; + return this.handleError(error); + }) + ); } private openContentNodeDialog(data: ContentNodeSelectorComponentData, currentPanelClass: string, chosenWidth: string) {