aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app
diff options
context:
space:
mode:
authorJosh Morel <morel.josh@hotmail.com>2018-08-31 03:18:19 -0400
committerChocobozzz <me@florianbigard.com>2018-08-31 09:18:19 +0200
commitd9eaee3939bf2e93e5d775d32bce77842201faba (patch)
treec115acb3611986b98f51b3addf29ebe66f63ee7f /client/src/app
parent04291e1ba44032165388758e993d385a10c1c5a1 (diff)
downloadPeerTube-d9eaee3939bf2e93e5d775d32bce77842201faba.tar.gz
PeerTube-d9eaee3939bf2e93e5d775d32bce77842201faba.tar.zst
PeerTube-d9eaee3939bf2e93e5d775d32bce77842201faba.zip
add user account email verificiation (#977)
* add user account email verificiation includes server and client code to: * enable verificationRequired via custom config * send verification email with registration * ask for verification email * verify via email * prevent login if not verified and required * conditional client links to ask for new verification email * allow login for verified=null these are users created when verification not required should still be able to login when verification is enabled * refactor email verifcation pr * change naming from verified to emailVerified * change naming from askVerifyEmail to askSendVerifyEmail * undo unrelated automatic prettier formatting on api/config * use redirectService for home * remove redundant success notification on email verified * revert test.yaml smpt host
Diffstat (limited to 'client/src/app')
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html5
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts5
-rw-r--r--client/src/app/+verify-account/index.ts2
-rw-r--r--client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html22
-rw-r--r--client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss12
-rw-r--r--client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts58
-rw-r--r--client/src/app/+verify-account/verify-account-email/verify-account-email.component.html15
-rw-r--r--client/src/app/+verify-account/verify-account-email/verify-account-email.component.ts54
-rw-r--r--client/src/app/+verify-account/verify-account-routing.module.ts42
-rw-r--r--client/src/app/+verify-account/verify-account.module.ts27
-rw-r--r--client/src/app/app-routing.module.ts4
-rw-r--r--client/src/app/core/server/server.service.ts3
-rw-r--r--client/src/app/login/login.component.html4
-rw-r--r--client/src/app/shared/users/user.service.ts23
-rw-r--r--client/src/app/signup/signup.component.ts22
15 files changed, 290 insertions, 8 deletions
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
index ca7890d84..a0f0abd10 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
@@ -91,6 +91,11 @@
91 i18n-labelText labelText="Signup enabled" 91 i18n-labelText labelText="Signup enabled"
92 ></my-peertube-checkbox> 92 ></my-peertube-checkbox>
93 93
94 <my-peertube-checkbox *ngIf="isSignupEnabled()"
95 inputName="signupRequiresEmailVerification" formControlName="signupRequiresEmailVerification"
96 i18n-labelText labelText="Signup requires email verification"
97 ></my-peertube-checkbox>
98
94 <div *ngIf="isSignupEnabled()" class="form-group"> 99 <div *ngIf="isSignupEnabled()" class="form-group">
95 <label i18n for="signupLimit">Signup limit</label> 100 <label i18n for="signupLimit">Signup limit</label>
96 <input 101 <input
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
index 248b0df50..ce2ea8a6c 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
@@ -90,6 +90,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
90 cacheCaptionsSize: this.customConfigValidatorsService.CACHE_CAPTIONS_SIZE, 90 cacheCaptionsSize: this.customConfigValidatorsService.CACHE_CAPTIONS_SIZE,
91 signupEnabled: null, 91 signupEnabled: null,
92 signupLimit: this.customConfigValidatorsService.SIGNUP_LIMIT, 92 signupLimit: this.customConfigValidatorsService.SIGNUP_LIMIT,
93 signupRequiresEmailVerification: null,
93 importVideosHttpEnabled: null, 94 importVideosHttpEnabled: null,
94 importVideosTorrentEnabled: null, 95 importVideosTorrentEnabled: null,
95 adminEmail: this.customConfigValidatorsService.ADMIN_EMAIL, 96 adminEmail: this.customConfigValidatorsService.ADMIN_EMAIL,
@@ -187,7 +188,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
187 }, 188 },
188 signup: { 189 signup: {
189 enabled: this.form.value['signupEnabled'], 190 enabled: this.form.value['signupEnabled'],
190 limit: this.form.value['signupLimit'] 191 limit: this.form.value['signupLimit'],
192 requiresEmailVerification: this.form.value['signupRequiresEmailVerification']
191 }, 193 },
192 admin: { 194 admin: {
193 email: this.form.value['adminEmail'] 195 email: this.form.value['adminEmail']
@@ -250,6 +252,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
250 cacheCaptionsSize: this.customConfig.cache.captions.size, 252 cacheCaptionsSize: this.customConfig.cache.captions.size,
251 signupEnabled: this.customConfig.signup.enabled, 253 signupEnabled: this.customConfig.signup.enabled,
252 signupLimit: this.customConfig.signup.limit, 254 signupLimit: this.customConfig.signup.limit,
255 signupRequiresEmailVerification: this.customConfig.signup.requiresEmailVerification,
253 adminEmail: this.customConfig.admin.email, 256 adminEmail: this.customConfig.admin.email,
254 userVideoQuota: this.customConfig.user.videoQuota, 257 userVideoQuota: this.customConfig.user.videoQuota,
255 userVideoQuotaDaily: this.customConfig.user.videoQuotaDaily, 258 userVideoQuotaDaily: this.customConfig.user.videoQuotaDaily,
diff --git a/client/src/app/+verify-account/index.ts b/client/src/app/+verify-account/index.ts
new file mode 100644
index 000000000..733f5ba77
--- /dev/null
+++ b/client/src/app/+verify-account/index.ts
@@ -0,0 +1,2 @@
1export * from '@app/+verify-account/verify-account-routing.module'
2export * from '@app/+verify-account/verify-account.module'
diff --git a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html b/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html
new file mode 100644
index 000000000..2e4180632
--- /dev/null
+++ b/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html
@@ -0,0 +1,22 @@
1<div class="margin-content">
2 <div i18n class="title-page title-page-single">
3 Request email for account verification
4 </div>
5
6 <form *ngIf="requiresEmailVerification; else emailVerificationNotRequired" role="form" (ngSubmit)="askSendVerifyEmail()" [formGroup]="form">
7 <div class="form-group">
8 <label i18n for="verify-email-email">Email</label>
9 <input
10 type="email" id="verify-email-email" i18n-placeholder placeholder="Email address" required
11 formControlName="verify-email-email" [ngClass]="{ 'input-error': formErrors['verify-email-email'] }"
12 >
13 <div *ngIf="formErrors['verify-email-email']" class="form-error">
14 {{ formErrors['verify-email-email'] }}
15 </div>
16 </div>
17 <input type="submit" i18n-value value="Send verification email" [disabled]="!form.valid">
18 </form>
19 <ng-template #emailVerificationNotRequired>
20 <div i18n>This instance does not require email verification.</div>
21 </ng-template>
22</div>
diff --git a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss b/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss
new file mode 100644
index 000000000..efec6b706
--- /dev/null
+++ b/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss
@@ -0,0 +1,12 @@
1@import '_variables';
2@import '_mixins';
3
4input:not([type=submit]) {
5 @include peertube-input-text(340px);
6 display: block;
7}
8
9input[type=submit] {
10 @include peertube-button;
11 @include orange-button;
12}
diff --git a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts b/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts
new file mode 100644
index 000000000..995f42ffc
--- /dev/null
+++ b/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts
@@ -0,0 +1,58 @@
1import { Component, OnInit } from '@angular/core'
2import { I18n } from '@ngx-translate/i18n-polyfill'
3import { NotificationsService } from 'angular2-notifications'
4import { ServerService } from '@app/core/server'
5import { RedirectService } from '@app/core'
6import { UserService, FormReactive } from '@app/shared'
7import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
8import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
9
10@Component({
11 selector: 'my-verify-account-ask-send-email',
12 templateUrl: './verify-account-ask-send-email.component.html',
13 styleUrls: [ './verify-account-ask-send-email.component.scss' ]
14})
15
16export class VerifyAccountAskSendEmailComponent extends FormReactive implements OnInit {
17
18 constructor (
19 protected formValidatorService: FormValidatorService,
20 private userValidatorsService: UserValidatorsService,
21 private userService: UserService,
22 private serverService: ServerService,
23 private notificationsService: NotificationsService,
24 private redirectService: RedirectService,
25 private i18n: I18n
26 ) {
27 super()
28 }
29
30 get requiresEmailVerification () {
31 return this.serverService.getConfig().signup.requiresEmailVerification
32 }
33
34 ngOnInit () {
35 this.buildForm({
36 'verify-email-email': this.userValidatorsService.USER_EMAIL
37 })
38 }
39
40 askSendVerifyEmail () {
41 const email = this.form.value['verify-email-email']
42 this.userService.askSendVerifyEmail(email)
43 .subscribe(
44 () => {
45 const message = this.i18n(
46 'An email with verification link will be sent to {{email}}.',
47 { email }
48 )
49 this.notificationsService.success(this.i18n('Success'), message)
50 this.redirectService.redirectToHomepage()
51 },
52
53 err => {
54 this.notificationsService.error(this.i18n('Error'), err.message)
55 }
56 )
57 }
58}
diff --git a/client/src/app/+verify-account/verify-account-email/verify-account-email.component.html b/client/src/app/+verify-account/verify-account-email/verify-account-email.component.html
new file mode 100644
index 000000000..30ace5e10
--- /dev/null
+++ b/client/src/app/+verify-account/verify-account-email/verify-account-email.component.html
@@ -0,0 +1,15 @@
1<div class="margin-content">
2 <div i18n class="title-page title-page-single">
3 Verify account email confirmation
4 </div>
5
6 <div i18n *ngIf="success; else verificationError">
7 Your email has been verified and you may now login. Redirecting...
8 </div>
9 <ng-template #verificationError>
10 <div>
11 <span i18n>An error occurred. </span>
12 <a i18n routerLink="/verify-account/ask-email">Request new verification email.</a>
13 </div>
14 </ng-template>
15</div>
diff --git a/client/src/app/+verify-account/verify-account-email/verify-account-email.component.ts b/client/src/app/+verify-account/verify-account-email/verify-account-email.component.ts
new file mode 100644
index 000000000..26b3bf4b1
--- /dev/null
+++ b/client/src/app/+verify-account/verify-account-email/verify-account-email.component.ts
@@ -0,0 +1,54 @@
1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { I18n } from '@ngx-translate/i18n-polyfill'
4import { NotificationsService } from 'angular2-notifications'
5import { UserService } from '@app/shared'
6
7@Component({
8 selector: 'my-verify-account-email',
9 templateUrl: './verify-account-email.component.html'
10})
11
12export class VerifyAccountEmailComponent implements OnInit {
13 success = false
14
15 private userId: number
16 private verificationString: string
17
18 constructor (
19 private userService: UserService,
20 private notificationsService: NotificationsService,
21 private router: Router,
22 private route: ActivatedRoute,
23 private i18n: I18n
24 ) {
25 }
26
27 ngOnInit () {
28
29 this.userId = this.route.snapshot.queryParams['userId']
30 this.verificationString = this.route.snapshot.queryParams['verificationString']
31
32 if (!this.userId || !this.verificationString) {
33 this.notificationsService.error(this.i18n('Error'), this.i18n('Unable to find user id or verification string.'))
34 } else {
35 this.verifyEmail()
36 }
37 }
38
39 verifyEmail () {
40 this.userService.verifyEmail(this.userId, this.verificationString)
41 .subscribe(
42 () => {
43 this.success = true
44 setTimeout(() => {
45 this.router.navigate([ '/login' ])
46 }, 2000)
47 },
48
49 err => {
50 this.notificationsService.error(this.i18n('Error'), err.message)
51 }
52 )
53 }
54}
diff --git a/client/src/app/+verify-account/verify-account-routing.module.ts b/client/src/app/+verify-account/verify-account-routing.module.ts
new file mode 100644
index 000000000..a038f0336
--- /dev/null
+++ b/client/src/app/+verify-account/verify-account-routing.module.ts
@@ -0,0 +1,42 @@
1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router'
3
4import { MetaGuard } from '@ngx-meta/core'
5
6import { VerifyAccountEmailComponent } from '@app/+verify-account/verify-account-email/verify-account-email.component'
7import {
8 VerifyAccountAskSendEmailComponent
9} from '@app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component'
10
11const verifyAccountRoutes: Routes = [
12 {
13 path: '',
14 canActivateChild: [ MetaGuard ],
15 children: [
16 {
17 path: 'email',
18 component: VerifyAccountEmailComponent,
19 data: {
20 meta: {
21 title: 'Verify account email'
22 }
23 }
24 },
25 {
26 path: 'ask-send-email',
27 component: VerifyAccountAskSendEmailComponent,
28 data: {
29 meta: {
30 title: 'Verify account ask send email'
31 }
32 }
33 }
34 ]
35 }
36]
37
38@NgModule({
39 imports: [ RouterModule.forChild(verifyAccountRoutes) ],
40 exports: [ RouterModule ]
41})
42export class VerifyAccountRoutingModule {}
diff --git a/client/src/app/+verify-account/verify-account.module.ts b/client/src/app/+verify-account/verify-account.module.ts
new file mode 100644
index 000000000..9092c6b4f
--- /dev/null
+++ b/client/src/app/+verify-account/verify-account.module.ts
@@ -0,0 +1,27 @@
1import { NgModule } from '@angular/core'
2
3import { VerifyAccountRoutingModule } from '@app/+verify-account/verify-account-routing.module'
4import { VerifyAccountEmailComponent } from '@app/+verify-account/verify-account-email/verify-account-email.component'
5import {
6 VerifyAccountAskSendEmailComponent
7} from '@app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component'
8import { SharedModule } from '@app/shared'
9
10@NgModule({
11 imports: [
12 VerifyAccountRoutingModule,
13 SharedModule
14 ],
15
16 declarations: [
17 VerifyAccountEmailComponent,
18 VerifyAccountAskSendEmailComponent
19 ],
20
21 exports: [
22 ],
23
24 providers: [
25 ]
26})
27export class VerifyAccountModule { }
diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts
index 30e615b3e..545d6aeda 100644
--- a/client/src/app/app-routing.module.ts
+++ b/client/src/app/app-routing.module.ts
@@ -14,6 +14,10 @@ const routes: Routes = [
14 loadChildren: './+my-account/my-account.module#MyAccountModule' 14 loadChildren: './+my-account/my-account.module#MyAccountModule'
15 }, 15 },
16 { 16 {
17 path: 'verify-account',
18 loadChildren: './+verify-account/verify-account.module#VerifyAccountModule'
19 },
20 {
17 path: 'accounts', 21 path: 'accounts',
18 loadChildren: './+accounts/accounts.module#AccountsModule' 22 loadChildren: './+accounts/accounts.module#AccountsModule'
19 }, 23 },
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index a1ce12069..e7152efa0 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -40,7 +40,8 @@ export class ServerService {
40 serverVersion: 'Unknown', 40 serverVersion: 'Unknown',
41 signup: { 41 signup: {
42 allowed: false, 42 allowed: false,
43 allowedForCurrentIP: false 43 allowedForCurrentIP: false,
44 requiresEmailVerification: false
44 }, 45 },
45 transcoding: { 46 transcoding: {
46 enabledResolutions: [] 47 enabledResolutions: []
diff --git a/client/src/app/login/login.component.html b/client/src/app/login/login.component.html
index 3a6d61327..619150ade 100644
--- a/client/src/app/login/login.component.html
+++ b/client/src/app/login/login.component.html
@@ -3,7 +3,9 @@
3 Login 3 Login
4 </div> 4 </div>
5 5
6 <div *ngIf="error" class="alert alert-danger">{{ error }}</div> 6 <div *ngIf="error" class="alert alert-danger">{{ error }}
7 <span *ngIf="error === 'User email is not verified.'"> <a i18n routerLink="/verify-account/ask-send-email">Request new verification email.</a></span>
8 </div>
7 9
8 <form role="form" (ngSubmit)="login()" [formGroup]="form"> 10 <form role="form" (ngSubmit)="login()" [formGroup]="form">
9 <div class="form-group"> 11 <div class="form-group">
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts
index e6dc3dbf8..249c589b7 100644
--- a/client/src/app/shared/users/user.service.ts
+++ b/client/src/app/shared/users/user.service.ts
@@ -94,4 +94,27 @@ export class UserService {
94 catchError(res => this.restExtractor.handleError(res)) 94 catchError(res => this.restExtractor.handleError(res))
95 ) 95 )
96 } 96 }
97
98 verifyEmail (userId: number, verificationString: string) {
99 const url = `${UserService.BASE_USERS_URL}/${userId}/verify-email`
100 const body = {
101 verificationString
102 }
103
104 return this.authHttp.post(url, body)
105 .pipe(
106 map(this.restExtractor.extractDataBool),
107 catchError(res => this.restExtractor.handleError(res))
108 )
109 }
110
111 askSendVerifyEmail (email: string) {
112 const url = UserService.BASE_USERS_URL + '/ask-send-verify-email'
113
114 return this.authHttp.post(url, { email })
115 .pipe(
116 map(this.restExtractor.extractDataBool),
117 catchError(err => this.restExtractor.handleError(err))
118 )
119 }
97} 120}
diff --git a/client/src/app/signup/signup.component.ts b/client/src/app/signup/signup.component.ts
index 47f9bc6f4..16e444678 100644
--- a/client/src/app/signup/signup.component.ts
+++ b/client/src/app/signup/signup.component.ts
@@ -3,7 +3,7 @@ import { Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import { UserCreate } from '../../../../shared' 4import { UserCreate } from '../../../../shared'
5import { FormReactive, UserService, UserValidatorsService } from '../shared' 5import { FormReactive, UserService, UserValidatorsService } from '../shared'
6import { RedirectService } from '@app/core' 6import { RedirectService, ServerService } from '@app/core'
7import { I18n } from '@ngx-translate/i18n-polyfill' 7import { I18n } from '@ngx-translate/i18n-polyfill'
8import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' 8import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
9 9
@@ -21,6 +21,7 @@ export class SignupComponent extends FormReactive implements OnInit {
21 private router: Router, 21 private router: Router,
22 private notificationsService: NotificationsService, 22 private notificationsService: NotificationsService,
23 private userService: UserService, 23 private userService: UserService,
24 private serverService: ServerService,
24 private redirectService: RedirectService, 25 private redirectService: RedirectService,
25 private i18n: I18n 26 private i18n: I18n
26 ) { 27 ) {
@@ -31,6 +32,10 @@ export class SignupComponent extends FormReactive implements OnInit {
31 return window.location.host 32 return window.location.host
32 } 33 }
33 34
35 get requiresEmailVerification () {
36 return this.serverService.getConfig().signup.requiresEmailVerification
37 }
38
34 ngOnInit () { 39 ngOnInit () {
35 this.buildForm({ 40 this.buildForm({
36 username: this.userValidatorsService.USER_USERNAME, 41 username: this.userValidatorsService.USER_USERNAME,
@@ -47,10 +52,17 @@ export class SignupComponent extends FormReactive implements OnInit {
47 52
48 this.userService.signup(userCreate).subscribe( 53 this.userService.signup(userCreate).subscribe(
49 () => { 54 () => {
50 this.notificationsService.success( 55 if (this.requiresEmailVerification) {
51 this.i18n('Success'), 56 this.notificationsService.alert(
52 this.i18n('Registration for {{username}} complete.', { username: userCreate.username }) 57 this.i18n('Welcome'),
53 ) 58 this.i18n('Please check your email to verify your account and complete signup.')
59 )
60 } else {
61 this.notificationsService.success(
62 this.i18n('Success'),
63 this.i18n('Registration for {{username}} complete.', { username: userCreate.username })
64 )
65 }
54 this.redirectService.redirectToHomepage() 66 this.redirectService.redirectToHomepage()
55 }, 67 },
56 68