Skip to content

Commit 7d4c8da

Browse files
mprinsCopilot
andauthored
HTM-1649: Add a password reset page (#1022)
* HTM-1690: Refactor tailormap-viewer: for the move of /validate-password * Move NAME_REGEX to common API so it can be used in the viewer and the admin * HTM-1649: add password reset page * fix testcase and localsation keys * Add Dutch and German translations * lint fixes * fix tests after refactoring * fix interpolation translation * Update projects/core/src/lib/pages/password-reset/password-reset.component.ts Co-authored-by: Copilot <[email protected]> * Update projects/core/assets/locale/messages.core.nl.xlf Co-authored-by: Copilot <[email protected]> * Update projects/core/assets/locale/messages.core.en.xlf Co-authored-by: Copilot <[email protected]> * Update projects/core/assets/locale/messages.core.de.xlf Co-authored-by: Copilot <[email protected]> * Fix typo in success message for password reset * Add return to login link to the bottom of the reset password email form * hide form when token has expired * HTM-1690: Refactor tailormap-viewer: for the move of /validate-password * Move NAME_REGEX to common API so it can be used in the viewer and the admin * HTM-1649: add password reset page * fix testcase and localsation keys * Add Dutch and German translations * lint fixes * fix tests after refactoring * fix interpolation translation * Update projects/core/src/lib/pages/password-reset/password-reset.component.ts Co-authored-by: Copilot <[email protected]> * Update projects/core/assets/locale/messages.core.nl.xlf Co-authored-by: Copilot <[email protected]> * Update projects/core/assets/locale/messages.core.en.xlf Co-authored-by: Copilot <[email protected]> * Update projects/core/assets/locale/messages.core.de.xlf Co-authored-by: Copilot <[email protected]> * Fix typo in success message for password reset * Add return to login link to the bottom of the reset password email form * hide form when token has expired * fix testcase after form changes --------- Co-authored-by: Copilot <[email protected]>
1 parent 11e6b50 commit 7d4c8da

27 files changed

+490
-29
lines changed

projects/admin-api/src/lib/services/tailormap-admin-api-v1-mock.service.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,6 @@ export class TailormapAdminApiV1MockService implements TailormapAdminApiV1Servic
136136
return of(true).pipe(delay(this.delay));
137137
}
138138

139-
public validatePasswordStrength$(_password: string): Observable<boolean> {
140-
return of(true).pipe(delay(this.delay));
141-
}
142-
143139
public updateUser$(params: { username: string; user: Omit<UserModel, 'groupNames'> & { groups: string[] } }): Observable<UserModel> {
144140
return of({ ...params.user, groupNames: params.user.groups }).pipe(delay(this.delay));
145141
}

projects/admin-api/src/lib/services/tailormap-admin-api-v1-service.model.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ export interface TailormapAdminApiV1ServiceModel {
3737
createUser$(params: { user: Omit<UserModel, 'groupNames'> & { groups: string[] } }): Observable<UserModel>;
3838
updateUser$(params: { username: string; user: Partial<Omit<UserModel, 'groupNames'>> & { groups: string[] } }): Observable<UserModel>;
3939
deleteUser$(username: string): Observable<boolean>;
40-
validatePasswordStrength$(password: string): Observable<boolean>;
4140
getApplications$(): Observable<ApplicationModel[]>;
4241
createApplication$(params: { application: Partial<Omit<ApplicationModel, 'id'>> }): Observable<ApplicationModel>;
4342
updateApplication$(params: { id: string; application: Partial<ApplicationModel> }): Observable<ApplicationModel>;

projects/admin-api/src/lib/services/tailormap-admin-api-v1.service.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,6 @@ export class TailormapAdminApiV1Service implements TailormapAdminApiV1ServiceMod
207207
);
208208
}
209209

