Skip to content

Commit 2df6906

Browse files
committed
Merged dspace-cris-2023_02_x into task/dspace-cris-2023_02_x/DSC-2028
2 parents 114c523 + ddbd43a commit 2df6906

33 files changed

Lines changed: 386 additions & 108 deletions

config/config.example.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,10 +400,6 @@ themes:
400400
attributes:
401401
rel: manifest
402402
href: assets/dspace/images/favicons/manifest.webmanifest
403-
- tagName: link
404-
attributes:
405-
rel: stylesheet
406-
href: "https://fonts.googleapis.com/icon?family=Material+Icons"
407403

408404
# The default bundles that should always be displayed as suggestions when you upload a new bundle
409405
bundle:

src/app/core/metadata/metadata.service.spec.ts

Lines changed: 100 additions & 73 deletions
Large diffs are not rendered by default.

src/app/core/metadata/metadata.service.ts

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators';
1818

1919
import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util';
2020
import { DSONameService } from '../breadcrumbs/dso-name.service';
21-
import { BitstreamDataService } from '../data/bitstream-data.service';
22-
import { BitstreamFormatDataService } from '../data/bitstream-format-data.service';
2321

2422
import { RemoteData } from '../data/remote-data';
2523
import { BitstreamFormat } from '../shared/bitstream-format.model';
@@ -46,6 +44,8 @@ import { ITEM } from '../shared/item.resource-type';
4644
import { DOCUMENT, isPlatformBrowser, isPlatformServer } from '@angular/common';
4745
import { Root } from '../data/root.model';
4846
import { environment } from '../../../environments/environment';
47+
import { Bundle } from '../shared/bundle.model';
48+
import { followLink } from '../../shared/utils/follow-link-config.model';
4949

5050
/**
5151
* The base selector function to select the metaTag section in the store
@@ -95,8 +95,6 @@ export class MetadataService {
9595
private title: Title,
9696
private dsoNameService: DSONameService,
9797
private bundleDataService: BundleDataService,
98-
private bitstreamDataService: BitstreamDataService,
99-
private bitstreamFormatDataService: BitstreamFormatDataService,
10098
private rootService: RootDataService,
10199
private store: Store<CoreState>,
102100
private hardRedirectService: HardRedirectService,
@@ -449,7 +447,7 @@ export class MetadataService {
449447
* Add <meta name="og:image" ... > to the <head>
450448
*/
451449
private setOpenGraphImageTag(): void {
452-
this.setPrimaryBitstreamInBundleTag('og:image');
450+
this.setPrimaryImageInBundleTag('og:image');
453451
}
454452

455453
/**
@@ -465,7 +463,7 @@ export class MetadataService {
465463
* Add <meta name="twitter:image" ... > to the <head>
466464
*/
467465
private setTwitterImageTag(): void {
468-
this.setPrimaryBitstreamInBundleTag('twitter:image');
466+
this.setPrimaryImageInBundleTag('twitter:image');
469467
}
470468

