diff --git a/src/app/item-page/full/full-item-page.component.html b/src/app/item-page/full/full-item-page.component.html index d2655c4ad0..e71dd92f96 100644 --- a/src/app/item-page/full/full-item-page.component.html +++ b/src/app/item-page/full/full-item-page.component.html @@ -4,19 +4,21 @@ -
- -
- +
+
+ +
+ +
-
- - - + +
+ @@ -24,14 +26,16 @@ - -
{{mdEntry.key}}{{mdValue.language}}
- - - -
-
- + + + + + +
+
+ +
diff --git a/src/app/item-page/full/full-item-page.component.spec.ts b/src/app/item-page/full/full-item-page.component.spec.ts index b4ab926667..c7643a940e 100644 --- a/src/app/item-page/full/full-item-page.component.spec.ts +++ b/src/app/item-page/full/full-item-page.component.spec.ts @@ -11,12 +11,15 @@ import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; import { VarDirective } from '../../shared/utils/var.directive'; import { RouterTestingModule } from '@angular/router/testing'; import { Item } from '../../core/shared/item.model'; -import { of as observableOf } from 'rxjs'; +import { BehaviorSubject, of as observableOf } from 'rxjs'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { By } from '@angular/platform-browser'; import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; import { AuthService } from '../../core/auth/auth.service'; import { createPaginatedList } from '../../shared/testing/utils.test'; +import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; +import { createRelationshipsObservable } from '../simple/item-types/shared/item.component.spec'; +import { RemoteData } from '../../core/data/remote-data'; const mockItem: Item = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])), @@ -30,6 +33,13 @@ const mockItem: Item = Object.assign(new Item(), { } }); +const mockWithdrawnItem: Item = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])), + metadata: [], + relationships: createRelationshipsObservable(), + isWithdrawn: true +}); + const metadataServiceStub = { /* tslint:disable:no-empty */ processRemoteData: () => { @@ -44,6 +54,7 @@ describe('FullItemPageComponent', () => { let authService: AuthService; let routeStub: ActivatedRouteStub; let routeData; + let authorizationDataService: AuthorizationDataService; @@ -61,6 +72,10 @@ describe('FullItemPageComponent', () => { data: observableOf(routeData) }); + authorizationDataService = jasmine.createSpyObj('authorizationDataService', { + isAuthorized: observableOf(false), + }); + TestBed.configureTestingModule({ imports: [TranslateModule.forRoot({ loader: { @@ -74,6 +89,7 @@ describe('FullItemPageComponent', () => { { provide: ItemDataService, useValue: {} }, { provide: MetadataService, useValue: metadataServiceStub }, { provide: AuthService, useValue: authService }, + { provide: AuthorizationDataService, useValue: authorizationDataService }, ], schemas: [NO_ERRORS_SCHEMA] @@ -111,4 +127,53 @@ describe('FullItemPageComponent', () => { expect(simpleViewBtn).toBeFalsy(); }); })); + + describe('when the item is withdrawn and the user is an admin', () => { + beforeEach(() => { + comp.isAdmin$ = observableOf(true); + comp.itemRD$ = new BehaviorSubject>(createSuccessfulRemoteDataObject(mockWithdrawnItem)); + fixture.detectChanges(); + }); + + it('should display the item', () => { + const objectLoader = fixture.debugElement.query(By.css('.full-item-info')); + expect(objectLoader.nativeElement).toBeDefined(); + }); + }); + describe('when the item is withdrawn and the user is not an admin', () => { + beforeEach(() => { + comp.itemRD$ = new BehaviorSubject>(createSuccessfulRemoteDataObject(mockWithdrawnItem)); + fixture.detectChanges(); + }); + + it('should not display the item', () => { + const objectLoader = fixture.debugElement.query(By.css('.full-item-info')); + expect(objectLoader).toBeNull(); + }); + }); + + describe('when the item is not withdrawn and the user is an admin', () => { + beforeEach(() => { + comp.isAdmin$ = observableOf(true); + comp.itemRD$ = new BehaviorSubject>(createSuccessfulRemoteDataObject(mockItem)); + fixture.detectChanges(); + }); + + it('should display the item', () => { + const objectLoader = fixture.debugElement.query(By.css('.full-item-info')); + expect(objectLoader.nativeElement).toBeDefined(); + }); + }); + + describe('when the item is not withdrawn and the user is not an admin', () => { + beforeEach(() => { + comp.itemRD$ = new BehaviorSubject>(createSuccessfulRemoteDataObject(mockItem)); + fixture.detectChanges(); + }); + + it('should display the item', () => { + const objectLoader = fixture.debugElement.query(By.css('.full-item-info')); + expect(objectLoader.nativeElement).toBeDefined(); + }); + }); }); diff --git a/src/app/item-page/full/full-item-page.component.ts b/src/app/item-page/full/full-item-page.component.ts index 7f1b6de614..369769c77d 100644 --- a/src/app/item-page/full/full-item-page.component.ts +++ b/src/app/item-page/full/full-item-page.component.ts @@ -15,6 +15,7 @@ import { fadeInOut } from '../../shared/animations/fade'; import { hasValue } from '../../shared/empty.util'; import { AuthService } from '../../core/auth/auth.service'; import { Location } from '@angular/common'; +import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; /** @@ -46,8 +47,9 @@ export class FullItemPageComponent extends ItemPageComponent implements OnInit, router: Router, items: ItemDataService, authService: AuthService, + authorizationService: AuthorizationDataService, private _location: Location) { - super(route, router, items, authService); + super(route, router, items, authService, authorizationService); } /*** AoT inheritance fix, will hopefully be resolved in the near future **/ diff --git a/src/app/item-page/simple/item-page.component.html b/src/app/item-page/simple/item-page.component.html index e843155d10..3e834b53db 100644 --- a/src/app/item-page/simple/item-page.component.html +++ b/src/app/item-page/simple/item-page.component.html @@ -4,7 +4,7 @@ - +
diff --git a/src/app/item-page/simple/item-page.component.spec.ts b/src/app/item-page/simple/item-page.component.spec.ts index ff5a1e38d5..2ad0bbb272 100644 --- a/src/app/item-page/simple/item-page.component.spec.ts +++ b/src/app/item-page/simple/item-page.component.spec.ts @@ -21,6 +21,7 @@ import { } from '../../shared/remote-data.utils'; import { AuthService } from '../../core/auth/auth.service'; import { createPaginatedList } from '../../shared/testing/utils.test'; +import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; const mockItem: Item = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])), @@ -28,10 +29,18 @@ const mockItem: Item = Object.assign(new Item(), { relationships: createRelationshipsObservable() }); +const mockWithdrawnItem: Item = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])), + metadata: [], + relationships: createRelationshipsObservable(), + isWithdrawn: true +}); + describe('ItemPageComponent', () => { let comp: ItemPageComponent; let fixture: ComponentFixture; let authService: AuthService; + let authorizationDataService: AuthorizationDataService; const mockMetadataService = { /* tslint:disable:no-empty */ @@ -48,6 +57,9 @@ describe('ItemPageComponent', () => { isAuthenticated: observableOf(true), setRedirectUrl: {} }); + authorizationDataService = jasmine.createSpyObj('authorizationDataService', { + isAuthorized: observableOf(false), + }); TestBed.configureTestingModule({ imports: [TranslateModule.forRoot({ @@ -63,6 +75,7 @@ describe('ItemPageComponent', () => { { provide: MetadataService, useValue: mockMetadataService }, { provide: Router, useValue: {} }, { provide: AuthService, useValue: authService }, + { provide: AuthorizationDataService, useValue: authorizationDataService }, ], schemas: [NO_ERRORS_SCHEMA] @@ -102,4 +115,53 @@ describe('ItemPageComponent', () => { }); }); + describe('when the item is withdrawn and the user is an admin', () => { + beforeEach(() => { + comp.isAdmin$ = observableOf(true); + comp.itemRD$ = createSuccessfulRemoteDataObject$(mockWithdrawnItem); + fixture.detectChanges(); + }); + + it('should display the item', () => { + const objectLoader = fixture.debugElement.query(By.css('ds-listable-object-component-loader')); + expect(objectLoader.nativeElement).toBeDefined(); + }); + }); + describe('when the item is withdrawn and the user is not an admin', () => { + beforeEach(() => { + comp.itemRD$ = createSuccessfulRemoteDataObject$(mockWithdrawnItem); + fixture.detectChanges(); + }); + + it('should not display the item', () => { + const objectLoader = fixture.debugElement.query(By.css('ds-listable-object-component-loader')); + expect(objectLoader).toBeNull(); + }); + }); + + describe('when the item is not withdrawn and the user is an admin', () => { + beforeEach(() => { + comp.isAdmin$ = observableOf(true); + comp.itemRD$ = createSuccessfulRemoteDataObject$(mockItem); + fixture.detectChanges(); + }); + + it('should display the item', () => { + const objectLoader = fixture.debugElement.query(By.css('ds-listable-object-component-loader')); + expect(objectLoader.nativeElement).toBeDefined(); + }); + }); + + describe('when the item is not withdrawn and the user is not an admin', () => { + beforeEach(() => { + comp.itemRD$ = createSuccessfulRemoteDataObject$(mockItem); + fixture.detectChanges(); + }); + + it('should display the item', () => { + const objectLoader = fixture.debugElement.query(By.css('ds-listable-object-component-loader')); + expect(objectLoader.nativeElement).toBeDefined(); + }); + }); + }); diff --git a/src/app/item-page/simple/item-page.component.ts b/src/app/item-page/simple/item-page.component.ts index cc23ba86d5..0559dc2219 100644 --- a/src/app/item-page/simple/item-page.component.ts +++ b/src/app/item-page/simple/item-page.component.ts @@ -1,4 +1,4 @@ -import { map } from 'rxjs/operators'; +import { map, switchMap } from 'rxjs/operators'; import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; @@ -13,6 +13,8 @@ import { getAllSucceededRemoteDataPayload, redirectOn4xx } from '../../core/shar import { ViewMode } from '../../core/shared/view-mode.model'; import { AuthService } from '../../core/auth/auth.service'; import { getItemPageRoute } from '../item-page-routing-paths'; +import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; +import { FeatureID } from '../../core/data/feature-authorization/feature-id'; /** * This component renders a simple item page. @@ -48,11 +50,17 @@ export class ItemPageComponent implements OnInit { */ itemPageRoute$: Observable; + /** + * Whether the current user is an admin or not + */ + isAdmin$: Observable; + constructor( protected route: ActivatedRoute, private router: Router, private items: ItemDataService, private authService: AuthService, + private authorizationService: AuthorizationDataService ) { } /** @@ -67,5 +75,7 @@ export class ItemPageComponent implements OnInit { getAllSucceededRemoteDataPayload(), map((item) => getItemPageRoute(item)) ); + + this.isAdmin$ = this.authorizationService.isAuthorized(FeatureID.AdministratorOf); } } diff --git a/src/app/shared/item/item-alerts/item-alerts.component.html b/src/app/shared/item/item-alerts/item-alerts.component.html index fce5c038e5..740ea2595d 100644 --- a/src/app/shared/item/item-alerts/item-alerts.component.html +++ b/src/app/shared/item/item-alerts/item-alerts.component.html @@ -1,8 +1,13 @@
-
- -
-
- -
+
+ +
+
+ +
+ {{'item.alerts.withdrawn' | translate}} + {{"404.link.home-page" | translate}} +
+
+