Add external login buttons

This commit is contained in:
Chocobozzz 2020-04-29 10:42:35 +02:00 committed by Chocobozzz
parent 9107d791e2
commit ebefc902f5
7 changed files with 125 additions and 41 deletions

View File

@ -23,40 +23,54 @@
<span *ngIf="error === 'User email is not verified.'"> <a i18n routerLink="/verify-account/ask-send-email">Request new verification email.</a></span> <span *ngIf="error === 'User email is not verified.'"> <a i18n routerLink="/verify-account/ask-send-email">Request new verification email.</a></span>
</div> </div>
<form role="form" (ngSubmit)="login()" [formGroup]="form"> <div class="login-form-and-externals">
<div class="form-group">
<div> <form role="form" (ngSubmit)="login()" [formGroup]="form">
<label i18n for="username">User</label> <div class="form-group">
<input <div>
type="text" id="username" i18n-placeholder placeholder="Username or email address" required tabindex="1" <label i18n for="username">User</label>
formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" #emailInput <input
> type="text" id="username" i18n-placeholder placeholder="Username or email address" required tabindex="1"
<a i18n *ngIf="signupAllowed === true" routerLink="/signup" class="create-an-account"> formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" #usernameInput
or create an account >
<a i18n *ngIf="signupAllowed === true" routerLink="/signup" class="create-an-account">
or create an account
</a>
</div>
<div *ngIf="formErrors.username" class="form-error">
{{ formErrors.username }}
</div>
</div>
<div class="form-group">
<label i18n for="password">Password</label>
<div>
<input
type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2" autocomplete="current-password"
formControlName="password" class="form-control" [ngClass]="{ 'input-error': formErrors['password'] }"
>
<a i18n-title class="forgot-password-button" (click)="openForgotPasswordModal()" title="Click here to reset your password">I forgot my password</a>
</div>
<div *ngIf="formErrors.password" class="form-error">
{{ formErrors.password }}
</div>
</div>
<input type="submit" i18n-value value="Login" [disabled]="!form.valid">
</form>
<div class="external-login-blocks" *ngIf="getExternalLogins().length !== 0">
<div class="block-title" i18n>Or sign in with</div>
<div class="external-login-block">
<a *ngFor="let auth of getExternalLogins()" [href]="getAuthHref(auth)" role="button">
{{ auth.authDisplayName }}
</a> </a>
</div> </div>
<div *ngIf="formErrors.username" class="form-error">
{{ formErrors.username }}
</div>
</div> </div>
</div>
<div class="form-group">
<label i18n for="password">Password</label>
<div>
<input
type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2" autocomplete="current-password"
formControlName="password" class="form-control" [ngClass]="{ 'input-error': formErrors['password'] }"
>
<a i18n-title class="forgot-password-button" (click)="openForgotPasswordModal()" title="Click here to reset your password">I forgot my password</a>
</div>
<div *ngIf="formErrors.password" class="form-error">
{{ formErrors.password }}
</div>
</div>
<input type="submit" i18n-value value="Login" [disabled]="!form.valid">
</form>
</ng-container> </ng-container>
</div> </div>

View File

@ -21,9 +21,49 @@ input[type=submit] {
color: var(--mainForegroundColor); color: var(--mainForegroundColor);
cursor: pointer; cursor: pointer;
transition: opacity cubic-bezier(0.39, 0.575, 0.565, 1); transition: opacity cubic-bezier(0.39, 0.575, 0.565, 1);
&:hover { &:hover {
text-decoration: none !important; text-decoration: none !important;
opacity: .7 !important; opacity: .7 !important;
} }
} }
.login-form-and-externals {
display: flex;
flex-wrap: wrap;
font-size: 15px;
form {
margin: 0 50px 20px 0;
}
.external-login-blocks {
padding: 0 10px 10px 10px;
min-width: 200px;
.block-title {
font-weight: $font-semibold;
}
.external-login-block {
cursor: pointer;
border: 1px solid #d1d7e0;
border-radius: 5px;
margin: 10px 10px 0 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 35px;
min-width: 100px;
&:hover {
background-color: rgba(209, 215, 224, 0.5)
}
a {
@include disable-default-a-behaviour;
color: var(--mainForegroundColor);
}
}
}
}

View File