210-
public validatePasswordStrength$(password: string): Observable<boolean> {
211-
const body = new HttpParams().set('password', password);
212-
return this.httpClient.post<{ result: boolean }>(`${TailormapAdminApiV1Service.BASE_URL}/validate-password`, body)
213-
.pipe(map(response => response.result));
214-
}
215-
216210
public getApplications$(): Observable<ApplicationModel[]> {
217211
return this.httpClient.get<{ _embedded: { applications: ApplicationModel[] }}>(`${TailormapAdminApiV1Service.BASE_URL}/applications?size=1000&sort=title`)
218212
.pipe(map(response => response._embedded.applications));

projects/admin-core/src/lib/application/application-form/application-form.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Component, OnInit, ChangeDetectionStrategy, Input, Output, EventEmitter, OnDestroy, inject } from '@angular/core';
22
import { AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
3-
import { BoundsModel, I18nSettingsModel, UiSettingsModel } from '@tailormap-viewer/api';
3+
import { BoundsModel, I18nSettingsModel, UiSettingsModel, ValidatorsHelper } from '@tailormap-viewer/api';
44
import { ApplicationModel, GroupModel, AuthorizationRuleGroup, AUTHORIZATION_RULE_ANONYMOUS } from '@tailormap-admin/admin-api';
55
import { Observable, debounceTime, filter, Subject, takeUntil, map, distinctUntilChanged } from 'rxjs';
66
import { FormHelper } from '../../helpers/form.helper';
@@ -51,7 +51,7 @@ export class ApplicationFormComponent implements OnInit, OnDestroy {
5151
nonNullable: true,
5252
validators: [
5353
Validators.required,
54-
Validators.pattern(FormHelper.NAME_REGEX),
54+
Validators.pattern(ValidatorsHelper.NAME_REGEX),
5555
this.isUniqueApplicationName(),
5656
],
5757
}),

projects/admin-core/src/lib/helpers/form.helper.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ export type ComparableValuesArray = Array<[ValueType, ValueType]>;
66

