From 6ba3a52477491a7056d0c82adede73b5bb289e27 Mon Sep 17 00:00:00 2001 From: George Nash Date: Mon, 20 Nov 2023 21:14:20 +0000 Subject: [PATCH 1/5] basic settings infrastructure and some small fixes --- .../account/settings/settings.component.html | 134 ++++++++++++++ .../account/settings/settings.component.scss | 0 .../settings/settings.component.spec.ts | 21 +++ .../account/settings/settings.component.ts | 168 ++++++++++++++++++ 4 files changed, 323 insertions(+) create mode 100644 ui/src/app/account/settings/settings.component.html create mode 100644 ui/src/app/account/settings/settings.component.scss create mode 100644 ui/src/app/account/settings/settings.component.spec.ts create mode 100644 ui/src/app/account/settings/settings.component.ts diff --git a/ui/src/app/account/settings/settings.component.html b/ui/src/app/account/settings/settings.component.html new file mode 100644 index 000000000..a3d2e4eac --- /dev/null +++ b/ui/src/app/account/settings/settings.component.html @@ -0,0 +1,134 @@ +
+
+
+

Personal details

+
+ +
+ Settings saved! +
+ + + +
+
+ + +
+ + Your first name is required. + + + Your first name is required to be at least 1 character. + + + Your first name cannot be longer than 50 characters. + +
+
+
+ + +
+ + Your last name is required. + + + Your last name is required to be at least 1 character. + + + Your last name cannot be longer than 50 characters. + +
+
+
+ + + +
+
+ + +
+ +
+
+ +
+

Security

+
+
+

Add extra security to your ORCID member portal account by enabling two-factor authentication. Each time you sign in, you'll be prompted to enter a six-digit code we send to your preferred authentication application.

+ + +
+
2FA settings updated
+
+
+
    +
  • Install a two-factor authentication app
    A 2FA app is required to create the six-digit code you need to access your account each time you sign in. Most apps are for mobile devices; some are also available as desktop or web-based apps. Download and install your preferred 2FA app, such as Google Authenticator, FreeOTP, or Authy.
  • +
  • Scan this QR code with your device
    Open your 2FA app and scan the image below.
  • +
+
+
+
+
+ +
+
+
+
+

{{ mfaSetup.secret }}

+
+
+
+
+
    +
  • Can't scan the QR code?
    Get a text code and enter it into your 2FA app instead
  • +
  • Enter the six-digit code from the app
    After scanning the QR code or entering in the text code, your 2FA app will display a six-digit code. Enter this code in the box below and click Save.
  • +
+
+
+
+
+
+ Incorrect verification code +
+ +
+
+
+
+

Make a note of the following backup codes, this is the only time they will be shown.

