Add ability to update the user display name/description
authorChocobozzz <me@florianbigard.com>
Thu, 26 Apr 2018 08:03:40 +0000 (10:03 +0200)
committerChocobozzz <me@florianbigard.com>
Thu, 26 Apr 2018 08:03:40 +0000 (10:03 +0200)
26 files changed:
client/src/app/menu/menu.component.html
client/src/app/my-account/my-account-settings/my-account-details/index.ts [deleted file]
client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.html [deleted file]
client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.scss [deleted file]
client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.ts [deleted file]
client/src/app/my-account/my-account-settings/my-account-profile/index.ts [new file with mode: 0644]
client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.html [new file with mode: 0644]
client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.scss [new file with mode: 0644]
client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.ts [new file with mode: 0644]
client/src/app/my-account/my-account-settings/my-account-settings.component.html
client/src/app/my-account/my-account-settings/my-account-video-settings/index.ts [new file with mode: 0644]
client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html [new file with mode: 0644]
client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.scss [new file with mode: 0644]
client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts [new file with mode: 0644]
client/src/app/my-account/my-account.component.html
client/src/app/my-account/my-account.module.ts
client/src/app/shared/forms/form-validators/user.ts
client/src/app/shared/users/user.service.ts
server/controllers/api/users.ts
server/helpers/custom-validators/users.ts
server/initializers/constants.ts
server/middlewares/validators/users.ts
server/tests/api/users/users-multiple-servers.ts
server/tests/api/users/users.ts
server/tests/utils/users/users.ts
shared/models/users/user-update-me.model.ts

index 6e81893713f31342a10c52369c0c1d2d01ba90bd..d1488ec3c3c5775a4cb564fb2e4691e374928c1f 100644 (file)
@@ -5,7 +5,7 @@
     </a>
 
     <div class="logged-in-info">
-      <a routerLink="/my-account/settings" class="logged-in-username">{{ user.username }}</a>
+      <a routerLink="/my-account/settings" class="logged-in-username">{{ user.account?.displayName }}</a>
       <div class="logged-in-email">{{ user.email }}</div>
     </div>
 
@@ -14,8 +14,8 @@
 
       <ul *dropdownMenu class="dropdown-menu">
         <li>
-          <a i18n routerLink="/my-account/settings" class="dropdown-item" title="My account">
-            My account
+          <a routerLink="/my-account/settings" class="dropdown-item" title="My settings">
+            My settings
           </a>
 
           <a (click)="logout($event)" class="dropdown-item" title="Log out" href="#">
