Auth Email Rework (#1567)
* Hooked up Send to for Series and volumes and fixed a bug where Email Service errors weren't propagating to the UI layer. When performing actions on series detail, don't disable the button anymore. * Added send to action to volumes * Fixed a bug where .kavitaignore wasn't being applied at library root level * Added a notification for when a device is being sent a file. * Added a check in forgot password for users that do not have an email set or aren't confirmed. * Added a new api for change email and moved change password directly into new Account tab (styling and logic needs testing) * Save approx scroll position like with jump key, but on normal click of card. * Implemented the ability to change your email address or set one. This requires a 2 step process using a confirmation token. This needs polishing and css. * Removed an unused directive from codebase * Fixed up some typos on publicly * Updated query for Pending Invites to also check if the user account has not logged in at least once. * Cleaned up the css for validate email change * Hooked in an indicator to tell user that a user has an unconfirmed email * Cleaned up code smells
This commit is contained in:
parent
3792ac3421
commit
5f17c2fb73
49 changed files with 816 additions and 274 deletions
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
<app-splash-container>
|
||||
<ng-container title><h2>Validate Email Change</h2></ng-container>
|
||||
<ng-container body>
|
||||
<p *ngIf="!confirmed; else confirmedMessage">Please wait while your email update is validated.</p>
|
||||
|
||||
<ng-template #confirmedMessage>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-title">
|
||||
<h3><i class="fa-regular fa-circle-check me-2" style="font-size: 1.8rem" aria-hidden="true"></i>Success!</h3>
|
||||
</div>
|
||||
<p>Your email has been validated and is now changed within Kavita. You will be redirected to login.</p>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</app-splash-container>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
.card-body {
|
||||
padding: 0px 0px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { AccountService } from 'src/app/_services/account.service';
|
||||
import { NavService } from 'src/app/_services/nav.service';
|
||||
import { ThemeService } from 'src/app/_services/theme.service';
|
||||
|
||||
/**
|
||||
* This component just validates the email via API then redirects to login
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-confirm-email-change',
|
||||
templateUrl: './confirm-email-change.component.html',
|
||||
styleUrls: ['./confirm-email-change.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ConfirmEmailChangeComponent implements OnInit {
|
||||
|
||||
email: string = '';
|
||||
token: string = '';
|
||||
|
||||
confirmed: boolean = false;
|
||||
|
||||
constructor(private route: ActivatedRoute, private router: Router, private accountService: AccountService,
|
||||
private toastr: ToastrService, private themeService: ThemeService, private navService: NavService,
|
||||
private readonly cdRef: ChangeDetectorRef) {
|
||||
this.navService.hideSideNav();
|
||||
this.themeService.setTheme(this.themeService.defaultTheme);
|
||||
const token = this.route.snapshot.queryParamMap.get('token');
|
||||
const email = this.route.snapshot.queryParamMap.get('email');
|
||||
|
||||
if (this.isNullOrEmpty(token) || this.isNullOrEmpty(email)) {
|
||||
// This is not a valid url, redirect to login
|
||||
this.toastr.error('Invalid confirmation url');
|
||||
this.router.navigateByUrl('login');
|
||||
return;
|
||||
}
|
||||
|
||||
this.token = token!;
|
||||
this.email = email!;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.accountService.confirmEmailUpdate({email: this.email, token: this.token}).subscribe((errors) => {
|
||||
this.confirmed = true;
|
||||
this.cdRef.markForCheck();
|
||||
setTimeout(() => this.router.navigateByUrl('login'), 2000);
|
||||
});
|
||||
}
|
||||
|
||||
isNullOrEmpty(v: string | null | undefined) {
|
||||
return v == undefined || v === '' || v === null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -38,19 +38,23 @@ export class ConfirmEmailComponent {
|
|||
const token = this.route.snapshot.queryParamMap.get('token');
|
||||
const email = this.route.snapshot.queryParamMap.get('email');
|
||||
this.cdRef.markForCheck();
|
||||
if (token == undefined || token === '' || token === null) {
|
||||
if (this.isNullOrEmpty(token) || this.isNullOrEmpty(email)) {
|
||||
// This is not a valid url, redirect to login
|
||||
this.toastr.error('Invalid confirmation email');
|
||||
this.toastr.error('Invalid confirmation url');
|
||||
this.router.navigateByUrl('login');
|
||||
return;
|
||||
}
|
||||
this.token = token;
|
||||
this.token = token!;
|
||||
this.registerForm.get('email')?.setValue(email || '');
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
isNullOrEmpty(v: string | null | undefined) {
|
||||
return v == undefined || v === '' || v === null;
|
||||
}
|
||||
|
||||
submit() {
|
||||
let model = this.registerForm.getRawValue();
|
||||
const model = this.registerForm.getRawValue();
|
||||
model.token = this.token;
|
||||
this.accountService.confirmEmail(model).subscribe((user) => {
|
||||
this.toastr.success('Account registration complete');
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<div class="mb-3" style="width:100%">
|
||||
<label for="email" class="form-label">Email</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="emailTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #emailTooltip>Email does not have to be valid, it is used for forgot password flow. It is not sent outside the server unless forgot password is used without a custom email service host.</ng-template>
|
||||
<ng-template #emailTooltip>Email is optional and provides acccess to forgot password. It is not sent outside the server unless forgot password is used without a custom email service host.</ng-template>
|
||||
<span class="visually-hidden" id="email-help">
|
||||
<ng-container [ngTemplateOutlet]="emailTooltip"></ng-container>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { MemberService } from 'src/app/_services/member.service';
|
|||
export class RegisterComponent implements OnInit {
|
||||
|
||||
registerForm: FormGroup = new FormGroup({
|
||||
email: new FormControl('', [Validators.required, Validators.email]),
|
||||
email: new FormControl('', [Validators.email]),
|
||||
username: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { ConfirmMigrationEmailComponent } from './confirm-migration-email/confir
|
|||
import { ResetPasswordComponent } from './reset-password/reset-password.component';
|
||||
import { ConfirmResetPasswordComponent } from './confirm-reset-password/confirm-reset-password.component';
|
||||
import { UserLoginComponent } from './user-login/user-login.component';
|
||||
import { ConfirmEmailChangeComponent } from './confirm-email-change/confirm-email-change.component';
|
||||
|
||||
|
||||
|
||||
|
|
@ -23,7 +24,8 @@ import { UserLoginComponent } from './user-login/user-login.component';
|
|||
ConfirmMigrationEmailComponent,
|
||||
ResetPasswordComponent,
|
||||
ConfirmResetPasswordComponent,
|
||||
UserLoginComponent
|
||||
UserLoginComponent,
|
||||
ConfirmEmailChangeComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { ConfirmEmailChangeComponent } from './confirm-email-change/confirm-email-change.component';
|
||||
import { ConfirmEmailComponent } from './confirm-email/confirm-email.component';
|
||||
import { ConfirmMigrationEmailComponent } from './confirm-migration-email/confirm-migration-email.component';
|
||||
import { ConfirmResetPasswordComponent } from './confirm-reset-password/confirm-reset-password.component';
|
||||
|
|
@ -24,6 +25,10 @@ const routes: Routes = [
|
|||
path: 'confirm-migration-email',
|
||||
component: ConfirmMigrationEmailComponent,
|
||||
},
|
||||
{
|
||||
path: 'confirm-email-update',
|
||||
component: ConfirmEmailChangeComponent,
|
||||
},
|
||||
{
|
||||
path: 'register',
|
||||
component: RegisterComponent,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue