+ {{epersonDto.eperson.id}} |
+ {{epersonDto.eperson.name}} |
+ {{epersonDto.eperson.email}} |
-
-
@@ -85,7 +85,7 @@
-
+
{{labelPrefix + 'no-items' | translate}}
diff --git a/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.spec.ts b/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.spec.ts
index 4cc68a5540..0ff07d688c 100644
--- a/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.spec.ts
+++ b/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.spec.ts
@@ -24,6 +24,8 @@ import { getMockTranslateService } from '../../../shared/mocks/translate.service
import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../../shared/testing/router.stub';
+import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
+import { RequestService } from '../../../core/data/request.service';
describe('EPeopleRegistryComponent', () => {
let component: EPeopleRegistryComponent;
@@ -33,6 +35,8 @@ describe('EPeopleRegistryComponent', () => {
let mockEPeople;
let ePersonDataServiceStub: any;
+ let authorizationService: AuthorizationDataService;
+ let modalService;
beforeEach(async(() => {
mockEPeople = [EPersonMock, EPersonMock2];
@@ -82,6 +86,9 @@ describe('EPeopleRegistryComponent', () => {
return '/admin/access-control/epeople';
}
};
+ authorizationService = jasmine.createSpyObj('authorizationService', {
+ isAuthorized: observableOf(true)
+ });
builderService = getMockFormBuilderService();
translateService = getMockTranslateService();
TestBed.configureTestingModule({
@@ -94,11 +101,13 @@ describe('EPeopleRegistryComponent', () => {
}),
],
declarations: [EPeopleRegistryComponent],
- providers: [EPeopleRegistryComponent,
+ providers: [
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
+ { provide: AuthorizationDataService, useValue: authorizationService },
{ provide: FormBuilderService, useValue: builderService },
{ provide: Router, useValue: new RouterStub() },
+ { provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring'])}
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
@@ -107,12 +116,14 @@ describe('EPeopleRegistryComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(EPeopleRegistryComponent);
component = fixture.componentInstance;
+ modalService = (component as any).modalService;
+ spyOn(modalService, 'open').and.returnValue(Object.assign({ componentInstance: Object.assign({ response: observableOf(true) }) }));
fixture.detectChanges();
});
- it('should create EPeopleRegistryComponent', inject([EPeopleRegistryComponent], (comp: EPeopleRegistryComponent) => {
- expect(comp).toBeDefined();
- }));
+ it('should create EPeopleRegistryComponent', () => {
+ expect(component).toBeDefined();
+ });
it('should display list of ePeople', () => {
const ePeopleIdsFound = fixture.debugElement.queryAll(By.css('#epeople tr td:first-child'));
@@ -215,4 +226,20 @@ describe('EPeopleRegistryComponent', () => {
});
});
+ describe('delete EPerson button when the isAuthorized returns false', () => {
+ let ePeopleDeleteButton;
+ beforeEach(() => {
+ authorizationService = jasmine.createSpyObj('authorizationService', {
+ isAuthorized: observableOf(false)
+ });
+ });
+
+ it ('should be disabled', () => {
+ ePeopleDeleteButton = fixture.debugElement.queryAll(By.css('#epeople tr td div button.delete-button'));
+ ePeopleDeleteButton.forEach((deleteButton) => {
+ expect(deleteButton.nativeElement.disabled).toBe(true);
+ });
+
+ })
+ })
});
diff --git a/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts b/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts
index e88ba84418..2f989490a7 100644
--- a/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts
+++ b/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts
@@ -2,9 +2,9 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
-import { Observable } from 'rxjs';
+import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { Subscription } from 'rxjs/internal/Subscription';
-import { map, take } from 'rxjs/operators';
+import { map, switchMap, take } from 'rxjs/operators';
import { PaginatedList } from '../../../core/data/paginated-list';
import { RemoteData } from '../../../core/data/remote-data';
import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
@@ -12,6 +12,16 @@ import { EPerson } from '../../../core/eperson/models/eperson.model';
import { hasValue } from '../../../shared/empty.util';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
+import { EpersonDtoModel } from '../../../core/eperson/models/eperson-dto.model';
+import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
+import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
+import { getAllSucceededRemoteDataPayload } from '../../../core/shared/operators';
+import { ErrorResponse, RestResponse } from '../../../core/cache/response.models';
+import { ConfirmationModalComponent } from '../../../shared/confirmation-modal/confirmation-modal.component';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { RequestService } from '../../../core/data/request.service';
+import { filter } from 'rxjs/internal/operators/filter';
+import { PageInfo } from '../../../core/shared/page-info.model';
@Component({
selector: 'ds-epeople-registry',
@@ -28,7 +38,17 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
/**
* A list of all the current EPeople within the repository or the result of the search
*/
- ePeople: Observable>>;
+ ePeople$: BehaviorSubject>> = new BehaviorSubject>>({} as any);
+ /**
+ * A BehaviorSubject with the list of EpersonDtoModel objects made from the EPeople in the repository or
+ * as the result of the search
+ */
+ ePeopleDto$: BehaviorSubject> = new BehaviorSubject>({} as any);
+
+ /**
+ * An observable for the pageInfo, needed to pass to the pagination component
+ */
+ pageInfoState$: BehaviorSubject = new BehaviorSubject(undefined);
/**
* Pagination config used to display the list of epeople
@@ -59,8 +79,11 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
constructor(private epersonService: EPersonDataService,
private translateService: TranslateService,
private notificationsService: NotificationsService,
+ private authorizationService: AuthorizationDataService,
private formBuilder: FormBuilder,
- private router: Router) {
+ private router: Router,
+ private modalService: NgbModal,
+ public requestService: RequestService) {
this.currentSearchQuery = '';
this.currentSearchScope = 'metadata';
this.searchForm = this.formBuilder.group(({
@@ -70,6 +93,13 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
}
ngOnInit() {
+ this.initialisePage();
+ }
+
+ /**
+ * This method will initialise the page
+ */
+ initialisePage() {
this.isEPersonFormShown = false;
this.search({ scope: this.currentSearchScope, query: this.currentSearchQuery });
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
@@ -84,18 +114,10 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
* @param event
*/
onPageChange(event) {
- this.config.currentPage = event;
- this.search({ scope: this.currentSearchScope, query: this.currentSearchQuery })
- }
-
- /**
- * Force-update the list of EPeople by first clearing the cache related to EPeople, then performing
- * a new REST call
- */
- public forceUpdateEPeople() {
- this.epersonService.clearEPersonRequests();
- this.isEPersonFormShown = false;
- this.search({ query: '', scope: 'metadata' })
+ if (this.config.currentPage !== event) {
+ this.config.currentPage = event;
+ this.search({ scope: this.currentSearchScope, query: this.currentSearchQuery })
+ }
}
/**
@@ -115,10 +137,33 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
this.currentSearchScope = scope;
this.config.currentPage = 1;
}
- this.ePeople = this.epersonService.searchByScope(this.currentSearchScope, this.currentSearchQuery, {
+ this.subs.push(this.epersonService.searchByScope(this.currentSearchScope, this.currentSearchQuery, {
currentPage: this.config.currentPage,
elementsPerPage: this.config.pageSize
- });
+ }).subscribe((peopleRD) => {
+ this.ePeople$.next(peopleRD)
+ }
+ ));
+
+ this.subs.push(this.ePeople$.pipe(
+ getAllSucceededRemoteDataPayload(),
+ switchMap((epeople) => {
+ return combineLatest(...epeople.page.map((eperson) => {
+ return this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined).pipe(
+ map((authorized) => {
+ const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel();
+ epersonDtoModel.ableToDelete = authorized;
+ epersonDtoModel.eperson = eperson;
+ return epersonDtoModel;
+ })
+ );
+ })).pipe(map((dtos: EpersonDtoModel[]) => {
+ return new PaginatedList(epeople.pageInfo, dtos);
+ }))
+ })).subscribe((value) => {
+ this.ePeopleDto$.next(value);
+ this.pageInfoState$.next(value.pageInfo);
+ }));
}
/**
@@ -160,16 +205,26 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
*/
deleteEPerson(ePerson: EPerson) {
if (hasValue(ePerson.id)) {
- this.epersonService.deleteEPerson(ePerson).pipe(take(1)).subscribe((success: boolean) => {
- if (success) {
- this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: ePerson.name }));
- this.forceUpdateEPeople();
- } else {
- this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.deleted.failure', { name: ePerson.name }));
- }
- this.epersonService.cancelEditEPerson();
- this.isEPersonFormShown = false;
- })
+ const modalRef = this.modalService.open(ConfirmationModalComponent);
+ modalRef.componentInstance.dso = ePerson;
+ modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-eperson.header';
+ modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-eperson.info';
+ modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-eperson.cancel';
+ modalRef.componentInstance.confirmLabel = 'confirmation-modal.delete-eperson.confirm';
+ modalRef.componentInstance.response.pipe(take(1)).subscribe((confirm: boolean) => {
+ if (confirm) {
+ if (hasValue(ePerson.id)) {
+ this.epersonService.deleteEPerson(ePerson).pipe(take(1)).subscribe((restResponse: RestResponse) => {
+ if (restResponse.isSuccessful) {
+ this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: ePerson.name }));
+ this.reset();
+ } else {
+ const errorResponse = restResponse as ErrorResponse;
+ this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + ePerson.id + ' with code: ' + errorResponse.statusCode + ' and message: ' + errorResponse.errorMessage);
+ }
+ })
+ }}
+ });
}
}
@@ -177,6 +232,10 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
* Unsub all subscriptions
*/
ngOnDestroy(): void {
+ this.cleanupSubscribes();
+ }
+
+ cleanupSubscribes() {
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
}
@@ -199,4 +258,18 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
});
this.search({ query: '' });
}
+
+ /**
+ * This method will ensure that the page gets reset and that the cache is cleared
+ */
+ reset() {
+ this.epersonService.getBrowseEndpoint().pipe(
+ switchMap((href) => this.requestService.removeByHrefSubstring(href)),
+ filter((isCached) => isCached),
+ take(1)
+ ).subscribe(() => {
+ this.cleanupSubscribes();
+ this.initialisePage();
+ });
+ }
}
diff --git a/src/app/+admin/admin-access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/+admin/admin-access-control/epeople-registry/eperson-form/eperson-form.component.html
index 34fdef89bf..3f744240e5 100644
--- a/src/app/+admin/admin-access-control/epeople-registry/eperson-form/eperson-form.component.html
+++ b/src/app/+admin/admin-access-control/epeople-registry/eperson-form/eperson-form.component.html
@@ -17,7 +17,7 @@
- |