aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/account/user.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/account/user.ts')
-rw-r--r--server/models/account/user.ts217
1 files changed, 207 insertions, 10 deletions
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index e56b0bf40..017a96657 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -1,6 +1,6 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { 2import {
3 AfterDelete, 3 AfterDestroy,
4 AfterUpdate, 4 AfterUpdate,
5 AllowNull, 5 AllowNull,
6 BeforeCreate, 6 BeforeCreate,
@@ -31,7 +31,9 @@ import {
31 isUserRoleValid, 31 isUserRoleValid,
32 isUserUsernameValid, 32 isUserUsernameValid,
33 isUserVideoQuotaDailyValid, 33 isUserVideoQuotaDailyValid,
34 isUserVideoQuotaValid 34 isUserVideoQuotaValid,
35 isUserVideosHistoryEnabledValid,
36 isUserWebTorrentEnabledValid
35} from '../../helpers/custom-validators/users' 37} from '../../helpers/custom-validators/users'
36import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' 38import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
37import { OAuthTokenModel } from '../oauth/oauth-token' 39import { OAuthTokenModel } from '../oauth/oauth-token'
@@ -42,6 +44,11 @@ import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type'
42import { values } from 'lodash' 44import { values } from 'lodash'
43import { NSFW_POLICY_TYPES } from '../../initializers' 45import { NSFW_POLICY_TYPES } from '../../initializers'
44import { clearCacheByUserId } from '../../lib/oauth-model' 46import { clearCacheByUserId } from '../../lib/oauth-model'
47import { UserNotificationSettingModel } from './user-notification-setting'
48import { VideoModel } from '../video/video'
49import { ActorModel } from '../activitypub/actor'
50import { ActorFollowModel } from '../activitypub/actor-follow'
51import { VideoImportModel } from '../video/video-import'
45 52
46enum ScopeNames { 53enum ScopeNames {
47 WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' 54 WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL'
@@ -52,6 +59,10 @@ enum ScopeNames {
52 { 59 {
53 model: () => AccountModel, 60 model: () => AccountModel,
54 required: true 61 required: true
62 },
63 {
64 model: () => UserNotificationSettingModel,
65 required: true
55 } 66 }
56 ] 67 ]
57}) 68})
@@ -62,6 +73,10 @@ enum ScopeNames {
62 model: () => AccountModel, 73 model: () => AccountModel,
63 required: true, 74 required: true,
64 include: [ () => VideoChannelModel ] 75 include: [ () => VideoChannelModel ]
76 },
77 {
78 model: () => UserNotificationSettingModel,
79 required: true
65 } 80 }
66 ] 81 ]
67 } 82 }
@@ -109,6 +124,18 @@ export class UserModel extends Model<UserModel> {
109 124
110 @AllowNull(false) 125 @AllowNull(false)
111 @Default(true) 126 @Default(true)
127 @Is('UserWebTorrentEnabled', value => throwIfNotValid(value, isUserWebTorrentEnabledValid, 'WebTorrent enabled'))
128 @Column
129 webTorrentEnabled: boolean
130
131 @AllowNull(false)
132 @Default(true)
133 @Is('UserVideosHistoryEnabled', value => throwIfNotValid(value, isUserVideosHistoryEnabledValid, 'Videos history enabled'))
134 @Column
135 videosHistoryEnabled: boolean
136
137 @AllowNull(false)
138 @Default(true)
112 @Is('UserAutoPlayVideo', value => throwIfNotValid(value, isUserAutoPlayVideoValid, 'auto play video boolean')) 139 @Is('UserAutoPlayVideo', value => throwIfNotValid(value, isUserAutoPlayVideoValid, 'auto play video boolean'))
113 @Column 140 @Column
114 autoPlayVideo: boolean 141 autoPlayVideo: boolean
@@ -153,6 +180,19 @@ export class UserModel extends Model<UserModel> {
153 }) 180 })
154 Account: AccountModel 181 Account: AccountModel
155 182
183 @HasOne(() => UserNotificationSettingModel, {
184 foreignKey: 'userId',
185 onDelete: 'cascade',
186 hooks: true
187 })
188 NotificationSetting: UserNotificationSettingModel
189
190 @HasMany(() => VideoImportModel, {
191 foreignKey: 'userId',
192 onDelete: 'cascade'
193 })
194 VideoImports: VideoImportModel[]
195
156 @HasMany(() => OAuthTokenModel, { 196 @HasMany(() => OAuthTokenModel, {
157 foreignKey: 'userId', 197 foreignKey: 'userId',
158 onDelete: 'cascade' 198 onDelete: 'cascade'
@@ -172,7 +212,7 @@ export class UserModel extends Model<UserModel> {
172 } 212 }
173 213
174 @AfterUpdate 214 @AfterUpdate
175 @AfterDelete 215 @AfterDestroy
176 static removeTokenCache (instance: UserModel) { 216 static removeTokenCache (instance: UserModel) {
177 return clearCacheByUserId(instance.id) 217 return clearCacheByUserId(instance.id)
178 } 218 }
@@ -181,7 +221,25 @@ export class UserModel extends Model<UserModel> {
181 return this.count() 221 return this.count()
182 } 222 }
183 223
184 static listForApi (start: number, count: number, sort: string) { 224 static listForApi (start: number, count: number, sort: string, search?: string) {
225 let where = undefined
226 if (search) {
227 where = {
228 [Sequelize.Op.or]: [
229 {
230 email: {
231 [Sequelize.Op.iLike]: '%' + search + '%'
232 }
233 },
234 {
235 username: {
236 [ Sequelize.Op.iLike ]: '%' + search + '%'
237 }
238 }
239 ]
240 }
241 }
242
185 const query = { 243 const query = {
186 attributes: { 244 attributes: {
187 include: [ 245 include: [
@@ -204,7 +262,8 @@ export class UserModel extends Model<UserModel> {
204 }, 262 },
205 offset: start, 263 offset: start,
206 limit: count, 264 limit: count,
207 order: getSort(sort) 265 order: getSort(sort),
266 where
208 } 267 }
209 268
210 return UserModel.findAndCountAll(query) 269 return UserModel.findAndCountAll(query)
@@ -216,13 +275,12 @@ export class UserModel extends Model<UserModel> {
216 }) 275 })
217 } 276 }
218 277
219 static listEmailsWithRight (right: UserRight) { 278 static listWithRight (right: UserRight) {
220 const roles = Object.keys(USER_ROLE_LABELS) 279 const roles = Object.keys(USER_ROLE_LABELS)
221 .map(k => parseInt(k, 10) as UserRole) 280 .map(k => parseInt(k, 10) as UserRole)
222 .filter(role => hasUserRight(role, right)) 281 .filter(role => hasUserRight(role, right))
223 282
224 const query = { 283 const query = {
225 attribute: [ 'email' ],
226 where: { 284 where: {
227 role: { 285 role: {
228 [Sequelize.Op.in]: roles 286 [Sequelize.Op.in]: roles
@@ -230,9 +288,56 @@ export class UserModel extends Model<UserModel> {
230 } 288 }
231 } 289 }
232 290
233 return UserModel.unscoped() 291 return UserModel.findAll(query)
234 .findAll(query) 292 }
235 .then(u => u.map(u => u.email)) 293
294 static listUserSubscribersOf (actorId: number) {
295 const query = {
296 include: [
297 {
298 model: UserNotificationSettingModel.unscoped(),
299 required: true
300 },
301 {
302 attributes: [ 'userId' ],
303 model: AccountModel.unscoped(),
304 required: true,
305 include: [
306 {
307 attributes: [ ],
308 model: ActorModel.unscoped(),
309 required: true,
310 where: {
311 serverId: null
312 },
313 include: [
314 {
315 attributes: [ ],
316 as: 'ActorFollowings',
317 model: ActorFollowModel.unscoped(),
318 required: true,
319 where: {
320 targetActorId: actorId
321 }
322 }
323 ]
324 }
325 ]
326 }
327 ]
328 }
329
330 return UserModel.unscoped().findAll(query)
331 }
332
333 static listByUsernames (usernames: string[]) {
334 const query = {
335 where: {
336 username: usernames
337 }
338 }
339
340 return UserModel.findAll(query)
236 } 341 }
237 342
238 static loadById (id: number) { 343 static loadById (id: number) {
@@ -281,6 +386,95 @@ export class UserModel extends Model<UserModel> {
281 return UserModel.findOne(query) 386 return UserModel.findOne(query)
282 } 387 }
283 388
389 static loadByVideoId (videoId: number) {
390 const query = {
391 include: [
392 {
393 required: true,
394 attributes: [ 'id' ],
395 model: AccountModel.unscoped(),
396 include: [
397 {
398 required: true,
399 attributes: [ 'id' ],
400 model: VideoChannelModel.unscoped(),
401 include: [
402 {
403 required: true,
404 attributes: [ 'id' ],
405 model: VideoModel.unscoped(),
406 where: {
407 id: videoId
408 }
409 }
410 ]
411 }
412 ]
413 }
414 ]
415 }
416
417 return UserModel.findOne(query)
418 }
419
420 static loadByVideoImportId (videoImportId: number) {
421 const query = {
422 include: [
423 {
424 required: true,
425 attributes: [ 'id' ],
426 model: VideoImportModel.unscoped(),
427 where: {
428 id: videoImportId
429 }
430 }
431 ]
432 }
433
434 return UserModel.findOne(query)
435 }
436
437 static loadByChannelActorId (videoChannelActorId: number) {
438 const query = {
439 include: [
440 {
441 required: true,
442 attributes: [ 'id' ],
443 model: AccountModel.unscoped(),
444 include: [
445 {
446 required: true,
447 attributes: [ 'id' ],
448 model: VideoChannelModel.unscoped(),
449 where: {
450 actorId: videoChannelActorId
451 }
452 }
453 ]
454 }
455 ]
456 }
457
458 return UserModel.findOne(query)
459 }
460
461 static loadByAccountActorId (accountActorId: number) {
462 const query = {
463 include: [
464 {
465 required: true,
466 attributes: [ 'id' ],
467 model: AccountModel.unscoped(),
468 where: {
469 actorId: accountActorId
470 }
471 }
472 ]
473 }
474
475 return UserModel.findOne(query)
476 }
477
284 static getOriginalVideoFileTotalFromUser (user: UserModel) { 478 static getOriginalVideoFileTotalFromUser (user: UserModel) {
285 // Don't use sequelize because we need to use a sub query 479 // Don't use sequelize because we need to use a sub query
286 const query = UserModel.generateUserQuotaBaseSQL() 480 const query = UserModel.generateUserQuotaBaseSQL()
@@ -336,6 +530,8 @@ export class UserModel extends Model<UserModel> {
336 email: this.email, 530 email: this.email,
337 emailVerified: this.emailVerified, 531 emailVerified: this.emailVerified,
338 nsfwPolicy: this.nsfwPolicy, 532 nsfwPolicy: this.nsfwPolicy,
533 webTorrentEnabled: this.webTorrentEnabled,
534 videosHistoryEnabled: this.videosHistoryEnabled,
339 autoPlayVideo: this.autoPlayVideo, 535 autoPlayVideo: this.autoPlayVideo,
340 role: this.role, 536 role: this.role,
341 roleLabel: USER_ROLE_LABELS[ this.role ], 537 roleLabel: USER_ROLE_LABELS[ this.role ],
@@ -345,6 +541,7 @@ export class UserModel extends Model<UserModel> {
345 blocked: this.blocked, 541 blocked: this.blocked,
346 blockedReason: this.blockedReason, 542 blockedReason: this.blockedReason,
347 account: this.Account.toFormattedJSON(), 543 account: this.Account.toFormattedJSON(),
544 notificationSettings: this.NotificationSetting ? this.NotificationSetting.toFormattedJSON() : undefined,
348 videoChannels: [], 545 videoChannels: [],
349 videoQuotaUsed: videoQuotaUsed !== undefined 546 videoQuotaUsed: videoQuotaUsed !== undefined
350 ? parseInt(videoQuotaUsed, 10) 547 ? parseInt(videoQuotaUsed, 10)