mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-24 17:31:52 +00:00
[ACA-3729] Join library action for Admin Users (#1801)
This commit is contained in:
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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());
|
||||
|
||||
|
@@ -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]));
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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'));
|
||||
|
@@ -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));
|
||||
}
|
||||
|
@@ -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());
|
||||
})
|
||||
);
|
||||
|
||||
|
Reference in New Issue
Block a user