Skip to content

Commit

Permalink
Merge pull request #509 from atmire/w2p-65572_Add-support-for-bundles
Browse files Browse the repository at this point in the history
Add support for bundles
  • Loading branch information
tdonohue committed Nov 21, 2019
2 parents 0f4c905 + ed3f7df commit 536ecbb
Show file tree
Hide file tree
Showing 67 changed files with 278 additions and 198 deletions.
2 changes: 1 addition & 1 deletion src/app/+item-page/full/full-item-page.component.spec.ts
Expand Up @@ -23,7 +23,7 @@ import {
} from '../../shared/testing/utils';

const mockItem: Item = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -50,7 +50,7 @@ describe('ItemPageFieldComponent', () => {

export function mockItemWithMetadataFieldAndValue(field: string, value: string): Item {
const item = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: new MetadataMap()
});
item.metadata[field] = [{
Expand Down
2 changes: 1 addition & 1 deletion src/app/+item-page/simple/item-page.component.spec.ts
Expand Up @@ -22,7 +22,7 @@ import {
} from '../../shared/testing/utils';

const mockItem: Item = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [],
relationships: createRelationshipsObservable()
});
Expand Down
Expand Up @@ -17,7 +17,7 @@ import { MetadataMap } from '../../../../core/shared/metadata.models';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';

const mockItem: Item = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: new MetadataMap(),
relationships: createRelationshipsObservable()
});
Expand Down
Expand Up @@ -11,17 +11,17 @@ import { RelationshipService } from '../../../core/data/relationship.service';
import { TranslateModule } from '@ngx-translate/core';

