mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-10 19:43:04 +00:00
added support for embedded resources
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import { GenericConstructor } from "../../shared/generic-constructor";
|
import { GenericConstructor } from "../../shared/generic-constructor";
|
||||||
import { CacheableObject } from "../object-cache.reducer";
|
import { CacheableObject } from "../object-cache.reducer";
|
||||||
import { NormalizedDSOType } from "../models/normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
const mapsToMetadataKey = Symbol("mapsTo");
|
const mapsToMetadataKey = Symbol("mapsTo");
|
||||||
const relationshipKey = Symbol("relationship");
|
const relationshipKey = Symbol("relationship");
|
||||||
@@ -16,7 +16,7 @@ export const getMapsTo = function(target: any) {
|
|||||||
return Reflect.getOwnMetadata(mapsToMetadataKey, target);
|
return Reflect.getOwnMetadata(mapsToMetadataKey, target);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const relationship = function(value: NormalizedDSOType): any {
|
export const relationship = function(value: ResourceType): any {
|
||||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||||
if (!target || !propertyKey) {
|
if (!target || !propertyKey) {
|
||||||
return;
|
return;
|
||||||
|
@@ -13,7 +13,8 @@ import { Observable } from "rxjs/Observable";
|
|||||||
import { RemoteData } from "../../data/remote-data";
|
import { RemoteData } from "../../data/remote-data";
|
||||||
import { GenericConstructor } from "../../shared/generic-constructor";
|
import { GenericConstructor } from "../../shared/generic-constructor";
|
||||||
import { getMapsTo, getResourceType, getRelationships } from "./build-decorators";
|
import { getMapsTo, getResourceType, getRelationships } from "./build-decorators";
|
||||||
import { NormalizedDSOFactory } from "../models/normalized-dspace-object-factory";
|
import { NormalizedObjectFactory } from "../models/normalized-object-factory";
|
||||||
|
import { Request } from "../../data/request.models";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RemoteDataBuildService {
|
export class RemoteDataBuildService {
|
||||||
@@ -124,13 +125,13 @@ export class RemoteDataBuildService {
|
|||||||
relationships.forEach((relationship: string) => {
|
relationships.forEach((relationship: string) => {
|
||||||
if (hasValue(normalized[relationship])) {
|
if (hasValue(normalized[relationship])) {
|
||||||
const resourceType = getResourceType(normalized, relationship);
|
const resourceType = getResourceType(normalized, relationship);
|
||||||
const resourceConstructor = NormalizedDSOFactory.getConstructor(resourceType);
|
const resourceConstructor = NormalizedObjectFactory.getConstructor(resourceType);
|
||||||
if (Array.isArray(normalized[relationship])) {
|
if (Array.isArray(normalized[relationship])) {
|
||||||
// without the setTimeout, the actions inside requestService.configure
|
// without the setTimeout, the actions inside requestService.configure
|
||||||
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
|
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
normalized[relationship].forEach((href: string) => {
|
normalized[relationship].forEach((href: string) => {
|
||||||
this.requestService.configure(href, resourceConstructor)
|
this.requestService.configure(new Request(href))
|
||||||
});
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
@@ -142,7 +143,7 @@ export class RemoteDataBuildService {
|
|||||||
// without the setTimeout, the actions inside requestService.configure
|
// without the setTimeout, the actions inside requestService.configure
|
||||||
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
|
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.requestService.configure(normalized[relationship], resourceConstructor);
|
this.requestService.configure(new Request(normalized[relationship]));
|
||||||
},0);
|
},0);
|
||||||
|
|
||||||
links[relationship] = this.buildSingle(normalized[relationship], resourceConstructor);
|
links[relationship] = this.buildSingle(normalized[relationship], resourceConstructor);
|
||||||
|
@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization } from "cerialize";
|
|||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Bundle } from "../../shared/bundle.model";
|
import { Bundle } from "../../shared/bundle.model";
|
||||||
import { mapsTo, relationship } from "../builders/build-decorators";
|
import { mapsTo, relationship } from "../builders/build-decorators";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
@mapsTo(Bundle)
|
@mapsTo(Bundle)
|
||||||
@inheritSerialization(NormalizedDSpaceObject)
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
@@ -11,7 +11,7 @@ export class NormalizedBundle extends NormalizedDSpaceObject {
|
|||||||
* The primary bitstream of this Bundle
|
* The primary bitstream of this Bundle
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedBitstream)
|
@relationship(ResourceType.Bitstream)
|
||||||
primaryBitstream: string;
|
primaryBitstream: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,6 +25,6 @@ export class NormalizedBundle extends NormalizedDSpaceObject {
|
|||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedBitstream)
|
@relationship(ResourceType.Bitstream)
|
||||||
bitstreams: Array<string>;
|
bitstreams: Array<string>;
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization, autoserializeAs } from "cerialize"
|
|||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Collection } from "../../shared/collection.model";
|
import { Collection } from "../../shared/collection.model";
|
||||||
import { mapsTo, relationship } from "../builders/build-decorators";
|
import { mapsTo, relationship } from "../builders/build-decorators";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
@mapsTo(Collection)
|
@mapsTo(Collection)
|
||||||
@inheritSerialization(NormalizedDSpaceObject)
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
@@ -30,7 +30,7 @@ export class NormalizedCollection extends NormalizedDSpaceObject {
|
|||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedItem)
|
@relationship(ResourceType.Item)
|
||||||
items: Array<string>;
|
items: Array<string>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization, autoserializeAs } from "cerialize"
|
|||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Community } from "../../shared/community.model";
|
import { Community } from "../../shared/community.model";
|
||||||
import { mapsTo, relationship } from "../builders/build-decorators";
|
import { mapsTo, relationship } from "../builders/build-decorators";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
@mapsTo(Community)
|
@mapsTo(Community)
|
||||||
@inheritSerialization(NormalizedDSpaceObject)
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
@@ -30,7 +30,7 @@ export class NormalizedCommunity extends NormalizedDSpaceObject {
|
|||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedCollection)
|
@relationship(ResourceType.Collection)
|
||||||
collections: Array<string>;
|
collections: Array<string>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
export enum NormalizedDSOType {
|
|
||||||
NormalizedBitstream,
|
|
||||||
NormalizedBundle,
|
|
||||||
NormalizedItem,
|
|
||||||
NormalizedCollection,
|
|
||||||
NormalizedCommunity
|
|
||||||
}
|
|
@@ -1,6 +1,7 @@
|
|||||||
import { autoserialize, autoserializeAs } from "cerialize";
|
import { autoserialize, autoserializeAs } from "cerialize";
|
||||||
import { CacheableObject } from "../object-cache.reducer";
|
import { CacheableObject } from "../object-cache.reducer";
|
||||||
import { Metadatum } from "../../shared/metadatum.model";
|
import { Metadatum } from "../../shared/metadatum.model";
|
||||||
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* An abstract model class for a DSpaceObject.
|
||||||
@@ -26,7 +27,7 @@ export abstract class NormalizedDSpaceObject implements CacheableObject {
|
|||||||
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
type: string;
|
type: ResourceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name for this DSpaceObject
|
* The name for this DSpaceObject
|
||||||
@@ -49,5 +50,6 @@ export abstract class NormalizedDSpaceObject implements CacheableObject {
|
|||||||
/**
|
/**
|
||||||
* The DSpaceObject that owns this DSpaceObject
|
* The DSpaceObject that owns this DSpaceObject
|
||||||
*/
|
*/
|
||||||
|
@autoserialize
|
||||||
owner: string;
|
owner: string;
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import { inheritSerialization, autoserialize } from "cerialize";
|
|||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Item } from "../../shared/item.model";
|
import { Item } from "../../shared/item.model";
|
||||||
import { mapsTo, relationship } from "../builders/build-decorators";
|
import { mapsTo, relationship } from "../builders/build-decorators";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
@mapsTo(Item)
|
@mapsTo(Item)
|
||||||
@inheritSerialization(NormalizedDSpaceObject)
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
@@ -33,7 +33,7 @@ export class NormalizedItem extends NormalizedDSpaceObject {
|
|||||||
* An array of Collections that are direct parents of this Item
|
* An array of Collections that are direct parents of this Item
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedCollection)
|
@relationship(ResourceType.Collection)
|
||||||
parents: Array<string>;
|
parents: Array<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,6 +42,6 @@ export class NormalizedItem extends NormalizedDSpaceObject {
|
|||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedBundle)
|
@relationship(ResourceType.Bundle)
|
||||||
bundles: Array<string>;
|
bundles: Array<string>;
|
||||||
}
|
}
|
||||||
|
@@ -4,25 +4,25 @@ import { NormalizedBundle } from "./normalized-bundle.model";
|
|||||||
import { NormalizedItem } from "./normalized-item.model";
|
import { NormalizedItem } from "./normalized-item.model";
|
||||||
import { NormalizedCollection } from "./normalized-collection.model";
|
import { NormalizedCollection } from "./normalized-collection.model";
|
||||||
import { GenericConstructor } from "../../shared/generic-constructor";
|
import { GenericConstructor } from "../../shared/generic-constructor";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
|
||||||
import { NormalizedCommunity } from "./normalized-community.model";
|
import { NormalizedCommunity } from "./normalized-community.model";
|
||||||
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
export class NormalizedDSOFactory {
|
export class NormalizedObjectFactory {
|
||||||
public static getConstructor(type: NormalizedDSOType): GenericConstructor<NormalizedDSpaceObject> {
|
public static getConstructor(type: ResourceType): GenericConstructor<NormalizedDSpaceObject> {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NormalizedDSOType.NormalizedBitstream: {
|
case ResourceType.Bitstream: {
|
||||||
return NormalizedBitstream
|
return NormalizedBitstream
|
||||||
}
|
}
|
||||||
case NormalizedDSOType.NormalizedBundle: {
|
case ResourceType.Bundle: {
|
||||||
return NormalizedBundle
|
return NormalizedBundle
|
||||||
}
|
}
|
||||||
case NormalizedDSOType.NormalizedItem: {
|
case ResourceType.Item: {
|
||||||
return NormalizedItem
|
return NormalizedItem
|
||||||
}
|
}
|
||||||
case NormalizedDSOType.NormalizedCollection: {
|
case ResourceType.Collection: {
|
||||||
return NormalizedCollection
|
return NormalizedCollection
|
||||||
}
|
}
|
||||||
case NormalizedDSOType.NormalizedCommunity: {
|
case ResourceType.Community: {
|
||||||
return NormalizedCommunity
|
return NormalizedCommunity
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
6
src/app/core/cache/response-cache.models.ts
vendored
6
src/app/core/cache/response-cache.models.ts
vendored
@@ -9,8 +9,12 @@ export class SuccessResponse extends Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ErrorResponse extends Response {
|
export class ErrorResponse extends Response {
|
||||||
constructor(public errorMessage: string) {
|
errorMessage: string;
|
||||||
|
|
||||||
|
constructor(error: Error) {
|
||||||
super(false);
|
super(false);
|
||||||
|
console.error(error);
|
||||||
|
this.errorMessage = error.message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,11 +33,8 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
|
|||||||
|
|
||||||
findAll(scopeID?: string): RemoteData<Array<TDomain>> {
|
findAll(scopeID?: string): RemoteData<Array<TDomain>> {
|
||||||
const href = this.getFindAllHref(scopeID);
|
const href = this.getFindAllHref(scopeID);
|
||||||
if (!this.responseCache.has(href) && !this.requestService.isPending(href)) {
|
const request = new FindAllRequest(href, scopeID);
|
||||||
const request = new FindAllRequest(href, this.normalizedResourceType, scopeID);
|
this.requestService.configure(request);
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
|
||||||
}
|
|
||||||
return this.rdbService.buildList<TNormalized, TDomain>(href, this.normalizedResourceType);
|
return this.rdbService.buildList<TNormalized, TDomain>(href, this.normalizedResourceType);
|
||||||
// return this.rdbService.buildList(href);
|
// return this.rdbService.buildList(href);
|
||||||
}
|
}
|
||||||
@@ -48,21 +45,14 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
|
|||||||
|
|
||||||
findById(id: string): RemoteData<TDomain> {
|
findById(id: string): RemoteData<TDomain> {
|
||||||
const href = this.getFindByIDHref(id);
|
const href = this.getFindByIDHref(id);
|
||||||
if (!this.objectCache.hasBySelfLink(href) && !this.requestService.isPending(href)) {
|
const request = new FindByIDRequest(href, id);
|
||||||
const request = new FindByIDRequest(href, this.normalizedResourceType, id);
|
this.requestService.configure(request);
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
|
||||||
}
|
|
||||||
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
||||||
// return this.rdbService.buildSingle(href);
|
// return this.rdbService.buildSingle(href);
|
||||||
}
|
}
|
||||||
|
|
||||||
findByHref(href: string): RemoteData<TDomain> {
|
findByHref(href: string): RemoteData<TDomain> {
|
||||||
if (!this.objectCache.hasBySelfLink(href) && !this.requestService.isPending(href)) {
|
this.requestService.configure(new Request(href));
|
||||||
const request = new Request(href, this.normalizedResourceType);
|
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
|
||||||
}
|
|
||||||
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
||||||
// return this.rdbService.buildSingle(href));
|
// return this.rdbService.buildSingle(href));
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ import { DSpaceRESTv2Serializer } from "../dspace-rest-v2/dspace-rest-v2.seriali
|
|||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { Response, SuccessResponse, ErrorResponse } from "../cache/response-cache.models";
|
import { Response, SuccessResponse, ErrorResponse } from "../cache/response-cache.models";
|
||||||
import { hasNoValue } from "../../shared/empty.util";
|
import { hasNoValue, hasValue, isEmpty, isNotEmpty } from "../../shared/empty.util";
|
||||||
import { GlobalConfig, GLOBAL_CONFIG } from "../../../config";
|
import { GlobalConfig, GLOBAL_CONFIG } from "../../../config";
|
||||||
import { RequestState, RequestEntry } from "./request.reducer";
|
import { RequestState, RequestEntry } from "./request.reducer";
|
||||||
import {
|
import {
|
||||||
@@ -17,6 +17,12 @@ import {
|
|||||||
} from "./request.actions";
|
} from "./request.actions";
|
||||||
import { ResponseCacheService } from "../cache/response-cache.service";
|
import { ResponseCacheService } from "../cache/response-cache.service";
|
||||||
import { RequestService } from "./request.service";
|
import { RequestService } from "./request.service";
|
||||||
|
import { NormalizedObjectFactory } from "../cache/models/normalized-object-factory";
|
||||||
|
import { ResourceType } from "../shared/resource-type";
|
||||||
|
|
||||||
|
function isObjectLevel(halObj: any) {
|
||||||
|
return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RequestEffects {
|
export class RequestEffects {
|
||||||
@@ -38,30 +44,87 @@ export class RequestEffects {
|
|||||||
.take(1);
|
.take(1);
|
||||||
})
|
})
|
||||||
.flatMap((entry: RequestEntry) => {
|
.flatMap((entry: RequestEntry) => {
|
||||||
const [ifArray, ifNotArray] = this.restApi.get(entry.request.href)
|
return this.restApi.get(entry.request.href)
|
||||||
.share() // share ensures restApi.get() doesn't get called twice when the partitions are used below
|
.map((data: DSpaceRESTV2Response) => this.processEmbedded(data._embedded))
|
||||||
.partition((data: DSpaceRESTV2Response) => Array.isArray(data._embedded));
|
.map((ids: Array<string>) => new SuccessResponse(ids))
|
||||||
|
|
||||||
return Observable.merge(
|
|
||||||
|
|
||||||
ifArray.map((data: DSpaceRESTV2Response) => {
|
|
||||||
return new DSpaceRESTv2Serializer(entry.request.resourceType).deserializeArray(data);
|
|
||||||
}).do((cos: CacheableObject[]) => cos.forEach((t) => this.addToObjectCache(t)))
|
|
||||||
.map((cos: Array<CacheableObject>): Array<string> => cos.map(t => t.uuid)),
|
|
||||||
|
|
||||||
ifNotArray.map((data: DSpaceRESTV2Response) => {
|
|
||||||
return new DSpaceRESTv2Serializer(entry.request.resourceType).deserialize(data);
|
|
||||||
}).do((co: CacheableObject) => this.addToObjectCache(co))
|
|
||||||
.map((co: CacheableObject): Array<string> => [co.uuid])
|
|
||||||
|
|
||||||
).map((ids: Array<string>) => new SuccessResponse(ids))
|
|
||||||
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
|
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
|
||||||
.map((response: Response) => new RequestCompleteAction(entry.request.href))
|
.map((response: Response) => new RequestCompleteAction(entry.request.href))
|
||||||
.catch((error: Error) => Observable.of(new ErrorResponse(error.message))
|
.catch((error: Error) => Observable.of(new ErrorResponse(error))
|
||||||
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
|
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
|
||||||
.map((response: Response) => new RequestCompleteAction(entry.request.href)));
|
.map((response: Response) => new RequestCompleteAction(entry.request.href)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
protected processEmbedded(_embedded: any): Array<string> {
|
||||||
|
|
||||||
|
if (isNotEmpty(_embedded)) {
|
||||||
|
if (isObjectLevel(_embedded)) {
|
||||||
|
return this.deserializeAndCache(_embedded);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let uuids = [];
|
||||||
|
Object.keys(_embedded)
|
||||||
|
.filter(property => _embedded.hasOwnProperty(property))
|
||||||
|
.forEach(property => {
|
||||||
|
uuids = [...uuids, ...this.deserializeAndCache(_embedded[property])];
|
||||||
|
});
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected deserializeAndCache(obj): Array<string> {
|
||||||
|
let type: ResourceType;
|
||||||
|
const isArray = Array.isArray(obj);
|
||||||
|
|
||||||
|
if (isArray && isEmpty(obj)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArray) {
|
||||||
|
type = obj[0]["type"];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
type = obj["type"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasValue(type)) {
|
||||||
|
const normObjConstructor = NormalizedObjectFactory.getConstructor(type);
|
||||||
|
|
||||||
|
if (hasValue(normObjConstructor)) {
|
||||||
|
const serializer = new DSpaceRESTv2Serializer(normObjConstructor);
|
||||||
|
|
||||||
|
if (isArray) {
|
||||||
|
obj.forEach(o => {
|
||||||
|
if (isNotEmpty(o._embedded)) {
|
||||||
|
this.processEmbedded(o._embedded);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const normalizedObjArr = serializer.deserializeArray(obj);
|
||||||
|
normalizedObjArr.forEach(t => this.addToObjectCache(t));
|
||||||
|
return normalizedObjArr.map(t => t.uuid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isNotEmpty(obj._embedded)) {
|
||||||
|
this.processEmbedded(obj._embedded);
|
||||||
|
}
|
||||||
|
const normalizedObj = serializer.deserialize(obj);
|
||||||
|
this.addToObjectCache(normalizedObj);
|
||||||
|
return [normalizedObj.uuid];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//TODO move check to Validator?
|
||||||
|
throw new Error(`The server returned an object with an unknown a known type: ${type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//TODO move check to Validator
|
||||||
|
throw new Error(`The server returned an object without a type: ${JSON.stringify(obj)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected addToObjectCache(co: CacheableObject): void {
|
protected addToObjectCache(co: CacheableObject): void {
|
||||||
if (hasNoValue(co) || hasNoValue(co.uuid)) {
|
if (hasNoValue(co) || hasNoValue(co.uuid)) {
|
||||||
throw new Error('The server returned an invalid object');
|
throw new Error('The server returned an invalid object');
|
||||||
|
@@ -5,28 +5,25 @@ import { GenericConstructor } from "../shared/generic-constructor";
|
|||||||
export class Request<T> {
|
export class Request<T> {
|
||||||
constructor(
|
constructor(
|
||||||
public href: string,
|
public href: string,
|
||||||
public resourceType: GenericConstructor<T>
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FindByIDRequest<T> extends Request<T> {
|
export class FindByIDRequest<T> extends Request<T> {
|
||||||
constructor(
|
constructor(
|
||||||
href: string,
|
href: string,
|
||||||
resourceType: GenericConstructor<T>,
|
|
||||||
public resourceID: string
|
public resourceID: string
|
||||||
) {
|
) {
|
||||||
super(href, resourceType);
|
super(href);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FindAllRequest<T> extends Request<T> {
|
export class FindAllRequest<T> extends Request<T> {
|
||||||
constructor(
|
constructor(
|
||||||
href: string,
|
href: string,
|
||||||
resourceType: GenericConstructor<T>,
|
|
||||||
public scopeID?: string,
|
public scopeID?: string,
|
||||||
public paginationOptions?: PaginationOptions,
|
public paginationOptions?: PaginationOptions,
|
||||||
public sortOptions?: SortOptions
|
public sortOptions?: SortOptions
|
||||||
) {
|
) {
|
||||||
super(href, resourceType);
|
super(href);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,6 @@ import { RequestConfigureAction, RequestExecuteAction } from "./request.actions"
|
|||||||
import { ResponseCacheService } from "../cache/response-cache.service";
|
import { ResponseCacheService } from "../cache/response-cache.service";
|
||||||
import { ObjectCacheService } from "../cache/object-cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { GenericConstructor } from "../shared/generic-constructor";
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RequestService {
|
export class RequestService {
|
||||||
@@ -35,14 +34,13 @@ export class RequestService {
|
|||||||
return this.store.select<RequestEntry>('core', 'data', 'request', href);
|
return this.store.select<RequestEntry>('core', 'data', 'request', href);
|
||||||
}
|
}
|
||||||
|
|
||||||
configure<T extends CacheableObject>(href: string, normalizedType: GenericConstructor<T>): void {
|
configure<T extends CacheableObject>(request: Request<T>): void {
|
||||||
const isCached = this.objectCache.hasBySelfLink(href);
|
const isCached = this.objectCache.hasBySelfLink(request.href);
|
||||||
const isPending = this.isPending(href);
|
const isPending = this.isPending(request.href);
|
||||||
|
|
||||||
if (!(isCached || isPending)) {
|
if (!(isCached || isPending)) {
|
||||||
const request = new Request(href, normalizedType);
|
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
this.store.dispatch(new RequestConfigureAction(request));
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
this.store.dispatch(new RequestExecuteAction(request.href));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -84,14 +84,10 @@ describe("DSpaceRESTv2Serializer", () => {
|
|||||||
|
|
||||||
it("should turn a valid document describing a single entity in to a valid model", () => {
|
it("should turn a valid document describing a single entity in to a valid model", () => {
|
||||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||||
const doc = {
|
const model = serializer.deserialize(testResponses[0]);
|
||||||
"_embedded": testResponses[0],
|
|
||||||
};
|
|
||||||
|
|
||||||
const model = serializer.deserialize(doc);
|
expect(model.id).toBe(testResponses[0].id);
|
||||||
|
expect(model.name).toBe(testResponses[0].name);
|
||||||
expect(model.id).toBe(doc._embedded.id);
|
|
||||||
expect(model.name).toBe(doc._embedded.name);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO cant implement/test this yet - depends on how relationships
|
//TODO cant implement/test this yet - depends on how relationships
|
||||||
@@ -127,12 +123,8 @@ describe("DSpaceRESTv2Serializer", () => {
|
|||||||
|
|
||||||
it("should throw an error when dealing with a document describing an array", () => {
|
it("should throw an error when dealing with a document describing an array", () => {
|
||||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||||
const doc = {
|
|
||||||
"_embedded": testResponses
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
serializer.deserialize(doc);
|
serializer.deserialize(testResponses);
|
||||||
}).toThrow();
|
}).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@ import { Serializer } from "../serializer";
|
|||||||
import { DSpaceRESTV2Response } from "./dspace-rest-v2-response.model";
|
import { DSpaceRESTV2Response } from "./dspace-rest-v2-response.model";
|
||||||
import { DSpaceRESTv2Validator } from "./dspace-rest-v2.validator";
|
import { DSpaceRESTv2Validator } from "./dspace-rest-v2.validator";
|
||||||
import { GenericConstructor } from "../shared/generic-constructor";
|
import { GenericConstructor } from "../shared/generic-constructor";
|
||||||
|
import { hasNoValue, hasValue } from "../../shared/empty.util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Serializer turns responses from v2 of DSpace's REST API
|
* This Serializer turns responses from v2 of DSpace's REST API
|
||||||
@@ -49,13 +50,13 @@ export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
|
|||||||
* @param response An object returned by the backend
|
* @param response An object returned by the backend
|
||||||
* @returns a model of type T
|
* @returns a model of type T
|
||||||
*/
|
*/
|
||||||
deserialize(response: DSpaceRESTV2Response): T {
|
deserialize(response: any): T {
|
||||||
// TODO enable validation, once rest data stabilizes
|
// TODO enable validation, once rest data stabilizes
|
||||||
// new DSpaceRESTv2Validator(response).validate();
|
// new DSpaceRESTv2Validator(response).validate();
|
||||||
if (Array.isArray(response._embedded)) {
|
if (Array.isArray(response)) {
|
||||||
throw new Error('Expected a single model, use deserializeArray() instead');
|
throw new Error('Expected a single model, use deserializeArray() instead');
|
||||||
}
|
}
|
||||||
let normalized = Object.assign({}, response._embedded, this.normalizeLinks(response._embedded._links));
|
let normalized = Object.assign({}, response, this.normalizeLinks(response._links));
|
||||||
return <T> Deserialize(normalized, this.modelType);
|
return <T> Deserialize(normalized, this.modelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,13 +66,13 @@ export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
|
|||||||
* @param response An object returned by the backend
|
* @param response An object returned by the backend
|
||||||
* @returns an array of models of type T
|
* @returns an array of models of type T
|
||||||
*/
|
*/
|
||||||
deserializeArray(response: DSpaceRESTV2Response): Array<T> {
|
deserializeArray(response: any): Array<T> {
|
||||||
//TODO enable validation, once rest data stabilizes
|
//TODO enable validation, once rest data stabilizes
|
||||||
// new DSpaceRESTv2Validator(response).validate();
|
// new DSpaceRESTv2Validator(response).validate();
|
||||||
if (!Array.isArray(response._embedded)) {
|
if (!Array.isArray(response)) {
|
||||||
throw new Error('Expected an Array, use deserialize() instead');
|
throw new Error('Expected an Array, use deserialize() instead');
|
||||||
}
|
}
|
||||||
let normalized = response._embedded.map((resource) => {
|
let normalized = response.map((resource) => {
|
||||||
return Object.assign({}, resource, this.normalizeLinks(resource._links));
|
return Object.assign({}, resource, this.normalizeLinks(resource._links));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@ import { Metadatum } from "./metadatum.model"
|
|||||||
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
|
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
|
||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { RemoteData } from "../data/remote-data";
|
import { RemoteData } from "../data/remote-data";
|
||||||
|
import { ResourceType } from "./resource-type";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* An abstract model class for a DSpaceObject.
|
||||||
@@ -23,7 +24,7 @@ export abstract class DSpaceObject implements CacheableObject {
|
|||||||
/**
|
/**
|
||||||
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
||||||
*/
|
*/
|
||||||
type: string;
|
type: ResourceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name for this DSpaceObject
|
* The name for this DSpaceObject
|
||||||
|
11
src/app/core/shared/resource-type.ts
Normal file
11
src/app/core/shared/resource-type.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* TODO replace with actual string enum after upgrade to TypeScript 2.4:
|
||||||
|
* https://github.com/Microsoft/TypeScript/pull/15486
|
||||||
|
*/
|
||||||
|
export enum ResourceType {
|
||||||
|
Bundle = <any> "bundle",
|
||||||
|
Bitstream = <any> "bitstream",
|
||||||
|
Item = <any> "item",
|
||||||
|
Collection = <any> "collection",
|
||||||
|
Community = <any> "community"
|
||||||
|
}
|
@@ -82,7 +82,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.community_id;
|
let id = req.params.community_id;
|
||||||
try {
|
try {
|
||||||
req.community_id = id;
|
req.community_id = id;
|
||||||
req.community = COMMUNITIES.find((community) => {
|
req.community = COMMUNITIES["communities"].find((community) => {
|
||||||
return community.id === id;
|
return community.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -143,7 +143,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.collection_id;
|
let id = req.params.collection_id;
|
||||||
try {
|
try {
|
||||||
req.collection_id = id;
|
req.collection_id = id;
|
||||||
req.collection = COLLECTIONS.find((collection) => {
|
req.collection = COLLECTIONS["collections"].find((collection) => {
|
||||||
return collection.id === id;
|
return collection.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -205,7 +205,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.item_id;
|
let id = req.params.item_id;
|
||||||
try {
|
try {
|
||||||
req.item_id = id;
|
req.item_id = id;
|
||||||
req.item = ITEMS.find((item) => {
|
req.item = ITEMS["items"].find((item) => {
|
||||||
return item.id === id;
|
return item.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -250,7 +250,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.bundle_id;
|
let id = req.params.bundle_id;
|
||||||
try {
|
try {
|
||||||
req.bundle_id = id;
|
req.bundle_id = id;
|
||||||
req.bundle = BUNDLES.find((bundle) => {
|
req.bundle = BUNDLES["bundles"].find((bundle) => {
|
||||||
return bundle.id === id;
|
return bundle.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -280,7 +280,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.bitstream_id;
|
let id = req.params.bitstream_id;
|
||||||
try {
|
try {
|
||||||
req.bitstream_id = id;
|
req.bitstream_id = id;
|
||||||
req.bitstream = BITSTREAMS.find((bitstream) => {
|
req.bitstream = BITSTREAMS["bitstreams"].find((bitstream) => {
|
||||||
return bitstream.id === id;
|
return bitstream.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const BITSTREAMS = [
|
export const BITSTREAMS = {
|
||||||
|
"bitstreams": [
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": { "href": "/bitstreams/3678" },
|
"self": { "href": "/bitstreams/3678" },
|
||||||
@@ -43,4 +44,5 @@ export const BITSTREAMS = [
|
|||||||
"format": "JPEG",
|
"format": "JPEG",
|
||||||
"mimetype": "image/jpeg"
|
"mimetype": "image/jpeg"
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const BUNDLES = [
|
export const BUNDLES = {
|
||||||
|
"bundles": [
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": { "href": "/bundles/2355" },
|
"self": { "href": "/bundles/2355" },
|
||||||
@@ -37,4 +38,5 @@ export const BUNDLES = [
|
|||||||
{ "key": "dc.title", "value": "THUMBNAIL", "language": "en" }
|
{ "key": "dc.title", "value": "THUMBNAIL", "language": "en" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const COLLECTIONS = [
|
export const COLLECTIONS = {
|
||||||
|
"collections": [
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": { "href": "/collections/5179" },
|
"self": { "href": "/collections/5179" },
|
||||||
@@ -71,4 +72,5 @@ export const COLLECTIONS = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const COMMUNITIES = [
|
export const COMMUNITIES = {
|
||||||
|
"communities": [
|
||||||
{
|
{
|
||||||
"name": "Community 1",
|
"name": "Community 1",
|
||||||
"handle": "10673/1",
|
"handle": "10673/1",
|
||||||
@@ -83,4 +84,5 @@ export const COMMUNITIES = [
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const ITEMS = [
|
export const ITEMS = {
|
||||||
|
"items": [
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": {
|
"self": {
|
||||||
@@ -90,8 +91,87 @@ export const ITEMS = [
|
|||||||
"value": "(not specified)",
|
"value": "(not specified)",
|
||||||
"language": "en"
|
"language": "en"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"_embedded": {
|
||||||
|
"parents": [
|
||||||
|
{
|
||||||
|
"_links": {
|
||||||
|
"self": { "href": "/collections/5179" },
|
||||||
|
"items": [
|
||||||
|
{ "href": "/items/8871" },
|
||||||
|
{ "href": "/items/9978" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"id": "5179",
|
||||||
|
"uuid": "9e32a2e2-6b91-4236-a361-995ccdc14c60",
|
||||||
|
"type": "collection",
|
||||||
|
"name": "A Test Collection",
|
||||||
|
"handle": "123456789/5179",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_links": {
|
||||||
|
"self": { "href": "/collections/6547" },
|
||||||
|
"items": [
|
||||||
|
{ "href": "/items/8871" },
|
||||||
|
{ "href": "/items/9978" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"id": "6547",
|
||||||
|
"uuid": "598ce822-c357-46f3-ab70-63724d02d6ad",
|
||||||
|
"type": "collection",
|
||||||
|
"name": "Another Test Collection",
|
||||||
|
"handle": "123456789/6547",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bundles": [
|
||||||
|
{
|
||||||
|
"_links": {
|
||||||
|
"self": { "href": "/bundles/2355" },
|
||||||
|
"items": [
|
||||||
|
{ "href": "/items/8871" }
|
||||||
|
],
|
||||||
|
"bitstreams": [
|
||||||
|
{ "href": "/bitstreams/3678" },
|
||||||
|
],
|
||||||
|
"primaryBitstream": { "href": "/bitstreams/3678" }
|
||||||
|
},
|
||||||
|
"id": "2355",
|
||||||
|
"uuid": "35e0606d-5e18-4f9c-aa61-74fc751cc3f9",
|
||||||
|
"type": "bundle",
|
||||||
|
"name": "ORIGINAL",
|
||||||
|
"metadata": [
|
||||||
|
{ "key": "dc.title", "value": "ORIGINAL", "language": "en" }
|
||||||
|
],
|
||||||
|
"_embedded": {
|
||||||
|
"bitstreams": [
|
||||||
|
{
|
||||||
|
"_links": {
|
||||||
|
"self": { "href": "/bitstreams/3678" },
|
||||||
|
"bundle": { "href": "/bundles/35e0606d-5e18-4f9c-aa61-74fc751cc3f9" },
|
||||||
|
"retrieve": { "href": "/bitstreams/43c57c2b-206f-4645-8c8f-5f10c84b09fa/retrieve" }
|
||||||
|
},
|
||||||
|
"id": "3678",
|
||||||
|
"uuid": "43c57c2b-206f-4645-8c8f-5f10c84b09fa",
|
||||||
|
"type": "bitstream",
|
||||||
|
"name": "do_open_access_CRL.pdf",
|
||||||
|
"size": 636626,
|
||||||
|
"checksum": {
|
||||||
|
"value": "063dfbbbac873aa3fca479b878eccff3",
|
||||||
|
"algorithm": "MD5"
|
||||||
|
},
|
||||||
|
"metadata": [
|
||||||
|
{ "key": "dc.title", "value": "do_open_access_CRL.pdf", "language": null },
|
||||||
|
{ "key": "dc.description", "value": "Conference Paper", "language": "en" }
|
||||||
|
],
|
||||||
|
"format": "Adobe PDF",
|
||||||
|
"mimetype": "application/pdf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": {
|
"self": {
|
||||||
@@ -163,6 +243,39 @@ export const ITEMS = [
|
|||||||
"value": "(not specified)",
|
"value": "(not specified)",
|
||||||
"language": "en"
|
"language": "en"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"_embedded": {
|
||||||
|
"parents": [
|
||||||
|
{
|
||||||
|
"_links": {
|
||||||
|
"self": { "href": "/collections/5179" },
|
||||||
|
"items": [
|
||||||
|
{ "href": "/items/8871" },
|
||||||
|
{ "href": "/items/9978" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"id": "5179",
|
||||||
|
"uuid": "9e32a2e2-6b91-4236-a361-995ccdc14c60",
|
||||||
|
"type": "collection",
|
||||||
|
"name": "A Test Collection",
|
||||||
|
"handle": "123456789/5179",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_links": {
|
||||||
|
"self": { "href": "/collections/6547" },
|
||||||
|
"items": [
|
||||||
|
{ "href": "/items/8871" },
|
||||||
|
{ "href": "/items/9978" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"id": "6547",
|
||||||
|
"uuid": "598ce822-c357-46f3-ab70-63724d02d6ad",
|
||||||
|
"type": "collection",
|
||||||
|
"name": "Another Test Collection",
|
||||||
|
"handle": "123456789/6547",
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const METADATA = [
|
export const METADATA = {
|
||||||
|
"metadata": [
|
||||||
{
|
{
|
||||||
"type": "metadata",
|
"type": "metadata",
|
||||||
"id": "d58a3098-b390-4cd6-8f52-b088b3daa637",
|
"id": "d58a3098-b390-4cd6-8f52-b088b3daa637",
|
||||||
@@ -179,4 +180,5 @@ export const METADATA = [
|
|||||||
"language": "en"
|
"language": "en"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user