Fetch the userInfo once loggedIn and expose the capability of admin (#7682)

* Fetch the userInfo once loggedIn and expose the cabilibility of admin

* Rollback method

* Return same use if defined

* Use the same pepleContent service for UserInfoCOmpnent

* Remove useless import

* Use interface

* Use angular resolver instead of guard

* Remove fdescribe

* Fix linting

* Regenerate doc

* Improve doc

* Fix optional

* Fix the unit test

* Fix comment

* Fix lint

* Fix unit

* Add fetch user as part of the ssoGuard

* Fix unit test after fetch

* Add additional unit

* Fix await
This commit is contained in:
Maurizio Vitale
2022-06-27 12:02:01 +01:00
committed by GitHub
parent a30de37a02
commit 28a47e83d2
49 changed files with 378 additions and 332 deletions

View File

@@ -149,7 +149,7 @@ describe('ColumnsSelectorComponent', () => {
const firstColumnCheckbox = await loader.getHarness(MatCheckboxHarness);
const checkBoxName = await firstColumnCheckbox.getLabelText();
let toggledColumnItem = component.columnItems.find(item => item.title === checkBoxName);
const toggledColumnItem = component.columnItems.find(item => item.title === checkBoxName);
expect(toggledColumnItem.isHidden).toBeFalsy();
await firstColumnCheckbox.toggle();

View File

@@ -17,7 +17,6 @@
import { EcmCompanyModel } from '../models/ecm-company.model';
import { PersonEntry, Person, PersonPaging } from '@alfresco/js-api';
import { EcmUserModel } from '../models';
export const fakeEcmCompany: EcmCompanyModel = {
organization: 'company-fake-name',
@@ -30,7 +29,7 @@ export const fakeEcmCompany: EcmCompanyModel = {
email: 'fakeCompany@fake.com'
};
export const fakeEcmUser = new EcmUserModel({
export const fakeEcmUser = {
id: 'fake-id',
firstName: 'fake-ecm-first-name',
lastName: 'fake-ecm-last-name',
@@ -49,7 +48,14 @@ export const fakeEcmUser = new EcmUserModel({
userStatus: 'active',
enabled: true,
emailNotificationsEnabled: true
});
};
export const fakeEcmAdminUser = {
...fakeEcmUser,
capabilities: {
isAdmin: true
}
};
export const fakeEcmUser2 = {
id: 'another-fake-id',

View File

@@ -65,4 +65,8 @@ export class EcmUserModel {
this.properties = obj && obj.properties;
this.capabilities = obj && obj.capabilities;
}
isAdmin(): boolean {
return this.capabilities?.isAdmin;
}
}

View File

@@ -24,10 +24,8 @@ import { JwtHelperService } from './jwt-helper.service';
import { MatDialog } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { PeopleContentService } from './people-content.service';
import { of } from 'rxjs';
import { getFakeUserWithContentAdminCapability, getFakeUserWithContentUserCapability } from '../mock/ecm-user.service.mock';
import { UserAccessService } from './user-access.service';
import { AppConfigService } from '../app-config/app-config.service';
import { of } from 'rxjs';
describe('Auth Guard SSO role service', () => {
@@ -36,7 +34,6 @@ describe('Auth Guard SSO role service', () => {
let routerService: Router;
let peopleContentService: PeopleContentService;
let userAccessService: UserAccessService;
let appConfig: AppConfigService;
setupTestBed({
imports: [
@@ -46,8 +43,6 @@ describe('Auth Guard SSO role service', () => {
});
beforeEach(() => {
appConfig = TestBed.inject(AppConfigService);
appConfig.config.providers = 'ECM';
localStorage.clear();
authGuard = TestBed.inject(AuthGuardSsoRoleService);
jwtHelperService = TestBed.inject(JwtHelperService);
@@ -186,76 +181,51 @@ describe('Auth Guard SSO role service', () => {
describe('Content Admin', () => {
afterEach(() => {
peopleContentService.hasCheckedIsContentAdmin = false;
});
it('Should give access to a content section (ALFRESCO_ADMINISTRATORS) when the user has content admin capability', async () => {
spyOn(peopleContentService, 'getCurrentPerson').and.returnValue(of(getFakeUserWithContentAdminCapability()));
spyOn(peopleContentService, 'getCurrentUserInfo').and.returnValue(of({}));
spyOn(peopleContentService, 'isCurrentUserAdmin').and.returnValue(true);
spyUserAccess([], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['ALFRESCO_ADMINISTRATORS'] };
expect(await authGuard.canActivate(router)).toBeTruthy();
expect(await authGuard.canActivate(router)).toBe(true);
});
it('Should not give access to a content section (ALFRESCO_ADMINISTRATORS) when the user does not have content admin capability', async () => {
spyOn(peopleContentService, 'getCurrentPerson').and.returnValue(of(getFakeUserWithContentUserCapability()));
spyOn(peopleContentService, 'getCurrentUserInfo').and.returnValue(of({}));
spyOn(peopleContentService, 'isCurrentUserAdmin').and.returnValue(false);
spyUserAccess([], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['ALFRESCO_ADMINISTRATORS'] };
expect(await authGuard.canActivate(router)).toBeFalsy();
expect(await authGuard.canActivate(router)).toBe(false);
});
it('Should not call the service to check if the user has content admin capability when the roles do not contain ALFRESCO_ADMINISTRATORS', async () => {
const getCurrentPersonSpy = spyOn(peopleContentService, 'getCurrentPerson').and.returnValue(of(getFakeUserWithContentAdminCapability()));
const isCurrentAdminSpy = spyOn(peopleContentService, 'isCurrentUserAdmin').and.stub();
spyUserAccess([], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['fakeRole'] };
await authGuard.canActivate(router);
expect(getCurrentPersonSpy).not.toHaveBeenCalled();
});
it('Should not retrieve the user when the provider is BPM', async () => {
spyUserAccess([], {});
spyOn(peopleContentService, 'getCurrentPerson');
appConfig.config.providers = 'BPM';
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['ALFRESCO_ADMINISTRATORS'] };
const result = await authGuard.canActivate(router);
expect(result).toBeFalsy();
expect(peopleContentService.getCurrentPerson).not.toHaveBeenCalled();
});
it('Should not fail when the people service throws an error', async () => {
spyUserAccess([], {});
spyOn(peopleContentService, 'getCurrentPerson').and.throwError('404 Not found');
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['ALFRESCO_ADMINISTRATORS'] };
const result = await authGuard.canActivate(router);
expect(result).toBeFalsy();
expect(peopleContentService.getCurrentPerson).toHaveBeenCalled();
expect(isCurrentAdminSpy).not.toHaveBeenCalled();
});
});
describe('Excluded Roles', () => {
it('Should canActivate be false when the user has one of the excluded roles', async () => {
spyOn(peopleContentService, 'getCurrentPerson').and.returnValue(of(getFakeUserWithContentAdminCapability()));
spyUserAccess(['MOCK_USER_ROLE'], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['ALFRESCO_ADMINISTRATORS'], excludedRoles: ['MOCK_USER_ROLE'] };
router.data = { roles: ['MOCK_ANOTHER_ROLE'], excludedRoles: ['MOCK_USER_ROLE'] };
expect(await authGuard.canActivate(router)).toBeFalsy();
expect(await authGuard.canActivate(router)).toBe(false);
});
it('Should canActivate be true when the user has none of the excluded roles', async () => {
@@ -263,18 +233,31 @@ describe('Auth Guard SSO role service', () => {
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'], excludedRoles: ['MOCK_ROOT_USER_ROLE'] };
expect(await authGuard.canActivate(router)).toBeTruthy();
const result = await authGuard.canActivate(router);
expect(result).toBeTruthy();
});
it('Should canActivate be false when the user is a content admin and the ALFRESCO_ADMINISTRATORS role is excluded', async () => {
spyOn(peopleContentService, 'getCurrentPerson').and.returnValue(of(getFakeUserWithContentAdminCapability()));
it('Should canActivate be true when the user has none of the excluded role and is not a content admin', async () => {
spyOn(peopleContentService, 'getCurrentUserInfo').and.returnValue(of({}));
spyOn(peopleContentService, 'isCurrentUserAdmin').and.returnValue(false);
spyUserAccess(['MOCK_USER_ROLE'], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_USER_ROLE'], excludedRoles: ['ALFRESCO_ADMINISTRATORS'] };
expect(await authGuard.canActivate(router)).toBeFalsy();
expect(await authGuard.canActivate(router)).toBe(true);
});
it('Should canActivate be false if the user is a content admin but has one of the excluded roles', async () => {
const isCurrentAdminSpy = spyOn(peopleContentService, 'getCurrentUserInfo').and.returnValue(of({}));
spyOn(peopleContentService, 'isCurrentUserAdmin').and.returnValue(true);
spyUserAccess(['MOCK_USER_ROLE'], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['ALFRESCO_ADMINISTRATORS'], excludedRoles: ['MOCK_USER_ROLE'] };
expect(await authGuard.canActivate(router)).toBe(false);
expect(isCurrentAdminSpy).toHaveBeenCalled();
});
});
});

View File

@@ -20,7 +20,6 @@ import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
import { ContentGroups, PeopleContentService } from './people-content.service';
import { UserAccessService } from './user-access.service';
import { AppConfigService } from '../app-config/app-config.service';
@Injectable({
providedIn: 'root'
@@ -29,15 +28,13 @@ export class AuthGuardSsoRoleService implements CanActivate {
constructor(private userAccessService: UserAccessService,
private router: Router,
private dialog: MatDialog,
private peopleContentService: PeopleContentService,
private appConfig: AppConfigService) {
private peopleContentService: PeopleContentService) {
}
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
await this.userAccessService.fetchUserAccess();
let hasRealmRole = false;
let hasClientRole = true;
if (route.data) {
if (route.data['roles']) {
const rolesToCheck: string[] = route.data['roles'];
@@ -45,11 +42,7 @@ export class AuthGuardSsoRoleService implements CanActivate {
hasRealmRole = true;
} else {
const excludedRoles = route.data['excludedRoles'] || [];
let isContentAdmin = false;
if (this.checkContentAdministratorRole(rolesToCheck, excludedRoles)) {
isContentAdmin = await this.peopleContentService.isContentAdmin().catch(() => false);
}
hasRealmRole = excludedRoles.length ? this.checkAccessWithExcludedRoles(rolesToCheck, excludedRoles, isContentAdmin) : this.hasRoles(rolesToCheck, isContentAdmin);
hasRealmRole = await this.validateRoles(rolesToCheck, excludedRoles);
}
}
@@ -59,7 +52,6 @@ export class AuthGuardSsoRoleService implements CanActivate {
hasClientRole = this.userAccessService.hasApplicationAccess(clientRoleName, rolesToCheck);
}
}
const hasRole = hasRealmRole && hasClientRole;
if (!hasRole && route?.data && route.data['redirectUrl']) {
@@ -73,19 +65,23 @@ export class AuthGuardSsoRoleService implements CanActivate {
return hasRole;
}
private checkContentAdministratorRole(rolesToCheck: string[], excludedRoles: string[]): boolean {
const hasContentProvider = this.appConfig.config.providers === 'ECM' || this.appConfig.config.providers === 'ALL';
const checkAdminRole = rolesToCheck.includes(ContentGroups.ALFRESCO_ADMINISTRATORS) || excludedRoles.includes(ContentGroups.ALFRESCO_ADMINISTRATORS);
return hasContentProvider && checkAdminRole;
private async validateRoles(rolesToCheck: string[], excludedRoles?: string[]): Promise<boolean> {
if (excludedRoles?.length > 0) {
return await this.hasRoles(rolesToCheck) && !await this.hasRoles(excludedRoles);
}
return this.hasRoles(rolesToCheck);
}
private checkAccessWithExcludedRoles(rolesToCheck: string[], excludedRoles: string[], isContentAdmin: boolean): boolean {
return this.hasRoles(rolesToCheck, isContentAdmin) && !this.hasRoles(excludedRoles, isContentAdmin);
private async hasRoles(roles: string[] = []): Promise<boolean> {
if (this.containsAlfrescoAdminRole(roles)) {
await this.peopleContentService.getCurrentUserInfo().toPromise();
return this.peopleContentService.isCurrentUserAdmin() || this.userAccessService.hasGlobalAccess(roles);
}
return this.userAccessService.hasGlobalAccess(roles);
}
private hasRoles(rolesToCheck: string[], isContentAdmin: boolean): boolean {
return rolesToCheck.includes(ContentGroups.ALFRESCO_ADMINISTRATORS)
? this.userAccessService.hasGlobalAccess(rolesToCheck) || isContentAdmin
: this.userAccessService.hasGlobalAccess(rolesToCheck);
private containsAlfrescoAdminRole(roles: string []): boolean {
return roles.includes(ContentGroups.ALFRESCO_ADMINISTRATORS);
}
}

View File

@@ -15,16 +15,16 @@
* limitations under the License.
*/
import { fakeEcmUser, fakeEcmUserList, createNewPersonMock, getFakeUserWithContentAdminCapability } from '../mock/ecm-user.service.mock';
import { fakeEcmUserList, createNewPersonMock, fakeEcmUser, fakeEcmAdminUser } from '../mock/ecm-user.service.mock';
import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
import { CoreTestingModule } from '../testing/core.testing.module';
import { PeopleContentService, PeopleContentQueryResponse, PeopleContentQueryRequestModel } from './people-content.service';
import { PeopleContentService, PeopleContentQueryRequestModel } from './people-content.service';
import { AlfrescoApiService } from './alfresco-api.service';
import { TranslateModule } from '@ngx-translate/core';
import { TestBed } from '@angular/core/testing';
import { LogService } from './log.service';
import { PersonEntry } from '@alfresco/js-api';
import { AuthenticationService } from './authentication.service';
import { of } from 'rxjs';
describe('PeopleContentService', () => {
@@ -48,58 +48,31 @@ describe('PeopleContentService', () => {
logService = TestBed.inject(LogService);
});
it('should be able to fetch person details based on id', (done) => {
spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(Promise.resolve(new PersonEntry({ entry: fakeEcmUser })));
peopleContentService.getPerson('fake-id').subscribe((person) => {
expect(person.entry.id).toEqual('fake-id');
expect(person.entry.email).toEqual('fakeEcm@ecmUser.com');
done();
});
it('should be able to fetch person details based on id', async () => {
spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(of({entry: fakeEcmUser }));
const person = await peopleContentService.getPerson('fake-id').toPromise();
expect(person.id).toEqual('fake-id');
expect(person.email).toEqual('fakeEcm@ecmUser.com');
});
it('calls getPerson api method by an id', (done) => {
const getPersonSpy = spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(Promise.resolve(null));
peopleContentService.getPerson('fake-id').subscribe(() => {
expect(getPersonSpy).toHaveBeenCalledWith('fake-id');
done();
});
});
it('should be able to list people', async () => {
spyOn(peopleContentService.peopleApi, 'listPeople').and.returnValue(of(fakeEcmUserList));
const response = await peopleContentService.listPeople().toPromise();
const people = response.entries;
const pagination = response.pagination;
it('calls getPerson api method with "-me-"', (done) => {
const getPersonSpy = spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(Promise.resolve(null));
peopleContentService.getPerson('-me-').subscribe(() => {
expect(getPersonSpy).toHaveBeenCalledWith('-me-');
done();
});
});
expect(people).toBeDefined();
expect(people[0].id).toEqual('fake-id');
expect(people[1].id).toEqual('another-fake-id');
expect(pagination.count).toEqual(2);
expect(pagination.totalItems).toEqual(2);
expect(pagination.hasMoreItems).toBeFalsy();
expect(pagination.skipCount).toEqual(0);
it('should be able to list people', (done) => {
spyOn(peopleContentService.peopleApi, 'listPeople').and.returnValue(Promise.resolve(fakeEcmUserList));
peopleContentService.listPeople().subscribe((response: PeopleContentQueryResponse) => {
const people = response.entries;
const pagination = response.pagination;
expect(people).toBeDefined();
expect(people[0].id).toEqual('fake-id');
expect(people[1].id).toEqual('another-fake-id');
expect(pagination.count).toEqual(2);
expect(pagination.totalItems).toEqual(2);
expect(pagination.hasMoreItems).toBeFalsy();
expect(pagination.skipCount).toEqual(0);
done();
});
});
it('should call listPeople api method', (done) => {
const listPeopleSpy = spyOn(peopleContentService.peopleApi, 'listPeople').and.returnValue(Promise.resolve(fakeEcmUserList));
peopleContentService.listPeople().subscribe(() => {
expect(listPeopleSpy).toHaveBeenCalled();
done();
});
});
it('should call listPeople api with requested sorting params', async () => {
const listPeopleSpy = spyOn(peopleContentService.peopleApi, 'listPeople').and.returnValue(Promise.resolve(fakeEcmUserList));
const listPeopleSpy = spyOn(peopleContentService.peopleApi, 'listPeople').and.returnValue(of(fakeEcmUserList));
const requestQueryParams: PeopleContentQueryRequestModel = { skipCount: 10, maxItems: 20, sorting: { orderBy: 'firstName', direction: 'asc' } };
const expectedValue = { skipCount: 10, maxItems: 20, orderBy: ['firstName ASC'] };
@@ -109,7 +82,7 @@ describe('PeopleContentService', () => {
});
it('should not call listPeople api with sorting params if sorting is not defined', async () => {
const listPeopleSpy = spyOn(peopleContentService.peopleApi, 'listPeople').and.returnValue(Promise.resolve(fakeEcmUserList));
const listPeopleSpy = spyOn(peopleContentService.peopleApi, 'listPeople').and.returnValue(of(fakeEcmUserList));
const requestQueryParams: PeopleContentQueryRequestModel = { skipCount: 10, maxItems: 20, sorting: undefined };
const expectedValue = { skipCount: 10, maxItems: 20 };
@@ -118,60 +91,48 @@ describe('PeopleContentService', () => {
expect(listPeopleSpy).toHaveBeenCalledWith(expectedValue);
});
it('should be able to create new person', (done) => {
spyOn(peopleContentService.peopleApi, 'createPerson').and.returnValue(Promise.resolve(new PersonEntry({ entry: fakeEcmUser })));
peopleContentService.createPerson(createNewPersonMock).subscribe((person) => {
expect(person.id).toEqual('fake-id');
expect(person.email).toEqual('fakeEcm@ecmUser.com');
done();
});
});
it('should be able to call createPerson api with new person details', (done) => {
const createPersonSpy = spyOn(peopleContentService.peopleApi, 'createPerson').and.returnValue(Promise.resolve(new PersonEntry({ entry: fakeEcmUser })));
peopleContentService.createPerson(createNewPersonMock).subscribe((person) => {
expect(person.id).toEqual('fake-id');
expect(person.email).toEqual('fakeEcm@ecmUser.com');
expect(createPersonSpy).toHaveBeenCalledWith(createNewPersonMock, undefined);
done();
});
it('should be able to create new person', async () => {
spyOn(peopleContentService.peopleApi, 'createPerson').and.returnValue(of({entry: fakeEcmUser }));
const newUser = await peopleContentService.createPerson(createNewPersonMock).toPromise();
expect(newUser.id).toEqual('fake-id');
expect(newUser.email).toEqual('fakeEcm@ecmUser.com');
});
it('should be able to throw an error if createPerson api failed', (done) => {
const createPersonSpy = spyOn(peopleContentService.peopleApi, 'createPerson').and.returnValue(Promise.reject({ message: 'failed to create new person' }));
spyOn(peopleContentService.peopleApi, 'createPerson').and.returnValue(Promise.reject('failed to create new person'));
const logErrorSpy = spyOn(logService, 'error');
peopleContentService.createPerson(createNewPersonMock).subscribe(
() => {},
(error) => {
expect(error).toEqual({ message: 'failed to create new person' });
expect(createPersonSpy).toHaveBeenCalled();
expect(logErrorSpy).toHaveBeenCalledWith({ message: 'failed to create new person' });
done();
});
() => {},
(error) => {
expect(logErrorSpy).toHaveBeenCalledWith('failed to create new person');
expect(error).toEqual('failed to create new person');
done();
}
);
});
it('Should make the api call to check if the user is a content admin only once', async () => {
const getCurrentPersonSpy = spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(Promise.resolve(getFakeUserWithContentAdminCapability()));
const getCurrentPersonSpy = spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(of({entry: fakeEcmAdminUser}));
expect(await peopleContentService.isContentAdmin()).toBe(true);
const user = await peopleContentService.getCurrentUserInfo().toPromise();
expect(user.id).toEqual('fake-id');
expect(peopleContentService.isCurrentUserAdmin()).toBe(true);
expect(getCurrentPersonSpy.calls.count()).toEqual(1);
await peopleContentService.isContentAdmin();
await peopleContentService.getCurrentUserInfo().toPromise();
expect(await peopleContentService.isContentAdmin()).toBe(true);
expect(await peopleContentService.isCurrentUserAdmin()).toBe(true);
expect(getCurrentPersonSpy.calls.count()).toEqual(1);
});
it('should reset the admin cache upon logout', async () => {
const getCurrentPersonSpy = spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(Promise.resolve(getFakeUserWithContentAdminCapability()));
spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(of({entry: fakeEcmAdminUser}));
expect(await peopleContentService.isContentAdmin()).toBeTruthy();
expect(peopleContentService.hasCheckedIsContentAdmin).toBeTruthy();
const user = await peopleContentService.getCurrentUserInfo().toPromise();
expect(user.id).toEqual('fake-id');
expect(peopleContentService.isCurrentUserAdmin()).toBe(true);
authenticationService.onLogout.next(true);
expect(peopleContentService.hasCheckedIsContentAdmin).toBeFalsy();
expect(await peopleContentService.isContentAdmin()).toBe(true);
expect(getCurrentPersonSpy.calls.count()).toEqual(2);
expect(peopleContentService.isCurrentUserAdmin()).toBe(false);
});
});

View File

@@ -16,13 +16,14 @@
*/
import { Injectable } from '@angular/core';
import { Observable, from, throwError } from 'rxjs';
import { Observable, from, throwError, of } from 'rxjs';
import { AlfrescoApiService } from './alfresco-api.service';
import { catchError, map } from 'rxjs/operators';
import { PersonEntry, PeopleApi, PersonBodyCreate, Pagination, PersonBodyUpdate } from '@alfresco/js-api';
import { catchError, map, tap } from 'rxjs/operators';
import { PeopleApi, PersonBodyCreate, Pagination, PersonBodyUpdate } from '@alfresco/js-api';
import { EcmUserModel } from '../models/ecm-user.model';
import { LogService } from './log.service';
import { AuthenticationService } from './authentication.service';
import { ContentService } from './content.service';
// eslint-disable-next-line no-shadow
export enum ContentGroups {
@@ -49,8 +50,7 @@ export interface PeopleContentQueryRequestModel {
providedIn: 'root'
})
export class PeopleContentService {
private hasContentAdminRole: boolean = false;
hasCheckedIsContentAdmin: boolean = false;
private currentUser: EcmUserModel;
private _peopleApi: PeopleApi;
get peopleApi(): PeopleApi {
@@ -61,11 +61,11 @@ export class PeopleContentService {
constructor(
private apiService: AlfrescoApiService,
authenticationService: AuthenticationService,
private logService: LogService
private logService: LogService,
private contentService: ContentService
) {
authenticationService.onLogout.subscribe(() => {
this.hasCheckedIsContentAdmin = false;
this.hasContentAdminRole = false;
this.resetLocalCurrentUser();
});
}
@@ -75,23 +75,46 @@ export class PeopleContentService {
* @param personId ID of the target user
* @returns User information
*/
getPerson(personId: string): Observable<any> {
const promise = this.peopleApi.getPerson(personId);
getPerson(personId: string): Observable<EcmUserModel> {
return from(this.peopleApi.getPerson(personId))
.pipe(
map((personEntry) => new EcmUserModel(personEntry.entry)),
tap( user => this.currentUser = user),
catchError((error) => this.handleError(error)));
}
return from(promise).pipe(
catchError((error) => this.handleError(error))
);
getCurrentPerson(): Observable<EcmUserModel> {
return this.getCurrentUserInfo();
}
/**
* Gets information about the user who is currently logged in.
* Gets information about the current user alias -me-
*
* @returns User information
*/
getCurrentPerson(): Observable<any> {
getCurrentUserInfo(): Observable<EcmUserModel> {
if (this.currentUser) {
return of(this.currentUser);
}
return this.getPerson('-me-');
}
/**
* Used to know if the current user has the admin capability
*
* @returns true or false
*/
isCurrentUserAdmin(): boolean {
return this.currentUser?.isAdmin() ?? false;
}
/**
* Reset the local current user object
*/
resetLocalCurrentUser() {
this.currentUser = undefined;
}
/**
* Gets a list of people.
*
@@ -144,13 +167,14 @@ export class PeopleContentService {
);
}
async isContentAdmin(): Promise<boolean> {
if (!this.hasCheckedIsContentAdmin) {
const user: PersonEntry = await this.getCurrentPerson().toPromise();
this.hasContentAdminRole = user?.entry?.capabilities?.isAdmin;
this.hasCheckedIsContentAdmin = true;
}
return this.hasContentAdminRole;
/**
* Returns a profile image as a URL.
*
* @param avatarId Target avatar
* @returns Image URL
*/
getUserProfileImage(avatarId: string): string {
return this.contentService.getContentUrl(avatarId);
}
private buildOrderArray(sorting: PeopleContentSortingModel): string[] {

View File

@@ -70,3 +70,4 @@ export * from './identity-group.interface';
export * from './language-item.interface';
export * from './sort-by-category.service';
export * from './user-access.service';
export * from './user-info-resolver.service';

View File

@@ -0,0 +1,41 @@
/*!
* @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 { Injectable } from '@angular/core';
import {
Resolve,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from '@angular/router';
import { EcmUserModel } from '../models/ecm-user.model';
import { Observable } from 'rxjs';
import { PeopleContentService } from './people-content.service';
@Injectable({
providedIn: 'root'
})
export class UserInfoResolverService implements Resolve<EcmUserModel> {
constructor(private peopleContentService: PeopleContentService) {}
resolve(
_route: ActivatedRouteSnapshot,
_state: RouterStateSnapshot
): Observable<EcmUserModel> {
return this.peopleContentService.getCurrentUserInfo();
}
}

View File

@@ -17,12 +17,11 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By, DomSanitizer } from '@angular/platform-browser';
import { AuthenticationService, ContentService } from '../../services';
import { AuthenticationService, ContentService, PeopleContentService } from '../../services';
import { InitialUsernamePipe } from '../../pipes';
import { fakeBpmUser } from '../../mock/bpm-user.service.mock';
import { fakeEcmEditedUser, fakeEcmUser, fakeEcmUserNoImage } from '../../mock/ecm-user.service.mock';
import { BpmUserService } from '../../services/bpm-user.service';
import { EcmUserService } from '../../services/ecm-user.service';
import { IdentityUserService } from '../../services/identity-user.service';
import { BpmUserModel } from '../../models/bpm-user.model';
import { EcmUserModel } from '../../models/ecm-user.model';
@@ -71,7 +70,7 @@ describe('User info component', () => {
let element: HTMLElement;
let authService: AuthenticationService;
let contentService: ContentService;
let ecmUserService: EcmUserService;
let peopleContentService: PeopleContentService;
let bpmUserService: BpmUserService;
let identityUserService: IdentityUserService;
@@ -106,7 +105,7 @@ describe('User info component', () => {
element = fixture.nativeElement;
authService = TestBed.inject(AuthenticationService);
ecmUserService = TestBed.inject(EcmUserService);
peopleContentService = TestBed.inject(PeopleContentService);
bpmUserService = TestBed.inject(BpmUserService);
contentService = TestBed.inject(ContentService);
identityUserService = TestBed.inject(IdentityUserService);
@@ -145,7 +144,7 @@ describe('User info component', () => {
isEcmLoggedInStub = spyOn(authService, 'isEcmLoggedIn').and.returnValue(true);
isLoggedInStub = spyOn(authService, 'isLoggedIn').and.returnValue(true);
isBpmLoggedInStub = spyOn(authService, 'isBpmLoggedIn').and.returnValue(false);
getCurrenEcmtUserInfoStub = spyOn(ecmUserService, 'getCurrentUserInfo').and.returnValue(of(fakeEcmUser));
getCurrenEcmtUserInfoStub = spyOn(peopleContentService, 'getCurrentUserInfo').and.returnValue(of(fakeEcmUser));
});
describe('ui ', () => {

View File

@@ -21,10 +21,10 @@ import { BpmUserModel } from '../../models/bpm-user.model';
import { EcmUserModel } from '../../models/ecm-user.model';
import { IdentityUserModel } from '../../models/identity-user.model';
import { BpmUserService } from '../../services/bpm-user.service';
import { EcmUserService } from '../../services/ecm-user.service';
import { IdentityUserService } from '../../services/identity-user.service';
import { of, Observable, Subject } from 'rxjs';
import { MatMenuTrigger, MenuPositionX, MenuPositionY } from '@angular/material/menu';
import { PeopleContentService } from '../../services/people-content.service';
@Component({
selector: 'adf-userinfo',
@@ -70,7 +70,7 @@ export class UserInfoComponent implements OnInit, OnDestroy {
selectedIndex: number;
private destroy$ = new Subject();
constructor(private ecmUserService: EcmUserService,
constructor(private peopleContentService: PeopleContentService,
private bpmUserService: BpmUserService,
private identityUserService: IdentityUserService,
private authService: AuthenticationService) {
@@ -125,7 +125,7 @@ export class UserInfoComponent implements OnInit, OnDestroy {
}
private loadEcmUserInfo(): void {
this.ecmUser$ = this.ecmUserService.getCurrentUserInfo();
this.ecmUser$ = this.peopleContentService.getCurrentUserInfo();
}
private loadBpmUserInfo() {
@@ -153,7 +153,7 @@ export class UserInfoComponent implements OnInit, OnDestroy {
}
getEcmAvatar(avatarId: any): string {
return this.ecmUserService.getUserProfileImage(avatarId);
return this.peopleContentService.getUserProfileImage(avatarId);
}
getBpmUserImage(): string {