[CST-5307] use followlink for retrieving profile item on create and find

This commit is contained in:
Giuseppe Digilio
2022-05-26 15:32:18 +02:00
parent be3fceb185
commit e6f6bc96f3
6 changed files with 33 additions and 21 deletions

View File

@@ -8,11 +8,11 @@ import {
find, find,
map, map,
mergeMap, mergeMap,
skipWhile,
switchMap,
take, take,
takeWhile, takeWhile,
switchMap,
tap, tap,
skipWhile,
} from 'rxjs/operators'; } from 'rxjs/operators';
import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
@@ -25,18 +25,12 @@ import { ObjectCacheService } from '../cache/object-cache.service';
import { DSpaceSerializer } from '../dspace-rest/dspace.serializer'; import { DSpaceSerializer } from '../dspace-rest/dspace.serializer';
import { DSpaceObject } from '../shared/dspace-object.model'; import { DSpaceObject } from '../shared/dspace-object.model';
import { HALEndpointService } from '../shared/hal-endpoint.service'; import { HALEndpointService } from '../shared/hal-endpoint.service';
import { getRemoteDataPayload, getFirstSucceededRemoteData, } from '../shared/operators'; import { getFirstSucceededRemoteData, getRemoteDataPayload, } from '../shared/operators';
import { URLCombiner } from '../url-combiner/url-combiner'; import { URLCombiner } from '../url-combiner/url-combiner';
import { ChangeAnalyzer } from './change-analyzer'; import { ChangeAnalyzer } from './change-analyzer';
import { PaginatedList } from './paginated-list.model'; import { PaginatedList } from './paginated-list.model';
import { RemoteData } from './remote-data'; import { RemoteData } from './remote-data';
import { import { CreateRequest, DeleteRequest, GetRequest, PatchRequest, PutRequest } from './request.models';
CreateRequest,
GetRequest,
PatchRequest,
PutRequest,
DeleteRequest
} from './request.models';
import { RequestService } from './request.service'; import { RequestService } from './request.service';
import { RestRequestMethod } from './rest-request-method'; import { RestRequestMethod } from './rest-request-method';
import { UpdateDataService } from './update-data.service'; import { UpdateDataService } from './update-data.service';
@@ -168,7 +162,7 @@ export abstract class DataService<T extends CacheableObject> implements UpdateDa
* @return {Observable<string>} * @return {Observable<string>}
* Return an observable that emits created HREF * Return an observable that emits created HREF
*/ */
protected buildHrefWithParams(href: string, params: RequestParam[], ...linksToFollow: FollowLinkConfig<T>[]): string { buildHrefWithParams(href: string, params: RequestParam[], ...linksToFollow: FollowLinkConfig<T>[]): string {
let args = []; let args = [];
if (hasValue(params)) { if (hasValue(params)) {

View File

@@ -1,10 +1,15 @@
import { Observable } from 'rxjs';
import { autoserialize, deserialize, deserializeAs } from 'cerialize'; import { autoserialize, deserialize, deserializeAs } from 'cerialize';
import { typedObject } from '../../cache/builders/build-decorators';
import { link, typedObject } from '../../cache/builders/build-decorators';
import { HALLink } from '../../shared/hal-link.model'; import { HALLink } from '../../shared/hal-link.model';
import { ResourceType } from '../../shared/resource-type'; import { ResourceType } from '../../shared/resource-type';
import { excludeFromEquals } from '../../utilities/equals.decorators'; import { excludeFromEquals } from '../../utilities/equals.decorators';
import { RESEARCHER_PROFILE } from './researcher-profile.resource-type'; import { RESEARCHER_PROFILE } from './researcher-profile.resource-type';
import {CacheableObject} from '../../cache/cacheable-object.model'; import { CacheableObject } from '../../cache/cacheable-object.model';
import { RemoteData } from '../../data/remote-data';
import { ITEM } from '../../shared/item.resource-type';
import { Item } from '../../shared/item.model';
/** /**
* Class the represents a Researcher Profile. * Class the represents a Researcher Profile.
@@ -46,4 +51,11 @@ export class ResearcherProfile extends CacheableObject {
eperson: HALLink eperson: HALLink
}; };
/**
* The related person Item
* Will be undefined unless the item {@link HALLink} has been resolved.
*/
@link(ITEM)
item?: Observable<RemoteData<Item>>;
} }

View File

@@ -25,6 +25,7 @@ import { Item } from '../shared/item.model';
import { ReplaceOperation } from 'fast-json-patch'; import { ReplaceOperation } from 'fast-json-patch';
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 { followLink } from '../../shared/utils/follow-link-config.model';
describe('ResearcherProfileService', () => { describe('ResearcherProfileService', () => {
let scheduler: TestScheduler; let scheduler: TestScheduler;
@@ -86,6 +87,7 @@ describe('ResearcherProfileService', () => {
} }
}); });
const endpointURL = `https://rest.api/rest/api/profiles`; const endpointURL = `https://rest.api/rest/api/profiles`;
const endpointURLWithEmbed = 'https://rest.api/rest/api/profiles?embed=item';
const sourceUri = `https://rest.api/rest/api/external-source/profile`; const sourceUri = `https://rest.api/rest/api/external-source/profile`;
const requestURL = `https://rest.api/rest/api/profiles/${researcherProfileId}`; const requestURL = `https://rest.api/rest/api/profiles/${researcherProfileId}`;
const requestUUID = '8b3c613a-5a4b-438b-9686-be1d5b4a1c5a'; const requestUUID = '8b3c613a-5a4b-438b-9686-be1d5b4a1c5a';
@@ -280,13 +282,13 @@ describe('ResearcherProfileService', () => {
let headers = new HttpHeaders(); let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'text/uri-list'); headers = headers.append('Content-Type', 'text/uri-list');
options.headers = headers; options.headers = headers;
const request = new PostRequest(requestUUID, endpointURL, sourceUri, options); const request = new PostRequest(requestUUID, endpointURLWithEmbed, sourceUri, options);
scheduler.schedule(() => service.createFromExternalSource(sourceUri)); scheduler.schedule(() => service.createFromExternalSource(sourceUri));
scheduler.flush(); scheduler.flush();
expect((service as any).requestService.send).toHaveBeenCalledWith(request); expect((service as any).requestService.send).toHaveBeenCalledWith(request);
expect((service as any).rdbService.buildFromRequestUUID).toHaveBeenCalledWith(requestUUID); expect((service as any).rdbService.buildFromRequestUUID).toHaveBeenCalledWith(requestUUID, followLink('item'));
}); });
}); });