diff --git a/client/src/app/my-account/my-account-settings/my-account-details/index.ts b/client/src/app/my-account/my-account-settings/my-account-details/index.ts
deleted file mode 100644 (file)
index b7f58e3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-export * from './my-account-details.component'
diff --git a/client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.html b/client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.html
deleted file mode 100644 (file)
index 0e8598e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<form role="form" (ngSubmit)="updateDetails()" [formGroup]="form">
-  <div class="form-group">
-    <label for="nsfwPolicy">Default policy on videos containing sensitive content</label>
-    <my-help helpType="custom" customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."></my-help>
-
-    <div class="peertube-select-container">
-      <select id="nsfwPolicy" formControlName="nsfwPolicy">
-        <option value="do_not_list">Do not list</option>
-        <option value="blur">Blur thumbnails</option>
-        <option value="display">Display</option>
-      </select>
-    </div>
-  </div>
-
-  <div class="form-group">
-    <input
-      type="checkbox" id="autoPlayVideo"
-      formControlName="autoPlayVideo"
-    >
-    <label for="autoPlayVideo"></label>
-    <label for="autoPlayVideo">Automatically plays video</label>
-  </div>
-
-  <input type="submit" value="Save" [disabled]="!form.valid">
-</form>
diff --git a/client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.scss b/client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.scss
deleted file mode 100644 (file)
index ed59e46..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-@import '_variables';
-@import '_mixins';
-
-input[type=checkbox] {
-  @include peertube-checkbox(1px);
-}
-
-input[type=submit] {
-  @include peertube-button;
-  @include orange-button;
-
-  display: block;
-  margin-top: 15px;
-}
-
-.peertube-select-container {
-  @include peertube-select-container(340px);
-
-  margin-bottom: 30px;
-}
\ No newline at end of file
diff --git a/client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.ts b/client/src/app/my-account/my-account-settings/my-account-details/my-account-details.component.ts
deleted file mode 100644 (file)
index 4c14565..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core'
-import { FormBuilder, FormGroup } from '@angular/forms'
-import { NotificationsService } from 'angular2-notifications'
-import { UserUpdateMe } from '../../../../../../shared'
-import { AuthService } from '../../../core'
-import { FormReactive, User, UserService } from '../../../shared'
-
-@Component({
-  selector: 'my-account-details',
-  templateUrl: './my-account-details.component.html',
-  styleUrls: [ './my-account-details.component.scss' ]
-})
-export class MyAccountDetailsComponent extends FormReactive implements OnInit {
-  @Input() user: User = null
-
-  form: FormGroup
-  formErrors = {}
-  validationMessages = {}
-
-  constructor (
-    private authService: AuthService,
-    private formBuilder: FormBuilder,
-    private notificationsService: NotificationsService,
-    private userService: UserService
-  ) {
-    super()
-  }
-
-  buildForm () {
-    this.form = this.formBuilder.group({
-      nsfwPolicy: [ this.user.nsfwPolicy ],
-      autoPlayVideo: [ this.user.autoPlayVideo ]
-    })
-
-    this.form.valueChanges.subscribe(data => this.onValueChanged(data))
-  }
-
-  ngOnInit () {
-    this.buildForm()
-  }
-
-  updateDetails () {
-    const nsfwPolicy = this.form.value['nsfwPolicy']
-    const autoPlayVideo = this.form.value['autoPlayVideo']
-    const details: UserUpdateMe = {
-      nsfwPolicy,
-      autoPlayVideo
-    }
-
-    this.userService.updateMyDetails(details).subscribe(
-      () => {
-        this.notificationsService.success('Success', 'Information updated.')
-
-        this.authService.refreshUserInformation()
-      },
-
-      err => this.notificationsService.error('Error', err.message)
-    )
-  }
-}
diff --git a/client/src/app/my-account/my-account-settings/my-account-profile/index.ts b/client/src/app/my-account/my-account-settings/my-account-profile/index.ts
new file mode 100644 (file)
index 0000000..3cc049f
--- /dev/null
@@ -0,0 +1 @@
+export * from './my-account-profile.component'
diff --git a/client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.html b/client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.html
new file mode 100644 (file)
index 0000000..306f3a1
--- /dev/null
@@ -0,0 +1,24 @@
+<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
+
+<form role="form" (ngSubmit)="updateMyProfile()" [formGroup]="form">
+
+  <label for="display-name">Display name</label>
+  <input
+    type="text" id="display-name"
+    formControlName="display-name" [ngClass]="{ 'input-error': formErrors['display-name'] }"
+  >
+  <div *ngIf="formErrors['display-name']" class="form-error">
+    {{ formErrors['display-name'] }}
+  </div>
+
+  <label for="description">Description</label>
+  <textarea
+    id="description" formControlName="description"
+    [ngClass]="{ 'input-error': formErrors['description'] }"
+  ></textarea>
+  <div *ngIf="formErrors.description" class="form-error">
+    {{ formErrors.description }}
+  </div>
+
+  <input type="submit" value="Update my profile" [disabled]="!form.valid">
+</form>
diff --git a/client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.scss b/client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.scss
new file mode 100644 (file)
index 0000000..fc2b92c
--- /dev/null
@@ -0,0 +1,23 @@
+@import '_variables';
+@import '_mixins';
+
+input[type=text] {
+  @include peertube-input-text(340px);
+
+  display: block;
+  margin-bottom: 15px;
+}
+
+textarea {
+  @include peertube-textarea(500px, 150px);
+
+  display: block;
+}
+
+input[type=submit] {
+  @include peertube-button;
+  @include orange-button;
+
+  margin-top: 15px;
+}
+
diff --git a/client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.ts b/client/src/app/my-account/my-account-settings/my-account-profile/my-account-profile.component.ts
new file mode 100644 (file)
index 0000000..2b7ba35
--- /dev/null
@@ -0,0 +1,65 @@
+import { Component, Input, OnInit } from '@angular/core'
+import { FormBuilder, FormGroup } from '@angular/forms'
+import { NotificationsService } from 'angular2-notifications'
+import { FormReactive, USER_DESCRIPTION, USER_DISPLAY_NAME, UserService } from '../../../shared'
+import { User } from '@app/shared'
+
+@Component({
+  selector: 'my-account-profile',
+  templateUrl: './my-account-profile.component.html',
+  styleUrls: [ './my-account-profile.component.scss' ]
+})
+export class MyAccountProfileComponent extends FormReactive implements OnInit {
+  @Input() user: User = null
+
+  error: string = null
+
+  form: FormGroup
+  formErrors = {
+    'display-name': '',
+    'description': ''
+  }
+  validationMessages = {
+    'display-name': USER_DISPLAY_NAME.MESSAGES,
+    'description': USER_DESCRIPTION.MESSAGES
+  }
+
+  constructor (
+    private formBuilder: FormBuilder,
+    private notificationsService: NotificationsService,
+    private userService: UserService
+  ) {
+    super()
+  }
+
+  buildForm () {
+    this.form = this.formBuilder.group({
+      'display-name': [ this.user.account.displayName, USER_DISPLAY_NAME.VALIDATORS ],
+      'description': [ this.user.account.description, USER_DESCRIPTION.VALIDATORS ]
+    })
+
+    this.form.valueChanges.subscribe(data => this.onValueChanged(data))
+  }
+
+  ngOnInit () {
+    this.buildForm()
+  }
+
+  updateMyProfile () {
+    const displayName = this.form.value['display-name']
+    const description = this.form.value['description']
+
+    this.error = null
+
+    this.userService.updateMyProfile({ displayName, description }).subscribe(
+      () => {
+        this.user.account.displayName = displayName
+        this.user.account.description = description
+
+        this.notificationsService.success('Success', 'Profile updated.')
+      },
+
+      err => this.error = err.message
+    )
+  }
+}
index e11d93c01d6aeacdd895634c0573036e81b12e2a..e655b9d96a235da8a0ac699829e6f0fe30764288 100644 (file)
   <span class="user-quota-label">Video quota:</span> {{ userVideoQuotaUsed | bytes: 0 }} / {{ userVideoQuota }}
 </div>
 
