71764: Refactor DsoPageAdministratorGuard to more abstract DsoPageFeatureGuard and add implementations for WithdrawItem / ReinstateItem guards

This commit is contained in:
Kristof De Langhe
2020-07-10 12:08:48 +02:00
parent 9a666731e6
commit 02fb4a4e4e
9 changed files with 125 additions and 33 deletions

View File

@@ -1,9 +1,12 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Router } from '@angular/router'; import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { DsoPageAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-administrator.guard';
import { Collection } from '../core/shared/collection.model'; import { Collection } from '../core/shared/collection.model';
import { CollectionPageResolver } from './collection-page.resolver'; import { CollectionPageResolver } from './collection-page.resolver';
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
import { of as observableOf } from 'rxjs';
import { DsoPageFeatureGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
import { Observable } from 'rxjs/internal/Observable';
import { FeatureID } from '../core/data/feature-authorization/feature-id';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -11,10 +14,17 @@ import { AuthorizationDataService } from '../core/data/feature-authorization/aut
/** /**
* Guard for preventing unauthorized access to certain {@link Collection} pages requiring administrator rights * Guard for preventing unauthorized access to certain {@link Collection} pages requiring administrator rights
*/ */
export class CollectionPageAdministratorGuard extends DsoPageAdministratorGuard<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); super(resolver, authorizationService, router);
} }
/**
* Check administrator authorization rights
*/
getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
return observableOf(FeatureID.AdministratorOf);
}
} }

View File

@@ -1,9 +1,12 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Router } from '@angular/router'; import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { DsoPageAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-administrator.guard';
import { Community } from '../core/shared/community.model'; import { Community } from '../core/shared/community.model';
import { CommunityPageResolver } from './community-page.resolver'; import { CommunityPageResolver } from './community-page.resolver';
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
import { of as observableOf } from 'rxjs';
import { DsoPageFeatureGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
import { Observable } from 'rxjs/internal/Observable';
import { FeatureID } from '../core/data/feature-authorization/feature-id';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -11,10 +14,17 @@ import { AuthorizationDataService } from '../core/data/feature-authorization/aut
/** /**
* Guard for preventing unauthorized access to certain {@link Community} pages requiring administrator rights * Guard for preventing unauthorized access to certain {@link Community} pages requiring administrator rights
*/ */
export class CommunityPageAdministratorGuard extends DsoPageAdministratorGuard<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); super(resolver, authorizationService, router);
} }
/**
* Check administrator authorization rights
*/
getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
return observableOf(FeatureID.AdministratorOf);
}
} }

View File

