diff --git a/src/app/core/shared/collection.model.ts b/src/app/core/shared/collection.model.ts index 30259b7dbe..d1c49c8d4b 100644 --- a/src/app/core/shared/collection.model.ts +++ b/src/app/core/shared/collection.model.ts @@ -15,10 +15,11 @@ import { RESOURCE_POLICY } from '../resource-policy/models/resource-policy.resou import { COMMUNITY } from './community.resource-type'; import { Community } from './community.model'; import { ChildHALResource } from './child-hal-resource.model'; +import { HandleObject } from './handle-object.model'; @typedObject @inheritSerialization(DSpaceObject) -export class Collection extends DSpaceObject implements ChildHALResource { +export class Collection extends DSpaceObject implements ChildHALResource, HandleObject { static type = COLLECTION; /** diff --git a/src/app/core/shared/community.model.ts b/src/app/core/shared/community.model.ts index afe2c6dfef..f16aad9645 100644 --- a/src/app/core/shared/community.model.ts +++ b/src/app/core/shared/community.model.ts @@ -11,10 +11,11 @@ import { COMMUNITY } from './community.resource-type'; import { DSpaceObject } from './dspace-object.model'; import { HALLink } from './hal-link.model'; import { ChildHALResource } from './child-hal-resource.model'; +import { HandleObject } from './handle-object.model'; @typedObject @inheritSerialization(DSpaceObject) -export class Community extends DSpaceObject implements ChildHALResource { +export class Community extends DSpaceObject implements ChildHALResource, HandleObject { static type = COMMUNITY; /** diff --git a/src/app/core/shared/handle-object.model.ts b/src/app/core/shared/handle-object.model.ts new file mode 100644 index 0000000000..04a1f5e663 --- /dev/null +++ b/src/app/core/shared/handle-object.model.ts @@ -0,0 +1,8 @@ +/** + * Interface representing an object in DSpace that contains a handle + */ +export interface HandleObject { + + handle: string; + +} diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index 49ca7750b4..28f0d7fd36 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -23,13 +23,14 @@ import { BITSTREAM } from './bitstream.resource-type'; import { Bitstream } from './bitstream.model'; import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type'; import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model'; +import { HandleObject } from './handle-object.model'; /** * Class representing a DSpace Item */ @typedObject @inheritSerialization(DSpaceObject) -export class Item extends DSpaceObject implements ChildHALResource { +export class Item extends DSpaceObject implements ChildHALResource, HandleObject { static type = ITEM; /** diff --git a/src/app/shared/theme-support/theme.service.ts b/src/app/shared/theme-support/theme.service.ts index 4a4f6ae986..99e1702dff 100644 --- a/src/app/shared/theme-support/theme.service.ts +++ b/src/app/shared/theme-support/theme.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Inject } from '@angular/core'; +import { Injectable, Inject, Injector } from '@angular/core'; import { Store, createFeatureSelector, createSelector, select } from '@ngrx/store'; import { EMPTY, Observable, of as observableOf } from 'rxjs'; import { ThemeState } from './theme.reducer'; @@ -46,10 +46,11 @@ export class ThemeService { private store: Store, private linkService: LinkService, private dSpaceObjectDataService: DSpaceObjectDataService, + protected injector: Injector, @Inject(GET_THEME_CONFIG_FOR_FACTORY) private gtcf: (str) => ThemeConfig ) { // Create objects from the theme configs in the environment file - this.themes = environment.themes.map((themeConfig: ThemeConfig) => themeFactory(themeConfig)); + this.themes = environment.themes.map((themeConfig: ThemeConfig) => themeFactory(themeConfig, injector)); this.hasDynamicTheme = environment.themes.some((themeConfig: any) => hasValue(themeConfig.regex) || hasValue(themeConfig.handle) || diff --git a/src/config/theme.model.spec.ts b/src/config/theme.model.spec.ts index 16c76539d6..79b5a1f32b 100644 --- a/src/config/theme.model.spec.ts +++ b/src/config/theme.model.spec.ts @@ -8,6 +8,7 @@ import { Collection } from '../app/core/shared/collection.model'; import { Item } from '../app/core/shared/item.model'; import { ITEM } from '../app/core/shared/item.resource-type'; import { getItemModuleRoute } from '../app/item-page/item-page-routing-paths'; +import { HandleService } from '../app/shared/handle.service'; describe('Theme Models', () => { let theme: Theme; @@ -67,24 +68,40 @@ describe('Theme Models', () => { }); describe('HandleTheme', () => { + let handleService; + beforeEach(() => { + handleService = new HandleService(); + }); it('should return true when the DSO\'s handle matches the theme\'s handle', () => { theme = new HandleTheme({ name: 'matching-handle', handle: '1234/5678', - }); - const dso = Object.assign(new Item(), { + }, handleService); + const matchingDso = Object.assign(new Item(), { type: ITEM.value, uuid: 'item-uuid', handle: '1234/5678', + }, handleService); + expect(theme.matches('', matchingDso)).toEqual(true); + }); + it('should return false when the DSO\'s handle contains the theme\'s handle as a subpart', () => { + theme = new HandleTheme({ + name: 'matching-handle', + handle: '1234/5678', + }, handleService); + const dso = Object.assign(new Item(), { + type: ITEM.value, + uuid: 'item-uuid', + handle: '1234/567891011', }); - expect(theme.matches('', dso)).toEqual(true); + expect(theme.matches('', dso)).toEqual(false); }); it('should return false when the handles don\'t match', () => { theme = new HandleTheme({ name: 'no-matching-handle', handle: '1234/5678', - }); + }, handleService); const dso = Object.assign(new Item(), { type: ITEM.value, uuid: 'item-uuid', diff --git a/src/config/theme.model.ts b/src/config/theme.model.ts index b7654b1fd7..019540f18a 100644 --- a/src/config/theme.model.ts +++ b/src/config/theme.model.ts @@ -3,6 +3,9 @@ import { Config } from './config.interface'; import { hasValue, hasNoValue, isNotEmpty } from '../app/shared/empty.util'; import { DSpaceObject } from '../app/core/shared/dspace-object.model'; import { getDSORoute } from '../app/app-routing-paths'; +import { HandleObject } from '../app/core/shared/handle-object.model'; +import { Injector } from '@angular/core'; +import { HandleService } from '../app/shared/handle.service'; export interface NamedThemeConfig extends Config { name: string; @@ -82,12 +85,20 @@ export class RegExTheme extends Theme { } export class HandleTheme extends Theme { - constructor(public config: HandleThemeConfig) { + + private normalizedHandle; + + constructor(public config: HandleThemeConfig, + protected handleService: HandleService + ) { super(config); + this.normalizedHandle = this.handleService.normalizeHandle(this.config.handle); + } - matches(url: string, dso: any): boolean { - return hasValue(dso) && hasValue(dso.handle) && dso.handle.includes(this.config.handle); + matches(url: string, dso: T): boolean { + return hasValue(dso) && hasValue(dso.handle) + && this.handleService.normalizeHandle(dso.handle) === this.normalizedHandle; } } @@ -101,11 +112,11 @@ export class UUIDTheme extends Theme { } } -export const themeFactory = (config: ThemeConfig): Theme => { +export const themeFactory = (config: ThemeConfig, injector: Injector): Theme => { if (hasValue((config as RegExThemeConfig).regex)) { return new RegExTheme(config as RegExThemeConfig); } else if (hasValue((config as HandleThemeConfig).handle)) { - return new HandleTheme(config as HandleThemeConfig); + return new HandleTheme(config as HandleThemeConfig, injector.get(HandleService)); } else if (hasValue((config as UUIDThemeConfig).uuid)) { return new UUIDTheme(config as UUIDThemeConfig); } else {