aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-06-11 14:30:49 +0200
committerChocobozzz <me@florianbigard.com>2019-06-11 14:31:12 +0200
commit0ba5f5baade94a051710d9d9d408ac8083c14ac6 (patch)
treee470a2b546d1d1ac9796b6c8ae3afffccd0aca6c
parentd1ab89deb79f70c439b58750d044d9cadf1194e5 (diff)
downloadPeerTube-0ba5f5baade94a051710d9d9d408ac8083c14ac6.tar.gz
PeerTube-0ba5f5baade94a051710d9d9d408ac8083c14ac6.tar.zst
PeerTube-0ba5f5baade94a051710d9d9d408ac8083c14ac6.zip
Add ability to change email in client
-rw-r--r--client/proxy.config.json5
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-change-email/index.ts1
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html36
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.scss24
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts73
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html2
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-settings.component.html3
-rw-r--r--client/src/app/+my-account/my-account.module.ts4
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html17
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts19
-rw-r--r--client/src/app/shared/users/user.model.ts1
-rw-r--r--client/src/app/shared/users/user.service.ts19
-rw-r--r--server/middlewares/validators/users.ts2
13 files changed, 189 insertions, 17 deletions
diff --git a/client/proxy.config.json b/client/proxy.config.json
index e5f0dfd61..4a72f1826 100644
--- a/client/proxy.config.json
+++ b/client/proxy.config.json
@@ -8,7 +8,8 @@
8 "secure": false 8 "secure": false
9 }, 9 },
10 "/socket.io": { 10 "/socket.io": {
11 "target": "http://localhost:9000", 11 "target": "ws://localhost:9000",
12 "secure": false 12 "secure": false,
13 "ws": true
13 } 14 }
14} 15}
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/index.ts b/client/src/app/+my-account/my-account-settings/my-account-change-email/index.ts
new file mode 100644
index 000000000..f42af361e
--- /dev/null
+++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/index.ts
@@ -0,0 +1 @@
export * from './my-account-change-email.component'
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html
new file mode 100644
index 000000000..ebfe3126d
--- /dev/null
+++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html
@@ -0,0 +1,36 @@
1<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
2<div *ngIf="success" class="alert alert-success">{{ success }}</div>
3
4<div i18n class="current-email">
5 Your current email is <span class="email">{{ user.email }}</span>
6</div>
7
8<div i18n class="pending-email" *ngIf="user.pendingEmail">
9 <span class="email">{{ user.pendingEmail }}</span> is awaiting email verification
10</div>
11
12<form role="form" (ngSubmit)="changeEmail()" [formGroup]="form">
13
14 <div class="form-group">
15 <label i18n for="new-email">New email</label>
16 <input
17 type="email" id="new-email" i18n-placeholder placeholder="Your new email"
18 formControlName="new-email" [ngClass]="{ 'input-error': formErrors['new-email'] }"
19 >
20 <div *ngIf="formErrors['new-email']" class="form-error">
21 {{ formErrors['new-email'] }}
22 </div>
23 </div>
24
25 <div class="form-group">
26 <input
27 type="password" id="password" i18n-placeholder placeholder="Your password"
28 formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
29 >
30 <div *ngIf="formErrors['password']" class="form-error">
31 {{ formErrors['password'] }}
32 </div>
33 </div>
34
35 <input type="submit" i18n-value value="Change email" [disabled]="!form.valid">
36</form>
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.scss b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.scss
new file mode 100644
index 000000000..81eba3ec9
--- /dev/null
+++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.scss
@@ -0,0 +1,24 @@
1@import '_variables';
2@import '_mixins';
3
4input[type=password],
5input[type=email] {
6 @include peertube-input-text(340px);
7
8 display: block;
9}
10
11input[type=submit] {
12 @include peertube-button;
13 @include orange-button;
14}
15
16.current-email,
17.pending-email {
18 font-size: 16px;
19 margin: 15px 0;
20
21 .email {
22 font-weight: $font-semibold;
23 }
24}
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts
new file mode 100644
index 000000000..577c5b102
--- /dev/null
+++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts
@@ -0,0 +1,73 @@
1import { Component, OnInit } from '@angular/core'
2import { AuthService, Notifier, ServerService } from '@app/core'
3import { FormReactive, UserService } from '../../../shared'
4import { I18n } from '@ngx-translate/i18n-polyfill'
5import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
6import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
7import { User } from '../../../../../../shared'
8import { switchMap, tap } from 'rxjs/operators'
9
10@Component({
11 selector: 'my-account-change-email',
12 templateUrl: './my-account-change-email.component.html',
13 styleUrls: [ './my-account-change-email.component.scss' ]
14})
15export class MyAccountChangeEmailComponent extends FormReactive implements OnInit {
16 error: string = null
17 success: string = null
18 user: User = null
19
20 constructor (
21 protected formValidatorService: FormValidatorService,
22 private userValidatorsService: UserValidatorsService,
23 private notifier: Notifier,
24 private authService: AuthService,
25 private userService: UserService,
26 private serverService: ServerService,
27 private i18n: I18n
28 ) {
29 super()
30 }
31
32 ngOnInit () {
33 this.buildForm({
34 'new-email': this.userValidatorsService.USER_EMAIL,
35 'password': this.userValidatorsService.USER_PASSWORD
36 })
37
38 this.user = this.authService.getUser()
39 }
40
41 changeEmail () {
42 this.error = null
43 this.success = null
44
45 const password = this.form.value[ 'password' ]
46 const email = this.form.value[ 'new-email' ]
47
48 this.userService.changeEmail(password, email)
49 .pipe(
50 tap(() => this.authService.refreshUserInformation())
51 )
52 .subscribe(
53 () => {
54 this.form.reset()
55
56 if (this.serverService.getConfig().signup.requiresEmailVerification) {
57 this.success = this.i18n('Please check your emails to verify your new email.')
58 } else {
59 this.success = this.i18n('Email updated.')
60 }
61 },
62
63 err => {
64 if (err.status === 401) {
65 this.error = this.i18n('You current password is invalid.')
66 return
67 }
68
69 this.error = err.message
70 }
71 )
72 }
73}
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html
index ae797d1bc..a39061ee3 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html
+++ b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html
@@ -2,7 +2,7 @@
2 2
3<form role="form" (ngSubmit)="changePassword()" [formGroup]="form"> 3<form role="form" (ngSubmit)="changePassword()" [formGroup]="form">
4 4
5 <label i18n for="new-password">Change password</label> 5 <label i18n for="current-password">Change password</label>
6 <input 6 <input
7 type="password" id="current-password" i18n-placeholder placeholder="Current password" 7 type="password" id="current-password" i18n-placeholder placeholder="Current password"
8 formControlName="current-password" [ngClass]="{ 'input-error': formErrors['current-password'] }" 8 formControlName="current-password" [ngClass]="{ 'input-error': formErrors['current-password'] }"
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html
index ad64f28fe..f93d41110 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html
+++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html
@@ -13,6 +13,9 @@
13<div i18n class="account-title">Password</div> 13<div i18n class="account-title">Password</div>
14<my-account-change-password></my-account-change-password> 14<my-account-change-password></my-account-change-password>
15 15
16<div i18n class="account-title">Email</div>
17<my-account-change-email></my-account-change-email>
18
16<div i18n class="account-title">Video settings</div> 19<div i18n class="account-title">Video settings</div>
17<my-account-video-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-video-settings> 20<my-account-video-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-video-settings>
18 21
diff --git a/client/src/app/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts
index 4a18a9968..ca5b1f7cb 100644
--- a/client/src/app/+my-account/my-account.module.ts
+++ b/client/src/app/+my-account/my-account.module.ts
@@ -36,6 +36,7 @@ import {
36 MyAccountVideoPlaylistElementsComponent 36 MyAccountVideoPlaylistElementsComponent
37} from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component' 37} from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component'
38import { DragDropModule } from '@angular/cdk/drag-drop' 38import { DragDropModule } from '@angular/cdk/drag-drop'
39import { MyAccountChangeEmailComponent } from '@app/+my-account/my-account-settings/my-account-change-email'
39 40
40@NgModule({ 41@NgModule({
41 imports: [ 42 imports: [
@@ -54,7 +55,10 @@ import { DragDropModule } from '@angular/cdk/drag-drop'
54 MyAccountChangePasswordComponent, 55 MyAccountChangePasswordComponent,
55 MyAccountVideoSettingsComponent, 56 MyAccountVideoSettingsComponent,
56 MyAccountProfileComponent, 57 MyAccountProfileComponent,
58 MyAccountChangeEmailComponent,
59
57 MyAccountVideosComponent, 60 MyAccountVideosComponent,
61
58 VideoChangeOwnershipComponent, 62 VideoChangeOwnershipComponent,
59 MyAccountOwnershipComponent, 63 MyAccountOwnershipComponent,
60 MyAccountAcceptOwnershipComponent, 64 MyAccountAcceptOwnershipComponent,
diff --git a/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html
index 728709ca6..47519c943 100644
--- a/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html
+++ b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html
@@ -3,13 +3,16 @@
3 Verify account email confirmation 3 Verify account email confirmation
4 </div> 4 </div>
5 5
6 <my-signup-success i18n *ngIf="success; else verificationError" message="Your email has been verified and you may now login."> 6 <my-signup-success i18n *ngIf="!isPendingEmail && success" message="Your email has been verified and you may now login.">
7 </my-signup-success> 7 </my-signup-success>
8 8
9 <ng-template #verificationError> 9 <div i18n class="alert alert-success" *ngIf="isPendingEmail && success">
10 <div> 10 Email updated.
11 <span i18n>An error occurred. </span> 11 </div>
12 <a i18n routerLink="/verify-account/ask-send-email">Request new verification email.</a> 12
13 </div> 13 <div *ngIf="failed">
14 </ng-template> 14 <span i18n>An error occurred.</span>
15
16 <a i18n routerLink="/verify-account/ask-send-email" [queryParams]="{ isPendingEmail: isPendingEmail }">Request new verification email.</a>
17 </div>
15</div> 18</div>
diff --git a/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts
index 3fb2d1cd8..054f04310 100644
--- a/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts
+++ b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts
@@ -1,7 +1,7 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { I18n } from '@ngx-translate/i18n-polyfill' 3import { I18n } from '@ngx-translate/i18n-polyfill'
4import { Notifier } from '@app/core' 4import { AuthService, Notifier } from '@app/core'
5import { UserService } from '@app/shared' 5import { UserService } from '@app/shared'
6 6
7@Component({ 7@Component({
@@ -11,12 +11,15 @@ import { UserService } from '@app/shared'
11 11
12export class VerifyAccountEmailComponent implements OnInit { 12export class VerifyAccountEmailComponent implements OnInit {
13 success = false 13 success = false
14 failed = false
15 isPendingEmail = false
14 16
15 private userId: number 17 private userId: number
16 private verificationString: string 18 private verificationString: string
17 19
18 constructor ( 20 constructor (
19 private userService: UserService, 21 private userService: UserService,
22 private authService: AuthService,
20 private notifier: Notifier, 23 private notifier: Notifier,
21 private router: Router, 24 private router: Router,
22 private route: ActivatedRoute, 25 private route: ActivatedRoute,
@@ -25,8 +28,12 @@ export class VerifyAccountEmailComponent implements OnInit {
25 } 28 }
26 29
27 ngOnInit () { 30 ngOnInit () {
28 this.userId = this.route.snapshot.queryParams['userId'] 31 const queryParams = this.route.snapshot.queryParams
29 this.verificationString = this.route.snapshot.queryParams['verificationString'] 32 this.userId = queryParams['userId']
33 this.verificationString = queryParams['verificationString']
34 this.isPendingEmail = queryParams['isPendingEmail'] === 'true'
35
36 console.log(this.isPendingEmail)
30 37
31 if (!this.userId || !this.verificationString) { 38 if (!this.userId || !this.verificationString) {
32 this.notifier.error(this.i18n('Unable to find user id or verification string.')) 39 this.notifier.error(this.i18n('Unable to find user id or verification string.'))
@@ -36,13 +43,17 @@ export class VerifyAccountEmailComponent implements OnInit {
36 } 43 }
37 44
38 verifyEmail () { 45 verifyEmail () {
39 this.userService.verifyEmail(this.userId, this.verificationString) 46 this.userService.verifyEmail(this.userId, this.verificationString, this.isPendingEmail)
40 .subscribe( 47 .subscribe(
41 () => { 48 () => {
49 this.authService.refreshUserInformation()
50
42 this.success = true 51 this.success = true
43 }, 52 },
44 53
45 err => { 54 err => {
55 this.failed = true
56
46 this.notifier.error(err.message) 57 this.notifier.error(err.message)
47 } 58 }
48 ) 59 )
diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts
index e3ed2dfbd..14d13959a 100644
--- a/client/src/app/shared/users/user.model.ts
+++ b/client/src/app/shared/users/user.model.ts
@@ -8,6 +8,7 @@ export class User implements UserServerModel {
8 id: number 8 id: number
9 username: string 9 username: string
10 email: string 10 email: string
11 pendingEmail: string | null
11 emailVerified: boolean 12 emailVerified: boolean
12 nsfwPolicy: NSFWPolicyType 13 nsfwPolicy: NSFWPolicyType
13 14
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts
index 70ff9a058..41ee87197 100644
--- a/client/src/app/shared/users/user.service.ts
+++ b/client/src/app/shared/users/user.service.ts
@@ -38,6 +38,20 @@ export class UserService {
38 ) 38 )
39 } 39 }
40 40
41 changeEmail (password: string, newEmail: string) {
42 const url = UserService.BASE_USERS_URL + 'me'
43 const body: UserUpdateMe = {
44 currentPassword: password,
45 email: newEmail
46 }
47
48 return this.authHttp.put(url, body)
49 .pipe(
50 map(this.restExtractor.extractDataBool),
51 catchError(err => this.restExtractor.handleError(err))
52 )
53 }
54
41 updateMyProfile (profile: UserUpdateMe) { 55 updateMyProfile (profile: UserUpdateMe) {
42 const url = UserService.BASE_USERS_URL + 'me' 56 const url = UserService.BASE_USERS_URL + 'me'
43 57
@@ -104,10 +118,11 @@ export class UserService {
104 ) 118 )
105 } 119 }
106 120
107 verifyEmail (userId: number, verificationString: string) { 121 verifyEmail (userId: number, verificationString: string, isPendingEmail: boolean) {
108 const url = `${UserService.BASE_USERS_URL}/${userId}/verify-email` 122 const url = `${UserService.BASE_USERS_URL}/${userId}/verify-email`
109 const body = { 123 const body = {
110 verificationString 124 verificationString,
125 isPendingEmail
111 } 126 }
112 127
113 return this.authHttp.post(url, body) 128 return this.authHttp.post(url, body)
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index a4d4ae46d..ec70fa0fd 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -205,7 +205,7 @@ const usersUpdateMeValidator = [
205 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 205 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
206 logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') }) 206 logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') })
207 207
208 if (req.body.password) { 208 if (req.body.password || req.body.email) {
209 if (!req.body.currentPassword) { 209 if (!req.body.currentPassword) {
210 return res.status(400) 210 return res.status(400)
211 .send({ error: 'currentPassword parameter is missing.' }) 211 .send({ error: 'currentPassword parameter is missing.' })