diff options
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/user/user-interface.ts | 4 | ||||
-rw-r--r-- | server/models/user/user.ts | 60 | ||||
-rw-r--r-- | server/models/video/video.ts | 7 |
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 | ||
44 | export interface UserAttributes { | 46 | export 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 | ||
52 | export interface UserInstance extends UserClass, UserAttributes, Sequelize.Instance<UserAttributes> { | 56 | export 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 @@ | |||
1 | import { values } from 'lodash' | 1 | import { values } from 'lodash' |
2 | import * as Sequelize from 'sequelize' | 2 | import * as Sequelize from 'sequelize' |
3 | import * as Promise from 'bluebird' | ||
3 | 4 | ||
4 | import { getSort } from '../utils' | 5 | import { getSort } from '../utils' |
5 | import { USER_ROLES } from '../../initializers' | 6 | import { 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 | ||
14 | import { addMethodsToModel } from '../utils' | 16 | import { addMethodsToModel } from '../utils' |
@@ -30,6 +32,7 @@ let listForApi: UserMethods.ListForApi | |||
30 | let loadById: UserMethods.LoadById | 32 | let loadById: UserMethods.LoadById |
31 | let loadByUsername: UserMethods.LoadByUsername | 33 | let loadByUsername: UserMethods.LoadByUsername |
32 | let loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail | 34 | let loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail |
35 | let isAbleToUploadVideo: UserMethods.IsAbleToUploadVideo | ||
33 | 36 | ||
34 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | 37 | export 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 | ||
162 | isAbleToUploadVideo = 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 | ||
149 | function associate (models) { | 172 | function 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 | |||
244 | function 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' | |||
9 | import * as Promise from 'bluebird' | 9 | import * as Promise from 'bluebird' |
10 | 10 | ||
11 | import { TagInstance } from './tag-interface' | 11 | import { TagInstance } from './tag-interface' |
12 | import { UserInstance } from '../user/user-interface' | ||
12 | import { | 13 | import { |
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 | ||
610 | removeTorrent = function (this: VideoInstance, videoFile: VideoFileInstance) { | 611 | removeTorrent = 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 ------------------------------ |