aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/login/login.component.html68
-rw-r--r--client/src/app/login/login.component.scss42
-rw-r--r--client/src/app/login/login.component.ts24
-rw-r--r--client/src/sass/include/_variables.scss2
-rw-r--r--server/controllers/api/config.ts4
-rw-r--r--server/lib/plugins/plugin-manager.ts16
-rw-r--r--shared/models/server/server-config.model.ts4
7 files changed, 122 insertions, 38 deletions
diff --git a/client/src/app/login/login.component.html b/client/src/app/login/login.component.html
index 3e53e5854..b0639d8ca 100644
--- a/client/src/app/login/login.component.html
+++ b/client/src/app/login/login.component.html
@@ -23,40 +23,54 @@
23 <span *ngIf="error === 'User email is not verified.'"> <a i18n routerLink="/verify-account/ask-send-email">Request new verification email.</a></span> 23 <span *ngIf="error === 'User email is not verified.'"> <a i18n routerLink="/verify-account/ask-send-email">Request new verification email.</a></span>
24 </div> 24 </div>
25 25
26 <form role="form" (ngSubmit)="login()" [formGroup]="form"> 26 <div class="login-form-and-externals">
27 <div class="form-group"> 27
28 <div> 28 <form role="form" (ngSubmit)="login()" [formGroup]="form">
29 <label i18n for="username">User</label> 29 <div class="form-group">
30 <input 30 <div>
31 type="text" id="username" i18n-placeholder placeholder="Username or email address" required tabindex="1" 31 <label i18n for="username">User</label>
32 formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" #emailInput 32 <input
33 > 33 type="text" id="username" i18n-placeholder placeholder="Username or email address" required tabindex="1"
34 <a i18n *ngIf="signupAllowed === true" routerLink="/signup" class="create-an-account"> 34 formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" #usernameInput
35 or create an account 35 >
36 </a> 36 <a i18n *ngIf="signupAllowed === true" routerLink="/signup" class="create-an-account">
37 or create an account
38 </a>
39 </div>
40
41 <div *ngIf="formErrors.username" class="form-error">
42 {{ formErrors.username }}
43 </div>
37 </div> 44 </div>
38 45
39 <div *ngIf="formErrors.username" class="form-error"> 46 <div class="form-group">
40 {{ formErrors.username }} 47 <label i18n for="password">Password</label>
48 <div>
49 <input
50 type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2" autocomplete="current-password"
51 formControlName="password" class="form-control" [ngClass]="{ 'input-error': formErrors['password'] }"
52 >
53 <a i18n-title class="forgot-password-button" (click)="openForgotPasswordModal()" title="Click here to reset your password">I forgot my password</a>
54 </div>
55 <div *ngIf="formErrors.password" class="form-error">
56 {{ formErrors.password }}
57 </div>
41 </div> 58 </div>
42 </div>
43 59
44 <div class="form-group"> 60 <input type="submit" i18n-value value="Login" [disabled]="!form.valid">
45 <label i18n for="password">Password</label> 61 </form>
46 <div> 62
47 <input 63 <div class="external-login-blocks" *ngIf="getExternalLogins().length !== 0">
48 type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2" autocomplete="current-password" 64 <div class="block-title" i18n>Or sign in with</div>
49 formControlName="password" class="form-control" [ngClass]="{ 'input-error': formErrors['password'] }" 65
50 > 66 <div class="external-login-block">
51 <a i18n-title class="forgot-password-button" (click)="openForgotPasswordModal()" title="Click here to reset your password">I forgot my password</a> 67 <a *ngFor="let auth of getExternalLogins()" [href]="getAuthHref(auth)" role="button">
52 </div> 68 {{ auth.authDisplayName }}
53 <div *ngIf="formErrors.password" class="form-error"> 69 </a>
54 {{ formErrors.password }}
55 </div> 70 </div>
56 </div> 71 </div>
72 </div>
57 73
58 <input type="submit" i18n-value value="Login" [disabled]="!form.valid">
59 </form>
60 </ng-container> 74 </ng-container>
61</div> 75</div>
62 76
diff --git a/client/src/app/login/login.component.scss b/client/src/app/login/login.component.scss
index 8ac231475..ccc98c12a 100644
--- a/client/src/app/login/login.component.scss
+++ b/client/src/app/login/login.component.scss
@@ -21,9 +21,49 @@ input[type=submit] {
21 color: var(--mainForegroundColor); 21 color: var(--mainForegroundColor);
22 cursor: pointer; 22 cursor: pointer;
23 transition: opacity cubic-bezier(0.39, 0.575, 0.565, 1); 23 transition: opacity cubic-bezier(0.39, 0.575, 0.565, 1);
24 24
25 &:hover { 25 &:hover {
26 text-decoration: none !important; 26 text-decoration: none !important;
27 opacity: .7 !important; 27 opacity: .7 !important;
28 } 28 }
29} 29}
30
31.login-form-and-externals {
32 display: flex;
33 flex-wrap: wrap;
34 font-size: 15px;
35
36 form {
37 margin: 0 50px 20px 0;
38 }
39
40 .external-login-blocks {
41 padding: 0 10px 10px 10px;
42 min-width: 200px;
43
44 .block-title {
45 font-weight: $font-semibold;
46 }
47
48 .external-login-block {
49 cursor: pointer;
50 border: 1px solid #d1d7e0;
51 border-radius: 5px;
52 margin: 10px 10px 0 0;
53 display: flex;
54 justify-content: center;
55 align-items: center;
56 min-height: 35px;
57 min-width: 100px;
58
59 &:hover {
60 background-color: rgba(209, 215, 224, 0.5)
61 }
62
63 a {
64 @include disable-default-a-behaviour;
65 color: var(--mainForegroundColor);
66 }
67 }
68 }
69}
diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts
index 9c8f5c52e..5db8d3dbb 100644
--- a/client/src/app/login/login.component.ts
+++ b/client/src/app/login/login.component.ts
@@ -1,4 +1,4 @@
1import { Component, ElementRef, OnInit, ViewChild } from '@angular/core' 1import { Component, ElementRef, OnInit, ViewChild, AfterViewInit } from '@angular/core'
2import { Notifier, RedirectService } from '@app/core' 2import { Notifier, RedirectService } from '@app/core'
3import { UserService } from '@app/shared' 3import { UserService } from '@app/shared'
4import { AuthService } from '../core' 4import { AuthService } from '../core'
@@ -8,7 +8,8 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val
8import { LoginValidatorsService } from '@app/shared/forms/form-validators/login-validators.service' 8import { LoginValidatorsService } from '@app/shared/forms/form-validators/login-validators.service'
9import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' 9import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
10import { ActivatedRoute } from '@angular/router' 10import { ActivatedRoute } from '@angular/router'
11import { ServerConfig } from '@shared/models/server/server-config.model' 11import { ServerConfig, RegisteredExternalAuthConfig } from '@shared/models/server/server-config.model'
12import { environment } from 'src/environments/environment'
12 13
13@Component({ 14@Component({
14 selector: 'my-login', 15 selector: 'my-login',
@@ -16,13 +17,14 @@ import { ServerConfig } from '@shared/models/server/server-config.model'
16 styleUrls: [ './login.component.scss' ] 17 styleUrls: [ './login.component.scss' ]
17}) 18})
18 19
19export class LoginComponent extends FormReactive implements OnInit { 20export class LoginComponent extends FormReactive implements OnInit, AfterViewInit {
20 @ViewChild('emailInput', { static: true }) input: ElementRef 21 @ViewChild('usernameInput', { static: false }) usernameInput: ElementRef
21 @ViewChild('forgotPasswordModal', { static: true }) forgotPasswordModal: ElementRef 22 @ViewChild('forgotPasswordModal', { static: true }) forgotPasswordModal: ElementRef
22 23
23 error: string = null 24 error: string = null
24 forgotPasswordEmail = '' 25 forgotPasswordEmail = ''
25 isAuthenticatedWithExternalAuth = false 26 isAuthenticatedWithExternalAuth = false
27 externalLogins: string[] = []
26 28
27 private openedForgotPasswordModal: NgbModalRef 29 private openedForgotPasswordModal: NgbModalRef
28 private serverConfig: ServerConfig 30 private serverConfig: ServerConfig
@@ -63,8 +65,20 @@ export class LoginComponent extends FormReactive implements OnInit {
63 username: this.loginValidatorsService.LOGIN_USERNAME, 65 username: this.loginValidatorsService.LOGIN_USERNAME,
64 password: this.loginValidatorsService.LOGIN_PASSWORD 66 password: this.loginValidatorsService.LOGIN_PASSWORD
65 }) 67 })
68 }
69
70 ngAfterViewInit () {
71 if (this.usernameInput) {
72 this.usernameInput.nativeElement.focus()
73 }
74 }
75
76 getExternalLogins () {
77 return this.serverConfig.plugin.registeredExternalAuths
78 }
66 79
67 this.input.nativeElement.focus() 80 getAuthHref (auth: RegisteredExternalAuthConfig) {
81 return environment.apiUrl + `/plugins/${auth.name}/${auth.version}/auth/${auth.authName}`
68 } 82 }
69 83
70 login () { 84 login () {
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss
index 72eb7b61e..46f1e99f7 100644
--- a/client/src/sass/include/_variables.scss
+++ b/client/src/sass/include/_variables.scss
@@ -53,8 +53,6 @@ $sub-menu-color: #F7F7F7;
53$footer-height: 30px; 53$footer-height: 30px;
54$footer-margin: 30px; 54$footer-margin: 30px;
55 55
56$footer-border-color: $header-border-color;
57
58$separator-border-color: rgba(0, 0, 0, 0.10); 56$separator-border-color: rgba(0, 0, 0, 0.10);
59 57
60$video-miniature-width: 238px; 58$video-miniature-width: 238px;
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index e8941bc73..85f3ad3d9 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -278,6 +278,8 @@ function getIdAndPassAuthPlugins () {
278 for (const auth of p.idAndPassAuths) { 278 for (const auth of p.idAndPassAuths) {
279 result.push({ 279 result.push({
280 npmName: p.npmName, 280 npmName: p.npmName,
281 name: p.name,
282 version: p.version,
281 authName: auth.authName, 283 authName: auth.authName,
282 weight: auth.getWeight() 284 weight: auth.getWeight()
283 }) 285 })
@@ -294,6 +296,8 @@ function getExternalAuthsPlugins () {
294 for (const auth of p.externalAuths) { 296 for (const auth of p.externalAuths) {
295 result.push({ 297 result.push({
296 npmName: p.npmName, 298 npmName: p.npmName,
299 name: p.name,
300 version: p.version,
297 authName: auth.authName, 301 authName: auth.authName,
298 authDisplayName: auth.authDisplayName 302 authDisplayName: auth.authDisplayName
299 }) 303 })
diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts
index 38336bcc6..f7b84b1ff 100644
--- a/server/lib/plugins/plugin-manager.ts
+++ b/server/lib/plugins/plugin-manager.ts
@@ -106,14 +106,24 @@ export class PluginManager implements ServerHook {
106 106
107 getIdAndPassAuths () { 107 getIdAndPassAuths () {
108 return this.getRegisteredPlugins() 108 return this.getRegisteredPlugins()
109 .map(p => ({ npmName: p.npmName, idAndPassAuths: p.registerHelpersStore.getIdAndPassAuths() })) 109 .map(p => ({
110 npmName: p.npmName,
111 name: p.name,
112 version: p.version,
113 idAndPassAuths: p.registerHelpersStore.getIdAndPassAuths()
114 }))
110 .filter(v => v.idAndPassAuths.length !== 0) 115 .filter(v => v.idAndPassAuths.length !== 0)
111 } 116 }
112 117
113 getExternalAuths () { 118 getExternalAuths () {
114 return this.getRegisteredPlugins() 119 return this.getRegisteredPlugins()
115 .map(p => ({ npmName: p.npmName, externalAuths: p.registerHelpersStore.getExternalAuths() })) 120 .map(p => ({
116 .filter(v => v.externalAuths.length !== 0) 121 npmName: p.npmName,
122 name: p.name,
123 version: p.version,
124 externalAuths: p.registerHelpersStore.getExternalAuths()
125 }))
126 .filter(v => v.externalAuths.length !== 0)
117 } 127 }
118 128
119 getRegisteredSettings (npmName: string) { 129 getRegisteredSettings (npmName: string) {
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts
index 0ff079216..a1f9b3b5d 100644
--- a/shared/models/server/server-config.model.ts
+++ b/shared/models/server/server-config.model.ts
@@ -14,12 +14,16 @@ export interface ServerConfigTheme extends ServerConfigPlugin {
14 14
15export interface RegisteredExternalAuthConfig { 15export interface RegisteredExternalAuthConfig {
16 npmName: string 16 npmName: string
17 name: string
18 version: string
17 authName: string 19 authName: string
18 authDisplayName: string 20 authDisplayName: string
19} 21}
20 22
21export interface RegisteredIdAndPassAuthConfig { 23export interface RegisteredIdAndPassAuthConfig {
22 npmName: string 24 npmName: string
25 name: string
26 version: string
23 authName: string 27 authName: string
24 weight: number 28 weight: number
25} 29}