+ + + + +
{{ backupCode }}
+
+
+ +
+
+
+
+ +
diff --git a/ui/src/app/account/settings/settings.component.scss b/ui/src/app/account/settings/settings.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/ui/src/app/account/settings/settings.component.spec.ts b/ui/src/app/account/settings/settings.component.spec.ts new file mode 100644 index 000000000..c2333ad20 --- /dev/null +++ b/ui/src/app/account/settings/settings.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SettingsComponent } from './settings.component'; + +describe('SettingsComponent', () => { + let component: SettingsComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [SettingsComponent] + }); + fixture = TestBed.createComponent(SettingsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ui/src/app/account/settings/settings.component.ts b/ui/src/app/account/settings/settings.component.ts new file mode 100644 index 000000000..17c608937 --- /dev/null +++ b/ui/src/app/account/settings/settings.component.ts @@ -0,0 +1,168 @@ +import { Component, OnInit } from '@angular/core' +import { FormBuilder, Validators } from '@angular/forms' +import { AccountService } from '../service/account.service' +import { DomSanitizer } from '@angular/platform-browser' + +@Component({ + selector: 'app-settings', + templateUrl: './settings.component.html', + styleUrls: ['./settings.component.scss'], +}) +export class SettingsComponent implements OnInit { + error: string | undefined + success: string | undefined + languages: any[] | undefined + userName: string | undefined + mfaSetup: any + showMfaSetup: boolean | undefined + showMfaTextCode: boolean | undefined + mfaSetupFailure: boolean | undefined + mfaBackupCodes: string[] | undefined + showMfaBackupCodes: boolean | undefined + showMfaUpdated: boolean | undefined + settingsForm = this.fb.group({ + firstName: [undefined, [Validators.required, Validators.minLength(1), Validators.maxLength(50)]], + lastName: [undefined, [Validators.required, Validators.minLength(1), Validators.maxLength(50)]], + email: [undefined, [Validators.required, Validators.minLength(5), Validators.maxLength(254), Validators.email]], + activated: [false], + authorities: [[]], + langKey: ['en'], + imageUrl: [], + }) + mfaForm = this.fb.group({ + mfaEnabled: [[]], + verificationCode: [], + securitySave: [], + }) + + constructor( + private accountService: AccountService, + private fb: FormBuilder, + private languageService: JhiLanguageService, + private languageHelper: JhiLanguageHelper, + private sanitizer: DomSanitizer + ) {} + + ngOnInit() { + this.showMfaSetup = false + this.showMfaTextCode = false + this.showMfaBackupCodes = false + this.accountService.identity(true).then((account) => { + this.updateForm(account) + this.updateMfaForm(account) + this.userName = this.accountService.getUserName() + if (!account.mfaEnabled) { + this.accountService.getMfaSetup().subscribe((res) => { + this.mfaSetup = res.body + }) + } + }) + this.languageHelper.getAll().then((languages) => { + this.languages = languages + }) + } + + mfaEnabledStateChange(): void { + this.showMfaUpdated = false + const mfaEnabled = this.mfaForm.get('mfaEnabled').value + console.log('setup is ' + this.mfaSetup) + if (mfaEnabled && this.mfaSetup) { + this.showMfaSetup = true + this.showMfaBackupCodes = false + } else { + this.showMfaSetup = false + this.showMfaBackupCodes = false + } + } + + toggleMfaTextCode(): void { + this.showMfaTextCode = true + } + + save() { + const settingsAccount = this.accountFromForm() + this.accountService.save(settingsAccount).subscribe( + () => { + this.error = null + this.success = 'OK' + this.accountService.identity(true).then((account) => { + this.updateForm(account) + this.updateMfaForm(account) + }) + this.languageService.getCurrent().then((current) => { + if (settingsAccount.langKey !== current) { + this.languageService.changeLanguage(settingsAccount.langKey) + } + }) + }, + () => { + this.success = null + this.error = 'ERROR' + } + ) + } + + saveMfa() { + const enabled = this.mfaForm.get('mfaEnabled').value + if (enabled) { + const otp = this.mfaForm.get('verificationCode').value + this.mfaSetup.otp = otp + this.accountService.enableMfa(this.mfaSetup).subscribe( + (res) => { + this.mfaBackupCodes = res.body + this.showMfaBackupCodes = true + this.showMfaUpdated = true + }, + (err) => { + this.mfaSetupFailure = true + } + ) + } else { + this.accountService.disableMfa().subscribe( + () => { + this.showMfaUpdated = true + this.accountService.getMfaSetup().subscribe((res) => { + this.mfaSetup = res.body + }) + }, + (err) => console.log('error disabling mfa') + ) + } + } + + safeQrCode() { + return this.sanitizer.bypassSecurityTrustResourceUrl('data:image/png;base64, ' + this.mfaSetup.qrCode) + } + + private accountFromForm(): any { + const account = {} + return { + ...account, + firstName: this.settingsForm.get('firstName').value, + lastName: this.settingsForm.get('lastName').value, + email: this.settingsForm.get('email').value, + activated: this.settingsForm.get('activated').value, + authorities: this.settingsForm.get('authorities').value, + langKey: this.settingsForm.get('langKey').value, + imageUrl: this.settingsForm.get('imageUrl').value, + } + } + + updateForm(account: any): void { + this.settingsForm.patchValue({ + firstName: account.firstName, + lastName: account.lastName, + email: account.email, + activated: account.activated, + authorities: account.authorities, + langKey: account.langKey, + imageUrl: account.imageUrl, + }) + } + + updateMfaForm(account: any): void { + this.mfaForm.patchValue({ + mfaEnabled: account.mfaEnabled, + }) + } +} From 767ec0f896a47f3a764e052beccde98d84006e0e Mon Sep 17 00:00:00 2001 From: George Nash Date: Tue, 21 Nov 2023 14:18:21 +0000 Subject: [PATCH 2/5] settings component and start of test --- ui/src/app/account/account.module.ts | 8 +- ui/src/app/account/account.route.ts | 11 ++ ui/src/app/account/auth.guard.ts | 2 - ui/src/app/account/login/login.component.ts | 1 - ui/src/app/account/service/account.service.ts | 6 +- .../account/settings/settings.component.html | 36 +++-- .../settings/settings.component.spec.ts | 153 ++++++++++++++++-- .../account/settings/settings.component.ts | 89 +++++----- ui/src/app/app.module.ts | 4 +- .../app/layout/navbar/navbar.component.html | 2 +- .../app/shared/pipe/find-language-from-key.ts | 11 ++ ui/src/app/shared/service/language.service.ts | 30 ++++ ui/src/app/shared/shared.module.ts | 14 ++ 13 files changed, 286 insertions(+), 81 deletions(-) create mode 100644 ui/src/app/shared/pipe/find-language-from-key.ts create mode 100644 ui/src/app/shared/service/language.service.ts create mode 100644 ui/src/app/shared/shared.module.ts diff --git a/ui/src/app/account/account.module.ts b/ui/src/app/account/account.module.ts index 59bdfd816..13f05b381 100644 --- a/ui/src/app/account/account.module.ts +++ b/ui/src/app/account/account.module.ts @@ -3,11 +3,13 @@ import { CommonModule } from '@angular/common' import { LoginComponent } from './login/login.component' import { RouterModule } from '@angular/router' import { ReactiveFormsModule } from '@angular/forms' -import { routes } from './account.route'; +import { routes } from './account.route' import { PasswordResetInitComponent } from './password/password-reset-init.component' +import { SettingsComponent } from './settings/settings.component' +import { SharedModule } from '../shared/shared.module' @NgModule({ - declarations: [LoginComponent, PasswordResetInitComponent], - imports: [CommonModule, ReactiveFormsModule, RouterModule.forChild(routes)], + declarations: [LoginComponent, PasswordResetInitComponent, SettingsComponent], + imports: [SharedModule, CommonModule, ReactiveFormsModule, RouterModule.forChild(routes)], }) export class AccountModule {} diff --git a/ui/src/app/account/account.route.ts b/ui/src/app/account/account.route.ts index 48f4f60fd..8794f2b25 100644 --- a/ui/src/app/account/account.route.ts +++ b/ui/src/app/account/account.route.ts @@ -1,6 +1,8 @@ import { Routes } from '@angular/router' import { LoginComponent } from './login/login.component' import { PasswordResetInitComponent } from './password/password-reset-init.component' +import { SettingsComponent } from './settings/settings.component' +import { AuthGuard } from './auth.guard' export const routes: Routes = [ { @@ -15,4 +17,13 @@ export const routes: Routes = [ pageTitle: 'global.menu.account.password.string', }, }, + { + path: 'settings', + component: SettingsComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'global.menu.account.settings.string', + }, + canActivate: [AuthGuard], + }, ] diff --git a/ui/src/app/account/auth.guard.ts b/ui/src/app/account/auth.guard.ts index 4f49e9871..67718ff98 100644 --- a/ui/src/app/account/auth.guard.ts +++ b/ui/src/app/account/auth.guard.ts @@ -15,8 +15,6 @@ export const AuthGuard = (route: ActivatedRouteSnapshot, state: RouterStateSnaps return accountService.getAccountData().pipe( filter((account) => account !== undefined), map((account) => { - console.log(authorities, account) - if (account) { const hasAnyAuthority = accountService.hasAnyAuthority(authorities) if (hasAnyAuthority) { diff --git a/ui/src/app/account/login/login.component.ts b/ui/src/app/account/login/login.component.ts index edca1cc51..83bbc9c86 100644 --- a/ui/src/app/account/login/login.component.ts +++ b/ui/src/app/account/login/login.component.ts @@ -43,7 +43,6 @@ export class LoginComponent implements AfterViewInit, OnDestroy { ngOnDestroy(): void { this.sub?.unsubscribe() - console.log('test') } ngAfterViewInit() { diff --git a/ui/src/app/account/service/account.service.ts b/ui/src/app/account/service/account.service.ts index 7dc4be9ed..9d49fb025 100644 --- a/ui/src/app/account/service/account.service.ts +++ b/ui/src/app/account/service/account.service.ts @@ -67,8 +67,8 @@ export class AccountService { ) } - getMfaSetup(): Observable> { - return this.http.get('/services/userservice/api/account/mfa', { observe: 'response' }) + getMfaSetup(): Observable<{ secret: string; otp: string; qrCode: any }> { + return this.http.get('/services/userservice/api/account/mfa') } save(account: any): Observable> { @@ -90,8 +90,6 @@ export class AccountService { } hasAnyAuthority(authorities: string[]): boolean { - console.log(authorities, this.accountData.value?.authorities) - if (!this.authenticated || !this.accountData || !this.accountData.value?.authorities) { return false } diff --git a/ui/src/app/account/settings/settings.component.html b/ui/src/app/account/settings/settings.component.html index a3d2e4eac..26a6d4aa9 100644 --- a/ui/src/app/account/settings/settings.component.html +++ b/ui/src/app/account/settings/settings.component.html @@ -8,50 +8,52 @@

Personal details Settings saved! - - -
+
- + -
+
+ *ngIf="settingsForm.get('firstName')?.errors!['required']" jhiTranslate="settings.messages.validate.firstname.required.string"> Your first name is required. + *ngIf="settingsForm.get('firstName')?.errors!['minlength']" jhiTranslate="settings.messages.validate.firstname.minlength.string"> Your first name is required to be at least 1 character. + *ngIf="settingsForm.get('firstName')?.errors!['maxlength']" jhiTranslate="settings.messages.validate.firstname.maxlength.string"> Your first name cannot be longer than 50 characters.
- + + -
+
+ *ngIf="settingsForm.get('lastName')?.errors!['required']" jhiTranslate="settings.messages.validate.lastname.required.string"> Your last name is required. + *ngIf="settingsForm.get('lastName')?.errors!['minlength']" jhiTranslate="settings.messages.validate.lastname.minlength.string"> Your last name is required to be at least 1 character. + *ngIf="settingsForm.get('lastName')?.errors!['maxlength']" jhiTranslate="settings.messages.validate.lastname.maxlength.string"> Your last name cannot be longer than 50 characters.
- +
@@ -66,7 +68,7 @@

Personal details

Security


@@ -111,8 +113,10 @@

Security

Incorrect verification code
+ + + placeholder="{{'settings.security.verificationCode.string'}}" />
diff --git a/ui/src/app/account/settings/settings.component.spec.ts b/ui/src/app/account/settings/settings.component.spec.ts index c2333ad20..4459288b7 100644 --- a/ui/src/app/account/settings/settings.component.spec.ts +++ b/ui/src/app/account/settings/settings.component.spec.ts @@ -1,21 +1,148 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing' -import { SettingsComponent } from './settings.component'; +import { SettingsComponent } from './settings.component' +import { ReactiveFormsModule } from '@angular/forms' +import { HttpClientModule } from '@angular/common/http' +import { LanguageService } from 'src/app/shared/service/language.service' +import { AccountService } from '../service/account.service' +import { of } from 'rxjs' describe('SettingsComponent', () => { - let component: SettingsComponent; - let fixture: ComponentFixture; + let component: SettingsComponent + let fixture: ComponentFixture + let accountServiceSpy: jasmine.SpyObj + let languageServiceSpy: jasmine.SpyObj beforeEach(() => { + accountServiceSpy = jasmine.createSpyObj('AccountService', [ + 'getAccountData', + 'getUserName', + 'save', + 'getMfaSetup', + 'enableMfa', + 'disableMfa', + ]) + languageServiceSpy = jasmine.createSpyObj('LanguageService', [ + 'getAllLanguages', + 'getCurrentLanguage', + 'changeLanguage', + ]) + TestBed.configureTestingModule({ - declarations: [SettingsComponent] - }); - fixture = TestBed.createComponent(SettingsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + declarations: [SettingsComponent], + imports: [ReactiveFormsModule, HttpClientModule], + providers: [ + { provide: LanguageService, useValue: languageServiceSpy }, + { provide: AccountService, useValue: accountServiceSpy }, + ], + }).compileComponents() + + fixture = TestBed.createComponent(SettingsComponent) + component = fixture.componentInstance + accountServiceSpy = TestBed.inject(AccountService) as jasmine.SpyObj + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + accountServiceSpy.getAccountData.and.returnValue( + of({ + activated: true, + authorities: ['test', 'test'], + email: 'email@email.com', + firstName: 'name', + langKey: 'en', + lastName: 'surname', + imageUrl: 'url', + salesforceId: 'sfid', + loggedAs: false, + loginAs: 'sfid', + mainContact: false, + mfaEnabled: true, + }) + ) + + expect(component).toBeTruthy() + }) + + it('should flip mfa fields when mfa state changed', fakeAsync(() => { + accountServiceSpy.getAccountData.and.returnValue( + of({ + activated: true, + authorities: ['test', 'test'], + email: 'email@email.com', + firstName: 'name', + langKey: 'en', + lastName: 'surname', + imageUrl: 'url', + salesforceId: 'sfid', + loggedAs: false, + loginAs: 'sfid', + mainContact: false, + mfaEnabled: false, + }) + ) + accountServiceSpy.getMfaSetup.and.returnValue(of({ secret: 'test', otp: 'test', qrCode: 'test' })) + accountServiceSpy.getUserName.and.returnValue('test') + tick() + + expect(component.showMfaSetup).toBeFalsy() + expect(component.showMfaBackupCodes).toBeFalsy() + + component.mfaForm.patchValue({ mfaEnabled: true }) + component.mfaEnabledStateChange() + + expect(component.showMfaSetup).toBeTruthy() + expect(component.showMfaBackupCodes).toBeFalsy() + })) + + it('should flip mfa fields when mfa state changed', fakeAsync(() => { + accountServiceSpy.getAccountData.and.returnValue( + of({ + activated: true, + authorities: ['test', 'test'], + email: 'email@email.com', + firstName: 'name', + langKey: 'en', + lastName: 'surname', + imageUrl: 'url', + salesforceId: 'sfid', + loggedAs: false, + loginAs: 'sfid', + mainContact: false, + mfaEnabled: true, + }) + ) + accountServiceSpy.getMfaSetup.and.returnValue(of({ secret: 'test', otp: 'test', qrCode: 'test' })) + tick() + + expect(component.showMfaTextCode).toBeFalsy() + + component.toggleMfaTextCode() + + expect(component.showMfaTextCode).toBeTruthy() + })) + + it('save mfa enabled should call account service enable', fakeAsync(() => { + accountServiceSpy.getAccountData.and.returnValue( + of({ + activated: true, + authorities: ['test', 'test'], + email: 'email@email.com', + firstName: 'name', + langKey: 'en', + lastName: 'surname', + imageUrl: 'url', + salesforceId: 'sfid', + loggedAs: false, + loginAs: 'sfid', + mainContact: false, + mfaEnabled: false, + }) + ) + accountServiceSpy.getMfaSetup.and.returnValue(of({ secret: 'test', otp: 'test', qrCode: ['test'] })) + + component.mfaForm.patchValue({ mfaEnabled: true, verificationCode: 'test' }) + component.saveMfa() + + expect(accountServiceSpy.enableMfa).toHaveBeenCalled() + })) +}) diff --git a/ui/src/app/account/settings/settings.component.ts b/ui/src/app/account/settings/settings.component.ts index 17c608937..d2e650153 100644 --- a/ui/src/app/account/settings/settings.component.ts +++ b/ui/src/app/account/settings/settings.component.ts @@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core' import { FormBuilder, Validators } from '@angular/forms' import { AccountService } from '../service/account.service' import { DomSanitizer } from '@angular/platform-browser' +import { LanguageService } from 'src/app/shared/service/language.service' +import { IAccount } from '../model/account.model' @Component({ selector: 'app-settings', @@ -12,7 +14,7 @@ export class SettingsComponent implements OnInit { error: string | undefined success: string | undefined languages: any[] | undefined - userName: string | undefined + userName: string | null = null mfaSetup: any showMfaSetup: boolean | undefined showMfaTextCode: boolean | undefined @@ -21,25 +23,24 @@ export class SettingsComponent implements OnInit { showMfaBackupCodes: boolean | undefined showMfaUpdated: boolean | undefined settingsForm = this.fb.group({ - firstName: [undefined, [Validators.required, Validators.minLength(1), Validators.maxLength(50)]], - lastName: [undefined, [Validators.required, Validators.minLength(1), Validators.maxLength(50)]], - email: [undefined, [Validators.required, Validators.minLength(5), Validators.maxLength(254), Validators.email]], + firstName: ['', [Validators.required, Validators.minLength(1), Validators.maxLength(50)]], + lastName: ['', [Validators.required, Validators.minLength(1), Validators.maxLength(50)]], + email: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(254), Validators.email]], activated: [false], - authorities: [[]], + authorities: [['']], langKey: ['en'], - imageUrl: [], + imageUrl: [''], }) mfaForm = this.fb.group({ - mfaEnabled: [[]], - verificationCode: [], + mfaEnabled: false, + verificationCode: [''], securitySave: [], }) constructor( private accountService: AccountService, private fb: FormBuilder, - private languageService: JhiLanguageService, - private languageHelper: JhiLanguageHelper, + private languageService: LanguageService, private sanitizer: DomSanitizer ) {} @@ -47,24 +48,29 @@ export class SettingsComponent implements OnInit { this.showMfaSetup = false this.showMfaTextCode = false this.showMfaBackupCodes = false - this.accountService.identity(true).then((account) => { - this.updateForm(account) - this.updateMfaForm(account) - this.userName = this.accountService.getUserName() - if (!account.mfaEnabled) { - this.accountService.getMfaSetup().subscribe((res) => { - this.mfaSetup = res.body - }) + console.log('calling get account data') + this.accountService.getAccountData().subscribe((account) => { + console.log('got account data', account) + if (account) { + this.updateForm(account) + this.updateMfaForm(account) + this.userName = this.accountService.getUserName() + console.log('acocunt and account mfa enabled are ', account, ' and ', account.mfaEnabled) + if (account && !account.mfaEnabled) { + this.accountService.getMfaSetup().subscribe((res) => { + console.log('setting mfa setup to ' + res) + this.mfaSetup = res + }) + } } }) - this.languageHelper.getAll().then((languages) => { - this.languages = languages - }) + this.languages = this.languageService.getAllLanguages() } mfaEnabledStateChange(): void { + console.log('mfa state change called') this.showMfaUpdated = false - const mfaEnabled = this.mfaForm.get('mfaEnabled').value + const mfaEnabled = this.mfaForm.get('mfaEnabled')!.value console.log('setup is ' + this.mfaSetup) if (mfaEnabled && this.mfaSetup) { this.showMfaSetup = true @@ -83,29 +89,32 @@ export class SettingsComponent implements OnInit { const settingsAccount = this.accountFromForm() this.accountService.save(settingsAccount).subscribe( () => { - this.error = null + this.error = undefined this.success = 'OK' - this.accountService.identity(true).then((account) => { - this.updateForm(account) - this.updateMfaForm(account) + this.accountService.getAccountData().subscribe((account) => { + if (account) { + this.updateForm(account) + this.updateMfaForm(account) + } }) - this.languageService.getCurrent().then((current) => { + this.languageService.getCurrentLanguage().subscribe((current) => { if (settingsAccount.langKey !== current) { this.languageService.changeLanguage(settingsAccount.langKey) } }) }, () => { - this.success = null + this.success = undefined this.error = 'ERROR' } ) } saveMfa() { - const enabled = this.mfaForm.get('mfaEnabled').value + const enabled = this.mfaForm.get('mfaEnabled')!.value if (enabled) { - const otp = this.mfaForm.get('verificationCode').value + const otp = this.mfaForm.get('verificationCode')!.value + console.log('about to set otp on ' + this.mfaSetup) this.mfaSetup.otp = otp this.accountService.enableMfa(this.mfaSetup).subscribe( (res) => { @@ -122,7 +131,7 @@ export class SettingsComponent implements OnInit { () => { this.showMfaUpdated = true this.accountService.getMfaSetup().subscribe((res) => { - this.mfaSetup = res.body + this.mfaSetup = res }) }, (err) => console.log('error disabling mfa') @@ -138,17 +147,17 @@ export class SettingsComponent implements OnInit { const account = {} return { ...account, - firstName: this.settingsForm.get('firstName').value, - lastName: this.settingsForm.get('lastName').value, - email: this.settingsForm.get('email').value, - activated: this.settingsForm.get('activated').value, - authorities: this.settingsForm.get('authorities').value, - langKey: this.settingsForm.get('langKey').value, - imageUrl: this.settingsForm.get('imageUrl').value, + firstName: this.settingsForm.get('firstName')!.value, + lastName: this.settingsForm.get('lastName')!.value, + email: this.settingsForm.get('email')!.value, + activated: this.settingsForm.get('activated')!.value, + authorities: this.settingsForm.get('authorities')!.value, + langKey: this.settingsForm.get('langKey')!.value, + imageUrl: this.settingsForm.get('imageUrl')!.value, } } - updateForm(account: any): void { + updateForm(account: IAccount): void { this.settingsForm.patchValue({ firstName: account.firstName, lastName: account.lastName, @@ -160,7 +169,7 @@ export class SettingsComponent implements OnInit { }) } - updateMfaForm(account: any): void { + updateMfaForm(account: IAccount): void { this.mfaForm.patchValue({ mfaEnabled: account.mfaEnabled, }) diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index 140ef1aef..4b906ce98 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -11,8 +11,9 @@ import { NavbarComponent } from './layout/navbar/navbar.component' import { CommonModule } from '@angular/common' import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { HasAnyAuthorityDirective } from './shared/directive/has-any-authority.directive' -import { HomeModule } from './home/home.module'; +import { HomeModule } from './home/home.module' import { FooterComponent } from './layout/footer/footer.component' +import { SharedModule } from './shared/shared.module' @NgModule({ declarations: [AppComponent, NavbarComponent, HasAnyAuthorityDirective, FooterComponent], @@ -26,6 +27,7 @@ import { FooterComponent } from './layout/footer/footer.component' NgxWebstorageModule.forRoot(), CommonModule, NgbModule, + SharedModule.forRoot(), ], providers: [], bootstrap: [AppComponent], diff --git a/ui/src/app/layout/navbar/navbar.component.html b/ui/src/app/layout/navbar/navbar.component.html index c4f9422f0..f41071d7a 100644 --- a/ui/src/app/layout/navbar/navbar.component.html +++ b/ui/src/app/layout/navbar/navbar.component.html @@ -252,7 +252,7 @@
- + QR Code
diff --git a/ui/src/app/shared/service/language.service.ts b/ui/src/app/shared/service/language.service.ts index 1e1e07ca9..57c538adf 100644 --- a/ui/src/app/shared/service/language.service.ts +++ b/ui/src/app/shared/service/language.service.ts @@ -26,5 +26,7 @@ export class LanguageService { return of('en') } - changeLanguage(languageKey: string): void {} + changeLanguage(languageKey: string): void { + console.log('not empty') + } }