mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-19 07:53:02 +00:00
Parse embedded data
This commit is contained in:
3
src/app/core/cache/response-cache.models.ts
vendored
3
src/app/core/cache/response-cache.models.ts
vendored
@@ -56,7 +56,8 @@ export class ErrorResponse extends RestResponse {
|
|||||||
export class ConfigSuccessResponse extends RestResponse {
|
export class ConfigSuccessResponse extends RestResponse {
|
||||||
constructor(
|
constructor(
|
||||||
public configDefinition: ConfigObject[],
|
public configDefinition: ConfigObject[],
|
||||||
public statusCode: string
|
public statusCode: string,
|
||||||
|
public pageInfo?: PageInfo
|
||||||
) {
|
) {
|
||||||
super(true, statusCode);
|
super(true, statusCode);
|
||||||
}
|
}
|
||||||
|
13
src/app/core/config/config-data.ts
Normal file
13
src/app/core/config/config-data.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { PageInfo } from '../shared/page-info.model';
|
||||||
|
import { ConfigObject } from '../shared/config/config.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to represent the data retrieved by a configuration service
|
||||||
|
*/
|
||||||
|
export class ConfigData {
|
||||||
|
constructor(
|
||||||
|
public pageInfo: PageInfo,
|
||||||
|
public payload: ConfigObject[]
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
@@ -1,17 +1,19 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
import { RequestService } from '../data/request.service';
|
import { RequestService } from '../data/request.service';
|
||||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||||
import { GlobalConfig } from '../../../config/global-config.interface';
|
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||||
import { ConfigSuccessResponse, EndpointMap, RootSuccessResponse } from '../cache/response-cache.models';
|
import { ConfigSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models';
|
||||||
import { ConfigRequest, FindAllOptions, RestRequest, RootEndpointRequest } from '../data/request.models';
|
import { ConfigRequest, FindAllOptions, RestRequest } from '../data/request.models';
|
||||||
import { ResponseCacheEntry } from '../cache/response-cache.reducer';
|
import { ResponseCacheEntry } from '../cache/response-cache.reducer';
|
||||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { ConfigObject } from '../shared/config/config.model';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { ConfigData } from './config-data';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export abstract class ConfigService {
|
export abstract class ConfigService extends HALEndpointService {
|
||||||
protected request: ConfigRequest;
|
protected request: ConfigRequest;
|
||||||
protected abstract responseCache: ResponseCacheService;
|
protected abstract responseCache: ResponseCacheService;
|
||||||
protected abstract requestService: RequestService;
|
protected abstract requestService: RequestService;
|
||||||
@@ -19,12 +21,17 @@ export abstract class ConfigService {
|
|||||||
protected abstract EnvConfig: GlobalConfig;
|
protected abstract EnvConfig: GlobalConfig;
|
||||||
protected abstract browseEndpoint: string;
|
protected abstract browseEndpoint: string;
|
||||||
|
|
||||||
protected getConfig(request: RestRequest): Observable<ConfigObject[]> {
|
protected getConfig(request: RestRequest): Observable<ConfigData> {
|
||||||
return this.responseCache.get(request.href)
|
const [successResponse, errorResponse] = this.responseCache.get(request.href)
|
||||||
.map((entry: ResponseCacheEntry) => entry.response)
|
.map((entry: ResponseCacheEntry) => entry.response)
|
||||||
|
.partition((response: RestResponse) => response.isSuccessful);
|
||||||
|
return Observable.merge(
|
||||||
|
errorResponse.flatMap((response: ErrorResponse) =>
|
||||||
|
Observable.throw(new Error(`Couldn't retrieve the config`))),
|
||||||
|
successResponse
|
||||||
.filter((response: ConfigSuccessResponse) => isNotEmpty(response) && isNotEmpty(response.configDefinition))
|
.filter((response: ConfigSuccessResponse) => isNotEmpty(response) && isNotEmpty(response.configDefinition))
|
||||||
.map((response: ConfigSuccessResponse) => response.configDefinition)
|
.map((response: ConfigSuccessResponse) => new ConfigData(response.pageInfo, response.configDefinition))
|
||||||
.distinctUntilChanged();
|
.distinctUntilChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getConfigByIDHref(endpoint, resourceID): string {
|
protected getConfigByIDHref(endpoint, resourceID): string {
|
||||||
@@ -36,7 +43,7 @@ export abstract class ConfigService {
|
|||||||
const args = [];
|
const args = [];
|
||||||
|
|
||||||
if (hasValue(options.scopeID)) {
|
if (hasValue(options.scopeID)) {
|
||||||
result = `${endpoint}/${this.browseEndpoint}`
|
result = `${endpoint}/${this.browseEndpoint}`;
|
||||||
args.push(`uuid=${options.scopeID}`);
|
args.push(`uuid=${options.scopeID}`);
|
||||||
} else {
|
} else {
|
||||||
result = endpoint;
|
result = endpoint;
|
||||||
@@ -65,19 +72,7 @@ export abstract class ConfigService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getEndpointMap(): Observable<EndpointMap> {
|
public getConfigAll(): Observable<ConfigData> {
|
||||||
const request = new RootEndpointRequest(this.EnvConfig);
|
|
||||||
setTimeout(() => {
|
|
||||||
this.requestService.configure(request);
|
|
||||||
}, 0);
|
|
||||||
return this.responseCache.get(request.href)
|
|
||||||
.map((entry: ResponseCacheEntry) => entry.response)
|
|
||||||
.filter((response: RootSuccessResponse) => isNotEmpty(response) && isNotEmpty(response.endpointMap))
|
|
||||||
.map((response: RootSuccessResponse) => response.endpointMap)
|
|
||||||
.distinctUntilChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConfigAll(): Observable<ConfigObject[]> {
|
|
||||||
return this.getEndpoint()
|
return this.getEndpoint()
|
||||||
.filter((href: string) => isNotEmpty(href))
|
.filter((href: string) => isNotEmpty(href))
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
@@ -91,16 +86,16 @@ export abstract class ConfigService {
|
|||||||
.distinctUntilChanged();
|
.distinctUntilChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConfigByHref(href: string): Observable<ConfigObject[]> {
|
public getConfigByHref(href: string): Observable<ConfigData> {
|
||||||
const request = new ConfigRequest(href);
|
const request = new ConfigRequest(href);
|
||||||
this.requestService.configure(request);
|
this.requestService.configure(request);
|
||||||
|
|
||||||
return this.getConfig(request);
|
return this.getConfig(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConfigById(id: string): Observable<ConfigObject[]> {
|
public getConfigByName(name: string): Observable<ConfigData> {
|
||||||
return this.getEndpoint()
|
return this.getEndpoint()
|
||||||
.map((endpoint: string) => this.getConfigByIDHref(endpoint, id))
|
.map((endpoint: string) => this.getConfigByIDHref(endpoint, name))
|
||||||
.filter((href: string) => isNotEmpty(href))
|
.filter((href: string) => isNotEmpty(href))
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.map((endpointURL: string) => new ConfigRequest(endpointURL))
|
.map((endpointURL: string) => new ConfigRequest(endpointURL))
|
||||||
@@ -113,7 +108,7 @@ export abstract class ConfigService {
|
|||||||
.distinctUntilChanged();
|
.distinctUntilChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConfigBySearch(options: FindAllOptions = {}): Observable<ConfigObject[]> {
|
public getConfigBySearch(options: FindAllOptions = {}): Observable<ConfigData> {
|
||||||
return this.getEndpoint()
|
return this.getEndpoint()
|
||||||
.map((endpoint: string) => this.getConfigSearchHref(endpoint, options))
|
.map((endpoint: string) => this.getConfigSearchHref(endpoint, options))
|
||||||
.filter((href: string) => isNotEmpty(href))
|
.filter((href: string) => isNotEmpty(href))
|
||||||
@@ -128,10 +123,4 @@ export abstract class ConfigService {
|
|||||||
.distinctUntilChanged();
|
.distinctUntilChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEndpoint(): Observable<string> {
|
|
||||||
return this.getEndpointMap()
|
|
||||||
.map((map: EndpointMap) => map[this.linkName])
|
|
||||||
.distinctUntilChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
135
src/app/core/data/base-response-parsing.service.ts
Normal file
135
src/app/core/data/base-response-parsing.service.ts
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
|
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||||
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
|
import { PageInfo } from '../shared/page-info.model';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||||
|
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||||
|
import { GenericConstructor } from '../shared/generic-constructor';
|
||||||
|
|
||||||
|
function isObjectLevel(halObj: any) {
|
||||||
|
return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPaginatedResponse(halObj: any) {
|
||||||
|
return isNotEmpty(halObj.page) && hasValue(halObj._embedded);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tslint:disable:max-classes-per-file */
|
||||||
|
|
||||||
|
class ProcessRequestDTO<ObjectDomain> {
|
||||||
|
[key: string]: ObjectDomain[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class BaseResponseParsingService {
|
||||||
|
protected abstract EnvConfig: GlobalConfig;
|
||||||
|
protected abstract objectCache: ObjectCacheService;
|
||||||
|
protected abstract objectFactory: any;
|
||||||
|
protected abstract toCache: boolean;
|
||||||
|
|
||||||
|
protected process<ObjectDomain,ObjectType>(data: any, requestHref: string): ProcessRequestDTO<ObjectDomain> {
|
||||||
|
|
||||||
|
if (isNotEmpty(data)) {
|
||||||
|
if (isPaginatedResponse(data)) {
|
||||||
|
return this.process(data._embedded, requestHref);
|
||||||
|
} else if (isObjectLevel(data)) {
|
||||||
|
return { topLevel: this.deserializeAndCache(data, requestHref) };
|
||||||
|
} else {
|
||||||
|
const result = new ProcessRequestDTO<ObjectDomain>();
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
result.topLevel = [];
|
||||||
|
data.forEach((datum) => {
|
||||||
|
if (isPaginatedResponse(datum)) {
|
||||||
|
const obj = this.process(datum, requestHref);
|
||||||
|
result.topLevel = [...result.topLevel, ...this.flattenSingleKeyObject(obj)];
|
||||||
|
} else {
|
||||||
|
result.topLevel = [...result.topLevel, ...this.deserializeAndCache<ObjectDomain,ObjectType>(datum, requestHref)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Object.keys(data)
|
||||||
|
.filter((property) => data.hasOwnProperty(property))
|
||||||
|
.filter((property) => hasValue(data[property]))
|
||||||
|
.forEach((property) => {
|
||||||
|
if (isPaginatedResponse(data[property])) {
|
||||||
|
const obj = this.process(data[property], requestHref);
|
||||||
|
result[property] = this.flattenSingleKeyObject(obj);
|
||||||
|
} else {
|
||||||
|
result[property] = this.deserializeAndCache(data[property], requestHref);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected deserializeAndCache<ObjectDomain,ObjectType>(obj, requestHref: string): ObjectDomain[] {
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
let result = [];
|
||||||
|
obj.forEach((o) => result = [...result, ...this.deserializeAndCache<ObjectDomain,ObjectType>(o, requestHref)]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const type: ObjectType = obj.type;
|
||||||
|
if (hasValue(type)) {
|
||||||
|
const normObjConstructor = this.objectFactory.getConstructor(type) as GenericConstructor<ObjectDomain>;
|
||||||
|
|
||||||
|
if (hasValue(normObjConstructor)) {
|
||||||
|
const serializer = new DSpaceRESTv2Serializer(normObjConstructor);
|
||||||
|
|
||||||
|
let processed;
|
||||||
|
if (isNotEmpty(obj._embedded)) {
|
||||||
|
processed = this.process<ObjectDomain,ObjectType>(obj._embedded, requestHref);
|
||||||
|
}
|
||||||
|
const normalizedObj: any = serializer.deserialize(obj);
|
||||||
|
|
||||||
|
if (isNotEmpty(processed)) {
|
||||||
|
const processedList = {};
|
||||||
|
Object.keys(processed).forEach((key) => {
|
||||||
|
processedList[key] = processed[key].map((no: NormalizedObject) => (this.toCache) ? no.self : no);
|
||||||
|
});
|
||||||
|
Object.assign(normalizedObj, processedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.toCache) {
|
||||||
|
this.addToObjectCache(normalizedObj, requestHref);
|
||||||
|
}
|
||||||
|
return [normalizedObj] as any;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// TODO: move check to Validator?
|
||||||
|
// throw new Error(`The server returned an object with an unknown a known type: ${type}`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// TODO: move check to Validator
|
||||||
|
// throw new Error(`The server returned an object without a type: ${JSON.stringify(obj)}`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected addToObjectCache(co: CacheableObject, requestHref: string): void {
|
||||||
|
if (hasNoValue(co) || hasNoValue(co.self)) {
|
||||||
|
throw new Error('The server returned an invalid object');
|
||||||
|
}
|
||||||
|
this.objectCache.add(co, this.EnvConfig.cache.msToLive, requestHref);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processPageInfo(pageObj: any): PageInfo {
|
||||||
|
if (isNotEmpty(pageObj)) {
|
||||||
|
return new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected flattenSingleKeyObject(obj: any): any {
|
||||||
|
const keys = Object.keys(obj);
|
||||||
|
if (keys.length !== 1) {
|
||||||
|
throw new Error(`Expected an object with a single key, got: ${JSON.stringify(obj)}`);
|
||||||
|
}
|
||||||
|
return obj[keys[0]];
|
||||||
|
}
|
||||||
|
}
|
@@ -1,31 +1,35 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { ResponseParsingService } from './parsing.service';
|
import { ResponseParsingService } from './parsing.service';
|
||||||
import { RestRequest } from './request.models';
|
import { RestRequest } from './request.models';
|
||||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||||
import { ConfigSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models';
|
import { ConfigSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models';
|
||||||
import { isNotEmpty } from '../../shared/empty.util';
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
|
||||||
import { ConfigObjectFactory } from '../shared/config/config-object-factory';
|
import { ConfigObjectFactory } from '../shared/config/config-object-factory';
|
||||||
|
|
||||||
|
import { ConfigObject } from '../shared/config/config.model';
|
||||||
|
import { ConfigType } from '../shared/config/config-type';
|
||||||
|
import { BaseResponseParsingService } from './base-response-parsing.service';
|
||||||
|
import { GLOBAL_CONFIG } from '../../../config';
|
||||||
|
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ConfigResponseParsingService implements ResponseParsingService {
|
export class ConfigResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
|
||||||
|
|
||||||
|
protected objectFactory = ConfigObjectFactory;
|
||||||
|
protected toCache = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
) { super();
|
||||||
|
}
|
||||||
|
|
||||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||||
if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links)) {
|
if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links)) {
|
||||||
let configDefinition;
|
const configDefinition = this.process<ConfigObject,ConfigType>(data.payload, request.href);
|
||||||
let payload;
|
return new ConfigSuccessResponse(configDefinition[Object.keys(configDefinition)[0]], data.statusCode, this.processPageInfo(data.payload.page));
|
||||||
let type;
|
|
||||||
if (isNotEmpty(data.payload._embedded) && Array.isArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]])) {
|
|
||||||
type = Object.keys(data.payload._embedded)[0];
|
|
||||||
payload = data.payload._embedded[Object.keys(data.payload._embedded)[0]];
|
|
||||||
} else {
|
|
||||||
type = data.payload.type;
|
|
||||||
payload = [data.payload];
|
|
||||||
}
|
|
||||||
const serializer = new DSpaceRESTv2Serializer(ConfigObjectFactory.getConstructor(type));
|
|
||||||
configDefinition = serializer.deserializeArray(payload);
|
|
||||||
return new ConfigSuccessResponse(configDefinition, data.statusCode);
|
|
||||||
} else {
|
} else {
|
||||||
return new ErrorResponse(
|
return new ErrorResponse(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
@@ -35,4 +39,5 @@ export class ConfigResponseParsingService implements ResponseParsingService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,149 +1,34 @@
|
|||||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
|
||||||
import { Inject, Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
import { GlobalConfig } from '../../../config/global-config.interface';
|
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||||
import { GLOBAL_CONFIG } from '../../../config';
|
import { GLOBAL_CONFIG } from '../../../config';
|
||||||
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||||
import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util';
|
|
||||||
import { ResourceType } from '../shared/resource-type';
|
import { ResourceType } from '../shared/resource-type';
|
||||||
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
||||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
|
||||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
|
||||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||||
import { RestResponse, DSOSuccessResponse } from '../cache/response-cache.models';
|
import { RestResponse, DSOSuccessResponse } from '../cache/response-cache.models';
|
||||||
import { RestRequest } from './request.models';
|
import { RestRequest } from './request.models';
|
||||||
import { PageInfo } from '../shared/page-info.model';
|
|
||||||
import { ResponseParsingService } from './parsing.service';
|
import { ResponseParsingService } from './parsing.service';
|
||||||
|
import { BaseResponseParsingService } from './base-response-parsing.service';
|
||||||
function isObjectLevel(halObj: any) {
|
|
||||||
return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPaginatedResponse(halObj: any) {
|
|
||||||
return isNotEmpty(halObj.page) && hasValue(halObj._embedded);
|
|
||||||
}
|
|
||||||
|
|
||||||
function flattenSingleKeyObject(obj: any): any {
|
|
||||||
const keys = Object.keys(obj);
|
|
||||||
if (keys.length !== 1) {
|
|
||||||
throw new Error(`Expected an object with a single key, got: ${JSON.stringify(obj)}`);
|
|
||||||
}
|
|
||||||
return obj[keys[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
|
||||||
class ProcessRequestDTO {
|
|
||||||
[key: string]: NormalizedObject[]
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DSOResponseParsingService implements ResponseParsingService {
|
export class DSOResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
|
||||||
|
|
||||||
|
protected objectFactory = NormalizedObjectFactory;
|
||||||
|
protected toCache = true;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(GLOBAL_CONFIG) private EnvConfig: GlobalConfig,
|
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||||
private objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
) {
|
) { super();
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||||
const processRequestDTO = this.process(data.payload, request.href);
|
const processRequestDTO = this.process<NormalizedObject,ResourceType>(data.payload, request.href);
|
||||||
const selfLinks = flattenSingleKeyObject(processRequestDTO).map((no) => no.self);
|
const selfLinks = this.flattenSingleKeyObject(processRequestDTO).map((no) => no.self);
|
||||||
return new DSOSuccessResponse(selfLinks, data.statusCode, this.processPageInfo(data.payload.page))
|
return new DSOSuccessResponse(selfLinks, data.statusCode, this.processPageInfo(data.payload.page))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected process(data: any, requestHref: string): ProcessRequestDTO {
|
|
||||||
|
|
||||||
if (isNotEmpty(data)) {
|
|
||||||
if (isPaginatedResponse(data)) {
|
|
||||||
return this.process(data._embedded, requestHref);
|
|
||||||
} else if (isObjectLevel(data)) {
|
|
||||||
return { topLevel: this.deserializeAndCache(data, requestHref) };
|
|
||||||
} else {
|
|
||||||
const result = new ProcessRequestDTO();
|
|
||||||
if (Array.isArray(data)) {
|
|
||||||
result.topLevel = [];
|
|
||||||
data.forEach((datum) => {
|
|
||||||
if (isPaginatedResponse(datum)) {
|
|
||||||
const obj = this.process(datum, requestHref);
|
|
||||||
result.topLevel = [...result.topLevel, ...flattenSingleKeyObject(obj)];
|
|
||||||
} else {
|
|
||||||
result.topLevel = [...result.topLevel, ...this.deserializeAndCache(datum, requestHref)];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Object.keys(data)
|
|
||||||
.filter((property) => data.hasOwnProperty(property))
|
|
||||||
.filter((property) => hasValue(data[property]))
|
|
||||||
.forEach((property) => {
|
|
||||||
if (isPaginatedResponse(data[property])) {
|
|
||||||
const obj = this.process(data[property], requestHref);
|
|
||||||
result[property] = flattenSingleKeyObject(obj);
|
|
||||||
} else {
|
|
||||||
result[property] = this.deserializeAndCache(data[property], requestHref);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected deserializeAndCache(obj, requestHref: string): NormalizedObject[] {
|
|
||||||
if (Array.isArray(obj)) {
|
|
||||||
let result = [];
|
|
||||||
obj.forEach((o) => result = [...result, ...this.deserializeAndCache(o, requestHref)])
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const type: ResourceType = obj.type;
|
|
||||||
if (hasValue(type)) {
|
|
||||||
const normObjConstructor = NormalizedObjectFactory.getConstructor(type);
|
|
||||||
|
|
||||||
if (hasValue(normObjConstructor)) {
|
|
||||||
const serializer = new DSpaceRESTv2Serializer(normObjConstructor);
|
|
||||||
|
|
||||||
let processed;
|
|
||||||
if (isNotEmpty(obj._embedded)) {
|
|
||||||
processed = this.process(obj._embedded, requestHref);
|
|
||||||
}
|
|
||||||
const normalizedObj = serializer.deserialize(obj);
|
|
||||||
|
|
||||||
if (isNotEmpty(processed)) {
|
|
||||||
const linksOnly = {};
|
|
||||||
Object.keys(processed).forEach((key) => {
|
|
||||||
linksOnly[key] = processed[key].map((no: NormalizedObject) => no.self);
|
|
||||||
});
|
|
||||||
Object.assign(normalizedObj, linksOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addToObjectCache(normalizedObj, requestHref);
|
|
||||||
return [normalizedObj];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// TODO: move check to Validator?
|
|
||||||
// throw new Error(`The server returned an object with an unknown a known type: ${type}`);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// TODO: move check to Validator
|
|
||||||
// throw new Error(`The server returned an object without a type: ${JSON.stringify(obj)}`);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected addToObjectCache(co: CacheableObject, requestHref: string): void {
|
|
||||||
if (hasNoValue(co) || hasNoValue(co.self)) {
|
|
||||||
throw new Error('The server returned an invalid object');
|
|
||||||
}
|
|
||||||
this.objectCache.add(co, this.EnvConfig.cache.msToLive, requestHref);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected processPageInfo(pageObj: any): PageInfo {
|
|
||||||
if (isNotEmpty(pageObj)) {
|
|
||||||
return new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
/* tslint:enable:max-classes-per-file */
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import { autoserialize, inheritSerialization } from 'cerialize';
|
import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
|
||||||
import { ConfigObject } from './config.model';
|
import { ConfigObject } from './config.model';
|
||||||
import { SubmissionSectionModel } from './config-submission-section.model';
|
import { SubmissionSectionModel } from './config-submission-section.model';
|
||||||
import { RemoteData } from '../../data/remote-data';
|
|
||||||
|
|
||||||
@inheritSerialization(ConfigObject)
|
@inheritSerialization(ConfigObject)
|
||||||
export class SubmissionDefinitionsModel extends ConfigObject {
|
export class SubmissionDefinitionsModel extends ConfigObject {
|
||||||
@@ -9,7 +8,7 @@ export class SubmissionDefinitionsModel extends ConfigObject {
|
|||||||
@autoserialize
|
@autoserialize
|
||||||
isDefault: boolean;
|
isDefault: boolean;
|
||||||
|
|
||||||
@autoserialize
|
@autoserializeAs(SubmissionSectionModel)
|
||||||
sections: RemoteData<SubmissionSectionModel[]>;
|
sections: SubmissionSectionModel[];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
* TODO replace with actual string enum after upgrade to TypeScript 2.4:
|
* TODO replace with actual string enum after upgrade to TypeScript 2.4:
|
||||||
* https://github.com/Microsoft/TypeScript/pull/15486
|
* https://github.com/Microsoft/TypeScript/pull/15486
|
||||||
*/
|
*/
|
||||||
|
import { ResourceType } from '../resource-type';
|
||||||
|
|
||||||
export enum ConfigType {
|
export enum ConfigType {
|
||||||
SubmissionDefinitions = 'submissiondefinitions',
|
SubmissionDefinitions = 'submissiondefinitions',
|
||||||
SubmissionDefinition = 'submissiondefinition',
|
SubmissionDefinition = 'submissiondefinition',
|
||||||
|
@@ -12,4 +12,10 @@ export abstract class ConfigObject {
|
|||||||
public _links: {
|
public _links: {
|
||||||
[name: string]: string
|
[name: string]: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The link to the rest endpoint where this config object can be found
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
self: string;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user