-<div class="account-title">Account settings</div>
+<ng-template [ngIf]="user && user.account">
+  <div class="account-title">Profile</div>
+  <my-account-profile [user]="user"></my-account-profile>
+</ng-template>
+
+<div class="account-title">Password</div>
 <my-account-change-password></my-account-change-password>
 
 <div class="account-title">Video settings</div>
-<my-account-details [user]="user"></my-account-details>
+<my-account-video-settings [user]="user"></my-account-video-settings>
diff --git a/client/src/app/my-account/my-account-settings/my-account-video-settings/index.ts b/client/src/app/my-account/my-account-settings/my-account-video-settings/index.ts
new file mode 100644 (file)
index 0000000..1253bd3
--- /dev/null
@@ -0,0 +1 @@
+export * from './my-account-video-settings.component'
diff --git a/client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html b/client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.html
new file mode 100644 (file)
index 0000000..0e8598e
--- /dev/null
@@ -0,0 +1,25 @@
+<form role="form" (ngSubmit)="updateDetails()" [formGroup]="form">
+  <div class="form-group">
+    <label for="nsfwPolicy">Default policy on videos containing sensitive content</label>
+    <my-help helpType="custom" customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."></my-help>
+
+    <div class="peertube-select-container">
+      <select id="nsfwPolicy" formControlName="nsfwPolicy">
+        <option value="do_not_list">Do not list</option>
+        <option value="blur">Blur thumbnails</option>
+        <option value="display">Display</option>
+      </select>
+    </div>
+  </div>
+
+  <div class="form-group">
+    <input
+      type="checkbox" id="autoPlayVideo"
+      formControlName="autoPlayVideo"
+    >
+    <label for="autoPlayVideo"></label>
+    <label for="autoPlayVideo">Automatically plays video</label>
+  </div>
+
+  <input type="submit" value="Save" [disabled]="!form.valid">
+</form>
diff --git a/client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.scss b/client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.scss
new file mode 100644 (file)
index 0000000..ed59e46
--- /dev/null
@@ -0,0 +1,20 @@
+@import '_variables';
+@import '_mixins';
+
+input[type=checkbox] {
+  @include peertube-checkbox(1px);
+}
+
+input[type=submit] {
+  @include peertube-button;
+  @include orange-button;
+
+  display: block;
+  margin-top: 15px;
+}
+
+.peertube-select-container {
+  @include peertube-select-container(340px);
+
+  margin-bottom: 30px;
+}
\ No newline at end of file
diff --git a/client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts b/client/src/app/my-account/my-account-settings/my-account-video-settings/my-account-video-settings.component.ts
new file mode 100644 (file)
index 0000000..acc70c1
--- /dev/null
@@ -0,0 +1,60 @@
+import { Component, Input, OnInit } from '@angular/core'
+import { FormBuilder, FormGroup } from '@angular/forms'
+import { NotificationsService } from 'angular2-notifications'
+import { UserUpdateMe } from '../../../../../../shared'
+import { AuthService } from '../../../core'
+import { FormReactive, User, UserService } from '../../../shared'
+
+@Component({
+  selector: 'my-account-video-settings',
+  templateUrl: './my-account-video-settings.component.html',
+  styleUrls: [ './my-account-video-settings.component.scss' ]
+})
+export class MyAccountVideoSettingsComponent extends FormReactive implements OnInit {
+  @Input() user: User = null
+
+  form: FormGroup
+  formErrors = {}
+  validationMessages = {}
+
+  constructor (
+    private authService: AuthService,
+    private formBuilder: FormBuilder,
+    private notificationsService: NotificationsService,
+    private userService: UserService
+  ) {
+    super()
+  }
+
+  buildForm () {
+    this.form = this.formBuilder.group({
+      nsfwPolicy: [ this.user.nsfwPolicy ],
+      autoPlayVideo: [ this.user.autoPlayVideo ]
+    })
+
+    this.form.valueChanges.subscribe(data => this.onValueChanged(data))
+  }
+
+  ngOnInit () {
+    this.buildForm()
+  }
+
+  updateDetails () {
+    const nsfwPolicy = this.form.value['nsfwPolicy']
+    const autoPlayVideo = this.form.value['autoPlayVideo']
+    const details: UserUpdateMe = {
+      nsfwPolicy,
+      autoPlayVideo
+    }
+
+    this.userService.updateMyProfile(details).subscribe(
+      () => {
+        this.notificationsService.success('Success', 'Information updated.')
+
+        this.authService.refreshUserInformation()
+      },
+
+      err => this.notificationsService.error('Error', err.message)
+    )
+  }
+}
index 637b2587ccb20bffda3561ce77a54d30b2e59da7..41afc1e5d2f3fc769da31f285bbe0a5e3d99f8f6 100644 (file)
@@ -1,6 +1,6 @@
 <div class="row">
   <div class="sub-menu">
