diff options
Diffstat (limited to 'server/models/account/user.ts')
-rw-r--r-- | server/models/account/user.ts | 217 |
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 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { | 2 | import { |
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' |
36 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' | 38 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' |
37 | import { OAuthTokenModel } from '../oauth/oauth-token' | 39 | import { OAuthTokenModel } from '../oauth/oauth-token' |
@@ -42,6 +44,11 @@ import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type' | |||
42 | import { values } from 'lodash' | 44 | import { values } from 'lodash' |
43 | import { NSFW_POLICY_TYPES } from '../../initializers' | 45 | import { NSFW_POLICY_TYPES } from '../../initializers' |
44 | import { clearCacheByUserId } from '../../lib/oauth-model' | 46 | import { clearCacheByUserId } from '../../lib/oauth-model' |
47 | import { UserNotificationSettingModel } from './user-notification-setting' | ||
48 | import { VideoModel } from '../video/video' | ||
49 | import { ActorModel } from '../activitypub/actor' | ||
50 | import { ActorFollowModel } from '../activitypub/actor-follow' | ||
51 | import { VideoImportModel } from '../video/video-import' | ||
45 | 52 | ||
46 | enum ScopeNames { | 53 | enum 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) |