mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-16 14:33:03 +00:00
add DSONameService
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
|
import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
|
||||||
import { BreadcrumbsService } from './breadcrumbs.service';
|
import { BreadcrumbsService } from './breadcrumbs.service';
|
||||||
|
import { DSONameService } from './dso-name.service';
|
||||||
import { Observable, of as observableOf } from 'rxjs';
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
import { ChildHALResource } from '../shared/child-hal-resource.model';
|
import { ChildHALResource } from '../shared/child-hal-resource.model';
|
||||||
import { LinkService } from '../cache/builders/link.service';
|
import { LinkService } from '../cache/builders/link.service';
|
||||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||||
import { followLink } from '../../shared/utils/follow-link-config.model';
|
import { followLink } from '../../shared/utils/follow-link-config.model';
|
||||||
import { filter, find, map, switchMap } from 'rxjs/operators';
|
import { find, map, switchMap } from 'rxjs/operators';
|
||||||
import { getDSOPath } from '../../app-routing.module';
|
import { getDSOPath } from '../../app-routing.module';
|
||||||
import { RemoteData } from '../data/remote-data';
|
import { RemoteData } from '../data/remote-data';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
@@ -13,12 +14,16 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DSOBreadcrumbsService implements BreadcrumbsService<ChildHALResource & DSpaceObject> {
|
export class DSOBreadcrumbsService implements BreadcrumbsService<ChildHALResource & DSpaceObject> {
|
||||||
constructor(private linkService: LinkService) {
|
constructor(
|
||||||
|
private linkService: LinkService,
|
||||||
|
private dsoNameService: DSONameService
|
||||||
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getBreadcrumbs(key: ChildHALResource & DSpaceObject, url: string): Observable<Breadcrumb[]> {
|
getBreadcrumbs(key: ChildHALResource & DSpaceObject, url: string): Observable<Breadcrumb[]> {
|
||||||
const crumb = new Breadcrumb(key.name, url);
|
const label = this.dsoNameService.getName(key);
|
||||||
|
const crumb = new Breadcrumb(label, url);
|
||||||
const propertyName = key.getParentLinkKey();
|
const propertyName = key.getParentLinkKey();
|
||||||
return this.linkService.resolveLink(key, followLink(propertyName))[propertyName].pipe(
|
return this.linkService.resolveLink(key, followLink(propertyName))[propertyName].pipe(
|
||||||
find((childRD: RemoteData<ChildHALResource & DSpaceObject>) => childRD.hasSucceeded || childRD.statusCode === 204),
|
find((childRD: RemoteData<ChildHALResource & DSpaceObject>) => childRD.hasSucceeded || childRD.statusCode === 204),
|
||||||
|
116
src/app/core/breadcrumbs/dso-name.service.spec.ts
Normal file
116
src/app/core/breadcrumbs/dso-name.service.spec.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
||||||
|
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||||
|
import { GenericConstructor } from '../shared/generic-constructor';
|
||||||
|
import { Item } from '../shared/item.model';
|
||||||
|
import { MetadataValueFilter } from '../shared/metadata.models';
|
||||||
|
import { DSONameService } from './dso-name.service';
|
||||||
|
|
||||||
|
describe(`DSONameService`, () => {
|
||||||
|
let service: DSONameService;
|
||||||
|
let mockPersonName: string;
|
||||||
|
let mockPerson: DSpaceObject;
|
||||||
|
let mockOrgUnitName: string;
|
||||||
|
let mockOrgUnit: DSpaceObject;
|
||||||
|
let mockDSOName: string;
|
||||||
|
let mockDSO: DSpaceObject;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockPersonName = 'Doe, John';
|
||||||
|
mockPerson = Object.assign(new DSpaceObject(), {
|
||||||
|
firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
|
||||||
|
return mockPersonName
|
||||||
|
},
|
||||||
|
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
|
||||||
|
return ['Person', Item, DSpaceObject];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mockOrgUnitName = 'Molecular Spectroscopy';
|
||||||
|
mockOrgUnit = Object.assign(new DSpaceObject(), {
|
||||||
|
firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
|
||||||
|
return mockOrgUnitName
|
||||||
|
},
|
||||||
|
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
|
||||||
|
return ['OrgUnit', Item, DSpaceObject];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mockDSOName = 'Lorem Ipsum';
|
||||||
|
mockDSO = Object.assign(new DSpaceObject(), {
|
||||||
|
firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
|
||||||
|
return mockDSOName
|
||||||
|
},
|
||||||
|
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
|
||||||
|
return [DSpaceObject];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
service = new DSONameService();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`getName`, () => {
|
||||||
|
it(`should use the Person factory for Person entities`, () => {
|
||||||
|
spyOn((service as any).factories, 'Person').and.returnValue('Bingo!');
|
||||||
|
|
||||||
|
const result = service.getName(mockPerson);
|
||||||
|
|
||||||
|
expect((service as any).factories.Person).toHaveBeenCalledWith(mockPerson);
|
||||||
|
expect(result).toBe('Bingo!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should use the OrgUnit factory for OrgUnit entities`, () => {
|
||||||
|
spyOn((service as any).factories, 'OrgUnit').and.returnValue('Bingo!');
|
||||||
|
|
||||||
|
const result = service.getName(mockOrgUnit);
|
||||||
|
|
||||||
|
expect((service as any).factories.OrgUnit).toHaveBeenCalledWith(mockOrgUnit);
|
||||||
|
expect(result).toBe('Bingo!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should use the Default factory for regular DSpaceObjects`, () => {
|
||||||
|
spyOn((service as any).factories, 'Default').and.returnValue('Bingo!');
|
||||||
|
|
||||||
|
const result = service.getName(mockDSO);
|
||||||
|
|
||||||
|
expect((service as any).factories.Default).toHaveBeenCalledWith(mockDSO);
|
||||||
|
expect(result).toBe('Bingo!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`factories.Person`, () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(mockPerson, 'firstMetadataValue').and.returnValues(...mockPersonName.split(', '));
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return 'person.familyName, person.givenName'`, () => {
|
||||||
|
const result = (service as any).factories.Person(mockPerson);
|
||||||
|
expect(result).toBe(mockPersonName);
|
||||||
|
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.familyName');
|
||||||
|
expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.givenName');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`factories.OrgUnit`, () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(mockOrgUnit, 'firstMetadataValue').and.callThrough();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return 'organization.legalName'`, () => {
|
||||||
|
const result = (service as any).factories.OrgUnit(mockOrgUnit);
|
||||||
|
expect(result).toBe(mockOrgUnitName);
|
||||||
|
expect(mockOrgUnit.firstMetadataValue).toHaveBeenCalledWith('organization.legalName');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`factories.Default`, () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(mockDSO, 'firstMetadataValue').and.callThrough();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return 'dc.title'`, () => {
|
||||||
|
const result = (service as any).factories.Default(mockDSO);
|
||||||
|
expect(result).toBe(mockDSOName);
|
||||||
|
expect(mockDSO.firstMetadataValue).toHaveBeenCalledWith('dc.title');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
53
src/app/core/breadcrumbs/dso-name.service.ts
Normal file
53
src/app/core/breadcrumbs/dso-name.service.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { hasValue } from '../../shared/empty.util';
|
||||||
|
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a name for a {@link DSpaceObject} based
|
||||||
|
* on its render types.
|
||||||
|
*/
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class DSONameService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to generate the specific names.
|
||||||
|
*
|
||||||
|
* If this list ever expands it will probably be worth it to
|
||||||
|
* refactor this using decorators for specific entity types,
|
||||||
|
* or perhaps by using a dedicated model for each entity type
|
||||||
|
*
|
||||||
|
* With only two exceptions those solutions seem overkill for now.
|
||||||
|
*/
|
||||||
|
private factories = {
|
||||||
|
Person: (dso: DSpaceObject): string => {
|
||||||
|
return `${dso.firstMetadataValue('person.familyName')}, ${dso.firstMetadataValue('person.givenName')}`;
|
||||||
|
},
|
||||||
|
OrgUnit: (dso: DSpaceObject): string => {
|
||||||
|
return dso.firstMetadataValue('organization.legalName');
|
||||||
|
},
|
||||||
|
Default: (dso: DSpaceObject): string => {
|
||||||
|
return dso.firstMetadataValue('dc.title');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name for the given {@link DSpaceObject}
|
||||||
|
*
|
||||||
|
* @param dso The {@link DSpaceObject} you want a name for
|
||||||
|
*/
|
||||||
|
getName(dso: DSpaceObject): string {
|
||||||
|
const types = dso.getRenderTypes();
|
||||||
|
const match = types
|
||||||
|
.filter((type) => typeof type === 'string')
|
||||||
|
.find((type: string) => Object.keys(this.factories).includes(type)) as string;
|
||||||
|
|
||||||
|
if (hasValue(match)) {
|
||||||
|
return this.factories[match](dso);
|
||||||
|
} else {
|
||||||
|
return this.factories.Default(dso);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
6
src/app/core/cache/builders/link.service.ts
vendored
6
src/app/core/cache/builders/link.service.ts
vendored
@@ -55,7 +55,10 @@ export class LinkService {
|
|||||||
parent: this.parentInjector
|
parent: this.parentInjector
|
||||||
}).get(provider);
|
}).get(provider);
|
||||||
|
|
||||||
const href = model._links[matchingLinkDef.linkName].href;
|
const link = model._links[matchingLinkDef.linkName];
|
||||||
|
|
||||||
|
if (hasValue(link)) {
|
||||||
|
const href = link.href;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (matchingLinkDef.isList) {
|
if (matchingLinkDef.isList) {
|
||||||
@@ -67,6 +70,7 @@ export class LinkService {
|
|||||||
throw new Error(`Something went wrong when using @dataService(${matchingLinkDef.resourceType.value}) ${hasValue(service) ? '' : '(undefined) '}to resolve link ${linkToFollow.name} from ${href}`);
|
throw new Error(`Something went wrong when using @dataService(${matchingLinkDef.resourceType.value}) ${hasValue(service) ? '' : '(undefined) '}to resolve link ${linkToFollow.name} from ${href}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ import { catchError, distinctUntilKeyChanged, filter, first, map, take } from 'r
|
|||||||
|
|
||||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
||||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
|
import { DSONameService } from '../breadcrumbs/dso-name.service';
|
||||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
import { BitstreamDataService } from '../data/bitstream-data.service';
|
import { BitstreamDataService } from '../data/bitstream-data.service';
|
||||||
import { BitstreamFormatDataService } from '../data/bitstream-format-data.service';
|
import { BitstreamFormatDataService } from '../data/bitstream-format-data.service';
|
||||||
@@ -35,6 +36,7 @@ export class MetadataService {
|
|||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private meta: Meta,
|
private meta: Meta,
|
||||||
private title: Title,
|
private title: Title,
|
||||||
|
private dsoNameService: DSONameService,
|
||||||
private bitstreamDataService: BitstreamDataService,
|
private bitstreamDataService: BitstreamDataService,
|
||||||
private bitstreamFormatDataService: BitstreamFormatDataService,
|
private bitstreamFormatDataService: BitstreamFormatDataService,
|
||||||
@Inject(GLOBAL_CONFIG) private envConfig: GlobalConfig
|
@Inject(GLOBAL_CONFIG) private envConfig: GlobalConfig
|
||||||
@@ -154,7 +156,7 @@ export class MetadataService {
|
|||||||
* Add <meta name="title" ... > to the <head>
|
* Add <meta name="title" ... > to the <head>
|
||||||
*/
|
*/
|
||||||
private setTitleTag(): void {
|
private setTitleTag(): void {
|
||||||
const value = this.getMetaTagValue('dc.title');
|
const value = this.dsoNameService.getName(this.currentObject.getValue());
|
||||||
this.addMetaTag('title', value);
|
this.addMetaTag('title', value);
|
||||||
this.title.setTitle(value);
|
this.title.setTitle(value);
|
||||||
}
|
}
|
||||||
|
@@ -69,6 +69,7 @@ export class DSpaceObject extends ListableObject implements CacheableObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The name for this DSpaceObject
|
* The name for this DSpaceObject
|
||||||
|
* @deprecated use {@link DSONameService} instead
|
||||||
*/
|
*/
|
||||||
get name(): string {
|
get name(): string {
|
||||||
return (isUndefined(this._name)) ? this.firstMetadataValue('dc.title') : this._name;
|
return (isUndefined(this._name)) ? this.firstMetadataValue('dc.title') : this._name;
|
||||||
|
Reference in New Issue
Block a user