diff --git a/config/config.example.yml b/config/config.example.yml index 5fa2e74cbb..57a3a21316 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -350,6 +350,8 @@ item: # Rounded to the nearest size in the list of selectable sizes on the # settings menu. See pageSizeOptions in 'pagination-component-options.model.ts'. pageSize: 5 + # Show the bitstream access status label on the item page + showAccessStatuses: false # Community Page Config community: diff --git a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts index 3eb8d9caf7..7a6b58dea2 100644 --- a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts +++ b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts @@ -10,7 +10,6 @@ import { TranslateModule } from '@ngx-translate/core'; import { Observable } from 'rxjs'; import { AuthService } from '../../../../../core/auth/auth.service'; -import { AccessStatusDataService } from '../../../../../core/data/access-status-data.service'; import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; import { AuthorizationDataService } from '../../../../../core/data/feature-authorization/authorization-data.service'; import { RemoteData } from '../../../../../core/data/remote-data'; @@ -22,7 +21,6 @@ import { ViewMode } from '../../../../../core/shared/view-mode.model'; import { mockTruncatableService } from '../../../../../shared/mocks/mock-trucatable.service'; import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock'; import { CollectionElementLinkType } from '../../../../../shared/object-collection/collection-element-link.type'; -import { AccessStatusObject } from '../../../../../shared/object-collection/shared/badges/access-status-badge/access-status.model'; import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils'; import { AuthServiceStub } from '../../../../../shared/testing/auth-service.stub'; @@ -44,12 +42,6 @@ describe('ItemAdminSearchResultGridElementComponent', () => { }, }; - const mockAccessStatusDataService = { - findAccessStatusFor(item: Item): Observable> { - return createSuccessfulRemoteDataObject$(new AccessStatusObject()); - }, - }; - const mockThemeService = getMockThemeService(); function init() { @@ -74,7 +66,6 @@ describe('ItemAdminSearchResultGridElementComponent', () => { { provide: TruncatableService, useValue: mockTruncatableService }, { provide: BitstreamDataService, useValue: mockBitstreamDataService }, { provide: ThemeService, useValue: mockThemeService }, - { provide: AccessStatusDataService, useValue: mockAccessStatusDataService }, { provide: AuthService, useClass: AuthServiceStub }, { provide: FileService, useClass: FileServiceStub }, { provide: AuthorizationDataService, useClass: AuthorizationDataServiceStub }, diff --git a/src/app/core/data/access-status-data.service.spec.ts b/src/app/core/data/access-status-data.service.spec.ts index ed587c26d2..27c4005460 100644 --- a/src/app/core/data/access-status-data.service.spec.ts +++ b/src/app/core/data/access-status-data.service.spec.ts @@ -46,11 +46,11 @@ describe('AccessStatusDataService', () => { createService(); }); - describe('when calling findAccessStatusFor', () => { + describe('when calling findItemAccessStatusFor', () => { let contentSource$; beforeEach(() => { - contentSource$ = service.findAccessStatusFor(mockItem); + contentSource$ = service.findItemAccessStatusFor(mockItem); }); it('should send a new GetRequest', fakeAsync(() => { diff --git a/src/app/core/data/access-status-data.service.ts b/src/app/core/data/access-status-data.service.ts index 6d8acb1c8b..576b972f56 100644 --- a/src/app/core/data/access-status-data.service.ts +++ b/src/app/core/data/access-status-data.service.ts @@ -29,7 +29,7 @@ export class AccessStatusDataService extends BaseDataService * Returns {@link RemoteData} of {@link AccessStatusObject} that is the access status of the given item * @param item Item we want the access status of */ - findAccessStatusFor(item: Item): Observable> { + findItemAccessStatusFor(item: Item): Observable> { return this.findByHref(item._links.accessStatus.href); } } diff --git a/src/app/core/provide-core.ts b/src/app/core/provide-core.ts index 78629f9d95..0057c0823d 100644 --- a/src/app/core/provide-core.ts +++ b/src/app/core/provide-core.ts @@ -176,7 +176,6 @@ export const models = ResearcherProfile, OrcidQueue, OrcidHistory, - AccessStatusObject, IdentifierData, Subscription, ItemRequest, diff --git a/src/app/core/shared/bitstream.model.ts b/src/app/core/shared/bitstream.model.ts index 73e5e04b36..29a80069db 100644 --- a/src/app/core/shared/bitstream.model.ts +++ b/src/app/core/shared/bitstream.model.ts @@ -4,6 +4,8 @@ import { inheritSerialization, } from 'cerialize'; import { Observable } from 'rxjs'; +import { AccessStatusObject } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model'; +import { ACCESS_STATUS } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.resource-type'; import { link, @@ -52,6 +54,7 @@ export class Bitstream extends DSpaceObject implements ChildHALResource { format: HALLink; content: HALLink; thumbnail: HALLink; + accessStatus: HALLink; }; /** @@ -75,6 +78,13 @@ export class Bitstream extends DSpaceObject implements ChildHALResource { @link(BUNDLE) bundle?: Observable>; + /** + * The access status for this Bitstream + * Will be undefined unless the access status {@link HALLink} has been resolved. + */ + @link(ACCESS_STATUS, false, 'accessStatus') + accessStatus?: Observable>; + getParentLinkKey(): keyof this['_links'] { return 'format'; } diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index b13cf25f03..d6066f098c 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -130,7 +130,7 @@ export class Item extends DSpaceObject implements ChildHALResource, HandleObject * The access status for this Item * Will be undefined unless the access status {@link HALLink} has been resolved. */ - @link(ACCESS_STATUS) + @link(ACCESS_STATUS, false, 'accessStatus') accessStatus?: Observable>; /** diff --git a/src/app/item-page/full/field-components/file-section/full-file-section.component.ts b/src/app/item-page/full/field-components/file-section/full-file-section.component.ts index 463ee85635..73d844214a 100644 --- a/src/app/item-page/full/field-components/file-section/full-file-section.component.ts +++ b/src/app/item-page/full/field-components/file-section/full-file-section.component.ts @@ -109,6 +109,7 @@ export class FullFileSectionComponent extends FileSectionComponent implements On true, followLink('format'), followLink('thumbnail'), + followLink('accessStatus'), )), tap((rd: RemoteData>) => { if (hasValue(rd.errorMessage)) { @@ -127,6 +128,7 @@ export class FullFileSectionComponent extends FileSectionComponent implements On true, followLink('format'), followLink('thumbnail'), + followLink('accessStatus'), )), tap((rd: RemoteData>) => { if (hasValue(rd.errorMessage)) { diff --git a/src/app/item-page/simple/field-components/file-section/file-section.component.ts b/src/app/item-page/simple/field-components/file-section/file-section.component.ts index 9df34e0d13..f2cd028aab 100644 --- a/src/app/item-page/simple/field-components/file-section/file-section.component.ts +++ b/src/app/item-page/simple/field-components/file-section/file-section.component.ts @@ -28,6 +28,7 @@ import { ThemedLoadingComponent } from '../../../../shared/loading/themed-loadin import { MetadataFieldWrapperComponent } from '../../../../shared/metadata-field-wrapper/metadata-field-wrapper.component'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { FileSizePipe } from '../../../../shared/utils/file-size-pipe'; +import { followLink } from '../../../../shared/utils/follow-link-config.model'; import { VarDirective } from '../../../../shared/utils/var.directive'; /** @@ -109,7 +110,7 @@ export class FileSectionComponent implements OnInit { this.bitstreamDataService.findAllByItemAndBundleName(this.item, 'ORIGINAL', { currentPage: this.currentPage, elementsPerPage: this.pageSize, - }).pipe( + }, true, true, followLink('accessStatus')).pipe( getFirstCompletedRemoteData(), ).subscribe((bitstreamsRD: RemoteData>) => { if (bitstreamsRD.errorMessage) { diff --git a/src/app/process-page/detail/process-detail.component.html b/src/app/process-page/detail/process-detail.component.html index d984df0e9b..68a5877d0a 100644 --- a/src/app/process-page/detail/process-detail.component.html +++ b/src/app/process-page/detail/process-detail.component.html @@ -29,7 +29,7 @@ [title]="'process.detail.output-files'">
@for (file of files; track file; let last = $last) { - + {{getFileName(file)}} ({{(file?.sizeBytes) | dsFileSize }}) diff --git a/src/app/shared/file-download-link/file-download-link.component.html b/src/app/shared/file-download-link/file-download-link.component.html index e305d2a82b..ca15dd93a8 100644 --- a/src/app/shared/file-download-link/file-download-link.component.html +++ b/src/app/shared/file-download-link/file-download-link.component.html @@ -1,4 +1,7 @@ - +} + { let bitstream: Bitstream; let item: Item; + let storeMock: any; function init() { authorizationService = jasmine.createSpyObj('authorizationService', { @@ -51,6 +55,11 @@ describe('FileDownloadLinkComponent', () => { self: { href: 'obj-selflink' }, }, }); + storeMock = jasmine.createSpyObj('store', { + dispatch: jasmine.createSpy('dispatch'), + select: jasmine.createSpy('select'), + pipe: observableOf(true), + }); } function initTestbed() { @@ -63,6 +72,8 @@ describe('FileDownloadLinkComponent', () => { RouterLinkDirectiveStub, { provide: AuthorizationDataService, useValue: authorizationService }, { provide: ActivatedRoute, useValue: new ActivatedRouteStub() }, + { provide: Store, useValue: storeMock }, + { provide: APP_DATA_SERVICES_MAP, useValue: {} }, ], }) .overrideComponent(FileDownloadLinkComponent, { diff --git a/src/app/shared/file-download-link/file-download-link.component.ts b/src/app/shared/file-download-link/file-download-link.component.ts index a8475ee841..a323c49ce9 100644 --- a/src/app/shared/file-download-link/file-download-link.component.ts +++ b/src/app/shared/file-download-link/file-download-link.component.ts @@ -30,13 +30,14 @@ import { hasValue, isNotEmpty, } from '../empty.util'; +import { ThemedAccessStatusBadgeComponent } from '../object-collection/shared/badges/access-status-badge/themed-access-status-badge.component'; @Component({ selector: 'ds-base-file-download-link', templateUrl: './file-download-link.component.html', styleUrls: ['./file-download-link.component.scss'], standalone: true, - imports: [RouterLink, NgClass, NgTemplateOutlet, AsyncPipe, TranslateModule], + imports: [RouterLink, NgClass, NgTemplateOutlet, AsyncPipe, TranslateModule, ThemedAccessStatusBadgeComponent], }) /** * Component displaying a download link @@ -64,6 +65,11 @@ export class FileDownloadLinkComponent implements OnInit { @Input() enableRequestACopy = true; + /** + * A boolean indicating whether the access status badge is displayed + */ + @Input() showAccessStatusBadge = true; + bitstreamPath$: Observable<{ routerLink: string, queryParams: any, diff --git a/src/app/shared/file-download-link/themed-file-download-link.component.ts b/src/app/shared/file-download-link/themed-file-download-link.component.ts index c0fc4597f5..1b5def4012 100644 --- a/src/app/shared/file-download-link/themed-file-download-link.component.ts +++ b/src/app/shared/file-download-link/themed-file-download-link.component.ts @@ -27,7 +27,16 @@ export class ThemedFileDownloadLinkComponent extends ThemedComponent - {{ accessStatus | translate }} - + @if ({ status: accessStatus$ | async, date: embargoDate$ | async }; as accessStatus) { + {{ accessStatus.status | translate: {date: accessStatus.date} }} } } diff --git a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.spec.ts b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.spec.ts index 8d3a9a6a37..6107796d62 100644 --- a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.spec.ts +++ b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.spec.ts @@ -6,9 +6,13 @@ import { } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { TranslateModule } from '@ngx-translate/core'; +import { LinkService } from 'src/app/core/cache/builders/link.service'; +import { getMockLinkService } from 'src/app/shared/mocks/link-service.mock'; +import { followLink } from 'src/app/shared/utils/follow-link-config.model'; +import { APP_DATA_SERVICES_MAP } from 'src/config/app-config.interface'; import { environment } from 'src/environments/environment'; -import { AccessStatusDataService } from '../../../../../core/data/access-status-data.service'; +import { Bitstream } from '../../../../../core/shared/bitstream.model'; import { Item } from '../../../../../core/shared/item.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils'; import { TruncatePipe } from '../../../../utils/truncate.pipe'; @@ -25,9 +29,10 @@ describe('ItemAccessStatusBadgeComponent', () => { let embargoStatus: AccessStatusObject; let restrictedStatus: AccessStatusObject; - let accessStatusDataService: AccessStatusDataService; + let linkService; let item: Item; + let bitstream: Bitstream; function init() { unknownStatus = Object.assign(new AccessStatusObject(), { @@ -44,20 +49,24 @@ describe('ItemAccessStatusBadgeComponent', () => { embargoStatus = Object.assign(new AccessStatusObject(), { status: 'embargo', + embargoDate: '2050-01-01', }); restrictedStatus = Object.assign(new AccessStatusObject(), { status: 'restricted', }); - accessStatusDataService = jasmine.createSpyObj('accessStatusDataService', { - findAccessStatusFor: createSuccessfulRemoteDataObject$(unknownStatus), - }); + linkService = getMockLinkService(); item = Object.assign(new Item(), { uuid: 'item-uuid', type: 'item', }); + + bitstream = Object.assign(new Bitstream(), { + uuid: 'bitstream-uuid', + type: 'bitstream', + }); } function initTestBed() { @@ -65,12 +74,13 @@ describe('ItemAccessStatusBadgeComponent', () => { imports: [TranslateModule.forRoot(), AccessStatusBadgeComponent, TruncatePipe], schemas: [NO_ERRORS_SCHEMA], providers: [ - { provide: AccessStatusDataService, useValue: accessStatusDataService }, + { provide: LinkService, useValue: linkService }, + { provide: APP_DATA_SERVICES_MAP, useValue: {} }, ], }).compileComponents(); } - function initFixtureAndComponent() { + function initFixtureAndComponentWithItem() { environment.item.showAccessStatuses = true; fixture = TestBed.createComponent(AccessStatusBadgeComponent); component = fixture.componentInstance; @@ -79,90 +89,191 @@ describe('ItemAccessStatusBadgeComponent', () => { environment.item.showAccessStatuses = false; } - function lookForAccessStatusBadge(status: string) { + function initFixtureAndComponentWithBitstream() { + environment.item.bitstream.showAccessStatuses = true; + fixture = TestBed.createComponent(AccessStatusBadgeComponent); + component = fixture.componentInstance; + component.object = bitstream; + fixture.detectChanges(); + environment.item.bitstream.showAccessStatuses = false; + } + + function lookForAccessStatusBadgeForItem(status: string) { const badge = fixture.debugElement.query(By.css('span.badge')); expect(badge.nativeElement.textContent).toEqual(`access-status.${status.toLowerCase()}.listelement.badge`); } - describe('init', () => { + function lookForAccessStatusBadgeForBitstream() { + const badge = fixture.debugElement.query(By.css('span.badge')); + expect(badge.nativeElement.textContent).toEqual(`embargo.listelement.badge`); + } + + function lookForNoAccessStatusBadgeForBitstream() { + const badge = fixture.debugElement.query(By.css('span.badge')); + expect(badge.nativeElement.textContent).toEqual(``); + } + + describe('init with item', () => { beforeEach(waitForAsync(() => { init(); initTestBed(); })); beforeEach(() => { - initFixtureAndComponent(); + item.accessStatus = createSuccessfulRemoteDataObject$(unknownStatus); + initFixtureAndComponentWithItem(); }); it('should init the component', () => { expect(component).toBeTruthy(); }); }); - describe('When the findAccessStatusFor method returns unknown', () => { + describe('When the item have no accessStatus link', () => { beforeEach(waitForAsync(() => { init(); initTestBed(); })); beforeEach(() => { - initFixtureAndComponent(); - }); - it('should show the unknown badge', () => { - lookForAccessStatusBadge('unknown'); - }); - }); - - describe('When the findAccessStatusFor method returns metadata.only', () => { - beforeEach(waitForAsync(() => { - init(); - (accessStatusDataService.findAccessStatusFor as jasmine.Spy).and.returnValue(createSuccessfulRemoteDataObject$(metadataOnlyStatus)); - initTestBed(); - })); - beforeEach(() => { - initFixtureAndComponent(); - }); - it('should show the metadata only badge', () => { - lookForAccessStatusBadge('metadata.only'); - }); - }); - - describe('When the findAccessStatusFor method returns open.access', () => { - beforeEach(waitForAsync(() => { - init(); - (accessStatusDataService.findAccessStatusFor as jasmine.Spy).and.returnValue(createSuccessfulRemoteDataObject$(openAccessStatus)); - initTestBed(); - })); - beforeEach(() => { - initFixtureAndComponent(); - }); - it('should show the open access badge', () => { - lookForAccessStatusBadge('open.access'); - }); - }); - - describe('When the findAccessStatusFor method returns embargo', () => { - beforeEach(waitForAsync(() => { - init(); - (accessStatusDataService.findAccessStatusFor as jasmine.Spy).and.returnValue(createSuccessfulRemoteDataObject$(embargoStatus)); - initTestBed(); - })); - beforeEach(() => { - initFixtureAndComponent(); + item.accessStatus = null; + linkService.resolveLink.and.callFake((model: any) => { + item.accessStatus = createSuccessfulRemoteDataObject$(embargoStatus); + return model; + }); + initFixtureAndComponentWithItem(); }); it('should show the embargo badge', () => { - lookForAccessStatusBadge('embargo'); + expect(linkService.resolveLink).toHaveBeenCalledWith(item, followLink('accessStatus')); + lookForAccessStatusBadgeForItem('embargo'); }); }); - describe('When the findAccessStatusFor method returns restricted', () => { + describe('When the item accessStatus link returns unknown', () => { beforeEach(waitForAsync(() => { init(); - (accessStatusDataService.findAccessStatusFor as jasmine.Spy).and.returnValue(createSuccessfulRemoteDataObject$(restrictedStatus)); initTestBed(); })); beforeEach(() => { - initFixtureAndComponent(); + item.accessStatus = createSuccessfulRemoteDataObject$(unknownStatus); + initFixtureAndComponentWithItem(); + }); + it('should show the unknown badge', () => { + lookForAccessStatusBadgeForItem('unknown'); + }); + }); + + describe('When the item accessStatus link returns metadata.only', () => { + beforeEach(waitForAsync(() => { + init(); + item.accessStatus = createSuccessfulRemoteDataObject$(metadataOnlyStatus); + initTestBed(); + })); + beforeEach(() => { + initFixtureAndComponentWithItem(); + }); + it('should show the metadata only badge', () => { + lookForAccessStatusBadgeForItem('metadata.only'); + }); + }); + + describe('When the item accessStatus link returns open.access', () => { + beforeEach(waitForAsync(() => { + init(); + item.accessStatus = createSuccessfulRemoteDataObject$(openAccessStatus); + initTestBed(); + })); + beforeEach(() => { + initFixtureAndComponentWithItem(); + }); + it('should show the open access badge', () => { + lookForAccessStatusBadgeForItem('open.access'); + }); + }); + + describe('When the item accessStatus link returns embargo', () => { + beforeEach(waitForAsync(() => { + init(); + item.accessStatus = createSuccessfulRemoteDataObject$(embargoStatus); + initTestBed(); + })); + beforeEach(() => { + initFixtureAndComponentWithItem(); + }); + it('should show the embargo badge', () => { + lookForAccessStatusBadgeForItem('embargo'); + }); + }); + + describe('When the item accessStatus link returns restricted', () => { + beforeEach(waitForAsync(() => { + init(); + item.accessStatus = createSuccessfulRemoteDataObject$(restrictedStatus); + initTestBed(); + })); + beforeEach(() => { + initFixtureAndComponentWithItem(); }); it('should show the restricted badge', () => { - lookForAccessStatusBadge('restricted'); + lookForAccessStatusBadgeForItem('restricted'); + }); + }); + + describe('init with bitstream', () => { + beforeEach(waitForAsync(() => { + init(); + initTestBed(); + })); + beforeEach(() => { + bitstream.accessStatus = createSuccessfulRemoteDataObject$(unknownStatus); + initFixtureAndComponentWithBitstream(); + }); + it('should init the component', () => { + expect(component).toBeTruthy(); + }); + }); + + describe('When the bitstream have no accessStatus link', () => { + beforeEach(waitForAsync(() => { + init(); + initTestBed(); + })); + beforeEach(() => { + bitstream.accessStatus = null; + linkService.resolveLink.and.callFake((model: any) => { + bitstream.accessStatus = createSuccessfulRemoteDataObject$(embargoStatus); + return model; + }); + initFixtureAndComponentWithBitstream(); + }); + it('should show the badge', () => { + expect(linkService.resolveLink).toHaveBeenCalledWith(bitstream, followLink('accessStatus')); + lookForAccessStatusBadgeForBitstream(); + }); + }); + + describe('When the bitstream have an accessStatus link with no embargo date', () => { + beforeEach(waitForAsync(() => { + init(); + initTestBed(); + })); + beforeEach(() => { + bitstream.accessStatus = createSuccessfulRemoteDataObject$(openAccessStatus); + initFixtureAndComponentWithBitstream(); + }); + it('should not show the badge', () => { + lookForNoAccessStatusBadgeForBitstream(); + }); + }); + + describe('When the bitstream have an accessStatus link with an embargo date', () => { + beforeEach(waitForAsync(() => { + init(); + initTestBed(); + })); + beforeEach(() => { + bitstream.accessStatus = createSuccessfulRemoteDataObject$(embargoStatus); + initFixtureAndComponentWithBitstream(); + }); + it('should show the badge', () => { + lookForAccessStatusBadgeForBitstream(); }); }); }); diff --git a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts index 5fafb5db77..fc3ba0864a 100644 --- a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts +++ b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts @@ -15,12 +15,13 @@ import { catchError, map, } from 'rxjs/operators'; -import { AccessStatusDataService } from 'src/app/core/data/access-status-data.service'; +import { LinkService } from 'src/app/core/cache/builders/link.service'; +import { Bitstream } from 'src/app/core/shared/bitstream.model'; +import { getFirstSucceededRemoteDataPayload } from 'src/app/core/shared/operators'; +import { followLink } from 'src/app/shared/utils/follow-link-config.model'; import { environment } from 'src/environments/environment'; -import { DSpaceObject } from '../../../../../core/shared/dspace-object.model'; import { Item } from '../../../../../core/shared/item.model'; -import { ITEM } from '../../../../../core/shared/item.resource-type'; import { hasValue } from '../../../../empty.util'; import { AccessStatusObject } from './access-status.model'; @@ -36,8 +37,10 @@ import { AccessStatusObject } from './access-status.model'; */ export class AccessStatusBadgeComponent implements OnDestroy, OnInit { - @Input() object: DSpaceObject; + @Input() object: Item | Bitstream; + accessStatus$: Observable; + embargoDate$: Observable; /** * Whether to show the access status badge or not @@ -57,35 +60,49 @@ export class AccessStatusBadgeComponent implements OnDestroy, OnInit { /** * Initialize instance variables * - * @param {AccessStatusDataService} accessStatusDataService + * @param {LinkService} linkService */ - constructor(private accessStatusDataService: AccessStatusDataService) { } + constructor( + private linkService: LinkService, + ) { } ngOnInit(): void { - this.showAccessStatus = environment.item.showAccessStatuses; - if (this.object.type.toString() !== ITEM.value || !this.showAccessStatus || this.object == null) { - // Do not show the badge if the feature is inactive or if the item is null. + if (!hasValue(this.object)) { return; } - - const item = this.object as Item; - if (item.accessStatus == null) { + if (!hasValue(this.object.accessStatus)) { // In case the access status has not been loaded, do it individually. - item.accessStatus = this.accessStatusDataService.findAccessStatusFor(item); + this.linkService.resolveLink(this.object, followLink('accessStatus')); } - this.accessStatus$ = item.accessStatus.pipe( - map((accessStatusRD) => { - if (accessStatusRD.statusCode !== 401 && hasValue(accessStatusRD.payload)) { - return accessStatusRD.payload; - } else { - return []; - } - }), + switch ((this.object as any).type) { + case Item.type.value: + this.handleItem(); + break; + case Bitstream.type.value: + this.handleBitstream(); + break; + } + } + + ngOnDestroy(): void { + this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe()); + } + + /** + * Method to handle the object type Item + */ + private handleItem() { + this.showAccessStatus = environment.item.showAccessStatuses; + if (!this.showAccessStatus) { + // Do not show the badge if the feature is inactive. + return; + } + this.accessStatus$ = this.object.accessStatus.pipe( + getFirstSucceededRemoteDataPayload(), map((accessStatus: AccessStatusObject) => hasValue(accessStatus.status) ? accessStatus.status : 'unknown'), map((status: string) => `access-status.${status.toLowerCase()}.listelement.badge`), catchError(() => observableOf('access-status.unknown.listelement.badge')), ); - // stylesheet based on the access status value this.subs.push( this.accessStatus$.pipe( @@ -96,7 +113,26 @@ export class AccessStatusBadgeComponent implements OnDestroy, OnInit { ); } - ngOnDestroy(): void { - this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe()); + /** + * Method to handle the object type Bitstream + */ + private handleBitstream() { + this.showAccessStatus = environment.item.bitstream.showAccessStatuses; + if (!this.showAccessStatus) { + // Do not show the badge if the feature is inactive. + return; + } + this.embargoDate$ = this.object.accessStatus.pipe( + getFirstSucceededRemoteDataPayload(), + map((accessStatus: AccessStatusObject) => hasValue(accessStatus.embargoDate) ? accessStatus.embargoDate : null), + catchError(() => observableOf(null)), + ); + this.subs.push( + this.embargoDate$.pipe().subscribe((embargoDate: string) => { + if (hasValue(embargoDate)) { + this.accessStatus$ = observableOf('embargo.listelement.badge'); + } + }), + ); } } diff --git a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model.ts b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model.ts index f1b8001b21..62d59f45ff 100644 --- a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model.ts +++ b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model.ts @@ -27,6 +27,12 @@ export class AccessStatusObject implements CacheableObject { @autoserialize status: string; + /** + * The embargo date value + */ + @autoserialize + embargoDate: string; + /** * The {@link HALLink}s for this AccessStatusObject */ diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.html b/src/app/submission/sections/upload/file/section-upload-file.component.html index 876d00cd0f..ebddd53816 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.html +++ b/src/app/submission/sections/upload/file/section-upload-file.component.html @@ -27,7 +27,7 @@
+ [bitstream]="getBitstream()" [enableRequestACopy]="false" [showAccessStatusBadge]="false">