@ -1,4 +1,4 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core' import { Component, ElementRef, OnInit, ViewChild, AfterViewInit } from '@angular/core'
import { Notifier, RedirectService } from '@app/core' import { Notifier, RedirectService } from '@app/core'
import { UserService } from '@app/shared' import { UserService } from '@app/shared'
import { AuthService } from '../core' import { AuthService } from '../core'
@ -8,7 +8,8 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val
import { LoginValidatorsService } from '@app/shared/forms/form-validators/login-validators.service' import { LoginValidatorsService } from '@app/shared/forms/form-validators/login-validators.service'
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { ServerConfig } from '@shared/models/server/server-config.model' import { ServerConfig, RegisteredExternalAuthConfig } from '@shared/models/server/server-config.model'
import { environment } from 'src/environments/environment'
@Component({ @Component({
selector: 'my-login', selector: 'my-login',
@ -16,13 +17,14 @@ import { ServerConfig } from '@shared/models/server/server-config.model'
styleUrls: [ './login.component.scss' ] styleUrls: [ './login.component.scss' ]
}) })
export class LoginComponent extends FormReactive implements OnInit { export class LoginComponent extends FormReactive implements OnInit, AfterViewInit {
@ViewChild('emailInput', { static: true }) input: ElementRef @ViewChild('usernameInput', { static: false }) usernameInput: ElementRef
@ViewChild('forgotPasswordModal', { static: true }) forgotPasswordModal: ElementRef @ViewChild('forgotPasswordModal', { static: true }) forgotPasswordModal: ElementRef
error: string = null error: string = null
forgotPasswordEmail = '' forgotPasswordEmail = ''
isAuthenticatedWithExternalAuth = false isAuthenticatedWithExternalAuth = false
externalLogins: string[] = []
private openedForgotPasswordModal: NgbModalRef private openedForgotPasswordModal: NgbModalRef
private serverConfig: ServerConfig private serverConfig: ServerConfig
@ -63,8 +65,20 @@ export class LoginComponent extends FormReactive implements OnInit {
username: this.loginValidatorsService.LOGIN_USERNAME, username: this.loginValidatorsService.LOGIN_USERNAME,
password: this.loginValidatorsService.LOGIN_PASSWORD password: this.loginValidatorsService.LOGIN_PASSWORD
}) })
}
this.input.nativeElement.focus() ngAfterViewInit () {
if (this.usernameInput) {
this.usernameInput.nativeElement.focus()
}
}
getExternalLogins () {
return this.serverConfig.plugin.registeredExternalAuths
}
getAuthHref (auth: RegisteredExternalAuthConfig) {
return environment.apiUrl + `/plugins/${auth.name}/${auth.version}/auth/${auth.authName}`
} }
login () { login () {

View File

@ -53,8 +53,6 @@ $sub-menu-color: #F7F7F7;
$footer-height: 30px; $footer-height: 30px;
$footer-margin: 30px; $footer-margin: 30px;
$footer-border-color: $header-border-color;
$separator-border-color: rgba(0, 0, 0, 0.10); $separator-border-color: rgba(0, 0, 0, 0.10);
$video-miniature-width: 238px; $video-miniature-width: 238px;

View File

@ -278,6 +278,8 @@ function getIdAndPassAuthPlugins () {
for (const auth of p.idAndPassAuths) { for (const auth of p.idAndPassAuths) {
result.push({ result.push({
npmName: p.npmName, npmName: p.npmName,
name: p.name,
version: p.version,
authName: auth.authName, authName: auth.authName,
weight: auth.getWeight() weight: auth.getWeight()
}) })
@ -294,6 +296,8 @@ function getExternalAuthsPlugins () {
for (const auth of p.externalAuths) { for (const auth of p.externalAuths) {
result.push({ result.push({
npmName: p.npmName, npmName: p.npmName,
name: p.name,
version: p.version,
authName: auth.authName, authName: auth.authName,
authDisplayName: auth.authDisplayName authDisplayName: auth.authDisplayName
}) })

View File

@ -106,14 +106,24 @@ export class PluginManager implements ServerHook {
getIdAndPassAuths () { getIdAndPassAuths () {
return this.getRegisteredPlugins() return this.getRegisteredPlugins()
.map(p => ({ npmName: p.npmName, idAndPassAuths: p.registerHelpersStore.getIdAndPassAuths() })) .map(p => ({
npmName: p.npmName,
name: p.name,
version: p.version,
idAndPassAuths: p.registerHelpersStore.getIdAndPassAuths()
}))
.filter(v => v.idAndPassAuths.length !== 0) .filter(v => v.idAndPassAuths.length !== 0)
} }
getExternalAuths () { getExternalAuths () {
return this.getRegisteredPlugins() return this.getRegisteredPlugins()
.map(p => ({ npmName: p.npmName, externalAuths: p.registerHelpersStore.getExternalAuths() })) .map(p => ({
.filter(v => v.externalAuths.length !== 0) npmName: p.npmName,
name: p.name,
version: p.version,
externalAuths: p.registerHelpersStore.getExternalAuths()
}))
.filter(v => v.externalAuths.length !== 0)
} }
getRegisteredSettings (npmName: string) { getRegisteredSettings (npmName: string) {

View File

@ -14,12 +14,16 @@ export interface ServerConfigTheme extends ServerConfigPlugin {
export interface RegisteredExternalAuthConfig { export interface RegisteredExternalAuthConfig {
npmName: string npmName: string
name: string
version: string
authName: string authName: string
authDisplayName: string authDisplayName: string
} }
export interface RegisteredIdAndPassAuthConfig { export interface RegisteredIdAndPassAuthConfig {
npmName: string npmName: string
name: string
version: string
authName: string authName: string
weight: number weight: number
} }