Skip to content

Commit f993a27

Browse files
authored
VSB-TUO/Display total downloads for each item (#961)
* Added new feature for downloads of item's bitstreams * Fixed Copilot's suggestions: any type & redundant property access pattern
1 parent df29455 commit f993a27

9 files changed

Lines changed: 99 additions & 5 deletions

File tree

src/app/core/statistics/models/usage-report.model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,6 @@ export interface Point {
4747
type: string;
4848
values: {
4949
views: number;
50-
}[];
50+
[key: string]: number;
51+
};
5152
}

src/app/item-page/item-page.module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import { ItemAlertsComponent } from './alerts/item-alerts.component';
5757
import { ItemVersionsModule } from './versions/item-versions.module';
5858
import { BitstreamRequestACopyPageComponent } from './bitstreams/request-a-copy/bitstream-request-a-copy-page.component';
5959
import { FileSectionComponent } from './simple/field-components/file-section/file-section.component';
60+
import { TotalDownloadsComponent } from './simple/field-components/file-section/total-downloads.component';
6061
import { ItemSharedModule } from './item-shared.module';
6162
import { DsoPageModule } from '../shared/dso-page/dso-page.module';
6263
import { ThemedItemAlertsComponent } from './alerts/themed-item-alerts.component';
@@ -90,6 +91,7 @@ import { ClarinIdentifierItemFieldComponent } from './simple/field-components/cl
9091
import { ClarinDateItemFieldComponent } from './simple/field-components/clarin-date-item-field/clarin-date-item-field.component';
9192
import { ClarinDescriptionItemFieldComponent } from './simple/field-components/clarin-description-item-field/clarin-description-item-field.component';
9293
import { ClarinFilesSectionComponent } from './clarin-files-section/clarin-files-section.component';
94+
import { UsageReportDataService } from '../core/statistics/usage-report-data.service';
9395

