aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+login
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-06-23 14:49:20 +0200
committerChocobozzz <chocobozzz@cpy.re>2020-06-23 16:00:49 +0200
commit1942f11d5ee6926ad93dc1b79fae18325ba5de18 (patch)
tree3f2a3cd9466a56c419d197ac832a3e9cbc86bec4 /client/src/app/+login
parent67ed6552b831df66713bac9e672738796128d33f (diff)
downloadPeerTube-1942f11d5ee6926ad93dc1b79fae18325ba5de18.tar.gz
PeerTube-1942f11d5ee6926ad93dc1b79fae18325ba5de18.tar.zst
PeerTube-1942f11d5ee6926ad93dc1b79fae18325ba5de18.zip
Lazy load all routes
Diffstat (limited to 'client/src/app/+login')
-rw-r--r--client/src/app/+login/login-routing.module.ts27
-rw-r--r--client/src/app/+login/login.component.html114
-rw-r--r--client/src/app/+login/login.component.scss66
-rw-r--r--client/src/app/+login/login.component.ts147
-rw-r--r--client/src/app/+login/login.module.ts28
5 files changed, 382 insertions, 0 deletions
diff --git a/client/src/app/+login/login-routing.module.ts b/client/src/app/+login/login-routing.module.ts
new file mode 100644
index 000000000..aad55eac8
--- /dev/null
+++ b/client/src/app/+login/login-routing.module.ts
@@ -0,0 +1,27 @@
1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router'
3import { MetaGuard } from '@ngx-meta/core'
4import { LoginComponent } from './login.component'
5import { ServerConfigResolver } from '@app/core/routing/server-config-resolver.service'
6
7const loginRoutes: Routes = [
8 {
9 path: '',
10 component: LoginComponent,
11 canActivate: [ MetaGuard ],
12 data: {
13 meta: {
14 title: 'Login'
15 }
16 },
17 resolve: {
18 serverConfig: ServerConfigResolver
19 }
20 }
21]
22
23@NgModule({
24 imports: [ RouterModule.forChild(loginRoutes) ],
25 exports: [ RouterModule ]
26})
27export class LoginRoutingModule {}
diff --git a/client/src/app/+login/login.component.html b/client/src/app/+login/login.component.html
new file mode 100644
index 000000000..599b203ae
--- /dev/null
+++ b/client/src/app/+login/login.component.html
@@ -0,0 +1,114 @@
1<div class="margin-content">
2 <div i18n class="title-page title-page-single">
3 Login
4 </div>
5
6 <div class="alert alert-danger" i18n *ngIf="externalAuthError">
7 Sorry but there was an issue with the external login process. Please <a routerLink="/about">contact an administrator</a>.
8 </div>
9
10 <ng-container *ngIf="!externalAuthError && !isAuthenticatedWithExternalAuth">
11 <div class="looking-for-account alert alert-info" *ngIf="signupAllowed === false" role="alert">
12 <h6 class="alert-heading" i18n>
13 If you are looking for an account…
14 </h6>
15
16 <div i18n>
17 Currently this instance doesn't allow for user registration, but you can find an instance
18 that gives you the possibility to sign up for an account and upload your videos there.
19
20 <br />
21
22 Find yours among multiple instances at <a class="alert-link" href="https://joinpeertube.org/instances" target="_blank" rel="noopener noreferrer">https://joinpeertube.org/instances</a>.
23 </div>
24 </div>
25
26 <div *ngIf="error" class="alert alert-danger">{{ error }}
27 <span *ngIf="error === 'User email is not verified.'"> <a i18n routerLink="/verify-account/ask-send-email">Request new verification email.</a></span>
28 </div>
29
30 <div class="login-form-and-externals">
31
32 <form role="form" (ngSubmit)="login()" [formGroup]="form">
33 <div class="form-group">
34 <div>
35 <label i18n for="username">User</label>
36 <input
37 type="text" id="username" i18n-placeholder placeholder="Username or email address" required tabindex="1"
38 formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" #usernameInput
39 >
40 <a i18n *ngIf="signupAllowed === true" routerLink="/signup" class="create-an-account">
41 or create an account
42 </a>
43 </div>
44
45 <div *ngIf="formErrors.username" class="form-error">
46 {{ formErrors.username }}
47 </div>
48 </div>
49
50 <div class="form-group">
51 <label i18n for="password">Password</label>
52 <div>
53 <input
54 type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2" autocomplete="current-password"
55 formControlName="password" class="form-control" [ngClass]="{ 'input-error': formErrors['password'] }"
56 >
57 <a i18n-title class="forgot-password-button" (click)="openForgotPasswordModal()" title="Click here to reset your password">I forgot my password</a>
58 </div>
59 <div *ngIf="formErrors.password" class="form-error">
60 {{ formErrors.password }}
61 </div>
62 </div>
63
64 <input type="submit" i18n-value value="Login" [disabled]="!form.valid">
65 </form>
66
67 <div class="external-login-blocks" *ngIf="getExternalLogins().length !== 0">
68 <div class="block-title" i18n>Or sign in with</div>
69
70 <div>
71 <a class="external-login-block" *ngFor="let auth of getExternalLogins()" [href]="getAuthHref(auth)" role="button">
72 {{ auth.authDisplayName }}
73 </a>
74 </div>
75 </div>
76 </div>
77
78 </ng-container>
79</div>
80
81<ng-template #forgotPasswordModal>
82 <div class="modal-header">
83 <h4 i18n class="modal-title">Forgot your password</h4>
84
85 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hideForgotPasswordModal()"></my-global-icon>
86 </div>
87
88 <div class="modal-body">
89
90 <div *ngIf="isEmailDisabled()" class="alert alert-danger" i18n>
91 We are sorry, you cannot recover your password because your instance administrator did not configure the PeerTube email system.
92 </div>
93
94 <div class="form-group" [hidden]="isEmailDisabled()">
95 <label i18n for="forgot-password-email">Email</label>
96 <input
97 type="email" id="forgot-password-email" i18n-placeholder placeholder="Email address" required
98 [(ngModel)]="forgotPasswordEmail" #forgotPasswordEmailInput
99 >
100 </div>
101 </div>
102
103 <div class="modal-footer inputs">
104 <input
105 type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel"
106 (click)="hideForgotPasswordModal()" (key.enter)="hideForgotPasswordModal()"
107 >
108
109 <input
110 type="submit" i18n-value value="Send me an email to reset my password" class="action-button-submit"
111 (click)="askResetPassword()" [disabled]="!forgotPasswordEmailInput.validity.valid"
112 >
113 </div>
114</ng-template>
diff --git a/client/src/app/+login/login.component.scss b/client/src/app/+login/login.component.scss
new file mode 100644
index 000000000..fde6cc15e
--- /dev/null
+++ b/client/src/app/+login/login.component.scss
@@ -0,0 +1,66 @@
1@import '_variables';
2@import '_mixins';
3
4label {
5 display: block;
6}
7
8input:not([type=submit]) {
9 @include peertube-input-text(340px);
10 display: inline-block;
11 margin-right: 5px;
12
13}
14
15input[type=submit] {
16 @include peertube-button;
17 @include orange-button;
18}
19
20.create-an-account, .forgot-password-button {
21 color: pvar(--mainForegroundColor);
22 cursor: pointer;
23 transition: opacity cubic-bezier(0.39, 0.575, 0.565, 1);
24
25 &:hover {
26 text-decoration: none !important;
27 opacity: .7 !important;
28 }
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 min-width: 200px;
42
43 .block-title {
44 font-weight: $font-semibold;
45 }
46
47 .external-login-block {
48 @include disable-default-a-behaviour;
49
50 cursor: pointer;
51 border: 1px solid #d1d7e0;
52 border-radius: 5px;
53 color: pvar(--mainForegroundColor);
54 margin: 10px 10px 0 0;
55 display: flex;
56 justify-content: center;
57 align-items: center;
58 min-height: 35px;
59 min-width: 100px;
60
61 &:hover {
62 background-color: rgba(209, 215, 224, 0.5)
63 }
64 }
65 }
66}
diff --git a/client/src/app/+login/login.component.ts b/client/src/app/+login/login.component.ts
new file mode 100644
index 000000000..cbc51ee21
--- /dev/null
+++ b/client/src/app/+login/login.component.ts
@@ -0,0 +1,147 @@
1import { environment } from 'src/environments/environment'
2import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'
3import { ActivatedRoute } from '@angular/router'
4import { AuthService, Notifier, RedirectService, UserService } from '@app/core'
5import { HooksService } from '@app/core/plugins/hooks.service'
6import { FormReactive, FormValidatorService, LoginValidatorsService } from '@app/shared/shared-forms'
7import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
8import { I18n } from '@ngx-translate/i18n-polyfill'
9import { RegisteredExternalAuthConfig, ServerConfig } from '@shared/models'
10
11@Component({
12 selector: 'my-login',
13 templateUrl: './login.component.html',
14 styleUrls: [ './login.component.scss' ]
15})
16
17export class LoginComponent extends FormReactive implements OnInit, AfterViewInit {
18 @ViewChild('usernameInput', { static: false }) usernameInput: ElementRef
19 @ViewChild('forgotPasswordModal', { static: true }) forgotPasswordModal: ElementRef
20
21 error: string = null
22 forgotPasswordEmail = ''
23
24 isAuthenticatedWithExternalAuth = false
25 externalAuthError = false
26 externalLogins: string[] = []
27
28 private openedForgotPasswordModal: NgbModalRef
29 private serverConfig: ServerConfig
30
31 constructor (
32 protected formValidatorService: FormValidatorService,
33 private route: ActivatedRoute,
34 private modalService: NgbModal,
35 private loginValidatorsService: LoginValidatorsService,
36 private authService: AuthService,
37 private userService: UserService,
38 private redirectService: RedirectService,
39 private notifier: Notifier,
40 private hooks: HooksService,
41 private i18n: I18n
42 ) {
43 super()
44 }
45
46 get signupAllowed () {
47 return this.serverConfig.signup.allowed === true
48 }
49
50 isEmailDisabled () {
51 return this.serverConfig.email.enabled === false
52 }
53
54 ngOnInit () {
55 const snapshot = this.route.snapshot
56
57 this.serverConfig = snapshot.data.serverConfig
58
59 if (snapshot.queryParams.externalAuthToken) {
60 this.loadExternalAuthToken(snapshot.queryParams.username, snapshot.queryParams.externalAuthToken)
61 return
62 }
63
64 if (snapshot.queryParams.externalAuthError) {
65 this.externalAuthError = true
66 return
67 }
68
69 this.buildForm({
70 username: this.loginValidatorsService.LOGIN_USERNAME,
71 password: this.loginValidatorsService.LOGIN_PASSWORD
72 })
73 }
74
75 ngAfterViewInit () {
76 if (this.usernameInput) {
77 this.usernameInput.nativeElement.focus()
78 }
79
80 this.hooks.runAction('action:login.init', 'login')
81 }
82
83 getExternalLogins () {
84 return this.serverConfig.plugin.registeredExternalAuths
85 }
86
87 getAuthHref (auth: RegisteredExternalAuthConfig) {
88 return environment.apiUrl + `/plugins/${auth.name}/${auth.version}/auth/${auth.authName}`
89 }
90
91 login () {
92 this.error = null
93
94 const { username, password } = this.form.value
95
96 this.authService.login(username, password)
97 .subscribe(
98 () => this.redirectService.redirectToPreviousRoute(),
99
100 err => this.handleError(err)
101 )
102 }
103
104 askResetPassword () {
105 this.userService.askResetPassword(this.forgotPasswordEmail)
106 .subscribe(
107 () => {
108 const message = this.i18n(
109 'An email with the reset password instructions will be sent to {{email}}. The link will expire within 1 hour.',
110 { email: this.forgotPasswordEmail }
111 )
112 this.notifier.success(message)
113 this.hideForgotPasswordModal()
114 },
115
116 err => this.notifier.error(err.message)
117 )
118 }
119
120 openForgotPasswordModal () {
121 this.openedForgotPasswordModal = this.modalService.open(this.forgotPasswordModal)
122 }
123
124 hideForgotPasswordModal () {
125 this.openedForgotPasswordModal.close()
126 }
127
128 private loadExternalAuthToken (username: string, token: string) {
129 this.isAuthenticatedWithExternalAuth = true
130
131 this.authService.login(username, null, token)
132 .subscribe(
133 () => this.redirectService.redirectToPreviousRoute(),
134
135 err => {
136 this.handleError(err)
137 this.isAuthenticatedWithExternalAuth = false
138 }
139 )
140 }
141
142 private handleError (err: any) {
143 if (err.message.indexOf('credentials are invalid') !== -1) this.error = this.i18n('Incorrect username or password.')
144 else if (err.message.indexOf('blocked') !== -1) this.error = this.i18n('You account is blocked.')
145 else this.error = err.message
146 }
147}
diff --git a/client/src/app/+login/login.module.ts b/client/src/app/+login/login.module.ts
new file mode 100644
index 000000000..c41902426
--- /dev/null
+++ b/client/src/app/+login/login.module.ts
@@ -0,0 +1,28 @@
1import { NgModule } from '@angular/core'
2import { SharedFormModule } from '@app/shared/shared-forms'
3import { SharedGlobalIconModule } from '@app/shared/shared-icons'
4import { SharedMainModule } from '@app/shared/shared-main'
5import { LoginRoutingModule } from './login-routing.module'
6import { LoginComponent } from './login.component'
7
8@NgModule({
9 imports: [
10 LoginRoutingModule,
11
12 SharedMainModule,
13 SharedFormModule,
14 SharedGlobalIconModule
15 ],
16
17 declarations: [
18 LoginComponent
19 ],
20
21 exports: [
22 LoginComponent
23 ],
24
25 providers: [
26 ]
27})
28export class LoginModule { }