From d1feb01d29717793f42658434692dff3af5f6b6d Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 26 Mar 2021 14:41:48 +0000 Subject: [PATCH] switch to ADF directives for libraries (#2068) --- package-lock.json | 47 ++-- package.json | 12 +- .../toggle-favorite-library.component.spec.ts | 3 +- .../toggle-favorite-library.component.ts | 2 +- .../toggle-join-library-button.component.ts | 4 +- .../toggle-join-library-menu.component.ts | 2 +- .../toggle-join-library.component.spec.ts | 7 +- src/app/directives/directives.module.ts | 10 +- .../library-favorite.directive.spec.ts | 125 ---------- .../directives/library-favorite.directive.ts | 115 --------- .../library-membership.directive.spec.ts | 224 ----------------- .../library-membership.directive.ts | 235 ------------------ 12 files changed, 45 insertions(+), 741 deletions(-) delete mode 100644 src/app/directives/library-favorite.directive.spec.ts delete mode 100644 src/app/directives/library-favorite.directive.ts delete mode 100644 src/app/directives/library-membership.directive.spec.ts delete mode 100644 src/app/directives/library-membership.directive.ts diff --git a/package-lock.json b/package-lock.json index 93771f866..52c041dae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@alfresco/adf-cli": { - "version": "4.4.0-31956", - "resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-4.4.0-31956.tgz", - "integrity": "sha512-D8v4nVyW90RwqNItIZRDvj10JaCVR5SqBfBG4LooqXopBYyDrt0Q2oAfdNqVumYT7ieOpC2ukjUrH83L1JqsBQ==", + "version": "4.4.0-31970", + "resolved": "https://registry.npmjs.org/@alfresco/adf-cli/-/adf-cli-4.4.0-31970.tgz", + "integrity": "sha512-H5byGDZgn6nyGxT32PdHovPe/2kJJqyMB3JSIPkKmKSJ4V6WHKPuz9OgUnrdgqUFnMtgTjKVT9purHElr7/lHw==", "dev": true, "requires": { "@alfresco/js-api": "4.3.0", @@ -21,6 +21,17 @@ "spdx-license-list": "^5.0.0" }, "dependencies": { + "@alfresco/js-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-4.3.0.tgz", + "integrity": "sha512-Q/OeFqQ5uQWG2mGsXBbiG6CKh5MJvdL5h3mkcDqyFHMzZwM+URB082KOlL+6tQN5JgWegHgA3jGZE8EOPviQxw==", + "dev": true, + "requires": { + "event-emitter": "^0.3.5", + "minimatch": "3.0.4", + "superagent": "^6.0.0" + } + }, "commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -30,42 +41,42 @@ } }, "@alfresco/adf-content-services": { - "version": "4.4.0-31956", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-4.4.0-31956.tgz", - "integrity": "sha512-pqFNzY/R5ErRMgCbf69HNKi8Bj8293WSI2mIELkI2NEJMUfLhnmN/hMLwXzHjYl4AwhBosVBoPr2EE6dP9zB2Q==", + "version": "4.4.0-31970", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-4.4.0-31970.tgz", + "integrity": "sha512-/G2l9vGc/PjFxhdaIzK8wE8uElFDMpPQyQfmgZkgV+ntjvfAWK/ll7X7fSFstmKyEUcU4ksyUu0f9ZEsQMg62A==", "requires": { "tslib": "^2.0.0" } }, "@alfresco/adf-core": { - "version": "4.4.0-31956", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-4.4.0-31956.tgz", - "integrity": "sha512-GYyzbR9GO/S3AwDO6RA69MBBB72omZB4V1Zc6q9TCpGWw10eFco/7m/TcYOgXUmcYo0Rj5r6HHx1PuBOkXMUHQ==", + "version": "4.4.0-31970", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-4.4.0-31970.tgz", + "integrity": "sha512-AzgzrxbwImHvBOiJSxq4xb2FNjz83ZyPXBX9wmddQaNHcjLsk/wqlJp59NZvJHluVIBNE8sYDfNUs/+q4fSOQA==", "requires": { "tslib": "^2.0.0" } }, "@alfresco/adf-extensions": { - "version": "4.4.0-31956", - "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-4.4.0-31956.tgz", - "integrity": "sha512-9RQG+90dOAPHrpCOOVZZ97B6LdebvPTn+d0UYubajWS/9zP7aOC0/AgE91rOcWYCwgLSj9mOMYs8jbAQLzKYjg==", + "version": "4.4.0-31970", + "resolved": "https://registry.npmjs.org/@alfresco/adf-extensions/-/adf-extensions-4.4.0-31970.tgz", + "integrity": "sha512-24m8seOsoqTnnthWgr5SnwtHuN7YX9UkYs96vfCr9ED7Vdxy93Cel3MYUAEHXb58w7DP98r0nnWsCIl09yYBig==", "requires": { "tslib": "^2.0.0" } }, "@alfresco/adf-testing": { - "version": "4.4.0-31956", - "resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-4.4.0-31956.tgz", - "integrity": "sha512-1xGhKAgSMstWgo5NKgFABYcf5vw1b6ZTNsFs6EjaKqp2PKsHQx0ucqCeFB+GgPFvf5PeZlfMnMBAQlXOsxyvZg==", + "version": "4.4.0-31970", + "resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-4.4.0-31970.tgz", + "integrity": "sha512-PSHbe+ie23z2Vpc1LnJJWvA1LjoyRBU3q0OhBpIxk8mOtidh2ZQ0mF5r6ZSasjxl5vZvwzmgiUoYyWg15PRfLA==", "dev": true, "requires": { "tslib": "^2.0.0" } }, "@alfresco/js-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-4.3.0.tgz", - "integrity": "sha512-Q/OeFqQ5uQWG2mGsXBbiG6CKh5MJvdL5h3mkcDqyFHMzZwM+URB082KOlL+6tQN5JgWegHgA3jGZE8EOPviQxw==", + "version": "4.4.0-3338", + "resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-4.4.0-3338.tgz", + "integrity": "sha512-og5isR44wYOQ+6rnM04thLXe1QPT3Kmfp6hBd825tI1tWzAMrpHfT8tXk/XOF6cUbbbbwQFpvPoZ9UEAzYoC+Q==", "requires": { "event-emitter": "^0.3.5", "minimatch": "3.0.4", diff --git a/package.json b/package.json index a37cf359d..620a3aec6 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,10 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "4.4.0-31956", - "@alfresco/adf-core": "4.4.0-31956", - "@alfresco/adf-extensions": "4.4.0-31956", - "@alfresco/js-api": "4.3.0", + "@alfresco/adf-content-services": "4.4.0-31970", + "@alfresco/adf-core": "4.4.0-31970", + "@alfresco/adf-extensions": "4.4.0-31970", + "@alfresco/js-api": "4.4.0-3338", "@angular/animations": "10.0.4", "@angular/cdk": "^10.0.2", "@angular/common": "10.0.4", @@ -57,8 +57,8 @@ "zone.js": "~0.10.2" }, "devDependencies": { - "@alfresco/adf-cli": "4.4.0-31956", - "@alfresco/adf-testing": "4.4.0-31956", + "@alfresco/adf-cli": "4.4.0-31970", + "@alfresco/adf-testing": "4.4.0-31970", "@angular-custom-builders/lite-serve": "^0.2.3", "@angular-devkit/build-angular": "^0.1002.0", "@angular-devkit/build-ng-packagr": "^0.1002.0", diff --git a/src/app/components/toolbar/toggle-favorite-library/toggle-favorite-library.component.spec.ts b/src/app/components/toolbar/toggle-favorite-library/toggle-favorite-library.component.spec.ts index 92867bae3..b1d711352 100644 --- a/src/app/components/toolbar/toggle-favorite-library/toggle-favorite-library.component.spec.ts +++ b/src/app/components/toolbar/toggle-favorite-library/toggle-favorite-library.component.spec.ts @@ -26,7 +26,6 @@ import { TestBed, ComponentFixture } from '@angular/core/testing'; import { CoreModule, AlfrescoApiService } from '@alfresco/adf-core'; import { ToggleFavoriteLibraryComponent } from './toggle-favorite-library.component'; -import { LibraryFavoriteDirective } from '../../../directives/library-favorite.directive'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppTestingModule } from '../../../testing/app-testing.module'; @@ -48,7 +47,7 @@ describe('ToggleFavoriteLibraryComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), CoreModule.forRoot(), AppTestingModule], - declarations: [ToggleFavoriteLibraryComponent, LibraryFavoriteDirective], + declarations: [ToggleFavoriteLibraryComponent], providers: [ { provide: Router, diff --git a/src/app/components/toolbar/toggle-favorite-library/toggle-favorite-library.component.ts b/src/app/components/toolbar/toggle-favorite-library/toggle-favorite-library.component.ts index 5e81166e6..dce0ef455 100644 --- a/src/app/components/toolbar/toggle-favorite-library/toggle-favorite-library.component.ts +++ b/src/app/components/toolbar/toggle-favorite-library/toggle-favorite-library.component.ts @@ -38,7 +38,7 @@ import { Subject } from 'rxjs'; ` -}) -class TestComponent { - @ViewChild('favoriteLibrary', { static: true }) - directive: LibraryFavoriteDirective; - - selection: LibraryEntity = null; -} - -describe('LibraryFavoriteDirective', () => { - let fixture: ComponentFixture; - let api: AlfrescoApiService; - let component: TestComponent; - let selection: LibraryEntity; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), CoreModule.forRoot(), AppTestingModule], - declarations: [TestComponent, LibraryFavoriteDirective] - }); - fixture = TestBed.createComponent(TestComponent); - component = fixture.componentInstance; - api = TestBed.inject(AlfrescoApiService); - selection = { entry: { guid: 'guid', id: 'id', title: 'Site', visibility: 'PUBLIC' }, isLibrary: true, isFavorite: false }; - component.selection = selection; - }); - - it('should not check for favorite if no selection exists', () => { - spyOn(api.peopleApi, 'getFavoriteSite'); - fixture.detectChanges(); - - expect(api.peopleApi.getFavoriteSite).not.toHaveBeenCalled(); - }); - - it('should mark selection as favorite', async () => { - spyOn(api.peopleApi, 'getFavoriteSite').and.returnValue(Promise.resolve(null)); - - delete selection.isFavorite; - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(api.peopleApi.getFavoriteSite).toHaveBeenCalled(); - expect(component.directive.isFavorite()).toBe(true); - }); - - it('should mark selection not favorite', async () => { - spyOn(api.peopleApi, 'getFavoriteSite').and.returnValue(Promise.reject()); - - delete selection.isFavorite; - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(api.peopleApi.getFavoriteSite).toHaveBeenCalled(); - expect(component.directive.isFavorite()).toBe(false); - }); - - it('should call addFavorite() on click event when selection is not a favorite', async () => { - spyOn(api.peopleApi, 'getFavoriteSite').and.returnValue(Promise.reject()); - spyOn(api.peopleApi, 'addFavorite').and.returnValue(Promise.resolve(null)); - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(component.directive.isFavorite()).toBeFalsy(); - - fixture.nativeElement.querySelector('button').dispatchEvent(new MouseEvent('click')); - fixture.detectChanges(); - expect(api.peopleApi.addFavorite).toHaveBeenCalled(); - }); - - it('should call removeFavoriteSite() on click event when selection is favorite', async () => { - spyOn(api.peopleApi, 'getFavoriteSite').and.returnValue(Promise.resolve(null)); - spyOn(api.favoritesApi, 'removeFavoriteSite').and.returnValue(Promise.resolve()); - - selection.isFavorite = true; - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(component.directive.isFavorite()).toBeTruthy(); - - fixture.nativeElement.querySelector('button').dispatchEvent(new MouseEvent('click')); - - fixture.detectChanges(); - await fixture.whenStable(); - - expect(api.favoritesApi.removeFavoriteSite).toHaveBeenCalled(); - }); -}); diff --git a/src/app/directives/library-favorite.directive.ts b/src/app/directives/library-favorite.directive.ts deleted file mode 100644 index effaf7dac..000000000 --- a/src/app/directives/library-favorite.directive.ts +++ /dev/null @@ -1,115 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Directive, HostListener, Input, OnChanges, Output, EventEmitter } from '@angular/core'; -import { SiteBody, FavoriteBody, FavoriteEntry, Site } from '@alfresco/js-api'; -import { AlfrescoApiService } from '@alfresco/adf-core'; - -export interface LibraryEntity { - entry: Site; - isLibrary: boolean; - isFavorite: boolean; -} - -@Directive({ - selector: '[acaFavoriteLibrary]', - exportAs: 'favoriteLibrary' -}) -export class LibraryFavoriteDirective implements OnChanges { - @Input('acaFavoriteLibrary') - library: LibraryEntity = null; - - @Output() toggle = new EventEmitter(); - // tslint:disable-next-line: no-output-native - @Output() error = new EventEmitter(); - - private targetLibrary = null; - - @HostListener('click') - onClick() { - const guid = this.targetLibrary.entry.guid; - - if (this.targetLibrary.isFavorite) { - this.removeFavorite(guid); - } else { - this.addFavorite({ - target: { - site: { - guid - } - } - }); - } - } - - constructor(private alfrescoApiService: AlfrescoApiService) {} - - ngOnChanges(changes) { - if (!changes.library.currentValue) { - this.targetLibrary = null; - return; - } - - this.targetLibrary = changes.library.currentValue; - this.markFavoriteLibrary(changes.library.currentValue); - } - - isFavorite(): boolean { - return this.targetLibrary && this.targetLibrary.isFavorite; - } - - private async markFavoriteLibrary(library: LibraryEntity) { - if (this.targetLibrary.isFavorite === undefined) { - try { - await this.alfrescoApiService.peopleApi.getFavoriteSite('-me-', library.entry.id); - this.targetLibrary.isFavorite = true; - } catch { - this.targetLibrary.isFavorite = false; - } - } else { - this.targetLibrary = library; - } - } - - private addFavorite(favoriteBody: FavoriteBody) { - this.alfrescoApiService.peopleApi - .addFavorite('-me-', favoriteBody) - .then((libraryEntry: FavoriteEntry) => { - this.targetLibrary.isFavorite = true; - this.toggle.emit(libraryEntry); - }) - .catch((error) => this.error.emit(error)); - } - - private removeFavorite(favoriteId: string) { - this.alfrescoApiService.favoritesApi - .removeFavoriteSite('-me-', favoriteId) - .then((libraryBody: SiteBody) => { - this.targetLibrary.isFavorite = false; - this.toggle.emit(libraryBody); - }) - .catch((error) => this.error.emit(error)); - } -} diff --git a/src/app/directives/library-membership.directive.spec.ts b/src/app/directives/library-membership.directive.spec.ts deleted file mode 100644 index 9d48b7e4a..000000000 --- a/src/app/directives/library-membership.directive.spec.ts +++ /dev/null @@ -1,224 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { AlfrescoApiService, CoreModule, SitesService } from '@alfresco/adf-core'; -import { AppTestingModule } from '../testing/app-testing.module'; -import { DirectivesModule } from './directives.module'; -import { LibraryMembershipDirective } from './library-membership.directive'; -import { NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core'; -import { of, throwError, Subject } from 'rxjs'; -import { TranslateModule } from '@ngx-translate/core'; - -describe('LibraryMembershipDirective', () => { - let alfrescoApiService: AlfrescoApiService; - let directive: LibraryMembershipDirective; - let peopleApi: any; - let sitesService: SitesService; - let addMembershipSpy: jasmine.Spy; - let getMembershipSpy: jasmine.Spy; - let deleteMembershipSpy: jasmine.Spy; - let mockSupportedVersion = false; - - let testSiteEntry: any; - let requestedMembershipResponse: any; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), DirectivesModule, CoreModule.forRoot(), AppTestingModule], - schemas: [NO_ERRORS_SCHEMA] - }); - - testSiteEntry = { - id: 'id-1', - guid: 'site-1', - title: 'aa t m', - visibility: 'MODERATED' - }; - - requestedMembershipResponse = { - id: testSiteEntry.id, - createdAt: '2018-11-14', - site: testSiteEntry - }; - - alfrescoApiService = TestBed.inject(AlfrescoApiService); - sitesService = TestBed.inject(SitesService); - peopleApi = alfrescoApiService.getInstance().core.peopleApi; - directive = new LibraryMembershipDirective(alfrescoApiService, sitesService, { - ecmProductInfo$: new Subject(), - isVersionSupported: () => mockSupportedVersion - } as any); - }); - - describe('markMembershipRequest', () => { - beforeEach(() => { - getMembershipSpy = spyOn(peopleApi, 'getSiteMembershipRequest').and.returnValue(Promise.resolve({ entry: requestedMembershipResponse })); - }); - - it('should not check membership requests if no entry is selected', fakeAsync(() => { - const selection = {}; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - expect(getMembershipSpy).not.toHaveBeenCalled(); - })); - - it('should check if a membership request exists for the selected library', fakeAsync(() => { - const selection = { entry: {} }; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - expect(getMembershipSpy.calls.count()).toBe(1); - })); - - it('should remember when a membership request exists for selected library', fakeAsync(() => { - const selection = { entry: testSiteEntry }; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - expect(directive.targetSite.joinRequested).toBe(true); - })); - - it('should remember when a membership request is not found for selected library', fakeAsync(() => { - getMembershipSpy.and.returnValue(Promise.reject()); - - const selection = { entry: testSiteEntry }; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - expect(directive.targetSite.joinRequested).toBe(false); - })); - }); - - describe('toggleMembershipRequest', () => { - beforeEach(() => { - mockSupportedVersion = false; - getMembershipSpy = spyOn(peopleApi, 'getSiteMembershipRequest').and.returnValue(Promise.resolve({ entry: requestedMembershipResponse })); - addMembershipSpy = spyOn(peopleApi, 'addSiteMembershipRequest').and.returnValue(Promise.resolve({ entry: requestedMembershipResponse })); - deleteMembershipSpy = spyOn(peopleApi, 'removeSiteMembershipRequest').and.returnValue(Promise.resolve({})); - }); - - it('should do nothing if there is no selected library ', fakeAsync(() => { - const selection = {}; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - directive.toggleMembershipRequest(); - tick(); - expect(addMembershipSpy).not.toHaveBeenCalled(); - expect(deleteMembershipSpy).not.toHaveBeenCalled(); - })); - - it('should delete membership request if there is one', fakeAsync(() => { - const selection = { entry: testSiteEntry }; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - directive.toggleMembershipRequest(); - tick(); - expect(deleteMembershipSpy).toHaveBeenCalled(); - })); - - it('should call API to make a membership request if there is none', fakeAsync(() => { - const selection = { entry: { id: 'no-membership-requested' } }; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - directive.toggleMembershipRequest(); - tick(); - expect(addMembershipSpy).toHaveBeenCalledWith('-me-', { id: 'no-membership-requested' }); - expect(deleteMembershipSpy).not.toHaveBeenCalled(); - })); - - it("should add 'workspace' to send appropriate email", fakeAsync(() => { - mockSupportedVersion = true; - const selection = { entry: { id: 'no-membership-requested' } }; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - directive.toggleMembershipRequest(); - tick(); - expect(addMembershipSpy).toHaveBeenCalledWith('-me-', { id: 'no-membership-requested', client: 'workspace' }); - expect(deleteMembershipSpy).not.toHaveBeenCalled(); - })); - - it('should call API to add user to library if admin user', fakeAsync(() => { - const createSiteMembershipSpy = spyOn(sitesService, 'createSiteMembership').and.returnValue(of({} as any)); - const selection = { entry: { id: 'no-membership-requested' } }; - const selectionChange = new SimpleChange(null, selection, true); - directive.isAdmin = true; - directive.ngOnChanges({ selection: selectionChange }); - tick(); - directive.toggleMembershipRequest(); - tick(); - expect(createSiteMembershipSpy).toHaveBeenCalled(); - expect(addMembershipSpy).not.toHaveBeenCalled(); - })); - - it('should emit error when the request to join a library fails', fakeAsync(() => { - spyOn(directive.error, 'emit'); - addMembershipSpy.and.returnValue(throwError('err')); - - const selection = { entry: { id: 'no-membership-requested' } }; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - directive.toggleMembershipRequest(); - tick(); - expect(directive.error.emit).toHaveBeenCalled(); - })); - - it('should emit specific error message on invalid email address server error', fakeAsync(() => { - const emitErrorSpy = spyOn(directive.error, 'emit'); - const selection = { entry: { id: 'no-membership-requested' } }; - const change = new SimpleChange(null, selection, true); - directive.ngOnChanges({ selection: change }); - tick(); - - const testData = [ - { - fixture: 'Failed to resolve sender mail address', - expected: 'APP.MESSAGES.ERRORS.INVALID_SENDER_EMAIL' - }, - { - fixture: 'All recipients for the mail action were invalid', - expected: 'APP.MESSAGES.ERRORS.INVALID_RECEIVER_EMAIL' - } - ]; - - testData.forEach((data) => { - addMembershipSpy.and.returnValue(throwError({ message: data.fixture })); - emitErrorSpy.calls.reset(); - directive.toggleMembershipRequest(); - tick(); - expect(emitErrorSpy).toHaveBeenCalledWith({ - error: { message: data.fixture }, - i18nKey: data.expected - }); - }); - })); - }); -}); diff --git a/src/app/directives/library-membership.directive.ts b/src/app/directives/library-membership.directive.ts deleted file mode 100644 index 041a4612b..000000000 --- a/src/app/directives/library-membership.directive.ts +++ /dev/null @@ -1,235 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; -import { SiteEntry, SiteMembershipRequestBody, SiteMemberEntry, SiteMembershipRequestEntry } from '@alfresco/js-api'; -import { AlfrescoApiService, SitesService, VersionCompatibilityService } from '@alfresco/adf-core'; -import { BehaviorSubject, from, Observable } from 'rxjs'; - -export interface LibraryMembershipToggleEvent { - updatedEntry?: any; - shouldReload: boolean; - i18nKey: string; -} - -export interface LibraryMembershipErrorEvent { - error: any; - i18nKey: string; -} - -@Directive({ - selector: '[acaLibraryMembership]', - exportAs: 'libraryMembership' -}) -export class LibraryMembershipDirective implements OnChanges { - targetSite: any = null; - - isJoinRequested: BehaviorSubject = new BehaviorSubject(false); - - /** Site for which to toggle the membership request. */ - @Input('acaLibraryMembership') - selection: SiteEntry = null; - - /** Site for which to toggle the membership request. */ - @Input() - isAdmin = false; - - @Output() - toggle = new EventEmitter(); - - // tslint:disable-next-line: no-output-native - @Output() - error = new EventEmitter(); - - @HostListener('click') - onClick() { - this.toggleMembershipRequest(); - } - - constructor( - private alfrescoApiService: AlfrescoApiService, - private sitesService: SitesService, - private versionCompatibilityService: VersionCompatibilityService - ) {} - - ngOnChanges(changes: SimpleChanges) { - if (!changes.selection.currentValue || !changes.selection.currentValue.entry) { - this.targetSite = null; - - return; - } - this.targetSite = changes.selection.currentValue.entry; - this.markMembershipRequest(); - } - - toggleMembershipRequest() { - if (!this.targetSite) { - return; - } - - if (this.targetSite.joinRequested) { - this.cancelJoinRequest().subscribe( - () => { - this.targetSite.joinRequested = false; - this.isJoinRequested.next(false); - const info = { - updatedEntry: this.targetSite, - shouldReload: false, - i18nKey: 'APP.MESSAGES.INFO.JOIN_CANCELED' - }; - this.toggle.emit(info); - }, - (error) => { - const errWithMessage = { - error, - i18nKey: 'APP.MESSAGES.ERRORS.JOIN_CANCEL_FAILED' - }; - this.error.emit(errWithMessage); - } - ); - } - - if (!this.targetSite.joinRequested && !this.isAdmin) { - this.joinLibraryRequest().subscribe( - (createdMembership) => { - this.targetSite.joinRequested = true; - this.isJoinRequested.next(true); - - if (createdMembership.entry && createdMembership.entry.site && createdMembership.entry.site.role) { - const info = { - shouldReload: true, - i18nKey: 'APP.MESSAGES.INFO.JOINED' - }; - this.toggle.emit(info); - } else { - const info = { - updatedEntry: this.targetSite, - shouldReload: false, - i18nKey: 'APP.MESSAGES.INFO.JOIN_REQUESTED' - }; - this.toggle.emit(info); - } - }, - (error) => { - const errWithMessage = { - error, - i18nKey: 'APP.MESSAGES.ERRORS.JOIN_REQUEST_FAILED' - }; - - const senderEmailCheck = 'Failed to resolve sender mail address'; - const receiverEmailCheck = 'All recipients for the mail action were invalid'; - - if (error.message) { - if (error.message.includes(senderEmailCheck)) { - errWithMessage.i18nKey = 'APP.MESSAGES.ERRORS.INVALID_SENDER_EMAIL'; - } else if (error.message.includes(receiverEmailCheck)) { - errWithMessage.i18nKey = 'APP.MESSAGES.ERRORS.INVALID_RECEIVER_EMAIL'; - } - } - - this.error.emit(errWithMessage); - } - ); - } - - if (this.isAdmin) { - this.joinLibrary().subscribe( - (createdMembership: SiteMemberEntry) => { - if (createdMembership.entry && createdMembership.entry.role) { - const info = { - shouldReload: true, - i18nKey: 'APP.MESSAGES.INFO.JOINED' - }; - this.toggle.emit(info); - } - }, - (error) => { - const errWithMessage = { - error, - i18nKey: 'APP.MESSAGES.ERRORS.JOIN_REQUEST_FAILED' - }; - - const senderEmailCheck = 'Failed to resolve sender mail address'; - const receiverEmailCheck = 'All recipients for the mail action were invalid'; - - if (error.message) { - if (error.message.includes(senderEmailCheck)) { - errWithMessage.i18nKey = 'APP.MESSAGES.ERRORS.INVALID_SENDER_EMAIL'; - } else if (error.message.includes(receiverEmailCheck)) { - errWithMessage.i18nKey = 'APP.MESSAGES.ERRORS.INVALID_RECEIVER_EMAIL'; - } - } - - this.error.emit(errWithMessage); - } - ); - } - } - - markMembershipRequest() { - if (!this.targetSite) { - return; - } - - this.getMembershipRequest().subscribe( - (data) => { - if (data.entry.id === this.targetSite.id) { - this.targetSite.joinRequested = true; - this.isJoinRequested.next(true); - } - }, - () => { - this.targetSite.joinRequested = false; - this.isJoinRequested.next(false); - } - ); - } - - private joinLibraryRequest(): Observable { - const memberBody = { - id: this.targetSite.id - } as SiteMembershipRequestBody; - - if (this.versionCompatibilityService.isVersionSupported('7.0.0')) { - memberBody.client = 'workspace'; - } - return from(this.alfrescoApiService.peopleApi.addSiteMembershipRequest('-me-', memberBody)); - } - - private joinLibrary() { - return this.sitesService.createSiteMembership(this.targetSite.id, { - role: 'SiteConsumer', - id: '-me-' - }); - } - - private cancelJoinRequest() { - return from(this.alfrescoApiService.peopleApi.removeSiteMembershipRequest('-me-', this.targetSite.id)); - } - - private getMembershipRequest() { - return from(this.alfrescoApiService.peopleApi.getSiteMembershipRequest('-me-', this.targetSite.id)); - } -}