[Task 72956] applied feedback to the deletion of epersons

This commit is contained in:
Raf Ponsaerts
2020-09-23 15:07:38 +02:00
parent f8dab74b64
commit 3de2b50d10
5 changed files with 141 additions and 50 deletions

View File

@@ -25,6 +25,9 @@ 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 { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { UUIDService } from '../../../core/shared/uuid.service';
import { Store } from '@ngrx/store';
describe('EPeopleRegistryComponent', () => {
let component: EPeopleRegistryComponent;
@@ -35,6 +38,7 @@ describe('EPeopleRegistryComponent', () => {
let mockEPeople;
let ePersonDataServiceStub: any;
let authorizationService: AuthorizationDataService;
let modalService;
beforeEach(async(() => {
mockEPeople = [EPersonMock, EPersonMock2];
@@ -104,6 +108,9 @@ describe('EPeopleRegistryComponent', () => {
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: FormBuilderService, useValue: builderService },
{ provide: AuthorizationDataService, useValue: authorizationService },
{ provide: ObjectCacheService, useValue: {} },
{ provide: UUIDService, useValue: {} },
{ provide: Store, useValue: {} },
{ provide: Router, useValue: new RouterStub() },
],
schemas: [NO_ERRORS_SCHEMA]
@@ -113,6 +120,8 @@ 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();
});

View File

@@ -17,6 +17,9 @@ 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 { 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';
@Component({
selector: 'ds-epeople-registry',
@@ -71,7 +74,9 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
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(({
@@ -81,6 +86,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) => {
@@ -191,16 +203,28 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
*/
deleteEPerson(ePerson: EPerson) {
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.forceUpdateEPeople();
} else {
this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + ePerson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.statusText);
}
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();
this.forceUpdateEPeople();
} else {
this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + ePerson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.statusText);
}
this.epersonService.cancelEditEPerson();
this.isEPersonFormShown = false;
})
}}
});
}
}
@@ -230,4 +254,16 @@ 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.ePeopleDto$.pipe(take(1)).subscribe((epersons: PaginatedList<EpersonDtoModel>) => {
epersons.page.forEach((eperson: EpersonDtoModel) => {
this.requestService.removeByHrefSubstring(eperson.eperson.self);
})
});
this.initialisePage();
}
}

View File

@@ -2,11 +2,11 @@ import { HttpClient } from '@angular/common/http';
import { Store } from '@ngrx/store';
import { of as observableOf } from 'rxjs';
import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { EventEmitter, NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, inject, TestBed, tick } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgbModal, NgbModule, NgbModalModule, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs/internal/Observable';
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
@@ -286,16 +286,19 @@ describe('EPersonFormComponent', () => {
let ePersonId;
let eperson: EPerson;
let modalService;
beforeEach(() => {
spyOn(authService, 'impersonate').and.callThrough();
ePersonId = 'testEPersonId';
eperson = Object.assign(new EPerson(), {
id: ePersonId
});
eperson = EPersonMock;
component.epersonInitial = eperson;
component.canDelete$ = observableOf(true);
spyOn(component.epersonService, 'getActiveEPerson').and.returnValue(observableOf(eperson));
modalService = (component as any).modalService;
spyOn(modalService, 'open').and.returnValue(Object.assign({ componentInstance: Object.assign({ response: observableOf(true) }) }));
fixture.detectChanges()
});
it ('the delete button should be active if the eperson can be deleted', () => {
@@ -312,6 +315,7 @@ describe('EPersonFormComponent', () => {
it ('should call the epersonFormComponent delete when clicked on the button' , () => {
spyOn(component, 'delete').and.stub();
spyOn(component.epersonService, 'deleteEPerson').and.returnValue(observableOf(new RestResponse(true, 204, 'No Content')));
const deleteButton = fixture.debugElement.query(By.css('.delete-button'));
deleteButton.triggerEventHandler('click', null);
expect(component.delete).toHaveBeenCalled();

View File

@@ -7,7 +7,7 @@ import {
DynamicInputModel
} from '@ng-dynamic-forms/core';
import { TranslateService } from '@ngx-translate/core';
import { Subscription, combineLatest, of } from 'rxjs';
import { Subscription, combineLatest, of, of as observableOf } from 'rxjs';
import { Observable } from 'rxjs/internal/Observable';
import { switchMap, take } from 'rxjs/operators';
import { RestResponse } from '../../../../core/cache/response.models';
@@ -25,6 +25,9 @@ import { PaginationComponentOptions } from '../../../../shared/pagination/pagina
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';
import { ConfirmationModalComponent } from '../../../../shared/confirmation-modal/confirmation-modal.component';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { RequestService } from '../../../../core/data/request.service';
@Component({
selector: 'ds-eperson-form',
@@ -159,7 +162,9 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
private translateService: TranslateService,
private notificationsService: NotificationsService,
private authService: AuthService,
private authorizationService: AuthorizationDataService) {
private authorizationService: AuthorizationDataService,
private modalService: NgbModal,
public requestService: RequestService) {
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
this.epersonInitial = eperson;
if (hasValue(eperson)) {
@@ -169,13 +174,20 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.initialisePage();
}
/**
* This method will initialise the page
*/
initialisePage() {
combineLatest(
this.translateService.get(`${this.messagePrefix}.firstName`),
this.translateService.get(`${this.messagePrefix}.lastName`),
this.translateService.get(`${this.messagePrefix}.email`),
this.translateService.get(`${this.messagePrefix}.canLogIn`),
this.translateService.get(`${this.messagePrefix}.requireCertificate`),
this.translateService.get(`${this.messagePrefix}.emailHint`),
this.translateService.get(`${this.messagePrefix}.firstName`),
this.translateService.get(`${this.messagePrefix}.lastName`),
this.translateService.get(`${this.messagePrefix}.email`),
this.translateService.get(`${this.messagePrefix}.canLogIn`),
this.translateService.get(`${this.messagePrefix}.requireCertificate`),
this.translateService.get(`${this.messagePrefix}.emailHint`),
).subscribe(([firstName, lastName, email, canLogIn, requireCertificate, emailHint]) => {
this.firstName = new DynamicInputModel({
id: 'firstName',
@@ -207,19 +219,19 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
hint: emailHint
});
this.canLogIn = new DynamicCheckboxModel(
{
id: 'canLogIn',
label: canLogIn,
name: 'canLogIn',
value: (this.epersonInitial != null ? this.epersonInitial.canLogIn : true)
});
{
id: 'canLogIn',
label: canLogIn,
name: 'canLogIn',
value: (this.epersonInitial != null ? this.epersonInitial.canLogIn : true)
});
this.requireCertificate = new DynamicCheckboxModel(
{
id: 'requireCertificate',
label: requireCertificate,
name: 'requireCertificate',
value: (this.epersonInitial != null ? this.epersonInitial.requireCertificate : false)
});
{
id: 'requireCertificate',
label: requireCertificate,
name: 'requireCertificate',
value: (this.epersonInitial != null ? this.epersonInitial.requireCertificate : false)
});
this.formModel = [
this.firstName,
this.lastName,
@@ -244,7 +256,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
});
}));
this.canImpersonate$ = this.epersonService.getActiveEPerson().pipe(
switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.LoginOnBehalfOf, hasValue(eperson) ? eperson.self : undefined))
switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.LoginOnBehalfOf, hasValue(eperson) ? eperson.self : undefined))
);
this.canDelete$ = this.epersonService.getActiveEPerson().pipe(
switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined))
@@ -412,19 +424,28 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
* It'll either show a success or error message depending on whether the delete was successful or not.
*/
delete() {
this.epersonService.getActiveEPerson().pipe(take(1)).subscribe((eperson: EPerson) => {
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 }));
} else {
this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + eperson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.statusText);
}
this.cancelForm.emit();
})
}}
)
this.epersonService.getActiveEPerson().pipe(take(1)).subscribe((eperson: EPerson) => {
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 {
this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + eperson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.statusText);
}
this.cancelForm.emit();
})
}}
});
})
}
/**
@@ -442,4 +463,14 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
this.onCancel();
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
}
/**
* This method will ensure that the page gets reset and that the cache is cleared
*/
reset() {
this.epersonService.getActiveEPerson().pipe(take(1)).subscribe((eperson: EPerson) => {
this.requestService.removeByHrefSubstring(eperson.self);
});
this.initialisePage();
}
}

View File

@@ -258,6 +258,10 @@
"admin.access-control.epeople.form.notification.edited.failure": "Failed to edit EPerson \"{{name}}\"",
"admin.access-control.epeople.form.notification.deleted.success": "Successfully deleted EPerson \"{{name}}\"",
"admin.access-control.epeople.form.notification.deleted.failure": "Failed to delete EPerson \"{{name}}\"",
"admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Member of these groups:",
"admin.access-control.epeople.form.table.id": "ID",
@@ -1003,6 +1007,13 @@
"confirmation-modal.export-metadata.confirm": "Export",
"confirmation-modal.delete-eperson.header": "Delete EPerson \"{{ dsoName }}\"",
"confirmation-modal.delete-eperson.info": "Are you sure you want to delete EPerson \"{{ dsoName }}\"",
"confirmation-modal.delete-eperson.cancel": "Cancel",
"confirmation-modal.delete-eperson.confirm": "Delete",
"error.bitstream": "Error fetching bitstream",