aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/account
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/account')
-rw-r--r--server/models/account/account-blocklist.ts8
-rw-r--r--server/models/account/account-video-rate.ts28
-rw-r--r--server/models/account/account.ts27
-rw-r--r--server/models/account/user-notification-setting.ts15
-rw-r--r--server/models/account/user-notification.ts29
-rw-r--r--server/models/account/user-video-history.ts7
-rw-r--r--server/models/account/user.ts94
7 files changed, 147 insertions, 61 deletions
diff --git a/server/models/account/account-blocklist.ts b/server/models/account/account-blocklist.ts
index d5746ad76..8bcaca828 100644
--- a/server/models/account/account-blocklist.ts
+++ b/server/models/account/account-blocklist.ts
@@ -3,6 +3,8 @@ import { AccountModel } from './account'
3import { getSort } from '../utils' 3import { getSort } from '../utils'
4import { AccountBlock } from '../../../shared/models/blocklist' 4import { AccountBlock } from '../../../shared/models/blocklist'
5import { Op } from 'sequelize' 5import { Op } from 'sequelize'
6import * as Bluebird from 'bluebird'
7import { MAccountBlocklist, MAccountBlocklistAccounts, MAccountBlocklistFormattable } from '@server/typings/models'
6 8
7enum ScopeNames { 9enum ScopeNames {
8 WITH_ACCOUNTS = 'WITH_ACCOUNTS' 10 WITH_ACCOUNTS = 'WITH_ACCOUNTS'
@@ -103,7 +105,7 @@ export class AccountBlocklistModel extends Model<AccountBlocklistModel> {
103 }) 105 })
104 } 106 }
105 107
106 static loadByAccountAndTarget (accountId: number, targetAccountId: number) { 108 static loadByAccountAndTarget (accountId: number, targetAccountId: number): Bluebird<MAccountBlocklist> {
107 const query = { 109 const query = {
108 where: { 110 where: {
109 accountId, 111 accountId,
@@ -126,13 +128,13 @@ export class AccountBlocklistModel extends Model<AccountBlocklistModel> {
126 128
127 return AccountBlocklistModel 129 return AccountBlocklistModel
128 .scope([ ScopeNames.WITH_ACCOUNTS ]) 130 .scope([ ScopeNames.WITH_ACCOUNTS ])
129 .findAndCountAll(query) 131 .findAndCountAll<MAccountBlocklistAccounts>(query)
130 .then(({ rows, count }) => { 132 .then(({ rows, count }) => {
131 return { total: count, data: rows } 133 return { total: count, data: rows }
132 }) 134 })
133 } 135 }
134 136
135 toFormattedJSON (): AccountBlock { 137 toFormattedJSON (this: MAccountBlocklistFormattable): AccountBlock {
136 return { 138 return {
137 byAccount: this.ByAccount.toFormattedJSON(), 139 byAccount: this.ByAccount.toFormattedJSON(),
138 blockedAccount: this.BlockedAccount.toFormattedJSON(), 140 blockedAccount: this.BlockedAccount.toFormattedJSON(),
diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts
index 4bd8114cf..a6edbeee8 100644
--- a/server/models/account/account-video-rate.ts
+++ b/server/models/account/account-video-rate.ts
@@ -10,6 +10,13 @@ import { buildLocalAccountIdsIn, getSort, throwIfNotValid } from '../utils'
10import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 10import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
11import { AccountVideoRate } from '../../../shared' 11import { AccountVideoRate } from '../../../shared'
12import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel' 12import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel'
13import * as Bluebird from 'bluebird'
14import {
15 MAccountVideoRate,
16 MAccountVideoRateAccountUrl,
17 MAccountVideoRateAccountVideo,
18 MAccountVideoRateFormattable
19} from '@server/typings/models/video/video-rate'
13 20
14/* 21/*
15 Account rates per video. 22 Account rates per video.
@@ -77,7 +84,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
77 }) 84 })
78 Account: AccountModel 85 Account: AccountModel
79 86
80 static load (accountId: number, videoId: number, transaction?: Transaction) { 87 static load (accountId: number, videoId: number, transaction?: Transaction): Bluebird<MAccountVideoRate> {
81 const options: FindOptions = { 88 const options: FindOptions = {
82 where: { 89 where: {
83 accountId, 90 accountId,
@@ -89,7 +96,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
89 return AccountVideoRateModel.findOne(options) 96 return AccountVideoRateModel.findOne(options)
90 } 97 }
91 98
92 static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, transaction?: Transaction) { 99 static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> {
93 const options: FindOptions = { 100 const options: FindOptions = {
94 where: { 101 where: {
95 [ Op.or]: [ 102 [ Op.or]: [
@@ -103,7 +110,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
103 ] 110 ]
104 } 111 }
105 } 112 }
106 if (transaction) options.transaction = transaction 113 if (t) options.transaction = t
107 114
108 return AccountVideoRateModel.findOne(options) 115 return AccountVideoRateModel.findOne(options)
109 } 116 }
@@ -140,7 +147,12 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
140 return AccountVideoRateModel.findAndCountAll(query) 147 return AccountVideoRateModel.findAndCountAll(query)
141 } 148 }
142 149
143 static loadLocalAndPopulateVideo (rateType: VideoRateType, accountName: string, videoId: number, transaction?: Transaction) { 150 static loadLocalAndPopulateVideo (
151 rateType: VideoRateType,
152 accountName: string,
153 videoId: number,
154 t?: Transaction
155 ): Bluebird<MAccountVideoRateAccountVideo> {
144 const options: FindOptions = { 156 const options: FindOptions = {
145 where: { 157 where: {
146 videoId, 158 videoId,
@@ -152,7 +164,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
152 required: true, 164 required: true,
153 include: [ 165 include: [
154 { 166 {
155 attributes: [ 'id', 'url', 'preferredUsername' ], 167 attributes: [ 'id', 'url', 'followersUrl', 'preferredUsername' ],
156 model: ActorModel.unscoped(), 168 model: ActorModel.unscoped(),
157 required: true, 169 required: true,
158 where: { 170 where: {
@@ -167,7 +179,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
167 } 179 }
168 ] 180 ]
169 } 181 }
170 if (transaction) options.transaction = transaction 182 if (t) options.transaction = t
171 183
172 return AccountVideoRateModel.findOne(options) 184 return AccountVideoRateModel.findOne(options)
173 } 185 }
@@ -208,7 +220,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
208 ] 220 ]
209 } 221 }
210 222
211 return AccountVideoRateModel.findAndCountAll(query) 223 return AccountVideoRateModel.findAndCountAll<MAccountVideoRateAccountUrl>(query)
212 } 224 }
213 225
214 static cleanOldRatesOf (videoId: number, type: VideoRateType, beforeUpdatedAt: Date) { 226 static cleanOldRatesOf (videoId: number, type: VideoRateType, beforeUpdatedAt: Date) {
@@ -241,7 +253,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
241 }) 253 })
242 } 254 }
243 255
244 toFormattedJSON (): AccountVideoRate { 256 toFormattedJSON (this: MAccountVideoRateFormattable): AccountVideoRate {
245 return { 257 return {
246 video: this.Video.toFormattedJSON(), 258 video: this.Video.toFormattedJSON(),
247 rating: this.type 259 rating: this.type
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index 4dc412301..ba1094536 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -3,7 +3,8 @@ import {
3 BeforeDestroy, 3 BeforeDestroy,
4 BelongsTo, 4 BelongsTo,
5 Column, 5 Column,
6 CreatedAt, DataType, 6 CreatedAt,
7 DataType,
7 Default, 8 Default,
8 DefaultScope, 9 DefaultScope,
9 ForeignKey, 10 ForeignKey,
@@ -31,6 +32,8 @@ import { FindOptions, IncludeOptions, Op, Transaction, WhereOptions } from 'sequ
31import { AccountBlocklistModel } from './account-blocklist' 32import { AccountBlocklistModel } from './account-blocklist'
32import { ServerBlocklistModel } from '../server/server-blocklist' 33import { ServerBlocklistModel } from '../server/server-blocklist'
33import { ActorFollowModel } from '../activitypub/actor-follow' 34import { ActorFollowModel } from '../activitypub/actor-follow'
35import { MAccountActor, MAccountDefault, MAccountSummaryFormattable, MAccountFormattable, MAccountAP } from '../../typings/models'
36import * as Bluebird from 'bluebird'
34 37
35export enum ScopeNames { 38export enum ScopeNames {
36 SUMMARY = 'SUMMARY' 39 SUMMARY = 'SUMMARY'
@@ -229,11 +232,11 @@ export class AccountModel extends Model<AccountModel> {
229 return undefined 232 return undefined
230 } 233 }
231 234
232 static load (id: number, transaction?: Transaction) { 235 static load (id: number, transaction?: Transaction): Bluebird<MAccountDefault> {
233 return AccountModel.findByPk(id, { transaction }) 236 return AccountModel.findByPk(id, { transaction })
234 } 237 }
235 238
236 static loadByNameWithHost (nameWithHost: string) { 239 static loadByNameWithHost (nameWithHost: string): Bluebird<MAccountDefault> {
237 const [ accountName, host ] = nameWithHost.split('@') 240 const [ accountName, host ] = nameWithHost.split('@')
238 241
239 if (!host || host === WEBSERVER.HOST) return AccountModel.loadLocalByName(accountName) 242 if (!host || host === WEBSERVER.HOST) return AccountModel.loadLocalByName(accountName)
@@ -241,7 +244,7 @@ export class AccountModel extends Model<AccountModel> {
241 return AccountModel.loadByNameAndHost(accountName, host) 244 return AccountModel.loadByNameAndHost(accountName, host)
242 } 245 }
243 246
244 static loadLocalByName (name: string) { 247 static loadLocalByName (name: string): Bluebird<MAccountDefault> {
245 const query = { 248 const query = {
246 where: { 249 where: {
247 [ Op.or ]: [ 250 [ Op.or ]: [
@@ -271,7 +274,7 @@ export class AccountModel extends Model<AccountModel> {
271 return AccountModel.findOne(query) 274 return AccountModel.findOne(query)
272 } 275 }
273 276
274 static loadByNameAndHost (name: string, host: string) { 277 static loadByNameAndHost (name: string, host: string): Bluebird<MAccountDefault> {
275 const query = { 278 const query = {
276 include: [ 279 include: [
277 { 280 {
@@ -296,7 +299,7 @@ export class AccountModel extends Model<AccountModel> {
296 return AccountModel.findOne(query) 299 return AccountModel.findOne(query)
297 } 300 }
298 301
299 static loadByUrl (url: string, transaction?: Transaction) { 302 static loadByUrl (url: string, transaction?: Transaction): Bluebird<MAccountDefault> {
300 const query = { 303 const query = {
301 include: [ 304 include: [
302 { 305 {
@@ -329,7 +332,7 @@ export class AccountModel extends Model<AccountModel> {
329 }) 332 })
330 } 333 }
331 334
332 static listLocalsForSitemap (sort: string) { 335 static listLocalsForSitemap (sort: string): Bluebird<MAccountActor[]> {
333 const query = { 336 const query = {
334 attributes: [ ], 337 attributes: [ ],
335 offset: 0, 338 offset: 0,
@@ -350,7 +353,7 @@ export class AccountModel extends Model<AccountModel> {
350 .findAll(query) 353 .findAll(query)
351 } 354 }
352 355
353 toFormattedJSON (): Account { 356 toFormattedJSON (this: MAccountFormattable): Account {
354 const actor = this.Actor.toFormattedJSON() 357 const actor = this.Actor.toFormattedJSON()
355 const account = { 358 const account = {
356 id: this.id, 359 id: this.id,
@@ -364,8 +367,8 @@ export class AccountModel extends Model<AccountModel> {
364 return Object.assign(actor, account) 367 return Object.assign(actor, account)
365 } 368 }
366 369
367 toFormattedSummaryJSON (): AccountSummary { 370 toFormattedSummaryJSON (this: MAccountSummaryFormattable): AccountSummary {
368 const actor = this.Actor.toFormattedJSON() 371 const actor = this.Actor.toFormattedSummaryJSON()
369 372
370 return { 373 return {
371 id: this.id, 374 id: this.id,
@@ -377,8 +380,8 @@ export class AccountModel extends Model<AccountModel> {
377 } 380 }
378 } 381 }
379 382
380 toActivityPubObject () { 383 toActivityPubObject (this: MAccountAP) {
381 const obj = this.Actor.toActivityPubObject(this.name, 'Account') 384 const obj = this.Actor.toActivityPubObject(this.name)
382 385
383 return Object.assign(obj, { 386 return Object.assign(obj, {
384 summary: this.description 387 summary: this.description
diff --git a/server/models/account/user-notification-setting.ts b/server/models/account/user-notification-setting.ts
index c2fbc6d23..dc69a17fd 100644
--- a/server/models/account/user-notification-setting.ts
+++ b/server/models/account/user-notification-setting.ts
@@ -17,6 +17,7 @@ import { UserModel } from './user'
17import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' 17import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications'
18import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model' 18import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model'
19import { clearCacheByUserId } from '../../lib/oauth-model' 19import { clearCacheByUserId } from '../../lib/oauth-model'
20import { MNotificationSettingFormattable } from '@server/typings/models'
20 21
21@Table({ 22@Table({
22 tableName: 'userNotificationSetting', 23 tableName: 'userNotificationSetting',
@@ -113,6 +114,15 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM
113 @AllowNull(false) 114 @AllowNull(false)
114 @Default(null) 115 @Default(null)
115 @Is( 116 @Is(
117 'UserNotificationSettingNewInstanceFollower',
118 value => throwIfNotValid(value, isUserNotificationSettingValid, 'autoInstanceFollowing')
119 )
120 @Column
121 autoInstanceFollowing: UserNotificationSettingValue
122
123 @AllowNull(false)
124 @Default(null)
125 @Is(
116 'UserNotificationSettingNewFollow', 126 'UserNotificationSettingNewFollow',
117 value => throwIfNotValid(value, isUserNotificationSettingValid, 'newFollow') 127 value => throwIfNotValid(value, isUserNotificationSettingValid, 'newFollow')
118 ) 128 )
@@ -152,7 +162,7 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM
152 return clearCacheByUserId(instance.userId) 162 return clearCacheByUserId(instance.userId)
153 } 163 }
154 164
155 toFormattedJSON (): UserNotificationSetting { 165 toFormattedJSON (this: MNotificationSettingFormattable): UserNotificationSetting {
156 return { 166 return {
157 newCommentOnMyVideo: this.newCommentOnMyVideo, 167 newCommentOnMyVideo: this.newCommentOnMyVideo,
158 newVideoFromSubscription: this.newVideoFromSubscription, 168 newVideoFromSubscription: this.newVideoFromSubscription,
@@ -164,7 +174,8 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM
164 newUserRegistration: this.newUserRegistration, 174 newUserRegistration: this.newUserRegistration,
165 commentMention: this.commentMention, 175 commentMention: this.commentMention,
166 newFollow: this.newFollow, 176 newFollow: this.newFollow,
167 newInstanceFollower: this.newInstanceFollower 177 newInstanceFollower: this.newInstanceFollower,
178 autoInstanceFollowing: this.autoInstanceFollowing
168 } 179 }
169 } 180 }
170} 181}
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts
index f38cd7e78..ccb81b891 100644
--- a/server/models/account/user-notification.ts
+++ b/server/models/account/user-notification.ts
@@ -16,6 +16,7 @@ import { ActorModel } from '../activitypub/actor'
16import { ActorFollowModel } from '../activitypub/actor-follow' 16import { ActorFollowModel } from '../activitypub/actor-follow'
17import { AvatarModel } from '../avatar/avatar' 17import { AvatarModel } from '../avatar/avatar'
18import { ServerModel } from '../server/server' 18import { ServerModel } from '../server/server'
19import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/typings/models/user'
19 20
20enum ScopeNames { 21enum ScopeNames {
21 WITH_ALL = 'WITH_ALL' 22 WITH_ALL = 'WITH_ALL'
@@ -134,13 +135,18 @@ function buildAccountInclude (required: boolean, withActor = false) {
134 ] 135 ]
135 }, 136 },
136 { 137 {
137 attributes: [ 'preferredUsername' ], 138 attributes: [ 'preferredUsername', 'type' ],
138 model: ActorModel.unscoped(), 139 model: ActorModel.unscoped(),
139 required: true, 140 required: true,
140 as: 'ActorFollowing', 141 as: 'ActorFollowing',
141 include: [ 142 include: [
142 buildChannelInclude(false), 143 buildChannelInclude(false),
143 buildAccountInclude(false) 144 buildAccountInclude(false),
145 {
146 attributes: [ 'host' ],
147 model: ServerModel.unscoped(),
148 required: false
149 }
144 ] 150 ]
145 } 151 }
146 ] 152 ]
@@ -371,7 +377,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
371 return UserNotificationModel.update({ read: true }, query) 377 return UserNotificationModel.update({ read: true }, query)
372 } 378 }
373 379
374 toFormattedJSON (): UserNotification { 380 toFormattedJSON (this: UserNotificationModelForApi): UserNotification {
375 const video = this.Video 381 const video = this.Video
376 ? Object.assign(this.formatVideo(this.Video),{ channel: this.formatActor(this.Video.VideoChannel) }) 382 ? Object.assign(this.formatVideo(this.Video),{ channel: this.formatActor(this.Video.VideoChannel) })
377 : undefined 383 : undefined
@@ -403,6 +409,11 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
403 409
404 const account = this.Account ? this.formatActor(this.Account) : undefined 410 const account = this.Account ? this.formatActor(this.Account) : undefined
405 411
412 const actorFollowingType = {
413 Application: 'instance' as 'instance',
414 Group: 'channel' as 'channel',
415 Person: 'account' as 'account'
416 }
406 const actorFollow = this.ActorFollow ? { 417 const actorFollow = this.ActorFollow ? {
407 id: this.ActorFollow.id, 418 id: this.ActorFollow.id,
408 state: this.ActorFollow.state, 419 state: this.ActorFollow.state,
@@ -414,9 +425,10 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
414 host: this.ActorFollow.ActorFollower.getHost() 425 host: this.ActorFollow.ActorFollower.getHost()
415 }, 426 },
416 following: { 427 following: {
417 type: this.ActorFollow.ActorFollowing.VideoChannel ? 'channel' as 'channel' : 'account' as 'account', 428 type: actorFollowingType[this.ActorFollow.ActorFollowing.type],
418 displayName: (this.ActorFollow.ActorFollowing.VideoChannel || this.ActorFollow.ActorFollowing.Account).getDisplayName(), 429 displayName: (this.ActorFollow.ActorFollowing.VideoChannel || this.ActorFollow.ActorFollowing.Account).getDisplayName(),
419 name: this.ActorFollow.ActorFollowing.preferredUsername 430 name: this.ActorFollow.ActorFollowing.preferredUsername,
431 host: this.ActorFollow.ActorFollowing.getHost()
420 } 432 }
421 } : undefined 433 } : undefined
422 434
@@ -436,7 +448,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
436 } 448 }
437 } 449 }
438 450
439 private formatVideo (video: VideoModel) { 451 formatVideo (this: UserNotificationModelForApi, video: UserNotificationIncludes.VideoInclude) {
440 return { 452 return {
441 id: video.id, 453 id: video.id,
442 uuid: video.uuid, 454 uuid: video.uuid,
@@ -444,7 +456,10 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
444 } 456 }
445 } 457 }
446 458
447 private formatActor (accountOrChannel: AccountModel | VideoChannelModel) { 459 formatActor (
460 this: UserNotificationModelForApi,
461 accountOrChannel: UserNotificationIncludes.AccountIncludeActor | UserNotificationIncludes.VideoChannelIncludeActor
462 ) {
448 const avatar = accountOrChannel.Actor.Avatar 463 const avatar = accountOrChannel.Actor.Avatar
449 ? { path: accountOrChannel.Actor.Avatar.getStaticPath() } 464 ? { path: accountOrChannel.Actor.Avatar.getStaticPath() }
450 : undefined 465 : undefined
diff --git a/server/models/account/user-video-history.ts b/server/models/account/user-video-history.ts
index a862fc45f..3fe4c8db1 100644
--- a/server/models/account/user-video-history.ts
+++ b/server/models/account/user-video-history.ts
@@ -1,7 +1,8 @@
1import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Model, Table, UpdatedAt } from 'sequelize-typescript' 1import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Model, Table, UpdatedAt } from 'sequelize-typescript'
2import { VideoModel } from '../video/video' 2import { VideoModel } from '../video/video'
3import { UserModel } from './user' 3import { UserModel } from './user'
4import { Transaction, Op, DestroyOptions } from 'sequelize' 4import { DestroyOptions, Op, Transaction } from 'sequelize'
5import { MUserAccountId, MUserId } from '@server/typings/models'
5 6
6@Table({ 7@Table({
7 tableName: 'userVideoHistory', 8 tableName: 'userVideoHistory',
@@ -54,7 +55,7 @@ export class UserVideoHistoryModel extends Model<UserVideoHistoryModel> {
54 }) 55 })
55 User: UserModel 56 User: UserModel
56 57
57 static listForApi (user: UserModel, start: number, count: number) { 58 static listForApi (user: MUserAccountId, start: number, count: number) {
58 return VideoModel.listForApi({ 59 return VideoModel.listForApi({
59 start, 60 start,
60 count, 61 count,
@@ -67,7 +68,7 @@ export class UserVideoHistoryModel extends Model<UserVideoHistoryModel> {
67 }) 68 })
68 } 69 }
69 70
70 static removeUserHistoryBefore (user: UserModel, beforeDate: string, t: Transaction) { 71 static removeUserHistoryBefore (user: MUserId, beforeDate: string, t: Transaction) {
71 const query: DestroyOptions = { 72 const query: DestroyOptions = {
72 where: { 73 where: {
73 userId: user.id 74 userId: user.id
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 0041bf577..451e1fd6b 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -22,6 +22,7 @@ import {
22import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared' 22import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared'
23import { User, UserRole } from '../../../shared/models/users' 23import { User, UserRole } from '../../../shared/models/users'
24import { 24import {
25 isNoInstanceConfigWarningModal,
25 isUserAdminFlagsValid, 26 isUserAdminFlagsValid,
26 isUserAutoPlayVideoValid, 27 isUserAutoPlayVideoValid,
27 isUserBlockedReasonValid, 28 isUserBlockedReasonValid,
@@ -35,7 +36,8 @@ import {
35 isUserVideoQuotaDailyValid, 36 isUserVideoQuotaDailyValid,
36 isUserVideoQuotaValid, 37 isUserVideoQuotaValid,
37 isUserVideosHistoryEnabledValid, 38 isUserVideosHistoryEnabledValid,
38 isUserWebTorrentEnabledValid 39 isUserWebTorrentEnabledValid,
40 isNoWelcomeModal
39} from '../../helpers/custom-validators/users' 41} from '../../helpers/custom-validators/users'
40import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' 42import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
41import { OAuthTokenModel } from '../oauth/oauth-token' 43import { OAuthTokenModel } from '../oauth/oauth-token'
@@ -54,6 +56,14 @@ import { VideoImportModel } from '../video/video-import'
54import { UserAdminFlag } from '../../../shared/models/users/user-flag.model' 56import { UserAdminFlag } from '../../../shared/models/users/user-flag.model'
55import { isThemeNameValid } from '../../helpers/custom-validators/plugins' 57import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
56import { getThemeOrDefault } from '../../lib/plugins/theme-utils' 58import { getThemeOrDefault } from '../../lib/plugins/theme-utils'
59import * as Bluebird from 'bluebird'
60import {
61 MUserDefault,
62 MUserFormattable,
63 MUserId,
64 MUserNotifSettingChannelDefault,
65 MUserWithNotificationSetting
66} from '@server/typings/models'
57 67
58enum ScopeNames { 68enum ScopeNames {
59 WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' 69 WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL'
@@ -195,6 +205,24 @@ export class UserModel extends Model<UserModel> {
195 @Column 205 @Column
196 theme: string 206 theme: string
197 207
208 @AllowNull(false)
209 @Default(false)
210 @Is(
211 'UserNoInstanceConfigWarningModal',
212 value => throwIfNotValid(value, isNoInstanceConfigWarningModal, 'no instance config warning modal')
213 )
214 @Column
215 noInstanceConfigWarningModal: boolean
216
217 @AllowNull(false)
218 @Default(false)
219 @Is(
220 'UserNoInstanceConfigWarningModal',
221 value => throwIfNotValid(value, isNoWelcomeModal, 'no welcome modal')
222 )
223 @Column
224 noWelcomeModal: boolean
225
198 @CreatedAt 226 @CreatedAt
199 createdAt: Date 227 createdAt: Date
200 228
@@ -303,7 +331,7 @@ export class UserModel extends Model<UserModel> {
303 }) 331 })
304 } 332 }
305 333
306 static listWithRight (right: UserRight) { 334 static listWithRight (right: UserRight): Bluebird<MUserDefault[]> {
307 const roles = Object.keys(USER_ROLE_LABELS) 335 const roles = Object.keys(USER_ROLE_LABELS)
308 .map(k => parseInt(k, 10) as UserRole) 336 .map(k => parseInt(k, 10) as UserRole)
309 .filter(role => hasUserRight(role, right)) 337 .filter(role => hasUserRight(role, right))
@@ -319,7 +347,7 @@ export class UserModel extends Model<UserModel> {
319 return UserModel.findAll(query) 347 return UserModel.findAll(query)
320 } 348 }
321 349
322 static listUserSubscribersOf (actorId: number) { 350 static listUserSubscribersOf (actorId: number): Bluebird<MUserWithNotificationSetting[]> {
323 const query = { 351 const query = {
324 include: [ 352 include: [
325 { 353 {
@@ -358,7 +386,7 @@ export class UserModel extends Model<UserModel> {
358 return UserModel.unscoped().findAll(query) 386 return UserModel.unscoped().findAll(query)
359 } 387 }
360 388
361 static listByUsernames (usernames: string[]) { 389 static listByUsernames (usernames: string[]): Bluebird<MUserDefault[]> {
362 const query = { 390 const query = {
363 where: { 391 where: {
364 username: usernames 392 username: usernames
@@ -368,11 +396,11 @@ export class UserModel extends Model<UserModel> {
368 return UserModel.findAll(query) 396 return UserModel.findAll(query)
369 } 397 }
370 398
371 static loadById (id: number) { 399 static loadById (id: number): Bluebird<MUserDefault> {
372 return UserModel.findByPk(id) 400 return UserModel.findByPk(id)
373 } 401 }
374 402
375 static loadByUsername (username: string) { 403 static loadByUsername (username: string): Bluebird<MUserDefault> {
376 const query = { 404 const query = {
377 where: { 405 where: {
378 username: { [ Op.iLike ]: username } 406 username: { [ Op.iLike ]: username }
@@ -382,7 +410,7 @@ export class UserModel extends Model<UserModel> {
382 return UserModel.findOne(query) 410 return UserModel.findOne(query)
383 } 411 }
384 412
385 static loadByUsernameAndPopulateChannels (username: string) { 413 static loadByUsernameAndPopulateChannels (username: string): Bluebird<MUserNotifSettingChannelDefault> {
386 const query = { 414 const query = {
387 where: { 415 where: {
388 username: { [ Op.iLike ]: username } 416 username: { [ Op.iLike ]: username }
@@ -392,7 +420,7 @@ export class UserModel extends Model<UserModel> {
392 return UserModel.scope(ScopeNames.WITH_VIDEO_CHANNEL).findOne(query) 420 return UserModel.scope(ScopeNames.WITH_VIDEO_CHANNEL).findOne(query)
393 } 421 }
394 422
395 static loadByEmail (email: string) { 423 static loadByEmail (email: string): Bluebird<MUserDefault> {
396 const query = { 424 const query = {
397 where: { 425 where: {
398 email 426 email
@@ -402,7 +430,7 @@ export class UserModel extends Model<UserModel> {
402 return UserModel.findOne(query) 430 return UserModel.findOne(query)
403 } 431 }
404 432
405 static loadByUsernameOrEmail (username: string, email?: string) { 433 static loadByUsernameOrEmail (username: string, email?: string): Bluebird<MUserDefault> {
406 if (!email) email = username 434 if (!email) email = username
407 435
408 const query = { 436 const query = {
@@ -414,7 +442,7 @@ export class UserModel extends Model<UserModel> {
414 return UserModel.findOne(query) 442 return UserModel.findOne(query)
415 } 443 }
416 444
417 static loadByVideoId (videoId: number) { 445 static loadByVideoId (videoId: number): Bluebird<MUserDefault> {
418 const query = { 446 const query = {
419 include: [ 447 include: [
420 { 448 {
@@ -445,7 +473,7 @@ export class UserModel extends Model<UserModel> {
445 return UserModel.findOne(query) 473 return UserModel.findOne(query)
446 } 474 }
447 475
448 static loadByVideoImportId (videoImportId: number) { 476 static loadByVideoImportId (videoImportId: number): Bluebird<MUserDefault> {
449 const query = { 477 const query = {
450 include: [ 478 include: [
451 { 479 {
@@ -462,7 +490,7 @@ export class UserModel extends Model<UserModel> {
462 return UserModel.findOne(query) 490 return UserModel.findOne(query)
463 } 491 }
464 492
465 static loadByChannelActorId (videoChannelActorId: number) { 493 static loadByChannelActorId (videoChannelActorId: number): Bluebird<MUserDefault> {
466 const query = { 494 const query = {
467 include: [ 495 include: [
468 { 496 {
@@ -486,7 +514,7 @@ export class UserModel extends Model<UserModel> {
486 return UserModel.findOne(query) 514 return UserModel.findOne(query)
487 } 515 }
488 516
489 static loadByAccountActorId (accountActorId: number) { 517 static loadByAccountActorId (accountActorId: number): Bluebird<MUserDefault> {
490 const query = { 518 const query = {
491 include: [ 519 include: [
492 { 520 {
@@ -503,7 +531,7 @@ export class UserModel extends Model<UserModel> {
503 return UserModel.findOne(query) 531 return UserModel.findOne(query)
504 } 532 }
505 533
506 static getOriginalVideoFileTotalFromUser (user: UserModel) { 534 static getOriginalVideoFileTotalFromUser (user: MUserId) {
507 // Don't use sequelize because we need to use a sub query 535 // Don't use sequelize because we need to use a sub query
508 const query = UserModel.generateUserQuotaBaseSQL() 536 const query = UserModel.generateUserQuotaBaseSQL()
509 537
@@ -511,7 +539,7 @@ export class UserModel extends Model<UserModel> {
511 } 539 }
512 540
513 // Returns cumulative size of all video files uploaded in the last 24 hours. 541 // Returns cumulative size of all video files uploaded in the last 24 hours.
514 static getOriginalVideoFileTotalDailyFromUser (user: UserModel) { 542 static getOriginalVideoFileTotalDailyFromUser (user: MUserId) {
515 // Don't use sequelize because we need to use a sub query 543 // Don't use sequelize because we need to use a sub query
516 const query = UserModel.generateUserQuotaBaseSQL('"video"."createdAt" > now() - interval \'24 hours\'') 544 const query = UserModel.generateUserQuotaBaseSQL('"video"."createdAt" > now() - interval \'24 hours\'')
517 545
@@ -552,38 +580,52 @@ export class UserModel extends Model<UserModel> {
552 return comparePassword(password, this.password) 580 return comparePassword(password, this.password)
553 } 581 }
554 582
555 toFormattedJSON (parameters: { withAdminFlags?: boolean } = {}): User { 583 toFormattedJSON (this: MUserFormattable, parameters: { withAdminFlags?: boolean } = {}): User {
556 const videoQuotaUsed = this.get('videoQuotaUsed') 584 const videoQuotaUsed = this.get('videoQuotaUsed')
557 const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily') 585 const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
558 586
559 const json = { 587 const json: User = {
560 id: this.id, 588 id: this.id,
561 username: this.username, 589 username: this.username,
562 email: this.email, 590 email: this.email,
591 theme: getThemeOrDefault(this.theme, DEFAULT_USER_THEME_NAME),
592
563 pendingEmail: this.pendingEmail, 593 pendingEmail: this.pendingEmail,
564 emailVerified: this.emailVerified, 594 emailVerified: this.emailVerified,
595
565 nsfwPolicy: this.nsfwPolicy, 596 nsfwPolicy: this.nsfwPolicy,
566 webTorrentEnabled: this.webTorrentEnabled, 597 webTorrentEnabled: this.webTorrentEnabled,
567 videosHistoryEnabled: this.videosHistoryEnabled, 598 videosHistoryEnabled: this.videosHistoryEnabled,
568 autoPlayVideo: this.autoPlayVideo, 599 autoPlayVideo: this.autoPlayVideo,
569 videoLanguages: this.videoLanguages, 600 videoLanguages: this.videoLanguages,
601
570 role: this.role, 602 role: this.role,
571 theme: getThemeOrDefault(this.theme, DEFAULT_USER_THEME_NAME),
572 roleLabel: USER_ROLE_LABELS[ this.role ], 603 roleLabel: USER_ROLE_LABELS[ this.role ],
604
573 videoQuota: this.videoQuota, 605 videoQuota: this.videoQuota,
574 videoQuotaDaily: this.videoQuotaDaily, 606 videoQuotaDaily: this.videoQuotaDaily,
575 createdAt: this.createdAt, 607 videoQuotaUsed: videoQuotaUsed !== undefined
608 ? parseInt(videoQuotaUsed + '', 10)
609 : undefined,
610 videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined
611 ? parseInt(videoQuotaUsedDaily + '', 10)
612 : undefined,
613
614 noInstanceConfigWarningModal: this.noInstanceConfigWarningModal,
615 noWelcomeModal: this.noWelcomeModal,
616
576 blocked: this.blocked, 617 blocked: this.blocked,
577 blockedReason: this.blockedReason, 618 blockedReason: this.blockedReason,
619
578 account: this.Account.toFormattedJSON(), 620 account: this.Account.toFormattedJSON(),
579 notificationSettings: this.NotificationSetting ? this.NotificationSetting.toFormattedJSON() : undefined, 621
622 notificationSettings: this.NotificationSetting
623 ? this.NotificationSetting.toFormattedJSON()
624 : undefined,
625
580 videoChannels: [], 626 videoChannels: [],
581 videoQuotaUsed: videoQuotaUsed !== undefined 627
582 ? parseInt(videoQuotaUsed + '', 10) 628 createdAt: this.createdAt
583 : undefined,
584 videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined
585 ? parseInt(videoQuotaUsedDaily + '', 10)
586 : undefined
587 } 629 }
588 630
589 if (parameters.withAdminFlags) { 631 if (parameters.withAdminFlags) {