diff --git a/src/app/core/metadata/metadata.service.spec.ts b/src/app/core/metadata/metadata.service.spec.ts index 18421dd489..0a4377e1b7 100644 --- a/src/app/core/metadata/metadata.service.spec.ts +++ b/src/app/core/metadata/metadata.service.spec.ts @@ -15,11 +15,9 @@ import { RemoteData } from '../data/remote-data'; import { Item } from '../shared/item.model'; import { - ItemMock, - MockBitstream1, - MockBitstream2, - MockBitstreamFormat1, - MockBitstreamFormat2 + ItemMock, MockBitstream1, MockBitstream2, MockBitstream3, MockBitstreamFormat1, MockBitstreamFormat2, + MockBitstreamFormat3, + MockOriginalBundle, } from '../../shared/mocks/item.mock'; import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock'; import { NotificationsService } from '../../shared/notifications/notifications.service'; @@ -51,10 +49,11 @@ import { UUIDService } from '../shared/uuid.service'; import { MetadataService } from './metadata.service'; import { environment } from '../../../environments/environment'; import { storeModuleConfig } from '../../app.reducer'; -import { HardRedirectService } from '../services/hard-redirect.service'; -import { URLCombiner } from '../url-combiner/url-combiner'; import { RootDataService } from '../data/root-data.service'; import { Root } from '../data/root.model'; +import { Bundle } from '../shared/bundle.model'; +import { BundleDataService } from '../data/bundle-data.service'; +import { createPaginatedList } from '../../shared/testing/utils.test'; /* tslint:disable:max-classes-per-file */ @Component({ @@ -92,6 +91,8 @@ describe('MetadataService', () => { let uuidService: UUIDService; let remoteDataBuildService: RemoteDataBuildService; let itemDataService: ItemDataService; + let bundleDataService; + let bitstreamDataService; let authService: AuthService; let rootService: RootDataService; let translateService: TranslateService; @@ -111,7 +112,7 @@ describe('MetadataService', () => { uuidService = new UUIDService(); requestService = new RequestService(objectCacheService, uuidService, store, undefined); remoteDataBuildService = new RemoteDataBuildService(objectCacheService, undefined, requestService); - const mockBitstreamDataService = { + bitstreamDataService = { findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: FollowLinkConfig[]): Observable>> { if (item.equals(ItemMock)) { return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [MockBitstream1, MockBitstream2])); @@ -119,6 +120,7 @@ describe('MetadataService', () => { return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); } }, + findAllByHref: jasmine.createSpy(), }; const mockBitstreamFormatDataService = { findByBitstream(bitstream: Bitstream): Observable> { @@ -129,11 +131,17 @@ describe('MetadataService', () => { case MockBitstream2: return createSuccessfulRemoteDataObject$(MockBitstreamFormat2); break; + case MockBitstream3: + return createSuccessfulRemoteDataObject$(MockBitstreamFormat3); + break; default: return createSuccessfulRemoteDataObject$(new BitstreamFormat()); } } }; + bundleDataService = jasmine.createSpyObj('bundleDataService', { + findByItemAndName: createSuccessfulRemoteDataObject$(MockOriginalBundle), + }); rootService = jasmine.createSpyObj('rootService', { findRoot: createSuccessfulRemoteDataObject$(Object.assign(new Root(), { dspaceVersion: 'mock-dspace-version' @@ -176,7 +184,8 @@ describe('MetadataService', () => { { provide: CommunityDataService, useValue: {} }, { provide: DefaultChangeAnalyzer, useValue: {} }, { provide: BitstreamFormatDataService, useValue: mockBitstreamFormatDataService }, - { provide: BitstreamDataService, useValue: mockBitstreamDataService }, + { provide: BitstreamDataService, useValue: bitstreamDataService }, + { provide: BundleDataService, useValue: bundleDataService }, { provide: RootDataService, useValue: rootService }, Meta, Title, @@ -264,8 +273,42 @@ describe('MetadataService', () => { }); + describe('citation_pdf_url', () => { + it('should link to primary Bitstream URL regardless of format', fakeAsync(() => { + spyOn(itemDataService, 'findById').and.returnValue(mockRemoteData(ItemMock)); + bundleDataService.findByItemAndName.and.returnValue(mockBundleRD$([], MockBitstream3)); + router.navigate(['/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357']); + tick(); + expect(tagStore.get('citation_pdf_url')[0].content).toEqual('/bitstreams/4db100c1-e1f5-4055-9404-9bc3e2d15f29/download'); + })); + + describe('no primary Bitstream', () => { + it('should link to first and only Bitstream regardless of format', fakeAsync(() => { + spyOn(itemDataService, 'findById').and.returnValue(mockRemoteData(ItemMock)); + bundleDataService.findByItemAndName.and.returnValue(mockBundleRD$([MockBitstream3])); + router.navigate(['/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357']); + tick(); + expect(tagStore.get('citation_pdf_url')[0].content).toEqual('/bitstreams/4db100c1-e1f5-4055-9404-9bc3e2d15f29/download'); + })); + + it('should link to first Bitstream with allowed format', fakeAsync(() => { + spyOn(itemDataService, 'findById').and.returnValue(mockRemoteData(ItemMock)); + + const bitstreams = [MockBitstream3, MockBitstream3, MockBitstream1]; + bundleDataService.findByItemAndName.and.returnValue(mockBundleRD$(bitstreams)); + bitstreamDataService.findAllByHref.and.returnValues( + ...mockBitstreamPages$(bitstreams).map(bp => createSuccessfulRemoteDataObject$(bp)), + ); + + router.navigate(['/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357']); + tick(); + expect(tagStore.get('citation_pdf_url')[0].content).toEqual('/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/download'); + })); + }); + }); + const mockRemoteData = (mockItem: Item): Observable> => { - return createSuccessfulRemoteDataObject$(ItemMock); + return createSuccessfulRemoteDataObject$(mockItem); }; const mockType = (mockItem: Item, type: string): Item => { @@ -285,4 +328,24 @@ describe('MetadataService', () => { return publishedMockItem; }; + const mockBundleRD$ = (bitstreams: Bitstream[], primary?: Bitstream): Observable> => { + return createSuccessfulRemoteDataObject$( + Object.assign(new Bundle(), { + name: 'ORIGINAL', + bitstreams: createSuccessfulRemoteDataObject$(mockBitstreamPages$(bitstreams)[0]), + primaryBitstream: createSuccessfulRemoteDataObject$(primary), + }) + ); + }; + + const mockBitstreamPages$ = (bitstreams: Bitstream[]): PaginatedList[] => { + return bitstreams.map((bitstream, index) => Object.assign(createPaginatedList([bitstream]), { + pageInfo: { + totalElements: bitstreams.length, // announce multiple elements/pages + }, + _links: index < bitstreams.length - 1 + ? { next: { href: 'not empty' }} // fake link to the next bitstream page + : { next: { href: undefined }}, // last page has no link + })); + }; }); diff --git a/src/app/core/metadata/metadata.service.ts b/src/app/core/metadata/metadata.service.ts index 0b63e13976..848b48b8c5 100644 --- a/src/app/core/metadata/metadata.service.ts +++ b/src/app/core/metadata/metadata.service.ts @@ -44,7 +44,7 @@ export class MetadataService { 'application/pdf', // .pdf 'application/postscript', // .ps 'application/msword', // .doc - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document ', // .docx + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx 'application/rtf', // .rtf 'application/epub+zip', // .epub ]; diff --git a/src/app/shared/mocks/item.mock.ts b/src/app/shared/mocks/item.mock.ts index 945b0f7816..10eab2da00 100644 --- a/src/app/shared/mocks/item.mock.ts +++ b/src/app/shared/mocks/item.mock.ts @@ -5,6 +5,7 @@ import { Bitstream } from '../../core/shared/bitstream.model'; import { Item } from '../../core/shared/item.model'; import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; import { createPaginatedList } from '../testing/utils.test'; +import { Bundle } from '../../core/shared/bundle.model'; export const MockBitstreamFormat1: BitstreamFormat = Object.assign(new BitstreamFormat(), { shortDescription: 'Microsoft Word XML', @@ -34,11 +35,25 @@ export const MockBitstreamFormat2: BitstreamFormat = Object.assign(new Bitstream } }); +export const MockBitstreamFormat3: BitstreamFormat = Object.assign(new BitstreamFormat(), { + shortDescription: 'Binary', + description: 'Some scary unknown binary file', + mimetype: 'application/octet-stream', + supportLevel: 0, + internal: false, + extensions: null, + _links:{ + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/17' + } + } +}); + export const MockBitstream1: Bitstream = Object.assign(new Bitstream(), { sizeBytes: 10201, content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content', - format: observableOf(MockBitstreamFormat1), + format: createSuccessfulRemoteDataObject$(MockBitstreamFormat1), bundleName: 'ORIGINAL', _links:{ self: { @@ -61,7 +76,7 @@ export const MockBitstream1: Bitstream = Object.assign(new Bitstream(), export const MockBitstream2: Bitstream = Object.assign(new Bitstream(), { sizeBytes: 31302, content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content', - format: observableOf(MockBitstreamFormat2), + format: createSuccessfulRemoteDataObject$(MockBitstreamFormat2), bundleName: 'ORIGINAL', id: '99b00f3c-1cc6-4689-8158-91965bee6b28', uuid: '99b00f3c-1cc6-4689-8158-91965bee6b28', @@ -82,6 +97,68 @@ export const MockBitstream2: Bitstream = Object.assign(new Bitstream(), { } }); +export const MockBitstream3: Bitstream = Object.assign(new Bitstream(), { + sizeBytes: 4975123, + content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/4db100c1-e1f5-4055-9404-9bc3e2d15f29/content', + format: createSuccessfulRemoteDataObject$(MockBitstreamFormat3), + bundleName: 'ORIGINAL', + id: '4db100c1-e1f5-4055-9404-9bc3e2d15f29', + uuid: '4db100c1-e1f5-4055-9404-9bc3e2d15f29', + type: 'bitstream', + _links: { + self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/4db100c1-e1f5-4055-9404-9bc3e2d15f29' }, + content: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/4db100c1-e1f5-4055-9404-9bc3e2d15f29/content' }, + format: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/17' }, + bundle: { href: '' } + }, + metadata: { + 'dc.title': [ + { + language: null, + value: 'scary' + } + ] + } +}); + +export const MockOriginalBundle: Bundle = Object.assign(new Bundle(), { + name: 'ORIGINAL', + primaryBitstream: createSuccessfulRemoteDataObject$(MockBitstream2), + bitstreams: observableOf(Object.assign({ + _links: { + self: { + href: 'dspace-angular://aggregated/object/1507836003548', + } + }, + requestPending: false, + responsePending: false, + isSuccessful: true, + errorMessage: '', + state: '', + error: undefined, + isRequestPending: false, + isResponsePending: false, + isLoading: false, + hasFailed: false, + hasSucceeded: true, + statusCode: '202', + pageInfo: {}, + payload: { + pageInfo: { + elementsPerPage: 20, + totalElements: 3, + totalPages: 1, + currentPage: 2 + }, + page: [ + MockBitstream1, + MockBitstream2 + ] + } + })) +}); + + /* tslint:disable:no-shadowed-variable */ export const ItemMock: Item = Object.assign(new Item(), { handle: '10673/6', @@ -90,41 +167,7 @@ export const ItemMock: Item = Object.assign(new Item(), { isDiscoverable: true, isWithdrawn: false, bundles: createSuccessfulRemoteDataObject$(createPaginatedList([ - { - name: 'ORIGINAL', - bitstreams: observableOf(Object.assign({ - _links: { - self: { - href: 'dspace-angular://aggregated/object/1507836003548', - } - }, - requestPending: false, - responsePending: false, - isSuccessful: true, - errorMessage: '', - state: '', - error: undefined, - isRequestPending: false, - isResponsePending: false, - isLoading: false, - hasFailed: false, - hasSucceeded: true, - statusCode: '202', - pageInfo: {}, - payload: { - pageInfo: { - elementsPerPage: 20, - totalElements: 3, - totalPages: 1, - currentPage: 2 - }, - page: [ - MockBitstream1, - MockBitstream2 - ] - } - })) - } + MockOriginalBundle, ])), _links:{ self: {