@@ -20,6 +20,8 @@ import { ResourcePolicyResolver } from '../../shared/resource-policies/resolvers
import { ResourcePolicyCreateComponent } from '../../shared/resource-policies/create/resource-policy-create.component'; import { ResourcePolicyCreateComponent } from '../../shared/resource-policies/create/resource-policy-create.component';
import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit/resource-policy-edit.component'; import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit/resource-policy-edit.component';
import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service'; import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service';
import { ItemPageReinstateGuard } from './item-page-reinstate.guard';
import { ItemPageWithdrawGuard } from './item-page-withdraw.guard';
export const ITEM_EDIT_WITHDRAW_PATH = 'withdraw'; export const ITEM_EDIT_WITHDRAW_PATH = 'withdraw';
export const ITEM_EDIT_REINSTATE_PATH = 'reinstate'; export const ITEM_EDIT_REINSTATE_PATH = 'reinstate';
@@ -97,10 +99,12 @@ export const ITEM_EDIT_AUTHORIZATIONS_PATH = 'authorizations';
{ {
path: ITEM_EDIT_WITHDRAW_PATH, path: ITEM_EDIT_WITHDRAW_PATH,
component: ItemWithdrawComponent, component: ItemWithdrawComponent,
canActivate: [ItemPageWithdrawGuard]
}, },
{ {
path: ITEM_EDIT_REINSTATE_PATH, path: ITEM_EDIT_REINSTATE_PATH,
component: ItemReinstateComponent, component: ItemReinstateComponent,
canActivate: [ItemPageReinstateGuard]
}, },
{ {
path: ITEM_EDIT_PRIVATE_PATH, path: ITEM_EDIT_PRIVATE_PATH,
@@ -153,7 +157,9 @@ export const ITEM_EDIT_AUTHORIZATIONS_PATH = 'authorizations';
I18nBreadcrumbResolver, I18nBreadcrumbResolver,
I18nBreadcrumbsService, I18nBreadcrumbsService,
ResourcePolicyResolver, ResourcePolicyResolver,
ResourcePolicyTargetResolver ResourcePolicyTargetResolver,
ItemPageReinstateGuard,
ItemPageWithdrawGuard
] ]
}) })
export class EditItemPageRoutingModule { export class EditItemPageRoutingModule {

View File

@@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import { DsoPageFeatureGuard } from '../../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
import { Item } from '../../core/shared/item.model';
import { ItemPageResolver } from '../item-page.resolver';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/internal/Observable';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { of as observableOf } from 'rxjs';
@Injectable({
providedIn: 'root'
})
/**
* Guard for preventing unauthorized access to certain {@link Item} pages requiring reinstate rights
*/
export class ItemPageReinstateGuard extends DsoPageFeatureGuard<Item> {
constructor(protected resolver: ItemPageResolver,
protected authorizationService: AuthorizationDataService,
protected router: Router) {
super(resolver, authorizationService, router);
}
/**
* Check reinstate authorization rights
*/
getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
return observableOf(FeatureID.ReinstateItem);
}
}

View File

@@ -0,0 +1,30 @@
import { DsoPageFeatureGuard } from '../../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
import { Item } from '../../core/shared/item.model';
import { Injectable } from '@angular/core';
import { ItemPageResolver } from '../item-page.resolver';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/internal/Observable';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { of as observableOf } from 'rxjs';
@Injectable({
providedIn: 'root'
})
/**
* Guard for preventing unauthorized access to certain {@link Item} pages requiring withdraw rights
*/
export class ItemPageWithdrawGuard extends DsoPageFeatureGuard<Item> {
constructor(protected resolver: ItemPageResolver,
protected authorizationService: AuthorizationDataService,
protected router: Router) {
super(resolver, authorizationService, router);
}
/**
* Check withdraw authorization rights
*/
getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
return observableOf(FeatureID.WithdrawItem);
}
}

View File