-    <a routerLink="/my-account/settings" routerLinkActive="active" class="title-page">My account</a>
+    <a routerLink="/my-account/settings" routerLinkActive="active" class="title-page">My settings</a>
 
     <a routerLink="/my-account/videos" routerLinkActive="active" class="title-page">My videos</a>
   </div>
index 31727730491ffbfd8dda3fe52b1a2503cc98b114..981d3c6978a543362a080aeac9ea654137044b9c 100644 (file)
@@ -2,10 +2,11 @@ import { NgModule } from '@angular/core'
 import { SharedModule } from '../shared'
 import { MyAccountRoutingModule } from './my-account-routing.module'
 import { MyAccountChangePasswordComponent } from './my-account-settings/my-account-change-password/my-account-change-password.component'
-import { MyAccountDetailsComponent } from './my-account-settings/my-account-details/my-account-details.component'
+import { MyAccountVideoSettingsComponent } from './my-account-settings/my-account-video-settings/my-account-video-settings.component'
 import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component'
 import { MyAccountComponent } from './my-account.component'
 import { MyAccountVideosComponent } from './my-account-videos/my-account-videos.component'
+import { MyAccountProfileComponent } from '@app/my-account/my-account-settings/my-account-profile/my-account-profile.component'
 
 @NgModule({
   imports: [
@@ -17,7 +18,8 @@ import { MyAccountVideosComponent } from './my-account-videos/my-account-videos.
     MyAccountComponent,
     MyAccountSettingsComponent,
     MyAccountChangePasswordComponent,
-    MyAccountDetailsComponent,
+    MyAccountVideoSettingsComponent,
+    MyAccountProfileComponent,
     MyAccountVideosComponent
   ],
 
index d2a28a2721541fd02ffdefe76c9a233a7868bd7a..095b534c0052fdf20eea357236b8d745a575e5bb 100644 (file)
@@ -46,3 +46,27 @@ export const USER_ROLE = {
     'required': 'User role is required.'
   }
 }
+export const USER_DISPLAY_NAME = {
+  VALIDATORS: [
+    Validators.required,
+    Validators.minLength(3),
+    Validators.maxLength(120)
+  ],
+  MESSAGES: {
+    'required': 'Display name is required.',
+    'minlength': 'Display name must be at least 3 characters long.',
+    'maxlength': 'Display name cannot be more than 120 characters long.'
+  }
+}
+export const USER_DESCRIPTION = {
+  VALIDATORS: [
+    Validators.required,
+    Validators.minLength(3),
+    Validators.maxLength(250)
+  ],
+  MESSAGES: {
+    'required': 'Display name is required.',
+    'minlength': 'Display name must be at least 3 characters long.',
+    'maxlength': 'Display name cannot be more than 250 characters long.'
+  }
+}
index da7b583f4d833683417b0131958ae0a68a065e47..adb840ceca0ca755e8d78e17cdab5b5f149dec37 100644 (file)
@@ -26,10 +26,10 @@ export class UserService {
                         .catch(res => this.restExtractor.handleError(res))
   }
 
-  updateMyDetails (details: UserUpdateMe) {
+  updateMyProfile (profile: UserUpdateMe) {
     const url = UserService.BASE_USERS_URL + 'me'
 
-    return this.authHttp.put(url, details)
+    return this.authHttp.put(url, profile)
                         .map(this.restExtractor.extractDataBool)
                         .catch(res => this.restExtractor.handleError(res))
   }
index dcc4ef196b7444cef4f322deb7c8a8ef286e79f4..2342c23dd683b809ba9db028907033cb382ed04d 100644 (file)
@@ -303,6 +303,7 @@ async function updateMe (req: express.Request, res: express.Response, next: expr
   await sequelizeTypescript.transaction(async t => {
     await user.save({ transaction: t })
 
+    if (body.displayName !== undefined) user.Account.name = body.displayName
     if (body.description !== undefined) user.Account.description = body.description
     await user.Account.save({ transaction: t })
 
index c0acb8218b3bc9468a8313b7578ff0521b91d3b5..b59b766def6a037ca0a0272bd08769e8795dd880 100644 (file)
@@ -22,6 +22,10 @@ function isUserUsernameValid (value: string) {
   return exists(value) && validator.matches(value, new RegExp(`^[a-z0-9._]{${min},${max}}$`))
 }
 
+function isUserDisplayNameValid (value: string) {
+  return value === null || (exists(value) && validator.isLength(value, CONSTRAINTS_FIELDS.USERS.NAME))
+}
+
 function isUserDescriptionValid (value: string) {
   return value === null || (exists(value) && validator.isLength(value, CONSTRAINTS_FIELDS.USERS.DESCRIPTION))
 }
@@ -60,6 +64,7 @@ export {
   isUserUsernameValid,
   isUserNSFWPolicyValid,
   isUserAutoPlayVideoValid,
+  isUserDisplayNameValid,
   isUserDescriptionValid,
   isAvatarFile
 }
index 9c9c3afc0944651bb362670d5719ac5cbec50e9f..365b8617df6ec2607634e2b61da50406ece5c1a2 100644 (file)
@@ -180,9 +180,10 @@ const CONFIG = {
 
 const CONSTRAINTS_FIELDS = {
   USERS: {
+    NAME: { min: 3, max: 120 }, // Length
+    DESCRIPTION: { min: 3, max: 250 }, // Length
     USERNAME: { min: 3, max: 20 }, // Length
     PASSWORD: { min: 6, max: 255 }, // Length
-    DESCRIPTION: { min: 3, max: 250 }, // Length
     VIDEO_QUOTA: { min: -1 }
   },
   VIDEO_ABUSES: {
index 5dd8caa3f575467a7507d240e3620de7bf7cf163..247b704c4331d8ff27c397220ec41de20d90303f 100644 (file)
@@ -7,7 +7,7 @@ import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
 import {
   isAvatarFile,
   isUserAutoPlayVideoValid,
-  isUserDescriptionValid,
+  isUserDescriptionValid, isUserDisplayNameValid,
   isUserNSFWPolicyValid,
   isUserPasswordValid,
   isUserRoleValid,
@@ -98,6 +98,7 @@ const usersUpdateValidator = [
 ]
 
 const usersUpdateMeValidator = [
+  body('displayName').optional().custom(isUserDisplayNameValid).withMessage('Should have a valid display name'),
   body('description').optional().custom(isUserDescriptionValid).withMessage('Should have a valid description'),
   body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'),
   body('email').optional().isEmail().withMessage('Should have a valid email attribute'),
index a7f3aa8d35624e6cc062a640e8434a4f97985020..8b9b63348cc9d6f9662341d3469f51886d3a1c16 100644 (file)
@@ -76,6 +76,22 @@ describe('Test users with multiple servers', function () {
     await wait(5000)
   })
 
+  it('Should be able to update my display name', async function () {
+    this.timeout(10000)
+
+    await updateMyUser({
+      url: servers[0].url,
+      accessToken: servers[0].accessToken,
+      displayName: 'my super display name'
+    })
+
+    const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
+    user = res.body
+    expect(user.account.displayName).to.equal('my super display name')
+
+    await wait(5000)
+  })
+
   it('Should be able to update my description', async function () {
     this.timeout(10000)
 
@@ -87,6 +103,7 @@ describe('Test users with multiple servers', function () {
 
     const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
     user = res.body
+    expect(user.account.displayName).to.equal('my super display name')
     expect(user.account.description).to.equal('my super description updated')
 
     await wait(5000)
@@ -111,7 +128,7 @@ describe('Test users with multiple servers', function () {
     await wait(5000)
   })
 
-  it('Should have updated my avatar and my description on other servers too', async function () {
+  it('Should have updated my profile on other servers too', async function () {
     for (const server of servers) {
       const resAccounts = await getAccountsList(server.url, '-createdAt')
 
@@ -122,6 +139,7 @@ describe('Test users with multiple servers', function () {
       const rootServer1Get = resAccount.body as Account
       expect(rootServer1Get.name).to.equal('root')
       expect(rootServer1Get.host).to.equal('localhost:9001')
+      expect(rootServer1Get.displayName).to.equal('my super display name')
       expect(rootServer1Get.description).to.equal('my super description updated')
 
       await testImage(server.url, 'avatar2-resized', rootServer1Get.avatar.path, '.png')
index 1192ef9e4ad9fc5b248a718a6c0d307ec6ab8137..1ea599859313a7310a3f71e4b5fffb61db8f1ab1 100644 (file)
@@ -172,6 +172,7 @@ describe('Test users', function () {
     expect(user.videoQuota).to.equal(2 * 1024 * 1024)
     expect(user.roleLabel).to.equal('User')
     expect(user.id).to.be.a('number')
+    expect(user.account.displayName).to.equal('user_1')
     expect(user.account.description).to.be.null
   })
 
@@ -316,6 +317,7 @@ describe('Test users', function () {
     expect(user.nsfwPolicy).to.equal('do_not_list')
     expect(user.videoQuota).to.equal(2 * 1024 * 1024)
     expect(user.id).to.be.a('number')
+    expect(user.account.displayName).to.equal('user_1')
     expect(user.account.description).to.be.null
   })
 
@@ -347,6 +349,7 @@ describe('Test users', function () {
     expect(user.nsfwPolicy).to.equal('do_not_list')
     expect(user.videoQuota).to.equal(2 * 1024 * 1024)
     expect(user.id).to.be.a('number')
+    expect(user.account.displayName).to.equal('user_1')
     expect(user.account.description).to.be.null
   })
 
@@ -365,6 +368,25 @@ describe('Test users', function () {
     await testImage(server.url, 'avatar-resized', user.account.avatar.path, '.png')
   })
 
+  it('Should be able to update my display name', async function () {
+    await updateMyUser({
+      url: server.url,
+      accessToken: accessTokenUser,
+      displayName: 'new display name'
+    })
+
+    const res = await getMyUserInformation(server.url, accessTokenUser)
+    const user = res.body
+
+    expect(user.username).to.equal('user_1')
+    expect(user.email).to.equal('updated@example.com')
+    expect(user.nsfwPolicy).to.equal('do_not_list')
+    expect(user.videoQuota).to.equal(2 * 1024 * 1024)
+    expect(user.id).to.be.a('number')
+    expect(user.account.displayName).to.equal('new display name')
+    expect(user.account.description).to.be.null
+  })
+
   it('Should be able to update my description', async function () {
     await updateMyUser({
       url: server.url,
@@ -380,6 +402,7 @@ describe('Test users', function () {
     expect(user.nsfwPolicy).to.equal('do_not_list')
     expect(user.videoQuota).to.equal(2 * 1024 * 1024)
     expect(user.id).to.be.a('number')
+    expect(user.account.displayName).to.equal('new display name')
     expect(user.account.description).to.equal('my super description updated')
   })
 
index fc6b26c50af4462ba9688eb77857497a6db488d6..d31e57a25675e82e52e4e2eebd35e01b7d70d20a 100644 (file)
@@ -132,6 +132,7 @@ function updateMyUser (options: {
   nsfwPolicy?: NSFWPolicyType,
   email?: string,
   autoPlayVideo?: boolean
+  displayName?: string,
   description?: string
 }) {
   const path = '/api/v1/users/me'
@@ -142,6 +143,7 @@ function updateMyUser (options: {
   if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo
   if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
   if (options.description !== undefined && options.description !== null) toSend['description'] = options.description
+  if (options.displayName !== undefined && options.displayName !== null) toSend['displayName'] = options.displayName
 
   return makePutBodyRequest({
     url: options.url,
index 0a73879ed358180ca3e3bd0022d14c5b8d6362c6..ddab837fe8862f123e19e50f5a62d47acde0d6fb 100644 (file)
@@ -1,6 +1,7 @@
 import { NSFWPolicyType } from '../videos/nsfw-policy.type'
 
 export interface UserUpdateMe {
+  displayName?: string
   description?: string
   nsfwPolicy?: NSFWPolicyType
   autoPlayVideo?: boolean