aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models
diff options
context:
space:
mode:
Diffstat (limited to 'server/models')
-rw-r--r--server/models/user/user-interface.ts4
-rw-r--r--server/models/user/user.ts60
-rw-r--r--server/models/video/video.ts7
3 files changed, 66 insertions, 5 deletions
diff --git a/server/models/user/user-interface.ts b/server/models/user/user-interface.ts
index 0b97a8f6d..8974a9a97 100644
--- a/server/models/user/user-interface.ts
+++ b/server/models/user/user-interface.ts
@@ -11,6 +11,7 @@ export namespace UserMethods {
11 11
12 export type ToFormattedJSON = (this: UserInstance) => FormattedUser 12 export type ToFormattedJSON = (this: UserInstance) => FormattedUser
13 export type IsAdmin = (this: UserInstance) => boolean 13 export type IsAdmin = (this: UserInstance) => boolean
14 export type IsAbleToUploadVideo = (this: UserInstance, videoFile: Express.Multer.File) => Promise<boolean>
14 15
15 export type CountTotal = () => Promise<number> 16 export type CountTotal = () => Promise<number>
16 17
@@ -31,6 +32,7 @@ export interface UserClass {
31 isPasswordMatch: UserMethods.IsPasswordMatch, 32 isPasswordMatch: UserMethods.IsPasswordMatch,
32 toFormattedJSON: UserMethods.ToFormattedJSON, 33 toFormattedJSON: UserMethods.ToFormattedJSON,
33 isAdmin: UserMethods.IsAdmin, 34 isAdmin: UserMethods.IsAdmin,
35 isAbleToUploadVideo: UserMethods.IsAbleToUploadVideo,
34 36
35 countTotal: UserMethods.CountTotal, 37 countTotal: UserMethods.CountTotal,
36 getByUsername: UserMethods.GetByUsername, 38 getByUsername: UserMethods.GetByUsername,
@@ -42,11 +44,13 @@ export interface UserClass {
42} 44}
43 45
44export interface UserAttributes { 46export interface UserAttributes {
47 id?: number
45 password: string 48 password: string
46 username: string 49 username: string
47 email: string 50 email: string
48 displayNSFW?: boolean 51 displayNSFW?: boolean
49 role: UserRole 52 role: UserRole
53 videoQuota: number
50} 54}
51 55
52export interface UserInstance extends UserClass, UserAttributes, Sequelize.Instance<UserAttributes> { 56export interface UserInstance extends UserClass, UserAttributes, Sequelize.Instance<UserAttributes> {
diff --git a/server/models/user/user.ts b/server/models/user/user.ts
index d481fa13c..12a7547f5 100644
--- a/server/models/user/user.ts
+++ b/server/models/user/user.ts
@@ -1,5 +1,6 @@
1import { values } from 'lodash' 1import { values } from 'lodash'
2import * as Sequelize from 'sequelize' 2import * as Sequelize from 'sequelize'
3import * as Promise from 'bluebird'
3 4
4import { getSort } from '../utils' 5import { getSort } from '../utils'
5import { USER_ROLES } from '../../initializers' 6import { USER_ROLES } from '../../initializers'
@@ -8,7 +9,8 @@ import {
8 comparePassword, 9 comparePassword,
9 isUserPasswordValid, 10 isUserPasswordValid,
10 isUserUsernameValid, 11 isUserUsernameValid,
11 isUserDisplayNSFWValid 12 isUserDisplayNSFWValid,
13 isUserVideoQuotaValid
12} from '../../helpers' 14} from '../../helpers'
13 15
14import { addMethodsToModel } from '../utils' 16import { addMethodsToModel } from '../utils'
@@ -30,6 +32,7 @@ let listForApi: UserMethods.ListForApi
30let loadById: UserMethods.LoadById 32let loadById: UserMethods.LoadById
31let loadByUsername: UserMethods.LoadByUsername 33let loadByUsername: UserMethods.LoadByUsername
32let loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail 34let loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail
35let isAbleToUploadVideo: UserMethods.IsAbleToUploadVideo
33 36
34export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { 37export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
35 User = sequelize.define<UserInstance, UserAttributes>('User', 38 User = sequelize.define<UserInstance, UserAttributes>('User',
@@ -75,6 +78,16 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
75 role: { 78 role: {
76 type: DataTypes.ENUM(values(USER_ROLES)), 79 type: DataTypes.ENUM(values(USER_ROLES)),
77 allowNull: false 80 allowNull: false
81 },
82 videoQuota: {
83 type: DataTypes.BIGINT,
84 allowNull: false,
85 validate: {
86 videoQuotaValid: value => {
87 const res = isUserVideoQuotaValid(value)
88 if (res === false) throw new Error('Video quota is not valid.')
89 }
90 }
78 } 91 }
79 }, 92 },
80 { 93 {
@@ -109,7 +122,8 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
109 const instanceMethods = [ 122 const instanceMethods = [
110 isPasswordMatch, 123 isPasswordMatch,
111 toFormattedJSON, 124 toFormattedJSON,
112 isAdmin 125 isAdmin,
126 isAbleToUploadVideo
113 ] 127 ]
114 addMethodsToModel(User, classMethods, instanceMethods) 128 addMethodsToModel(User, classMethods, instanceMethods)
115 129
@@ -136,6 +150,7 @@ toFormattedJSON = function (this: UserInstance) {
136 email: this.email, 150 email: this.email,
137 displayNSFW: this.displayNSFW, 151 displayNSFW: this.displayNSFW,
138 role: this.role, 152 role: this.role,
153 videoQuota: this.videoQuota,
139 createdAt: this.createdAt 154 createdAt: this.createdAt
140 } 155 }
141} 156}
@@ -144,6 +159,14 @@ isAdmin = function (this: UserInstance) {
144 return this.role === USER_ROLES.ADMIN 159 return this.role === USER_ROLES.ADMIN
145} 160}
146 161
162isAbleToUploadVideo = function (this: UserInstance, videoFile: Express.Multer.File) {
163 if (this.videoQuota === -1) return Promise.resolve(true)
164
165 return getOriginalVideoFileTotalFromUser(this).then(totalBytes => {
166 return (videoFile.size + totalBytes) < this.videoQuota
167 })
168}
169
147// ------------------------------ STATICS ------------------------------ 170// ------------------------------ STATICS ------------------------------
148 171
149function associate (models) { 172function associate (models) {
@@ -215,3 +238,36 @@ loadByUsernameOrEmail = function (username: string, email: string) {
215 // FIXME: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18387 238 // FIXME: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18387
216 return (User as any).findOne(query) 239 return (User as any).findOne(query)
217} 240}
241
242// ---------------------------------------------------------------------------
243
244function getOriginalVideoFileTotalFromUser (user: UserInstance) {
245 const query = {
246 attributes: [
247 Sequelize.fn('COUNT', Sequelize.col('VideoFile.size'), 'totalVideoBytes')
248 ],
249 where: {
250 id: user.id
251 },
252 include: [
253 {
254 model: User['sequelize'].models.Author,
255 include: [
256 {
257 model: User['sequelize'].models.Video,
258 include: [
259 {
260 model: User['sequelize'].models.VideoFile
261 }
262 ]
263 }
264 ]
265 }
266 ]
267 }
268
269 // FIXME: cast to any because of bad typing...
270 return User.findAll(query).then((res: any) => {
271 return res.totalVideoBytes
272 })
273}
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index 7dfea8ac9..4fb4485d8 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -9,6 +9,7 @@ import * as Sequelize from 'sequelize'
9import * as Promise from 'bluebird' 9import * as Promise from 'bluebird'
10 10
11import { TagInstance } from './tag-interface' 11import { TagInstance } from './tag-interface'
12import { UserInstance } from '../user/user-interface'
12import { 13import {
13 logger, 14 logger,
14 isVideoNameValid, 15 isVideoNameValid,
@@ -582,7 +583,7 @@ transcodeVideofile = function (this: VideoInstance, inputVideoFile: VideoFileIns
582 return res() 583 return res()
583 }) 584 })
584 .catch(err => { 585 .catch(err => {
585 // Autodestruction... 586 // Auto destruction...
586 this.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', err)) 587 this.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', err))
587 588
588 return rej(err) 589 return rej(err)
@@ -608,8 +609,8 @@ removeFile = function (this: VideoInstance, videoFile: VideoFileInstance) {
608} 609}
609 610
610removeTorrent = function (this: VideoInstance, videoFile: VideoFileInstance) { 611removeTorrent = function (this: VideoInstance, videoFile: VideoFileInstance) {
611 const torrenPath = join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) 612 const torrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile))
612 return unlinkPromise(torrenPath) 613 return unlinkPromise(torrentPath)
613} 614}
614 615
615// ------------------------------ STATICS ------------------------------ 616// ------------------------------ STATICS ------------------------------