9496
const ENTRY_COMPONENTS = [
9597
// put only entry components that use custom decorator
@@ -99,6 +101,7 @@ const ENTRY_COMPONENTS = [
99101

100102
const DECLARATIONS = [
101103
FileSectionComponent,
104+
TotalDownloadsComponent,
102105
ThemedFileSectionComponent,
103106
ItemPageComponent,
104107
ThemedItemPageComponent,
@@ -181,6 +184,9 @@ const DECLARATIONS = [
181184
],
182185
exports: [
183186
...DECLARATIONS,
187+
],
188+
providers: [
189+
UsageReportDataService,
184190
]
185191
})
186192
export class ItemPageModule {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<ds-metadata-field-wrapper [label]="downloadsLabel | translate">
2+
<div class="total-downloads-section">
3+
<div class="total-downloads-count">
4+
<span>{{ totalDownloads }}</span>
5+
</div>
6+
</div>
7+
</ds-metadata-field-wrapper>

src/app/item-page/simple/field-components/file-section/total-downloads.component.scss

Whitespace-only changes.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Component, OnInit, Input } from '@angular/core';
2+
import { UsageReportDataService } from 'src/app/core/statistics/usage-report-data.service';
3+
import { catchError } from 'rxjs/operators';
4+
import { of } from 'rxjs';
5+
6+
/**
7+
* Component that displays the total number of downloads for all bitstreams within a DSpace item.
8+
*
9+
* This component fetches download statistics for a given item using its UUID and aggregates
10+
* the download counts from all bitstreams associated with that item. The result is displayed
11+
* as a single total download count.
12+
*/
13+
@Component({
14+
selector: 'ds-total-downloads',
15+
templateUrl: './total-downloads.component.html',
16+
styleUrls: ['./total-downloads.component.scss']
17+
})
18+
export class TotalDownloadsComponent implements OnInit {
19+
20+
/**
21+
* The UUID of the DSpace item for which to fetch download statistics.
22+
*/
23+
@Input() itemUuid!: string;
24+
25+
/**
26+
* The total number of downloads across all bitstreams for the item.
27+
* Defaults to 0 and will show 0 if no data is available or an error occurs.
28+
*/
29+
totalDownloads: number = 0;
30+
31+
/**
32+
* The translation key for the downloadsLabel displayed alongside the download count.
33+
*/
34+
readonly downloadsLabel = 'item.page.files.downloads';
35+
36+
37+
constructor(private usageReportDataService: UsageReportDataService) { }
38+
39+
/**
40+
* Fetches the total download statistics for the item specified by itemUuid.
41+
* The component will:
42+
* 1. Call the UsageReportDataService with the item UUID and 'TotalDownloads' report type
43+
* 2. Aggregate all download counts (views) from all bitstreams in the response
44+
* 3. Set the totalDownloads property with the sum
45+
* 4. Handle errors gracefully by setting totalDownloads to 0 and logging the error
46+
*
47+
* @throws Will log an error to console if the API call fails, but won't throw an exception
48+
*/
49+
ngOnInit(): void {
50+
if (!this.itemUuid) {
51+
return;
52+
}
53+
54+
const reportType = 'TotalDownloads';
55+
this.usageReportDataService.getStatistic(this.itemUuid, reportType)
56+
.pipe(
57+
catchError(error => {
58+
console.error('Failed to fetch total downloads statistics:', error);
59+
return of(null);
60+
})
61+
)
62+
.subscribe(report => {
63+
if (report) {
64+
this.totalDownloads = report.points.reduce((total, point) => {
65+
const views = point.values.views || 0;
66+
return total + views;
67+
}, 0);
68+
} else {
69+
this.totalDownloads = 0; // Show 0 instead of null when no data is available
70+
}
71+
});
72+
}
73+
}

src/app/item-page/simple/item-types/publication/publication.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
<div *ngIf="mediaViewer.image || mediaViewer.video" class="mb-2">
2424
<ds-themed-media-viewer [item]="object"></ds-themed-media-viewer>
2525
</div>
26-
<ds-themed-item-page-file-section [item]="object"></ds-themed-item-page-file-section>
26+
<ds-themed-item-page-file-section [item]="object"></ds-themed-item-page-file-section>
27+
<ds-total-downloads [itemUuid]="object.uuid"></ds-total-downloads>
2728
<ds-item-page-date-field [item]="object"></ds-item-page-date-field>
2829
<ds-themed-metadata-representation-list class="ds-item-page-mixed-author-field"
2930
[parentItem]="object"

src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
<div *ngIf="mediaViewer.image || mediaViewer.video" class="mb-2">
2525
<ds-themed-media-viewer [item]="object"></ds-themed-media-viewer>
2626
</div>
27-
<ds-themed-item-page-file-section [item]="object"></ds-themed-item-page-file-section>
27+
<ds-themed-item-page-file-section [item]="object"></ds-themed-item-page-file-section>
28+
<ds-total-downloads [itemUuid]="object.uuid"></ds-total-downloads>
2829
<ds-item-page-date-field [item]="object"></ds-item-page-date-field>
2930
<ds-themed-metadata-representation-list class="ds-item-page-mixed-author-field"
3031
[parentItem]="object"

src/assets/i18n/cs.json5

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3794,6 +3794,9 @@
37943794
// "item.page.files": "Files",
37953795
"item.page.files": "Soubory",
37963796

3797+
// "item.page.files.downloads": "Downloads",
3798+
"item.page.files.downloads": "Stažení",
3799+
37973800
// "item.page.filesection.description": "Description:",
37983801
"item.page.filesection.description": "Popis:",
37993802

@@ -11575,4 +11578,4 @@
1157511578

1157611579
// "clarin-license-agreement-page.download-error": "An error occurred while downloading the file. Please try again later.",
1157711580
"clarin-license-agreement-page.download-error": "Při stahování souboru došlo k chybě. Zkuste to prosím znovu později.",
11578-
}
11581+
}

src/assets/i18n/en.json5

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2529,6 +2529,8 @@
25292529

25302530
"item.page.files": "Files",
25312531

2532+
"item.page.files.downloads": "Downloads",
2533+
25322534
"item.page.filesection.description": "Description:",
25332535

25342536
"item.page.filesection.download": "Download",
@@ -6242,4 +6244,4 @@
62426244
"change.submitter.page.items.name.message": "Item's name: ",
62436245

62446246
"clarin-license-agreement-page.download-error": "An error occurred while downloading the file. Please try again later.",
6245-
}
6247+
}

0 commit comments

Comments
 (0)