@@ -81,7 +81,6 @@ export class ItemStatusComponent implements OnInit {
if (item.isWithdrawn) { if (item.isWithdrawn) {
this.authorizationService.isAuthorized(FeatureID.ReinstateItem, item.self).pipe(distinctUntilChanged()).subscribe((authorized) => { this.authorizationService.isAuthorized(FeatureID.ReinstateItem, item.self).pipe(distinctUntilChanged()).subscribe((authorized) => {
if (authorized) { if (authorized) {
console.log('added reinstate');
this.operations[index] = new ItemOperation('reinstate', this.getCurrentUrl(item) + '/reinstate'); this.operations[index] = new ItemOperation('reinstate', this.getCurrentUrl(item) + '/reinstate');
} else { } else {
this.operations[index] = undefined; this.operations[index] = undefined;
@@ -91,7 +90,6 @@ export class ItemStatusComponent implements OnInit {
} else { } else {
this.authorizationService.isAuthorized(FeatureID.WithdrawItem, item.self).pipe(distinctUntilChanged()).subscribe((authorized) => { this.authorizationService.isAuthorized(FeatureID.WithdrawItem, item.self).pipe(distinctUntilChanged()).subscribe((authorized) => {
if (authorized) { if (authorized) {
console.log('added withdraw');
this.operations[index] = new ItemOperation('withdraw', this.getCurrentUrl(item) + '/withdraw'); this.operations[index] = new ItemOperation('withdraw', this.getCurrentUrl(item) + '/withdraw');
} else { } else {
this.operations[index] = undefined; this.operations[index] = undefined;

View File

@@ -1,9 +1,12 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Router } from '@angular/router'; import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { DsoPageAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-administrator.guard';
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
import { ItemPageResolver } from './item-page.resolver'; import { ItemPageResolver } from './item-page.resolver';
import { Item } from '../core/shared/item.model'; import { Item } from '../core/shared/item.model';
import { DsoPageFeatureGuard } from '../core/data/feature-authorization/feature-authorization-guard/dso-page-feature.guard';
import { Observable } from 'rxjs/internal/Observable';
import { FeatureID } from '../core/data/feature-authorization/feature-id';
import { of as observableOf } from 'rxjs';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -11,10 +14,17 @@ import { Item } from '../core/shared/item.model';
/** /**
* Guard for preventing unauthorized access to certain {@link Item} pages requiring administrator rights * Guard for preventing unauthorized access to certain {@link Item} pages requiring administrator rights
*/ */
export class ItemPageAdministratorGuard extends DsoPageAdministratorGuard<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); super(resolver, authorizationService, router);
} }
/**
* Check administrator authorization rights
*/
getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
return observableOf(FeatureID.AdministratorOf);
}
} }

View File

@@ -1,24 +1,31 @@
import { DsoPageAdministratorGuard } from './dso-page-administrator.guard';
import { AuthorizationDataService } from '../authorization-data.service'; import { AuthorizationDataService } from '../authorization-data.service';
import { Resolve, Router } from '@angular/router'; import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
import { RemoteData } from '../../remote-data'; import { RemoteData } from '../../remote-data';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
import { DSpaceObject } from '../../../shared/dspace-object.model'; import { DSpaceObject } from '../../../shared/dspace-object.model';
import { DsoPageFeatureGuard } from './dso-page-feature.guard';
import { FeatureID } from '../feature-id';
import { Observable } from 'rxjs/internal/Observable';
/** /**
* Test implementation of abstract class DsoPageAdministratorGuard * Test implementation of abstract class DsoPageAdministratorGuard
*/ */
class DsoPageAdministratorGuardImpl extends DsoPageAdministratorGuard<any> { 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 featureID: FeatureID) {
super(resolver, authorizationService, router); super(resolver, authorizationService, router);
} }
getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
return observableOf(this.featureID);
}
} }
describe('DsoPageAdministratorGuard', () => { describe('DsoPageAdministratorGuard', () => {
let guard: DsoPageAdministratorGuard<any>; let guard: DsoPageFeatureGuard<any>;
let authorizationService: AuthorizationDataService; let authorizationService: AuthorizationDataService;
let router: Router; let router: Router;
let resolver: Resolve<RemoteData<any>>; let resolver: Resolve<RemoteData<any>>;
@@ -38,7 +45,7 @@ describe('DsoPageAdministratorGuard', () => {
resolver = jasmine.createSpyObj('resolver', { resolver = jasmine.createSpyObj('resolver', {
resolve: createSuccessfulRemoteDataObject$(object) resolve: createSuccessfulRemoteDataObject$(object)
}); });
guard = new DsoPageAdministratorGuardImpl(resolver, authorizationService, router); guard = new DsoPageFeatureGuardImpl(resolver, authorizationService, router, undefined);
} }
beforeEach(() => { beforeEach(() => {

View File

@@ -1,32 +1,23 @@
import { FeatureAuthorizationGuard } from './feature-authorization.guard';
import { AuthorizationDataService } from '../authorization-data.service';
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
import { DSpaceObject } from '../../../shared/dspace-object.model';
import { FeatureID } from '../feature-id';
import { of as observableOf } from 'rxjs';
import { Observable } from 'rxjs/internal/Observable';
import { RemoteData } from '../../remote-data'; import { RemoteData } from '../../remote-data';
import { AuthorizationDataService } from '../authorization-data.service';
import { Observable } from 'rxjs/internal/Observable';
import { getAllSucceededRemoteDataPayload } from '../../../shared/operators'; import { getAllSucceededRemoteDataPayload } from '../../../shared/operators';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { DSpaceObject } from '../../../shared/dspace-object.model';
import { FeatureAuthorizationGuard } from './feature-authorization.guard';
/** /**
* Abstract Guard for preventing unauthorized access to {@link DSpaceObject} pages that require administrator rights * Abstract Guard for preventing unauthorized access to {@link DSpaceObject} pages that require rights for a specific feature
* This guard utilizes a resolver to retrieve the relevant object to check authorizations for * This guard utilizes a resolver to retrieve the relevant object to check authorizations for
*/ */
export abstract class DsoPageAdministratorGuard<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); super(authorizationService, router);
} }
/**
* Check administrator authorization rights
*/
getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> {
return observableOf(FeatureID.AdministratorOf);
}
/** /**
* Check authorization rights for the object resolved using the provided resolver * Check authorization rights for the object resolved using the provided resolver
*/ */