|
| 1 | +import { Component, OnInit, Input } from '@angular/core'; |
| 2 | +import { UsageReportDataService } from 'src/app/core/statistics/usage-report-data.service'; |
| 3 | +import { ConfigurationDataService } from 'src/app/core/data/configuration-data.service'; |
| 4 | +import { catchError } from 'rxjs/operators'; |
| 5 | +import { BehaviorSubject, of } from 'rxjs'; |
| 6 | + |
| 7 | +/** |
| 8 | + * Component that displays the total number of downloads for all bitstreams within a DSpace item. |
| 9 | + * |
| 10 | + * This component checks the 'item.view.total.downloads.enabled' configuration property |
| 11 | + * to determine if download statistics should be displayed. If enabled, it fetches download |
| 12 | + * statistics for a given item using its UUID and aggregates the download counts from all |
| 13 | + * bitstreams associated with that item. The result is displayed as a single total download count. |
| 14 | + * |
| 15 | + * If the configuration is disabled or set to 'false', the component will not be displayed. |
| 16 | + */ |
| 17 | +@Component({ |
| 18 | + selector: 'ds-total-downloads', |
| 19 | + templateUrl: './total-downloads.component.html', |
| 20 | + styleUrls: ['./total-downloads.component.scss'] |
| 21 | +}) |
| 22 | +export class TotalDownloadsComponent implements OnInit { |
| 23 | + |
| 24 | + /** |
| 25 | + * The UUID of the DSpace item for which to fetch download statistics. |
| 26 | + */ |
| 27 | + @Input() itemUuid!: string; |
| 28 | + |
| 29 | + /** |
| 30 | + * The total number of downloads across all bitstreams for the item. |
| 31 | + * Defaults to 0 and will show 0 if no data is available or an error occurs. |
| 32 | + */ |
| 33 | + totalDownloads: number | null = 0; |
| 34 | + |
| 35 | + /** |
| 36 | + * Flag indicating whether the total downloads feature is enabled in the configuration. |
| 37 | + * Uses BehaviorSubject to allow reactive updates. Defaults to false and will only be |
| 38 | + * set to true if the configuration explicitly contains 'true' value. |
| 39 | + */ |
| 40 | + totalDownloadsEnabled = new BehaviorSubject<boolean>(false); |
| 41 | + |
| 42 | + /** |
| 43 | + * The translation key for the downloadsLabel displayed alongside the download count. |
| 44 | + */ |
| 45 | + readonly downloadsLabel = 'item.page.files.downloads'; |
| 46 | + |
| 47 | + |
| 48 | + constructor( |
| 49 | + private usageReportDataService: UsageReportDataService, |
| 50 | + private configService: ConfigurationDataService |
| 51 | + ) { } |
| 52 | + |
| 53 | + /** |
| 54 | + * Fetches the configuration to check if total downloads should be shown, |
| 55 | + * and if enabled, fetches the total download statistics for the item specified by itemUuid. |
| 56 | + * The component will: |
| 57 | + * 1. Check the 'item.view.total.downloads.enabled' configuration property |
| 58 | + * 2. If enabled (configuration value is explicitly 'true'), call the UsageReportDataService |
| 59 | + * If configuration is not found or fails to load, defaults to false (disabled) |
| 60 | + * 3. Aggregate all download counts (views) from all bitstreams in the response |
| 61 | + * 4. Set the totalDownloads property with the sum |
| 62 | + * 5. Handle errors gracefully by returning null and logging the error |
| 63 | + * |
| 64 | + * @throws Will log an error to console if the API call fails, but won't throw an exception |
| 65 | + */ |
| 66 | + ngOnInit(): void { |
| 67 | + if (!this.itemUuid) { |
| 68 | + return; |
| 69 | + } |
| 70 | + |
| 71 | + // First, check if total downloads feature is enabled in configuration |
| 72 | + this.configService.findByPropertyName('item.view.total.downloads.enabled') |
| 73 | + .pipe( |
| 74 | + catchError(error => { |
| 75 | + console.error('Failed to fetch total downloads configuration:', error); |
| 76 | + // Default to false if configuration cannot be retrieved |
| 77 | + return of(null); |
| 78 | + }) |
| 79 | + ) |
| 80 | + .subscribe(configData => { |
| 81 | + // Extract configuration value, default to 'false' if not found |
| 82 | + const itemViewTotalDownloadsEnabled = configData?.payload?.values?.[0]; |
| 83 | + this.totalDownloadsEnabled.next(itemViewTotalDownloadsEnabled === 'true'); |
| 84 | + |
| 85 | + // Only fetch download statistics if the feature is enabled |
| 86 | + if (this.totalDownloadsEnabled.value) { |
| 87 | + this.fetchDownloadStatistics(); |
| 88 | + } else { |
| 89 | + this.totalDownloads = null; // Ensure it's null when disabled |
| 90 | + } |
| 91 | + }); |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Private method to fetch download statistics from the usage report service. |
| 96 | + * This method is called only when the total downloads feature is enabled. |
| 97 | + */ |
| 98 | + private fetchDownloadStatistics(): void { |
| 99 | + const reportType = 'TotalDownloads'; |
| 100 | + this.usageReportDataService.getStatistic(this.itemUuid, reportType) |
| 101 | + .pipe( |
| 102 | + catchError(error => { |
| 103 | + console.error('Failed to fetch total downloads statistics:', error); |
| 104 | + return of(null); |
| 105 | + }) |
| 106 | + ) |
| 107 | + .subscribe(report => { |
| 108 | + if (report) { |
| 109 | + this.totalDownloads = report.points.reduce((total, point) => { |
| 110 | + const views = point.values.views || 0; |
| 111 | + return total + views; |
| 112 | + }, 0); |
| 113 | + } else { |
| 114 | + this.totalDownloads = 0; // Show 0 instead of null when no data is available |
| 115 | + } |
| 116 | + }); |
| 117 | + } |
| 118 | +} |
0 commit comments