[ACA-3729] Join library action for Admin Users (#1801)

This commit is contained in:
davidcanonieto
2020-11-23 15:07:12 +00:00
committed by GitHub
parent 8186ee16ac
commit b504a224ea
8 changed files with 102 additions and 14 deletions

View File

@@ -26,6 +26,7 @@
import { RuleContext } from '@alfresco/adf-extensions';
import * as navigation from './navigation.rules';
import * as repository from './repository.rules';
import { isAdmin } from './user.rules';
export interface AcaRuleContext extends RuleContext {
withCredentials: boolean;
@@ -81,7 +82,10 @@ export function canShareFile(context: RuleContext): boolean {
* JSON ref: `canToggleJoinLibrary`
*/
export function canToggleJoinLibrary(context: RuleContext): boolean {
return [hasLibrarySelected(context), !isPrivateLibrary(context), hasNoLibraryRole(context)].every(Boolean);
return (
[hasLibrarySelected(context), !isPrivateLibrary(context), hasNoLibraryRole(context)].every(Boolean) ||
[hasLibrarySelected(context), isPrivateLibrary(context), hasNoLibraryRole(context), isAdmin(context)].every(Boolean)
);
}
/**

View File

@@ -31,7 +31,8 @@ export enum LibraryActionTypes {
Create = 'CREATE_LIBRARY',
Navigate = 'NAVIGATE_LIBRARY',
Update = 'UPDATE_LIBRARY',
Leave = 'LEAVE_LIBRARY'
Leave = 'LEAVE_LIBRARY',
Reload = 'RELOAD_LIBRARY'
}
export class DeleteLibraryAction implements Action {
@@ -61,3 +62,6 @@ export class LeaveLibraryAction implements Action {
constructor(public payload?: string) {}
}
export class ReloadLibraryAction implements Action {
readonly type = LibraryActionTypes.Reload;
}

View File

@@ -79,7 +79,7 @@ export class AppComponent implements OnInit, OnDestroy {
ngOnInit() {
this.alfrescoApiService.getInstance().on('error', (error: { status: number; response: any }) => {
if (error.status === 401 && !this.alfrescoApiService.isExcludedErrorListener(error?.response?.req?.url)) {
if (error.status === 401) {
if (!this.authenticationService.isLoggedIn()) {
this.store.dispatch(new CloseModalDialogsAction());

View File

@@ -23,8 +23,16 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { AppStore, SetSelectedNodesAction, SnackbarErrorAction, SnackbarInfoAction, getAppSelection } from '@alfresco/aca-shared/store';
import { SelectionState } from '@alfresco/adf-extensions';
import {
AppStore,
SetSelectedNodesAction,
SnackbarErrorAction,
SnackbarInfoAction,
getAppSelection,
getUserProfile,
ReloadLibraryAction
} from '@alfresco/aca-shared/store';
import { ProfileState, SelectionState } from '@alfresco/adf-extensions';
import { Component, ViewEncapsulation } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
@@ -41,6 +49,7 @@ import { ContentManagementService } from '../../../services/content-management.s
(toggle)="onToggleEvent($event)"
(error)="onErrorEvent($event)"
[acaLibraryMembership]="(selection$ | async).library"
[isAdmin]="(profile$ | async).isAdmin"
[attr.title]="(membership.isJoinRequested | async) ? ('APP.ACTIONS.CANCEL_JOIN' | translate) : ('APP.ACTIONS.JOIN' | translate)"
>
<mat-icon *ngIf="membership.isJoinRequested | async">cancel</mat-icon>
@@ -52,9 +61,11 @@ import { ContentManagementService } from '../../../services/content-management.s
})
export class ToggleJoinLibraryButtonComponent {
selection$: Observable<SelectionState>;
profile$: Observable<ProfileState>;
constructor(private store: Store<AppStore>, private content: ContentManagementService) {
this.selection$ = this.store.select(getAppSelection);
this.profile$ = this.store.select(getUserProfile);
}
onToggleEvent(event: LibraryMembershipToggleEvent) {
@@ -62,6 +73,7 @@ export class ToggleJoinLibraryButtonComponent {
if (event.shouldReload) {
this.content.libraryJoined.next();
this.store.dispatch(new ReloadLibraryAction());
} else {
if (event.updatedEntry) {
this.store.dispatch(new SetSelectedNodesAction([{ entry: event.updatedEntry, isLibrary: true } as any]));

View File

@@ -29,7 +29,7 @@ import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-core';
import { LibraryMembershipDirective } from '../../../directives/library-membership.directive';
import { Store } from '@ngrx/store';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { SnackbarErrorAction, SnackbarInfoAction } from '@alfresco/aca-shared/store';
import { ReloadLibraryAction, SnackbarErrorAction, SnackbarInfoAction } from '@alfresco/aca-shared/store';
import { AppTestingModule } from '../../../testing/app-testing.module';
import { ContentManagementService } from '../../../services/content-management.service';
import { ToggleJoinLibraryButtonComponent } from './toggle-join-library-button.component';
@@ -98,6 +98,13 @@ describe('ToggleJoinLibraryComponent', () => {
expect(storeMock.dispatch).toHaveBeenCalledWith(new SnackbarInfoAction(event.i18nKey));
});
it('should dispatch `ReloadLibraryAction` action on onToggleEvent', () => {
const event = { shouldReload: true, i18nKey: 'SOME_i18nKey' };
component.onToggleEvent(event);
expect(storeMock.dispatch).toHaveBeenCalledWith(new ReloadLibraryAction());
});
it('should call libraryJoined.next on contentManagementService onToggleEvent', (done) => {
spyOn(contentManagementService.libraryJoined, 'next').and.callThrough();

View File

@@ -24,18 +24,19 @@
*/
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { AlfrescoApiService, AlfrescoApiServiceMock, AppConfigService, CoreModule, StorageService } from '@alfresco/adf-core';
import { AlfrescoApiService, AlfrescoApiServiceMock, AppConfigService, CoreModule, SitesService, StorageService } 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 { throwError } from 'rxjs';
import { of, throwError } from 'rxjs';
import { TranslateModule } from '@ngx-translate/core';
describe('LibraryMembershipDirective', () => {
let alfrescoApiService: AlfrescoApiService;
let directive: LibraryMembershipDirective;
let peopleApi;
let sitesService;
let addMembershipSpy;
let getMembershipSpy;
let deleteMembershipSpy;
@@ -58,8 +59,9 @@ describe('LibraryMembershipDirective', () => {
schemas: [NO_ERRORS_SCHEMA]
});
alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService());
sitesService = new SitesService(alfrescoApiService);
peopleApi = alfrescoApiService.getInstance().core.peopleApi;
directive = new LibraryMembershipDirective(alfrescoApiService);
directive = new LibraryMembershipDirective(alfrescoApiService, sitesService);
});
describe('markMembershipRequest', () => {
@@ -141,6 +143,19 @@ describe('LibraryMembershipDirective', () => {
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({}));
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'));

View File

@@ -24,8 +24,8 @@
*/
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { SiteEntry, SiteMembershipRequestBody } from '@alfresco/js-api';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { SiteEntry, SiteMemberEntry, SiteMembershipRequestBody } from '@alfresco/js-api';
import { AlfrescoApiService, SitesService } from '@alfresco/adf-core';
import { BehaviorSubject, from } from 'rxjs';
export interface LibraryMembershipToggleEvent {
@@ -52,6 +52,10 @@ export class LibraryMembershipDirective implements OnChanges {
@Input('acaLibraryMembership')
selection: SiteEntry = null;
/** Site for which to toggle the membership request. */
@Input()
isAdmin = false;
@Output()
toggle = new EventEmitter<LibraryMembershipToggleEvent>();
@@ -64,7 +68,7 @@ export class LibraryMembershipDirective implements OnChanges {
this.toggleMembershipRequest();
}
constructor(private alfrescoApiService: AlfrescoApiService) {}
constructor(private alfrescoApiService: AlfrescoApiService, private sitesService: SitesService) {}
ngOnChanges(changes: SimpleChanges) {
if (!changes.selection.currentValue || !changes.selection.currentValue.entry) {
@@ -103,7 +107,7 @@ export class LibraryMembershipDirective implements OnChanges {
);
}
if (!this.targetSite.joinRequested) {
if (!this.targetSite.joinRequested && !this.isAdmin) {
this.joinLibraryRequest().subscribe(
(createdMembership) => {
this.targetSite.joinRequested = true;
@@ -145,6 +149,39 @@ export class LibraryMembershipDirective implements OnChanges {
}
);
}
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() {
@@ -174,6 +211,13 @@ export class LibraryMembershipDirective implements OnChanges {
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));
}

View File

@@ -33,7 +33,8 @@ import {
NavigateRouteAction,
SnackbarErrorAction,
UpdateLibraryAction,
getAppSelection
getAppSelection,
ReloadLibraryAction
} from '@alfresco/aca-shared/store';
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
@@ -86,6 +87,7 @@ export class LibraryEffects {
}
});
}
this.store.dispatch(new ReloadLibraryAction());
})
);