View File

@@ -26,7 +26,7 @@ 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'; import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
import { Item } from '../shared/item.model'; import { Item } from '../shared/item.model';
/** /**
@@ -123,7 +123,8 @@ export class ResearcherProfileService {
* @param researcherProfile the profile to find for * @param researcherProfile the profile to find for
*/ */
public findRelatedItemId(researcherProfile: ResearcherProfile): Observable<string> { public findRelatedItemId(researcherProfile: ResearcherProfile): Observable<string> {
return this.itemService.findByHref(researcherProfile._links.item.href, false).pipe( const relatedItem$ = researcherProfile.item ? researcherProfile.item : this.itemService.findByHref(researcherProfile._links.item.href, false);
return relatedItem$.pipe(
getFirstCompletedRemoteData(), getFirstCompletedRemoteData(),
map((itemRD: RemoteData<Item>) => (itemRD.hasSucceeded && itemRD.payload) ? itemRD.payload.id : null) map((itemRD: RemoteData<Item>) => (itemRD.hasSucceeded && itemRD.payload) ? itemRD.payload.id : null)
); );
@@ -159,12 +160,13 @@ export class ResearcherProfileService {
const href$ = this.halService.getEndpoint(this.dataService.getLinkPath()); const href$ = this.halService.getEndpoint(this.dataService.getLinkPath());
href$.pipe( href$.pipe(
find((href: string) => hasValue(href)) find((href: string) => hasValue(href)),
map((href: string) => this.dataService.buildHrefWithParams(href, [], followLink('item')))
).subscribe((endpoint: string) => { ).subscribe((endpoint: string) => {
const request = new PostRequest(requestId, endpoint, sourceUri, options); const request = new PostRequest(requestId, endpoint, sourceUri, options);
this.requestService.send(request); this.requestService.send(request);
}); });
return this.rdbService.buildFromRequestUUID(requestId); return this.rdbService.buildFromRequestUUID(requestId, followLink('item'));
} }
} }

View File

@@ -17,6 +17,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 { AuthService } from '../../core/auth/auth.service'; import { AuthService } from '../../core/auth/auth.service';
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { followLink } from '../../shared/utils/follow-link-config.model';
describe('ProfilePageResearcherFormComponent', () => { describe('ProfilePageResearcherFormComponent', () => {
@@ -92,7 +93,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, false); expect(researcherProfileService.findById).toHaveBeenCalledWith(user.id, false, true, followLink('item'));
}); });
describe('createProfile', () => { describe('createProfile', () => {

View File

@@ -16,6 +16,7 @@ import { ResearcherProfileService } from '../../core/profile/researcher-profile.
import { ProfileClaimService } from '../profile-claim/profile-claim.service'; import { ProfileClaimService } from '../profile-claim/profile-claim.service';
import { RemoteData } from '../../core/data/remote-data'; import { RemoteData } from '../../core/data/remote-data';
import { isNotEmpty } from '../../shared/empty.util'; import { isNotEmpty } from '../../shared/empty.util';
import { followLink } from '../../shared/utils/follow-link-config.model';
@Component({ @Component({
selector: 'ds-profile-page-researcher-form', selector: 'ds-profile-page-researcher-form',
@@ -180,7 +181,7 @@ 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, false).pipe( this.researcherProfileService.findById(this.user.id, false, true, followLink('item')).pipe(
getFirstSucceededRemoteDataPayload(), getFirstSucceededRemoteDataPayload(),
tap((researcherProfile) => this.researcherProfile$.next(researcherProfile)), tap((researcherProfile) => this.researcherProfile$.next(researcherProfile)),
mergeMap((researcherProfile) => this.researcherProfileService.findRelatedItemId(researcherProfile)), mergeMap((researcherProfile) => this.researcherProfileService.findRelatedItemId(researcherProfile)),