mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-4911] migrate identity role service (#5096)
* migrate IdentityRoleService implementation * update unit tests * move interfaces to the origin * move models to proper places * migrate model to interface * fix test * update docs
This commit is contained in:
committed by
Eugenio Romano
parent
3fc9390666
commit
f731988ca6
93
lib/core/services/bpm-user.service.spec.ts
Normal file
93
lib/core/services/bpm-user.service.spec.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
/*!
|
||||
* @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 { BpmUserModel } from '../models/bpm-user.model';
|
||||
import { BpmUserService } from '../services/bpm-user.service';
|
||||
import { setupTestBed } from '../testing/setupTestBed';
|
||||
import { CoreModule } from '../core.module';
|
||||
import { AlfrescoApiService } from './alfresco-api.service';
|
||||
import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('Bpm user service', () => {
|
||||
|
||||
let service: BpmUserService;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
CoreModule.forRoot()
|
||||
],
|
||||
providers: [
|
||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
|
||||
]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
service = TestBed.get(BpmUserService);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
describe('when user is logged in', () => {
|
||||
|
||||
it('should be able to retrieve the user information', (done) => {
|
||||
service.getCurrentUserInfo().subscribe((user: BpmUserModel) => {
|
||||
expect(user).toBeDefined();
|
||||
expect(user.id).toBe(1);
|
||||
expect(user.lastName).toBe('fake-last-name');
|
||||
expect(user.fullname).toBe('fake-full-name');
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
'status': 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({
|
||||
lastName: 'fake-last-name',
|
||||
fullname: 'fake-full-name',
|
||||
groups: [],
|
||||
id: 1
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve avatar url for current user', () => {
|
||||
const path = service.getCurrentUserProfileImage();
|
||||
expect(path).toBeDefined();
|
||||
expect(path).toContain('/app/rest/admin/profile-picture');
|
||||
});
|
||||
|
||||
it('should catch errors on call for profile', (done) => {
|
||||
service.getCurrentUserInfo().subscribe(() => {
|
||||
}, () => {
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
73
lib/core/services/bpm-user.service.ts
Normal file
73
lib/core/services/bpm-user.service.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
* @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 { Observable, from, throwError } from 'rxjs';
|
||||
import { AlfrescoApiService } from './alfresco-api.service';
|
||||
import { LogService } from './log.service';
|
||||
import { BpmUserModel } from '../models/bpm-user.model';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
import { UserRepresentation } from '@alfresco/js-api';
|
||||
|
||||
/**
|
||||
*
|
||||
* BPMUserService retrieve all the information of an Ecm user.
|
||||
*
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class BpmUserService {
|
||||
|
||||
constructor(private apiService: AlfrescoApiService,
|
||||
private logService: LogService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about the current user.
|
||||
* @returns User information object
|
||||
*/
|
||||
getCurrentUserInfo(): Observable<BpmUserModel> {
|
||||
return from(this.apiService.getInstance().activiti.profileApi.getProfile())
|
||||
.pipe(
|
||||
map((userRepresentation: UserRepresentation) => {
|
||||
return new BpmUserModel(userRepresentation);
|
||||
}),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current user's profile image as a URL.
|
||||
* @returns URL string
|
||||
*/
|
||||
getCurrentUserProfileImage(): string {
|
||||
return this.apiService.getInstance().activiti.profileApi.getProfilePictureUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw the error
|
||||
* @param error
|
||||
*/
|
||||
private handleError(error: any) {
|
||||
// in a real world app, we may send the error to some remote logging infrastructure
|
||||
// instead of just logging it to the console
|
||||
this.logService.error(error);
|
||||
return throwError(error || 'Server error');
|
||||
}
|
||||
|
||||
}
|
105
lib/core/services/ecm-user.service.spec.ts
Normal file
105
lib/core/services/ecm-user.service.spec.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/*!
|
||||
* @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 { AuthenticationService, ContentService, AlfrescoApiService } from '.';
|
||||
import { fakeEcmUser } from '../mock/ecm-user.service.mock';
|
||||
import { EcmUserService } from '../services/ecm-user.service';
|
||||
import { setupTestBed } from '../testing/setupTestBed';
|
||||
import { CoreModule } from '../core.module';
|
||||
import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('EcmUserService', () => {
|
||||
|
||||
let service: EcmUserService;
|
||||
let authService: AuthenticationService;
|
||||
let contentService: ContentService;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
CoreModule.forRoot()
|
||||
],
|
||||
providers: [
|
||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
|
||||
]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
service = TestBed.get(EcmUserService);
|
||||
authService = TestBed.get(AuthenticationService);
|
||||
contentService = TestBed.get(ContentService);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
describe('when user is logged in', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(authService, 'isEcmLoggedIn').and.returnValue(true);
|
||||
});
|
||||
|
||||
it('should be able to retrieve current user info', (done) => {
|
||||
service.getCurrentUserInfo().subscribe(
|
||||
(user) => {
|
||||
expect(user).toBeDefined();
|
||||
expect(user.firstName).toEqual('fake-ecm-first-name');
|
||||
expect(user.lastName).toEqual('fake-ecm-last-name');
|
||||
expect(user.email).toEqual('fakeEcm@ecmUser.com');
|
||||
done();
|
||||
});
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({entry: fakeEcmUser})
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to log errors on call', (done) => {
|
||||
service.getCurrentUserInfo().subscribe(() => {
|
||||
}, () => {
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve avatar url for current user', () => {
|
||||
spyOn(contentService, 'getContentUrl').and.returnValue('fake/url/image/for/ecm/user');
|
||||
const urlRs = service.getUserProfileImage('fake-avatar-id');
|
||||
|
||||
expect(urlRs).toEqual('fake/url/image/for/ecm/user');
|
||||
});
|
||||
|
||||
it('should not call content service without avatar id', () => {
|
||||
spyOn(contentService, 'getContentUrl').and.callThrough();
|
||||
const urlRs = service.getUserProfileImage(undefined);
|
||||
|
||||
expect(urlRs).toBeNull();
|
||||
expect(contentService.getContentUrl).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
81
lib/core/services/ecm-user.service.ts
Normal file
81
lib/core/services/ecm-user.service.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
/*!
|
||||
* @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 { Observable, from, throwError } from 'rxjs';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
import { ContentService } from './content.service';
|
||||
import { AlfrescoApiService } from './alfresco-api.service';
|
||||
import { LogService } from './log.service';
|
||||
import { EcmUserModel } from '../models/ecm-user.model';
|
||||
import { PersonEntry } from '@alfresco/js-api';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EcmUserService {
|
||||
|
||||
constructor(private apiService: AlfrescoApiService,
|
||||
private contentService: ContentService,
|
||||
private logService: LogService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about a user identified by their username.
|
||||
* @param userName Target username
|
||||
* @returns User information
|
||||
*/
|
||||
getUserInfo(userName: string): Observable<EcmUserModel> {
|
||||
return from(this.apiService.getInstance().core.peopleApi.getPerson(userName))
|
||||
.pipe(
|
||||
map((personEntry: PersonEntry) => {
|
||||
return new EcmUserModel(personEntry.entry);
|
||||
}),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about the user who is currently logged-in.
|
||||
* @returns User information as for getUserInfo
|
||||
*/
|
||||
getCurrentUserInfo() {
|
||||
return this.getUserInfo('-me-');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a profile image as a URL.
|
||||
* @param avatarId Target avatar
|
||||
* @returns Image URL
|
||||
*/
|
||||
getUserProfileImage(avatarId: string): string {
|
||||
if (avatarId) {
|
||||
return this.contentService.getContentUrl(avatarId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw the error
|
||||
* @param error
|
||||
*/
|
||||
private handleError(error: any) {
|
||||
this.logService.error(error);
|
||||
return throwError(error || 'Server error');
|
||||
}
|
||||
|
||||
}
|
450
lib/core/services/identity-group.service.spec.ts
Normal file
450
lib/core/services/identity-group.service.spec.ts
Normal file
@@ -0,0 +1,450 @@
|
||||
/*!
|
||||
* @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 { async } from '@angular/core/testing';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import {
|
||||
AlfrescoApiServiceMock,
|
||||
CoreModule,
|
||||
setupTestBed,
|
||||
AlfrescoApiService,
|
||||
LogService,
|
||||
IdentityGroupService,
|
||||
IdentityGroupSearchParam,
|
||||
groupAPIMockError
|
||||
} from '@alfresco/adf-core';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { throwError, of } from 'rxjs';
|
||||
import {
|
||||
noRoleMappingApi,
|
||||
mockIdentityRoles,
|
||||
groupsMockApi,
|
||||
roleMappingApi,
|
||||
clientRoles,
|
||||
returnCallQueryParameters,
|
||||
returnCallUrl,
|
||||
applicationDetailsMockApi,
|
||||
mockApiError,
|
||||
mockIdentityGroup1,
|
||||
createGroupMappingApi,
|
||||
updateGroupMappingApi,
|
||||
deleteGroupMappingApi,
|
||||
mockIdentityGroupsCount
|
||||
} from '../mock/identity-group.service.mock';
|
||||
|
||||
describe('IdentityGroupService', () => {
|
||||
let service: IdentityGroupService;
|
||||
let apiService: AlfrescoApiService;
|
||||
let logService: LogService;
|
||||
|
||||
setupTestBed({
|
||||
imports: [CoreModule.forRoot()],
|
||||
providers: [
|
||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
|
||||
]
|
||||
});
|
||||
|
||||
beforeEach(async(() => {
|
||||
service = TestBed.get(IdentityGroupService);
|
||||
apiService = TestBed.get(AlfrescoApiService);
|
||||
logService = TestBed.get(LogService);
|
||||
}));
|
||||
|
||||
it('should be able to fetch groups based on group name', (done) => {
|
||||
spyOn(apiService, 'getInstance').and.returnValue(groupsMockApi);
|
||||
service.findGroupsByName(<IdentityGroupSearchParam> {name: 'mock'}).subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.length).toBe(5);
|
||||
expect(res[0].id).toBe('mock-group-id-1');
|
||||
expect(res[0].name).toBe('Mock Group 1');
|
||||
expect(res[1].id).toBe('mock-group-id-2');
|
||||
expect(res[1].name).toBe('Mock Group 2');
|
||||
expect(res[2].id).toBe('mock-group-id-3');
|
||||
expect(res[2].name).toBe('Mock Group 3');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return true if group has client role mapping', (done) => {
|
||||
spyOn(apiService, 'getInstance').and.returnValue(roleMappingApi);
|
||||
service.checkGroupHasClientApp('mock-group-id', 'mock-app-id').subscribe((hasRole) => {
|
||||
expect(hasRole).toBeDefined();
|
||||
expect(hasRole).toBe(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return false if group does not have client role mapping', (done) => {
|
||||
spyOn(apiService, 'getInstance').and.returnValue(noRoleMappingApi);
|
||||
service.checkGroupHasClientApp('mock-group-id', 'mock-app-id').subscribe((hasRole) => {
|
||||
expect(hasRole).toBeDefined();
|
||||
expect(hasRole).toBe(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should able to fetch group roles by groupId', (done) => {
|
||||
spyOn(service, 'getGroupRoles').and.returnValue(of(mockIdentityRoles));
|
||||
service.getGroupRoles('mock-group-id').subscribe(
|
||||
(res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.length).toEqual(3);
|
||||
expect(res[0].name).toEqual('MOCK-ADMIN-ROLE');
|
||||
expect(res[1].name).toEqual('MOCK-USER-ROLE');
|
||||
expect(res[2].name).toEqual('MOCK-ROLE-1');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Should not able to fetch group roles if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getGroupRoles').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getGroupRoles('mock-group-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not group roles');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true if group has given role', (done) => {
|
||||
spyOn(service, 'getGroupRoles').and.returnValue(of(mockIdentityRoles));
|
||||
service.checkGroupHasRole('mock-group-id', ['MOCK-ADMIN-ROLE']).subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false if group does not have given role', (done) => {
|
||||
spyOn(service, 'getGroupRoles').and.returnValue(of(mockIdentityRoles));
|
||||
service.checkGroupHasRole('mock-group-id', ['MOCK-ADMIN-MODELER']).subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should fetch client roles by groupId and clientId', (done) => {
|
||||
spyOn(service, 'getClientRoles').and.returnValue(of(clientRoles));
|
||||
service.getClientRoles('mock-group-id', 'mock-client-id').subscribe(
|
||||
(res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.length).toEqual(2);
|
||||
expect(res).toEqual(clientRoles);
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Should not fetch client roles if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getClientRoles').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getClientRoles('mock-group-id', 'mock-client-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not client roles');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true if group has client access', (done) => {
|
||||
spyOn(service, 'getClientRoles').and.returnValue(of(clientRoles));
|
||||
service.checkGroupHasClientApp('mock-group-id', 'mock-client-id').subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false if group does not have client access', (done) => {
|
||||
spyOn(service, 'getClientRoles').and.returnValue(of([]));
|
||||
service.checkGroupHasClientApp('mock-group-id', 'mock-client-id').subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true if group has any client role', (done) => {
|
||||
spyOn(service, 'checkGroupHasAnyClientAppRole').and.returnValue(of(true));
|
||||
service.checkGroupHasAnyClientAppRole('mock-group-id', 'mock-client-id', ['MOCK-USER-ROLE']).subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false if group does not have any client role', (done) => {
|
||||
spyOn(service, 'getClientRoles').and.returnValue(of([]));
|
||||
service.checkGroupHasAnyClientAppRole('mock-group-id', 'mock-client-id', ['MOCK-ADMIN-MODELER']).subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should append to the call all the parameters', (done) => {
|
||||
spyOn(apiService, 'getInstance').and.returnValue(returnCallQueryParameters);
|
||||
service.findGroupsByName(<IdentityGroupSearchParam> {name: 'mock'}).subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.search).toBe('mock');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should request groups api url', (done) => {
|
||||
spyOn(apiService, 'getInstance').and.returnValue(returnCallUrl);
|
||||
service.findGroupsByName(<IdentityGroupSearchParam> {name: 'mock'}).subscribe((requestUrl) => {
|
||||
expect(requestUrl).toBeDefined();
|
||||
expect(requestUrl).not.toBeNull();
|
||||
expect(requestUrl).toContain('/groups');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to fetch the client id', (done) => {
|
||||
spyOn(apiService, 'getInstance').and.returnValue(applicationDetailsMockApi);
|
||||
service.getClientIdByApplicationName('mock-app-name').subscribe((clientId) => {
|
||||
expect(clientId).toBeDefined();
|
||||
expect(clientId).not.toBeNull();
|
||||
expect(clientId).toBe('mock-app-id');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should notify errors returned from the API', (done) => {
|
||||
const logServiceSpy = spyOn(logService, 'error').and.callThrough();
|
||||
spyOn(apiService, 'getInstance').and.returnValue(mockApiError);
|
||||
service.findGroupsByName(<IdentityGroupSearchParam> {name: 'mock'}).subscribe(
|
||||
() => {},
|
||||
(res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toEqual(groupAPIMockError);
|
||||
expect(logServiceSpy).toHaveBeenCalled();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to all fetch groups', (done) => {
|
||||
spyOn(apiService, 'getInstance').and.returnValue(groupsMockApi);
|
||||
service.getGroups().subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.length).toBe(5);
|
||||
expect(res[0].id).toBe('mock-group-id-1');
|
||||
expect(res[0].name).toBe('Mock Group 1');
|
||||
expect(res[1].id).toBe('mock-group-id-2');
|
||||
expect(res[1].name).toBe('Mock Group 2');
|
||||
expect(res[2].id).toBe('mock-group-id-3');
|
||||
expect(res[2].name).toBe('Mock Group 3');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to fetch all group if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getGroups').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getGroups()
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not groups');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to query groups based on first & max params', (done) => {
|
||||
spyOn(service, 'getTotalGroupsCount').and.returnValue(of(mockIdentityGroupsCount));
|
||||
spyOn(apiService, 'getInstance').and.returnValue(groupsMockApi);
|
||||
service.queryGroups({first: 0, max: 5}).subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.entries.length).toBe(5);
|
||||
expect(res.entries[0].id).toBe('mock-group-id-1');
|
||||
expect(res.entries[0].name).toBe('Mock Group 1');
|
||||
expect(res.entries[1].id).toBe('mock-group-id-2');
|
||||
expect(res.entries[1].name).toBe('Mock Group 2');
|
||||
expect(res.entries[2].id).toBe('mock-group-id-3');
|
||||
expect(res.entries[2].name).toBe('Mock Group 3');
|
||||
expect(res.pagination.totalItems).toBe(10);
|
||||
expect(res.pagination.skipCount).toBe(0);
|
||||
expect(res.pagination.maxItems).toBe(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to query groups if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'queryGroups').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.queryGroups({first: 0, max: 5})
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not query groups');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to create group', (done) => {
|
||||
const createCustomApiSpy = spyOn(apiService, 'getInstance').and.returnValue(createGroupMappingApi);
|
||||
service.createGroup(mockIdentityGroup1).subscribe(() => {
|
||||
expect(createCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to create group if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'createGroup').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.createGroup(mockIdentityGroup1)
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to create group');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to update group', (done) => {
|
||||
const updateCustomApiSpy = spyOn(apiService, 'getInstance').and.returnValue(updateGroupMappingApi);
|
||||
service.updateGroup('mock-group-id', mockIdentityGroup1).subscribe(() => {
|
||||
expect(updateCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to update group if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'updateGroup').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.updateGroup('mock-group-id', mockIdentityGroup1)
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to update group');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to delete group', (done) => {
|
||||
const deleteCustomApiSpy = spyOn(apiService, 'getInstance').and.returnValue(deleteGroupMappingApi);
|
||||
service.deleteGroup('mock-group-id').subscribe(() => {
|
||||
expect(deleteCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to delete group if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'deleteGroup').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.deleteGroup('mock-group-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to delete group');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
347
lib/core/services/identity-group.service.ts
Normal file
347
lib/core/services/identity-group.service.ts
Normal file
@@ -0,0 +1,347 @@
|
||||
/*!
|
||||
* @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 { Observable, of, from, throwError } from 'rxjs';
|
||||
import { catchError, map, switchMap } from 'rxjs/operators';
|
||||
import { AppConfigService } from '../app-config/app-config.service';
|
||||
import { AlfrescoApiService } from './alfresco-api.service';
|
||||
import { LogService } from './log.service';
|
||||
import {
|
||||
IdentityGroupSearchParam,
|
||||
IdentityGroupQueryCloudRequestModel,
|
||||
IdentityGroupModel,
|
||||
IdentityGroupQueryResponse,
|
||||
IdentityGroupCountModel
|
||||
} from '../models/identity-group.model';
|
||||
import { IdentityRoleModel } from '../models/identity-role.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IdentityGroupService {
|
||||
|
||||
constructor(
|
||||
private alfrescoApiService: AlfrescoApiService,
|
||||
private appConfigService: AppConfigService,
|
||||
private logService: LogService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Gets all groups.
|
||||
* @returns Array of group information objects
|
||||
*/
|
||||
getGroups(): Observable<IdentityGroupModel[]> {
|
||||
const url = this.getGroupsApi();
|
||||
const httpMethod = 'GET', pathParams = {},
|
||||
queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, authNames = [], contentTypes = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam, authNames,
|
||||
contentTypes, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries groups.
|
||||
* @returns Array of user information objects
|
||||
*/
|
||||
queryGroups(requestQuery: IdentityGroupQueryCloudRequestModel): Observable<IdentityGroupQueryResponse> {
|
||||
const url = this.getGroupsApi();
|
||||
const httpMethod = 'GET', pathParams = {},
|
||||
queryParams = { first: requestQuery.first || 0, max: requestQuery.max || 5 }, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, authNames = [], contentTypes = ['application/json'];
|
||||
return this.getTotalGroupsCount().pipe(
|
||||
switchMap((totalCount: IdentityGroupCountModel) =>
|
||||
from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam, authNames,
|
||||
contentTypes, null, null, null)
|
||||
).pipe(
|
||||
map((response: any[]) => {
|
||||
return <IdentityGroupQueryResponse> {
|
||||
entries: response,
|
||||
pagination: {
|
||||
skipCount: requestQuery.first,
|
||||
maxItems: requestQuery.max,
|
||||
count: totalCount.count,
|
||||
hasMoreItems: false,
|
||||
totalItems: totalCount.count
|
||||
}
|
||||
};
|
||||
}),
|
||||
catchError((error) => this.handleError(error))
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets groups total count.
|
||||
* @returns Number of groups count.
|
||||
*/
|
||||
getTotalGroupsCount(): Observable<IdentityGroupCountModel> {
|
||||
const url = this.getGroupsApi() + `/count`;
|
||||
const contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
return from(this.alfrescoApiService.getInstance()
|
||||
.oauth2Auth.callCustomApi(url, 'GET',
|
||||
null, null, null,
|
||||
null, null, contentTypes,
|
||||
accepts, null, null, null)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new group.
|
||||
* @param newGroup Object of containing the new group details.
|
||||
* @returns Empty response when the group created.
|
||||
*/
|
||||
createGroup(newGroup: IdentityGroupModel): Observable<any> {
|
||||
const url = this.getGroupsApi();
|
||||
const httpMethod = 'POST', pathParams = {}, queryParams = {}, bodyParam = newGroup, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates group details.
|
||||
* @param groupId Id of the targeted group.
|
||||
* @param updatedGroup Object of containing the group details
|
||||
* @returns Empty response when the group updated.
|
||||
*/
|
||||
updateGroup(groupId: string, updatedGroup: IdentityGroupModel): Observable<any> {
|
||||
const url = this.getGroupsApi() + `/${groupId}`;
|
||||
const request = JSON.stringify(updatedGroup);
|
||||
const httpMethod = 'PUT', pathParams = {} , queryParams = {}, bodyParam = request, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes Group.
|
||||
* @param groupId Id of the group.
|
||||
* @returns Empty response when the group deleted.
|
||||
*/
|
||||
deleteGroup(groupId: string): Observable<any> {
|
||||
const url = this.getGroupsApi() + `/${groupId}`;
|
||||
const httpMethod = 'DELETE', pathParams = {} , queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds groups filtered by name.
|
||||
* @param searchParams Object containing the name filter string
|
||||
* @returns List of group information
|
||||
*/
|
||||
findGroupsByName(searchParams: IdentityGroupSearchParam): Observable<any> {
|
||||
if (searchParams.name === '') {
|
||||
return of([]);
|
||||
}
|
||||
const url = this.getGroupsApi();
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = {search: searchParams.name}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return (from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details for a specified group.
|
||||
* @param groupId Id of the target group
|
||||
* @returns Group details
|
||||
*/
|
||||
getGroupRoles(groupId: string): Observable<IdentityRoleModel[]> {
|
||||
const url = this.buildRolesUrl(groupId);
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return (from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a group has one or more roles from the supplied list.
|
||||
* @param groupId Id of the target group
|
||||
* @param roleNames Array of role names
|
||||
* @returns True if the group has one or more of the roles, false otherwise
|
||||
*/
|
||||
checkGroupHasRole(groupId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getGroupRoles(groupId).pipe(map((groupRoles: IdentityRoleModel[]) => {
|
||||
let hasRole = false;
|
||||
if (groupRoles && groupRoles.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = groupRoles.find((groupRole) => {
|
||||
return roleName === groupRole.name;
|
||||
});
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client Id using the app name.
|
||||
* @param applicationName Name of the app
|
||||
* @returns client Id string
|
||||
*/
|
||||
getClientIdByApplicationName(applicationName: string): Observable<string> {
|
||||
const url = this.getApplicationIdApi();
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = {clientId: applicationName}, bodyParam = {}, headerParams = {}, formParams = {},
|
||||
contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
return from(this.alfrescoApiService.getInstance()
|
||||
.oauth2Auth.callCustomApi(url, httpMethod, pathParams, queryParams, headerParams,
|
||||
formParams, bodyParam, contentTypes,
|
||||
accepts, Object, null, null)
|
||||
).pipe(
|
||||
map((response: any[]) => {
|
||||
const clientId = response && response.length > 0 ? response[0].id : '';
|
||||
return clientId;
|
||||
}),
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets client roles.
|
||||
* @param groupId Id of the target group
|
||||
* @param clientId Id of the client
|
||||
* @returns List of roles
|
||||
*/
|
||||
getClientRoles(groupId: string, clientId: string): Observable<IdentityRoleModel[]> {
|
||||
const url = this.groupClientRoleMappingApi(groupId, clientId);
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a group has a client app.
|
||||
* @param groupId Id of the target group
|
||||
* @param clientId Id of the client
|
||||
* @returns True if the group has the client app, false otherwise
|
||||
*/
|
||||
checkGroupHasClientApp(groupId: string, clientId: string): Observable<boolean> {
|
||||
return this.getClientRoles(groupId, clientId).pipe(
|
||||
map((response: any[]) => {
|
||||
if (response && response.length > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a group has any of the client app roles in the supplied list.
|
||||
* @param groupId Id of the target group
|
||||
* @param clientId Id of the client
|
||||
* @param roleNames Array of role names to check
|
||||
* @returns True if the group has one or more of the roles, false otherwise
|
||||
*/
|
||||
checkGroupHasAnyClientAppRole(groupId: string, clientId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getClientRoles(groupId, clientId).pipe(
|
||||
map((clientRoles: any[]) => {
|
||||
let hasRole = false;
|
||||
if (clientRoles.length > 0) {
|
||||
roleNames.forEach((roleName) => {
|
||||
const role = clientRoles.find((availableRole) => {
|
||||
return availableRole.name === roleName;
|
||||
});
|
||||
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
}),
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
private groupClientRoleMappingApi(groupId: string, clientId: string): string {
|
||||
return `${this.appConfigService.get('identityHost')}/groups/${groupId}/role-mappings/clients/${clientId}`;
|
||||
}
|
||||
|
||||
private getApplicationIdApi(): string {
|
||||
return `${this.appConfigService.get('identityHost')}/clients`;
|
||||
}
|
||||
|
||||
private getGroupsApi(): string {
|
||||
return `${this.appConfigService.get('identityHost')}/groups`;
|
||||
}
|
||||
|
||||
private buildRolesUrl(groupId: string): string {
|
||||
return `${this.appConfigService.get('identityHost')}/groups/${groupId}/role-mappings/realm/composite`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw the error
|
||||
* @param error
|
||||
*/
|
||||
private handleError(error: Response) {
|
||||
this.logService.error(error);
|
||||
return throwError(error || 'Server error');
|
||||
}
|
||||
}
|
140
lib/core/services/identity-role.service.spec.ts
Normal file
140
lib/core/services/identity-role.service.spec.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
/*!
|
||||
* @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 { setupTestBed } from '@alfresco/adf-core';
|
||||
import { HttpClientModule, HttpErrorResponse, HttpResponse } from '@angular/common/http';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { IdentityRoleResponseModel, IdentityRoleService } from './identity-role.service';
|
||||
|
||||
export let mockIdentityRole1 = {
|
||||
id: 'mock-id-1', name: 'Mock_Role_1', description: 'Mock desc1', clientRole: true, composite: false
|
||||
};
|
||||
|
||||
export let mockIdentityRole2 = {
|
||||
id: 'mock-id-2', name: 'Mock_Role_2', description: 'Mock desc2', clientRole: false, composite: true
|
||||
};
|
||||
|
||||
export let mockIdentityRole3 = {
|
||||
id: 'mock-id-3', name: 'Mock_Role_3', description: 'Mock desc3', clientRole: false, composite: false
|
||||
};
|
||||
|
||||
export let mockIdentityRoles = {
|
||||
entries: [
|
||||
mockIdentityRole1, mockIdentityRole2, mockIdentityRole3
|
||||
],
|
||||
pagination: {
|
||||
skipCount: 1,
|
||||
maxItems: 5,
|
||||
count: 100,
|
||||
hasMoreItems: false,
|
||||
totalItems: 100
|
||||
}
|
||||
};
|
||||
|
||||
describe('IdentityRoleService', () => {
|
||||
let service: IdentityRoleService;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
HttpClientModule
|
||||
]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
service = TestBed.get(IdentityRoleService);
|
||||
});
|
||||
|
||||
it('Should fetch roles', () => {
|
||||
spyOn(service, 'getRoles').and.returnValue(of(mockIdentityRoles));
|
||||
service.getRoles().subscribe((response: IdentityRoleResponseModel) => {
|
||||
expect(response).toBeDefined();
|
||||
|
||||
expect(response.entries[0]).toEqual(mockIdentityRole1);
|
||||
expect(response.entries[1]).toEqual(mockIdentityRole2);
|
||||
expect(response.entries[2]).toEqual(mockIdentityRole3);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to add role', (done) => {
|
||||
const response = new HttpResponse({
|
||||
body: [],
|
||||
'status': 201,
|
||||
'statusText': 'Created'
|
||||
});
|
||||
spyOn(service, 'addRole').and.returnValue(of(response));
|
||||
service.addRole(mockIdentityRole1).subscribe(
|
||||
(res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.status).toEqual(201);
|
||||
expect(res.statusText).toEqual('Created');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Should not add role if error occurred', () => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'test 404 error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
spyOn(service, 'addRole').and.returnValue(throwError(errorResponse));
|
||||
service.addRole(mockIdentityRole1)
|
||||
.subscribe(
|
||||
() => fail('expected an error'),
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('test 404 error');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to delete role', (done) => {
|
||||
const response = new HttpResponse({
|
||||
body: [],
|
||||
'status': 204,
|
||||
'statusText': 'No Content'
|
||||
});
|
||||
spyOn(service, 'deleteRole').and.returnValue(of(response));
|
||||
service.deleteRole(mockIdentityRole1).subscribe(
|
||||
(res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.status).toEqual(204);
|
||||
expect(res.statusText).toEqual('No Content');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Should not delete role if error occurred', () => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'test 404 error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
spyOn(service, 'deleteRole').and.returnValue(throwError(errorResponse));
|
||||
service.deleteRole(mockIdentityRole1)
|
||||
.subscribe(
|
||||
() => fail('expected an error'),
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('test 404 error');
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
128
lib/core/services/identity-role.service.ts
Normal file
128
lib/core/services/identity-role.service.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
/*!
|
||||
* @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 { HttpClient } from '@angular/common/http';
|
||||
import { throwError as observableThrowError, Observable } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { Pagination } from '@alfresco/js-api';
|
||||
import { IdentityRoleModel } from '../models/identity-role.model';
|
||||
import { AppConfigService } from '../app-config/app-config.service';
|
||||
import { LogService } from './log.service';
|
||||
|
||||
export interface IdentityRoleResponseModel {
|
||||
entries: IdentityRoleModel[];
|
||||
pagination: Pagination;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IdentityRoleService {
|
||||
contextRoot = '';
|
||||
identityHost = '';
|
||||
|
||||
constructor(
|
||||
protected http: HttpClient,
|
||||
protected appConfig: AppConfigService,
|
||||
protected logService: LogService
|
||||
) {
|
||||
this.contextRoot = this.appConfig.get('apiHost', '');
|
||||
this.identityHost = this.appConfig.get('identityHost');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ret all roles
|
||||
* @returns List of roles
|
||||
*/
|
||||
getRoles(
|
||||
skipCount: number = 0,
|
||||
size: number = 5
|
||||
): Observable<IdentityRoleResponseModel> {
|
||||
return this.http.get<any>(`${this.identityHost}/roles`).pipe(
|
||||
map(res => {
|
||||
return this.preparePaginationWithRoles(res, skipCount, size);
|
||||
}),
|
||||
catchError(error => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
private preparePaginationWithRoles(
|
||||
roles: IdentityRoleModel[],
|
||||
skipCount: number = 0,
|
||||
size: number = 5
|
||||
): IdentityRoleResponseModel {
|
||||
return {
|
||||
entries: roles.slice(skipCount, skipCount + size),
|
||||
pagination: {
|
||||
skipCount: skipCount,
|
||||
maxItems: size,
|
||||
count: roles.length,
|
||||
hasMoreItems: false,
|
||||
totalItems: roles.length
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new role
|
||||
* @param newRole Role model
|
||||
* @returns Server result payload
|
||||
*/
|
||||
addRole(newRole: IdentityRoleModel): Observable<any> {
|
||||
if (newRole) {
|
||||
const request = newRole;
|
||||
return this.http
|
||||
.post(`${this.identityHost}/roles`, request)
|
||||
.pipe(catchError(error => this.handleError(error)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete existing role
|
||||
* @param deletedRole Role model
|
||||
* @returns Server result payload
|
||||
*/
|
||||
deleteRole(deletedRole: IdentityRoleModel): Observable<any> {
|
||||
return this.http
|
||||
.delete(`${this.identityHost}/roles-by-id/${deletedRole.id}`)
|
||||
.pipe(catchError(error => this.handleError(error)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update existing role
|
||||
* @param updatedRole Role model
|
||||
* @param roleId Role id
|
||||
* @returns Server result payload
|
||||
*/
|
||||
updateRole(
|
||||
updatedRole: IdentityRoleModel,
|
||||
roleId: string
|
||||
): Observable<any> {
|
||||
if (updatedRole && roleId) {
|
||||
const request = updatedRole;
|
||||
return this.http
|
||||
.put(`${this.identityHost}/roles-by-id/${roleId}`, request)
|
||||
.pipe(catchError(error => this.handleError(error)));
|
||||
}
|
||||
}
|
||||
|
||||
private handleError(error: any) {
|
||||
this.logService.error(error);
|
||||
return observableThrowError(error || 'Server error');
|
||||
}
|
||||
}
|
689
lib/core/services/identity-user.service.spec.ts
Normal file
689
lib/core/services/identity-user.service.spec.ts
Normal file
@@ -0,0 +1,689 @@
|
||||
/*!
|
||||
* @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 { HttpErrorResponse } from '@angular/common/http';
|
||||
import { throwError, of } from 'rxjs';
|
||||
import {
|
||||
queryUsersMockApi,
|
||||
createUserMockApi,
|
||||
mockIdentityUser1,
|
||||
updateUserMockApi,
|
||||
mockIdentityUser2,
|
||||
deleteUserMockApi,
|
||||
getInvolvedGroupsMockApi,
|
||||
joinGroupMockApi,
|
||||
leaveGroupMockApi,
|
||||
getAvailableRolesMockApi,
|
||||
getAssignedRolesMockApi,
|
||||
getEffectiveRolesMockApi,
|
||||
assignRolesMockApi,
|
||||
mockIdentityRole,
|
||||
removeRolesMockApi,
|
||||
mockIdentityUsers,
|
||||
mockJoinGroupRequest
|
||||
} from 'core/mock/identity-user.service.mock';
|
||||
import { IdentityUserService } from '../services/identity-user.service';
|
||||
import { setupTestBed } from '../testing/setupTestBed';
|
||||
import { CoreModule } from '../core.module';
|
||||
import { AlfrescoApiService } from './alfresco-api.service';
|
||||
import { mockToken } from '../mock/jwt-helper.service.spec';
|
||||
import { IdentityRoleModel } from '../models/identity-role.model';
|
||||
import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
|
||||
|
||||
describe('IdentityUserService', () => {
|
||||
|
||||
const mockRoles = [
|
||||
{ id: 'id-1', name: 'MOCK-ADMIN-ROLE'},
|
||||
{ id: 'id-2', name: 'MOCK-USER-ROLE'},
|
||||
{ id: 'id-3', name: 'MOCK_MODELER-ROLE' },
|
||||
{ id: 'id-4', name: 'MOCK-ROLE-1' },
|
||||
{ id: 'id-5', name: 'MOCK-ROLE-2'}
|
||||
];
|
||||
|
||||
let service: IdentityUserService;
|
||||
let alfrescoApiService: AlfrescoApiService;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
CoreModule.forRoot()
|
||||
],
|
||||
providers: [
|
||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
|
||||
]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
service = TestBed.get(IdentityUserService);
|
||||
alfrescoApiService = TestBed.get(AlfrescoApiService);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const store = {};
|
||||
|
||||
spyOn(localStorage, 'getItem').and.callFake( (key: string): String => {
|
||||
return store[key] || null;
|
||||
});
|
||||
spyOn(localStorage, 'setItem').and.callFake((key: string, value: string): string => {
|
||||
return store[key] = <string> value;
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch identity user info from Jwt token', () => {
|
||||
localStorage.setItem('access_token', mockToken);
|
||||
const user = service.getCurrentUserInfo();
|
||||
expect(user).toBeDefined();
|
||||
expect(user.firstName).toEqual('John');
|
||||
expect(user.lastName).toEqual('Doe');
|
||||
expect(user.email).toEqual('johnDoe@gmail.com');
|
||||
expect(user.username).toEqual('johnDoe1');
|
||||
});
|
||||
|
||||
it('should fetch users ', (done) => {
|
||||
spyOn(service, 'getUsers').and.returnValue(of(mockIdentityUsers));
|
||||
service.getUsers().subscribe(
|
||||
res => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res[0].id).toEqual('mock-user-id-1');
|
||||
expect(res[0].username).toEqual('userName1');
|
||||
expect(res[1].id).toEqual('mock-user-id-2');
|
||||
expect(res[1].username).toEqual('userName2');
|
||||
expect(res[2].id).toEqual('mock-user-id-3');
|
||||
expect(res[2].username).toEqual('userName3');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Should not fetch users if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getUsers').and.returnValue(throwError(errorResponse));
|
||||
service.getUsers()
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not users');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should fetch roles by userId', (done) => {
|
||||
spyOn(service, 'getUserRoles').and.returnValue(of(mockRoles));
|
||||
service.getUserRoles('mock-user-id').subscribe(
|
||||
(res: IdentityRoleModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res[0].name).toEqual('MOCK-ADMIN-ROLE');
|
||||
expect(res[1].name).toEqual('MOCK-USER-ROLE');
|
||||
expect(res[4].name).toEqual('MOCK-ROLE-2');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Should not fetch roles if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getUserRoles').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getUserRoles('mock-user-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not users');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should fetch users by roles', (done) => {
|
||||
spyOn(service, 'getUsers').and.returnValue(of(mockIdentityUsers));
|
||||
spyOn(service, 'getUserRoles').and.returnValue(of(mockRoles));
|
||||
|
||||
service.getUsersByRolesWithCurrentUser([mockRoles[0].name]).then(
|
||||
res => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res[0].id).toEqual('mock-user-id-1');
|
||||
expect(res[0].username).toEqual('userName1');
|
||||
expect(res[1].id).toEqual('mock-user-id-2');
|
||||
expect(res[1].username).toEqual('userName2');
|
||||
expect(res[2].id).toEqual('mock-user-id-3');
|
||||
expect(res[2].username).toEqual('userName3');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Should not fetch users by roles if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getUsers').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getUsersByRolesWithCurrentUser([mockRoles[0].name])
|
||||
.catch(
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should fetch users by roles without current user', (done) => {
|
||||
spyOn(service, 'getUsers').and.returnValue(of(mockIdentityUsers));
|
||||
spyOn(service, 'getUserRoles').and.returnValue(of(mockRoles));
|
||||
spyOn(service, 'getCurrentUserInfo').and.returnValue(mockIdentityUsers[0]);
|
||||
|
||||
service.getUsersByRolesWithoutCurrentUser([mockRoles[0].name]).then(
|
||||
res => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res[0].id).toEqual('mock-user-id-2');
|
||||
expect(res[0].username).toEqual('userName2');
|
||||
expect(res[1].id).toEqual('mock-user-id-3');
|
||||
expect(res[1].username).toEqual('userName3');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true when user has access to an application', (done) => {
|
||||
spyOn(service, 'getClientIdByApplicationName').and.returnValue(of('mock-client'));
|
||||
spyOn(service, 'getClientRoles').and.returnValue(of(mockRoles));
|
||||
|
||||
service.checkUserHasClientApp('user-id', 'app-name').subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false when user does not have access to an application', (done) => {
|
||||
spyOn(service, 'getClientIdByApplicationName').and.returnValue(of('mock-client'));
|
||||
spyOn(service, 'getClientRoles').and.returnValue(of([]));
|
||||
|
||||
service.checkUserHasClientApp('user-id', 'app-name').subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true when user has any given application role', (done) => {
|
||||
spyOn(service, 'getClientIdByApplicationName').and.returnValue(of('mock-client'));
|
||||
spyOn(service, 'getClientRoles').and.returnValue(of(mockRoles));
|
||||
|
||||
service.checkUserHasAnyClientAppRole('user-id', 'app-name', [mockRoles[1].name] ).subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false when user does not have any given application role', (done) => {
|
||||
spyOn(service, 'getClientIdByApplicationName').and.returnValue(of('mock-client'));
|
||||
spyOn(service, 'getClientRoles').and.returnValue(of([]));
|
||||
|
||||
service.checkUserHasAnyClientAppRole('user-id', 'app-name', [mockRoles[1].name]).subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true if user has given role', (done) => {
|
||||
spyOn(service, 'getUserRoles').and.returnValue(of(mockRoles));
|
||||
service.checkUserHasRole('mock-user-id', ['MOCK-ROLE-1']).subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should return false if user does not have given role', (done) => {
|
||||
spyOn(service, 'getUserRoles').and.returnValue(of(mockRoles));
|
||||
service.checkUserHasRole('mock-user-id', ['MOCK-ROLE-10']).subscribe(
|
||||
(res: boolean) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to query users based on query params (first & max params)', (done) => {
|
||||
spyOn(alfrescoApiService, 'getInstance').and.returnValue(queryUsersMockApi);
|
||||
service.queryUsers({first: 0, max: 5}).subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.entries.length).toBe(5);
|
||||
expect(res.entries[0].id).toBe('mock-user-id-1');
|
||||
expect(res.entries[0].username).toBe('userName1');
|
||||
expect(res.entries[1].id).toBe('mock-user-id-2');
|
||||
expect(res.entries[1].username).toBe('userName2');
|
||||
expect(res.entries[2].id).toBe('mock-user-id-3');
|
||||
expect(res.entries[2].username).toBe('userName3');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not be able to query users if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'queryUsers').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.queryUsers({first: 0, max: 5})
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not users');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to create user', (done) => {
|
||||
const createCustomApiSpy = spyOn(alfrescoApiService, 'getInstance').and.returnValue(createUserMockApi);
|
||||
service.createUser(mockIdentityUser1).subscribe(() => {
|
||||
expect(createCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to create user if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'createUser').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.createUser(mockIdentityUser1)
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to create user');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to update user', (done) => {
|
||||
const updateCustomApiSpy = spyOn(alfrescoApiService, 'getInstance').and.returnValue(updateUserMockApi);
|
||||
service.updateUser('mock-id-2', mockIdentityUser2).subscribe(() => {
|
||||
expect(updateCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to update user if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'updateUser').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.updateUser('mock-id-2', mockIdentityUser2)
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to update user');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to delete group', (done) => {
|
||||
const deleteCustomApiSpy = spyOn(alfrescoApiService, 'getInstance').and.returnValue(deleteUserMockApi);
|
||||
service.deleteUser('mock-user-id').subscribe(() => {
|
||||
expect(deleteCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to delete user if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'deleteUser').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.deleteUser('mock-user-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to delete user');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to fetch involved groups based on user id', (done) => {
|
||||
spyOn(alfrescoApiService, 'getInstance').and.returnValue(getInvolvedGroupsMockApi);
|
||||
service.getInvolvedGroups('mock-user-id').subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.length).toBe(2);
|
||||
expect(res[0].id).toBe('mock-group-id-1');
|
||||
expect(res[0].name).toBe('Mock Group 1');
|
||||
expect(res[1].id).toBe('mock-group-id-2');
|
||||
expect(res[1].name).toBe('Mock Group 2');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not be able to fetch involved groups if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getInvolvedGroups').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getInvolvedGroups('mock-user-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not involved groups');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to join the group', (done) => {
|
||||
const joinGroupCustomApiSpy = spyOn(alfrescoApiService, 'getInstance').and.returnValue(joinGroupMockApi);
|
||||
service.joinGroup(mockJoinGroupRequest).subscribe(() => {
|
||||
expect(joinGroupCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to join group if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'joinGroup').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.joinGroup(mockJoinGroupRequest)
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to join group');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to leave the group', (done) => {
|
||||
const leaveGroupCustomApiSpy = spyOn(alfrescoApiService, 'getInstance').and.returnValue(leaveGroupMockApi);
|
||||
service.leaveGroup('mock-user-id', 'mock-group-id').subscribe(() => {
|
||||
expect(leaveGroupCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to leave group if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'leaveGroup').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.leaveGroup('mock-user-id', 'mock-group-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to leave group');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to fetch available roles based on user id', (done) => {
|
||||
spyOn(alfrescoApiService, 'getInstance').and.returnValue(getAvailableRolesMockApi);
|
||||
service.getAvailableRoles('mock-user-id').subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.length).toBe(4);
|
||||
expect(res[0].id).toBe('mock-role-id-1');
|
||||
expect(res[0].name).toBe('MOCK-ADMIN-ROLE');
|
||||
expect(res[1].id).toBe('mock-role-id-2');
|
||||
expect(res[1].name).toBe('MOCK-USER-ROLE');
|
||||
expect(res[2].id).toBe('mock-role-id-3');
|
||||
expect(res[2].name).toBe('MOCK_MODELER-ROLE');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not be able to fetch available roles based on user id if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getAvailableRoles').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getAvailableRoles('mock-user-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not available roles');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to fetch assigned roles based on user id', (done) => {
|
||||
spyOn(alfrescoApiService, 'getInstance').and.returnValue(getAssignedRolesMockApi);
|
||||
service.getAssignedRoles('mock-user-id').subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.length).toBe(3);
|
||||
expect(res[0].id).toBe('mock-role-id-1');
|
||||
expect(res[0].name).toBe('MOCK-ADMIN-ROLE');
|
||||
expect(res[1].id).toBe('mock-role-id-2');
|
||||
expect(res[1].name).toBe('MOCK_MODELER-ROLE');
|
||||
expect(res[2].id).toBe('mock-role-id-3');
|
||||
expect(res[2].name).toBe('MOCK-ROLE-1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not be able to fetch assigned roles based on user id if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getAssignedRoles').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getAssignedRoles('mock-user-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not assigned roles');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to fetch effective roles based on user id', (done) => {
|
||||
spyOn(alfrescoApiService, 'getInstance').and.returnValue(getEffectiveRolesMockApi);
|
||||
service.getEffectiveRoles('mock-user-id').subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.length).toBe(3);
|
||||
expect(res[0].id).toBe('mock-role-id-1');
|
||||
expect(res[0].name).toBe('MOCK-ACTIVE-ADMIN-ROLE');
|
||||
expect(res[1].id).toBe('mock-role-id-2');
|
||||
expect(res[1].name).toBe('MOCK-ACTIVE-USER-ROLE');
|
||||
expect(res[2].id).toBe('mock-role-id-3');
|
||||
expect(res[2].name).toBe('MOCK-ROLE-1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not be able to fetch effective roles based on user id if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'getEffectiveRoles').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.getEffectiveRoles('mock-user-id')
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not effective roles');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to assign roles to the user', (done) => {
|
||||
const assignRolesCustomApiSpy = spyOn(alfrescoApiService, 'getInstance').and.returnValue(assignRolesMockApi);
|
||||
service.assignRoles('mock-user-id', [mockIdentityRole]).subscribe(() => {
|
||||
expect(assignRolesCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to assign roles to the user if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'assignRoles').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.assignRoles('mock-user-id', [mockIdentityRole])
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to assigen roles to the user');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to remove roles', (done) => {
|
||||
const removeRolesCustomApiSpy = spyOn(alfrescoApiService, 'getInstance').and.returnValue(removeRolesMockApi);
|
||||
service.removeRoles('mock-user-id', [mockIdentityRole]).subscribe(() => {
|
||||
expect(removeRolesCustomApiSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not able to remove roles if error occurred', (done) => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'Mock Error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
});
|
||||
|
||||
spyOn(service, 'removeRoles').and.returnValue(throwError(errorResponse));
|
||||
|
||||
service.removeRoles('mock-user-id', [mockIdentityRole])
|
||||
.subscribe(
|
||||
() => {
|
||||
fail('expected an error, not to remove roles');
|
||||
},
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('Mock Error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
710
lib/core/services/identity-user.service.ts
Normal file
710
lib/core/services/identity-user.service.ts
Normal file
@@ -0,0 +1,710 @@
|
||||
/*!
|
||||
* @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 { Pagination } from '@alfresco/js-api';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { from, Observable, of, throwError } from 'rxjs';
|
||||
import { catchError, map, switchMap } from 'rxjs/operators';
|
||||
import { AppConfigService } from '../app-config/app-config.service';
|
||||
import { IdentityGroupModel } from '../models/identity-group.model';
|
||||
import { IdentityRoleModel } from '../models/identity-role.model';
|
||||
import { IdentityUserModel } from '../models/identity-user.model';
|
||||
import { AlfrescoApiService } from './alfresco-api.service';
|
||||
import { JwtHelperService } from './jwt-helper.service';
|
||||
import { LogService } from './log.service';
|
||||
|
||||
export interface IdentityUserQueryResponse {
|
||||
|
||||
entries: IdentityUserModel[];
|
||||
pagination: Pagination;
|
||||
}
|
||||
|
||||
export interface IdentityUserPasswordModel {
|
||||
type?: string;
|
||||
value?: string;
|
||||
temporary?: boolean;
|
||||
}
|
||||
|
||||
export interface IdentityUserQueryCloudRequestModel {
|
||||
first: number;
|
||||
max: number;
|
||||
}
|
||||
|
||||
export interface IdentityJoinGroupRequestModel {
|
||||
realm: string;
|
||||
userId: string;
|
||||
groupId: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IdentityUserService {
|
||||
|
||||
constructor(
|
||||
private jwtHelperService: JwtHelperService,
|
||||
private alfrescoApiService: AlfrescoApiService,
|
||||
private appConfigService: AppConfigService,
|
||||
private logService: LogService) { }
|
||||
|
||||
/**
|
||||
* Gets the name and other basic details of the current user.
|
||||
* @returns The user's details
|
||||
*/
|
||||
getCurrentUserInfo(): IdentityUserModel {
|
||||
const familyName = this.jwtHelperService.getValueFromLocalAccessToken<string>(JwtHelperService.FAMILY_NAME);
|
||||
const givenName = this.jwtHelperService.getValueFromLocalAccessToken<string>(JwtHelperService.GIVEN_NAME);
|
||||
const email = this.jwtHelperService.getValueFromLocalAccessToken<string>(JwtHelperService.USER_EMAIL);
|
||||
const username = this.jwtHelperService.getValueFromLocalAccessToken<string>(JwtHelperService.USER_PREFERRED_USERNAME);
|
||||
return { firstName: givenName, lastName: familyName, email: email, username: username };
|
||||
}
|
||||
|
||||
/**
|
||||
* Find users based on search input.
|
||||
* @param search Search query string
|
||||
* @returns List of users
|
||||
*/
|
||||
findUsersByName(search: string): Observable<any> {
|
||||
if (search === '') {
|
||||
return of([]);
|
||||
}
|
||||
const url = this.buildUserUrl();
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = { search: search }, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return (from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find users based on username input.
|
||||
* @param username Search query string
|
||||
* @returns List of users
|
||||
*/
|
||||
findUserByUsername(username: string): Observable<any> {
|
||||
if (username === '') {
|
||||
return of([]);
|
||||
}
|
||||
const url = this.buildUserUrl();
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = { username: username }, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return (from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find users based on email input.
|
||||
* @param email Search query string
|
||||
* @returns List of users
|
||||
*/
|
||||
findUserByEmail(email: string): Observable<any> {
|
||||
if (email === '') {
|
||||
return of([]);
|
||||
}
|
||||
const url = this.buildUserUrl();
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = { email: email }, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return (from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find users based on id input.
|
||||
* @param id Search query string
|
||||
* @returns users object
|
||||
*/
|
||||
findUserById(id: string): Observable<any> {
|
||||
if (id === '') {
|
||||
return of([]);
|
||||
}
|
||||
const url = this.buildUserUrl() + '/' + id;
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return (from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get client roles of a user for a particular client.
|
||||
* @param userId ID of the target user
|
||||
* @param clientId ID of the client app
|
||||
* @returns List of client roles
|
||||
*/
|
||||
getClientRoles(userId: string, clientId: string): Observable<any[]> {
|
||||
const url = this.buildUserClientRoleMapping(userId, clientId);
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether user has access to a client app.
|
||||
* @param userId ID of the target user
|
||||
* @param clientId ID of the client app
|
||||
* @returns True if the user has access, false otherwise
|
||||
*/
|
||||
checkUserHasClientApp(userId: string, clientId: string): Observable<boolean> {
|
||||
return this.getClientRoles(userId, clientId).pipe(
|
||||
map((clientRoles: any[]) => {
|
||||
if (clientRoles.length > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a user has any of the client app roles.
|
||||
* @param userId ID of the target user
|
||||
* @param clientId ID of the client app
|
||||
* @param roleNames List of role names to check for
|
||||
* @returns True if the user has one or more of the roles, false otherwise
|
||||
*/
|
||||
checkUserHasAnyClientAppRole(userId: string, clientId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getClientRoles(userId, clientId).pipe(
|
||||
map((clientRoles: any[]) => {
|
||||
let hasRole = false;
|
||||
if (clientRoles.length > 0) {
|
||||
roleNames.forEach((roleName) => {
|
||||
const role = clientRoles.find((availableRole) => {
|
||||
return availableRole.name === roleName;
|
||||
});
|
||||
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client ID for an application.
|
||||
* @param applicationName Name of the application
|
||||
* @returns Client ID string
|
||||
*/
|
||||
getClientIdByApplicationName(applicationName: string): Observable<string> {
|
||||
const url = this.buildGetClientsUrl();
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = { clientId: applicationName }, bodyParam = {}, headerParams = {}, formParams = {},
|
||||
contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
return from(this.alfrescoApiService.getInstance()
|
||||
.oauth2Auth.callCustomApi(url, httpMethod, pathParams, queryParams, headerParams,
|
||||
formParams, bodyParam, contentTypes,
|
||||
accepts, Object, null, null)
|
||||
).pipe(
|
||||
map((response: any[]) => {
|
||||
const clientId = response && response.length > 0 ? response[0].id : '';
|
||||
return clientId;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user has access to an application.
|
||||
* @param userId ID of the user
|
||||
* @param applicationName Name of the application
|
||||
* @returns True if the user has access, false otherwise
|
||||
*/
|
||||
checkUserHasApplicationAccess(userId: string, applicationName: string): Observable<boolean> {
|
||||
return this.getClientIdByApplicationName(applicationName).pipe(
|
||||
switchMap((clientId: string) => {
|
||||
return this.checkUserHasClientApp(userId, clientId);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user has any application role.
|
||||
* @param userId ID of the target user
|
||||
* @param applicationName Name of the application
|
||||
* @param roleNames List of role names to check for
|
||||
* @returns True if the user has one or more of the roles, false otherwise
|
||||
*/
|
||||
checkUserHasAnyApplicationRole(userId: string, applicationName: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getClientIdByApplicationName(applicationName).pipe(
|
||||
switchMap((clientId: string) => {
|
||||
return this.checkUserHasAnyClientAppRole(userId, clientId, roleNames);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details for all users.
|
||||
* @returns Array of user info objects
|
||||
*/
|
||||
getUsers(): Observable<IdentityUserModel[]> {
|
||||
const url = this.buildUserUrl();
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, authNames = [], contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam, authNames,
|
||||
contentTypes, accepts, null, null)
|
||||
).pipe(
|
||||
map((response: IdentityUserModel[]) => {
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of roles for a user.
|
||||
* @param userId ID of the user
|
||||
* @returns Array of role info objects
|
||||
*/
|
||||
getUserRoles(userId: string): Observable<IdentityRoleModel[]> {
|
||||
const url = this.buildRolesUrl(userId);
|
||||
const httpMethod = 'GET', pathParams = {}, queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, Object, null, null)
|
||||
).pipe(
|
||||
map((response: IdentityRoleModel[]) => {
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of users (including the current user) who have any of the roles in the supplied list.
|
||||
* @param roleNames List of role names to look for
|
||||
* @returns Array of user info objects
|
||||
*/
|
||||
async getUsersByRolesWithCurrentUser(roleNames: string[]): Promise<IdentityUserModel[]> {
|
||||
const filteredUsers: IdentityUserModel[] = [];
|
||||
if (roleNames && roleNames.length > 0) {
|
||||
const users = await this.getUsers().toPromise();
|
||||
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
const hasAnyRole = await this.userHasAnyRole(users[i].id, roleNames);
|
||||
if (hasAnyRole) {
|
||||
filteredUsers.push(users[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filteredUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of users (not including the current user) who have any of the roles in the supplied list.
|
||||
* @param roleNames List of role names to look for
|
||||
* @returns Array of user info objects
|
||||
*/
|
||||
async getUsersByRolesWithoutCurrentUser(roleNames: string[]): Promise<IdentityUserModel[]> {
|
||||
const filteredUsers: IdentityUserModel[] = [];
|
||||
if (roleNames && roleNames.length > 0) {
|
||||
const currentUser = this.getCurrentUserInfo();
|
||||
let users = await this.getUsers().toPromise();
|
||||
|
||||
users = users.filter((user) => { return user.username !== currentUser.username; });
|
||||
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
const hasAnyRole = await this.userHasAnyRole(users[i].id, roleNames);
|
||||
if (hasAnyRole) {
|
||||
filteredUsers.push(users[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filteredUsers;
|
||||
}
|
||||
|
||||
private async userHasAnyRole(userId: string, roleNames: string[]): Promise<boolean> {
|
||||
const userRoles = await this.getUserRoles(userId).toPromise();
|
||||
const hasAnyRole = roleNames.some((roleName) => {
|
||||
const filteredRoles = userRoles.filter((userRole) => {
|
||||
return userRole.name.toLocaleLowerCase() === roleName.toLocaleLowerCase();
|
||||
});
|
||||
|
||||
return filteredRoles.length > 0;
|
||||
});
|
||||
|
||||
return hasAnyRole;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user has one of the roles from a list.
|
||||
* @param userId ID of the target user
|
||||
* @param roleNames Array of roles to check for
|
||||
* @returns True if the user has one of the roles, false otherwise
|
||||
*/
|
||||
checkUserHasRole(userId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getUserRoles(userId).pipe(map((userRoles: IdentityRoleModel[]) => {
|
||||
let hasRole = false;
|
||||
if (userRoles && userRoles.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = userRoles.find((userRole) => {
|
||||
return roleName === userRole.name;
|
||||
});
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details for all users.
|
||||
* @returns Array of user information objects.
|
||||
*/
|
||||
queryUsers(requestQuery: IdentityUserQueryCloudRequestModel): Observable<IdentityUserQueryResponse> {
|
||||
const url = this.buildUserUrl();
|
||||
const httpMethod = 'GET', pathParams = {},
|
||||
queryParams = { first: requestQuery.first, max: requestQuery.max }, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, authNames = [], contentTypes = ['application/json'];
|
||||
|
||||
return this.getTotalUsersCount().pipe(
|
||||
switchMap((totalCount: any) =>
|
||||
from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam, authNames,
|
||||
contentTypes, null, null, null)
|
||||
).pipe(
|
||||
map((response: IdentityUserModel[]) => {
|
||||
return <IdentityUserQueryResponse> {
|
||||
entries: response,
|
||||
pagination: {
|
||||
skipCount: requestQuery.first,
|
||||
maxItems: requestQuery.max,
|
||||
count: totalCount,
|
||||
hasMoreItems: false,
|
||||
totalItems: totalCount
|
||||
}
|
||||
};
|
||||
}),
|
||||
catchError((error) => this.handleError(error))
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets users total count.
|
||||
* @returns Number of users count.
|
||||
*/
|
||||
getTotalUsersCount(): Observable<number> {
|
||||
const url = this.buildUserUrl() + `/count`;
|
||||
const contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
return from(this.alfrescoApiService.getInstance()
|
||||
.oauth2Auth.callCustomApi(url, 'GET',
|
||||
null, null, null,
|
||||
null, null, contentTypes,
|
||||
accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new user.
|
||||
* @param newUser Object containing the new user details.
|
||||
* @returns Empty response when the user created.
|
||||
*/
|
||||
createUser(newUser: IdentityUserModel): Observable<any> {
|
||||
const url = this.buildUserUrl();
|
||||
const request = JSON.stringify(newUser);
|
||||
const httpMethod = 'POST', pathParams = {}, queryParams = {}, bodyParam = request, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(
|
||||
this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)
|
||||
).pipe(catchError(error => this.handleError(error)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates user details.
|
||||
* @param userId Id of the user.
|
||||
* @param updatedUser Object containing the user details.
|
||||
* @returns Empty response when the user updated.
|
||||
*/
|
||||
updateUser(userId: string, updatedUser: IdentityUserModel): Observable<any> {
|
||||
const url = this.buildUserUrl() + '/' + userId;
|
||||
const request = JSON.stringify(updatedUser);
|
||||
const httpMethod = 'PUT', pathParams = {} , queryParams = {}, bodyParam = request, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes User.
|
||||
* @param userId Id of the user.
|
||||
* @returns Empty response when the user deleted.
|
||||
*/
|
||||
deleteUser(userId: string): Observable<any> {
|
||||
const url = this.buildUserUrl() + '/' + userId;
|
||||
const httpMethod = 'DELETE', pathParams = {} , queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes user password.
|
||||
* @param userId Id of the user.
|
||||
* @param credentials Details of user Credentials.
|
||||
* @returns Empty response when the password changed.
|
||||
*/
|
||||
changePassword(userId: string, newPassword: IdentityUserPasswordModel): Observable<any> {
|
||||
const url = this.buildUserUrl() + '/' + userId + '/reset-password';
|
||||
const request = JSON.stringify(newPassword);
|
||||
const httpMethod = 'PUT', pathParams = {} , queryParams = {}, bodyParam = request, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets involved groups.
|
||||
* @param userId Id of the user.
|
||||
* @returns Array of involved groups information objects.
|
||||
*/
|
||||
getInvolvedGroups(userId: string): Observable<IdentityGroupModel[]> {
|
||||
const url = this.buildUserUrl() + '/' + userId + '/groups/';
|
||||
const httpMethod = 'GET', pathParams = { id: userId},
|
||||
queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, authNames = [], contentTypes = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam, authNames,
|
||||
contentTypes, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins group.
|
||||
* @param joinGroupRequest Details of join group request (IdentityJoinGroupRequestModel).
|
||||
* @returns Empty response when the user joined the group.
|
||||
*/
|
||||
joinGroup(joinGroupRequest: IdentityJoinGroupRequestModel): Observable<any> {
|
||||
const url = this.buildUserUrl() + '/' + joinGroupRequest.userId + '/groups/' + joinGroupRequest.groupId;
|
||||
const request = JSON.stringify(joinGroupRequest);
|
||||
const httpMethod = 'PUT', pathParams = {} , queryParams = {}, bodyParam = request, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves group.
|
||||
* @param userId Id of the user.
|
||||
* @param groupId Id of the group.
|
||||
* @returns Empty response when the user left the group.
|
||||
*/
|
||||
leaveGroup(userId: any, groupId: string): Observable<any> {
|
||||
const url = this.buildUserUrl() + '/' + userId + '/groups/' + groupId;
|
||||
const httpMethod = 'DELETE', pathParams = {} , queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets available roles
|
||||
* @param userId Id of the user.
|
||||
* @returns Array of available roles information objects
|
||||
*/
|
||||
getAvailableRoles(userId: string): Observable<IdentityRoleModel[]> {
|
||||
const url = this.buildUserUrl() + '/' + userId + '/role-mappings/realm/available';
|
||||
const httpMethod = 'GET', pathParams = {},
|
||||
queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, authNames = [], contentTypes = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam, authNames,
|
||||
contentTypes, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets assigned roles.
|
||||
* @param userId Id of the user.
|
||||
* @returns Array of assigned roles information objects
|
||||
*/
|
||||
getAssignedRoles(userId: string): Observable<IdentityRoleModel[]> {
|
||||
const url = this.buildUserUrl() + '/' + userId + '/role-mappings/realm';
|
||||
const httpMethod = 'GET', pathParams = { id: userId},
|
||||
queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, authNames = [], contentTypes = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam, authNames,
|
||||
contentTypes, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets effective roles.
|
||||
* @param userId Id of the user.
|
||||
* @returns Array of composite roles information objects
|
||||
*/
|
||||
getEffectiveRoles(userId: string): Observable<IdentityRoleModel[]> {
|
||||
const url = this.buildUserUrl() + '/' + userId + '/role-mappings/realm/composite';
|
||||
const httpMethod = 'GET', pathParams = { id: userId},
|
||||
queryParams = {}, bodyParam = {}, headerParams = {},
|
||||
formParams = {}, authNames = [], contentTypes = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam, authNames,
|
||||
contentTypes, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns roles to the user.
|
||||
* @param userId Id of the user.
|
||||
* @param roles Array of roles.
|
||||
* @returns Empty response when the role assigned.
|
||||
*/
|
||||
assignRoles(userId: string, roles: IdentityRoleModel[]): Observable<any> {
|
||||
const url = this.buildUserUrl() + '/' + userId + '/role-mappings/realm';
|
||||
const request = JSON.stringify(roles);
|
||||
const httpMethod = 'POST', pathParams = {} , queryParams = {}, bodyParam = request, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes assigned roles.
|
||||
* @param userId Id of the user.
|
||||
* @param roles Array of roles.
|
||||
* @returns Empty response when the role removed.
|
||||
*/
|
||||
removeRoles(userId: string, removedRoles: IdentityRoleModel[]): Observable<any> {
|
||||
const url = this.buildUserUrl() + '/' + userId + '/role-mappings/realm';
|
||||
const request = JSON.stringify(removedRoles);
|
||||
const httpMethod = 'DELETE', pathParams = {} , queryParams = {}, bodyParam = request, headerParams = {},
|
||||
formParams = {}, contentTypes = ['application/json'], accepts = ['application/json'];
|
||||
|
||||
return from(this.alfrescoApiService.getInstance().oauth2Auth.callCustomApi(
|
||||
url, httpMethod, pathParams, queryParams,
|
||||
headerParams, formParams, bodyParam,
|
||||
contentTypes, accepts, null, null, null
|
||||
)).pipe(
|
||||
catchError((error) => this.handleError(error))
|
||||
);
|
||||
}
|
||||
|
||||
private buildUserUrl(): string {
|
||||
return `${this.appConfigService.get('identityHost')}/users`;
|
||||
}
|
||||
|
||||
private buildUserClientRoleMapping(userId: string, clientId: string): string {
|
||||
return `${this.appConfigService.get('identityHost')}/users/${userId}/role-mappings/clients/${clientId}/composite`;
|
||||
}
|
||||
|
||||
private buildRolesUrl(userId: string): string {
|
||||
return `${this.appConfigService.get('identityHost')}/users/${userId}/role-mappings/realm/composite`;
|
||||
}
|
||||
|
||||
private buildGetClientsUrl(): string {
|
||||
return `${this.appConfigService.get('identityHost')}/clients`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw the error
|
||||
* @param error
|
||||
*/
|
||||
private handleError(error: Response) {
|
||||
this.logService.error(error);
|
||||
return throwError(error || 'Server error');
|
||||
}
|
||||
}
|
@@ -56,3 +56,8 @@ export * from './lock.service';
|
||||
export * from './automation.service';
|
||||
export * from './automation.service';
|
||||
export * from './download.service';
|
||||
export * from './bpm-user.service';
|
||||
export * from './ecm-user.service';
|
||||
export * from './identity-user.service';
|
||||
export * from './identity-group.service';
|
||||
export * from './identity-role.service';
|
||||
|
Reference in New Issue
Block a user