Skip to content

Commit

Permalink
Merge pull request #1062 from ORCID/settingsComponent
Browse files Browse the repository at this point in the history
Settings component
  • Loading branch information
auumgn authored Nov 22, 2023
2 parents bd1224b + 868f7e6 commit 34f2c72
Show file tree
Hide file tree
Showing 14 changed files with 623 additions and 12 deletions.
8 changes: 5 additions & 3 deletions ui/src/app/account/account.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
11 changes: 11 additions & 0 deletions ui/src/app/account/account.route.ts
Original file line number Diff line number Diff line change
@@ -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 = [
{
Expand All @@ -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],
},
]
2 changes: 0 additions & 2 deletions ui/src/app/account/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 0 additions & 1 deletion ui/src/app/account/login/login.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export class LoginComponent implements AfterViewInit, OnDestroy {

ngOnDestroy(): void {
this.sub?.unsubscribe()
console.log('test')
}

ngAfterViewInit() {
Expand Down
6 changes: 2 additions & 4 deletions ui/src/app/account/service/account.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ export class AccountService {
)
}

getMfaSetup(): Observable<HttpResponse<any>> {
return this.http.get<any>('/services/userservice/api/account/mfa', { observe: 'response' })
getMfaSetup(): Observable<{ secret: string; otp: string; qrCode: any }> {
return this.http.get<any>('/services/userservice/api/account/mfa')
}

save(account: any): Observable<HttpResponse<any>> {
Expand All @@ -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
}
Expand Down
138 changes: 138 additions & 0 deletions ui/src/app/account/settings/settings.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<h1 class="mt-3" jhiTranslate="settings.personalDetails.string">Personal details</h1>
<hr />

<div class="alert alert-success" *ngIf="success" jhiTranslate="settings.messages.success.string">
<strong>Settings saved!</strong>
</div>

<form name="form" role="form" (ngSubmit)="save()" [formGroup]="settingsForm" *ngIf="settingsForm.get('email')?.value" novalidate>
<div class="form-group">
<label class="form-control-label" for="firstName" jhiTranslate="settings.form.firstname.label.string">First Name</label>
<!-- TODO: translate pipe removed -->
<input type="text" class="form-control" id="firstName" name="firstName" placeholder="{{'settings.form.firstname.placeholder.string' }}"
formControlName="firstName">
<div *ngIf="settingsForm.get('firstName')?.invalid && (settingsForm.get('firstName')?.dirty || settingsForm.get('firstName')?.touched)">
<small class="form-text text-danger"
*ngIf="settingsForm.get('firstName')?.errors!['required']" jhiTranslate="settings.messages.validate.firstname.required.string">
Your first name is required.
</small>
<small class="form-text text-danger"
*ngIf="settingsForm.get('firstName')?.errors!['minlength']" jhiTranslate="settings.messages.validate.firstname.minlength.string">
Your first name is required to be at least 1 character.
</small>
<small class="form-text text-danger"
*ngIf="settingsForm.get('firstName')?.errors!['maxlength']" jhiTranslate="settings.messages.validate.firstname.maxlength.string">
Your first name cannot be longer than 50 characters.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="lastName" jhiTranslate="settings.form.lastname.label.string">Last Name</label>
<!-- TODO: translate pipe removed -->

<input type="text" class="form-control" id="lastName" name="lastName" placeholder="{{'settings.form.lastname.placeholder.string'}}"
formControlName="lastName">
<div *ngIf="settingsForm.get('lastName')?.invalid && (settingsForm.get('lastName')?.dirty || settingsForm.get('lastName')?.touched)">
<small class="form-text text-danger"
*ngIf="settingsForm.get('lastName')?.errors!['required']" jhiTranslate="settings.messages.validate.lastname.required.string">
Your last name is required.
</small>
<small class="form-text text-danger"
*ngIf="settingsForm.get('lastName')?.errors!['minlength']" jhiTranslate="settings.messages.validate.lastname.minlength.string">
Your last name is required to be at least 1 character.
</small>
<small class="form-text text-danger"
*ngIf="settingsForm.get('lastName')?.errors!['maxlength']" jhiTranslate="settings.messages.validate.lastname.maxlength.string">
Your last name cannot be longer than 50 characters.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="email" jhiTranslate="global.form.email.label.string">Email</label>
<!-- TODO: translate pipe removed -->
<input type="email" class="form-control" id="email" name="email" placeholder="{{'global.form.email.placeholder.string'}}"
formControlName="email" readonly>

</div>
<div class="form-group" *ngIf="languages && languages.length > 0">
<label class="form-control-label" for="langKey" jhiTranslate="settings.form.language.string">Language</label>
<select class="form-control" id="langKey" name="langKey" formControlName="langKey">
<option *ngFor="let language of languages" [value]="language">{{language | findLanguageFromKey}}</option>
</select>
</div>
<button type="submit" [disabled]="settingsForm.invalid || settingsForm.pristine" class="btn btn-primary" jhiTranslate="settings.form.button.string">Save</button>
</form>
<hr />

<form name="form" role="form" (ngSubmit)="saveMfa()"
[formGroup]="mfaForm" *ngIf="settingsForm.get('email')?.value"
novalidate>
<h1 class="mt-3" jhiTranslate="settings.security.heading.string">Security</h1>
<hr />
<div class="form-group">
<p jhiTranslate="settings.security.mfaExplain.string">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.</p>
<label class="form-control-label" for="field_mfaEnabled"
jhiTranslate="settings.security.mfa.string">Two-factor
Authentication</label>
<input type="checkbox" class="form-control"
name="mfaEnabled" id="field_mfaEnabled"
formControlName="mfaEnabled" (change)="mfaEnabledStateChange()" />
</div>
<div *ngIf="showMfaUpdated" jhiTranslate="settings.security.mfaUpdated.string">2FA settings updated</div>
<div class="row" *ngIf="showMfaSetup && !showMfaBackupCodes">
<div class="col-md-8">
<ul>
<li jhiTranslate="settings.security.mfaQrCodeSteps.one.string">Install a two-factor authentication app<br />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 <a href='https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2'>Google Authenticator</a>, <a href='https://freeotp.github.io/'>FreeOTP</a>, or <a href='https://authy.com/'>Authy</a>.</li>
<li jhiTranslate="settings.security.mfaQrCodeSteps.two.string">Scan this QR code with your device<br />Open your 2FA app and scan the image below.</li>
</ul>
</div>
</div>
<div class="row" *ngIf="showMfaSetup && !showMfaBackupCodes">
<div class="col-md-8">
<img [src]="safeQrCode()" alt="QR Code" />
</div>
</div>
<div class="row" *ngIf="showMfaSetup && !showMfaBackupCodes && showMfaTextCode">
<div class="col-md-8">
<p class="mfaSecret"><strong>{{ mfaSetup.secret }}</strong></p>
</div>
</div>
<div class="row" *ngIf="showMfaSetup && !showMfaBackupCodes">
<div class="col-md-8">
<ul>
<li><span jhiTranslate="settings.security.mfaCannotScan.one.string">Can't scan the QR code?</span><br /><a href="JavaScript:void(0);" (click)="toggleMfaTextCode()" jhiTranslate="settings.security.mfaCannotScan.two.string">Get a text code</a>&nbsp;<span jhiTranslate="settings.security.mfaCannotScan.three.string">and enter it into your 2FA app instead</span></li>
<li jhiTranslate="settings.security.mfaTextCodeSteps.one.string">Enter the six-digit code from the app<br />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.</li>
</ul>
</div>
</div>
<div class="form-group" *ngIf="showMfaSetup && !showMfaBackupCodes">
<div class="col-md-8">
<div *ngIf="mfaSetupFailure" class="alert alert-danger" jhiTranslate="settings.security.otpError.string">
Incorrect verification code
</div>
<!-- TODO: translate pipe removed -->

<input class="indented" name="verificationCode" formControlName="verificationCode"
placeholder="{{'settings.security.verificationCode.string'}}" />
</div>
</div>
<div class="row" *ngIf="showMfaBackupCodes && showMfaSetup">
<div class="col-md-8">
<p jhiTranslate="settings.security.backupCodes.string">Make a note of the following backup codes, this is the only time they will be shown.</p>
<table>
<tr *ngFor="let backupCode of mfaBackupCodes">
<td>{{ backupCode }}</td>
</tr>
</table>
</div>
</div>
<button [disabled]="mfaForm.pristine || showMfaBackupCodes" type="submit" class="btn btn-primary" jhiTranslate="settings.form.button.string">Save</button>
</form>
<hr />
</div>
</div>

</div>
Empty file.
Loading

0 comments on commit 34f2c72

Please sign in to comment.