[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:
Denys Vuika
2019-10-10 10:25:57 +01:00
committed by Eugenio Romano
parent 3fc9390666
commit f731988ca6
32 changed files with 440 additions and 229 deletions

View File

@@ -21,16 +21,15 @@ import { AuthenticationService, ContentService } from '../../services';
import { InitialUsernamePipe } from '../../pipes';
import { fakeBpmUser } from '../../mock/bpm-user.service.mock';
import { fakeEcmEditedUser, fakeEcmUser, fakeEcmUserNoImage } from '../../mock/ecm-user.service.mock';
import { BpmUserService } from '../services/bpm-user.service';
import { EcmUserService } from '../services/ecm-user.service';
import { IdentityUserService } from '../services/identity-user.service';
import { BpmUserModel } from './../models/bpm-user.model';
import { EcmUserModel } from './../models/ecm-user.model';
import { BpmUserService } from '../../services/bpm-user.service';
import { EcmUserService } from '../../services/ecm-user.service';
import { IdentityUserService } from '../../services/identity-user.service';
import { BpmUserModel } from '../../models/bpm-user.model';
import { EcmUserModel } from '../../models/ecm-user.model';
import { UserInfoComponent } from './user-info.component';
import { of } from 'rxjs';
import { setupTestBed } from '../../testing/setupTestBed';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { IdentityUserModel } from '../models/identity-user.model';
class FakeSanitizer extends DomSanitizer {
@@ -556,7 +555,7 @@ describe('User info component', () => {
fixture.detectChanges();
fixture.whenStable().then(() => {
component.identityUser$.subscribe((response: IdentityUserModel) => {
component.identityUser$.subscribe(response => {
expect(response).toBeDefined();
expect(response.firstName).toBe('fake-identity-first-name');
expect(response.lastName).toBe('fake-identity-last-name');
@@ -583,8 +582,7 @@ describe('User info component', () => {
it('should show last name if first name is null', async(() => {
fixture.detectChanges();
const fakeIdentityUser: IdentityUserModel = new IdentityUserModel(identityUserWithOutFirstNameMock);
getCurrentUserInfoStub.and.returnValue(fakeIdentityUser);
getCurrentUserInfoStub.and.returnValue(identityUserWithOutFirstNameMock);
fixture.detectChanges();
fixture.whenStable().then(() => {
@@ -598,8 +596,7 @@ describe('User info component', () => {
}));
it('should not show first name if it is null string', async(() => {
const fakeIdentityUser: IdentityUserModel = new IdentityUserModel(identityUserWithOutFirstNameMock);
getCurrentUserInfoStub.and.returnValue(of(fakeIdentityUser));
getCurrentUserInfoStub.and.returnValue(of(identityUserWithOutFirstNameMock));
fixture.detectChanges();
fixture.whenStable().then(() => {
@@ -613,8 +610,7 @@ describe('User info component', () => {
}));
it('should not show last name if it is null string', async(() => {
const fakeIdentityUser: IdentityUserModel = new IdentityUserModel(identityUserWithOutLastNameMock);
getCurrentUserInfoStub.and.returnValue(of(fakeIdentityUser));
getCurrentUserInfoStub.and.returnValue(of(identityUserWithOutLastNameMock));
fixture.detectChanges();
fixture.whenStable().then(() => {

View File

@@ -17,12 +17,12 @@
import { Component, Input, OnInit, ViewEncapsulation, ViewChild } from '@angular/core';
import { AuthenticationService } from '../../services/authentication.service';
import { BpmUserModel } from './../models/bpm-user.model';
import { EcmUserModel } from './../models/ecm-user.model';
import { IdentityUserModel } from './../models/identity-user.model';
import { BpmUserService } from './../services/bpm-user.service';
import { EcmUserService } from './../services/ecm-user.service';
import { IdentityUserService } from '../services/identity-user.service';
import { BpmUserModel } from '../../models/bpm-user.model';
import { EcmUserModel } from '../../models/ecm-user.model';
import { IdentityUserModel } from '../../models/identity-user.model';
import { BpmUserService } from '../../services/bpm-user.service';
import { EcmUserService } from '../../services/ecm-user.service';
import { IdentityUserService } from '../../services/identity-user.service';
import { of, Observable } from 'rxjs';
import { MatMenuTrigger } from '@angular/material';

View File

@@ -1,66 +0,0 @@
/*!
* @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 { UserRepresentation } from '@alfresco/js-api';
export class BpmUserModel implements UserRepresentation {
apps: any;
capabilities: string[];
company: string;
created: Date;
email: string;
externalId: string;
firstName: string;
lastName: string;
fullname: string;
groups: any;
id: number;
lastUpdate: Date;
latestSyncTimeStamp: Date;
password: string;
pictureId: number;
status: string;
tenantId: number;
tenantName: string;
tenantPictureId: number;
type: string;
constructor(input?: any) {
if (input) {
this.apps = input.apps;
this.capabilities = input.capabilities;
this.company = input.company;
this.created = input.created;
this.email = input.email;
this.externalId = input.externalId;
this.firstName = input.firstName;
this.lastName = input.lastName;
this.fullname = input.fullname;
this.groups = input.groups;
this.id = input.id;
this.lastUpdate = input.lastUpdate;
this.latestSyncTimeStamp = input.latestSyncTimeStamp;
this.password = input.password;
this.pictureId = input.pictureId;
this.status = input.status;
this.tenantId = input.tenantId;
this.tenantName = input.tenantName;
this.tenantPictureId = input.tenantPictureId;
this.type = input.type;
}
}
}

View File

@@ -1,61 +0,0 @@
/*!
* @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 { Person } from '@alfresco/js-api';
import { EcmCompanyModel } from '../../models/ecm-company.model';
export class EcmUserModel implements Person {
id: string;
firstName: string;
lastName: string;
description: string;
avatarId: string;
email: string;
skypeId: string;
googleId: string;
instantMessageId: string;
jobTitle: string;
location: string;
company: EcmCompanyModel;
mobile: string;
telephone: string;
statusUpdatedAt: Date;
userStatus: string;
enabled: boolean;
emailNotificationsEnabled: boolean;
constructor(obj?: any) {
this.id = obj && obj.id || null;
this.firstName = obj && obj.firstName;
this.lastName = obj && obj.lastName;
this.description = obj && obj.description || null;
this.avatarId = obj && obj.avatarId || null;
this.email = obj && obj.email || null;
this.skypeId = obj && obj.skypeId;
this.googleId = obj && obj.googleId;
this.instantMessageId = obj && obj.instantMessageId;
this.jobTitle = obj && obj.jobTitle || null;
this.location = obj && obj.location || null;
this.company = obj && obj.company;
this.mobile = obj && obj.mobile;
this.telephone = obj && obj.telephone;
this.statusUpdatedAt = obj && obj.statusUpdatedAt;
this.userStatus = obj && obj.userStatus;
this.enabled = obj && obj.enabled;
this.emailNotificationsEnabled = obj && obj.emailNotificationsEnabled;
}
}

View File

@@ -1,68 +0,0 @@
/*!
* @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';
export class IdentityGroupModel {
id: string;
name: string;
path: string;
realmRoles: string[];
clientRoles: any;
access: any;
attributes: any;
constructor(obj?: any) {
if (obj) {
this.id = obj.id || null;
this.name = obj.name || null;
this.path = obj.path || null;
this.realmRoles = obj.realmRoles || null;
this.clientRoles = obj.clientRoles || null;
this.access = obj.access || null;
this.attributes = obj.attributes || null;
}
}
}
export interface IdentityGroupSearchParam {
name?: string;
}
export interface IdentityGroupQueryResponse {
entries: IdentityGroupModel[];
pagination: Pagination;
}
export class IdentityGroupQueryCloudRequestModel {
first: number;
max: number;
constructor(obj?: any) {
if (obj) {
this.first = obj.first;
this.max = obj.max;
}
}
}
export interface IdentityGroupCountModel {
count: number;
}

View File

@@ -1,37 +0,0 @@
/*!
* @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.
*/
export class IdentityRoleModel {
id: string;
name: string;
description?: string;
clientRole?: boolean;
composite?: boolean;
containerId?: string;
scopeParamRequired?: boolean;
constructor(obj?: any) {
if (obj) {
this.id = obj.id || null;
this.name = obj.name || null;
this.description = obj.description || null;
this.clientRole = obj.clientRole || null;
this.composite = obj.composite || null;
this.containerId = obj.containerId || null;
this.scopeParamRequired = obj.scopeParamRequired || null;
}
}
}

View File

@@ -1,91 +0,0 @@
/*!
* @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';
export class IdentityUserModel {
id: string;
firstName: string;
lastName: string;
email: string;
username: string;
createdTimestamp?: any;
emailVerified?: boolean;
enabled?: boolean;
constructor(obj?: any) {
if (obj) {
this.id = obj.id || null;
this.firstName = obj.firstName || null;
this.lastName = obj.lastName || null;
this.email = obj.email || null;
this.username = obj.username || null;
this.createdTimestamp = obj.createdTimestamp || null;
this.emailVerified = obj.emailVerified || null;
this.enabled = obj.enabled || null;
}
}
}
export class IdentityUserPasswordModel {
type: string;
value: string;
temporary: boolean;
constructor(obj?: any) {
if (obj) {
this.type = obj.type;
this.value = obj.value;
this.temporary = obj.temporary;
}
}
}
export interface IdentityUserQueryResponse {
entries: IdentityUserModel[];
pagination: Pagination;
}
export class IdentityUserQueryCloudRequestModel {
first: number;
max: number;
constructor(obj?: any) {
if (obj) {
this.first = obj.first;
this.max = obj.max;
}
}
}
export class IdentityJoinGroupRequestModel {
realm: string;
userId: string;
groupId: string;
constructor(obj?: any) {
if (obj) {
this.realm = obj.realm;
this.userId = obj.userId;
this.groupId = obj.groupId;
}
}
}

View File

@@ -16,15 +16,4 @@
*/
export * from './components/user-info.component';
export * from './services/bpm-user.service';
export * from './services/ecm-user.service';
export * from './services/identity-user.service';
export * from './services/identity-group.service';
export * from './models/bpm-user.model';
export * from './models/ecm-user.model';
export * from './models/identity-group.model';
export * from './models/identity-user.model';
export * from './models/identity-role.model';
export * from './models/identity-group.model';
export * from './userinfo.module';

View File

@@ -1,93 +0,0 @@
/*!
* @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 '../../services/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
});
});
});
});

View File

@@ -1,73 +0,0 @@
/*!
* @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 '../../services/alfresco-api.service';
import { LogService } from '../../services/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');
}
}

View File

@@ -1,105 +0,0 @@
/*!
* @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 '../../services';
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();
});
});
});

View File

@@ -1,81 +0,0 @@
/*!
* @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 '../../services/content.service';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { LogService } from '../../services/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');
}
}

View File

@@ -1,450 +0,0 @@
/*!
* @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();
}
);
});
});

View File

@@ -1,347 +0,0 @@
/*!
* @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 '../../services/alfresco-api.service';
import { LogService } from '../../services/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');
}
}

View File

@@ -1,690 +0,0 @@
/*!
* @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 '../../services/alfresco-api.service';
import { mockToken } from './../../mock/jwt-helper.service.spec';
import { IdentityUserModel, IdentityUserQueryCloudRequestModel } from '../models/identity-user.model';
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: IdentityUserModel[]) => {
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: IdentityUserModel[]) => {
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: IdentityUserModel[]) => {
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(new IdentityUserQueryCloudRequestModel({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(new IdentityUserQueryCloudRequestModel({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();
}
);
});
});

View File

@@ -1,694 +0,0 @@
/*!
* @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 {
IdentityUserModel,
IdentityUserQueryResponse,
IdentityUserQueryCloudRequestModel,
IdentityUserPasswordModel,
IdentityJoinGroupRequestModel
} from '../models/identity-user.model';
import { JwtHelperService } from '../../services/jwt-helper.service';
import { LogService } from '../../services/log.service';
import { AppConfigService } from '../../app-config/app-config.service';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { IdentityRoleModel } from '../models/identity-role.model';
import { IdentityGroupModel } from '../models/identity-group.model';
@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);
const user = { firstName: givenName, lastName: familyName, email: email, username: username };
return new IdentityUserModel(user);
}
/**
* 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');
}
}