mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[CST-5307] Refactoring and adding missing unit tests
This commit is contained in:
@@ -78,15 +78,32 @@ describe(`DSONameService`, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe(`factories.Person`, () => {
|
describe(`factories.Person`, () => {
|
||||||
beforeEach(() => {
|
describe(`with person.familyName and person.givenName`, () => {
|
||||||
spyOn(mockPerson, 'firstMetadataValue').and.returnValues(...mockPersonName.split(', '));
|
beforeEach(() => {
|
||||||
|
spyOn(mockPerson, 'firstMetadataValue').and.returnValues(...mockPersonName.split(', '));
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return 'person.familyName, person.givenName'`, () => {
|
||||||
|
const result = (service as any).factories.Person(mockPerson);
|
||||||
|
expect(result).toBe(mockPersonName);
|
||||||
|
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.familyName');
|
||||||
|
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.givenName');
|
||||||
|
expect(mockPerson.firstMetadataValue).not.toHaveBeenCalledWith('dc.title');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should return 'person.familyName, person.givenName'`, () => {
|
describe(`without person.familyName and person.givenName`, () => {
|
||||||
const result = (service as any).factories.Person(mockPerson);
|
beforeEach(() => {
|
||||||
expect(result).toBe(mockPersonName);
|
spyOn(mockPerson, 'firstMetadataValue').and.returnValues(undefined, undefined, mockPersonName);
|
||||||
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.familyName');
|
});
|
||||||
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.givenName');
|
|
||||||
|
it(`should return dc.title`, () => {
|
||||||
|
const result = (service as any).factories.Person(mockPerson);
|
||||||
|
expect(result).toBe(mockPersonName);
|
||||||
|
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.familyName');
|
||||||
|
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.givenName');
|
||||||
|
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('dc.title');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
290
src/app/core/profile/researcher-profile.service.spec.ts
Normal file
290
src/app/core/profile/researcher-profile.service.spec.ts
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
|
||||||
|
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { TestScheduler } from 'rxjs/testing';
|
||||||
|
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { RequestService } from '../data/request.service';
|
||||||
|
import { PageInfo } from '../shared/page-info.model';
|
||||||
|
import { buildPaginatedList } from '../data/paginated-list.model';
|
||||||
|
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||||
|
import { RestResponse } from '../cache/response.models';
|
||||||
|
import { RequestEntry } from '../data/request-entry.model';
|
||||||
|
import { ResearcherProfileService } from './researcher-profile.service';
|
||||||
|
import { RouterMock } from '../../shared/mocks/router.mock';
|
||||||
|
import { ResearcherProfile } from './model/researcher-profile.model';
|
||||||
|
import { Item } from '../shared/item.model';
|
||||||
|
import { ReplaceOperation } from 'fast-json-patch';
|
||||||
|
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
|
||||||
|
import { PostRequest } from '../data/request.models';
|
||||||
|
|
||||||
|
describe('ResearcherProfileService', () => {
|
||||||
|
let scheduler: TestScheduler;
|
||||||
|
let service: ResearcherProfileService;
|
||||||
|
let serviceAsAny: any;
|
||||||
|
let requestService: RequestService;
|
||||||
|
let rdbService: RemoteDataBuildService;
|
||||||
|
let objectCache: ObjectCacheService;
|
||||||
|
let halService: HALEndpointService;
|
||||||
|
let responseCacheEntry: RequestEntry;
|
||||||
|
|
||||||
|
const researcherProfileId = 'beef9946-rt56-479e-8f11-b90cbe9f7241';
|
||||||
|
const itemId = 'beef9946-rt56-479e-8f11-b90cbe9f7241';
|
||||||
|
const researcherProfileItem: Item = Object.assign(new Item(), {
|
||||||
|
id: itemId,
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: `https://rest.api/rest/api/items/${itemId}`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const researcherProfile: ResearcherProfile = Object.assign(new ResearcherProfile(), {
|
||||||
|
id: researcherProfileId,
|
||||||
|
visible: false,
|
||||||
|
type: 'profile',
|
||||||
|
_links: {
|
||||||
|
item: {
|
||||||
|
href: `https://rest.api/rest/api/profiles/${researcherProfileId}/item`
|
||||||
|
},
|
||||||
|
self: {
|
||||||
|
href: `https://rest.api/rest/api/profiles/${researcherProfileId}`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const researcherProfilePatched: ResearcherProfile = Object.assign(new ResearcherProfile(), {
|
||||||
|
id: researcherProfileId,
|
||||||
|
visible: true,
|
||||||
|
type: 'profile',
|
||||||
|
_links: {
|
||||||
|
item: {
|
||||||
|
href: `https://rest.api/rest/api/profiles/${researcherProfileId}/item`
|
||||||
|
},
|
||||||
|
self: {
|
||||||
|
href: `https://rest.api/rest/api/profiles/${researcherProfileId}`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const researcherProfileId2 = 'agbf9946-f4ce-479e-8f11-b90cbe9f7241';
|
||||||
|
const anotherResearcherProfile: ResearcherProfile = Object.assign(new ResearcherProfile(), {
|
||||||
|
id: researcherProfileId2,
|
||||||
|
visible: false,
|
||||||
|
type: 'profile',
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: `https://rest.api/rest/api/profiles/${researcherProfileId2}`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const endpointURL = `https://rest.api/rest/api/profiles`;
|
||||||
|
const sourceUri = `https://rest.api/rest/api/external-source/profile`;
|
||||||
|
const requestURL = `https://rest.api/rest/api/profiles/${researcherProfileId}`;
|
||||||
|
const requestUUID = '8b3c613a-5a4b-438b-9686-be1d5b4a1c5a';
|
||||||
|
|
||||||
|
const pageInfo = new PageInfo();
|
||||||
|
const array = [researcherProfile, anotherResearcherProfile];
|
||||||
|
const paginatedList = buildPaginatedList(pageInfo, array);
|
||||||
|
const researcherProfileRD = createSuccessfulRemoteDataObject(researcherProfile);
|
||||||
|
const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
|
||||||
|
halService = jasmine.createSpyObj('halService', {
|
||||||
|
getEndpoint: cold('a', { a: endpointURL })
|
||||||
|
});
|
||||||
|
|
||||||
|
responseCacheEntry = new RequestEntry();
|
||||||
|
responseCacheEntry.request = { href: 'https://rest.api/' } as any;
|
||||||
|
responseCacheEntry.response = new RestResponse(true, 200, 'Success');
|
||||||
|
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
generateRequestId: requestUUID,
|
||||||
|
send: true,
|
||||||
|
removeByHrefSubstring: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: observableOf(responseCacheEntry),
|
||||||
|
setStaleByHrefSubstring: jasmine.createSpy('setStaleByHrefSubstring')
|
||||||
|
});
|
||||||
|
rdbService = jasmine.createSpyObj('rdbService', {
|
||||||
|
buildSingle: hot('a|', {
|
||||||
|
a: researcherProfileRD
|
||||||
|
}),
|
||||||
|
buildList: hot('a|', {
|
||||||
|
a: paginatedListRD
|
||||||
|
}),
|
||||||
|
buildFromRequestUUID: hot('a|', {
|
||||||
|
a: researcherProfileRD
|
||||||
|
})
|
||||||
|
});
|
||||||
|
objectCache = {} as ObjectCacheService;
|
||||||
|
const notificationsService = {} as NotificationsService;
|
||||||
|
const http = {} as HttpClient;
|
||||||
|
const comparator = {} as any;
|
||||||
|
const routerStub: any = new RouterMock();
|
||||||
|
const itemService = jasmine.createSpyObj('ItemService', {
|
||||||
|
findByHref: jasmine.createSpy('findByHref')
|
||||||
|
});
|
||||||
|
|
||||||
|
service = new ResearcherProfileService(
|
||||||
|
requestService,
|
||||||
|
rdbService,
|
||||||
|
objectCache,
|
||||||
|
halService,
|
||||||
|
notificationsService,
|
||||||
|
http,
|
||||||
|
routerStub,
|
||||||
|
comparator,
|
||||||
|
itemService
|
||||||
|
);
|
||||||
|
serviceAsAny = service;
|
||||||
|
|
||||||
|
spyOn((service as any).dataService, 'create').and.callThrough();
|
||||||
|
spyOn((service as any).dataService, 'delete').and.callThrough();
|
||||||
|
spyOn((service as any).dataService, 'update').and.callThrough();
|
||||||
|
spyOn((service as any).dataService, 'findById').and.callThrough();
|
||||||
|
spyOn((service as any).dataService, 'findByHref').and.callThrough();
|
||||||
|
spyOn((service as any).dataService, 'searchBy').and.callThrough();
|
||||||
|
spyOn((service as any).dataService, 'getLinkPath').and.returnValue(observableOf(endpointURL));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findById', () => {
|
||||||
|
it('should proxy the call to dataservice.findById with eperson UUID', () => {
|
||||||
|
scheduler.schedule(() => service.findById(researcherProfileId));
|
||||||
|
scheduler.flush();
|
||||||
|
|
||||||
|
expect((service as any).dataService.findById).toHaveBeenCalledWith(researcherProfileId, true, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a ResearcherProfile object with the given id', () => {
|
||||||
|
const result = service.findById(researcherProfileId);
|
||||||
|
const expected = cold('a|', {
|
||||||
|
a: researcherProfileRD
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create', () => {
|
||||||
|
it('should proxy the call to dataservice.create with eperson UUID', () => {
|
||||||
|
scheduler.schedule(() => service.create());
|
||||||
|
scheduler.flush();
|
||||||
|
|
||||||
|
expect((service as any).dataService.create).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the RemoteData<ResearcherProfile> created', () => {
|
||||||
|
const result = service.create();
|
||||||
|
const expected = cold('a|', {
|
||||||
|
a: researcherProfileRD
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('delete', () => {
|
||||||
|
it('should proxy the call to dataservice.delete', () => {
|
||||||
|
scheduler.schedule(() => service.delete(researcherProfile));
|
||||||
|
scheduler.flush();
|
||||||
|
|
||||||
|
expect((service as any).dataService.delete).toHaveBeenCalledWith(researcherProfile.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findRelatedItemId', () => {
|
||||||
|
describe('with a related item', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
(service as any).itemService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(researcherProfileItem));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should proxy the call to dataservice.findById with eperson UUID', () => {
|
||||||
|
scheduler.schedule(() => service.findRelatedItemId(researcherProfile));
|
||||||
|
scheduler.flush();
|
||||||
|
|
||||||
|
expect((service as any).itemService.findByHref).toHaveBeenCalledWith(researcherProfile._links.item.href, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a ResearcherProfile object with the given id', () => {
|
||||||
|
const result = service.findRelatedItemId(researcherProfile);
|
||||||
|
const expected = cold('(a|)', {
|
||||||
|
a: itemId
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('without a related item', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
(service as any).itemService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(null));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should proxy the call to dataservice.findById with eperson UUID', () => {
|
||||||
|
scheduler.schedule(() => service.findRelatedItemId(researcherProfile));
|
||||||
|
scheduler.flush();
|
||||||
|
|
||||||
|
expect((service as any).itemService.findByHref).toHaveBeenCalledWith(researcherProfile._links.item.href, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a ResearcherProfile object with the given id', () => {
|
||||||
|
const result = service.findRelatedItemId(researcherProfile);
|
||||||
|
const expected = cold('(a|)', {
|
||||||
|
a: undefined
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setVisibility', () => {
|
||||||
|
let patchSpy;
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn((service as any), 'patch').and.returnValue(createSuccessfulRemoteDataObject$(researcherProfilePatched));
|
||||||
|
spyOn((service as any), 'findById').and.returnValue(createSuccessfulRemoteDataObject$(researcherProfilePatched));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should proxy the call to dataservice.patch', () => {
|
||||||
|
const replaceOperation: ReplaceOperation<boolean> = {
|
||||||
|
path: '/visible',
|
||||||
|
op: 'replace',
|
||||||
|
value: true
|
||||||
|
};
|
||||||
|
|
||||||
|
scheduler.schedule(() => service.setVisibility(researcherProfile, true));
|
||||||
|
scheduler.flush();
|
||||||
|
|
||||||
|
expect((service as any).patch).toHaveBeenCalledWith(researcherProfile, [replaceOperation]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createFromExternalSource', () => {
|
||||||
|
let patchSpy;
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn((service as any), 'patch').and.returnValue(createSuccessfulRemoteDataObject$(researcherProfilePatched));
|
||||||
|
spyOn((service as any), 'findById').and.returnValue(createSuccessfulRemoteDataObject$(researcherProfilePatched));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should proxy the call to dataservice.patch', () => {
|
||||||
|
const options: HttpOptions = Object.create({});
|
||||||
|
let headers = new HttpHeaders();
|
||||||
|
headers = headers.append('Content-Type', 'text/uri-list');
|
||||||
|
options.headers = headers;
|
||||||
|
const request = new PostRequest(requestUUID, endpointURL, sourceUri, options);
|
||||||
|
|
||||||
|
scheduler.schedule(() => service.createFromExternalSource(sourceUri));
|
||||||
|
scheduler.flush();
|
||||||
|
|
||||||
|
expect((service as any).requestService.send).toHaveBeenCalledWith(request);
|
||||||
|
expect((service as any).rdbService.buildFromRequestUUID).toHaveBeenCalledWith(requestUUID);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@@ -2,27 +2,25 @@
|
|||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { Operation, RemoveOperation, ReplaceOperation } from 'fast-json-patch';
|
import { Operation, ReplaceOperation } from 'fast-json-patch';
|
||||||
import { combineLatest, Observable, of as observableOf } from 'rxjs';
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
import { catchError, find, map, switchMap, tap } from 'rxjs/operators';
|
import { catchError, find, map, switchMap, tap } from 'rxjs/operators';
|
||||||
import { environment } from '../../../environments/environment';
|
|
||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { dataService } from '../cache/builders/build-decorators';
|
import { dataService } from '../cache/builders/build-decorators';
|
||||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
import { ConfigurationDataService } from '../data/configuration-data.service';
|
|
||||||
import { DataService } from '../data/data.service';
|
import { DataService } from '../data/data.service';
|
||||||
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
|
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
|
||||||
import { ItemDataService } from '../data/item-data.service';
|
import { ItemDataService } from '../data/item-data.service';
|
||||||
import { RemoteData } from '../data/remote-data';
|
import { RemoteData } from '../data/remote-data';
|
||||||
import { RequestService } from '../data/request.service';
|
import { RequestService } from '../data/request.service';
|
||||||
import { ConfigurationProperty } from '../shared/configuration-property.model';
|
|
||||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
import { Item } from '../shared/item.model';
|
|
||||||
import { NoContent } from '../shared/NoContent.model';
|
import { NoContent } from '../shared/NoContent.model';
|
||||||
import {
|
import {
|
||||||
getFinishedRemoteData,
|
getAllCompletedRemoteData,
|
||||||
getFirstCompletedRemoteData,
|
getFirstCompletedRemoteData,
|
||||||
getFirstSucceededRemoteDataPayload
|
getFirstSucceededRemoteDataPayload
|
||||||
} from '../shared/operators';
|
} from '../shared/operators';
|
||||||
@@ -31,25 +29,26 @@ import { RESEARCHER_PROFILE } from './model/researcher-profile.resource-type';
|
|||||||
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
|
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
|
||||||
import { PostRequest } from '../data/request.models';
|
import { PostRequest } from '../data/request.models';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
import {CoreState} from '../core-state.model';
|
import { CoreState } from '../core-state.model';
|
||||||
|
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A private DataService implementation to delegate specific methods to.
|
* A private DataService implementation to delegate specific methods to.
|
||||||
*/
|
*/
|
||||||
class ResearcherProfileServiceImpl extends DataService<ResearcherProfile> {
|
class ResearcherProfileServiceImpl extends DataService<ResearcherProfile> {
|
||||||
protected linkPath = 'profiles';
|
protected linkPath = 'profiles';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
protected store: Store<CoreState>,
|
protected store: Store<CoreState>,
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected halService: HALEndpointService,
|
protected halService: HALEndpointService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected http: HttpClient,
|
protected http: HttpClient,
|
||||||
protected comparator: DefaultChangeAnalyzer<ResearcherProfile>) {
|
protected comparator: DefaultChangeAnalyzer<ResearcherProfile>) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,100 +59,102 @@ class ResearcherProfileServiceImpl extends DataService<ResearcherProfile> {
|
|||||||
@dataService(RESEARCHER_PROFILE)
|
@dataService(RESEARCHER_PROFILE)
|
||||||
export class ResearcherProfileService {
|
export class ResearcherProfileService {
|
||||||
|
|
||||||
dataService: ResearcherProfileServiceImpl;
|
dataService: ResearcherProfileServiceImpl;
|
||||||
|
|
||||||
responseMsToLive: number = 10 * 1000;
|
responseMsToLive: number = 10 * 1000;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
protected store: Store<CoreState>,
|
protected objectCache: ObjectCacheService,
|
||||||
protected objectCache: ObjectCacheService,
|
protected halService: HALEndpointService,
|
||||||
protected halService: HALEndpointService,
|
protected notificationsService: NotificationsService,
|
||||||
protected notificationsService: NotificationsService,
|
protected http: HttpClient,
|
||||||
protected http: HttpClient,
|
protected router: Router,
|
||||||
protected router: Router,
|
protected comparator: DefaultChangeAnalyzer<ResearcherProfile>,
|
||||||
protected comparator: DefaultChangeAnalyzer<ResearcherProfile>,
|
protected itemService: ItemDataService) {
|
||||||
protected itemService: ItemDataService,
|
|
||||||
protected configurationService: ConfigurationDataService ) {
|
|
||||||
|
|
||||||
this.dataService = new ResearcherProfileServiceImpl(requestService, rdbService, store, objectCache, halService,
|
this.dataService = new ResearcherProfileServiceImpl(requestService, rdbService, null, objectCache, halService,
|
||||||
notificationsService, http, comparator);
|
notificationsService, http, comparator);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the researcher profile with the given uuid.
|
* Find the researcher profile with the given uuid.
|
||||||
*
|
*
|
||||||
* @param uuid the profile uuid
|
* @param uuid the profile uuid
|
||||||
*/
|
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||||
findById(uuid: string): Observable<ResearcherProfile> {
|
* no valid cached version. Defaults to true
|
||||||
return this.dataService.findById(uuid, false)
|
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||||
.pipe ( getFinishedRemoteData(),
|
* requested after the response becomes stale
|
||||||
map((remoteData) => remoteData.payload));
|
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||||
}
|
* {@link HALLink}s should be automatically resolved
|
||||||
|
*/
|
||||||
|
public findById(uuid: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<ResearcherProfile>[]): Observable<RemoteData<ResearcherProfile>> {
|
||||||
|
return this.dataService.findById(uuid, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow).pipe(
|
||||||
|
getAllCompletedRemoteData(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new researcher profile for the current user.
|
* Create a new researcher profile for the current user.
|
||||||
*/
|
*/
|
||||||
create(): Observable<RemoteData<ResearcherProfile>> {
|
public create(): Observable<RemoteData<ResearcherProfile>> {
|
||||||
return this.dataService.create( new ResearcherProfile());
|
return this.dataService.create(new ResearcherProfile());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a researcher profile.
|
* Delete a researcher profile.
|
||||||
*
|
*
|
||||||
* @param researcherProfile the profile to delete
|
* @param researcherProfile the profile to delete
|
||||||
*/
|
*/
|
||||||
delete(researcherProfile: ResearcherProfile): Observable<boolean> {
|
public delete(researcherProfile: ResearcherProfile): Observable<boolean> {
|
||||||
return this.dataService.delete(researcherProfile.id).pipe(
|
return this.dataService.delete(researcherProfile.id).pipe(
|
||||||
getFirstCompletedRemoteData(),
|
getFirstCompletedRemoteData(),
|
||||||
tap((response: RemoteData<NoContent>) => {
|
tap((response: RemoteData<NoContent>) => {
|
||||||
if (response.isSuccess) {
|
if (response.isSuccess) {
|
||||||
this.requestService.setStaleByHrefSubstring(researcherProfile._links.self.href);
|
this.requestService.setStaleByHrefSubstring(researcherProfile._links.self.href);
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
map((response: RemoteData<NoContent>) => response.isSuccess)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the item id related to the given researcher profile.
|
||||||
|
*
|
||||||
|
* @param researcherProfile the profile to find for
|
||||||
|
*/
|
||||||
|
public findRelatedItemId(researcherProfile: ResearcherProfile): Observable<string> {
|
||||||
|
return this.itemService.findByHref(researcherProfile._links.item.href, false)
|
||||||
|
.pipe(getFirstSucceededRemoteDataPayload(),
|
||||||
|
catchError((error) => {
|
||||||
|
console.debug(error);
|
||||||
|
return observableOf(null);
|
||||||
}),
|
}),
|
||||||
map((response: RemoteData<NoContent>) => response.isSuccess)
|
map((item) => item?.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the item id related to the given researcher profile.
|
* Change the visibility of the given researcher profile setting the given value.
|
||||||
*
|
*
|
||||||
* @param researcherProfile the profile to find for
|
* @param researcherProfile the profile to update
|
||||||
*/
|
* @param visible the visibility value to set
|
||||||
findRelatedItemId( researcherProfile: ResearcherProfile ): Observable<string> {
|
*/
|
||||||
return this.itemService.findByHref(researcherProfile._links.item.href, false)
|
public setVisibility(researcherProfile: ResearcherProfile, visible: boolean): Observable<ResearcherProfile> {
|
||||||
.pipe (getFirstSucceededRemoteDataPayload(),
|
|
||||||
catchError((error) => {
|
|
||||||
console.debug(error);
|
|
||||||
return observableOf(null);
|
|
||||||
}),
|
|
||||||
map((item) => item != null ? item.id : null ));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
const replaceOperation: ReplaceOperation<boolean> = {
|
||||||
* Change the visibility of the given researcher profile setting the given value.
|
path: '/visible',
|
||||||
*
|
op: 'replace',
|
||||||
* @param researcherProfile the profile to update
|
value: visible
|
||||||
* @param visible the visibility value to set
|
};
|
||||||
*/
|
|
||||||
setVisibility(researcherProfile: ResearcherProfile, visible: boolean): Observable<ResearcherProfile> {
|
|
||||||
|
|
||||||
const replaceOperation: ReplaceOperation<boolean> = {
|
return this.patch(researcherProfile, [replaceOperation]).pipe(
|
||||||
path: '/visible',
|
switchMap(() => this.findById(researcherProfile.id)),
|
||||||
op: 'replace',
|
getFirstSucceededRemoteDataPayload()
|
||||||
value: visible
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
return this.patch(researcherProfile, [replaceOperation]).pipe (
|
|
||||||
switchMap( ( ) => this.findById(researcherProfile.id))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
patch(researcherProfile: ResearcherProfile, operations: Operation[]): Observable<RemoteData<ResearcherProfile>> {
|
|
||||||
return this.dataService.patch(researcherProfile, operations);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a researcher profile starting from an external source URI
|
* Creates a researcher profile starting from an external source URI
|
||||||
@@ -179,4 +180,7 @@ export class ResearcherProfileService {
|
|||||||
return this.rdbService.buildFromRequestUUID(requestId);
|
return this.rdbService.buildFromRequestUUID(requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private patch(researcherProfile: ResearcherProfile, operations: Operation[]): Observable<RemoteData<ResearcherProfile>> {
|
||||||
|
return this.dataService.patch(researcherProfile, operations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
215
src/app/profile-page/profile-claim/profile-claim.service.spec.ts
Normal file
215
src/app/profile-page/profile-claim/profile-claim.service.spec.ts
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
import { cold, getTestScheduler } from 'jasmine-marbles';
|
||||||
|
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { TestScheduler } from 'rxjs/testing';
|
||||||
|
|
||||||
|
import { ProfileClaimService } from './profile-claim.service';
|
||||||
|
import { SearchService } from '../../core/shared/search/search.service';
|
||||||
|
import { ItemSearchResult } from '../../shared/object-collection/shared/item-search-result.model';
|
||||||
|
import { SearchObjects } from '../../shared/search/models/search-objects.model';
|
||||||
|
import { Item } from '../../core/shared/item.model';
|
||||||
|
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
|
||||||
|
import { EPerson } from '../../core/eperson/models/eperson.model';
|
||||||
|
|
||||||
|
describe('ProfileClaimService', () => {
|
||||||
|
let scheduler: TestScheduler;
|
||||||
|
let service: ProfileClaimService;
|
||||||
|
let serviceAsAny: any;
|
||||||
|
let searchService: jasmine.SpyObj<SearchService>;
|
||||||
|
|
||||||
|
const eperson: EPerson = Object.assign(new EPerson(), {
|
||||||
|
id: 'id',
|
||||||
|
metadata: {
|
||||||
|
'eperson.firstname': [
|
||||||
|
{
|
||||||
|
value: 'John'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'eperson.lastname': [
|
||||||
|
{
|
||||||
|
value: 'Doe'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
email: 'fake@email.com'
|
||||||
|
});
|
||||||
|
const item1: Item = Object.assign(new Item(), {
|
||||||
|
uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e',
|
||||||
|
metadata: {
|
||||||
|
'person.email': [
|
||||||
|
{
|
||||||
|
value: 'fake@email.com'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'person.familyName': [
|
||||||
|
{
|
||||||
|
value: 'Doe'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'person.givenName': [
|
||||||
|
{
|
||||||
|
value: 'John'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'item-href'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const item2: Item = Object.assign(new Item(), {
|
||||||
|
uuid: 'c8279647-1acc-41ae-b036-951d5f65649b',
|
||||||
|
metadata: {
|
||||||
|
'person.email': [
|
||||||
|
{
|
||||||
|
value: 'fake2@email.com'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.title': [
|
||||||
|
{
|
||||||
|
value: 'John, Doe'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'item-href'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const item3: Item = Object.assign(new Item(), {
|
||||||
|
uuid: 'c8279647-1acc-41ae-b036-951d5f65649b',
|
||||||
|
metadata: {
|
||||||
|
'person.email': [
|
||||||
|
{
|
||||||
|
value: 'fake3@email.com'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.title': [
|
||||||
|
{
|
||||||
|
value: 'John, Doe'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'item-href'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 });
|
||||||
|
const searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 });
|
||||||
|
const searchResult3 = Object.assign(new ItemSearchResult(), { indexableObject: item3 });
|
||||||
|
|
||||||
|
const searchResult = Object.assign(new SearchObjects(), {
|
||||||
|
page: [searchResult1, searchResult2, searchResult3]
|
||||||
|
});
|
||||||
|
const emptySearchResult = Object.assign(new SearchObjects(), {
|
||||||
|
page: []
|
||||||
|
});
|
||||||
|
const searchResultRD = createSuccessfulRemoteDataObject(searchResult);
|
||||||
|
const emptyRearchResultRD = createSuccessfulRemoteDataObject(emptySearchResult);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
|
||||||
|
searchService = jasmine.createSpyObj('SearchService', {
|
||||||
|
search: jasmine.createSpy('search')
|
||||||
|
});
|
||||||
|
|
||||||
|
service = new ProfileClaimService(searchService);
|
||||||
|
serviceAsAny = service;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('hasProfilesToSuggest', () => {
|
||||||
|
|
||||||
|
describe('when has suggestions', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(service, 'search').and.returnValue(observableOf(searchResultRD));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true', () => {
|
||||||
|
const result = service.hasProfilesToSuggest(eperson);
|
||||||
|
const expected = cold('(a|)', {
|
||||||
|
a: true
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when has not suggestions', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(service, 'search').and.returnValue(observableOf(emptyRearchResultRD));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false', () => {
|
||||||
|
const result = service.hasProfilesToSuggest(eperson);
|
||||||
|
const expected = cold('(a|)', {
|
||||||
|
a: false
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when has not valid eperson', () => {
|
||||||
|
it('should return false', () => {
|
||||||
|
const result = service.hasProfilesToSuggest(null);
|
||||||
|
const expected = cold('(a|)', {
|
||||||
|
a: false
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('search', () => {
|
||||||
|
|
||||||
|
describe('when has search results', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
searchService.search.and.returnValue(observableOf(searchResultRD));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the proper search object', () => {
|
||||||
|
const result = service.search(eperson);
|
||||||
|
const expected = cold('(a|)', {
|
||||||
|
a: searchResultRD
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when has not suggestions', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
searchService.search.and.returnValue(observableOf(emptyRearchResultRD));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return null', () => {
|
||||||
|
const result = service.search(eperson);
|
||||||
|
const expected = cold('(a|)', {
|
||||||
|
a: emptyRearchResultRD
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when has not valid eperson', () => {
|
||||||
|
it('should return null', () => {
|
||||||
|
const result = service.search(null);
|
||||||
|
const expected = cold('(a|)', {
|
||||||
|
a: null
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
@@ -1,16 +1,16 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { mergeMap, take } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { ConfigurationDataService } from '../../core/data/configuration-data.service';
|
|
||||||
import { PaginatedList } from '../../core/data/paginated-list.model';
|
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { EPerson } from '../../core/eperson/models/eperson.model';
|
import { EPerson } from '../../core/eperson/models/eperson.model';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { SearchService } from '../../core/shared/search/search.service';
|
import { SearchService } from '../../core/shared/search/search.service';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||||
import { SearchResult } from '../../shared/search/models/search-result.model';
|
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
|
||||||
import { getFirstSucceededRemoteData } from './../../core/shared/operators';
|
import { SearchObjects } from '../../shared/search/models/search-objects.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that handle profiles claim.
|
* Service that handle profiles claim.
|
||||||
@@ -18,8 +18,7 @@ import { getFirstSucceededRemoteData } from './../../core/shared/operators';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProfileClaimService {
|
export class ProfileClaimService {
|
||||||
|
|
||||||
constructor(private searchService: SearchService,
|
constructor(private searchService: SearchService) {
|
||||||
private configurationService: ConfigurationDataService) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,27 +26,21 @@ export class ProfileClaimService {
|
|||||||
*
|
*
|
||||||
* @param eperson the eperson
|
* @param eperson the eperson
|
||||||
*/
|
*/
|
||||||
canClaimProfiles(eperson: EPerson): Observable<boolean> {
|
hasProfilesToSuggest(eperson: EPerson): Observable<boolean> {
|
||||||
|
return this.search(eperson).pipe(
|
||||||
const query = this.personQueryData(eperson);
|
map((rd: RemoteData<SearchObjects<DSpaceObject>>) => {
|
||||||
|
return isNotEmpty(rd) && rd.hasSucceeded && rd.payload?.page?.length > 0;
|
||||||
if (!hasValue(query) || query.length === 0) {
|
})
|
||||||
return of(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.lookup(query).pipe(
|
|
||||||
mergeMap((rd: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) => of(rd.payload.totalElements > 0))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns profiles that could be associated with the given user.
|
* Returns profiles that could be associated with the given user.
|
||||||
* @param eperson the user
|
* @param eperson the user
|
||||||
*/
|
*/
|
||||||
search(eperson: EPerson): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
|
search(eperson: EPerson): Observable<RemoteData<SearchObjects<DSpaceObject>>> {
|
||||||
const query = this.personQueryData(eperson);
|
const query = this.personQueryData(eperson);
|
||||||
if (!hasValue(query) || query.length === 0) {
|
if (isEmpty(query)) {
|
||||||
return of(null);
|
return of(null);
|
||||||
}
|
}
|
||||||
return this.lookup(query);
|
return this.lookup(query);
|
||||||
@@ -57,21 +50,31 @@ export class ProfileClaimService {
|
|||||||
* Search object by the given query.
|
* Search object by the given query.
|
||||||
* @param query the query for the search
|
* @param query the query for the search
|
||||||
*/
|
*/
|
||||||
private lookup(query: string): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
|
private lookup(query: string): Observable<RemoteData<SearchObjects<DSpaceObject>>> {
|
||||||
if (!hasValue(query)) {
|
if (isEmpty(query)) {
|
||||||
return of(null);
|
return of(null);
|
||||||
}
|
}
|
||||||
return this.searchService.search(new PaginatedSearchOptions({
|
return this.searchService.search(new PaginatedSearchOptions({
|
||||||
configuration: 'eperson_claims',
|
configuration: 'eperson_claims',
|
||||||
query: query
|
query: query
|
||||||
}))
|
})).pipe(
|
||||||
.pipe(
|
getFirstCompletedRemoteData()
|
||||||
getFirstSucceededRemoteData(),
|
);
|
||||||
take(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the search query for person lookup, from the given eperson
|
||||||
|
*
|
||||||
|
* @param eperson The eperson to use for the lookup
|
||||||
|
*/
|
||||||
private personQueryData(eperson: EPerson): string {
|
private personQueryData(eperson: EPerson): string {
|
||||||
return 'dc.title:' + eperson.name;
|
if (eperson) {
|
||||||
|
const firstname = eperson.firstMetadataValue('eperson.firstname');
|
||||||
|
const lastname = eperson.firstMetadataValue('eperson.lastname');
|
||||||
|
return 'dc.title:' + eperson.name + ' OR (person.familyName:' + lastname + ' AND person.givenName:' + firstname + ')';
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@ import { ProfilePageResearcherFormComponent } from './profile-page-researcher-fo
|
|||||||
import { ProfileClaimService } from '../profile-claim/profile-claim.service';
|
import { ProfileClaimService } from '../profile-claim/profile-claim.service';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { AuthService } from 'src/app/core/auth/auth.service';
|
import { AuthService } from 'src/app/core/auth/auth.service';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||||
|
|
||||||
describe('ProfilePageResearcherFormComponent', () => {
|
describe('ProfilePageResearcherFormComponent', () => {
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ describe('ProfilePageResearcherFormComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
researcherProfileService = jasmine.createSpyObj('researcherProfileService', {
|
researcherProfileService = jasmine.createSpyObj('researcherProfileService', {
|
||||||
findById: observableOf(profile),
|
findById: createSuccessfulRemoteDataObject$(profile),
|
||||||
create: observableOf(profile),
|
create: observableOf(profile),
|
||||||
setVisibility: observableOf(profile),
|
setVisibility: observableOf(profile),
|
||||||
delete: observableOf(true),
|
delete: observableOf(true),
|
||||||
@@ -61,7 +62,7 @@ describe('ProfilePageResearcherFormComponent', () => {
|
|||||||
notificationsServiceStub = new NotificationsServiceStub();
|
notificationsServiceStub = new NotificationsServiceStub();
|
||||||
|
|
||||||
profileClaimService = jasmine.createSpyObj('profileClaimService', {
|
profileClaimService = jasmine.createSpyObj('profileClaimService', {
|
||||||
canClaimProfiles: observableOf(false),
|
hasProfilesToSuggest: observableOf(false),
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -91,7 +92,7 @@ describe('ProfilePageResearcherFormComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should search the researcher profile for the current user', () => {
|
it('should search the researcher profile for the current user', () => {
|
||||||
expect(researcherProfileService.findById).toHaveBeenCalledWith(user.id);
|
expect(researcherProfileService.findById).toHaveBeenCalledWith(user.id, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createProfile', () => {
|
describe('createProfile', () => {
|
||||||
|
@@ -4,17 +4,18 @@ import { Router } from '@angular/router';
|
|||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
import { filter, mergeMap, switchMap, take, tap } from 'rxjs/operators';
|
import { mergeMap, switchMap, take, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
|
import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../../core/shared/operators';
|
||||||
import { ClaimItemSelectorComponent } from '../../shared/dso-selector/modal-wrappers/claim-item-selector/claim-item-selector.component';
|
import {
|
||||||
|
ClaimItemSelectorComponent
|
||||||
|
} from '../../shared/dso-selector/modal-wrappers/claim-item-selector/claim-item-selector.component';
|
||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { AuthService } from '../../core/auth/auth.service';
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
import { EPerson } from '../../core/eperson/models/eperson.model';
|
import { EPerson } from '../../core/eperson/models/eperson.model';
|
||||||
import { ResearcherProfile } from '../../core/profile/model/researcher-profile.model';
|
import { ResearcherProfile } from '../../core/profile/model/researcher-profile.model';
|
||||||
import { ResearcherProfileService } from '../../core/profile/researcher-profile.service';
|
import { ResearcherProfileService } from '../../core/profile/researcher-profile.service';
|
||||||
import { ProfileClaimService } from '../profile-claim/profile-claim.service';
|
import { ProfileClaimService } from '../profile-claim/profile-claim.service';
|
||||||
import { isNotEmpty } from '../../shared/empty.util';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-profile-page-researcher-form',
|
selector: 'ds-profile-page-researcher-form',
|
||||||
@@ -77,10 +78,10 @@ export class ProfilePageResearcherFormComponent implements OnInit {
|
|||||||
this.processingCreate$.next(true);
|
this.processingCreate$.next(true);
|
||||||
|
|
||||||
this.authService.getAuthenticatedUserFromStore().pipe(
|
this.authService.getAuthenticatedUserFromStore().pipe(
|
||||||
switchMap((currentUser) => this.profileClaimService.canClaimProfiles(currentUser)))
|
switchMap((currentUser) => this.profileClaimService.hasProfilesToSuggest(currentUser)))
|
||||||
.subscribe((canClaimProfiles) => {
|
.subscribe((hasProfilesToSuggest) => {
|
||||||
|
|
||||||
if (canClaimProfiles) {
|
if (hasProfilesToSuggest) {
|
||||||
this.processingCreate$.next(false);
|
this.processingCreate$.next(false);
|
||||||
const modal = this.modalService.open(ClaimItemSelectorComponent);
|
const modal = this.modalService.open(ClaimItemSelectorComponent);
|
||||||
modal.componentInstance.dso = this.user;
|
modal.componentInstance.dso = this.user;
|
||||||
@@ -174,9 +175,8 @@ export class ProfilePageResearcherFormComponent implements OnInit {
|
|||||||
* Initializes the researcherProfile and researcherProfileItemId attributes using the profile of the current user.
|
* Initializes the researcherProfile and researcherProfileItemId attributes using the profile of the current user.
|
||||||
*/
|
*/
|
||||||
private initResearchProfile(): void {
|
private initResearchProfile(): void {
|
||||||
this.researcherProfileService.findById(this.user.id).pipe(
|
this.researcherProfileService.findById(this.user.id, false).pipe(
|
||||||
take(1),
|
getFirstSucceededRemoteDataPayload(),
|
||||||
filter((researcherProfile) => isNotEmpty(researcherProfile)),
|
|
||||||
tap((researcherProfile) => this.researcherProfile$.next(researcherProfile)),
|
tap((researcherProfile) => this.researcherProfile$.next(researcherProfile)),
|
||||||
mergeMap((researcherProfile) => this.researcherProfileService.findRelatedItemId(researcherProfile)),
|
mergeMap((researcherProfile) => this.researcherProfileService.findRelatedItemId(researcherProfile)),
|
||||||
).subscribe((itemId: string) => {
|
).subscribe((itemId: string) => {
|
||||||
|
@@ -11,17 +11,17 @@ import { AuthTokenInfo } from '../core/auth/models/auth-token-info.model';
|
|||||||
import { EPersonDataService } from '../core/eperson/eperson-data.service';
|
import { EPersonDataService } from '../core/eperson/eperson-data.service';
|
||||||
import { NotificationsService } from '../shared/notifications/notifications.service';
|
import { NotificationsService } from '../shared/notifications/notifications.service';
|
||||||
import { authReducer } from '../core/auth/auth.reducer';
|
import { authReducer } from '../core/auth/auth.reducer';
|
||||||
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
|
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
|
||||||
import { createPaginatedList } from '../shared/testing/utils.test';
|
import { createPaginatedList } from '../shared/testing/utils.test';
|
||||||
import { BehaviorSubject, of as observableOf } from 'rxjs';
|
import { BehaviorSubject, of as observableOf } from 'rxjs';
|
||||||
import { AuthService } from '../core/auth/auth.service';
|
import { AuthService } from '../core/auth/auth.service';
|
||||||
import { RestResponse } from '../core/cache/response.models';
|
import { RestResponse } from '../core/cache/response.models';
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||||
import { getTestScheduler } from 'jasmine-marbles';
|
import { cold, getTestScheduler } from 'jasmine-marbles';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import {ConfigurationDataService} from '../core/data/configuration-data.service';
|
import { ConfigurationDataService } from '../core/data/configuration-data.service';
|
||||||
import {ConfigurationProperty} from '../core/shared/configuration-property.model';
|
import { ConfigurationProperty } from '../core/shared/configuration-property.model';
|
||||||
|
|
||||||
describe('ProfilePageComponent', () => {
|
describe('ProfilePageComponent', () => {
|
||||||
let component: ProfilePageComponent;
|
let component: ProfilePageComponent;
|
||||||
@@ -30,16 +30,28 @@ describe('ProfilePageComponent', () => {
|
|||||||
let initialState: any;
|
let initialState: any;
|
||||||
|
|
||||||
let authService;
|
let authService;
|
||||||
|
let authorizationService;
|
||||||
let epersonService;
|
let epersonService;
|
||||||
let notificationsService;
|
let notificationsService;
|
||||||
|
let configurationService;
|
||||||
|
|
||||||
const canChangePassword = new BehaviorSubject(true);
|
const canChangePassword = new BehaviorSubject(true);
|
||||||
|
const validConfiguration = Object.assign(new ConfigurationProperty(), {
|
||||||
|
name: 'researcher-profile.entity-type',
|
||||||
|
values: [
|
||||||
|
'Person'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
const emptyConfiguration = Object.assign(new ConfigurationProperty(), {
|
||||||
|
name: 'researcher-profile.entity-type',
|
||||||
|
values: []
|
||||||
|
});
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
user = Object.assign(new EPerson(), {
|
user = Object.assign(new EPerson(), {
|
||||||
id: 'userId',
|
id: 'userId',
|
||||||
groups: createSuccessfulRemoteDataObject$(createPaginatedList([])),
|
groups: createSuccessfulRemoteDataObject$(createPaginatedList([])),
|
||||||
_links: {self: {href: 'test.com/uuid/1234567654321'}}
|
_links: { self: { href: 'test.com/uuid/1234567654321' } }
|
||||||
});
|
});
|
||||||
initialState = {
|
initialState = {
|
||||||
core: {
|
core: {
|
||||||
@@ -54,7 +66,7 @@ describe('ProfilePageComponent', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
authorizationService = jasmine.createSpyObj('authorizationService', { isAuthorized: canChangePassword });
|
||||||
authService = jasmine.createSpyObj('authService', {
|
authService = jasmine.createSpyObj('authService', {
|
||||||
getAuthenticatedUserFromStore: observableOf(user)
|
getAuthenticatedUserFromStore: observableOf(user)
|
||||||
});
|
});
|
||||||
@@ -67,6 +79,9 @@ describe('ProfilePageComponent', () => {
|
|||||||
error: {},
|
error: {},
|
||||||
warning: {}
|
warning: {}
|
||||||
});
|
});
|
||||||
|
configurationService = jasmine.createSpyObj('configurationDataService', {
|
||||||
|
findByPropertyName: jasmine.createSpy('findByPropertyName')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
@@ -82,15 +97,8 @@ describe('ProfilePageComponent', () => {
|
|||||||
{ provide: EPersonDataService, useValue: epersonService },
|
{ provide: EPersonDataService, useValue: epersonService },
|
||||||
{ provide: NotificationsService, useValue: notificationsService },
|
{ provide: NotificationsService, useValue: notificationsService },
|
||||||
{ provide: AuthService, useValue: authService },
|
{ provide: AuthService, useValue: authService },
|
||||||
{ provide: ConfigurationDataService, useValue: jasmine.createSpyObj('configurationDataService', {
|
{ provide: ConfigurationDataService, useValue: configurationService },
|
||||||
findByPropertyName: createSuccessfulRemoteDataObject$(Object.assign(new ConfigurationProperty(), {
|
{ provide: AuthorizationDataService, useValue: authorizationService },
|
||||||
name: 'researcher-profile.entity-type',
|
|
||||||
values: [
|
|
||||||
'Person'
|
|
||||||
]
|
|
||||||
}))
|
|
||||||
})},
|
|
||||||
{ provide: AuthorizationDataService, useValue: jasmine.createSpyObj('authorizationService', { isAuthorized: canChangePassword }) },
|
|
||||||
provideMockStore({ initialState }),
|
provideMockStore({ initialState }),
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
@@ -100,148 +108,206 @@ describe('ProfilePageComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(ProfilePageComponent);
|
fixture = TestBed.createComponent(ProfilePageComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('updateProfile', () => {
|
describe('', () => {
|
||||||
describe('when the metadata form returns false and the security form returns true', () => {
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.metadataForm = jasmine.createSpyObj('metadataForm', {
|
configurationService.findByPropertyName.and.returnValue(createSuccessfulRemoteDataObject$(validConfiguration));
|
||||||
updateProfile: false
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updateProfile', () => {
|
||||||
|
describe('when the metadata form returns false and the security form returns true', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
component.metadataForm = jasmine.createSpyObj('metadataForm', {
|
||||||
|
updateProfile: false
|
||||||
|
});
|
||||||
|
spyOn(component, 'updateSecurity').and.returnValue(true);
|
||||||
|
component.updateProfile();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display a warning', () => {
|
||||||
|
expect(notificationsService.warning).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
spyOn(component, 'updateSecurity').and.returnValue(true);
|
|
||||||
component.updateProfile();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not display a warning', () => {
|
describe('when the metadata form returns true and the security form returns false', () => {
|
||||||
expect(notificationsService.warning).not.toHaveBeenCalled();
|
beforeEach(() => {
|
||||||
|
component.metadataForm = jasmine.createSpyObj('metadataForm', {
|
||||||
|
updateProfile: true
|
||||||
|
});
|
||||||
|
component.updateProfile();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display a warning', () => {
|
||||||
|
expect(notificationsService.warning).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the metadata form returns true and the security form returns true', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
component.metadataForm = jasmine.createSpyObj('metadataForm', {
|
||||||
|
updateProfile: true
|
||||||
|
});
|
||||||
|
component.updateProfile();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display a warning', () => {
|
||||||
|
expect(notificationsService.warning).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the metadata form returns false and the security form returns false', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
component.metadataForm = jasmine.createSpyObj('metadataForm', {
|
||||||
|
updateProfile: false
|
||||||
|
});
|
||||||
|
component.updateProfile();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a warning', () => {
|
||||||
|
expect(notificationsService.warning).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when the metadata form returns true and the security form returns false', () => {
|
describe('updateSecurity', () => {
|
||||||
beforeEach(() => {
|
describe('when no password value present', () => {
|
||||||
component.metadataForm = jasmine.createSpyObj('metadataForm', {
|
let result;
|
||||||
updateProfile: true
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.setPasswordValue('');
|
||||||
|
|
||||||
|
result = component.updateSecurity();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false', () => {
|
||||||
|
expect(result).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call epersonService.patch', () => {
|
||||||
|
expect(epersonService.patch).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
component.updateProfile();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not display a warning', () => {
|
describe('when password is filled in, but the password is invalid', () => {
|
||||||
expect(notificationsService.warning).not.toHaveBeenCalled();
|
let result;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.setPasswordValue('test');
|
||||||
|
component.setInvalid(true);
|
||||||
|
result = component.updateSecurity();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true', () => {
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
expect(epersonService.patch).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when password is filled in, and is valid', () => {
|
||||||
|
let result;
|
||||||
|
let operations;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.setPasswordValue('testest');
|
||||||
|
component.setInvalid(false);
|
||||||
|
|
||||||
|
operations = [{ op: 'add', path: '/password', value: 'testest' }];
|
||||||
|
result = component.updateSecurity();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true', () => {
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return call epersonService.patch', () => {
|
||||||
|
expect(epersonService.patch).toHaveBeenCalledWith(user, operations);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when the metadata form returns true and the security form returns true', () => {
|
describe('canChangePassword$', () => {
|
||||||
beforeEach(() => {
|
describe('when the user is allowed to change their password', () => {
|
||||||
component.metadataForm = jasmine.createSpyObj('metadataForm', {
|
beforeEach(() => {
|
||||||
updateProfile: true
|
canChangePassword.next(true);
|
||||||
});
|
});
|
||||||
component.updateProfile();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not display a warning', () => {
|
it('should contain true', () => {
|
||||||
expect(notificationsService.warning).not.toHaveBeenCalled();
|
getTestScheduler().expectObservable(component.canChangePassword$).toBe('(a)', { a: true });
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('should show the security section on the page', () => {
|
||||||
describe('when the metadata form returns false and the security form returns false', () => {
|
fixture.detectChanges();
|
||||||
beforeEach(() => {
|
expect(fixture.debugElement.query(By.css('.security-section'))).not.toBeNull();
|
||||||
component.metadataForm = jasmine.createSpyObj('metadataForm', {
|
|
||||||
updateProfile: false
|
|
||||||
});
|
});
|
||||||
component.updateProfile();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display a warning', () => {
|
describe('when the user is not allowed to change their password', () => {
|
||||||
expect(notificationsService.warning).toHaveBeenCalled();
|
beforeEach(() => {
|
||||||
|
canChangePassword.next(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain false', () => {
|
||||||
|
getTestScheduler().expectObservable(component.canChangePassword$).toBe('(a)', { a: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show the security section on the page', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.query(By.css('.security-section'))).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('updateSecurity', () => {
|
describe('isResearcherProfileEnabled', () => {
|
||||||
describe('when no password value present', () => {
|
|
||||||
let result;
|
describe('when configuration service return values', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.setPasswordValue('');
|
configurationService.findByPropertyName.and.returnValue(createSuccessfulRemoteDataObject$(validConfiguration));
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
result = component.updateSecurity();
|
it('should return true', () => {
|
||||||
|
const result = component.isResearcherProfileEnabled();
|
||||||
|
const expected = cold('a', {
|
||||||
|
a: true
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when configuration service return no values', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
configurationService.findByPropertyName.and.returnValue(createSuccessfulRemoteDataObject$(emptyConfiguration));
|
||||||
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false', () => {
|
it('should return false', () => {
|
||||||
expect(result).toEqual(false);
|
const result = component.isResearcherProfileEnabled();
|
||||||
});
|
const expected = cold('a', {
|
||||||
|
a: false
|
||||||
it('should not call epersonService.patch', () => {
|
});
|
||||||
expect(epersonService.patch).not.toHaveBeenCalled();
|
expect(result).toBeObservable(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when password is filled in, but the password is invalid', () => {
|
describe('when configuration service return an error', () => {
|
||||||
let result;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.setPasswordValue('test');
|
configurationService.findByPropertyName.and.returnValue(createFailedRemoteDataObject$());
|
||||||
component.setInvalid(true);
|
|
||||||
result = component.updateSecurity();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true', () => {
|
|
||||||
expect(result).toEqual(true);
|
|
||||||
expect(epersonService.patch).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when password is filled in, and is valid', () => {
|
|
||||||
let result;
|
|
||||||
let operations;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
component.setPasswordValue('testest');
|
|
||||||
component.setInvalid(false);
|
|
||||||
|
|
||||||
operations = [{ op: 'add', path: '/password', value: 'testest' }];
|
|
||||||
result = component.updateSecurity();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true', () => {
|
|
||||||
expect(result).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return call epersonService.patch', () => {
|
|
||||||
expect(epersonService.patch).toHaveBeenCalledWith(user, operations);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('canChangePassword$', () => {
|
|
||||||
describe('when the user is allowed to change their password', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
canChangePassword.next(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should contain true', () => {
|
|
||||||
getTestScheduler().expectObservable(component.canChangePassword$).toBe('(a)', { a: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the security section on the page', () => {
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(fixture.debugElement.query(By.css('.security-section'))).not.toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when the user is not allowed to change their password', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
canChangePassword.next(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contain false', () => {
|
it('should return false', () => {
|
||||||
getTestScheduler().expectObservable(component.canChangePassword$).toBe('(a)', { a: false });
|
const result = component.isResearcherProfileEnabled();
|
||||||
});
|
const expected = cold('a', {
|
||||||
|
a: false
|
||||||
it('should not show the security section on the page', () => {
|
});
|
||||||
fixture.detectChanges();
|
expect(result).toBeObservable(expected);
|
||||||
expect(fixture.debugElement.query(By.css('.security-section'))).toBeNull();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import {BehaviorSubject, Observable} from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
import { EPerson } from '../core/eperson/models/eperson.model';
|
import { EPerson } from '../core/eperson/models/eperson.model';
|
||||||
import { ProfilePageMetadataFormComponent } from './profile-page-metadata-form/profile-page-metadata-form.component';
|
import { ProfilePageMetadataFormComponent } from './profile-page-metadata-form/profile-page-metadata-form.component';
|
||||||
import { NotificationsService } from '../shared/notifications/notifications.service';
|
import { NotificationsService } from '../shared/notifications/notifications.service';
|
||||||
@@ -9,18 +9,15 @@ import { RemoteData } from '../core/data/remote-data';
|
|||||||
import { PaginatedList } from '../core/data/paginated-list.model';
|
import { PaginatedList } from '../core/data/paginated-list.model';
|
||||||
import { filter, switchMap, tap } from 'rxjs/operators';
|
import { filter, switchMap, tap } from 'rxjs/operators';
|
||||||
import { EPersonDataService } from '../core/eperson/eperson-data.service';
|
import { EPersonDataService } from '../core/eperson/eperson-data.service';
|
||||||
import {
|
import { getAllSucceededRemoteData, getFirstCompletedRemoteData, getRemoteDataPayload } from '../core/shared/operators';
|
||||||
getAllSucceededRemoteData,
|
|
||||||
getRemoteDataPayload,
|
|
||||||
getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload
|
|
||||||
} from '../core/shared/operators';
|
|
||||||
import { hasValue, isNotEmpty } from '../shared/empty.util';
|
import { hasValue, isNotEmpty } from '../shared/empty.util';
|
||||||
import { followLink } from '../shared/utils/follow-link-config.model';
|
import { followLink } from '../shared/utils/follow-link-config.model';
|
||||||
import { AuthService } from '../core/auth/auth.service';
|
import { AuthService } from '../core/auth/auth.service';
|
||||||
import { Operation } from 'fast-json-patch';
|
import { Operation } from 'fast-json-patch';
|
||||||
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
||||||
import {ConfigurationDataService} from '../core/data/configuration-data.service';
|
import { ConfigurationDataService } from '../core/data/configuration-data.service';
|
||||||
|
import { ConfigurationProperty } from '../core/shared/configuration-property.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-profile-page',
|
selector: 'ds-profile-page',
|
||||||
@@ -94,8 +91,10 @@ export class ProfilePageComponent implements OnInit {
|
|||||||
this.canChangePassword$ = this.user$.pipe(switchMap((user: EPerson) => this.authorizationService.isAuthorized(FeatureID.CanChangePassword, user._links.self.href)));
|
this.canChangePassword$ = this.user$.pipe(switchMap((user: EPerson) => this.authorizationService.isAuthorized(FeatureID.CanChangePassword, user._links.self.href)));
|
||||||
|
|
||||||
this.configurationService.findByPropertyName('researcher-profile.entity-type').pipe(
|
this.configurationService.findByPropertyName('researcher-profile.entity-type').pipe(
|
||||||
getFirstSucceededRemoteDataPayload()
|
getFirstCompletedRemoteData()
|
||||||
).subscribe(() => this.isResearcherProfileEnabled$.next(true));
|
).subscribe((configRD: RemoteData<ConfigurationProperty>) => {
|
||||||
|
this.isResearcherProfileEnabled$.next(configRD.hasSucceeded && configRD.payload.values.length > 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,8 +174,8 @@ export class ProfilePageComponent implements OnInit {
|
|||||||
/**
|
/**
|
||||||
* Returns true if the researcher profile feature is enabled, false otherwise.
|
* Returns true if the researcher profile feature is enabled, false otherwise.
|
||||||
*/
|
*/
|
||||||
isResearcherProfileEnabled(){
|
isResearcherProfileEnabled(): Observable<boolean> {
|
||||||
return this.isResearcherProfileEnabled$;
|
return this.isResearcherProfileEnabled$.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -8884,11 +8884,6 @@ ngx-ui-switch@^11.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/ngx-ui-switch/-/ngx-ui-switch-11.0.1.tgz#c7f1e97ebe698f827a26f49951b50492b22c7839"
|
resolved "https://registry.yarnpkg.com/ngx-ui-switch/-/ngx-ui-switch-11.0.1.tgz#c7f1e97ebe698f827a26f49951b50492b22c7839"
|
||||||
integrity sha512-N8QYT/wW+xJdyh/aeebTSLPA6Sgrwp69H6KAcW0XZueg/LF+FKiqyG6Po/gFHq2gDhLikwyJEMpny8sudTI08w==
|
integrity sha512-N8QYT/wW+xJdyh/aeebTSLPA6Sgrwp69H6KAcW0XZueg/LF+FKiqyG6Po/gFHq2gDhLikwyJEMpny8sudTI08w==
|
||||||
|
|
||||||
nice-try@^1.0.4:
|
|
||||||
version "1.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
|
||||||
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
|
||||||
|
|
||||||
nice-napi@^1.0.2:
|
nice-napi@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/nice-napi/-/nice-napi-1.0.2.tgz#dc0ab5a1eac20ce548802fc5686eaa6bc654927b"
|
resolved "https://registry.yarnpkg.com/nice-napi/-/nice-napi-1.0.2.tgz#dc0ab5a1eac20ce548802fc5686eaa6bc654927b"
|
||||||
|
Reference in New Issue
Block a user