Kavita/UI/Web/src/app/registration/user-login/user-login.component.ts
2025-06-30 20:27:53 +02:00

147 lines
4.6 KiB
TypeScript

import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component, computed,
effect, inject,
OnInit,
signal
} from '@angular/core';
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
import {ActivatedRoute, Router, RouterLink} from '@angular/router';
import {NgbTooltip} from '@ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
import { take } from 'rxjs/operators';
import { AccountService } from '../../_services/account.service';
import { MemberService } from '../../_services/member.service';
import { NavService } from '../../_services/nav.service';
import {NgOptimizedImage} from '@angular/common';
import { SplashContainerComponent } from '../_components/splash-container/splash-container.component';
import {TranslocoDirective} from "@jsverse/transloco";
import {environment} from "../../../environments/environment";
import {OidcService} from "../../_services/oidc.service";
@Component({
selector: 'app-user-login',
templateUrl: './user-login.component.html',
styleUrls: ['./user-login.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [SplashContainerComponent, ReactiveFormsModule, RouterLink, TranslocoDirective, NgbTooltip, NgOptimizedImage]
})
export class UserLoginComponent implements OnInit {
private readonly accountService = inject(AccountService);
private readonly router = inject(Router);
private readonly memberService = inject(MemberService);
private readonly toastr = inject(ToastrService);
private readonly navService = inject(NavService);
private readonly cdRef = inject(ChangeDetectorRef);
private readonly route = inject(ActivatedRoute);
protected readonly oidcService = inject(OidcService);
baseUrl = environment.apiUrl;
loginForm: FormGroup = new FormGroup({
username: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required, Validators.maxLength(256), Validators.minLength(6), Validators.pattern("^.{6,256}$")])
});
/**
* If there are no admins on the server, this will enable the registration to kick in.
*/
firstTimeFlow = signal(true);
/**
* Used for first time the page loads to ensure no flashing
*/
isLoaded = signal(false);
isSubmitting = signal(false);
/**
* undefined until query params are read
*/
skipAutoLogin = signal<boolean | undefined>(undefined);
/**
* Display the login form, regardless if the password authentication is disabled (admins can still log in)
* Set from query
*/
forceShowPasswordLogin = signal(false);
/**
* Display the login form
*/
showPasswordLogin = computed(() => {
const loaded = this.isLoaded();
const config = this.oidcService.settings();
const force = this.forceShowPasswordLogin();
if (force) return true;
return loaded && config && !config.disablePasswordAuthentication;
});
constructor() {
this.navService.hideNavBar();
this.navService.hideSideNav();
effect(() => {
const skipAutoLogin = this.skipAutoLogin();
const oidcConfig = this.oidcService.settings();
if (!oidcConfig || skipAutoLogin === undefined) return;
if (oidcConfig.autoLogin && !skipAutoLogin) {
this.oidcService.login()
}
});
}
ngOnInit(): void {
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
if (user) {
this.navService.showNavBar();
this.navService.showSideNav();
this.router.navigateByUrl('/home');
this.cdRef.markForCheck();
}
});
this.memberService.adminExists().pipe(take(1)).subscribe(adminExists => {
this.firstTimeFlow.set(!adminExists);
if (this.firstTimeFlow()) {
this.router.navigateByUrl('registration/register');
return;
}
this.isLoaded.set(true);
});
this.route.queryParamMap.subscribe(params => {
const val = params.get('apiKey');
if (val != null && val.length > 0) {
this.login(val);
return;
}
this.skipAutoLogin.set(params.get('skipAutoLogin') === 'true')
this.forceShowPasswordLogin.set(params.get('forceShowPassword') === 'true');
});
}
login(apiKey: string = '') {
const model = this.loginForm.getRawValue();
model.apiKey = apiKey;
this.isSubmitting.set(true);
this.accountService.login(model).subscribe({
next: () => {
this.loginForm.reset();
this.navService.handleLogin()
this.isSubmitting.set(false);
},
error: (err) => {
this.toastr.error(err.error);
this.isSubmitting.set(false);
}
});
}
}