2019-04-23 07:50:57 +00:00
import { FindOptions , literal , Op , QueryTypes } from 'sequelize'
2017-12-12 16:53:50 +00:00
import {
2018-11-19 16:08:18 +00:00
AfterDestroy ,
2018-09-20 09:31:48 +00:00
AfterUpdate ,
2018-03-01 12:02:09 +00:00
AllowNull ,
BeforeCreate ,
BeforeUpdate ,
Column ,
CreatedAt ,
DataType ,
Default ,
DefaultScope ,
HasMany ,
HasOne ,
Is ,
IsEmail ,
Model ,
Scopes ,
Table ,
UpdatedAt
2017-12-12 16:53:50 +00:00
} from 'sequelize-typescript'
2020-01-02 12:07:18 +00:00
import { hasUserRight , USER_ROLE_LABELS , UserRight , VideoPrivacy , MyUser } from '../../../shared'
2018-02-01 10:08:10 +00:00
import { User , UserRole } from '../../../shared/models/users'
2017-05-15 20:22:03 +00:00
import {
2019-08-28 12:40:06 +00:00
isNoInstanceConfigWarningModal ,
2019-04-15 08:49:46 +00:00
isUserAdminFlagsValid ,
2018-03-01 12:02:09 +00:00
isUserAutoPlayVideoValid ,
2019-09-24 06:48:01 +00:00
isUserAutoPlayNextVideoValid ,
2019-12-11 19:20:42 +00:00
isUserAutoPlayNextVideoPlaylistValid ,
2018-08-08 15:36:10 +00:00
isUserBlockedReasonValid ,
2018-08-08 12:58:21 +00:00
isUserBlockedValid ,
2018-08-31 07:18:19 +00:00
isUserEmailVerifiedValid ,
2018-09-04 08:22:10 +00:00
isUserNSFWPolicyValid ,
2018-03-01 12:02:09 +00:00
isUserPasswordValid ,
isUserRoleValid ,
isUserUsernameValid ,
2019-06-19 12:55:58 +00:00
isUserVideoLanguages ,
2018-09-04 08:22:10 +00:00
isUserVideoQuotaDailyValid ,
2018-10-05 13:17:34 +00:00
isUserVideoQuotaValid ,
2018-12-26 09:36:24 +00:00
isUserVideosHistoryEnabledValid ,
2019-08-28 12:40:06 +00:00
isUserWebTorrentEnabledValid ,
isNoWelcomeModal
2017-12-12 16:53:50 +00:00
} from '../../helpers/custom-validators/users'
2017-12-28 10:16:08 +00:00
import { comparePassword , cryptPassword } from '../../helpers/peertube-crypto'
2017-12-12 16:53:50 +00:00
import { OAuthTokenModel } from '../oauth/oauth-token'
import { getSort , throwIfNotValid } from '../utils'
import { VideoChannelModel } from '../video/video-channel'
2020-01-02 12:07:18 +00:00
import { VideoPlaylistModel } from '../video/video-playlist'
2017-12-12 16:53:50 +00:00
import { AccountModel } from './account'
2018-04-19 09:01:34 +00:00
import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type'
import { values } from 'lodash'
2019-07-10 12:06:19 +00:00
import { DEFAULT_THEME_NAME , DEFAULT_USER_THEME_NAME , NSFW_POLICY_TYPES } from '../../initializers/constants'
2018-09-20 09:31:48 +00:00
import { clearCacheByUserId } from '../../lib/oauth-model'
2018-12-26 09:36:24 +00:00
import { UserNotificationSettingModel } from './user-notification-setting'
import { VideoModel } from '../video/video'
import { ActorModel } from '../activitypub/actor'
import { ActorFollowModel } from '../activitypub/actor-follow'
2019-01-02 15:37:43 +00:00
import { VideoImportModel } from '../video/video-import'
2019-04-15 08:49:46 +00:00
import { UserAdminFlag } from '../../../shared/models/users/user-flag.model'
2019-07-15 13:41:56 +00:00
import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
2019-07-09 09:45:19 +00:00
import { getThemeOrDefault } from '../../lib/plugins/theme-utils'
2019-08-15 09:53:26 +00:00
import * as Bluebird from 'bluebird'
2019-08-20 17:05:31 +00:00
import {
MUserDefault ,
MUserFormattable ,
MUserId ,
MUserNotifSettingChannelDefault ,
2019-12-12 14:47:47 +00:00
MUserWithNotificationSetting , MVideoFullLight
2019-08-20 17:05:31 +00:00
} from '@server/typings/models'
2017-12-12 16:53:50 +00:00
2018-06-19 12:02:57 +00:00
enum ScopeNames {
2020-01-02 12:07:18 +00:00
WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' ,
WITH_SPECIAL_PLAYLISTS = 'WITH_SPECIAL_PLAYLISTS'
2018-06-19 12:02:57 +00:00
}
2019-04-23 07:50:57 +00:00
@DefaultScope ( ( ) = > ( {
2017-12-14 09:07:57 +00:00
include : [
{
2019-04-23 07:50:57 +00:00
model : AccountModel ,
2017-12-14 09:07:57 +00:00
required : true
2018-12-26 09:36:24 +00:00
} ,
{
2019-04-23 07:50:57 +00:00
model : UserNotificationSettingModel ,
2018-12-26 09:36:24 +00:00
required : true
2017-12-14 09:07:57 +00:00
}
]
2019-04-23 07:50:57 +00:00
} ) )
@Scopes ( ( ) = > ( {
2018-06-19 12:02:57 +00:00
[ ScopeNames . WITH_VIDEO_CHANNEL ] : {
2017-12-14 09:07:57 +00:00
include : [
{
2019-04-23 07:50:57 +00:00
model : AccountModel ,
2017-12-14 09:07:57 +00:00
required : true ,
2019-04-23 07:50:57 +00:00
include : [ VideoChannelModel ]
2018-12-26 09:36:24 +00:00
} ,
{
2019-04-23 07:50:57 +00:00
model : UserNotificationSettingModel ,
2018-12-26 09:36:24 +00:00
required : true
2017-12-14 09:07:57 +00:00
}
2019-04-23 07:50:57 +00:00
]
2020-01-02 12:07:18 +00:00
} ,
[ ScopeNames . WITH_SPECIAL_PLAYLISTS ] : {
attributes : {
include : [
[
literal ( '(select array(select "id" from "videoPlaylist" where "ownerAccountId" in (select id from public.account where "userId" = "UserModel"."id") and name LIKE \'Watch later\'))' ) ,
'specialPlaylists'
]
]
}
2017-12-14 09:07:57 +00:00
}
2019-04-23 07:50:57 +00:00
} ) )
2017-12-12 16:53:50 +00:00
@Table ( {
tableName : 'user' ,
indexes : [
2016-12-11 20:50:51 +00:00
{
2017-12-12 16:53:50 +00:00
fields : [ 'username' ] ,
unique : true
2016-12-11 20:50:51 +00:00
} ,
{
2017-12-12 16:53:50 +00:00
fields : [ 'email' ] ,
unique : true
2016-12-11 20:50:51 +00:00
}
2017-05-22 18:58:25 +00:00
]
2017-12-12 16:53:50 +00:00
} )
export class UserModel extends Model < UserModel > {
@AllowNull ( false )
@Is ( 'UserPassword' , value = > throwIfNotValid ( value , isUserPasswordValid , 'user password' ) )
@Column
password : string
@AllowNull ( false )
@Is ( 'UserPassword' , value = > throwIfNotValid ( value , isUserUsernameValid , 'user name' ) )
@Column
username : string
@AllowNull ( false )
@IsEmail
@Column ( DataType . STRING ( 400 ) )
email : string
2019-06-11 09:54:33 +00:00
@AllowNull ( true )
@IsEmail
@Column ( DataType . STRING ( 400 ) )
pendingEmail : string
2018-08-31 07:18:19 +00:00
@AllowNull ( true )
@Default ( null )
2019-04-18 09:28:17 +00:00
@Is ( 'UserEmailVerified' , value = > throwIfNotValid ( value , isUserEmailVerifiedValid , 'email verified boolean' , true ) )
2018-08-31 07:18:19 +00:00
@Column
emailVerified : boolean
2017-12-12 16:53:50 +00:00
@AllowNull ( false )
2018-04-19 09:01:34 +00:00
@Is ( 'UserNSFWPolicy' , value = > throwIfNotValid ( value , isUserNSFWPolicyValid , 'NSFW policy' ) )
2019-04-18 09:28:17 +00:00
@Column ( DataType . ENUM ( . . . values ( NSFW_POLICY_TYPES ) ) )
2018-04-19 09:01:34 +00:00
nsfwPolicy : NSFWPolicyType
2017-12-12 16:53:50 +00:00
2018-10-05 13:17:34 +00:00
@AllowNull ( false )
2018-10-17 11:10:58 +00:00
@Default ( true )
2018-10-12 16:12:39 +00:00
@Is ( 'UserWebTorrentEnabled' , value = > throwIfNotValid ( value , isUserWebTorrentEnabledValid , 'WebTorrent enabled' ) )
@Column
webTorrentEnabled : boolean
2018-10-05 13:17:34 +00:00
2018-12-17 14:52:38 +00:00
@AllowNull ( false )
@Default ( true )
@Is ( 'UserVideosHistoryEnabled' , value = > throwIfNotValid ( value , isUserVideosHistoryEnabledValid , 'Videos history enabled' ) )
@Column
videosHistoryEnabled : boolean
2017-12-19 09:45:49 +00:00
@AllowNull ( false )
@Default ( true )
@Is ( 'UserAutoPlayVideo' , value = > throwIfNotValid ( value , isUserAutoPlayVideoValid , 'auto play video boolean' ) )
@Column
autoPlayVideo : boolean
2019-09-24 06:48:01 +00:00
@AllowNull ( false )
@Default ( false )
@Is ( 'UserAutoPlayNextVideo' , value = > throwIfNotValid ( value , isUserAutoPlayNextVideoValid , 'auto play next video boolean' ) )
@Column
autoPlayNextVideo : boolean
2019-12-11 19:20:42 +00:00
@AllowNull ( false )
@Default ( true )
@Is ( 'UserAutoPlayNextVideoPlaylist' , value = > throwIfNotValid ( value , isUserAutoPlayNextVideoPlaylistValid , 'auto play next video for playlists boolean' ) )
@Column
autoPlayNextVideoPlaylist : boolean
2019-06-19 12:55:58 +00:00
@AllowNull ( true )
@Default ( null )
@Is ( 'UserVideoLanguages' , value = > throwIfNotValid ( value , isUserVideoLanguages , 'video languages' ) )
@Column ( DataType . ARRAY ( DataType . STRING ) )
videoLanguages : string [ ]
2019-04-15 08:49:46 +00:00
@AllowNull ( false )
@Default ( UserAdminFlag . NONE )
@Is ( 'UserAdminFlags' , value = > throwIfNotValid ( value , isUserAdminFlagsValid , 'user admin flags' ) )
@Column
adminFlags? : UserAdminFlag
2018-08-08 12:58:21 +00:00
@AllowNull ( false )
@Default ( false )
@Is ( 'UserBlocked' , value = > throwIfNotValid ( value , isUserBlockedValid , 'blocked boolean' ) )
@Column
blocked : boolean
2018-08-08 15:36:10 +00:00
@AllowNull ( true )
@Default ( null )
2019-04-18 09:28:17 +00:00
@Is ( 'UserBlockedReason' , value = > throwIfNotValid ( value , isUserBlockedReasonValid , 'blocked reason' , true ) )
2018-08-08 15:36:10 +00:00
@Column
blockedReason : string
2017-12-12 16:53:50 +00:00
@AllowNull ( false )
@Is ( 'UserRole' , value = > throwIfNotValid ( value , isUserRoleValid , 'role' ) )
@Column
role : number
@AllowNull ( false )
@Is ( 'UserVideoQuota' , value = > throwIfNotValid ( value , isUserVideoQuotaValid , 'video quota' ) )
@Column ( DataType . BIGINT )
videoQuota : number
2018-08-28 07:01:35 +00:00
@AllowNull ( false )
@Is ( 'UserVideoQuotaDaily' , value = > throwIfNotValid ( value , isUserVideoQuotaDailyValid , 'video quota daily' ) )
@Column ( DataType . BIGINT )
videoQuotaDaily : number
2019-07-09 09:45:19 +00:00
@AllowNull ( false )
2019-07-10 12:06:19 +00:00
@Default ( DEFAULT_THEME_NAME )
2019-07-15 13:41:56 +00:00
@Is ( 'UserTheme' , value = > throwIfNotValid ( value , isThemeNameValid , 'theme' ) )
2019-07-09 09:45:19 +00:00
@Column
theme : string
2019-08-28 12:40:06 +00:00
@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
2017-12-12 16:53:50 +00:00
@CreatedAt
createdAt : Date
@UpdatedAt
updatedAt : Date
@HasOne ( ( ) = > AccountModel , {
foreignKey : 'userId' ,
2018-01-18 09:53:54 +00:00
onDelete : 'cascade' ,
hooks : true
2017-12-12 16:53:50 +00:00
} )
Account : AccountModel
2016-07-01 14:03:53 +00:00
2018-12-26 09:36:24 +00:00
@HasOne ( ( ) = > UserNotificationSettingModel , {
foreignKey : 'userId' ,
onDelete : 'cascade' ,
hooks : true
} )
NotificationSetting : UserNotificationSettingModel
2019-01-02 15:37:43 +00:00
@HasMany ( ( ) = > VideoImportModel , {
foreignKey : 'userId' ,
onDelete : 'cascade'
} )
VideoImports : VideoImportModel [ ]
2017-12-12 16:53:50 +00:00
@HasMany ( ( ) = > OAuthTokenModel , {
foreignKey : 'userId' ,
onDelete : 'cascade'
} )
OAuthTokens : OAuthTokenModel [ ]
@BeforeCreate
@BeforeUpdate
static cryptPasswordIfNeeded ( instance : UserModel ) {
if ( instance . changed ( 'password' ) ) {
return cryptPassword ( instance . password )
. then ( hash = > {
instance . password = hash
return undefined
} )
}
2017-11-04 17:09:23 +00:00
}
2016-08-25 15:57:37 +00:00
2018-09-20 09:31:48 +00:00
@AfterUpdate
2018-11-19 16:08:18 +00:00
@AfterDestroy
2018-09-20 09:31:48 +00:00
static removeTokenCache ( instance : UserModel ) {
return clearCacheByUserId ( instance . id )
}
2017-12-12 16:53:50 +00:00
static countTotal ( ) {
return this . count ( )
}
2017-10-27 14:55:03 +00:00
2018-10-08 13:51:38 +00:00
static listForApi ( start : number , count : number , sort : string , search? : string ) {
let where = undefined
if ( search ) {
where = {
2019-04-23 07:50:57 +00:00
[ Op . or ] : [
2018-10-08 13:51:38 +00:00
{
email : {
2019-04-23 07:50:57 +00:00
[ Op . iLike ] : '%' + search + '%'
2018-10-08 13:51:38 +00:00
}
} ,
{
username : {
2019-04-23 07:50:57 +00:00
[ Op . iLike ] : '%' + search + '%'
2018-10-08 13:51:38 +00:00
}
}
]
}
}
2019-04-23 07:50:57 +00:00
const query : FindOptions = {
2018-08-14 15:56:51 +00:00
attributes : {
include : [
[
2019-04-23 07:50:57 +00:00
literal (
2018-08-14 15:56:51 +00:00
'(' +
2018-08-28 16:29:29 +00:00
'SELECT COALESCE(SUM("size"), 0) ' +
'FROM (' +
2018-08-14 15:56:51 +00:00
'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' +
') t' +
')'
) ,
'videoQuotaUsed'
2019-04-23 07:50:57 +00:00
]
2018-08-14 15:56:51 +00:00
]
} ,
2017-12-12 16:53:50 +00:00
offset : start ,
limit : count ,
2018-10-08 13:51:38 +00:00
order : getSort ( sort ) ,
where
2017-12-12 16:53:50 +00:00
}
2017-10-24 17:41:09 +00:00
2017-12-12 16:53:50 +00:00
return UserModel . findAndCountAll ( query )
. then ( ( { rows , count } ) = > {
return {
data : rows ,
total : count
}
2017-10-24 17:41:09 +00:00
} )
}
2019-08-15 09:53:26 +00:00
static listWithRight ( right : UserRight ) : Bluebird < MUserDefault [ ] > {
2018-02-01 10:08:10 +00:00
const roles = Object . keys ( USER_ROLE_LABELS )
. map ( k = > parseInt ( k , 10 ) as UserRole )
. filter ( role = > hasUserRight ( role , right ) )
const query = {
where : {
role : {
2019-04-23 07:50:57 +00:00
[ Op . in ] : roles
2018-02-01 10:08:10 +00:00
}
}
}
2018-12-26 09:36:24 +00:00
return UserModel . findAll ( query )
}
2019-08-15 09:53:26 +00:00
static listUserSubscribersOf ( actorId : number ) : Bluebird < MUserWithNotificationSetting [ ] > {
2018-12-26 09:36:24 +00:00
const query = {
include : [
{
model : UserNotificationSettingModel.unscoped ( ) ,
required : true
} ,
{
attributes : [ 'userId' ] ,
model : AccountModel.unscoped ( ) ,
required : true ,
include : [
{
attributes : [ ] ,
model : ActorModel.unscoped ( ) ,
required : true ,
where : {
serverId : null
} ,
include : [
{
attributes : [ ] ,
as : 'ActorFollowings' ,
model : ActorFollowModel.unscoped ( ) ,
required : true ,
where : {
targetActorId : actorId
}
}
]
}
]
}
]
}
return UserModel . unscoped ( ) . findAll ( query )
2018-02-01 10:08:10 +00:00
}
2019-08-15 09:53:26 +00:00
static listByUsernames ( usernames : string [ ] ) : Bluebird < MUserDefault [ ] > {
2019-01-04 07:56:20 +00:00
const query = {
where : {
username : usernames
}
}
return UserModel . findAll ( query )
}
2019-08-15 09:53:26 +00:00
static loadById ( id : number ) : Bluebird < MUserDefault > {
2019-02-21 13:28:06 +00:00
return UserModel . findByPk ( id )
2017-12-12 16:53:50 +00:00
}
2016-12-11 20:50:51 +00:00
2019-08-15 09:53:26 +00:00
static loadByUsername ( username : string ) : Bluebird < MUserDefault > {
2017-12-12 16:53:50 +00:00
const query = {
where : {
2019-07-02 09:16:33 +00:00
username : { [ Op . iLike ] : username }
2017-12-14 09:07:57 +00:00
}
2017-12-12 16:53:50 +00:00
}
2016-08-16 19:51:35 +00:00
2017-12-12 16:53:50 +00:00
return UserModel . findOne ( query )
2016-12-11 20:50:51 +00:00
}
2019-08-20 11:52:49 +00:00
static loadByUsernameAndPopulateChannels ( username : string ) : Bluebird < MUserNotifSettingChannelDefault > {
2017-12-12 16:53:50 +00:00
const query = {
where : {
2019-07-02 09:16:33 +00:00
username : { [ Op . iLike ] : username }
2017-12-14 09:07:57 +00:00
}
2017-12-12 16:53:50 +00:00
}
2016-08-04 20:32:36 +00:00
2020-01-02 12:07:18 +00:00
return UserModel . scope ( [
ScopeNames . WITH_VIDEO_CHANNEL ,
ScopeNames . WITH_SPECIAL_PLAYLISTS
] ) . findOne ( query )
2016-12-11 20:50:51 +00:00
}
2019-08-15 09:53:26 +00:00
static loadByEmail ( email : string ) : Bluebird < MUserDefault > {
2018-01-30 12:27:07 +00:00
const query = {
where : {
email
}
}
return UserModel . findOne ( query )
}
2019-08-15 09:53:26 +00:00
static loadByUsernameOrEmail ( username : string , email? : string ) : Bluebird < MUserDefault > {
2018-01-29 15:09:50 +00:00
if ( ! email ) email = username
2017-12-12 16:53:50 +00:00
const query = {
where : {
2019-07-02 09:16:33 +00:00
[ Op . or ] : [ { username : { [ Op . iLike ] : username } } , { email } ]
2017-12-12 16:53:50 +00:00
}
2017-07-05 11:26:25 +00:00
}
2016-07-01 14:03:53 +00:00
2017-12-14 09:07:57 +00:00
return UserModel . findOne ( query )
2017-10-24 17:41:09 +00:00
}
2019-08-15 09:53:26 +00:00
static loadByVideoId ( videoId : number ) : Bluebird < MUserDefault > {
2018-12-26 09:36:24 +00:00
const query = {
include : [
{
required : true ,
attributes : [ 'id' ] ,
model : AccountModel.unscoped ( ) ,
include : [
{
required : true ,
attributes : [ 'id' ] ,
model : VideoChannelModel.unscoped ( ) ,
include : [
{
required : true ,
attributes : [ 'id' ] ,
model : VideoModel.unscoped ( ) ,
where : {
id : videoId
}
}
]
}
]
}
]
}
return UserModel . findOne ( query )
}
2019-08-15 09:53:26 +00:00
static loadByVideoImportId ( videoImportId : number ) : Bluebird < MUserDefault > {
2019-01-02 15:37:43 +00:00
const query = {
include : [
{
required : true ,
attributes : [ 'id' ] ,
model : VideoImportModel.unscoped ( ) ,
where : {
id : videoImportId
}
}
]
}
return UserModel . findOne ( query )
}
2019-08-15 09:53:26 +00:00
static loadByChannelActorId ( videoChannelActorId : number ) : Bluebird < MUserDefault > {
2019-01-04 07:56:20 +00:00
const query = {
include : [
{
required : true ,
attributes : [ 'id' ] ,
model : AccountModel.unscoped ( ) ,
include : [
{
required : true ,
attributes : [ 'id' ] ,
model : VideoChannelModel.unscoped ( ) ,
where : {
actorId : videoChannelActorId
}
}
]
}
]
}
return UserModel . findOne ( query )
}
2019-08-15 09:53:26 +00:00
static loadByAccountActorId ( accountActorId : number ) : Bluebird < MUserDefault > {
2019-01-04 07:56:20 +00:00
const query = {
include : [
{
required : true ,
attributes : [ 'id' ] ,
model : AccountModel.unscoped ( ) ,
where : {
actorId : accountActorId
}
}
]
}
return UserModel . findOne ( query )
}
2019-08-15 09:53:26 +00:00
static getOriginalVideoFileTotalFromUser ( user : MUserId ) {
2017-12-12 16:53:50 +00:00
// Don't use sequelize because we need to use a sub query
2018-08-28 16:29:29 +00:00
const query = UserModel . generateUserQuotaBaseSQL ( )
2018-08-28 07:01:35 +00:00
2018-08-28 16:29:29 +00:00
return UserModel . getTotalRawQuery ( query , user . id )
2018-08-28 07:01:35 +00:00
}
2018-08-28 16:29:29 +00:00
// Returns cumulative size of all video files uploaded in the last 24 hours.
2019-08-15 09:53:26 +00:00
static getOriginalVideoFileTotalDailyFromUser ( user : MUserId ) {
2018-08-28 07:01:35 +00:00
// Don't use sequelize because we need to use a sub query
2018-08-28 16:29:29 +00:00
const query = UserModel . generateUserQuotaBaseSQL ( '"video"."createdAt" > now() - interval \'24 hours\'' )
2016-08-09 19:44:45 +00:00
2018-08-28 16:29:29 +00:00
return UserModel . getTotalRawQuery ( query , user . id )
2017-10-24 17:41:09 +00:00
}
2018-02-28 17:04:46 +00:00
static async getStats ( ) {
const totalUsers = await UserModel . count ( )
return {
totalUsers
}
}
2018-09-04 08:22:10 +00:00
static autoComplete ( search : string ) {
const query = {
where : {
username : {
2019-04-23 07:50:57 +00:00
[ Op . like ] : ` % ${ search } % `
2018-09-04 08:22:10 +00:00
}
} ,
limit : 10
}
return UserModel . findAll ( query )
. then ( u = > u . map ( u = > u . username ) )
}
2019-12-12 14:47:47 +00:00
canGetVideo ( video : MVideoFullLight ) {
2019-12-18 15:38:39 +00:00
const videoUserId = video . VideoChannel . Account . userId
2019-12-12 14:47:47 +00:00
2019-12-18 15:38:39 +00:00
if ( video . isBlacklisted ( ) ) {
return videoUserId === this . id || this . hasRight ( UserRight . MANAGE_VIDEO_BLACKLIST )
2019-12-12 14:47:47 +00:00
}
2019-12-18 15:38:39 +00:00
if ( video . privacy === VideoPrivacy . PRIVATE ) {
return video . VideoChannel && videoUserId === this . id || this . hasRight ( UserRight . MANAGE_VIDEO_BLACKLIST )
2019-12-12 14:47:47 +00:00
}
2019-12-18 15:38:39 +00:00
if ( video . privacy === VideoPrivacy . INTERNAL ) return true
2019-12-12 14:47:47 +00:00
return false
}
2017-12-12 16:53:50 +00:00
hasRight ( right : UserRight ) {
return hasUserRight ( this . role , right )
}
2017-10-24 17:41:09 +00:00
2019-04-15 08:49:46 +00:00
hasAdminFlag ( flag : UserAdminFlag ) {
return this . adminFlags & flag
}
2017-12-12 16:53:50 +00:00
isPasswordMatch ( password : string ) {
return comparePassword ( password , this . password )
2016-12-11 20:50:51 +00:00
}
2020-01-02 12:07:18 +00:00
toFormattedJSON ( this : MUserFormattable , parameters : { withAdminFlags? : boolean , me? : boolean } = { } ) : User | MyUser {
2018-08-14 15:56:51 +00:00
const videoQuotaUsed = this . get ( 'videoQuotaUsed' )
2018-08-28 07:01:35 +00:00
const videoQuotaUsedDaily = this . get ( 'videoQuotaUsedDaily' )
2018-08-14 15:56:51 +00:00
2020-01-02 12:07:18 +00:00
const json : User | MyUser = {
2017-12-12 16:53:50 +00:00
id : this.id ,
username : this.username ,
email : this.email ,
2019-08-28 12:40:06 +00:00
theme : getThemeOrDefault ( this . theme , DEFAULT_USER_THEME_NAME ) ,
2019-06-11 09:54:33 +00:00
pendingEmail : this.pendingEmail ,
2018-08-31 07:18:19 +00:00
emailVerified : this.emailVerified ,
2019-08-28 12:40:06 +00:00
2018-04-19 09:01:34 +00:00
nsfwPolicy : this.nsfwPolicy ,
2018-10-12 16:12:39 +00:00
webTorrentEnabled : this.webTorrentEnabled ,
2018-12-18 10:32:37 +00:00
videosHistoryEnabled : this.videosHistoryEnabled ,
2017-12-19 09:45:49 +00:00
autoPlayVideo : this.autoPlayVideo ,
2019-09-24 06:48:01 +00:00
autoPlayNextVideo : this.autoPlayNextVideo ,
2019-12-11 19:20:42 +00:00
autoPlayNextVideoPlaylist : this.autoPlayNextVideoPlaylist ,
2019-06-19 12:55:58 +00:00
videoLanguages : this.videoLanguages ,
2019-08-28 12:40:06 +00:00
2017-12-12 16:53:50 +00:00
role : this.role ,
roleLabel : USER_ROLE_LABELS [ this . role ] ,
2019-08-28 12:40:06 +00:00
2017-12-12 16:53:50 +00:00
videoQuota : this.videoQuota ,
2018-08-28 07:01:35 +00:00
videoQuotaDaily : this.videoQuotaDaily ,
2019-08-28 12:40:06 +00:00
videoQuotaUsed : videoQuotaUsed !== undefined
? parseInt ( videoQuotaUsed + '' , 10 )
: undefined ,
videoQuotaUsedDaily : videoQuotaUsedDaily !== undefined
? parseInt ( videoQuotaUsedDaily + '' , 10 )
: undefined ,
noInstanceConfigWarningModal : this.noInstanceConfigWarningModal ,
noWelcomeModal : this.noWelcomeModal ,
2018-08-08 15:36:10 +00:00
blocked : this.blocked ,
blockedReason : this.blockedReason ,
2019-08-28 12:40:06 +00:00
2017-12-29 18:10:13 +00:00
account : this.Account.toFormattedJSON ( ) ,
2019-08-28 12:40:06 +00:00
notificationSettings : this.NotificationSetting
? this . NotificationSetting . toFormattedJSON ( )
: undefined ,
2018-08-14 15:56:51 +00:00
videoChannels : [ ] ,
2019-08-28 12:40:06 +00:00
createdAt : this.createdAt
2017-12-12 16:53:50 +00:00
}
2019-04-15 08:49:46 +00:00
if ( parameters . withAdminFlags ) {
Object . assign ( json , { adminFlags : this.adminFlags } )
}
2017-12-12 16:53:50 +00:00
if ( Array . isArray ( this . Account . VideoChannels ) === true ) {
2017-12-29 18:10:13 +00:00
json . videoChannels = this . Account . VideoChannels
2017-12-12 16:53:50 +00:00
. map ( c = > c . toFormattedJSON ( ) )
. sort ( ( v1 , v2 ) = > {
if ( v1 . createdAt < v2 . createdAt ) return - 1
if ( v1 . createdAt === v2 . createdAt ) return 0
2017-02-18 08:29:59 +00:00
2017-12-12 16:53:50 +00:00
return 1
} )
2017-02-18 08:29:59 +00:00
}
2017-12-12 16:53:50 +00:00
2020-01-02 12:07:18 +00:00
if ( parameters . me ) {
Object . assign ( json , {
specialPlaylists : ( this . get ( 'specialPlaylists' ) as Array < number > ) . map ( p = > ( { id : p } ) )
} )
}
2017-12-12 16:53:50 +00:00
return json
2017-02-18 08:29:59 +00:00
}
2018-08-28 07:01:35 +00:00
async isAbleToUploadVideo ( videoFile : { size : number } ) {
if ( this . videoQuota === - 1 && this . videoQuotaDaily === - 1 ) return Promise . resolve ( true )
2017-09-04 18:07:54 +00:00
2018-08-28 07:01:35 +00:00
const [ totalBytes , totalBytesDaily ] = await Promise . all ( [
UserModel . getOriginalVideoFileTotalFromUser ( this ) ,
UserModel . getOriginalVideoFileTotalDailyFromUser ( this )
] )
const uploadedTotal = videoFile . size + totalBytes
const uploadedDaily = videoFile . size + totalBytesDaily
2019-04-23 07:50:57 +00:00
if ( this . videoQuotaDaily === - 1 ) return uploadedTotal < this . videoQuota
if ( this . videoQuota === - 1 ) return uploadedDaily < this . videoQuotaDaily
return uploadedTotal < this . videoQuota && uploadedDaily < this . videoQuotaDaily
2017-09-04 18:07:54 +00:00
}
2018-08-28 16:29:29 +00:00
private static generateUserQuotaBaseSQL ( where? : string ) {
const andWhere = where ? 'AND ' + where : ''
return 'SELECT SUM("size") AS "total" ' +
'FROM (' +
'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
'WHERE "account"."userId" = $userId ' + andWhere +
'GROUP BY "video"."id"' +
') t'
}
private static getTotalRawQuery ( query : string , userId : number ) {
const options = {
bind : { userId } ,
2019-04-23 07:50:57 +00:00
type : QueryTypes . SELECT as QueryTypes . SELECT
2018-08-28 16:29:29 +00:00
}
2019-04-23 07:50:57 +00:00
return UserModel . sequelize . query < { total : string } > ( query , options )
2018-08-28 16:29:29 +00:00
. then ( ( [ { total } ] ) = > {
if ( total === null ) return 0
2019-04-23 07:50:57 +00:00
return parseInt ( total , 10 )
2018-08-28 16:29:29 +00:00
} )
}
2017-09-04 18:07:54 +00:00
}