mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge pull request #955 from atmire/401-login-page-and-403-page
401 login page and 403 page
This commit is contained in:
@@ -7,6 +7,7 @@ import { of as observableOf } from 'rxjs';
|
|||||||
import { DsoPageFeatureGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
|
import { DsoPageFeatureGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
||||||
|
import { AuthService } from '../core/auth/auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -17,8 +18,9 @@ import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
|||||||
export class CollectionPageAdministratorGuard extends DsoPageFeatureGuard<Collection> {
|
export class CollectionPageAdministratorGuard extends DsoPageFeatureGuard<Collection> {
|
||||||
constructor(protected resolver: CollectionPageResolver,
|
constructor(protected resolver: CollectionPageResolver,
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router) {
|
protected router: Router,
|
||||||
super(resolver, authorizationService, router);
|
protected authService: AuthService) {
|
||||||
|
super(resolver, authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -17,13 +17,14 @@ import { DSpaceObjectType } from '../core/shared/dspace-object-type.model';
|
|||||||
import { Item } from '../core/shared/item.model';
|
import { Item } from '../core/shared/item.model';
|
||||||
import {
|
import {
|
||||||
getSucceededRemoteData,
|
getSucceededRemoteData,
|
||||||
redirectOn404Or401,
|
redirectOn4xx,
|
||||||
toDSpaceObjectListRD
|
toDSpaceObjectListRD
|
||||||
} from '../core/shared/operators';
|
} from '../core/shared/operators';
|
||||||
|
|
||||||
import { fadeIn, fadeInOut } from '../shared/animations/fade';
|
import { fadeIn, fadeInOut } from '../shared/animations/fade';
|
||||||
import { hasNoValue, hasValue, isNotEmpty } from '../shared/empty.util';
|
import { hasNoValue, hasValue, isNotEmpty } from '../shared/empty.util';
|
||||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||||
|
import { AuthService } from '../core/auth/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-collection-page',
|
selector: 'ds-collection-page',
|
||||||
@@ -51,7 +52,8 @@ export class CollectionPageComponent implements OnInit {
|
|||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private metadata: MetadataService,
|
private metadata: MetadataService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private authService: AuthService,
|
||||||
) {
|
) {
|
||||||
this.paginationConfig = new PaginationComponentOptions();
|
this.paginationConfig = new PaginationComponentOptions();
|
||||||
this.paginationConfig.id = 'collection-page-pagination';
|
this.paginationConfig.id = 'collection-page-pagination';
|
||||||
@@ -63,7 +65,7 @@ export class CollectionPageComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.collectionRD$ = this.route.data.pipe(
|
this.collectionRD$ = this.route.data.pipe(
|
||||||
map((data) => data.dso as RemoteData<Collection>),
|
map((data) => data.dso as RemoteData<Collection>),
|
||||||
redirectOn404Or401(this.router),
|
redirectOn4xx(this.router, this.authService),
|
||||||
take(1)
|
take(1)
|
||||||
);
|
);
|
||||||
this.logoRD$ = this.collectionRD$.pipe(
|
this.logoRD$ = this.collectionRD$.pipe(
|
||||||
|
@@ -7,6 +7,7 @@ import { of as observableOf } from 'rxjs';
|
|||||||
import { DsoPageFeatureGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
|
import { DsoPageFeatureGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
||||||
|
import { AuthService } from '../core/auth/auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -17,8 +18,9 @@ import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
|||||||
export class CommunityPageAdministratorGuard extends DsoPageFeatureGuard<Community> {
|
export class CommunityPageAdministratorGuard extends DsoPageFeatureGuard<Community> {
|
||||||
constructor(protected resolver: CommunityPageResolver,
|
constructor(protected resolver: CommunityPageResolver,
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router) {
|
protected router: Router,
|
||||||
super(resolver, authorizationService, router);
|
protected authService: AuthService) {
|
||||||
|
super(resolver, authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -13,7 +13,8 @@ import { MetadataService } from '../core/metadata/metadata.service';
|
|||||||
|
|
||||||
import { fadeInOut } from '../shared/animations/fade';
|
import { fadeInOut } from '../shared/animations/fade';
|
||||||
import { hasValue } from '../shared/empty.util';
|
import { hasValue } from '../shared/empty.util';
|
||||||
import { redirectOn404Or401 } from '../core/shared/operators';
|
import { redirectOn4xx } from '../core/shared/operators';
|
||||||
|
import { AuthService } from '../core/auth/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-community-page',
|
selector: 'ds-community-page',
|
||||||
@@ -39,7 +40,8 @@ export class CommunityPageComponent implements OnInit {
|
|||||||
private communityDataService: CommunityDataService,
|
private communityDataService: CommunityDataService,
|
||||||
private metadata: MetadataService,
|
private metadata: MetadataService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private authService: AuthService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -47,7 +49,7 @@ export class CommunityPageComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.communityRD$ = this.route.data.pipe(
|
this.communityRD$ = this.route.data.pipe(
|
||||||
map((data) => data.dso as RemoteData<Community>),
|
map((data) => data.dso as RemoteData<Community>),
|
||||||
redirectOn404Or401(this.router)
|
redirectOn4xx(this.router, this.authService)
|
||||||
);
|
);
|
||||||
this.logoRD$ = this.communityRD$.pipe(
|
this.logoRD$ = this.communityRD$.pipe(
|
||||||
map((rd: RemoteData<Community>) => rd.payload),
|
map((rd: RemoteData<Community>) => rd.payload),
|
||||||
|
@@ -7,6 +7,7 @@ import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/ro
|
|||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -17,8 +18,9 @@ import { of as observableOf } from 'rxjs';
|
|||||||
export class ItemPageReinstateGuard extends DsoPageFeatureGuard<Item> {
|
export class ItemPageReinstateGuard extends DsoPageFeatureGuard<Item> {
|
||||||
constructor(protected resolver: ItemPageResolver,
|
constructor(protected resolver: ItemPageResolver,
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router) {
|
protected router: Router,
|
||||||
super(resolver, authorizationService, router);
|
protected authService: AuthService) {
|
||||||
|
super(resolver, authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -7,6 +7,7 @@ import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/ro
|
|||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -17,8 +18,9 @@ import { of as observableOf } from 'rxjs';
|
|||||||
export class ItemPageWithdrawGuard extends DsoPageFeatureGuard<Item> {
|
export class ItemPageWithdrawGuard extends DsoPageFeatureGuard<Item> {
|
||||||
constructor(protected resolver: ItemPageResolver,
|
constructor(protected resolver: ItemPageResolver,
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router) {
|
protected router: Router,
|
||||||
super(resolver, authorizationService, router);
|
protected authService: AuthService) {
|
||||||
|
super(resolver, authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -20,6 +20,7 @@ import {
|
|||||||
createSuccessfulRemoteDataObject,
|
createSuccessfulRemoteDataObject,
|
||||||
createSuccessfulRemoteDataObject$
|
createSuccessfulRemoteDataObject$
|
||||||
} from '../../shared/remote-data.utils';
|
} from '../../shared/remote-data.utils';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
const mockItem: Item = Object.assign(new Item(), {
|
const mockItem: Item = Object.assign(new Item(), {
|
||||||
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||||
@@ -45,7 +46,14 @@ describe('FullItemPageComponent', () => {
|
|||||||
let comp: FullItemPageComponent;
|
let comp: FullItemPageComponent;
|
||||||
let fixture: ComponentFixture<FullItemPageComponent>;
|
let fixture: ComponentFixture<FullItemPageComponent>;
|
||||||
|
|
||||||
|
let authService: AuthService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
|
authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true),
|
||||||
|
setRedirectUrl: {}
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot({
|
imports: [TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
@@ -57,7 +65,8 @@ describe('FullItemPageComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{provide: ActivatedRoute, useValue: routeStub},
|
{provide: ActivatedRoute, useValue: routeStub},
|
||||||
{provide: ItemDataService, useValue: {}},
|
{provide: ItemDataService, useValue: {}},
|
||||||
{provide: MetadataService, useValue: metadataServiceStub}
|
{provide: MetadataService, useValue: metadataServiceStub},
|
||||||
|
{ provide: AuthService, useValue: authService },
|
||||||
],
|
],
|
||||||
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
@@ -15,6 +15,7 @@ import { MetadataService } from '../../core/metadata/metadata.service';
|
|||||||
|
|
||||||
import { fadeInOut } from '../../shared/animations/fade';
|
import { fadeInOut } from '../../shared/animations/fade';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
@@ -35,8 +36,8 @@ export class FullItemPageComponent extends ItemPageComponent implements OnInit {
|
|||||||
|
|
||||||
metadata$: Observable<MetadataMap>;
|
metadata$: Observable<MetadataMap>;
|
||||||
|
|
||||||
constructor(route: ActivatedRoute, router: Router, items: ItemDataService, metadataService: MetadataService) {
|
constructor(route: ActivatedRoute, router: Router, items: ItemDataService, metadataService: MetadataService, authService: AuthService) {
|
||||||
super(route, router, items, metadataService);
|
super(route, router, items, metadataService, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** AoT inheritance fix, will hopefully be resolved in the near future **/
|
/*** AoT inheritance fix, will hopefully be resolved in the near future **/
|
||||||
|
@@ -7,6 +7,7 @@ import { DsoPageFeatureGuard } from '../core/data/feature-authorization/feature-
|
|||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { AuthService } from '../core/auth/auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -17,8 +18,9 @@ import { of as observableOf } from 'rxjs';
|
|||||||
export class ItemPageAdministratorGuard extends DsoPageFeatureGuard<Item> {
|
export class ItemPageAdministratorGuard extends DsoPageFeatureGuard<Item> {
|
||||||
constructor(protected resolver: ItemPageResolver,
|
constructor(protected resolver: ItemPageResolver,
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router) {
|
protected router: Router,
|
||||||
super(resolver, authorizationService, router);
|
protected authService: AuthService) {
|
||||||
|
super(resolver, authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -19,6 +19,7 @@ import {
|
|||||||
createFailedRemoteDataObject$, createPendingRemoteDataObject$, createSuccessfulRemoteDataObject,
|
createFailedRemoteDataObject$, createPendingRemoteDataObject$, createSuccessfulRemoteDataObject,
|
||||||
createSuccessfulRemoteDataObject$
|
createSuccessfulRemoteDataObject$
|
||||||
} from '../../shared/remote-data.utils';
|
} from '../../shared/remote-data.utils';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
const mockItem: Item = Object.assign(new Item(), {
|
const mockItem: Item = Object.assign(new Item(), {
|
||||||
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||||
@@ -29,6 +30,7 @@ const mockItem: Item = Object.assign(new Item(), {
|
|||||||
describe('ItemPageComponent', () => {
|
describe('ItemPageComponent', () => {
|
||||||
let comp: ItemPageComponent;
|
let comp: ItemPageComponent;
|
||||||
let fixture: ComponentFixture<ItemPageComponent>;
|
let fixture: ComponentFixture<ItemPageComponent>;
|
||||||
|
let authService: AuthService;
|
||||||
|
|
||||||
const mockMetadataService = {
|
const mockMetadataService = {
|
||||||
/* tslint:disable:no-empty */
|
/* tslint:disable:no-empty */
|
||||||
@@ -40,6 +42,11 @@ describe('ItemPageComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
|
authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true),
|
||||||
|
setRedirectUrl: {}
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot({
|
imports: [TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
@@ -52,7 +59,8 @@ describe('ItemPageComponent', () => {
|
|||||||
{provide: ActivatedRoute, useValue: mockRoute},
|
{provide: ActivatedRoute, useValue: mockRoute},
|
||||||
{provide: ItemDataService, useValue: {}},
|
{provide: ItemDataService, useValue: {}},
|
||||||
{provide: MetadataService, useValue: mockMetadataService},
|
{provide: MetadataService, useValue: mockMetadataService},
|
||||||
{provide: Router, useValue: {}}
|
{provide: Router, useValue: {}},
|
||||||
|
{ provide: AuthService, useValue: authService },
|
||||||
],
|
],
|
||||||
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
@@ -11,8 +11,9 @@ import { Item } from '../../core/shared/item.model';
|
|||||||
import { MetadataService } from '../../core/metadata/metadata.service';
|
import { MetadataService } from '../../core/metadata/metadata.service';
|
||||||
|
|
||||||
import { fadeInOut } from '../../shared/animations/fade';
|
import { fadeInOut } from '../../shared/animations/fade';
|
||||||
import { redirectOn404Or401 } from '../../core/shared/operators';
|
import { redirectOn4xx } from '../../core/shared/operators';
|
||||||
import { ViewMode } from '../../core/shared/view-mode.model';
|
import { ViewMode } from '../../core/shared/view-mode.model';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
@@ -48,6 +49,7 @@ export class ItemPageComponent implements OnInit {
|
|||||||
private router: Router,
|
private router: Router,
|
||||||
private items: ItemDataService,
|
private items: ItemDataService,
|
||||||
private metadataService: MetadataService,
|
private metadataService: MetadataService,
|
||||||
|
private authService: AuthService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +58,7 @@ export class ItemPageComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.itemRD$ = this.route.data.pipe(
|
this.itemRD$ = this.route.data.pipe(
|
||||||
map((data) => data.dso as RemoteData<Item>),
|
map((data) => data.dso as RemoteData<Item>),
|
||||||
redirectOn404Or401(this.router)
|
redirectOn4xx(this.router, this.authService)
|
||||||
);
|
);
|
||||||
this.metadataService.processRemoteData(this.itemRD$);
|
this.metadataService.processRemoteData(this.itemRD$);
|
||||||
}
|
}
|
||||||
|
@@ -55,10 +55,10 @@ export function getDSORoute(dso: DSpaceObject): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UNAUTHORIZED_PATH = '401';
|
export const FORBIDDEN_PATH = '403';
|
||||||
|
|
||||||
export function getUnauthorizedRoute() {
|
export function getForbiddenRoute() {
|
||||||
return `/${UNAUTHORIZED_PATH}`;
|
return `/${FORBIDDEN_PATH}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PAGE_NOT_FOUND_PATH = '404';
|
export const PAGE_NOT_FOUND_PATH = '404';
|
||||||
|
@@ -5,16 +5,15 @@ import { AuthBlockingGuard } from './core/auth/auth-blocking.guard';
|
|||||||
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
||||||
import { AuthenticatedGuard } from './core/auth/authenticated.guard';
|
import { AuthenticatedGuard } from './core/auth/authenticated.guard';
|
||||||
import { SiteAdministratorGuard } from './core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
|
import { SiteAdministratorGuard } from './core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
|
||||||
import { UnauthorizedComponent } from './unauthorized/unauthorized.component';
|
|
||||||
import {
|
import {
|
||||||
UNAUTHORIZED_PATH,
|
|
||||||
WORKFLOW_ITEM_MODULE_PATH,
|
WORKFLOW_ITEM_MODULE_PATH,
|
||||||
FORGOT_PASSWORD_PATH,
|
FORGOT_PASSWORD_PATH,
|
||||||
REGISTER_PATH,
|
REGISTER_PATH,
|
||||||
PROFILE_MODULE_PATH,
|
PROFILE_MODULE_PATH,
|
||||||
ADMIN_MODULE_PATH,
|
ADMIN_MODULE_PATH,
|
||||||
BITSTREAM_MODULE_PATH,
|
BITSTREAM_MODULE_PATH,
|
||||||
INFO_MODULE_PATH
|
INFO_MODULE_PATH,
|
||||||
|
FORBIDDEN_PATH,
|
||||||
} from './app-routing-paths';
|
} from './app-routing-paths';
|
||||||
import { COLLECTION_MODULE_PATH } from './+collection-page/collection-page-routing-paths';
|
import { COLLECTION_MODULE_PATH } from './+collection-page/collection-page-routing-paths';
|
||||||
import { COMMUNITY_MODULE_PATH } from './+community-page/community-page-routing-paths';
|
import { COMMUNITY_MODULE_PATH } from './+community-page/community-page-routing-paths';
|
||||||
@@ -22,6 +21,7 @@ import { ITEM_MODULE_PATH } from './+item-page/item-page-routing-paths';
|
|||||||
import { ReloadGuard } from './core/reload/reload.guard';
|
import { ReloadGuard } from './core/reload/reload.guard';
|
||||||
import { EndUserAgreementCurrentUserGuard } from './core/end-user-agreement/end-user-agreement-current-user.guard';
|
import { EndUserAgreementCurrentUserGuard } from './core/end-user-agreement/end-user-agreement-current-user.guard';
|
||||||
import { SiteRegisterGuard } from './core/data/feature-authorization/feature-authorization-guard/site-register.guard';
|
import { SiteRegisterGuard } from './core/data/feature-authorization/feature-authorization-guard/site-register.guard';
|
||||||
|
import { ForbiddenComponent } from './forbidden/forbidden.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -68,7 +68,7 @@ import { SiteRegisterGuard } from './core/data/feature-authorization/feature-aut
|
|||||||
},
|
},
|
||||||
{ path: 'processes', loadChildren: './process-page/process-page.module#ProcessPageModule', canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] },
|
{ path: 'processes', loadChildren: './process-page/process-page.module#ProcessPageModule', canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] },
|
||||||
{ path: INFO_MODULE_PATH, loadChildren: './info/info.module#InfoModule' },
|
{ path: INFO_MODULE_PATH, loadChildren: './info/info.module#InfoModule' },
|
||||||
{ path: UNAUTHORIZED_PATH, component: UnauthorizedComponent },
|
{ path: FORBIDDEN_PATH, component: ForbiddenComponent },
|
||||||
{
|
{
|
||||||
path: 'statistics',
|
path: 'statistics',
|
||||||
loadChildren: './statistics-page/statistics-page-routing.module#StatisticsPageRoutingModule',
|
loadChildren: './statistics-page/statistics-page-routing.module#StatisticsPageRoutingModule',
|
||||||
|
@@ -41,7 +41,7 @@ import { SharedModule } from './shared/shared.module';
|
|||||||
import { BreadcrumbsComponent } from './breadcrumbs/breadcrumbs.component';
|
import { BreadcrumbsComponent } from './breadcrumbs/breadcrumbs.component';
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { UnauthorizedComponent } from './unauthorized/unauthorized.component';
|
import { ForbiddenComponent } from './forbidden/forbidden.component';
|
||||||
|
|
||||||
export function getBase() {
|
export function getBase() {
|
||||||
return environment.ui.nameSpace;
|
return environment.ui.nameSpace;
|
||||||
@@ -116,6 +116,8 @@ const DECLARATIONS = [
|
|||||||
NotificationComponent,
|
NotificationComponent,
|
||||||
NotificationsBoardComponent,
|
NotificationsBoardComponent,
|
||||||
SearchNavbarComponent,
|
SearchNavbarComponent,
|
||||||
|
BreadcrumbsComponent,
|
||||||
|
ForbiddenComponent,
|
||||||
];
|
];
|
||||||
|
|
||||||
const EXPORTS = [
|
const EXPORTS = [
|
||||||
@@ -133,8 +135,6 @@ const EXPORTS = [
|
|||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
...DECLARATIONS,
|
...DECLARATIONS,
|
||||||
BreadcrumbsComponent,
|
|
||||||
UnauthorizedComponent,
|
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
...EXPORTS
|
...EXPORTS
|
||||||
|
@@ -453,7 +453,7 @@ export class AuthService {
|
|||||||
* Clear redirect url
|
* Clear redirect url
|
||||||
*/
|
*/
|
||||||
clearRedirectUrl() {
|
clearRedirectUrl() {
|
||||||
this.store.dispatch(new SetRedirectUrlAction(''));
|
this.store.dispatch(new SetRedirectUrlAction(undefined));
|
||||||
this.storage.remove(REDIRECT_COOKIE);
|
this.storage.remove(REDIRECT_COOKIE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@ import { DSpaceObject } from '../../../shared/dspace-object.model';
|
|||||||
import { DsoPageFeatureGuard } from './dso-page-feature.guard';
|
import { DsoPageFeatureGuard } from './dso-page-feature.guard';
|
||||||
import { FeatureID } from '../feature-id';
|
import { FeatureID } from '../feature-id';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { AuthService } from '../../../auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test implementation of abstract class DsoPageAdministratorGuard
|
* Test implementation of abstract class DsoPageAdministratorGuard
|
||||||
@@ -15,8 +16,9 @@ class DsoPageFeatureGuardImpl extends DsoPageFeatureGuard<any> {
|
|||||||
constructor(protected resolver: Resolve<RemoteData<any>>,
|
constructor(protected resolver: Resolve<RemoteData<any>>,
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
|
protected authService: AuthService,
|
||||||
protected featureID: FeatureID) {
|
protected featureID: FeatureID) {
|
||||||
super(resolver, authorizationService, router);
|
super(resolver, authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
|
getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
|
||||||
@@ -28,6 +30,7 @@ describe('DsoPageAdministratorGuard', () => {
|
|||||||
let guard: DsoPageFeatureGuard<any>;
|
let guard: DsoPageFeatureGuard<any>;
|
||||||
let authorizationService: AuthorizationDataService;
|
let authorizationService: AuthorizationDataService;
|
||||||
let router: Router;
|
let router: Router;
|
||||||
|
let authService: AuthService;
|
||||||
let resolver: Resolve<RemoteData<any>>;
|
let resolver: Resolve<RemoteData<any>>;
|
||||||
let object: DSpaceObject;
|
let object: DSpaceObject;
|
||||||
|
|
||||||
@@ -45,7 +48,10 @@ describe('DsoPageAdministratorGuard', () => {
|
|||||||
resolver = jasmine.createSpyObj('resolver', {
|
resolver = jasmine.createSpyObj('resolver', {
|
||||||
resolve: createSuccessfulRemoteDataObject$(object)
|
resolve: createSuccessfulRemoteDataObject$(object)
|
||||||
});
|
});
|
||||||
guard = new DsoPageFeatureGuardImpl(resolver, authorizationService, router, undefined);
|
authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true)
|
||||||
|
});
|
||||||
|
guard = new DsoPageFeatureGuardImpl(resolver, authorizationService, router, authService, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@@ -6,6 +6,7 @@ import { getAllSucceededRemoteDataPayload } from '../../../shared/operators';
|
|||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { DSpaceObject } from '../../../shared/dspace-object.model';
|
import { DSpaceObject } from '../../../shared/dspace-object.model';
|
||||||
import { FeatureAuthorizationGuard } from './feature-authorization.guard';
|
import { FeatureAuthorizationGuard } from './feature-authorization.guard';
|
||||||
|
import { AuthService } from '../../../auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract Guard for preventing unauthorized access to {@link DSpaceObject} pages that require rights for a specific feature
|
* Abstract Guard for preventing unauthorized access to {@link DSpaceObject} pages that require rights for a specific feature
|
||||||
@@ -14,8 +15,9 @@ import { FeatureAuthorizationGuard } from './feature-authorization.guard';
|
|||||||
export abstract class DsoPageFeatureGuard<T extends DSpaceObject> extends FeatureAuthorizationGuard {
|
export abstract class DsoPageFeatureGuard<T extends DSpaceObject> extends FeatureAuthorizationGuard {
|
||||||
constructor(protected resolver: Resolve<RemoteData<T>>,
|
constructor(protected resolver: Resolve<RemoteData<T>>,
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router) {
|
protected router: Router,
|
||||||
super(authorizationService, router);
|
protected authService: AuthService) {
|
||||||
|
super(authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -4,6 +4,7 @@ import { FeatureID } from '../feature-id';
|
|||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { AuthService } from '../../../auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test implementation of abstract class FeatureAuthorizationGuard
|
* Test implementation of abstract class FeatureAuthorizationGuard
|
||||||
@@ -12,10 +13,11 @@ import { Observable } from 'rxjs/internal/Observable';
|
|||||||
class FeatureAuthorizationGuardImpl extends FeatureAuthorizationGuard {
|
class FeatureAuthorizationGuardImpl extends FeatureAuthorizationGuard {
|
||||||
constructor(protected authorizationService: AuthorizationDataService,
|
constructor(protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
|
protected authService: AuthService,
|
||||||
protected featureId: FeatureID,
|
protected featureId: FeatureID,
|
||||||
protected objectUrl: string,
|
protected objectUrl: string,
|
||||||
protected ePersonUuid: string) {
|
protected ePersonUuid: string) {
|
||||||
super(authorizationService, router);
|
super(authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
|
getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
|
||||||
@@ -35,6 +37,7 @@ describe('FeatureAuthorizationGuard', () => {
|
|||||||
let guard: FeatureAuthorizationGuard;
|
let guard: FeatureAuthorizationGuard;
|
||||||
let authorizationService: AuthorizationDataService;
|
let authorizationService: AuthorizationDataService;
|
||||||
let router: Router;
|
let router: Router;
|
||||||
|
let authService: AuthService;
|
||||||
|
|
||||||
let featureId: FeatureID;
|
let featureId: FeatureID;
|
||||||
let objectUrl: string;
|
let objectUrl: string;
|
||||||
@@ -51,7 +54,10 @@ describe('FeatureAuthorizationGuard', () => {
|
|||||||
router = jasmine.createSpyObj('router', {
|
router = jasmine.createSpyObj('router', {
|
||||||
parseUrl: {}
|
parseUrl: {}
|
||||||
});
|
});
|
||||||
guard = new FeatureAuthorizationGuardImpl(authorizationService, router, featureId, objectUrl, ePersonUuid);
|
authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true)
|
||||||
|
});
|
||||||
|
guard = new FeatureAuthorizationGuardImpl(authorizationService, router, authService, featureId, objectUrl, ePersonUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -60,7 +66,7 @@ describe('FeatureAuthorizationGuard', () => {
|
|||||||
|
|
||||||
describe('canActivate', () => {
|
describe('canActivate', () => {
|
||||||
it('should call authorizationService.isAuthenticated with the appropriate arguments', () => {
|
it('should call authorizationService.isAuthenticated with the appropriate arguments', () => {
|
||||||
guard.canActivate(undefined, undefined).subscribe();
|
guard.canActivate(undefined, { url: 'current-url' } as any).subscribe();
|
||||||
expect(authorizationService.isAuthorized).toHaveBeenCalledWith(featureId, objectUrl, ePersonUuid);
|
expect(authorizationService.isAuthorized).toHaveBeenCalledWith(featureId, objectUrl, ePersonUuid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -8,9 +8,10 @@ import {
|
|||||||
import { AuthorizationDataService } from '../authorization-data.service';
|
import { AuthorizationDataService } from '../authorization-data.service';
|
||||||
import { FeatureID } from '../feature-id';
|
import { FeatureID } from '../feature-id';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { returnUnauthorizedUrlTreeOnFalse } from '../../../shared/operators';
|
import { returnForbiddenUrlTreeOrLoginOnFalse } from '../../../shared/operators';
|
||||||
import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
|
import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
|
||||||
import { switchMap } from 'rxjs/operators';
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
import { AuthService } from '../../../auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract Guard for preventing unauthorized activating and loading of routes when a user
|
* Abstract Guard for preventing unauthorized activating and loading of routes when a user
|
||||||
@@ -19,7 +20,8 @@ import { switchMap } from 'rxjs/operators';
|
|||||||
*/
|
*/
|
||||||
export abstract class FeatureAuthorizationGuard implements CanActivate {
|
export abstract class FeatureAuthorizationGuard implements CanActivate {
|
||||||
constructor(protected authorizationService: AuthorizationDataService,
|
constructor(protected authorizationService: AuthorizationDataService,
|
||||||
protected router: Router) {
|
protected router: Router,
|
||||||
|
protected authService: AuthService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,7 +31,7 @@ export abstract class FeatureAuthorizationGuard implements CanActivate {
|
|||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
|
||||||
return observableCombineLatest(this.getFeatureID(route, state), this.getObjectUrl(route, state), this.getEPersonUuid(route, state)).pipe(
|
return observableCombineLatest(this.getFeatureID(route, state), this.getObjectUrl(route, state), this.getEPersonUuid(route, state)).pipe(
|
||||||
switchMap(([featureID, objectUrl, ePersonUuid]) => this.authorizationService.isAuthorized(featureID, objectUrl, ePersonUuid)),
|
switchMap(([featureID, objectUrl, ePersonUuid]) => this.authorizationService.isAuthorized(featureID, objectUrl, ePersonUuid)),
|
||||||
returnUnauthorizedUrlTreeOnFalse(this.router)
|
returnForbiddenUrlTreeOrLoginOnFalse(this.router, this.authService, state.url)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@ import { AuthorizationDataService } from '../authorization-data.service';
|
|||||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { AuthService } from '../../../auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent unauthorized activating and loading of routes when the current authenticated user doesn't have administrator
|
* Prevent unauthorized activating and loading of routes when the current authenticated user doesn't have administrator
|
||||||
@@ -14,8 +15,8 @@ import { Observable } from 'rxjs/internal/Observable';
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class SiteAdministratorGuard extends FeatureAuthorizationGuard {
|
export class SiteAdministratorGuard extends FeatureAuthorizationGuard {
|
||||||
constructor(protected authorizationService: AuthorizationDataService, protected router: Router) {
|
constructor(protected authorizationService: AuthorizationDataService, protected router: Router, protected authService: AuthService) {
|
||||||
super(authorizationService, router);
|
super(authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -5,6 +5,7 @@ import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/ro
|
|||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { FeatureID } from '../feature-id';
|
import { FeatureID } from '../feature-id';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { AuthService } from '../../../auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent unauthorized activating and loading of routes when the current authenticated user doesn't have registration
|
* Prevent unauthorized activating and loading of routes when the current authenticated user doesn't have registration
|
||||||
@@ -14,8 +15,8 @@ import { of as observableOf } from 'rxjs';
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class SiteRegisterGuard extends FeatureAuthorizationGuard {
|
export class SiteRegisterGuard extends FeatureAuthorizationGuard {
|
||||||
constructor(protected authorizationService: AuthorizationDataService, protected router: Router) {
|
constructor(protected authorizationService: AuthorizationDataService, protected router: Router, protected authService: AuthService) {
|
||||||
super(authorizationService, router);
|
super(authorizationService, router, authService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -24,6 +24,10 @@ export class ServerResponseService {
|
|||||||
return this.setStatus(401, message)
|
return this.setStatus(401, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setForbidden(message = 'Forbidden'): this {
|
||||||
|
return this.setStatus(403, message)
|
||||||
|
}
|
||||||
|
|
||||||
setNotFound(message = 'Not found'): this {
|
setNotFound(message = 'Not found'): this {
|
||||||
return this.setStatus(404, message)
|
return this.setStatus(404, message)
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@ import {
|
|||||||
getResourceLinksFromResponse,
|
getResourceLinksFromResponse,
|
||||||
getResponseFromEntry,
|
getResponseFromEntry,
|
||||||
getSucceededRemoteData,
|
getSucceededRemoteData,
|
||||||
redirectOn404Or401
|
redirectOn4xx
|
||||||
} from './operators';
|
} from './operators';
|
||||||
import { RemoteData } from '../data/remote-data';
|
import { RemoteData } from '../data/remote-data';
|
||||||
import { RemoteDataError } from '../data/remote-data-error';
|
import { RemoteDataError } from '../data/remote-data-error';
|
||||||
@@ -200,39 +200,67 @@ describe('Core Module - RxJS Operators', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('redirectOn404Or401', () => {
|
describe('redirectOn4xx', () => {
|
||||||
let router;
|
let router;
|
||||||
|
let authService;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
router = jasmine.createSpyObj('router', ['navigateByUrl']);
|
router = jasmine.createSpyObj('router', ['navigateByUrl']);
|
||||||
|
authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true),
|
||||||
|
setRedirectUrl: {}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call navigateByUrl to a 404 page, when the remote data contains a 404 error', () => {
|
it('should call navigateByUrl to a 404 page, when the remote data contains a 404 error', () => {
|
||||||
const testRD = createFailedRemoteDataObject(undefined, new RemoteDataError(404, 'Not Found', 'Object was not found'));
|
const testRD = createFailedRemoteDataObject(undefined, new RemoteDataError(404, 'Not Found', 'Object was not found'));
|
||||||
|
|
||||||
observableOf(testRD).pipe(redirectOn404Or401(router)).subscribe();
|
observableOf(testRD).pipe(redirectOn4xx(router, authService)).subscribe();
|
||||||
expect(router.navigateByUrl).toHaveBeenCalledWith('/404', { skipLocationChange: true });
|
expect(router.navigateByUrl).toHaveBeenCalledWith('/404', { skipLocationChange: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call navigateByUrl to a 401 page, when the remote data contains a 401 error', () => {
|
it('should call navigateByUrl to a 403 page, when the remote data contains a 403 error', () => {
|
||||||
const testRD = createFailedRemoteDataObject(undefined, new RemoteDataError(401, 'Unauthorized', 'The current user is unauthorized'));
|
const testRD = createFailedRemoteDataObject(undefined, new RemoteDataError(403, 'Forbidden', 'Forbidden access'));
|
||||||
|
|
||||||
observableOf(testRD).pipe(redirectOn404Or401(router)).subscribe();
|
observableOf(testRD).pipe(redirectOn4xx(router, authService)).subscribe();
|
||||||
expect(router.navigateByUrl).toHaveBeenCalledWith('/401', { skipLocationChange: true });
|
expect(router.navigateByUrl).toHaveBeenCalledWith('/403', { skipLocationChange: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not call navigateByUrl to a 404 or 401 page, when the remote data contains another error than a 404 or 401', () => {
|
it('should not call navigateByUrl to a 404, 403 or 401 page, when the remote data contains another error than a 404, 403 or 401', () => {
|
||||||
const testRD = createFailedRemoteDataObject(undefined, new RemoteDataError(500, 'Server Error', 'Something went wrong'));
|
const testRD = createFailedRemoteDataObject(undefined, new RemoteDataError(500, 'Server Error', 'Something went wrong'));
|
||||||
|
|
||||||
observableOf(testRD).pipe(redirectOn404Or401(router)).subscribe();
|
observableOf(testRD).pipe(redirectOn4xx(router, authService)).subscribe();
|
||||||
expect(router.navigateByUrl).not.toHaveBeenCalled();
|
expect(router.navigateByUrl).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not call navigateByUrl to a 404 or 401 page, when the remote data contains no error', () => {
|
it('should not call navigateByUrl to a 404, 403 or 401 page, when the remote data contains no error', () => {
|
||||||
const testRD = createSuccessfulRemoteDataObject(undefined);
|
const testRD = createSuccessfulRemoteDataObject(undefined);
|
||||||
|
|
||||||
observableOf(testRD).pipe(redirectOn404Or401(router)).subscribe();
|
observableOf(testRD).pipe(redirectOn4xx(router, authService)).subscribe();
|
||||||
expect(router.navigateByUrl).not.toHaveBeenCalled();
|
expect(router.navigateByUrl).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when the user is not authenticated', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
(authService.isAuthenticated as jasmine.Spy).and.returnValue(observableOf(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the redirect url and navigate to login when the remote data contains a 401 error', () => {
|
||||||
|
const testRD = createFailedRemoteDataObject(undefined, new RemoteDataError(401, 'Unauthorized', 'The current user is unauthorized'));
|
||||||
|
|
||||||
|
observableOf(testRD).pipe(redirectOn4xx(router, authService)).subscribe();
|
||||||
|
expect(authService.setRedirectUrl).toHaveBeenCalled();
|
||||||
|
expect(router.navigateByUrl).toHaveBeenCalledWith('login');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the redirect url and navigate to login when the remote data contains a 403 error', () => {
|
||||||
|
const testRD = createFailedRemoteDataObject(undefined, new RemoteDataError(403, 'Forbidden', 'Forbidden access'));
|
||||||
|
|
||||||
|
observableOf(testRD).pipe(redirectOn4xx(router, authService)).subscribe();
|
||||||
|
expect(authService.setRedirectUrl).toHaveBeenCalled();
|
||||||
|
expect(router.navigateByUrl).toHaveBeenCalledWith('login');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getResponseFromEntry', () => {
|
describe('getResponseFromEntry', () => {
|
||||||
|
@@ -13,8 +13,9 @@ import { MetadataField } from '../metadata/metadata-field.model';
|
|||||||
import { MetadataSchema } from '../metadata/metadata-schema.model';
|
import { MetadataSchema } from '../metadata/metadata-schema.model';
|
||||||
import { BrowseDefinition } from './browse-definition.model';
|
import { BrowseDefinition } from './browse-definition.model';
|
||||||
import { DSpaceObject } from './dspace-object.model';
|
import { DSpaceObject } from './dspace-object.model';
|
||||||
import { getPageNotFoundRoute, getUnauthorizedRoute } from '../../app-routing-paths';
|
import { getForbiddenRoute, getPageNotFoundRoute } from '../../app-routing-paths';
|
||||||
import { getEndUserAgreementPath } from '../../info/info-routing-paths';
|
import { getEndUserAgreementPath } from '../../info/info-routing-paths';
|
||||||
|
import { AuthService } from '../auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file contains custom RxJS operators that can be used in multiple places
|
* This file contains custom RxJS operators that can be used in multiple places
|
||||||
@@ -178,29 +179,47 @@ export const getAllSucceededRemoteListPayload = () =>
|
|||||||
* Operator that checks if a remote data object returned a 401 or 404 error
|
* Operator that checks if a remote data object returned a 401 or 404 error
|
||||||
* When it does contain such an error, it will redirect the user to the related error page, without altering the current URL
|
* When it does contain such an error, it will redirect the user to the related error page, without altering the current URL
|
||||||
* @param router The router used to navigate to a new page
|
* @param router The router used to navigate to a new page
|
||||||
|
* @param authService Service to check if the user is authenticated
|
||||||
*/
|
*/
|
||||||
export const redirectOn404Or401 = (router: Router) =>
|
export const redirectOn4xx = (router: Router, authService: AuthService) =>
|
||||||
<T>(source: Observable<RemoteData<T>>): Observable<RemoteData<T>> =>
|
<T>(source: Observable<RemoteData<T>>): Observable<RemoteData<T>> =>
|
||||||
source.pipe(
|
observableCombineLatest(source, authService.isAuthenticated()).pipe(
|
||||||
tap((rd: RemoteData<T>) => {
|
map(([rd, isAuthenticated]: [RemoteData<T>, boolean]) => {
|
||||||
if (rd.hasFailed) {
|
if (rd.hasFailed) {
|
||||||
if (rd.error.statusCode === 404) {
|
if (rd.error.statusCode === 404) {
|
||||||
router.navigateByUrl(getPageNotFoundRoute(), {skipLocationChange: true});
|
router.navigateByUrl(getPageNotFoundRoute(), {skipLocationChange: true});
|
||||||
} else if (rd.error.statusCode === 401) {
|
} else if (rd.error.statusCode === 403 || rd.error.statusCode === 401) {
|
||||||
router.navigateByUrl(getUnauthorizedRoute(), {skipLocationChange: true});
|
if (isAuthenticated) {
|
||||||
|
router.navigateByUrl(getForbiddenRoute(), {skipLocationChange: true});
|
||||||
|
} else {
|
||||||
|
authService.setRedirectUrl(router.url);
|
||||||
|
router.navigateByUrl('login');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return rd;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Operator that returns a UrlTree to the unauthorized page when the boolean received is false
|
* Operator that returns a UrlTree to a forbidden page or the login page when the boolean received is false
|
||||||
* @param router
|
* @param router The router used to navigate to a forbidden page
|
||||||
|
* @param authService The AuthService used to determine whether or not the user is logged in
|
||||||
|
* @param redirectUrl The URL to redirect back to after logging in
|
||||||
*/
|
*/
|
||||||
export const returnUnauthorizedUrlTreeOnFalse = (router: Router) =>
|
export const returnForbiddenUrlTreeOrLoginOnFalse = (router: Router, authService: AuthService, redirectUrl: string) =>
|
||||||
(source: Observable<boolean>): Observable<boolean | UrlTree> =>
|
(source: Observable<boolean>): Observable<boolean | UrlTree> =>
|
||||||
source.pipe(
|
observableCombineLatest(source, authService.isAuthenticated()).pipe(
|
||||||
map((authorized: boolean) => {
|
map(([authorized, authenticated]: [boolean, boolean]) => {
|
||||||
return authorized ? authorized : router.parseUrl(getUnauthorizedRoute())
|
if (authorized) {
|
||||||
|
return authorized;
|
||||||
|
} else {
|
||||||
|
if (authenticated) {
|
||||||
|
return router.parseUrl(getForbiddenRoute());
|
||||||
|
} else {
|
||||||
|
authService.setRedirectUrl(redirectUrl);
|
||||||
|
return router.parseUrl('login');
|
||||||
|
}
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
10
src/app/forbidden/forbidden.component.html
Normal file
10
src/app/forbidden/forbidden.component.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<div class="forbidden container">
|
||||||
|
<h1>403</h1>
|
||||||
|
<h2><small>{{"403.forbidden" | translate}}</small></h2>
|
||||||
|
<br/>
|
||||||
|
<p>{{"403.help" | translate}}</p>
|
||||||
|
<br/>
|
||||||
|
<p class="text-center">
|
||||||
|
<a routerLink="/home" class="btn btn-primary">{{"403.link.home-page" | translate}}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
@@ -3,30 +3,30 @@ import { AuthService } from '../core/auth/auth.service';
|
|||||||
import { ServerResponseService } from '../core/services/server-response.service';
|
import { ServerResponseService } from '../core/services/server-response.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component representing the `Unauthorized` DSpace page.
|
* This component representing the `Forbidden` DSpace page.
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-unauthorized',
|
selector: 'ds-forbidden',
|
||||||
templateUrl: './unauthorized.component.html',
|
templateUrl: './forbidden.component.html',
|
||||||
styleUrls: ['./unauthorized.component.scss']
|
styleUrls: ['./forbidden.component.scss']
|
||||||
})
|
})
|
||||||
export class UnauthorizedComponent implements OnInit {
|
export class ForbiddenComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize instance variables
|
* Initialize instance variables
|
||||||
*
|
*
|
||||||
* @param {AuthService} authservice
|
* @param {AuthService} authService
|
||||||
* @param {ServerResponseService} responseService
|
* @param {ServerResponseService} responseService
|
||||||
*/
|
*/
|
||||||
constructor(private authservice: AuthService, private responseService: ServerResponseService) {
|
constructor(private authService: AuthService, private responseService: ServerResponseService) {
|
||||||
this.responseService.setUnauthorized();
|
this.responseService.setForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove redirect url from the state
|
* Remove redirect url from the state
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.authservice.clearRedirectUrl();
|
this.authService.clearRedirectUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -12,7 +12,7 @@ import { ProcessDataService } from '../../core/data/processes/process-data.servi
|
|||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { Bitstream } from '../../core/shared/bitstream.model';
|
import { Bitstream } from '../../core/shared/bitstream.model';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { getFirstSucceededRemoteDataPayload, redirectOn404Or401 } from '../../core/shared/operators';
|
import { getFirstSucceededRemoteDataPayload, redirectOn4xx } from '../../core/shared/operators';
|
||||||
import { URLCombiner } from '../../core/url-combiner/url-combiner';
|
import { URLCombiner } from '../../core/url-combiner/url-combiner';
|
||||||
import { AlertType } from '../../shared/alert/aletr-type';
|
import { AlertType } from '../../shared/alert/aletr-type';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
@@ -84,7 +84,7 @@ export class ProcessDetailComponent implements OnInit {
|
|||||||
map((data) => {
|
map((data) => {
|
||||||
return data.process as RemoteData<Process>
|
return data.process as RemoteData<Process>
|
||||||
}),
|
}),
|
||||||
redirectOn404Or401(this.router)
|
redirectOn4xx(this.router, this.authService)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.filesRD$ = this.processRD$.pipe(
|
this.filesRD$ = this.processRD$.pipe(
|
||||||
|
@@ -12,4 +12,11 @@ export class AuthServiceMock {
|
|||||||
public getShortlivedToken(): Observable<string> {
|
public getShortlivedToken(): Observable<string> {
|
||||||
return observableOf('token');
|
return observableOf('token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isAuthenticated(): Observable<boolean> {
|
||||||
|
return observableOf(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setRedirectUrl(url: string) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ import { SharedModule } from '../../shared/shared.module';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
describe('CollectionStatisticsPageComponent', () => {
|
describe('CollectionStatisticsPageComponent', () => {
|
||||||
|
|
||||||
@@ -59,6 +60,11 @@ describe('CollectionStatisticsPageComponent', () => {
|
|||||||
getName: () => observableOf('test dso name'),
|
getName: () => observableOf('test dso name'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true),
|
||||||
|
setRedirectUrl: {}
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
@@ -75,6 +81,7 @@ describe('CollectionStatisticsPageComponent', () => {
|
|||||||
{ provide: UsageReportService, useValue: usageReportService },
|
{ provide: UsageReportService, useValue: usageReportService },
|
||||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||||
{ provide: DSONameService, useValue: nameService },
|
{ provide: DSONameService, useValue: nameService },
|
||||||
|
{ provide: AuthService, useValue: authService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
@@ -4,6 +4,7 @@ import { UsageReportService } from '../../core/statistics/usage-report-data.serv
|
|||||||
import { ActivatedRoute , Router} from '@angular/router';
|
import { ActivatedRoute , Router} from '@angular/router';
|
||||||
import { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component representing the statistics page for a collection.
|
* Component representing the statistics page for a collection.
|
||||||
@@ -30,12 +31,14 @@ export class CollectionStatisticsPageComponent extends StatisticsPageComponent<C
|
|||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected usageReportService: UsageReportService,
|
protected usageReportService: UsageReportService,
|
||||||
protected nameService: DSONameService,
|
protected nameService: DSONameService,
|
||||||
|
protected authService: AuthService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
route,
|
route,
|
||||||
router,
|
router,
|
||||||
usageReportService,
|
usageReportService,
|
||||||
nameService,
|
nameService,
|
||||||
|
authService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ import { SharedModule } from '../../shared/shared.module';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
describe('CommunityStatisticsPageComponent', () => {
|
describe('CommunityStatisticsPageComponent', () => {
|
||||||
|
|
||||||
@@ -59,6 +60,11 @@ describe('CommunityStatisticsPageComponent', () => {
|
|||||||
getName: () => observableOf('test dso name'),
|
getName: () => observableOf('test dso name'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true),
|
||||||
|
setRedirectUrl: {}
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
@@ -75,6 +81,7 @@ describe('CommunityStatisticsPageComponent', () => {
|
|||||||
{ provide: UsageReportService, useValue: usageReportService },
|
{ provide: UsageReportService, useValue: usageReportService },
|
||||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||||
{ provide: DSONameService, useValue: nameService },
|
{ provide: DSONameService, useValue: nameService },
|
||||||
|
{ provide: AuthService, useValue: authService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
@@ -4,6 +4,7 @@ import { UsageReportService } from '../../core/statistics/usage-report-data.serv
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../core/shared/community.model';
|
||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component representing the statistics page for a community.
|
* Component representing the statistics page for a community.
|
||||||
@@ -30,12 +31,14 @@ export class CommunityStatisticsPageComponent extends StatisticsPageComponent<Co
|
|||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected usageReportService: UsageReportService,
|
protected usageReportService: UsageReportService,
|
||||||
protected nameService: DSONameService,
|
protected nameService: DSONameService,
|
||||||
|
protected authService: AuthService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
route,
|
route,
|
||||||
router,
|
router,
|
||||||
usageReportService,
|
usageReportService,
|
||||||
nameService,
|
nameService,
|
||||||
|
authService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ import { SharedModule } from '../../shared/shared.module';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
describe('ItemStatisticsPageComponent', () => {
|
describe('ItemStatisticsPageComponent', () => {
|
||||||
|
|
||||||
@@ -59,6 +60,11 @@ describe('ItemStatisticsPageComponent', () => {
|
|||||||
getName: () => observableOf('test dso name'),
|
getName: () => observableOf('test dso name'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true),
|
||||||
|
setRedirectUrl: {}
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
@@ -75,6 +81,7 @@ describe('ItemStatisticsPageComponent', () => {
|
|||||||
{ provide: UsageReportService, useValue: usageReportService },
|
{ provide: UsageReportService, useValue: usageReportService },
|
||||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||||
{ provide: DSONameService, useValue: nameService },
|
{ provide: DSONameService, useValue: nameService },
|
||||||
|
{ provide: AuthService, useValue: authService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
@@ -4,6 +4,7 @@ import { UsageReportService } from '../../core/statistics/usage-report-data.serv
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Item } from '../../core/shared/item.model';
|
import { Item } from '../../core/shared/item.model';
|
||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component representing the statistics page for an item.
|
* Component representing the statistics page for an item.
|
||||||
@@ -31,12 +32,14 @@ export class ItemStatisticsPageComponent extends StatisticsPageComponent<Item> {
|
|||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected usageReportService: UsageReportService,
|
protected usageReportService: UsageReportService,
|
||||||
protected nameService: DSONameService,
|
protected nameService: DSONameService,
|
||||||
|
protected authService: AuthService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
route,
|
route,
|
||||||
router,
|
router,
|
||||||
usageReportService,
|
usageReportService,
|
||||||
nameService,
|
nameService,
|
||||||
|
authService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||||
import { SiteDataService } from '../../core/data/site-data.service';
|
import { SiteDataService } from '../../core/data/site-data.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
describe('SiteStatisticsPageComponent', () => {
|
describe('SiteStatisticsPageComponent', () => {
|
||||||
|
|
||||||
@@ -55,6 +56,11 @@ describe('SiteStatisticsPageComponent', () => {
|
|||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const authService = jasmine.createSpyObj('authService', {
|
||||||
|
isAuthenticated: observableOf(true),
|
||||||
|
setRedirectUrl: {}
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
@@ -72,6 +78,7 @@ describe('SiteStatisticsPageComponent', () => {
|
|||||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||||
{ provide: DSONameService, useValue: nameService },
|
{ provide: DSONameService, useValue: nameService },
|
||||||
{ provide: SiteDataService, useValue: siteService },
|
{ provide: SiteDataService, useValue: siteService },
|
||||||
|
{ provide: AuthService, useValue: authService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
@@ -6,6 +6,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||||||
import { Site } from '../../core/shared/site.model';
|
import { Site } from '../../core/shared/site.model';
|
||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component representing the site-wide statistics page.
|
* Component representing the site-wide statistics page.
|
||||||
@@ -30,12 +31,14 @@ export class SiteStatisticsPageComponent extends StatisticsPageComponent<Site> {
|
|||||||
protected usageReportService: UsageReportService,
|
protected usageReportService: UsageReportService,
|
||||||
protected nameService: DSONameService,
|
protected nameService: DSONameService,
|
||||||
protected siteService: SiteDataService,
|
protected siteService: SiteDataService,
|
||||||
|
protected authService: AuthService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
route,
|
route,
|
||||||
router,
|
router,
|
||||||
usageReportService,
|
usageReportService,
|
||||||
nameService,
|
nameService,
|
||||||
|
authService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,10 +4,11 @@ import { UsageReportService } from '../../core/statistics/usage-report-data.serv
|
|||||||
import { map, switchMap } from 'rxjs/operators';
|
import { map, switchMap } from 'rxjs/operators';
|
||||||
import { UsageReport } from '../../core/statistics/models/usage-report.model';
|
import { UsageReport } from '../../core/statistics/models/usage-report.model';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { getRemoteDataPayload, getSucceededRemoteData, redirectOn404Or401 } from '../../core/shared/operators';
|
import { getRemoteDataPayload, getSucceededRemoteData, redirectOn4xx } from '../../core/shared/operators';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing an abstract statistics page component.
|
* Class representing an abstract statistics page component.
|
||||||
@@ -36,6 +37,7 @@ export abstract class StatisticsPageComponent<T extends DSpaceObject> implements
|
|||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected usageReportService: UsageReportService,
|
protected usageReportService: UsageReportService,
|
||||||
protected nameService: DSONameService,
|
protected nameService: DSONameService,
|
||||||
|
protected authService: AuthService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +57,7 @@ export abstract class StatisticsPageComponent<T extends DSpaceObject> implements
|
|||||||
protected getScope$(): Observable<DSpaceObject> {
|
protected getScope$(): Observable<DSpaceObject> {
|
||||||
return this.route.data.pipe(
|
return this.route.data.pipe(
|
||||||
map((data) => data.scope as RemoteData<T>),
|
map((data) => data.scope as RemoteData<T>),
|
||||||
redirectOn404Or401(this.router),
|
redirectOn4xx(this.router, this.authService),
|
||||||
getSucceededRemoteData(),
|
getSucceededRemoteData(),
|
||||||
getRemoteDataPayload(),
|
getRemoteDataPayload(),
|
||||||
);
|
);
|
||||||
|
@@ -1,10 +0,0 @@
|
|||||||
<div class="unauthorized container">
|
|
||||||
<h1>401</h1>
|
|
||||||
<h2><small>{{"401.unauthorized" | translate}}</small></h2>
|
|
||||||
<br/>
|
|
||||||
<p>{{"401.help" | translate}}</p>
|
|
||||||
<br/>
|
|
||||||
<p class="text-center">
|
|
||||||
<a routerLink="/home" class="btn btn-primary">{{"401.link.home-page" | translate}}</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
@@ -8,6 +8,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"403.help": "You don't have permission to access this page. You can use the button below to get back to the home page.",
|
||||||
|
|
||||||
|
"403.link.home-page": "Take me to the home page",
|
||||||
|
|
||||||
|
"403.forbidden": "forbidden",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ",
|
"404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ",
|
||||||
|
|
||||||
"404.link.home-page": "Take me to the home page",
|
"404.link.home-page": "Take me to the home page",
|
||||||
|
Reference in New Issue
Block a user