471469
/**
@@ -496,6 +494,74 @@ export class MetadataService {
496494
}
497495

498496
private setPrimaryBitstreamInBundleTag(tag: string): void {
497+
if (this.currentObject.value instanceof Item) {
498+
const item = this.currentObject.value as Item;
499+
500+
// Retrieve the ORIGINAL bundle for the item
501+
this.bundleDataService.findByItemAndName(
502+
item,
503+
'ORIGINAL',
504+
true,
505+
true,
506+
followLink('primaryBitstream'),
507+
followLink('bitstreams', {
508+
findListOptions: {
509+
// limit the number of bitstreams used to find the citation pdf url to the number
510+
// shown by default on an item page
511+
elementsPerPage: this.appConfig.item.bitstream.pageSize,
512+
},
513+
}, followLink('format')),
514+
).pipe(
515+
getFirstSucceededRemoteDataPayload(),
516+
switchMap((bundle: Bundle) =>
517+
// First try the primary bitstream
518+
bundle.primaryBitstream.pipe(
519+
getFirstCompletedRemoteData(),
520+
map((rd: RemoteData<Bitstream>) => {
521+
if (hasValue(rd.payload)) {
522+
return rd.payload;
523+
} else {
524+
return null;
525+
}
526+
}),
527+
getDownloadableBitstream(this.authorizationService),
528+
// return the bundle as well so we can use it again if there's no primary bitstream
529+
map((bitstream: Bitstream) => [bundle, bitstream]),
530+
),
531+
),
532+
switchMap(([bundle, primaryBitstream]: [Bundle, Bitstream]) => {
533+
if (hasValue(primaryBitstream)) {
534+
// If there was a downloadable primary bitstream, emit its link
535+
return [getBitstreamDownloadRoute(primaryBitstream)];
536+
} else {
537+
// Otherwise consider the regular bitstreams in the bundle
538+
return bundle.bitstreams.pipe(
539+
getFirstCompletedRemoteData(),
540+
switchMap((bitstreamRd: RemoteData<PaginatedList<Bitstream>>) => {
541+
if (hasValue(bitstreamRd.payload) && bitstreamRd.payload.totalElements === 1) {
542+
// If there's only one bitstream in the bundle, emit its link if its downloadable
543+
return this.getBitLinkIfDownloadable(bitstreamRd.payload.page[0], bitstreamRd);
544+
} else {
545+
// Otherwise check all bitstreams to see if one matches the format whitelist
546+
return this.getFirstAllowedFormatBitstreamLink(bitstreamRd);
547+
}
548+
}),
549+
);
550+
}
551+
}),
552+
take(1),
553+
).subscribe((link: string) => {
554+
// Use the found link to set the <meta> tag
555+
this.addMetaTag(
556+
tag,
557+
new URLCombiner(this.hardRedirectService.getCurrentOrigin(), link).toString(),
558+
true,
559+
);
560+
});
561+
}
562+
}
563+
564+
private setPrimaryImageInBundleTag(tag: string): void {
499565
if (this.currentObject.value instanceof Item) {
500566
const item = this.currentObject.value as Item;
501567
this.getBitstreamFromThumbnail(item).pipe(
@@ -506,14 +572,14 @@ export class MetadataService {
506572
return null;
507573
}
508574
}),
509-
take(1)
575+
take(1),
510576
).subscribe((link) => {
511577
if (hasValue(link)) {
512578
// Use the found link to set the <meta> tag
513579
this.addMetaTag(
514580
tag,
515581
new URLCombiner(this.getUrlOrigin(), link).toString(),
516-
true
582+
true,
517583
);
518584
} else {
519585
this.addFallbackImageToTag(tag);
@@ -654,9 +720,9 @@ export class MetadataService {
654720
return this.currentObject.value.allMetadataValues(keys);
655721
}
656722

657-
private addMetaTag(name: string, content: string, isProperty = false): void {
723+
protected addMetaTag(name: string, content: string, isProperty = false): void {
658724
if (content) {
659-
const tag = isProperty ? {property: name, content} as MetaDefinition
725+
const tag = isProperty ? { name, property: name, content } as MetaDefinition
660726
: { name, content } as MetaDefinition;
661727
this.meta.updateTag(tag);
662728
this.storeTag(name);

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/metadata/rendering-types/link-authority/link-authority.component.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { RenderingTypeValueModelComponent } from '../rendering-type-value.model'
88
import { Item } from '../../../../../../../core/shared/item.model';
99
import { LayoutField } from '../../../../../../../core/layout/models/box.model';
1010
import { MetadataValue } from '../../../../../../../core/shared/metadata.models';
11+
import { isEmpty } from '../../../../../../../shared/empty.util';
1112

1213
/**
1314
* This component renders the links metadata fields.
@@ -56,8 +57,11 @@ export class LinkAuthorityComponent extends RenderingTypeValueModelComponent imp
5657
}
5758

5859
getWebsiteIcon(): string {
59-
const siteUrl = this.metadataValue.authority;
6060
let iconStyle = '';
61+
const siteUrl = this.metadataValue.authority;
62+
if (isEmpty(siteUrl)) {
63+
return iconStyle;
64+
}
6165

6266
if (siteUrl.includes('linkedin')) {
6367
iconStyle = 'fab fa-linkedin';

src/app/shared/mocks/item.mock.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,18 @@ export const ItemMock: Item = Object.assign(new Item(), {
275275
language: 'en_US',
276276
value: 'text'
277277
}
278+
],
279+
'dc.relation.issn': [
280+
{
281+
language: 'en_US',
282+
value: '123456789',
283+
},
284+
],
285+
'dspace.entity.type': [
286+
{
287+
language: 'en',
288+
value: 'Publication',
289+
},
278290
]
279291
},
280292
owningCollection: observableOf({

src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
</div>
1111
<ds-truncatable [id]="item.id">
1212
<h3 [innerHTML]="dsoTitle" [ngClass]="{'lead': true,'text-muted': !item.firstMetadataValue('dc.title')}"></h3>
13+
<div *ngIf="item.hasMetadata('dspace.workflow.startDateTime') && item.hasMetadata('dc.date.accessioned')">
14+
{{ 'mydspace.results.in-workflow-for' | translate }}
15+
{{ getDateForArchivedItem(item.firstMetadataValue('dspace.workflow.startDateTime'), item.firstMetadataValue('dc.date.accessioned')) }}
16+
</div>
1317
<div>
1418
<span class="text-muted">
1519
<ds-truncatable-part [id]="item.id" [minLines]="1">

src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { WorkflowItem } from '../../../../core/submission/models/workflowitem.mo
1010
import {
1111
DuplicateMatchMetadataDetailConfig
1212
} from '../../../../submission/sections/detect-duplicate/models/duplicate-detail-metadata.model';
13+
import { parseISO, differenceInDays, differenceInMilliseconds } from 'date-fns';
1314
import { environment } from '../../../../../environments/environment';
1415

1516
/**
@@ -83,6 +84,15 @@ export class ItemListPreviewComponent implements OnInit {
8384
) {
8485
}
8586

87+
getDateForArchivedItem(itemStartDate: string, dateAccessioned: string) {
88+
const itemStartDateConverted: Date = parseISO(itemStartDate);
89+
const dateAccessionedConverted: Date = parseISO(dateAccessioned);
90+
const days: number = Math.floor(differenceInDays(dateAccessionedConverted, itemStartDateConverted));
91+
const remainingMilliseconds: number = differenceInMilliseconds(dateAccessionedConverted, itemStartDateConverted) - days * 24 * 60 * 60 * 1000;
92+
const hours: number = Math.floor(remainingMilliseconds / (60 * 60 * 1000));
93+
return `${days} d ${hours} h`;
94+
}
95+
8696
ngOnInit(): void {
8797
this.showThumbnails = this.showThumbnails ?? this.appConfig.browseBy.showThumbnails;
8898
this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.item);

src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
[innerHTML]="dsoTitle"></a>
2727
<span *ngIf="linkType == linkTypes.None" class="lead item-list-title dont-break-out"
2828
[innerHTML]="dsoTitle"></span>
29+
<div *ngIf="dso.hasMetadata('dspace.workflow.startDateTime')">
30+
{{ 'mydspace.results.in-workflow-since' | translate }}
31+
{{ getDateForItem(dso.firstMetadataValue('dspace.workflow.startDateTime')) }}
32+
</div>
2933
<span class="text-muted">
3034
<ds-truncatable-part [id]="dso.id" [minLines]="1">
3135
<ng-container *ngIf="dso.firstMetadataValue('dc.publisher') || dso.firstMetadataValue('dc.date.issued')">

src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { TruncatableService } from '../../../../../truncatable/truncatable.servi
1515
import { DSONameService } from '../../../../../../core/breadcrumbs/dso-name.service';
1616
import { APP_CONFIG, AppConfig } from '../../../../../../../config/app-config.interface';
1717
import { getFirstSucceededRemoteListPayload } from '../../../../../../core/shared/operators';
18+
import { differenceInDays, differenceInMilliseconds, parseISO} from 'date-fns';
1819
import { filter, map } from 'rxjs/operators';
1920
import { isNotEmpty } from '../../../../../empty.util';
2021

@@ -89,6 +90,14 @@ export class ItemSearchResultListElementComponent extends SearchResultListElemen
8990
}
9091
}
9192

93+
getDateForItem(itemStartDate: string) {
94+
const itemStartDateConverted: Date = parseISO(itemStartDate);
95+
const days: number = Math.floor(differenceInDays(Date.now(), itemStartDateConverted));
96+
const remainingMilliseconds: number = differenceInMilliseconds(Date.now(), itemStartDateConverted) - days * 24 * 60 * 60 * 1000;
97+
const hours: number = Math.floor(remainingMilliseconds / (60 * 60 * 1000));
98+
return `${days} d ${hours} h`;
99+
}
100+
92101
/**
93102
* Prompt user for consents settings
94103
*/
276 KB
Binary file not shown.

0 commit comments

Comments
 (0)