X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;ds=sidebyside;f=client%2Fsrc%2Fapp%2F%2Blogin%2Flogin.component.ts;h=ba0d412d61824e3046fb240b5ca357ce1b61375f;hb=7815dc450ea9f8fd63e2234b6215013a132e6229;hp=9731383afc78cb1a1b0c61e78689389368d49bfa;hpb=c4fa01f7c45b66b112ebd08abce744b7c4041feb;p=github%2FChocobozzz%2FPeerTube.git diff --git a/client/src/app/+login/login.component.ts b/client/src/app/+login/login.component.ts index 9731383af..ba0d412d6 100644 --- a/client/src/app/+login/login.component.ts +++ b/client/src/app/+login/login.component.ts @@ -1,13 +1,15 @@ import { environment } from 'src/environments/environment' import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core' -import { ActivatedRoute } from '@angular/router' -import { AuthService, Notifier, RedirectService, UserService } from '@app/core' +import { ActivatedRoute, Router } from '@angular/router' +import { AuthService, Notifier, RedirectService, SessionStorageService, UserService } from '@app/core' import { HooksService } from '@app/core/plugins/hooks.service' import { LOGIN_PASSWORD_VALIDATOR, LOGIN_USERNAME_VALIDATOR } from '@app/shared/form-validators/login-validators' -import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' +import { USER_OTP_TOKEN_VALIDATOR } from '@app/shared/form-validators/user-validators' +import { FormReactive, FormReactiveService, InputTextComponent } from '@app/shared/shared-forms' import { InstanceAboutAccordionComponent } from '@app/shared/shared-instance' import { NgbAccordion, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' -import { RegisteredExternalAuthConfig, ServerConfig } from '@shared/models' +import { getExternalAuthHref } from '@shared/core-utils' +import { RegisteredExternalAuthConfig, ServerConfig, ServerErrorCode } from '@shared/models' @Component({ selector: 'my-login', @@ -16,7 +18,10 @@ import { RegisteredExternalAuthConfig, ServerConfig } from '@shared/models' }) export class LoginComponent extends FormReactive implements OnInit, AfterViewInit { + private static SESSION_STORAGE_REDIRECT_URL_KEY = 'login-previous-url' + @ViewChild('forgotPasswordModal', { static: true }) forgotPasswordModal: ElementRef + @ViewChild('otpTokenInput') otpTokenInput: InputTextComponent accordion: NgbAccordion error: string = null @@ -34,19 +39,23 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni codeOfConduct: false } + otpStep = false + private openedForgotPasswordModal: NgbModalRef private serverConfig: ServerConfig constructor ( - protected formValidatorService: FormValidatorService, + protected formReactiveService: FormReactiveService, private route: ActivatedRoute, private modalService: NgbModal, private authService: AuthService, private userService: UserService, private redirectService: RedirectService, private notifier: Notifier, - private hooks: HooksService - ) { + private hooks: HooksService, + private storage: SessionStorageService, + private router: Router + ) { super() } @@ -54,6 +63,10 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni return this.serverConfig.signup.allowed === true } + get instanceName () { + return this.serverConfig.instance.name + } + onTermsClick (event: Event, instanceInformation: HTMLElement) { event.preventDefault() @@ -73,7 +86,11 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni // Avoid undefined errors when accessing form error properties this.buildForm({ username: LOGIN_USERNAME_VALIDATOR, - password: LOGIN_PASSWORD_VALIDATOR + password: LOGIN_PASSWORD_VALIDATOR, + 'otp-token': { + VALIDATORS: [], // Will be set dynamically + MESSAGES: USER_OTP_TOKEN_VALIDATOR.MESSAGES + } }) this.serverConfig = snapshot.data.serverConfig @@ -87,6 +104,11 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni this.externalAuthError = true return } + + const previousUrl = this.redirectService.getPreviousUrl() + if (previousUrl && previousUrl !== '/') { + this.storage.setItem(LoginComponent.SESSION_STORAGE_REDIRECT_URL_KEY, previousUrl) + } } ngAfterViewInit () { @@ -98,26 +120,33 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni } getAuthHref (auth: RegisteredExternalAuthConfig) { - return environment.apiUrl + `/plugins/${auth.name}/${auth.version}/auth/${auth.authName}` + return getExternalAuthHref(environment.apiUrl, auth) } login () { this.error = null - const { username, password } = this.form.value + const options = { + username: this.form.value['username'], + password: this.form.value['password'], + otpToken: this.form.value['otp-token'] + } - this.authService.login(username, password) - .subscribe( - () => this.redirectService.redirectToPreviousRoute(), + this.authService.login(options) + .pipe() + .subscribe({ + next: () => this.redirectService.redirectToPreviousRoute(), - err => this.handleError(err) - ) + error: err => { + this.handleError(err) + } + }) } askResetPassword () { this.userService.askResetPassword(this.forgotPasswordEmail) - .subscribe( - () => { + .subscribe({ + next: () => { const message = $localize`An email with the reset password instructions will be sent to ${this.forgotPasswordEmail}. The link will expire within 1 hour.` @@ -125,8 +154,8 @@ The link will expire within 1 hour.` this.hideForgotPasswordModal() }, - err => this.notifier.error(err.message) - ) + error: err => this.notifier.error(err.message) + }) } openForgotPasswordModal () { @@ -148,20 +177,57 @@ The link will expire within 1 hour.` private loadExternalAuthToken (username: string, token: string) { this.isAuthenticatedWithExternalAuth = true - this.authService.login(username, null, token) - .subscribe( - () => this.redirectService.redirectToPreviousRoute(), + this.authService.login({ username, password: null, token }) + .subscribe({ + next: () => { + const redirectUrl = this.storage.getItem(LoginComponent.SESSION_STORAGE_REDIRECT_URL_KEY) + if (redirectUrl) { + this.storage.removeItem(LoginComponent.SESSION_STORAGE_REDIRECT_URL_KEY) + return this.router.navigateByUrl(redirectUrl) + } - err => { - this.handleError(err) - this.isAuthenticatedWithExternalAuth = false - } - ) + this.redirectService.redirectToLatestSessionRoute() + }, + + error: err => { + this.handleError(err) + this.isAuthenticatedWithExternalAuth = false + } + }) } private handleError (err: any) { - if (err.message.indexOf('credentials are invalid') !== -1) this.error = $localize`Incorrect username or password.` - else if (err.message.indexOf('blocked') !== -1) this.error = $localize`Your account is blocked.` - else this.error = err.message + if (this.authService.isOTPMissingError(err)) { + this.otpStep = true + + setTimeout(() => { + this.form.get('otp-token').setValidators(USER_OTP_TOKEN_VALIDATOR.VALIDATORS) + this.otpTokenInput.focus() + }) + + return + } + + if (err.message.includes('credentials are invalid')) { + this.error = $localize`Incorrect username or password.` + return + } + + if (err.message.includes('blocked')) { + this.error = $localize`Your account is blocked.` + return + } + + if (err.body?.code === ServerErrorCode.ACCOUNT_WAITING_FOR_APPROVAL) { + this.error = $localize`This account is awaiting approval by moderators.` + return + } + + if (err.body?.code === ServerErrorCode.ACCOUNT_APPROVAL_REJECTED) { + this.error = $localize`Registration approval has been rejected for this account.` + return + } + + this.error = err.message } }