</div>
</ng-template>
</p-toast>
+
+<ng-template [ngIf]="isUserLoggedIn()">
+ <my-welcome-modal #welcomeModal></my-welcome-modal>
+ <my-instance-config-warning-modal #instanceConfigWarningModal></my-instance-config-warning-modal>
+</ng-template>
-import { Component, OnInit } from '@angular/core'
+import { Component, OnInit, ViewChild } from '@angular/core'
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
import { Event, GuardsCheckStart, NavigationEnd, Router, Scroll } from '@angular/router'
import { AuthService, RedirectService, ServerService, ThemeService } from '@app/core'
import { is18nPath } from '../../../shared/models/i18n'
import { ScreenService } from '@app/shared/misc/screen.service'
-import { debounceTime, filter, map, pairwise, skip } from 'rxjs/operators'
+import { debounceTime, filter, map, pairwise, skip, switchMap } from 'rxjs/operators'
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { fromEvent } from 'rxjs'
import { HooksService } from '@app/core/plugins/hooks.service'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { POP_STATE_MODAL_DISMISS } from '@app/shared/misc/constants'
+import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
+import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
+import { UserRole } from '@shared/models'
+import { User } from '@app/shared'
+import { InstanceService } from '@app/shared/instance/instance.service'
@Component({
selector: 'my-app',
styleUrls: [ './app.component.scss' ]
})
export class AppComponent implements OnInit {
+ @ViewChild('welcomeModal', { static: false }) welcomeModal: WelcomeModalComponent
+ @ViewChild('instanceConfigWarningModal', { static: false }) instanceConfigWarningModal: InstanceConfigWarningModalComponent
+
isMenuDisplayed = true
isMenuChangedByUser = false
private authService: AuthService,
private serverService: ServerService,
private pluginService: PluginService,
+ private instanceService: InstanceService,
private domSanitizer: DomSanitizer,
private redirectService: RedirectService,
private screenService: ScreenService,
.subscribe(() => this.onResize())
this.location.onPopState(() => this.modalService.dismissAll(POP_STATE_MODAL_DISMISS))
+
+ this.openModalsIfNeeded()
}
isUserLoggedIn () {
this.hooks.runAction('action:application.init', 'common')
}
+ private async openModalsIfNeeded () {
+ this.serverService.configLoaded
+ .pipe(
+ switchMap(() => this.authService.userInformationLoaded),
+ map(() => this.authService.getUser()),
+ filter(user => user.role === UserRole.ADMINISTRATOR)
+ ).subscribe(user => setTimeout(() => this.openAdminModals(user))) // setTimeout because of ngIf in template
+ }
+
+ private async openAdminModals (user: User) {
+ if (user.noWelcomeModal !== true) return this.welcomeModal.show()
+
+ const config = this.serverService.getConfig()
+
+ if (user.noInstanceConfigWarningModal !== true && config.signup.allowed && config.instance.name.toLowerCase() === 'peertube') {
+ this.instanceService.getAbout()
+ .subscribe(about => {
+ if (!about.instance.terms) {
+ this.instanceConfigWarningModal.show()
+ }
+ })
+ }
+ }
+
private initHotkeys () {
this.hotkeysService.add([
new Hotkey(['/', 's'], (event: KeyboardEvent): boolean => {
document.getElementById('search-video').focus()
return false
}, undefined, this.i18n('Focus the search bar')),
+
new Hotkey('b', (event: KeyboardEvent): boolean => {
this.toggleMenu()
return false
}, undefined, this.i18n('Toggle the left menu')),
+
new Hotkey('g o', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/overview' ])
return false
}, undefined, this.i18n('Go to the discover videos page')),
+
new Hotkey('g t', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/trending' ])
return false
}, undefined, this.i18n('Go to the trending videos page')),
+
new Hotkey('g r', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/recently-added' ])
return false
}, undefined, this.i18n('Go to the recently added videos page')),
+
new Hotkey('g l', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/local' ])
return false
}, undefined, this.i18n('Go to the local videos page')),
+
new Hotkey('g u', (event: KeyboardEvent): boolean => {
this.router.navigate([ '/videos/upload' ])
return false
import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n'
import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
import { SearchModule } from '@app/search'
+import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
+import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
export function metaFactory (serverService: ServerService): MetaLoader {
return new MetaStaticLoader({
MenuComponent,
LanguageChooserComponent,
AvatarNotificationComponent,
- HeaderComponent
+ HeaderComponent,
+
+ WelcomeModalComponent,
+ InstanceConfigWarningModalComponent
],
imports: [
BrowserModule,
--- /dev/null
+<ng-template #modal let-hide="close">
+ <div class="modal-header">
+ <h4 i18n class="modal-title">Warning!</h4>
+ <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
+ </div>
+
+ <div class="modal-body">
+
+ </div>
+
+ <div class="modal-footer inputs">
+ <span i18n class="action-button action-button-cancel" (click)="hide()">Close</span>
+ </div>
+
+</ng-template>
--- /dev/null
+@import '_mixins';
+@import '_variables';
+
+.action-button-cancel {
+ margin-right: 0 !important;
+}
--- /dev/null
+import { Component, ElementRef, ViewChild } from '@angular/core'
+import { Notifier } from '@app/core'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+
+@Component({
+ selector: 'my-instance-config-warning-modal',
+ templateUrl: './instance-config-warning-modal.component.html',
+ styleUrls: [ './instance-config-warning-modal.component.scss' ]
+})
+export class InstanceConfigWarningModalComponent {
+ @ViewChild('modal', { static: true }) modal: ElementRef
+
+ constructor (
+ private modalService: NgbModal,
+ private notifier: Notifier,
+ private i18n: I18n
+ ) { }
+
+ show () {
+ this.modalService.open(this.modal)
+ }
+}
--- /dev/null
+<ng-template #modal let-hide="close">
+ <div class="modal-header">
+ <h4 i18n class="modal-title">Welcome on PeerTube dear administrator!</h4>
+ <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
+ </div>
+
+ <div class="modal-body">
+
+ <div class="block-links">
+ <div class="subtitle">Useful links</div>
+
+ <ul>
+ <li>
+ Official PeerTube website: <a href="https://joinpeertube.org" target="_blank" rel="noopener noreferrer">https://joinpeertube.org</a>
+ </li>
+
+ <li>
+ Discover CLI PeerTube tools (to upload or import videos, parse logs, prune storage directories, reset user password...):
+ <a href="https://docs.joinpeertube.org/#/maintain-tools" target="_blank" rel="noopener noreferrer">https://docs.joinpeertube.org/#/maintain-tools</a>
+ </li>
+
+ <li>
+ Understand how to administer your instance (managing users, following other instances, dealing with spammers...):
+ <a href="https://docs.joinpeertube.org/#/admin-following-instances" target="_blank" rel="noopener noreferrer">https://docs.joinpeertube.org/#/admin-following-instances</a>
+ </li>
+
+ <li>
+ Learn how to use PeerTube (setup your account, managing video playlists, discover third-party applications...):
+ <a href="https://docs.joinpeertube.org/#/use-setup-account" target="_blank" rel="noopener noreferrer">https://docs.joinpeertube.org/#/use-setup-account</a>
+ </li>
+ </ul>
+ </div>
+
+ <div class="block-configuration">
+ <div class="subtitle">Configure your instance</div>
+
+ <p>
+ Now it's time to configure your instance! Choosing your <strong>instance name</strong>, <strong>setting up a description</strong>,
+ specifying <strong>who you are</strong> and <strong>how long</strong> you plan to <strong>maintain your instance</strong>
+ is very important for visitors to understand on what type of instance they are.
+ </p>
+
+ <p>
+ If you want to open registrations, please decide what are <strong>your moderation rules</strong>, fill your <strong>instance terms</strong>
+ and specify the categories and languages you speak. This way, users that are looking for a PeerTube instance on which they can register
+ will be able to choose <strong>the right one</strong>.
+ </p>
+
+ <div class="configure-instance">
+ <a href="/admin/config/edit-custom" target="_blank" rel="noopener noreferrer">Configure your instance</a>
+ </div>
+ </div>
+
+ <div class="block-instance">
+ <div class="subtitle">Index your instance</div>
+
+ If you want, you can index your PeerTube instance on the public PeerTube instances list:
+ <a href="https://instances.joinpeertube.org/instances">https://instances.joinpeertube.org/instances</a>
+ </div>
+ </div>
+
+ <div class="modal-footer inputs">
+ <span i18n class="action-button action-button-submit" (click)="hide()">Understood!</span>
+ </div>
+
+</ng-template>
--- /dev/null
+@import '_mixins';
+@import '_variables';
+
+.modal-body {
+ font-size: 15px;
+}
+
+.action-button-cancel {
+ margin-right: 0 !important;
+}
+
+.subtitle {
+ font-weight: $font-semibold;
+ margin-bottom: 10px;
+ font-size: 16px;
+}
+
+.block-configuration,
+.block-instance {
+ margin-top: 30px;
+}
+
+li {
+ margin-bottom: 10px;
+}
+
+.configure-instance {
+ text-align: center;
+ font-weight: 600;
+ font-size: 18px;
+}
--- /dev/null
+import { Component, ElementRef, ViewChild } from '@angular/core'
+import { Notifier } from '@app/core'
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { UserService } from '@app/shared'
+
+@Component({
+ selector: 'my-welcome-modal',
+ templateUrl: './welcome-modal.component.html',
+ styleUrls: [ './welcome-modal.component.scss' ]
+})
+export class WelcomeModalComponent {
+ @ViewChild('modal', { static: true }) modal: ElementRef
+
+ constructor (
+ private userService: UserService,
+ private modalService: NgbModal,
+ private notifier: Notifier
+ ) { }
+
+ show () {
+ const ref = this.modalService.open(this.modal,{
+ backdrop: 'static',
+ keyboard: false,
+ size: 'lg'
+ })
+
+ ref.result.finally(() => this.doNotOpenAgain())
+ }
+
+ private doNotOpenAgain () {
+ this.userService.updateMyProfile({ noWelcomeModal: true })
+ .subscribe(
+ () => console.log('We will not open the welcome modal again.'),
+
+ err => this.notifier.error(err.message)
+ )
+
+ return true
+ }
+}
username: string
email: string
pendingEmail: string | null
+
emailVerified: boolean
nsfwPolicy: NSFWPolicyType
- role: UserRole
- roleLabel: string
+ adminFlags?: UserAdminFlag
- webTorrentEnabled: boolean
autoPlayVideo: boolean
+ webTorrentEnabled: boolean
videosHistoryEnabled: boolean
videoLanguages: string[]
+ role: UserRole
+ roleLabel: string
+
videoQuota: number
videoQuotaDaily: number
- account: Account
- videoChannels: VideoChannel[]
- createdAt: Date
+ videoQuotaUsed?: number
+ videoQuotaUsedDaily?: number
theme: string
- adminFlags?: UserAdminFlag
+ account: Account
+ notificationSettings?: UserNotificationSetting
+ videoChannels?: VideoChannel[]
blocked: boolean
blockedReason?: string
- notificationSettings?: UserNotificationSetting
+ noInstanceConfigWarningModal: boolean
+ noWelcomeModal: boolean
+
+ createdAt: Date
constructor (hash: Partial<UserServerModel>) {
this.id = hash.id
this.role = hash.role
this.videoChannels = hash.videoChannels
+
this.videoQuota = hash.videoQuota
this.videoQuotaDaily = hash.videoQuotaDaily
+ this.videoQuotaUsed = hash.videoQuotaUsed
+ this.videoQuotaUsedDaily = hash.videoQuotaUsedDaily
+
this.nsfwPolicy = hash.nsfwPolicy
this.webTorrentEnabled = hash.webTorrentEnabled
this.videosHistoryEnabled = hash.videosHistoryEnabled
this.autoPlayVideo = hash.autoPlayVideo
- this.createdAt = hash.createdAt
this.theme = hash.theme
this.blocked = hash.blocked
this.blockedReason = hash.blockedReason
+ this.noInstanceConfigWarningModal = hash.noInstanceConfigWarningModal
+ this.noWelcomeModal = hash.noWelcomeModal
+
this.notificationSettings = hash.notificationSettings
+ this.createdAt = hash.createdAt
+
if (hash.account !== undefined) {
this.account = new Account(hash.account)
}
// We did not load channels in res.locals.user
const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
- return res.json(user.toFormattedJSON({}))
+ return res.json(user.toFormattedJSON())
}
async function getUserVideoQuotaUsed (req: express.Request, res: express.Response) {
if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled
if (body.videoLanguages !== undefined) user.videoLanguages = body.videoLanguages
if (body.theme !== undefined) user.theme = body.theme
+ if (body.noInstanceConfigWarningModal !== undefined) user.noInstanceConfigWarningModal = body.noInstanceConfigWarningModal
+ if (body.noWelcomeModal !== undefined) user.noWelcomeModal = body.noWelcomeModal
if (body.email !== undefined) {
if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
}
}
- await sequelizeTypescript.transaction(async t => {
- const userAccount = await AccountModel.load(user.Account.id)
+ if (body.displayName !== undefined || body.description !== undefined) {
+ await sequelizeTypescript.transaction(async t => {
+ const userAccount = await AccountModel.load(user.Account.id, t)
- await user.save({ transaction: t })
+ await user.save({ transaction: t })
- if (body.displayName !== undefined) userAccount.name = body.displayName
- if (body.description !== undefined) userAccount.description = body.description
- await userAccount.save({ transaction: t })
+ if (body.displayName !== undefined) userAccount.name = body.displayName
+ if (body.description !== undefined) userAccount.description = body.description
+ await userAccount.save({ transaction: t })
- await sendUpdateActor(userAccount, t)
- })
+ await sendUpdateActor(userAccount, t)
+ })
+ }
if (sendVerificationEmail === true) {
await sendVerifyUserEmail(user, true)
return isBooleanValid(value)
}
+function isNoInstanceConfigWarningModal (value: any) {
+ return isBooleanValid(value)
+}
+
+function isNoWelcomeModal (value: any) {
+ return isBooleanValid(value)
+}
+
function isUserBlockedReasonValid (value: any) {
return value === null || (exists(value) && validator.isLength(value, CONSTRAINTS_FIELDS.USERS.BLOCKED_REASON))
}
isUserAutoPlayVideoValid,
isUserDisplayNameValid,
isUserDescriptionValid,
+ isNoInstanceConfigWarningModal,
+ isNoWelcomeModal,
isAvatarFile
}
--- /dev/null
+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', 'noInstanceConfigWarningModal', data)
+ }
+
+ {
+ const data = {
+ type: Sequelize.BOOLEAN,
+ allowNull: false,
+ defaultValue: true
+ }
+
+ await utils.queryInterface.addColumn('user', 'noWelcomeModal', data)
+ data.defaultValue = false
+
+ await utils.queryInterface.changeColumn('user', 'noWelcomeModal', data)
+ }
+}
+
+function down (options) {
+ throw new Error('Not implemented.')
+}
+
+export {
+ up,
+ down
+}
import { omit } from 'lodash'
import { isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
import {
+ isNoInstanceConfigWarningModal, isNoWelcomeModal,
isUserAdminFlagsValid,
isUserAutoPlayVideoValid,
isUserBlockedReasonValid,
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'),
+ body('noWelcomeModal')
+ .optional()
+ .custom(v => isNoWelcomeModal(v)).withMessage('Should have a valid noWelcomeModal boolean'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') })
import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared'
import { User, UserRole } from '../../../shared/models/users'
import {
+ isNoInstanceConfigWarningModal,
isUserAdminFlagsValid,
isUserAutoPlayVideoValid,
isUserBlockedReasonValid,
isUserVideoQuotaDailyValid,
isUserVideoQuotaValid,
isUserVideosHistoryEnabledValid,
- isUserWebTorrentEnabledValid
+ isUserWebTorrentEnabledValid,
+ isNoWelcomeModal
} from '../../helpers/custom-validators/users'
import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
import { OAuthTokenModel } from '../oauth/oauth-token'
@Column
theme: string
+ @AllowNull(false)
+ @Default(false)
+ @Is(
+ 'UserNoInstanceConfigWarningModal',
+ value => throwIfNotValid(value, isNoInstanceConfigWarningModal, 'no instance config warning modal')
+ )
+ @Column
+ noInstanceConfigWarningModal: boolean
+
+ @AllowNull(false)
+ @Default(false)
+ @Is(
+ 'UserNoInstanceConfigWarningModal',
+ value => throwIfNotValid(value, isNoWelcomeModal, 'no welcome modal')
+ )
+ @Column
+ noWelcomeModal: boolean
+
@CreatedAt
createdAt: Date
return comparePassword(password, this.password)
}
- toSummaryJSON
-
toFormattedJSON (this: MUserFormattable, parameters: { withAdminFlags?: boolean } = {}): User {
const videoQuotaUsed = this.get('videoQuotaUsed')
const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
- const json = {
+ const json: User = {
id: this.id,
username: this.username,
email: this.email,
+ theme: getThemeOrDefault(this.theme, DEFAULT_USER_THEME_NAME),
+
pendingEmail: this.pendingEmail,
emailVerified: this.emailVerified,
+
nsfwPolicy: this.nsfwPolicy,
webTorrentEnabled: this.webTorrentEnabled,
videosHistoryEnabled: this.videosHistoryEnabled,
autoPlayVideo: this.autoPlayVideo,
videoLanguages: this.videoLanguages,
+
role: this.role,
- theme: getThemeOrDefault(this.theme, DEFAULT_USER_THEME_NAME),
roleLabel: USER_ROLE_LABELS[ this.role ],
+
videoQuota: this.videoQuota,
videoQuotaDaily: this.videoQuotaDaily,
- createdAt: this.createdAt,
+ videoQuotaUsed: videoQuotaUsed !== undefined
+ ? parseInt(videoQuotaUsed + '', 10)
+ : undefined,
+ videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined
+ ? parseInt(videoQuotaUsedDaily + '', 10)
+ : undefined,
+
+ noInstanceConfigWarningModal: this.noInstanceConfigWarningModal,
+ noWelcomeModal: this.noWelcomeModal,
+
blocked: this.blocked,
blockedReason: this.blockedReason,
+
account: this.Account.toFormattedJSON(),
- notificationSettings: this.NotificationSetting ? this.NotificationSetting.toFormattedJSON() : undefined,
+
+ notificationSettings: this.NotificationSetting
+ ? this.NotificationSetting.toFormattedJSON()
+ : undefined,
+
videoChannels: [],
- videoQuotaUsed: videoQuotaUsed !== undefined
- ? parseInt(videoQuotaUsed + '', 10)
- : undefined,
- videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined
- ? parseInt(videoQuotaUsedDaily + '', 10)
- : undefined
+
+ createdAt: this.createdAt
}
if (parameters.withAdminFlags) {
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
})
+ it('Should fail with an invalid noInstanceConfigWarningModal attribute', async function () {
+ const fields = {
+ noInstanceConfigWarningModal: -1
+ }
+
+ await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
+ })
+
+ it('Should fail with an invalid noWelcomeModal attribute', async function () {
+ const fields = {
+ noWelcomeModal: -1
+ }
+
+ await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
+ })
+
it('Should succeed to change password with the correct params', async function () {
const fields = {
currentPassword: 'my super password',
nsfwPolicy: 'blur',
autoPlayVideo: false,
email: 'super_email@example.com',
- theme: 'default'
+ theme: 'default',
+ noInstanceConfigWarningModal: true,
+ noWelcomeModal: true
}
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields, statusCodeExpected: 204 })
url: server.url,
accessToken: accessTokenUser,
currentPassword: 'super password',
- newPassword: 'new password'
+ password: 'new password'
})
user.password = 'new password'
})
const res = await getMyUserInformation(server.url, accessTokenUser)
- const user = res.body
+ const user: User = res.body
expect(user.username).to.equal('user_1')
expect(user.email).to.equal('updated@example.com')
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')
+ expect(user.noWelcomeModal).to.be.false
+ expect(user.noInstanceConfigWarningModal).to.be.false
})
it('Should be able to update my theme', async function () {
expect(body.theme).to.equal(theme)
}
})
+
+ it('Should be able to update my modal preferences', async function () {
+ await updateMyUser({
+ url: server.url,
+ accessToken: accessTokenUser,
+ noInstanceConfigWarningModal: true,
+ noWelcomeModal: true
+ })
+
+ const res = await getMyUserInformation(server.url, accessTokenUser)
+ const user: User = res.body
+
+ expect(user.noWelcomeModal).to.be.true
+ expect(user.noInstanceConfigWarningModal).to.be.true
+ })
})
describe('Updating another user', function () {
import * as request from 'supertest'
import { makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
-import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type'
import { UserAdminFlag } from '../../models/users/user-flag.model'
import { UserRegister } from '../../models/users/user-register.model'
import { UserRole } from '../../models/users/user-role'
import { ServerInfo } from '../server/servers'
import { userLogin } from './login'
import { UserUpdateMe } from '../../models/users'
+import { omit } from 'lodash'
type CreateUserArgs = { url: string,
accessToken: string,
.expect(expectedStatus)
}
-function updateMyUser (options: {
- url: string
- accessToken: string
- currentPassword?: string
- newPassword?: string
- nsfwPolicy?: NSFWPolicyType
- email?: string
- autoPlayVideo?: boolean
- displayName?: string
- description?: string
- videosHistoryEnabled?: boolean
- theme?: string
-}) {
+function updateMyUser (options: { url: string, accessToken: string } & UserUpdateMe) {
const path = '/api/v1/users/me'
- const toSend: UserUpdateMe = {}
- if (options.currentPassword !== undefined && options.currentPassword !== null) toSend.currentPassword = options.currentPassword
- if (options.newPassword !== undefined && options.newPassword !== null) toSend.password = options.newPassword
- if (options.nsfwPolicy !== undefined && options.nsfwPolicy !== null) toSend.nsfwPolicy = options.nsfwPolicy
- 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
- if (options.theme !== undefined && options.theme !== null) toSend.theme = options.theme
- if (options.videosHistoryEnabled !== undefined && options.videosHistoryEnabled !== null) {
- toSend.videosHistoryEnabled = options.videosHistoryEnabled
- }
+ const toSend: UserUpdateMe = omit(options, 'url', 'accessToken')
return makePutBodyRequest({
url: options.url,
password?: string
theme?: string
+
+ noInstanceConfigWarningModal?: boolean
+ noWelcomeModal?: boolean
}
username: string
email: string
pendingEmail: string | null
+
emailVerified: boolean
nsfwPolicy: NSFWPolicyType
autoPlayVideo: boolean
webTorrentEnabled: boolean
videosHistoryEnabled: boolean
+ videoLanguages: string[]
role: UserRole
roleLabel: string
videoQuota: number
videoQuotaDaily: number
- createdAt: Date
+ videoQuotaUsed?: number
+ videoQuotaUsedDaily?: number
theme: string
blocked: boolean
blockedReason?: string
- videoQuotaUsed?: number
+ noInstanceConfigWarningModal: boolean
+ noWelcomeModal: boolean
+
+ createdAt: Date
}