77
export class FormHelper {
88

9-
public static NAME_REGEX = /^[a-zA-Z0-9\-_]+$/;
10-
119
public static isValidValue(value: string | undefined | null) {
1210
return typeof value !== 'undefined' && value !== null && value.length > 0;
1311
}

projects/admin-core/src/lib/user/group-form/group-form.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, OnI
22
import { FormControl, FormGroup, Validators } from '@angular/forms';
33
import { BehaviorSubject, combineLatest, debounceTime, map, Observable, of, Subject, takeUntil } from 'rxjs';
44
import { AdditionalPropertyModel, GroupModel, OIDCConfigurationModel } from '@tailormap-admin/admin-api';
5-
import { FormHelper } from '../../helpers/form.helper';
65
import { AdminFieldLocation, AdminFieldModel, AdminFieldRegistrationService } from '../../shared/services/admin-field-registration.service';
76
import { GroupService } from '../services/group.service';
87
import { OIDCConfigurationService } from '../../oidc/services/oidc-configuration.service';
8+
import { ValidatorsHelper } from '@tailormap-viewer/api';
99

1010
@Component({
1111
selector: 'tm-admin-group-form',
@@ -23,7 +23,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
2323
public groupForm = new FormGroup({
2424
name: new FormControl<string>('', {
2525
nonNullable: true,
26-
validators: [ Validators.required, Validators.pattern(FormHelper.NAME_REGEX) ],
26+
validators: [ Validators.required, Validators.pattern(ValidatorsHelper.NAME_REGEX) ],
2727
}),
2828
description: new FormControl<string>('', { nonNullable: false }),
2929
aliasForGroup: new FormControl<string>('', { nonNullable: false }),

projects/admin-core/src/lib/user/services/user.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
99
import { selectUsers, selectUsersLoadStatus } from '../state/user.selectors';
1010
import { DebounceHelper, LoadingStateEnum } from '@tailormap-viewer/shared';
1111
import { UserAddUpdateModel } from '../models/user-add-update.model';
12+
import { TailormapSecurityApiV1Service } from '@tailormap-viewer/api';
1213

1314
@Injectable({
1415
providedIn: 'root',
1516
})
1617
export class UserService {
1718
private adminApiService = inject(TailormapAdminApiV1Service);
19+
private securityApiService = inject(TailormapSecurityApiV1Service);
1820
private store$ = inject(Store);
1921
private adminSnackbarService = inject(AdminSnackbarService);
2022
private sseService = inject(AdminSseService);
@@ -111,7 +113,7 @@ export class UserService {
111113
}
112114

113115
public validatePasswordStrength$(password: string) {
114-
return this.adminApiService.validatePasswordStrength$(password);
116+
return this.securityApiService.validatePasswordStrength$(password);
115117
}
116118

117119
private updateUserState(

projects/admin-core/src/lib/user/user-form/user-form.component.spec.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import { initialUserState, userStateKey } from '../state/user.state';
1010
import { MatIconTestingModule } from '@angular/material/icon/testing';
1111
import { SharedAdminComponentsModule } from '../../shared/components/shared-admin-components.module';
1212
import { AuthenticatedUserTestHelper } from '../../test-helpers/authenticated-user-test.helper.spec';
13+
import { TailormapSecurityApiV1Service } from '@tailormap-viewer/api';
1314

1415
const setup = async (isValidPassword: boolean) => {
15-
const mockApiService = {
16+
const mockAdminApiService = {
1617
getGroups$: jest.fn(() => of([])),
1718
getUsers$: jest.fn(() => of([])),
19+
};
20+
const mockApiService = {
1821
validatePasswordStrength$: jest.fn(() => of(isValidPassword)),
1922
};
2023
const userUpdated = jest.fn();
@@ -23,7 +26,8 @@ const setup = async (isValidPassword: boolean) => {
2326
declarations: [PasswordFieldComponent],
2427
on: { userUpdated },
2528
providers: [
26-
{ provide: TailormapAdminApiV1Service, useValue: mockApiService },
29+
{ provide: TailormapAdminApiV1Service, useValue: mockAdminApiService },
30+
{ provide: TailormapSecurityApiV1Service, useValue: mockApiService },
2731
provideMockStore({ initialState: { [userStateKey]: initialUserState } }),
2832
AuthenticatedUserTestHelper.provideAuthenticatedUserServiceWithAdminUser(),
2933
],

projects/admin-core/src/lib/user/user-form/user-form.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { GroupService } from '../services/group.service';
66
import { formatDate } from '@angular/common';
77
import { UserService } from '../services/user.service';
88
import { UserAddUpdateModel } from '../models/user-add-update.model';
9-
import { FormHelper } from '../../helpers/form.helper';
109
import { AdminFieldLocation, AdminFieldModel, AdminFieldRegistrationService } from '../../shared/services/admin-field-registration.service';
10+
import { ValidatorsHelper } from '@tailormap-viewer/api';
1111

1212
@Component({
1313
selector: 'tm-admin-user-form',
@@ -25,7 +25,7 @@ export class UserFormComponent implements OnInit, OnDestroy {
2525
public userForm = new FormGroup({
2626
username: new FormControl<string>('', {
2727
nonNullable: true,
28-
validators: [ Validators.required, Validators.pattern(FormHelper.NAME_REGEX) ],
28+
validators: [ Validators.required, Validators.pattern(ValidatorsHelper.NAME_REGEX) ],
2929
}),
3030
password: new FormControl<string>('', {
3131
nonNullable: true,

projects/admin-core/src/lib/user/user-list/user-list.component.spec.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ import { provideMockStore } from '@ngrx/store/testing';
88
import { initialUserState, userStateKey } from '../state/user.state';
99
import { AuthenticatedUserTestHelper } from '../../test-helpers/authenticated-user-test.helper.spec';
1010
import { SharedAdminComponentsModule } from '../../shared/components/shared-admin-components.module';
11+
import { TailormapSecurityApiV1Service } from '@tailormap-viewer/api';
1112

1213
const setup = async () => {
13-
const mockApiService = {
14+
const mockAdminApiService = {
1415
getUsers$: jest.fn(() => of(getUsers)),
1516
};
17+
const mockApiService = {};
1618

1719
await render(UserListComponent, {
1820
imports: [ SharedModule, MatListModule, SharedAdminComponentsModule ],
1921
providers: [
20-
{ provide: TailormapAdminApiV1Service, useValue: mockApiService },
22+
{ provide: TailormapAdminApiV1Service, useValue: mockAdminApiService },
23+
{ provide: TailormapSecurityApiV1Service, useValue: mockApiService },
2124
provideMockStore({ initialState: { [userStateKey]: initialUserState } }),
2225
AuthenticatedUserTestHelper.provideAuthenticatedUserServiceWithAdminUser(),
2326
],

0 commit comments

Comments
 (0)