const parentItem: Item = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [],
relationships: createRelationshipsObservable()
});
const mockItem1: Item = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [],
relationships: createRelationshipsObservable()
});
const mockItem2: Item = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [],
relationships: createRelationshipsObservable()
});
Expand Down
7 changes: 7 additions & 0 deletions src/app/core/cache/models/normalized-bundle.model.ts
Expand Up @@ -11,6 +11,13 @@ import { Bitstream } from '../../shared/bitstream.model';
@mapsTo(Bundle)
@inheritSerialization(NormalizedDSpaceObject)
export class NormalizedBundle extends NormalizedDSpaceObject<Bundle> {

/**
* The bundle's name
*/
@autoserialize
name: string;

/**
* The primary bitstream of this Bundle
*/
Expand Down
10 changes: 3 additions & 7 deletions src/app/core/cache/models/normalized-item.model.ts
Expand Up @@ -3,13 +3,9 @@ import { inheritSerialization, deserialize, autoserialize, autoserializeAs } fro
import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
import { Item } from '../../shared/item.model';
import { mapsTo, relationship } from '../builders/build-decorators';
import { ResourceType } from '../../shared/resource-type';
import { NormalizedCollection } from './normalized-collection.model';
import { NormalizedBitstream } from './normalized-bitstream.model';
import { NormalizedRelationship } from './items/normalized-relationship.model';
import { Collection } from '../../shared/collection.model';
import { Bitstream } from '../../shared/bitstream.model';
import { Relationship } from '../../shared/item-relationships/relationship.model';
import { Bundle } from '../../shared/bundle.model';

/**
* Normalized model class for a DSpace Item
Expand Down Expand Up @@ -66,8 +62,8 @@ export class NormalizedItem extends NormalizedDSpaceObject<Item> {
* List of Bitstreams that are owned by this Item
*/
@deserialize
@relationship(Bitstream, true)
bitstreams: string[];
@relationship(Bundle, true)
bundles: string[];

@autoserialize
@relationship(Relationship, true)
Expand Down
46 changes: 46 additions & 0 deletions src/app/core/data/bundle-data.service.ts
@@ -0,0 +1,46 @@
import { Injectable } from '@angular/core';
import { DataService } from './data.service';
import { Bundle } from '../shared/bundle.model';
import { RequestService } from './request.service';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
import { Store } from '@ngrx/store';
import { CoreState } from '../core.reducers';
import { ObjectCacheService } from '../cache/object-cache.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { HttpClient } from '@angular/common/http';
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
import { FindAllOptions } from './request.models';
import { Observable } from 'rxjs/internal/Observable';

/**
* A service responsible for fetching/sending data from/to the REST API on the bundles endpoint
*/
@Injectable()
export class BundleDataService extends DataService<Bundle> {
protected linkPath = 'bundles';
protected forceBypassCache = false;

constructor(
protected requestService: RequestService,
protected rdbService: RemoteDataBuildService,
protected dataBuildService: NormalizedObjectBuildService,
protected store: Store<CoreState>,
protected objectCache: ObjectCacheService,
protected halService: HALEndpointService,
protected notificationsService: NotificationsService,
protected http: HttpClient,
protected comparator: DefaultChangeAnalyzer<Bundle>) {
super();
}

/**
* Get the endpoint for browsing bundles
* @param {FindAllOptions} options
* @returns {Observable<string>}
*/
getBrowseEndpoint(options: FindAllOptions = {}, linkPath?: string): Observable<string> {
return this.halService.getEndpoint(this.linkPath);
}
}
11 changes: 10 additions & 1 deletion src/app/core/shared/bundle.model.ts
Expand Up @@ -4,10 +4,16 @@ import { Item } from './item.model';
import { RemoteData } from '../data/remote-data';
import { Observable } from 'rxjs';
import { ResourceType } from './resource-type';
import { PaginatedList } from '../data/paginated-list';

export class Bundle extends DSpaceObject {
static type = new ResourceType('bundle');

/**
* The bundle's name
*/
name: string;

/**
* The primary bitstream of this Bundle
*/
Expand All @@ -23,6 +29,9 @@ export class Bundle extends DSpaceObject {
*/
owner: Observable<RemoteData<Item>>;

bitstreams: Observable<RemoteData<Bitstream[]>>
/**
* List of Bitstreams that are part of this Bundle
*/
bitstreams: Observable<RemoteData<PaginatedList<Bitstream>>>;

}
16 changes: 10 additions & 6 deletions src/app/core/shared/item.model.spec.ts
Expand Up @@ -4,7 +4,7 @@ import { Item } from './item.model';
import { Bitstream } from './bitstream.model';
import { isEmpty } from '../../shared/empty.util';
import { first, map } from 'rxjs/operators';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';

describe('Item', () => {

Expand All @@ -18,8 +18,9 @@ describe('Item', () => {
const nonExistingBundleName = 'c1e568f7-d14e-496b-bdd7-07026998cc00';
let bitstreams;
let remoteDataThumbnail;
let remoteDataThumbnailList;
let remoteDataFiles;
let remoteDataAll;
let remoteDataBundles;

beforeEach(() => {
const thumbnail = {
Expand All @@ -33,23 +34,26 @@ describe('Item', () => {
}];

remoteDataThumbnail = createSuccessfulRemoteDataObject$(thumbnail);
remoteDataFiles = createSuccessfulRemoteDataObject$(bitstreams);
remoteDataAll = createSuccessfulRemoteDataObject$([...bitstreams, thumbnail]);
remoteDataThumbnailList = createSuccessfulRemoteDataObject$(createPaginatedList([thumbnail]));
remoteDataFiles = createSuccessfulRemoteDataObject$(createPaginatedList(bitstreams));

// Create Bundles
const bundles =
[
{
name: thumbnailBundleName,
primaryBitstream: remoteDataThumbnail
primaryBitstream: remoteDataThumbnail,
bitstreams: remoteDataThumbnailList
},

{
name: originalBundleName,
bitstreams: remoteDataFiles
}];

item = Object.assign(new Item(), { bitstreams: remoteDataAll });
remoteDataBundles = createSuccessfulRemoteDataObject$(createPaginatedList(bundles));

item = Object.assign(new Item(), { bundles: remoteDataBundles });
});

it('should return the bitstreams related to this item with the specified bundle name', () => {
Expand Down
28 changes: 15 additions & 13 deletions src/app/core/shared/item.model.ts
@@ -1,15 +1,16 @@
import { map, startWith, filter, take } from 'rxjs/operators';
import { map, startWith, filter, switchMap } from 'rxjs/operators';
import { Observable } from 'rxjs';

import { DSpaceObject } from './dspace-object.model';
import { Collection } from './collection.model';
import { RemoteData } from '../data/remote-data';
import { Bitstream } from './bitstream.model';
import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
import { hasValueOperator, isNotEmpty, isEmpty } from '../../shared/empty.util';
import { PaginatedList } from '../data/paginated-list';
import { Relationship } from './item-relationships/relationship.model';
import { ResourceType } from './resource-type';
import { getSucceededRemoteData } from './operators';
import { getAllSucceededRemoteData, getSucceededRemoteData } from './operators';
import { Bundle } from './bundle.model';
import { GenericConstructor } from './generic-constructor';
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
import { DEFAULT_ENTITY_TYPE } from '../../shared/metadata-representation/metadata-representation.decorator';
Expand Down Expand Up @@ -59,7 +60,10 @@ export class Item extends DSpaceObject {
return this.owningCollection;
}

bitstreams: Observable<RemoteData<PaginatedList<Bitstream>>>;
/**
* Bitstream bundles within this item
*/
bundles: Observable<RemoteData<PaginatedList<Bundle>>>;

relationships: Observable<RemoteData<PaginatedList<Relationship>>>;

Expand Down Expand Up @@ -103,17 +107,15 @@ export class Item extends DSpaceObject {
* see https://github.com/DSpace/dspace-angular/issues/332
*/
getBitstreamsByBundleName(bundleName: string): Observable<Bitstream[]> {
return this.bitstreams.pipe(
return this.bundles.pipe(
getSucceededRemoteData(),
map((rd: RemoteData<PaginatedList<Bundle>>) => rd.payload.page.find((bundle: Bundle) => bundle.name === bundleName)),
hasValueOperator(),
switchMap((bundle: Bundle) => bundle.bitstreams),
getAllSucceededRemoteData(),
map((rd: RemoteData<PaginatedList<Bitstream>>) => rd.payload.page),
filter((bitstreams: Bitstream[]) => hasValue(bitstreams)),
take(1),
startWith([]),
map((bitstreams) => {
return bitstreams
.filter((bitstream) => hasValue(bitstream))
.filter((bitstream) => bitstream.bundleName === bundleName)
}));
startWith([])
);
}

/**
Expand Down
Expand Up @@ -12,7 +12,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';

const mockItem = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -12,7 +12,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';

const mockItem = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -12,7 +12,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';

const mockItem = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -9,7 +9,7 @@ import { JournalIssueSearchResultGridElementComponent } from './journal-issue-se
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand All @@ -35,7 +35,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithoutMetadata.hitHighlights = {};
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -9,7 +9,7 @@ import { JournalVolumeSearchResultGridElementComponent } from './journal-volume-
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand All @@ -35,7 +35,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithoutMetadata.hitHighlights = {};
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -9,7 +9,7 @@ import { JournalSearchResultGridElementComponent } from './journal-search-result
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand Down Expand Up @@ -41,7 +41,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithoutMetadata.hitHighlights = {};
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -8,7 +8,7 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';

const mockItem: Item = Object.assign(new Item(), {
bitstreams: observableOf({}),
bundles: observableOf({}),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -8,7 +8,7 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';

const mockItem: Item = Object.assign(new Item(), {
bitstreams: observableOf({}),
bundles: observableOf({}),
metadata: {
'dc.title': [
{
Expand Down
Expand Up @@ -8,7 +8,7 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';

const mockItem: Item = Object.assign(new Item(), {
bitstreams: observableOf({}),
bundles: observableOf({}),
metadata: {
'dc.title': [
{
Expand Down

0 comments on commit 536ecbb

Please sign in to comment.