ソースを参照

Allow accounts to skip account setup modal

Chocobozzz 2 年 前
コミット
8f58172565

+ 2 - 2
client/src/app/app.component.html

@@ -61,8 +61,8 @@
 </p-toast>
 
 <ng-container *ngIf="isUserLoggedIn()">
-  <my-account-setup-modal #accountSetupModal></my-account-setup-modal>
-  <my-welcome-modal #welcomeModal></my-welcome-modal>
+  <my-account-setup-warning-modal #accountSetupWarningModal></my-account-setup-warning-modal>
+  <my-admin-welcome-modal #adminWelcomeModal></my-admin-welcome-modal>
   <my-instance-config-warning-modal #instanceConfigWarningModal></my-instance-config-warning-modal>
 </ng-container>
 

+ 40 - 31
client/src/app/app.component.ts

@@ -1,5 +1,6 @@
 import { Hotkey, HotkeysService } from 'angular2-hotkeys'
-import { filter, map, switchMap } from 'rxjs/operators'
+import { forkJoin } from 'rxjs'
+import { filter, first, map } from 'rxjs/operators'
 import { DOCUMENT, getLocaleDirection, PlatformLocation } from '@angular/common'
 import { AfterViewInit, Component, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core'
 import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
@@ -17,15 +18,15 @@ import {
 } from '@app/core'
 import { HooksService } from '@app/core/plugins/hooks.service'
 import { PluginService } from '@app/core/plugins/plugin.service'
+import { AccountSetupWarningModalComponent } from '@app/modal/account-setup-warning-modal.component'
 import { CustomModalComponent } from '@app/modal/custom-modal.component'
 import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
-import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
-import { AccountSetupModalComponent } from '@app/modal/account-setup-modal.component'
+import { AdminWelcomeModalComponent } from '@app/modal/admin-welcome-modal.component'
 import { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap'
 import { LoadingBarService } from '@ngx-loading-bar/core'
 import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
 import { getShortLocale } from '@shared/core-utils/i18n'
-import { BroadcastMessageLevel, HTMLServerConfig, ServerConfig, UserRole } from '@shared/models'
+import { BroadcastMessageLevel, HTMLServerConfig, UserRole } from '@shared/models'
 import { MenuService } from './core/menu/menu.service'
 import { POP_STATE_MODAL_DISMISS } from './helpers'
 import { InstanceService } from './shared/shared-instance'
@@ -38,8 +39,8 @@ import { InstanceService } from './shared/shared-instance'
 export class AppComponent implements OnInit, AfterViewInit {
   private static BROADCAST_MESSAGE_KEY = 'app-broadcast-message-dismissed'
 
-  @ViewChild('accountSetupModal') accountSetupModal: AccountSetupModalComponent
-  @ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent
+  @ViewChild('accountSetupWarningModal') accountSetupWarningModal: AccountSetupWarningModalComponent
+  @ViewChild('adminWelcomeModal') adminWelcomeModal: AdminWelcomeModalComponent
   @ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent
   @ViewChild('customModal') customModal: CustomModalComponent
 
@@ -221,33 +222,41 @@ export class AppComponent implements OnInit, AfterViewInit {
   }
 
   private openModalsIfNeeded () {
-    this.authService.userInformationLoaded
-        .pipe(
-          map(() => this.authService.getUser()),
-          filter(user => user.role === UserRole.ADMINISTRATOR),
-          switchMap(user => {
-            return this.serverService.getConfig()
-              .pipe(map(serverConfig => ({ serverConfig, user })))
-          })
-        ).subscribe(({ serverConfig, user }) => this._openAdminModalsIfNeeded(serverConfig, user))
+    const userSub = this.authService.userInformationLoaded
+        .pipe(map(() => this.authService.getUser()))
+
+    // Admin modal
+    userSub.pipe(
+      filter(user => user.role === UserRole.ADMINISTRATOR)
+    ).subscribe(user => this.openAdminModalsIfNeeded(user))
+
+    // Account modal
+    userSub.pipe(
+      filter(user => user.role !== UserRole.ADMINISTRATOR)
+    ).subscribe(user => this.openAccountModalsIfNeeded(user))
   }
 
-  private _openAdminModalsIfNeeded (serverConfig: ServerConfig, user: User) {
-    if (user.noWelcomeModal !== true) return this.welcomeModal.show()
-
-    if (user.noInstanceConfigWarningModal === true || !serverConfig.signup.allowed) return
-
-    this.instanceService.getAbout()
-      .subscribe(about => {
-        if (
-          this.serverConfig.instance.name.toLowerCase() === 'peertube' ||
-          !about.instance.terms ||
-          !about.instance.administrator ||
-          !about.instance.maintenanceLifetime
-        ) {
-          this.instanceConfigWarningModal.show(about)
-        }
-      })
+  private openAdminModalsIfNeeded (user: User) {
+    if (this.adminWelcomeModal.shouldOpen(user)) {
+      return this.adminWelcomeModal.show()
+    }
+
+    if (!this.instanceConfigWarningModal.shouldOpenByUser(user)) return
+
+    forkJoin([
+      this.serverService.getConfig().pipe(first()),
+      this.instanceService.getAbout().pipe(first())
+    ]).subscribe(([ config, about ]) => {
+      if (this.instanceConfigWarningModal.shouldOpen(config, about)) {
+        this.instanceConfigWarningModal.show(about)
+      }
+    })
+  }
+
+  private openAccountModalsIfNeeded (user: User) {
+    if (this.accountSetupWarningModal.shouldOpen(user)) {
+      this.accountSetupWarningModal.show(user)
+    }
   }
 
   private initHotkeys () {

+ 4 - 4
client/src/app/app.module.ts

@@ -17,8 +17,8 @@ import { ConfirmComponent } from './modal/confirm.component'
 import { CustomModalComponent } from './modal/custom-modal.component'
 import { InstanceConfigWarningModalComponent } from './modal/instance-config-warning-modal.component'
 import { QuickSettingsModalComponent } from './modal/quick-settings-modal.component'
-import { WelcomeModalComponent } from './modal/welcome-modal.component'
-import { AccountSetupModalComponent } from './modal/account-setup-modal.component'
+import { AdminWelcomeModalComponent } from './modal/admin-welcome-modal.component'
+import { AccountSetupWarningModalComponent } from './modal/account-setup-warning-modal.component'
 import { SharedActorImageModule } from './shared/shared-actor-image/shared-actor-image.module'
 import { SharedFormModule } from './shared/shared-forms'
 import { SharedGlobalIconModule } from './shared/shared-icons'
@@ -54,9 +54,9 @@ export function loadConfigFactory (server: ServerService, pluginService: PluginS
     SuggestionComponent,
     HighlightPipe,
 
-    AccountSetupModalComponent,
+    AccountSetupWarningModalComponent,
     CustomModalComponent,
-    WelcomeModalComponent,
+    AdminWelcomeModalComponent,
     InstanceConfigWarningModalComponent,
     ConfirmComponent
   ],

+ 2 - 0
client/src/app/core/users/user.model.ts

@@ -55,6 +55,7 @@ export class User implements UserServerModel {
 
   noInstanceConfigWarningModal: boolean
   noWelcomeModal: boolean
+  noAccountSetupWarningModal: boolean
 
   pluginAuth: string | null
 
@@ -98,6 +99,7 @@ export class User implements UserServerModel {
 
     this.noInstanceConfigWarningModal = hash.noInstanceConfigWarningModal
     this.noWelcomeModal = hash.noWelcomeModal
+    this.noAccountSetupWarningModal = hash.noAccountSetupWarningModal
 
     this.notificationSettings = hash.notificationSettings
 

+ 0 - 73
client/src/app/modal/account-setup-modal.component.ts

@@ -1,73 +0,0 @@
-import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
-import { AuthService, ServerService, User, UserService } from '@app/core'
-import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
-import { HTMLServerConfig } from '@shared/models'
-
-@Component({
-  selector: 'my-account-setup-modal',
-  templateUrl: './account-setup-modal.component.html',
-  styleUrls: [ './account-setup-modal.component.scss' ]
-})
-export class AccountSetupModalComponent implements OnInit {
-  @ViewChild('modal', { static: true }) modal: ElementRef
-
-  user: User = null
-  ref: NgbModalRef = null
-
-  private serverConfig: HTMLServerConfig
-
-  constructor (
-    private userService: UserService,
-    private authService: AuthService,
-    private modalService: NgbModal,
-    private serverService: ServerService
-  ) { }
-
-  get userInformationLoaded () {
-    return this.authService.userInformationLoaded
-  }
-
-  get instanceName () {
-    return this.serverConfig.instance.name
-  }
-
-  get isUserRoot () {
-    return this.user.username === 'root'
-  }
-
-  get hasAccountAvatar () {
-    return !!this.user.account.avatar
-  }
-
-  get hasAccountDescription () {
-    return !!this.user.account.description
-  }
-
-  ngOnInit () {
-    this.serverConfig = this.serverService.getHTMLConfig()
-
-    this.authService.userInformationLoaded
-      .subscribe(
-        () => {
-          this.user = this.authService.getUser()
-
-          if (this.isUserRoot) return
-          if (this.hasAccountAvatar && this.hasAccountDescription) return
-          if (this.userService.hasSignupInThisSession()) return
-
-          this.show()
-        }
-      )
-  }
-
-  show () {
-    if (this.ref) return
-
-    this.ref = this.modalService.open(this.modal, {
-      centered: true,
-      backdrop: 'static',
-      keyboard: false,
-      size: 'md'
-    })
-  }
-}

+ 8 - 2
client/src/app/modal/account-setup-modal.component.html → client/src/app/modal/account-setup-warning-modal.component.html

@@ -12,12 +12,18 @@
     <p i18n>Help moderators and other users to know <strong>who you are</strong> by:</p>
 
     <ul>
-      <li *ngIf="!hasAccountAvatar" i18n>Uploading an <strong>avatar</strong></li>
-      <li *ngIf="!hasAccountDescription" i18n>Writing a <strong>description</strong></li>
+      <li *ngIf="!hasAccountAvatar(user)" i18n>Uploading an <strong>avatar</strong></li>
+      <li *ngIf="!hasAccountDescription(user)" i18n>Writing a <strong>description</strong></li>
     </ul>
   </div>
 
   <div class="modal-footer inputs">
+    <my-peertube-checkbox
+      inputName="stopDisplayModal" [(ngModel)]="stopDisplayModal"
+      i18n-labelText labelText="Don't show me this anymore"
+    >
+    </my-peertube-checkbox>
+
     <input
       type="button" role="button" i18n-value value="Remind me later" class="peertube-button grey-button"
       (click)="hide()" (key.enter)="hide()"

+ 0 - 0
client/src/app/modal/account-setup-modal.component.scss → client/src/app/modal/account-setup-warning-modal.component.scss


+ 79 - 0
client/src/app/modal/account-setup-warning-modal.component.ts

@@ -0,0 +1,79 @@
+import { Component, ElementRef, ViewChild } from '@angular/core'
+import { Notifier, ServerService, User, UserService } from '@app/core'
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
+import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
+
+@Component({
+  selector: 'my-account-setup-warning-modal',
+  templateUrl: './account-setup-warning-modal.component.html',
+  styleUrls: [ './account-setup-warning-modal.component.scss' ]
+})
+export class AccountSetupWarningModalComponent {
+  @ViewChild('modal', { static: true }) modal: ElementRef
+
+  stopDisplayModal = false
+  ref: NgbModalRef
+
+  user: User
+
+  private LOCAL_STORAGE_KEYS = {
+    NO_ACCOUNT_SETUP_WARNING_MODAL: 'no_account_setup_warning_modal'
+  }
+
+  constructor (
+    private userService: UserService,
+    private modalService: NgbModal,
+    private notifier: Notifier,
+    private serverService: ServerService
+  ) { }
+
+  get instanceName () {
+    return this.serverService.getHTMLConfig().instance.name
+  }
+
+  hasAccountAvatar (user: User) {
+    return !!user.account.avatar
+  }
+
+  hasAccountDescription (user: User) {
+    return !!user.account.description
+  }
+
+  shouldOpen (user: User) {
+    if (user.noAccountSetupWarningModal === true) return false
+    if (peertubeLocalStorage.getItem(this.LOCAL_STORAGE_KEYS.NO_ACCOUNT_SETUP_WARNING_MODAL) === 'true') return false
+
+    if (this.hasAccountAvatar(user) && this.hasAccountDescription(user)) return false
+    if (this.userService.hasSignupInThisSession()) return false
+
+    return true
+  }
+
+  show (user: User) {
+    this.user = user
+
+    if (this.ref) return
+
+    this.ref = this.modalService.open(this.modal, {
+      centered: true,
+      backdrop: 'static',
+      keyboard: false,
+      size: 'md'
+    })
+
+    this.ref.result.finally(() => {
+      if (this.stopDisplayModal === true) this.doNotOpenAgain()
+    })
+  }
+
+  private doNotOpenAgain () {
+    peertubeLocalStorage.setItem(this.LOCAL_STORAGE_KEYS.NO_ACCOUNT_SETUP_WARNING_MODAL, 'true')
+
+    this.userService.updateMyProfile({ noAccountSetupWarningModal: true })
+        .subscribe({
+          next: () => console.log('We will not open the account setup modal again.'),
+
+          error: err => this.notifier.error(err.message)
+        })
+  }
+}

+ 0 - 0
client/src/app/modal/welcome-modal.component.html → client/src/app/modal/admin-welcome-modal.component.html


+ 0 - 0
client/src/app/modal/welcome-modal.component.scss → client/src/app/modal/admin-welcome-modal.component.scss


+ 12 - 8
client/src/app/modal/welcome-modal.component.ts → client/src/app/modal/admin-welcome-modal.component.ts

@@ -1,14 +1,14 @@
 import { Component, ElementRef, ViewChild } from '@angular/core'
-import { Notifier, UserService } from '@app/core'
+import { Notifier, User, UserService } from '@app/core'
 import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
 import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
 
 @Component({
-  selector: 'my-welcome-modal',
-  templateUrl: './welcome-modal.component.html',
-  styleUrls: [ './welcome-modal.component.scss' ]
+  selector: 'my-admin-welcome-modal',
+  templateUrl: './admin-welcome-modal.component.html',
+  styleUrls: [ './admin-welcome-modal.component.scss' ]
 })
-export class WelcomeModalComponent {
+export class AdminWelcomeModalComponent {
   @ViewChild('modal', { static: true }) modal: ElementRef
 
   private LOCAL_STORAGE_KEYS = {
@@ -21,10 +21,14 @@ export class WelcomeModalComponent {
     private notifier: Notifier
   ) { }
 
-  show () {
-    const result = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_KEYS.NO_WELCOME_MODAL)
-    if (result === 'true') return
+  shouldOpen (user: User) {
+    if (user.noWelcomeModal === true) return false
+    if (peertubeLocalStorage.getItem(this.LOCAL_STORAGE_KEYS.NO_WELCOME_MODAL) === 'true') return false
+
+    return true
+  }
 
+  show () {
     this.modalService.open(this.modal, {
       centered: true,
       backdrop: 'static',

+ 18 - 5
client/src/app/modal/instance-config-warning-modal.component.ts

@@ -1,9 +1,9 @@
 import { Location } from '@angular/common'
 import { Component, ElementRef, ViewChild } from '@angular/core'
-import { Notifier, UserService } from '@app/core'
+import { Notifier, User, UserService } from '@app/core'
 import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
 import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
-import { About } from '@shared/models/server'
+import { About, ServerConfig } from '@shared/models/server'
 
 @Component({
   selector: 'my-instance-config-warning-modal',
@@ -27,10 +27,23 @@ export class InstanceConfigWarningModalComponent {
     private notifier: Notifier
   ) { }
 
-  show (about: About) {
-    const result = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_KEYS.NO_INSTANCE_CONFIG_WARNING_MODAL)
-    if (result === 'true') return
+  shouldOpenByUser (user: User) {
+    if (user.noInstanceConfigWarningModal === true) return false
+    if (peertubeLocalStorage.getItem(this.LOCAL_STORAGE_KEYS.NO_INSTANCE_CONFIG_WARNING_MODAL) === 'true') return false
+
+    return true
+  }
+
+  shouldOpen (serverConfig: ServerConfig, about: About) {
+    if (!serverConfig.signup.allowed) return false
 
+    return serverConfig.instance.name.toLowerCase() === 'peertube' ||
+      !about.instance.terms ||
+      !about.instance.administrator ||
+      !about.instance.maintenanceLifetime
+  }
+
+  show (about: About) {
     if (this.location.path().startsWith('/admin/config/edit-custom')) return
 
     this.about = about

+ 1 - 0
server/controllers/api/users/me.ts

@@ -203,6 +203,7 @@ async function updateMe (req: express.Request, res: express.Response) {
     'videoLanguages',
     'theme',
     'noInstanceConfigWarningModal',
+    'noAccountSetupWarningModal',
     'noWelcomeModal'
   ]
 

+ 2 - 7
server/helpers/custom-validators/users.ts

@@ -81,11 +81,7 @@ function isUserAutoPlayNextVideoPlaylistValid (value: any) {
   return isBooleanValid(value)
 }
 
-function isNoInstanceConfigWarningModal (value: any) {
-  return isBooleanValid(value)
-}
-
-function isNoWelcomeModal (value: any) {
+function isUserNoModal (value: any) {
   return isBooleanValid(value)
 }
 
@@ -119,6 +115,5 @@ export {
   isUserAutoPlayNextVideoPlaylistValid,
   isUserDisplayNameValid,
   isUserDescriptionValid,
-  isNoInstanceConfigWarningModal,
-  isNoWelcomeModal
+  isUserNoModal
 }

+ 1 - 1
server/initializers/constants.ts

@@ -24,7 +24,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
 
 // ---------------------------------------------------------------------------
 
-const LAST_MIGRATION_VERSION = 660
+const LAST_MIGRATION_VERSION = 665
 
 // ---------------------------------------------------------------------------
 

+ 27 - 0
server/initializers/migrations/0665-no-account-warning-modal.ts

@@ -0,0 +1,27 @@
+import * as Sequelize from 'sequelize'
+
+async function up (utils: {
+  transaction: Sequelize.Transaction
+  queryInterface: Sequelize.QueryInterface
+  sequelize: Sequelize.Sequelize
+  db: any
+}): Promise<void> {
+  {
+    const data = {
+      type: Sequelize.BOOLEAN,
+      allowNull: false,
+      defaultValue: false
+    }
+
+    await utils.queryInterface.addColumn('user', 'noAccountSetupWarningModal', data)
+  }
+}
+
+function down (options) {
+  throw new Error('Not implemented.')
+}
+
+export {
+  up,
+  down
+}

+ 8 - 4
server/middlewares/validators/users.ts

@@ -9,14 +9,13 @@ import { UserRegister } from '../../../shared/models/users/user-register.model'
 import { toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
 import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
 import {
-  isNoInstanceConfigWarningModal,
-  isNoWelcomeModal,
   isUserAdminFlagsValid,
   isUserAutoPlayNextVideoValid,
   isUserAutoPlayVideoValid,
   isUserBlockedReasonValid,
   isUserDescriptionValid,
   isUserDisplayNameValid,
+  isUserNoModal,
   isUserNSFWPolicyValid,
   isUserPasswordValid,
   isUserPasswordValidOrEmpty,
@@ -251,12 +250,17 @@ const usersUpdateMeValidator = [
   body('theme')
     .optional()
     .custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'),
+
   body('noInstanceConfigWarningModal')
     .optional()
-    .custom(v => isNoInstanceConfigWarningModal(v)).withMessage('Should have a valid noInstanceConfigWarningModal boolean'),
+    .custom(v => isUserNoModal(v)).withMessage('Should have a valid noInstanceConfigWarningModal boolean'),
   body('noWelcomeModal')
     .optional()
-    .custom(v => isNoWelcomeModal(v)).withMessage('Should have a valid noWelcomeModal boolean'),
+    .custom(v => isUserNoModal(v)).withMessage('Should have a valid noWelcomeModal boolean'),
+  body('noAccountSetupWarningModal')
+    .optional()
+    .custom(v => isUserNoModal(v)).withMessage('Should have a valid noAccountSetupWarningModal boolean'),
+
   body('autoPlayNextVideo')
     .optional()
     .custom(v => isUserAutoPlayNextVideoValid(v)).withMessage('Should have a valid autoPlayNextVideo boolean'),

+ 14 - 5
server/models/user/user.ts

@@ -39,8 +39,6 @@ import { UserAdminFlag } from '../../../shared/models/users/user-flag.model'
 import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type'
 import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
 import {
-  isNoInstanceConfigWarningModal,
-  isNoWelcomeModal,
   isUserAdminFlagsValid,
   isUserAutoPlayNextVideoPlaylistValid,
   isUserAutoPlayNextVideoValid,
@@ -48,6 +46,7 @@ import {
   isUserBlockedReasonValid,
   isUserBlockedValid,
   isUserEmailVerifiedValid,
+  isUserNoModal,
   isUserNSFWPolicyValid,
   isUserPasswordValid,
   isUserRoleValid,
@@ -349,7 +348,7 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> {
   @Default(false)
   @Is(
     'UserNoInstanceConfigWarningModal',
-    value => throwIfNotValid(value, isNoInstanceConfigWarningModal, 'no instance config warning modal')
+    value => throwIfNotValid(value, isUserNoModal, 'no instance config warning modal')
   )
   @Column
   noInstanceConfigWarningModal: boolean
@@ -357,12 +356,21 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> {
   @AllowNull(false)
   @Default(false)
   @Is(
-    'UserNoInstanceConfigWarningModal',
-    value => throwIfNotValid(value, isNoWelcomeModal, 'no welcome modal')
+    'UserNoWelcomeModal',
+    value => throwIfNotValid(value, isUserNoModal, 'no welcome modal')
   )
   @Column
   noWelcomeModal: boolean
 
+  @AllowNull(false)
+  @Default(false)
+  @Is(
+    'UserNoAccountSetupWarningModal',
+    value => throwIfNotValid(value, isUserNoModal, 'no account setup warning modal')
+  )
+  @Column
+  noAccountSetupWarningModal: boolean
+
   @AllowNull(true)
   @Default(null)
   @Column
@@ -920,6 +928,7 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> {
 
       noInstanceConfigWarningModal: this.noInstanceConfigWarningModal,
       noWelcomeModal: this.noWelcomeModal,
+      noAccountSetupWarningModal: this.noAccountSetupWarningModal,
 
       blocked: this.blocked,
       blockedReason: this.blockedReason,

+ 14 - 13
server/tests/api/check-params/users.ts

@@ -491,20 +491,20 @@ describe('Test users API validators', function () {
       await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
     })
 
-    it('Should fail with an invalid noInstanceConfigWarningModal attribute', async function () {
-      const fields = {
-        noInstanceConfigWarningModal: -1
-      }
-
-      await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
-    })
+    it('Should fail with invalid no modal attributes', async function () {
+      const keys = [
+        'noInstanceConfigWarningModal',
+        'noAccountSetupWarningModal',
+        'noWelcomeModal'
+      ]
+
+      for (const key of keys) {
+        const fields = {
+          [key]: -1
+        }
 
-    it('Should fail with an invalid noWelcomeModal attribute', async function () {
-      const fields = {
-        noWelcomeModal: -1
+        await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
       }
-
-      await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
     })
 
     it('Should succeed to change password with the correct params', async function () {
@@ -516,7 +516,8 @@ describe('Test users API validators', function () {
         email: 'super_email@example.com',
         theme: 'default',
         noInstanceConfigWarningModal: true,
-        noWelcomeModal: true
+        noWelcomeModal: true,
+        noAccountSetupWarningModal: true
       }
 
       await makePutBodyRequest({

+ 4 - 1
server/tests/api/users/users.ts

@@ -597,6 +597,7 @@ describe('Test users', function () {
       expect(user.account.description).to.equal('my super description updated')
       expect(user.noWelcomeModal).to.be.false
       expect(user.noInstanceConfigWarningModal).to.be.false
+      expect(user.noAccountSetupWarningModal).to.be.false
     })
 
     it('Should be able to update my theme', async function () {
@@ -612,12 +613,14 @@ describe('Test users', function () {
       await server.users.updateMe({
         token: userToken,
         noInstanceConfigWarningModal: true,
-        noWelcomeModal: true
+        noWelcomeModal: true,
+        noAccountSetupWarningModal: true
       })
 
       const user = await server.users.getMyInfo({ token: userToken })
       expect(user.noWelcomeModal).to.be.true
       expect(user.noInstanceConfigWarningModal).to.be.true
+      expect(user.noAccountSetupWarningModal).to.be.true
     })
   })
 

+ 1 - 0
shared/models/users/user-update-me.model.ts

@@ -20,4 +20,5 @@ export interface UserUpdateMe {
 
   noInstanceConfigWarningModal?: boolean
   noWelcomeModal?: boolean
+  noAccountSetupWarningModal?: boolean
 }

+ 1 - 0
shared/models/users/user.model.ts

@@ -51,6 +51,7 @@ export interface User {
 
   noInstanceConfigWarningModal: boolean
   noWelcomeModal: boolean
+  noAccountSetupWarningModal: boolean
 
   createdAt: Date
 

+ 4 - 0
support/doc/api/openapi.yaml

@@ -6376,6 +6376,8 @@ components:
           format: date-time
         noInstanceConfigWarningModal:
           type: boolean
+        noAccountSetupWarningModal:
+          type: boolean
         noWelcomeModal:
           type: boolean
         nsfwPolicy:
@@ -6530,6 +6532,8 @@ components:
           type: string
         noInstanceConfigWarningModal:
           type: boolean
+        noAccountSetupWarningModal:
+          type: boolean
         noWelcomeModal:
           type: boolean
     GetMeVideoRating: