From 8f581725651c4b2c213d75fc028e306bbf239d3e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 27 Aug 2021 10:15:55 +0200 Subject: Allow accounts to skip account setup modal --- client/src/app/app.component.html | 4 +- client/src/app/app.component.ts | 71 ++++++++++-------- client/src/app/app.module.ts | 8 +- client/src/app/core/users/user.model.ts | 2 + .../app/modal/account-setup-modal.component.html | 33 --------- .../app/modal/account-setup-modal.component.scss | 32 -------- .../src/app/modal/account-setup-modal.component.ts | 73 ------------------- .../account-setup-warning-modal.component.html | 39 ++++++++++ .../account-setup-warning-modal.component.scss | 32 ++++++++ .../modal/account-setup-warning-modal.component.ts | 79 ++++++++++++++++++++ .../app/modal/admin-welcome-modal.component.html | 85 ++++++++++++++++++++++ .../app/modal/admin-welcome-modal.component.scss | 77 ++++++++++++++++++++ .../src/app/modal/admin-welcome-modal.component.ts | 50 +++++++++++++ .../instance-config-warning-modal.component.ts | 23 ++++-- client/src/app/modal/welcome-modal.component.html | 85 ---------------------- client/src/app/modal/welcome-modal.component.scss | 77 -------------------- client/src/app/modal/welcome-modal.component.ts | 46 ------------ server/controllers/api/users/me.ts | 1 + server/helpers/custom-validators/users.ts | 9 +-- server/initializers/constants.ts | 2 +- .../migrations/0665-no-account-warning-modal.ts | 27 +++++++ server/middlewares/validators/users.ts | 12 ++- server/models/user/user.ts | 19 +++-- server/tests/api/check-params/users.ts | 27 +++---- server/tests/api/users/users.ts | 5 +- shared/models/users/user-update-me.model.ts | 1 + shared/models/users/user.model.ts | 1 + support/doc/api/openapi.yaml | 4 + 28 files changed, 505 insertions(+), 419 deletions(-) delete mode 100644 client/src/app/modal/account-setup-modal.component.html delete mode 100644 client/src/app/modal/account-setup-modal.component.scss delete mode 100644 client/src/app/modal/account-setup-modal.component.ts create mode 100644 client/src/app/modal/account-setup-warning-modal.component.html create mode 100644 client/src/app/modal/account-setup-warning-modal.component.scss create mode 100644 client/src/app/modal/account-setup-warning-modal.component.ts create mode 100644 client/src/app/modal/admin-welcome-modal.component.html create mode 100644 client/src/app/modal/admin-welcome-modal.component.scss create mode 100644 client/src/app/modal/admin-welcome-modal.component.ts delete mode 100644 client/src/app/modal/welcome-modal.component.html delete mode 100644 client/src/app/modal/welcome-modal.component.scss delete mode 100644 client/src/app/modal/welcome-modal.component.ts create mode 100644 server/initializers/migrations/0665-no-account-warning-modal.ts diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index da66e4ef0..6969329e8 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -61,8 +61,8 @@ - - + + diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index ae6046cc1..86b687173 100644 --- a/client/src/app/app.component.ts +++ b/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 () { diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 8d9c39ad8..bb20c2d83 100644 --- a/client/src/app/app.module.ts +++ b/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 ], diff --git a/client/src/app/core/users/user.model.ts b/client/src/app/core/users/user.model.ts index 7467519c4..00078af5d 100644 --- a/client/src/app/core/users/user.model.ts +++ b/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 diff --git a/client/src/app/modal/account-setup-modal.component.html b/client/src/app/modal/account-setup-modal.component.html deleted file mode 100644 index d1f153835..000000000 --- a/client/src/app/modal/account-setup-modal.component.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - diff --git a/client/src/app/modal/account-setup-modal.component.scss b/client/src/app/modal/account-setup-modal.component.scss deleted file mode 100644 index d99edaf7a..000000000 --- a/client/src/app/modal/account-setup-modal.component.scss +++ /dev/null @@ -1,32 +0,0 @@ -@use '_mixins' as *; -@use '_variables' as *; - -.modal-body { - font-size: 15px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.mascot-fw { - width: 170px; -} - -.mascot { - @include margin-right(2rem); - - display: block; - width: 170px; - height: 220px; -} - -.subtitle { - font-weight: $font-semibold; - margin-bottom: 10px; - font-size: 16px; -} - -li { - margin-bottom: 10px; -} diff --git a/client/src/app/modal/account-setup-modal.component.ts b/client/src/app/modal/account-setup-modal.component.ts deleted file mode 100644 index 4cb8de2c7..000000000 --- a/client/src/app/modal/account-setup-modal.component.ts +++ /dev/null @@ -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' - }) - } -} diff --git a/client/src/app/modal/account-setup-warning-modal.component.html b/client/src/app/modal/account-setup-warning-modal.component.html new file mode 100644 index 000000000..614c0693d --- /dev/null +++ b/client/src/app/modal/account-setup-warning-modal.component.html @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/client/src/app/modal/account-setup-warning-modal.component.scss b/client/src/app/modal/account-setup-warning-modal.component.scss new file mode 100644 index 000000000..d99edaf7a --- /dev/null +++ b/client/src/app/modal/account-setup-warning-modal.component.scss @@ -0,0 +1,32 @@ +@use '_mixins' as *; +@use '_variables' as *; + +.modal-body { + font-size: 15px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.mascot-fw { + width: 170px; +} + +.mascot { + @include margin-right(2rem); + + display: block; + width: 170px; + height: 220px; +} + +.subtitle { + font-weight: $font-semibold; + margin-bottom: 10px; + font-size: 16px; +} + +li { + margin-bottom: 10px; +} diff --git a/client/src/app/modal/account-setup-warning-modal.component.ts b/client/src/app/modal/account-setup-warning-modal.component.ts new file mode 100644 index 000000000..c78de447d --- /dev/null +++ b/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) + }) + } +} diff --git a/client/src/app/modal/admin-welcome-modal.component.html b/client/src/app/modal/admin-welcome-modal.component.html new file mode 100644 index 000000000..f5d2b8799 --- /dev/null +++ b/client/src/app/modal/admin-welcome-modal.component.html @@ -0,0 +1,85 @@ + + + + + + + + diff --git a/client/src/app/modal/admin-welcome-modal.component.scss b/client/src/app/modal/admin-welcome-modal.component.scss new file mode 100644 index 000000000..242a498d0 --- /dev/null +++ b/client/src/app/modal/admin-welcome-modal.component.scss @@ -0,0 +1,77 @@ +@use '_mixins' as *; +@use '_variables' as *; + +.modal-body { + font-size: 15px; +} + +.two-columns { + display: flex; + align-items: center; + justify-content: center; + margin-top: 50px; +} + +.mascot-fw { + width: 170px; +} + +.mascot { + @include margin-right(2rem); + + display: block; + min-width: 170px; +} + +.subtitle { + font-weight: $font-semibold; + margin-bottom: 10px; + font-size: 16px; +} + +.block-documentation { + .subtitle { + margin-bottom: 20px; + } +} + +li { + margin-bottom: 10px; +} + +.configure-instance { + text-align: center; + font-weight: 600; + font-size: 18px; + margin: 20px 0 40px; +} + +.columns { + display: flex; +} + +.link-block { + @include disable-default-a-behaviour; + + color: pvar(--mainForegroundColor); + padding: 10px; + transition: background-color 0.2s ease-in; + flex-basis: 33%; + + &:hover { + background-color: rgba(0, 0, 0, 0.05); + } + + .link-title { + font-size: 16px; + font-weight: $font-semibold; + display: flex; + justify-content: center; + margin-bottom: 5px; + } + + .link-title, + div { + text-align: center; + } +} diff --git a/client/src/app/modal/admin-welcome-modal.component.ts b/client/src/app/modal/admin-welcome-modal.component.ts new file mode 100644 index 000000000..3679f0847 --- /dev/null +++ b/client/src/app/modal/admin-welcome-modal.component.ts @@ -0,0 +1,50 @@ +import { Component, ElementRef, ViewChild } from '@angular/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-admin-welcome-modal', + templateUrl: './admin-welcome-modal.component.html', + styleUrls: [ './admin-welcome-modal.component.scss' ] +}) +export class AdminWelcomeModalComponent { + @ViewChild('modal', { static: true }) modal: ElementRef + + private LOCAL_STORAGE_KEYS = { + NO_WELCOME_MODAL: 'no_welcome_modal' + } + + constructor ( + private userService: UserService, + private modalService: NgbModal, + private notifier: Notifier + ) { } + + 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', + keyboard: false, + size: 'lg' + }) + } + + doNotOpenAgain () { + peertubeLocalStorage.setItem(this.LOCAL_STORAGE_KEYS.NO_WELCOME_MODAL, 'true') + + this.userService.updateMyProfile({ noWelcomeModal: true }) + .subscribe({ + next: () => console.log('We will not open the welcome modal again.'), + + error: err => this.notifier.error(err.message) + }) + } +} diff --git a/client/src/app/modal/instance-config-warning-modal.component.ts b/client/src/app/modal/instance-config-warning-modal.component.ts index e40958976..300738a41 100644 --- a/client/src/app/modal/instance-config-warning-modal.component.ts +++ b/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 diff --git a/client/src/app/modal/welcome-modal.component.html b/client/src/app/modal/welcome-modal.component.html deleted file mode 100644 index f5d2b8799..000000000 --- a/client/src/app/modal/welcome-modal.component.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - diff --git a/client/src/app/modal/welcome-modal.component.scss b/client/src/app/modal/welcome-modal.component.scss deleted file mode 100644 index 242a498d0..000000000 --- a/client/src/app/modal/welcome-modal.component.scss +++ /dev/null @@ -1,77 +0,0 @@ -@use '_mixins' as *; -@use '_variables' as *; - -.modal-body { - font-size: 15px; -} - -.two-columns { - display: flex; - align-items: center; - justify-content: center; - margin-top: 50px; -} - -.mascot-fw { - width: 170px; -} - -.mascot { - @include margin-right(2rem); - - display: block; - min-width: 170px; -} - -.subtitle { - font-weight: $font-semibold; - margin-bottom: 10px; - font-size: 16px; -} - -.block-documentation { - .subtitle { - margin-bottom: 20px; - } -} - -li { - margin-bottom: 10px; -} - -.configure-instance { - text-align: center; - font-weight: 600; - font-size: 18px; - margin: 20px 0 40px; -} - -.columns { - display: flex; -} - -.link-block { - @include disable-default-a-behaviour; - - color: pvar(--mainForegroundColor); - padding: 10px; - transition: background-color 0.2s ease-in; - flex-basis: 33%; - - &:hover { - background-color: rgba(0, 0, 0, 0.05); - } - - .link-title { - font-size: 16px; - font-weight: $font-semibold; - display: flex; - justify-content: center; - margin-bottom: 5px; - } - - .link-title, - div { - text-align: center; - } -} diff --git a/client/src/app/modal/welcome-modal.component.ts b/client/src/app/modal/welcome-modal.component.ts deleted file mode 100644 index 06fe4cba5..000000000 --- a/client/src/app/modal/welcome-modal.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Component, ElementRef, ViewChild } from '@angular/core' -import { Notifier, 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' ] -}) -export class WelcomeModalComponent { - @ViewChild('modal', { static: true }) modal: ElementRef - - private LOCAL_STORAGE_KEYS = { - NO_WELCOME_MODAL: 'no_welcome_modal' - } - - constructor ( - private userService: UserService, - private modalService: NgbModal, - private notifier: Notifier - ) { } - - show () { - const result = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_KEYS.NO_WELCOME_MODAL) - if (result === 'true') return - - this.modalService.open(this.modal, { - centered: true, - backdrop: 'static', - keyboard: false, - size: 'lg' - }) - } - - doNotOpenAgain () { - peertubeLocalStorage.setItem(this.LOCAL_STORAGE_KEYS.NO_WELCOME_MODAL, 'true') - - this.userService.updateMyProfile({ noWelcomeModal: true }) - .subscribe({ - next: () => console.log('We will not open the welcome modal again.'), - - error: err => this.notifier.error(err.message) - }) - } -} diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index ac6faca9c..a98d79218 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts @@ -203,6 +203,7 @@ async function updateMe (req: express.Request, res: express.Response) { 'videoLanguages', 'theme', 'noInstanceConfigWarningModal', + 'noAccountSetupWarningModal', 'noWelcomeModal' ] diff --git a/server/helpers/custom-validators/users.ts b/server/helpers/custom-validators/users.ts index 5b21c3529..f52c60b60 100644 --- a/server/helpers/custom-validators/users.ts +++ b/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 } diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 8a1526ae8..2d8087f46 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -24,7 +24,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' // --------------------------------------------------------------------------- -const LAST_MIGRATION_VERSION = 660 +const LAST_MIGRATION_VERSION = 665 // --------------------------------------------------------------------------- diff --git a/server/initializers/migrations/0665-no-account-warning-modal.ts b/server/initializers/migrations/0665-no-account-warning-modal.ts new file mode 100644 index 000000000..6718aed85 --- /dev/null +++ b/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 { + { + 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 +} diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index bc8607523..c6977fcd9 100644 --- a/server/middlewares/validators/users.ts +++ b/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'), diff --git a/server/models/user/user.ts b/server/models/user/user.ts index 069d7266e..ddce455a1 100644 --- a/server/models/user/user.ts +++ b/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>> { @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>> { @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>> { noInstanceConfigWarningModal: this.noInstanceConfigWarningModal, noWelcomeModal: this.noWelcomeModal, + noAccountSetupWarningModal: this.noAccountSetupWarningModal, blocked: this.blocked, blockedReason: this.blockedReason, diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 9d8f933db..58b360f92 100644 --- a/server/tests/api/check-params/users.ts +++ b/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({ diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 318ff832a..085d9d870 100644 --- a/server/tests/api/users/users.ts +++ b/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 }) }) diff --git a/shared/models/users/user-update-me.model.ts b/shared/models/users/user-update-me.model.ts index db6539cd2..6d7df38fb 100644 --- a/shared/models/users/user-update-me.model.ts +++ b/shared/models/users/user-update-me.model.ts @@ -20,4 +20,5 @@ export interface UserUpdateMe { noInstanceConfigWarningModal?: boolean noWelcomeModal?: boolean + noAccountSetupWarningModal?: boolean } diff --git a/shared/models/users/user.model.ts b/shared/models/users/user.model.ts index 7a982c2e5..78870c556 100644 --- a/shared/models/users/user.model.ts +++ b/shared/models/users/user.model.ts @@ -51,6 +51,7 @@ export interface User { noInstanceConfigWarningModal: boolean noWelcomeModal: boolean + noAccountSetupWarningModal: boolean createdAt: Date diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 76e78fe53..65a2ac897 100644 --- a/support/doc/api/openapi.yaml +++ b/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: -- cgit v1.2.3