mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 18:44:14 +00:00
Merge pull request #874 from atmire/w2p-72956_delete-eperson
Delete eperson
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<h2 id="header" class="border-bottom pb-2">{{labelPrefix + 'head' | translate}}</h2>
|
<h2 id="header" class="border-bottom pb-2">{{labelPrefix + 'head' | translate}}</h2>
|
||||||
|
|
||||||
<ds-eperson-form *ngIf="isEPersonFormShown" (submitForm)="forceUpdateEPeople()"
|
<ds-eperson-form *ngIf="isEPersonFormShown" (submitForm)="reset()"
|
||||||
(cancelForm)="isEPersonFormShown = false"></ds-eperson-form>
|
(cancelForm)="isEPersonFormShown = false"></ds-eperson-form>
|
||||||
|
|
||||||
<div *ngIf="!isEPersonFormShown">
|
<div *ngIf="!isEPersonFormShown">
|
||||||
@@ -40,10 +40,10 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<ds-pagination
|
<ds-pagination
|
||||||
*ngIf="(ePeople | async)?.payload?.totalElements > 0"
|
*ngIf="(ePeopleDto$ | async)?.totalElements > 0"
|
||||||
[paginationOptions]="config"
|
[paginationOptions]="config"
|
||||||
[pageInfoState]="(ePeople | async)?.payload"
|
[pageInfoState]="pageInfoState$"
|
||||||
[collectionSize]="(ePeople | async)?.payload?.totalElements"
|
[collectionSize]="(pageInfoState$ | async)?.totalElements"
|
||||||
[hideGear]="true"
|
[hideGear]="true"
|
||||||
[hidePagerWhenSinglePage]="true"
|
[hidePagerWhenSinglePage]="true"
|
||||||
(pageChange)="onPageChange($event)">
|
(pageChange)="onPageChange($event)">
|
||||||
@@ -59,21 +59,21 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let eperson of (ePeople | async)?.payload?.page"
|
<tr *ngFor="let epersonDto of (ePeopleDto$ | async)?.page"
|
||||||
[ngClass]="{'table-primary' : isActive(eperson) | async}">
|
[ngClass]="{'table-primary' : isActive(epersonDto.eperson) | async}">
|
||||||
<td>{{eperson.id}}</td>
|
<td>{{epersonDto.eperson.id}}</td>
|
||||||
<td>{{eperson.name}}</td>
|
<td>{{epersonDto.eperson.name}}</td>
|
||||||
<td>{{eperson.email}}</td>
|
<td>{{epersonDto.eperson.email}}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group edit-field">
|
<div class="btn-group edit-field">
|
||||||
<button (click)="toggleEditEPerson(eperson)"
|
<button class="delete-button" (click)="toggleEditEPerson(epersonDto.eperson)"
|
||||||
class="btn btn-outline-primary btn-sm access-control-editEPersonButton"
|
class="btn btn-outline-primary btn-sm access-control-editEPersonButton"
|
||||||
title="{{labelPrefix + 'table.edit.buttons.edit' | translate: {name: eperson.name} }}">
|
title="{{labelPrefix + 'table.edit.buttons.edit' | translate: {name: epersonDto.eperson.name} }}">
|
||||||
<i class="fas fa-edit fa-fw"></i>
|
<i class="fas fa-edit fa-fw"></i>
|
||||||
</button>
|
</button>
|
||||||
<button (click)="deleteEPerson(eperson)"
|
<button [disabled]="!epersonDto.ableToDelete" (click)="deleteEPerson(epersonDto.eperson)"
|
||||||
class="btn btn-outline-danger btn-sm access-control-deleteEPersonButton"
|
class="btn btn-outline-danger btn-sm access-control-deleteEPersonButton"
|
||||||
title="{{labelPrefix + 'table.edit.buttons.remove' | translate: {name: eperson.name} }}">
|
title="{{labelPrefix + 'table.edit.buttons.remove' | translate: {name: epersonDto.eperson.name} }}">
|
||||||
<i class="fas fa-trash-alt fa-fw"></i>
|
<i class="fas fa-trash-alt fa-fw"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
|
|
||||||
</ds-pagination>
|
</ds-pagination>
|
||||||
|
|
||||||
<div *ngIf="(ePeople | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert">
|
<div *ngIf="(pageInfoState$ | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert">
|
||||||
{{labelPrefix + 'no-items' | translate}}
|
{{labelPrefix + 'no-items' | translate}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -24,6 +24,8 @@ import { getMockTranslateService } from '../../../shared/mocks/translate.service
|
|||||||
import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock';
|
import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock';
|
||||||
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
|
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
|
||||||
import { RouterStub } from '../../../shared/testing/router.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', () => {
|
describe('EPeopleRegistryComponent', () => {
|
||||||
let component: EPeopleRegistryComponent;
|
let component: EPeopleRegistryComponent;
|
||||||
@@ -33,6 +35,8 @@ describe('EPeopleRegistryComponent', () => {
|
|||||||
|
|
||||||
let mockEPeople;
|
let mockEPeople;
|
||||||
let ePersonDataServiceStub: any;
|
let ePersonDataServiceStub: any;
|
||||||
|
let authorizationService: AuthorizationDataService;
|
||||||
|
let modalService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
mockEPeople = [EPersonMock, EPersonMock2];
|
mockEPeople = [EPersonMock, EPersonMock2];
|
||||||
@@ -82,6 +86,9 @@ describe('EPeopleRegistryComponent', () => {
|
|||||||
return '/admin/access-control/epeople';
|
return '/admin/access-control/epeople';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
authorizationService = jasmine.createSpyObj('authorizationService', {
|
||||||
|
isAuthorized: observableOf(true)
|
||||||
|
});
|
||||||
builderService = getMockFormBuilderService();
|
builderService = getMockFormBuilderService();
|
||||||
translateService = getMockTranslateService();
|
translateService = getMockTranslateService();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
@@ -94,11 +101,13 @@ describe('EPeopleRegistryComponent', () => {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
declarations: [EPeopleRegistryComponent],
|
declarations: [EPeopleRegistryComponent],
|
||||||
providers: [EPeopleRegistryComponent,
|
providers: [
|
||||||
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
|
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
|
||||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
||||||
|
{ provide: AuthorizationDataService, useValue: authorizationService },
|
||||||
{ provide: FormBuilderService, useValue: builderService },
|
{ provide: FormBuilderService, useValue: builderService },
|
||||||
{ provide: Router, useValue: new RouterStub() },
|
{ provide: Router, useValue: new RouterStub() },
|
||||||
|
{ provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring'])}
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
@@ -107,12 +116,14 @@ describe('EPeopleRegistryComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(EPeopleRegistryComponent);
|
fixture = TestBed.createComponent(EPeopleRegistryComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
modalService = (component as any).modalService;
|
||||||
|
spyOn(modalService, 'open').and.returnValue(Object.assign({ componentInstance: Object.assign({ response: observableOf(true) }) }));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create EPeopleRegistryComponent', inject([EPeopleRegistryComponent], (comp: EPeopleRegistryComponent) => {
|
it('should create EPeopleRegistryComponent', () => {
|
||||||
expect(comp).toBeDefined();
|
expect(component).toBeDefined();
|
||||||
}));
|
});
|
||||||
|
|
||||||
it('should display list of ePeople', () => {
|
it('should display list of ePeople', () => {
|
||||||
const ePeopleIdsFound = fixture.debugElement.queryAll(By.css('#epeople tr td:first-child'));
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
@@ -2,9 +2,9 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
|
|||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Observable } from 'rxjs';
|
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||||
import { Subscription } from 'rxjs/internal/Subscription';
|
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 { PaginatedList } from '../../../core/data/paginated-list';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
|
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 { hasValue } from '../../../shared/empty.util';
|
||||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
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({
|
@Component({
|
||||||
selector: 'ds-epeople-registry',
|
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
|
* A list of all the current EPeople within the repository or the result of the search
|
||||||
*/
|
*/
|
||||||
ePeople: Observable<RemoteData<PaginatedList<EPerson>>>;
|
ePeople$: BehaviorSubject<RemoteData<PaginatedList<EPerson>>> = new BehaviorSubject<RemoteData<PaginatedList<EPerson>>>({} 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<PaginatedList<EpersonDtoModel>> = new BehaviorSubject<PaginatedList<EpersonDtoModel>>({} as any);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An observable for the pageInfo, needed to pass to the pagination component
|
||||||
|
*/
|
||||||
|
pageInfoState$: BehaviorSubject<PageInfo> = new BehaviorSubject<PageInfo>(undefined);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pagination config used to display the list of epeople
|
* Pagination config used to display the list of epeople
|
||||||
@@ -59,8 +79,11 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
|
|||||||
constructor(private epersonService: EPersonDataService,
|
constructor(private epersonService: EPersonDataService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
|
private authorizationService: AuthorizationDataService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private router: Router) {
|
private router: Router,
|
||||||
|
private modalService: NgbModal,
|
||||||
|
public requestService: RequestService) {
|
||||||
this.currentSearchQuery = '';
|
this.currentSearchQuery = '';
|
||||||
this.currentSearchScope = 'metadata';
|
this.currentSearchScope = 'metadata';
|
||||||
this.searchForm = this.formBuilder.group(({
|
this.searchForm = this.formBuilder.group(({
|
||||||
@@ -70,6 +93,13 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.initialisePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will initialise the page
|
||||||
|
*/
|
||||||
|
initialisePage() {
|
||||||
this.isEPersonFormShown = false;
|
this.isEPersonFormShown = false;
|
||||||
this.search({ scope: this.currentSearchScope, query: this.currentSearchQuery });
|
this.search({ scope: this.currentSearchScope, query: this.currentSearchQuery });
|
||||||
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
|
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
|
||||||
@@ -84,18 +114,10 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
|
|||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
onPageChange(event) {
|
onPageChange(event) {
|
||||||
|
if (this.config.currentPage !== event) {
|
||||||
this.config.currentPage = event;
|
this.config.currentPage = event;
|
||||||
this.search({ scope: this.currentSearchScope, query: this.currentSearchQuery })
|
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' })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,10 +137,33 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
|
|||||||
this.currentSearchScope = scope;
|
this.currentSearchScope = scope;
|
||||||
this.config.currentPage = 1;
|
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,
|
currentPage: this.config.currentPage,
|
||||||
elementsPerPage: this.config.pageSize
|
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) {
|
deleteEPerson(ePerson: EPerson) {
|
||||||
if (hasValue(ePerson.id)) {
|
if (hasValue(ePerson.id)) {
|
||||||
this.epersonService.deleteEPerson(ePerson).pipe(take(1)).subscribe((success: boolean) => {
|
const modalRef = this.modalService.open(ConfirmationModalComponent);
|
||||||
if (success) {
|
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.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: ePerson.name }));
|
||||||
this.forceUpdateEPeople();
|
this.reset();
|
||||||
} else {
|
} else {
|
||||||
this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.deleted.failure', { name: ePerson.name }));
|
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);
|
||||||
}
|
}
|
||||||
this.epersonService.cancelEditEPerson();
|
|
||||||
this.isEPersonFormShown = false;
|
|
||||||
})
|
})
|
||||||
|
}}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,6 +232,10 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
|
|||||||
* Unsub all subscriptions
|
* Unsub all subscriptions
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
this.cleanupSubscribes();
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupSubscribes() {
|
||||||
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
|
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,4 +258,18 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
this.search({ query: '' });
|
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();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
<button class="btn btn-light" [disabled]="!(canReset$ | async)">
|
<button class="btn btn-light" [disabled]="!(canReset$ | async)">
|
||||||
<i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}}
|
<i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-light" [disabled]="!(canDelete$ | async)">
|
<button class="btn btn-light delete-button" [disabled]="!(canDelete$ | async)" (click)="delete()">
|
||||||
<i class="fa fa-trash"></i> {{'admin.access-control.epeople.actions.delete' | translate}}
|
<i class="fa fa-trash"></i> {{'admin.access-control.epeople.actions.delete' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button *ngIf="!isImpersonated" class="btn btn-light" [ngClass]="{'d-none' : !(canImpersonate$ | async)}" (click)="impersonate()">
|
<button *ngIf="!isImpersonated" class="btn btn-light" [ngClass]="{'d-none' : !(canImpersonate$ | async)}" (click)="impersonate()">
|
||||||
|
@@ -1,34 +1,25 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { Store } from '@ngrx/store';
|
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule, By } from '@angular/platform-browser';
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
|
|
||||||
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
|
|
||||||
import { RestResponse } from '../../../../core/cache/response.models';
|
import { RestResponse } from '../../../../core/cache/response.models';
|
||||||
import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
|
|
||||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||||
import { RemoteData } from '../../../../core/data/remote-data';
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
import { FindListOptions } from '../../../../core/data/request.models';
|
import { FindListOptions } from '../../../../core/data/request.models';
|
||||||
import { EPersonDataService } from '../../../../core/eperson/eperson-data.service';
|
import { EPersonDataService } from '../../../../core/eperson/eperson-data.service';
|
||||||
import { EPerson } from '../../../../core/eperson/models/eperson.model';
|
import { EPerson } from '../../../../core/eperson/models/eperson.model';
|
||||||
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
|
|
||||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||||
import { UUIDService } from '../../../../core/shared/uuid.service';
|
|
||||||
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
|
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
|
||||||
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
import { EPeopleRegistryComponent } from '../epeople-registry.component';
|
|
||||||
import { EPersonFormComponent } from './eperson-form.component';
|
import { EPersonFormComponent } from './eperson-form.component';
|
||||||
import { EPersonMock, EPersonMock2 } from '../../../../shared/testing/eperson.mock';
|
import { EPersonMock, EPersonMock2 } from '../../../../shared/testing/eperson.mock';
|
||||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
|
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
|
||||||
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
|
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
|
||||||
import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock';
|
|
||||||
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
|
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
|
||||||
import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock';
|
import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock';
|
||||||
import { AuthService } from '../../../../core/auth/auth.service';
|
import { AuthService } from '../../../../core/auth/auth.service';
|
||||||
@@ -36,11 +27,11 @@ import { AuthServiceStub } from '../../../../shared/testing/auth-service.stub';
|
|||||||
import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { GroupDataService } from '../../../../core/eperson/group-data.service';
|
import { GroupDataService } from '../../../../core/eperson/group-data.service';
|
||||||
import { createPaginatedList } from '../../../../shared/testing/utils.test';
|
import { createPaginatedList } from '../../../../shared/testing/utils.test';
|
||||||
|
import { RequestService } from '../../../../core/data/request.service';
|
||||||
|
|
||||||
describe('EPersonFormComponent', () => {
|
describe('EPersonFormComponent', () => {
|
||||||
let component: EPersonFormComponent;
|
let component: EPersonFormComponent;
|
||||||
let fixture: ComponentFixture<EPersonFormComponent>;
|
let fixture: ComponentFixture<EPersonFormComponent>;
|
||||||
let translateService: TranslateService;
|
|
||||||
let builderService: FormBuilderService;
|
let builderService: FormBuilderService;
|
||||||
|
|
||||||
let mockEPeople;
|
let mockEPeople;
|
||||||
@@ -111,7 +102,6 @@ describe('EPersonFormComponent', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
builderService = getMockFormBuilderService();
|
builderService = getMockFormBuilderService();
|
||||||
translateService = getMockTranslateService();
|
|
||||||
authService = new AuthServiceStub();
|
authService = new AuthServiceStub();
|
||||||
authorizationService = jasmine.createSpyObj('authorizationService', {
|
authorizationService = jasmine.createSpyObj('authorizationService', {
|
||||||
isAuthorized: observableOf(true)
|
isAuthorized: observableOf(true)
|
||||||
@@ -129,22 +119,15 @@ describe('EPersonFormComponent', () => {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
declarations: [EPeopleRegistryComponent, EPersonFormComponent],
|
declarations: [EPersonFormComponent],
|
||||||
providers: [EPersonFormComponent,
|
providers: [
|
||||||
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
|
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
|
||||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
{ provide: GroupDataService, useValue: groupsDataService },
|
||||||
{ provide: FormBuilderService, useValue: builderService },
|
{ provide: FormBuilderService, useValue: builderService },
|
||||||
{ provide: DSOChangeAnalyzer, useValue: {} },
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
||||||
{ provide: HttpClient, useValue: {} },
|
|
||||||
{ provide: ObjectCacheService, useValue: {} },
|
|
||||||
{ provide: UUIDService, useValue: {} },
|
|
||||||
{ provide: Store, useValue: {} },
|
|
||||||
{ provide: RemoteDataBuildService, useValue: {} },
|
|
||||||
{ provide: HALEndpointService, useValue: {} },
|
|
||||||
{ provide: AuthService, useValue: authService },
|
{ provide: AuthService, useValue: authService },
|
||||||
{ provide: AuthorizationDataService, useValue: authorizationService },
|
{ provide: AuthorizationDataService, useValue: authorizationService },
|
||||||
{ provide: GroupDataService, useValue: groupsDataService },
|
{ provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring'])}
|
||||||
EPeopleRegistryComponent
|
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
@@ -156,9 +139,9 @@ describe('EPersonFormComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create EPersonFormComponent', inject([EPersonFormComponent], (comp: EPersonFormComponent) => {
|
it('should create EPersonFormComponent', () => {
|
||||||
expect(comp).toBeDefined();
|
expect(component).toBeDefined();
|
||||||
}));
|
});
|
||||||
|
|
||||||
describe('when submitting the form', () => {
|
describe('when submitting the form', () => {
|
||||||
let firstName;
|
let firstName;
|
||||||
@@ -283,4 +266,53 @@ describe('EPersonFormComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('delete', () => {
|
||||||
|
|
||||||
|
let ePersonId;
|
||||||
|
let eperson: EPerson;
|
||||||
|
let modalService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(authService, 'impersonate').and.callThrough();
|
||||||
|
ePersonId = 'testEPersonId';
|
||||||
|
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', () => {
|
||||||
|
const deleteButton = fixture.debugElement.query(By.css('.delete-button'));
|
||||||
|
expect(deleteButton.nativeElement.disabled).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('the delete button should be disabled if the eperson cannot be deleted', () => {
|
||||||
|
component.canDelete$ = observableOf(false);
|
||||||
|
fixture.detectChanges()
|
||||||
|
const deleteButton = fixture.debugElement.query(By.css('.delete-button'));
|
||||||
|
expect(deleteButton.nativeElement.disabled).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('should call the epersonService delete when clicked on the button' , () => {
|
||||||
|
// ePersonDataServiceStub.activeEPerson = eperson;
|
||||||
|
spyOn(component.epersonService, 'deleteEPerson').and.returnValue(observableOf(new RestResponse(true, 204, 'No Content')));
|
||||||
|
const deleteButton = fixture.debugElement.query(By.css('.delete-button'));
|
||||||
|
expect(deleteButton.nativeElement.disabled).toBe(false);
|
||||||
|
deleteButton.triggerEventHandler('click', null);
|
||||||
|
fixture.detectChanges()
|
||||||
|
expect(component.epersonService.deleteEPerson).toHaveBeenCalledWith(eperson);
|
||||||
|
});
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
@@ -25,6 +25,9 @@ import { PaginationComponentOptions } from '../../../../shared/pagination/pagina
|
|||||||
import { AuthService } from '../../../../core/auth/auth.service';
|
import { AuthService } from '../../../../core/auth/auth.service';
|
||||||
import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../../core/data/feature-authorization/feature-id';
|
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({
|
@Component({
|
||||||
selector: 'ds-eperson-form',
|
selector: 'ds-eperson-form',
|
||||||
@@ -116,9 +119,8 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Observable whether or not the admin is allowed to delete the EPerson
|
* Observable whether or not the admin is allowed to delete the EPerson
|
||||||
* TODO: Initialize the observable once the REST API supports this (currently hardcoded to return false)
|
|
||||||
*/
|
*/
|
||||||
canDelete$: Observable<boolean> = of(false);
|
canDelete$: Observable<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observable whether or not the admin is allowed to impersonate the EPerson
|
* Observable whether or not the admin is allowed to impersonate the EPerson
|
||||||
@@ -160,7 +162,9 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
|||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private authService: AuthService,
|
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.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
|
||||||
this.epersonInitial = eperson;
|
this.epersonInitial = eperson;
|
||||||
if (hasValue(eperson)) {
|
if (hasValue(eperson)) {
|
||||||
@@ -170,6 +174,13 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.initialisePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will initialise the page
|
||||||
|
*/
|
||||||
|
initialisePage() {
|
||||||
combineLatest(
|
combineLatest(
|
||||||
this.translateService.get(`${this.messagePrefix}.firstName`),
|
this.translateService.get(`${this.messagePrefix}.firstName`),
|
||||||
this.translateService.get(`${this.messagePrefix}.lastName`),
|
this.translateService.get(`${this.messagePrefix}.lastName`),
|
||||||
@@ -247,6 +258,9 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
|||||||
this.canImpersonate$ = this.epersonService.getActiveEPerson().pipe(
|
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))
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,6 +419,35 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
|||||||
this.isImpersonated = true;
|
this.isImpersonated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the EPerson from the Repository. The EPerson will be the only that this form is showing.
|
||||||
|
* 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) => {
|
||||||
|
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();
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop impersonating the EPerson
|
* Stop impersonating the EPerson
|
||||||
*/
|
*/
|
||||||
@@ -420,4 +463,14 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
|||||||
this.onCancel();
|
this.onCancel();
|
||||||
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
export enum FeatureID {
|
export enum FeatureID {
|
||||||
LoginOnBehalfOf = 'loginOnBehalfOf',
|
LoginOnBehalfOf = 'loginOnBehalfOf',
|
||||||
AdministratorOf = 'administratorOf',
|
AdministratorOf = 'administratorOf',
|
||||||
|
CanDelete = 'canDelete',
|
||||||
WithdrawItem = 'withdrawItem',
|
WithdrawItem = 'withdrawItem',
|
||||||
ReinstateItem = 'reinstateItem',
|
ReinstateItem = 'reinstateItem',
|
||||||
EPersonRegistration = 'epersonRegistration',
|
EPersonRegistration = 'epersonRegistration',
|
||||||
|
@@ -5,7 +5,7 @@ import { HttpClient, HttpHeaders, HttpParams, HttpResponse } from '@angular/comm
|
|||||||
|
|
||||||
import { DSpaceRESTV2Response } from './dspace-rest-v2-response.model';
|
import { DSpaceRESTV2Response } from './dspace-rest-v2-response.model';
|
||||||
import { RestRequestMethod } from '../data/rest-request-method';
|
import { RestRequestMethod } from '../data/rest-request-method';
|
||||||
import { hasNoValue, isNotEmpty } from '../../shared/empty.util';
|
import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||||
|
|
||||||
export const DEFAULT_CONTENT_TYPE = 'application/json; charset=utf-8';
|
export const DEFAULT_CONTENT_TYPE = 'application/json; charset=utf-8';
|
||||||
@@ -53,7 +53,7 @@ export class DSpaceRESTv2Service {
|
|||||||
return observableThrowError({
|
return observableThrowError({
|
||||||
statusCode: err.status,
|
statusCode: err.status,
|
||||||
statusText: err.statusText,
|
statusText: err.statusText,
|
||||||
message: err.message
|
message: (hasValue(err.error) && isNotEmpty(err.error.message)) ? err.error.message : err.message
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ export class DSpaceRESTv2Service {
|
|||||||
return observableThrowError({
|
return observableThrowError({
|
||||||
statusCode: err.status,
|
statusCode: err.status,
|
||||||
statusText: err.statusText,
|
statusText: err.statusText,
|
||||||
message: err.message
|
message: (hasValue(err.error) && isNotEmpty(err.error.message)) ? err.error.message : err.message
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { createSelector, select, Store } from '@ngrx/store';
|
import { createSelector, select, Store } from '@ngrx/store';
|
||||||
import { Operation } from 'fast-json-patch/lib/core';
|
import { Operation } from 'fast-json-patch/lib/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { filter, find, map, skipWhile, switchMap, take, tap } from 'rxjs/operators';
|
import { filter, find, map, take } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
EPeopleRegistryCancelEPersonAction,
|
EPeopleRegistryCancelEPersonAction,
|
||||||
EPeopleRegistryEditEPersonAction
|
EPeopleRegistryEditEPersonAction
|
||||||
@@ -223,8 +223,8 @@ export class EPersonDataService extends DataService<EPerson> {
|
|||||||
* Method to delete an EPerson
|
* Method to delete an EPerson
|
||||||
* @param ePerson The EPerson to delete
|
* @param ePerson The EPerson to delete
|
||||||
*/
|
*/
|
||||||
public deleteEPerson(ePerson: EPerson): Observable<boolean> {
|
public deleteEPerson(ePerson: EPerson): Observable<RestResponse> {
|
||||||
return this.delete(ePerson.id).pipe(map((response: RestResponse) => response.isSuccessful));
|
return this.delete(ePerson.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -299,34 +299,4 @@ export class EPersonDataService extends DataService<EPerson> {
|
|||||||
map((request: RequestEntry) => request.response)
|
map((request: RequestEntry) => request.response)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Make a new FindListRequest with given search method
|
|
||||||
*
|
|
||||||
* @param searchMethod The search method for the object
|
|
||||||
* @param options The [[FindListOptions]] object
|
|
||||||
* @param linksToFollow The array of [[FollowLinkConfig]]
|
|
||||||
* @return {Observable<RemoteData<PaginatedList<EPerson>>}
|
|
||||||
* Return an observable that emits response from the server
|
|
||||||
*/
|
|
||||||
searchBy(searchMethod: string, options: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<EPerson>>): Observable<RemoteData<PaginatedList<EPerson>>> {
|
|
||||||
const hrefObs = this.getSearchByHref(searchMethod, options, ...linksToFollow);
|
|
||||||
|
|
||||||
return hrefObs.pipe(
|
|
||||||
find((href: string) => hasValue(href)),
|
|
||||||
tap((href: string) => {
|
|
||||||
this.requestService.removeByHrefSubstring(href);
|
|
||||||
const request = new FindListRequest(this.requestService.generateRequestId(), href, options);
|
|
||||||
|
|
||||||
this.requestService.configure(request);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
switchMap((href) => this.requestService.getByHref(href)),
|
|
||||||
skipWhile((requestEntry) => hasValue(requestEntry) && requestEntry.completed),
|
|
||||||
switchMap((href) =>
|
|
||||||
this.rdbService.buildList<EPerson>(hrefObs, ...linksToFollow) as Observable<RemoteData<PaginatedList<EPerson>>>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
17
src/app/core/eperson/models/eperson-dto.model.ts
Normal file
17
src/app/core/eperson/models/eperson-dto.model.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { EPerson } from './eperson.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class serves as a Data Transfer Model that contains the EPerson and whether or not it's able to be deleted
|
||||||
|
*/
|
||||||
|
export class EpersonDtoModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EPerson linked to this object
|
||||||
|
*/
|
||||||
|
public eperson: EPerson;
|
||||||
|
/**
|
||||||
|
* Whether or not the linked EPerson is able to be deleted
|
||||||
|
*/
|
||||||
|
public ableToDelete: boolean;
|
||||||
|
|
||||||
|
}
|
@@ -258,6 +258,10 @@
|
|||||||
|
|
||||||
"admin.access-control.epeople.form.notification.edited.failure": "Failed to edit EPerson \"{{name}}\"",
|
"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.groupsEPersonIsMemberOf": "Member of these groups:",
|
||||||
|
|
||||||
"admin.access-control.epeople.form.table.id": "ID",
|
"admin.access-control.epeople.form.table.id": "ID",
|
||||||
@@ -1065,6 +1069,13 @@
|
|||||||
|
|
||||||
"confirmation-modal.export-metadata.confirm": "Export",
|
"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",
|
"error.bitstream": "Error fetching bitstream",
|
||||||
|
Reference in New Issue
Block a user