1 import { values } from 'lodash'
2 import * as Sequelize from 'sequelize'
3 import * as Promise from 'bluebird'
5 import { getSort } from '../utils'
6 import { USER_ROLES } from '../../initializers'
12 isUserDisplayNSFWValid,
14 } from '../../helpers'
15 import { VideoResolution } from '../../../shared'
17 import { addMethodsToModel } from '../utils'
23 } from './user-interface'
25 let User: Sequelize.Model<UserInstance, UserAttributes>
26 let isPasswordMatch: UserMethods.IsPasswordMatch
27 let toFormattedJSON: UserMethods.ToFormattedJSON
28 let isAdmin: UserMethods.IsAdmin
29 let countTotal: UserMethods.CountTotal
30 let getByUsername: UserMethods.GetByUsername
31 let list: UserMethods.List
32 let listForApi: UserMethods.ListForApi
33 let loadById: UserMethods.LoadById
34 let loadByUsername: UserMethods.LoadByUsername
35 let loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail
36 let isAbleToUploadVideo: UserMethods.IsAbleToUploadVideo
38 export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
39 User = sequelize.define<UserInstance, UserAttributes>('User',
42 type: DataTypes.STRING,
45 passwordValid: value => {
46 const res = isUserPasswordValid(value)
47 if (res === false) throw new Error('Password not valid.')
52 type: DataTypes.STRING,
55 usernameValid: value => {
56 const res = isUserUsernameValid(value)
57 if (res === false) throw new Error('Username not valid.')
62 type: DataTypes.STRING(400),
69 type: DataTypes.BOOLEAN,
74 const res = isUserDisplayNSFWValid(value)
75 if (res === false) throw new Error('Display NSFW is not valid.')
80 type: DataTypes.ENUM(values(USER_ROLES)),
84 type: DataTypes.BIGINT,
87 videoQuotaValid: value => {
88 const res = isUserVideoQuotaValid(value)
89 if (res === false) throw new Error('Video quota is not valid.')
97 fields: [ 'username' ],
106 beforeCreate: beforeCreateOrUpdate,
107 beforeUpdate: beforeCreateOrUpdate
112 const classMethods = [
121 loadByUsernameOrEmail
123 const instanceMethods = [
129 addMethodsToModel(User, classMethods, instanceMethods)
134 function beforeCreateOrUpdate (user: UserInstance) {
135 return cryptPassword(user.password).then(hash => {
141 // ------------------------------ METHODS ------------------------------
143 isPasswordMatch = function (this: UserInstance, password: string) {
144 return comparePassword(password, this.password)
147 toFormattedJSON = function (this: UserInstance) {
150 username: this.username,
152 displayNSFW: this.displayNSFW,
154 videoQuota: this.videoQuota,
155 createdAt: this.createdAt
159 isAdmin = function (this: UserInstance) {
160 return this.role === USER_ROLES.ADMIN
163 isAbleToUploadVideo = function (this: UserInstance, videoFile: Express.Multer.File) {
164 if (this.videoQuota === -1) return Promise.resolve(true)
166 return getOriginalVideoFileTotalFromUser(this).then(totalBytes => {
167 return (videoFile.size + totalBytes) < this.videoQuota
171 // ------------------------------ STATICS ------------------------------
173 function associate (models) {
174 User.hasOne(models.Author, {
175 foreignKey: 'userId',
179 User.hasMany(models.OAuthToken, {
180 foreignKey: 'userId',
185 countTotal = function () {
189 getByUsername = function (username: string) {
196 return User.findOne(query)
200 return User.findAll()
203 listForApi = function (start: number, count: number, sort: string) {
207 order: [ getSort(sort) ]
210 return User.findAndCountAll(query).then(({ rows, count }) => {
218 loadById = function (id: number) {
219 return User.findById(id)
222 loadByUsername = function (username: string) {
229 return User.findOne(query)
232 loadByUsernameOrEmail = function (username: string, email: string) {
235 $or: [ { username }, { email } ]
239 // FIXME: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18387
240 return (User as any).findOne(query)
243 // ---------------------------------------------------------------------------
245 function getOriginalVideoFileTotalFromUser (user: UserInstance) {
246 // attributes = [] because we don't want other fields than the sum
249 resolution: VideoResolution.ORIGINAL
254 model: User['sequelize'].models.Video,
258 model: User['sequelize'].models.Author,
262 model: User['sequelize'].models.User,
274 return User['sequelize'].models.VideoFile.sum('size', query)