forked from hazza/dspace-angular
77205: Add Comm/Coll admin guards & authorization checks
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Component, Injector, OnInit } from '@angular/core';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
||||
import { combineLatest, combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
||||
import { first, map, take } from 'rxjs/operators';
|
||||
import { AuthService } from '../../core/auth/auth.service';
|
||||
import { ScriptDataService } from '../../core/data/processes/script-data.service';
|
||||
@@ -103,6 +103,10 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
||||
* Initialize all menu sections and items for this menu
|
||||
*/
|
||||
createMenu() {
|
||||
combineLatest([
|
||||
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
|
||||
this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin),
|
||||
]).subscribe(([isCollectionAdmin, isCommunityAdmin]) => {
|
||||
const menuList = [
|
||||
/* News */
|
||||
{
|
||||
@@ -194,7 +198,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
||||
id: 'edit_community',
|
||||
parentID: 'edit',
|
||||
active: false,
|
||||
visible: true,
|
||||
visible: isCommunityAdmin,
|
||||
model: {
|
||||
type: MenuItemType.ONCLICK,
|
||||
text: 'menu.section.edit_community',
|
||||
@@ -207,7 +211,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
||||
id: 'edit_collection',
|
||||
parentID: 'edit',
|
||||
active: false,
|
||||
visible: true,
|
||||
visible: isCollectionAdmin,
|
||||
model: {
|
||||
type: MenuItemType.ONCLICK,
|
||||
text: 'menu.section.edit_collection',
|
||||
@@ -289,6 +293,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
||||
menuList.forEach((menuSection) => this.menuService.addSection(this.menuID, Object.assign(menuSection, {
|
||||
shouldPersistOnRouteChange: true
|
||||
})));
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -35,7 +35,7 @@
|
||||
</ds-comcol-page-content>
|
||||
</header>
|
||||
<div class="pl-2">
|
||||
<ds-dso-page-edit-button [pageRoutePrefix]="'collections'" [dso]="collection" [tooltipMsg]="'collection.page.edit'"></ds-dso-page-edit-button>
|
||||
<ds-dso-page-edit-button *ngIf="isCollectionAdmin$ | async" [pageRoutePrefix]="'collections'" [dso]="collection" [tooltipMsg]="'collection.page.edit'"></ds-dso-page-edit-button>
|
||||
</div>
|
||||
</div>
|
||||
<section class="comcol-page-browse-section">
|
||||
|
@@ -22,6 +22,8 @@ import { hasValue, isNotEmpty } from '../shared/empty.util';
|
||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||
import { AuthService } from '../core/auth/auth.service';
|
||||
import {PaginationChangeEvent} from '../shared/pagination/paginationChangeEvent.interface';
|
||||
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-collection-page',
|
||||
@@ -44,6 +46,11 @@ export class CollectionPageComponent implements OnInit {
|
||||
sortConfig: SortOptions
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Whether the current user is a Community admin
|
||||
*/
|
||||
isCollectionAdmin$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private collectionDataService: CollectionDataService,
|
||||
private searchService: SearchService,
|
||||
@@ -51,6 +58,7 @@ export class CollectionPageComponent implements OnInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private authService: AuthService,
|
||||
private authorizationDataService: AuthorizationDataService,
|
||||
) {
|
||||
this.paginationConfig = new PaginationComponentOptions();
|
||||
this.paginationConfig.id = 'collection-page-pagination';
|
||||
@@ -70,6 +78,7 @@ export class CollectionPageComponent implements OnInit {
|
||||
filter((collection: Collection) => hasValue(collection)),
|
||||
mergeMap((collection: Collection) => collection.logo)
|
||||
);
|
||||
this.isCollectionAdmin$ = this.authorizationDataService.isAuthorized(FeatureID.IsCollectionAdmin);
|
||||
|
||||
this.paginationChanges$ = new BehaviorSubject({
|
||||
paginationConfig: this.paginationConfig,
|
||||
|
@@ -12,6 +12,7 @@ import { ResourcePolicyTargetResolver } from '../../shared/resource-policies/res
|
||||
import { ResourcePolicyCreateComponent } from '../../shared/resource-policies/create/resource-policy-create.component';
|
||||
import { ResourcePolicyResolver } from '../../shared/resource-policies/resolvers/resource-policy.resolver';
|
||||
import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit/resource-policy-edit.component';
|
||||
import { IsCollectionAdminGuard } from '../../access-control/guards/is-collection-admin.guard';
|
||||
|
||||
/**
|
||||
* Routing module that handles the routing for the Edit Collection page administrator functionality
|
||||
@@ -26,6 +27,7 @@ import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit
|
||||
},
|
||||
data: { breadcrumbKey: 'collection.edit' },
|
||||
component: EditCollectionPageComponent,
|
||||
canActivate: [IsCollectionAdminGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
|
@@ -21,7 +21,7 @@
|
||||
</ds-comcol-page-content>
|
||||
</header>
|
||||
<div class="pl-2">
|
||||
<ds-dso-page-edit-button [pageRoutePrefix]="'communities'" [dso]="communityPayload" [tooltipMsg]="'community.page.edit'"></ds-dso-page-edit-button>
|
||||
<ds-dso-page-edit-button *ngIf="isCommunityAdmin$ | async" [pageRoutePrefix]="'communities'" [dso]="communityPayload" [tooltipMsg]="'community.page.edit'"></ds-dso-page-edit-button>
|
||||
</div>
|
||||
</div>
|
||||
<section class="comcol-page-browse-section">
|
||||
|
@@ -15,6 +15,8 @@ import { fadeInOut } from '../shared/animations/fade';
|
||||
import { hasValue } from '../shared/empty.util';
|
||||
import { redirectOn4xx } from '../core/shared/operators';
|
||||
import { AuthService } from '../core/auth/auth.service';
|
||||
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||
import { FeatureID } from '../core/data/feature-authorization/feature-id';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-community-page',
|
||||
@@ -32,6 +34,11 @@ export class CommunityPageComponent implements OnInit {
|
||||
*/
|
||||
communityRD$: Observable<RemoteData<Community>>;
|
||||
|
||||
/**
|
||||
* Whether the current user is a Community admin
|
||||
*/
|
||||
isCommunityAdmin$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* The logo of this community
|
||||
*/
|
||||
@@ -42,6 +49,7 @@ export class CommunityPageComponent implements OnInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private authService: AuthService,
|
||||
private authorizationDataService: AuthorizationDataService
|
||||
) {
|
||||
|
||||
}
|
||||
@@ -54,7 +62,8 @@ export class CommunityPageComponent implements OnInit {
|
||||
this.logoRD$ = this.communityRD$.pipe(
|
||||
map((rd: RemoteData<Community>) => rd.payload),
|
||||
filter((community: Community) => hasValue(community)),
|
||||
mergeMap((community: Community) => community.logo));
|
||||
mergeMap((community: Community) => community.logo)
|
||||
);
|
||||
this.isCommunityAdmin$ = this.authorizationDataService.isAuthorized(FeatureID.IsCommunityAdmin);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import { ResourcePolicyTargetResolver } from '../../shared/resource-policies/res
|
||||
import { ResourcePolicyCreateComponent } from '../../shared/resource-policies/create/resource-policy-create.component';
|
||||
import { ResourcePolicyResolver } from '../../shared/resource-policies/resolvers/resource-policy.resolver';
|
||||
import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit/resource-policy-edit.component';
|
||||
import { IsCommunityAdminGuard } from '../../access-control/guards/is-community-admin.guard';
|
||||
|
||||
/**
|
||||
* Routing module that handles the routing for the Edit Community page administrator functionality
|
||||
@@ -24,6 +25,7 @@ import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit
|
||||
},
|
||||
data: { breadcrumbKey: 'community.edit' },
|
||||
component: EditCommunityPageComponent,
|
||||
canActivate: [IsCommunityAdminGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
|
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { IsCollectionAdminGuard } from './is-collection-admin.guard';
|
||||
|
||||
describe('IsCollectionAdminGuard', () => {
|
||||
let guard: IsCollectionAdminGuard;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
guard = TestBed.inject(IsCollectionAdminGuard);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(guard).toBeTruthy();
|
||||
});
|
||||
});
|
20
src/app/access-control/guards/is-collection-admin.guard.ts
Normal file
20
src/app/access-control/guards/is-collection-admin.guard.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
||||
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
||||
|
||||
/**
|
||||
* Guard for preventing unauthorized editing of Communities
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IsCollectionAdminGuard implements CanActivate {
|
||||
constructor(private authorizationService: AuthorizationDataService) {
|
||||
}
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
||||
return this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin);
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { IsCommunityAdminGuard } from './is-community-admin.guard';
|
||||
|
||||
describe('IsCommunityAdminGuard', () => {
|
||||
let guard: IsCommunityAdminGuard;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
guard = TestBed.inject(IsCommunityAdminGuard);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(guard).toBeTruthy();
|
||||
});
|
||||
});
|
20
src/app/access-control/guards/is-community-admin.guard.ts
Normal file
20
src/app/access-control/guards/is-community-admin.guard.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
|
||||
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
||||
|
||||
/**
|
||||
* Guard for preventing unauthorized editing of Communities
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IsCommunityAdminGuard implements CanActivate {
|
||||
constructor(private authorizationService: AuthorizationDataService) {
|
||||
}
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
||||
return this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin);
|
||||
}
|
||||
}
|
@@ -10,4 +10,6 @@ export enum FeatureID {
|
||||
ReinstateItem = 'reinstateItem',
|
||||
EPersonRegistration = 'epersonRegistration',
|
||||
CanManageGroups = 'canManageGroups',
|
||||
IsCollectionAdmin = 'isCollectionAdmin',
|
||||
IsCommunityAdmin = 'isCommunityAdmin',
|
||||
}
|
||||
|
Reference in New Issue
Block a user