From 21e78e33e525b95a6ea64040f5b9636abadbf87c Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Tue, 14 Sep 2021 10:20:29 +0200 Subject: [PATCH 1/4] [CST-5065] Admin is unable to reset other user password (cherry pick from DSC-215) --- .../eperson-form/eperson-form.component.html | 4 ++++ .../eperson-form/eperson-form.component.ts | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html index 45326c1abc..5d80f24990 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html @@ -36,9 +36,13 @@ + +
{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}
+ + = observableOf(false); + canReset$: Observable; /** * Observable whether or not the admin is allowed to delete the EPerson @@ -310,6 +310,11 @@ export class EPersonFormComponent implements OnInit, OnDestroy { this.canDelete$ = activeEPerson$.pipe( switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined)) ); + this.canReset$ = activeEPerson$.pipe( + switchMap((eperson) => { + return observableOf(true); + }) + ); }); } From 6a1bbc8afc9551728ba662303e4018ecb7408f9a Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 21 Dec 2021 12:43:13 +0100 Subject: [PATCH 2/4] [CST-5065] Admin is unable to reset other user password (function implementation) --- .../eperson-form/eperson-form.component.html | 4 +- .../eperson-form.component.spec.ts | 28 ++++++++++- .../eperson-form/eperson-form.component.ts | 47 ++++++++++++++----- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html index 5d80f24990..41ae67423c 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html @@ -19,7 +19,7 @@ class="btn btn-outline-secondary"> {{messagePrefix + '.return' | translate}}
-
@@ -42,7 +42,7 @@
{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}
- + { @@ -42,6 +43,7 @@ describe('EPersonFormComponent', () => { let authService: AuthServiceStub; let authorizationService: AuthorizationDataService; let groupsDataService: GroupDataService; + let epersonRegistrationService: EpersonRegistrationService; let paginationService; @@ -205,6 +207,10 @@ describe('EPersonFormComponent', () => { }).compileComponents(); })); + epersonRegistrationService = jasmine.createSpyObj('epersonRegistrationService', { + registerEmail: createSuccessfulRemoteDataObject$(null) + }); + beforeEach(() => { fixture = TestBed.createComponent(EPersonFormComponent); component = fixture.componentInstance; @@ -514,4 +520,24 @@ describe('EPersonFormComponent', () => { expect(component.epersonService.deleteEPerson).toHaveBeenCalledWith(eperson); }); }); + + + describe('Reset Password', () => { + let ePersonId; + let ePersonEmail; + + beforeEach(() => { + ePersonId = 'testEPersonId'; + ePersonEmail = 'person.email@4science.it'; + component.epersonInitial = Object.assign(new EPerson(), { + id: ePersonId, + email: ePersonEmail + }); + component.resetPassword(); + }); + + it('should call epersonRegistrationService.registerEmail', () => { + expect(epersonRegistrationService.registerEmail).toHaveBeenCalledWith(ePersonEmail); + }); + }); }); diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts index 8e248a17d8..0d6d9feaec 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts @@ -34,6 +34,8 @@ import { NoContent } from '../../../core/shared/NoContent.model'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { followLink } from '../../../shared/utils/follow-link-config.model'; import { ValidateEmailNotTaken } from './validators/email-taken.validator'; +import { Registration } from '../../../core/shared/registration.model'; +import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service'; @Component({ selector: 'ds-eperson-form', @@ -167,17 +169,20 @@ export class EPersonFormComponent implements OnInit, OnDestroy { */ emailValueChangeSubscribe: Subscription; - constructor(protected changeDetectorRef: ChangeDetectorRef, - public epersonService: EPersonDataService, - public groupsDataService: GroupDataService, - private formBuilderService: FormBuilderService, - private translateService: TranslateService, - private notificationsService: NotificationsService, - private authService: AuthService, - private authorizationService: AuthorizationDataService, - private modalService: NgbModal, - private paginationService: PaginationService, - public requestService: RequestService) { + constructor( + protected changeDetectorRef: ChangeDetectorRef, + public epersonService: EPersonDataService, + public groupsDataService: GroupDataService, + private formBuilderService: FormBuilderService, + private translateService: TranslateService, + private notificationsService: NotificationsService, + private authService: AuthService, + private authorizationService: AuthorizationDataService, + private modalService: NgbModal, + private paginationService: PaginationService, + public requestService: RequestService, + private epersonRegistrationService: EpersonRegistrationService, + ) { this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => { this.epersonInitial = eperson; if (hasValue(eperson)) { @@ -484,6 +489,26 @@ export class EPersonFormComponent implements OnInit, OnDestroy { this.isImpersonated = false; } + /** + * Sends an email to current eperson address with the information + * to reset password + */ + resetPassword() { + if (hasValue(this.epersonInitial.email)) { + this.epersonRegistrationService.registerEmail(this.epersonInitial.email).pipe(getFirstCompletedRemoteData()) + .subscribe((response: RemoteData) => { + if (response.hasSucceeded) { + this.notificationsService.success(this.translateService.get('admin.access-control.epeople.actions.reset'), + this.translateService.get('forgot-email.form.success.content', {email: this.epersonInitial.email})); + } else { + this.notificationsService.error(this.translateService.get('forgot-email.form.error.head'), + this.translateService.get('forgot-email.form.error.content', {email: this.epersonInitial.email})); + } + } + ); + } + } + /** * Cancel the current edit when component is destroyed & unsub all subscriptions */ From f46767be890f04af8204c6afe030aa81c893eb71 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 21 Dec 2021 13:06:16 +0100 Subject: [PATCH 3/4] [CST-5065] Tests fixed --- .../eperson-form/eperson-form.component.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts index 5593c77523..644b893265 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts @@ -2,7 +2,7 @@ import { Observable, of as observableOf } from 'rxjs'; import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { BrowserModule, By } from '@angular/platform-browser'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; @@ -14,6 +14,7 @@ import { EPerson } from '../../../core/eperson/models/eperson.model'; import { PageInfo } from '../../../core/shared/page-info.model'; import { FormBuilderService } from '../../../shared/form/builder/form-builder.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { EPeopleRegistryComponent } from '../epeople-registry.component'; import { EPersonFormComponent } from './eperson-form.component'; import { EPersonMock, EPersonMock2 } from '../../../shared/testing/eperson.mock'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; @@ -28,11 +29,9 @@ import { createPaginatedList } from '../../../shared/testing/utils.test'; import { RequestService } from '../../../core/data/request.service'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; import { ValidateEmailNotTaken } from './validators/email-taken.validator'; import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service'; - describe('EPersonFormComponent', () => { let component: EPersonFormComponent; let fixture: ComponentFixture; @@ -201,7 +200,9 @@ describe('EPersonFormComponent', () => { { provide: AuthService, useValue: authService }, { provide: AuthorizationDataService, useValue: authorizationService }, { provide: PaginationService, useValue: paginationService }, - { provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring']) } + { provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring'])}, + { provide: EpersonRegistrationService, useValue: epersonRegistrationService }, + EPeopleRegistryComponent ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -521,7 +522,6 @@ describe('EPersonFormComponent', () => { }); }); - describe('Reset Password', () => { let ePersonId; let ePersonEmail; From 8f2ef71e3c223196326d21f52364a9c66905214d Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 21 Dec 2021 13:53:17 +0100 Subject: [PATCH 4/4] [CST-5065] Fix --- .../epeople-registry/eperson-form/eperson-form.component.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts index 0d6d9feaec..05fc3189d0 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts @@ -315,11 +315,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy { this.canDelete$ = activeEPerson$.pipe( switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined)) ); - this.canReset$ = activeEPerson$.pipe( - switchMap((eperson) => { - return observableOf(true); - }) - ); + this.canReset$ = observableOf(true); }); }