]>
Commit | Line | Data |
---|---|---|
b60e5f38 | 1 | import { body, param, query } from 'express-validator/check' |
69818c93 | 2 | import * as express from 'express' |
0a6658fd C |
3 | import * as Promise from 'bluebird' |
4 | import * as validator from 'validator' | |
69818c93 | 5 | |
e02643f3 | 6 | import { database as db } from '../../initializers/database' |
65fcc311 C |
7 | import { checkErrors } from './utils' |
8 | import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers' | |
b60e5f38 C |
9 | import { |
10 | logger, | |
11 | isVideoDurationValid, | |
12 | isVideoFile, | |
13 | isVideoNameValid, | |
14 | isVideoCategoryValid, | |
15 | isVideoLicenceValid, | |
16 | isVideoDescriptionValid, | |
17 | isVideoLanguageValid, | |
18 | isVideoTagsValid, | |
19 | isVideoNSFWValid, | |
20 | isVideoIdOrUUIDValid, | |
21 | isVideoAbuseReasonValid, | |
14d3270f C |
22 | isVideoRatingTypeValid, |
23 | getDurationFromVideoFile | |
b60e5f38 | 24 | } from '../../helpers' |
0a6658fd | 25 | import { VideoInstance } from '../../models' |
34ca3b52 | 26 | |
b60e5f38 C |
27 | const videosAddValidator = [ |
28 | body('videofile').custom((value, { req }) => isVideoFile(req.files)).withMessage('Should have a valid file'), | |
29 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), | |
30 | body('category').custom(isVideoCategoryValid).withMessage('Should have a valid category'), | |
31 | body('licence').custom(isVideoLicenceValid).withMessage('Should have a valid licence'), | |
32 | body('language').optional().custom(isVideoLanguageValid).withMessage('Should have a valid language'), | |
33 | body('nsfw').custom(isVideoNSFWValid).withMessage('Should have a valid NSFW attribute'), | |
34 | body('description').custom(isVideoDescriptionValid).withMessage('Should have a valid description'), | |
35 | body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'), | |
36 | ||
37 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | |
38 | logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files }) | |
39 | ||
40 | checkErrors(req, res, () => { | |
41 | const videoFile: Express.Multer.File = req.files['videofile'][0] | |
42 | const user = res.locals.oauth.token.User | |
43 | ||
44 | user.isAbleToUploadVideo(videoFile) | |
45 | .then(isAble => { | |
46 | if (isAble === false) { | |
47 | res.status(403) | |
48 | .json({ error: 'The user video quota is exceeded with this video.' }) | |
49 | .end() | |
50 | ||
51 | return undefined | |
52 | } | |
53 | ||
14d3270f | 54 | return getDurationFromVideoFile(videoFile.path) |
b60e5f38 C |
55 | .catch(err => { |
56 | logger.error('Invalid input file in videosAddValidator.', err) | |
57 | res.status(400) | |
58 | .json({ error: 'Invalid input file.' }) | |
59 | .end() | |
60 | ||
61 | return undefined | |
62 | }) | |
63 | }) | |
64 | .then(duration => { | |
65 | // Previous test failed, abort | |
66 | if (duration === undefined) return | |
67 | ||
68 | if (!isVideoDurationValid('' + duration)) { | |
69 | return res.status(400) | |
70 | .json({ | |
71 | error: 'Duration of the video file is too big (max: ' + CONSTRAINTS_FIELDS.VIDEOS.DURATION.max + 's).' | |
72 | }) | |
73 | .end() | |
74 | } | |
75 | ||
76 | videoFile['duration'] = duration | |
77 | next() | |
78 | }) | |
79 | .catch(err => { | |
80 | logger.error('Error in video add validator', err) | |
81 | res.sendStatus(500) | |
b0f9f39e C |
82 | |
83 | return undefined | |
b60e5f38 C |
84 | }) |
85 | }) | |
86 | } | |
87 | ] | |
88 | ||
89 | const videosUpdateValidator = [ | |
90 | param('id').custom(isVideoIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | |
91 | body('name').optional().custom(isVideoNameValid).withMessage('Should have a valid name'), | |
92 | body('category').optional().custom(isVideoCategoryValid).withMessage('Should have a valid category'), | |
93 | body('licence').optional().custom(isVideoLicenceValid).withMessage('Should have a valid licence'), | |
94 | body('language').optional().custom(isVideoLanguageValid).withMessage('Should have a valid language'), | |
95 | body('nsfw').optional().custom(isVideoNSFWValid).withMessage('Should have a valid NSFW attribute'), | |
96 | body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'), | |
97 | body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'), | |
98 | ||
99 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | |
100 | logger.debug('Checking videosUpdate parameters', { parameters: req.body }) | |
101 | ||
102 | checkErrors(req, res, () => { | |
103 | checkVideoExists(req.params.id, res, () => { | |
104 | // We need to make additional checks | |
105 | if (res.locals.video.isOwned() === false) { | |
106 | return res.status(403) | |
107 | .json({ error: 'Cannot update video of another pod' }) | |
108 | .end() | |
b0f9f39e C |
109 | } |
110 | ||
b60e5f38 C |
111 | if (res.locals.video.Author.userId !== res.locals.oauth.token.User.id) { |
112 | return res.status(403) | |
113 | .json({ error: 'Cannot update video of another user' }) | |
bfb3a98f | 114 | .end() |
6fcd19ba | 115 | } |
67100f1f | 116 | |
6fcd19ba C |
117 | next() |
118 | }) | |
63d00f5d | 119 | }) |
b60e5f38 C |
120 | } |
121 | ] | |
c173e565 | 122 | |
b60e5f38 C |
123 | const videosGetValidator = [ |
124 | param('id').custom(isVideoIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | |
34ca3b52 | 125 | |
b60e5f38 C |
126 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
127 | logger.debug('Checking videosGet parameters', { parameters: req.params }) | |
7b1f49de | 128 | |
b60e5f38 C |
129 | checkErrors(req, res, () => { |
130 | checkVideoExists(req.params.id, res, next) | |
131 | }) | |
132 | } | |
133 | ] | |
34ca3b52 | 134 | |
b60e5f38 C |
135 | const videosRemoveValidator = [ |
136 | param('id').custom(isVideoIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | |
34ca3b52 | 137 | |
b60e5f38 C |
138 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
139 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) | |
34ca3b52 | 140 | |
b60e5f38 C |
141 | checkErrors(req, res, () => { |
142 | checkVideoExists(req.params.id, res, () => { | |
143 | // Check if the user who did the request is able to delete the video | |
144 | checkUserCanDeleteVideo(res.locals.oauth.token.User.id, res, () => { | |
145 | next() | |
146 | }) | |
198b205c | 147 | }) |
34ca3b52 | 148 | }) |
b60e5f38 C |
149 | } |
150 | ] | |
34ca3b52 | 151 | |
b60e5f38 C |
152 | const videosSearchValidator = [ |
153 | param('value').not().isEmpty().withMessage('Should have a valid search'), | |
154 | query('field').optional().isIn(SEARCHABLE_COLUMNS.VIDEOS).withMessage('Should have correct searchable column'), | |
c45f7f84 | 155 | |
b60e5f38 C |
156 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
157 | logger.debug('Checking videosSearch parameters', { parameters: req.params }) | |
c45f7f84 | 158 | |
b60e5f38 C |
159 | checkErrors(req, res, next) |
160 | } | |
161 | ] | |
c45f7f84 | 162 | |
b60e5f38 C |
163 | const videoAbuseReportValidator = [ |
164 | param('id').custom(isVideoIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | |
165 | body('reason').custom(isVideoAbuseReasonValid).withMessage('Should have a valid reason'), | |
55fa55a9 | 166 | |
b60e5f38 C |
167 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
168 | logger.debug('Checking videoAbuseReport parameters', { parameters: req.body }) | |
55fa55a9 | 169 | |
b60e5f38 C |
170 | checkErrors(req, res, () => { |
171 | checkVideoExists(req.params.id, res, next) | |
172 | }) | |
173 | } | |
174 | ] | |
55fa55a9 | 175 | |
b60e5f38 C |
176 | const videoRateValidator = [ |
177 | param('id').custom(isVideoIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | |
178 | body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'), | |
d38b8281 | 179 | |
b60e5f38 C |
180 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
181 | logger.debug('Checking videoRate parameters', { parameters: req.body }) | |
d38b8281 | 182 | |
b60e5f38 C |
183 | checkErrors(req, res, () => { |
184 | checkVideoExists(req.params.id, res, next) | |
185 | }) | |
186 | } | |
187 | ] | |
d38b8281 | 188 | |
b60e5f38 C |
189 | const videosBlacklistValidator = [ |
190 | param('id').custom(isVideoIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | |
ab683a8e | 191 | |
b60e5f38 C |
192 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
193 | logger.debug('Checking videosBlacklist parameters', { parameters: req.params }) | |
ab683a8e | 194 | |
b60e5f38 C |
195 | checkErrors(req, res, () => { |
196 | checkVideoExists(req.params.id, res, () => { | |
197 | checkVideoIsBlacklistable(req, res, next) | |
198 | }) | |
ab683a8e | 199 | }) |
b60e5f38 C |
200 | } |
201 | ] | |
ab683a8e | 202 | |
9f10b292 | 203 | // --------------------------------------------------------------------------- |
c45f7f84 | 204 | |
65fcc311 C |
205 | export { |
206 | videosAddValidator, | |
207 | videosUpdateValidator, | |
208 | videosGetValidator, | |
209 | videosRemoveValidator, | |
210 | videosSearchValidator, | |
211 | ||
212 | videoAbuseReportValidator, | |
213 | ||
214 | videoRateValidator, | |
215 | ||
216 | videosBlacklistValidator | |
217 | } | |
7b1f49de C |
218 | |
219 | // --------------------------------------------------------------------------- | |
220 | ||
69818c93 | 221 | function checkVideoExists (id: string, res: express.Response, callback: () => void) { |
0a6658fd C |
222 | let promise: Promise<VideoInstance> |
223 | if (validator.isInt(id)) { | |
224 | promise = db.Video.loadAndPopulateAuthorAndPodAndTags(+id) | |
225 | } else { // UUID | |
226 | promise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(id) | |
227 | } | |
228 | ||
229 | promise.then(video => { | |
bfb3a98f C |
230 | if (!video) { |
231 | return res.status(404) | |
232 | .json({ error: 'Video not found' }) | |
233 | .end() | |
234 | } | |
7b1f49de C |
235 | |
236 | res.locals.video = video | |
237 | callback() | |
238 | }) | |
6fcd19ba | 239 | .catch(err => { |
ad0997ad | 240 | logger.error('Error in video request validator.', err) |
6fcd19ba C |
241 | return res.sendStatus(500) |
242 | }) | |
7b1f49de | 243 | } |
198b205c | 244 | |
69818c93 | 245 | function checkUserCanDeleteVideo (userId: number, res: express.Response, callback: () => void) { |
198b205c | 246 | // Retrieve the user who did the request |
6fcd19ba C |
247 | db.User.loadById(userId) |
248 | .then(user => { | |
6d33593a | 249 | if (res.locals.video.isOwned() === false) { |
bfb3a98f C |
250 | return res.status(403) |
251 | .json({ error: 'Cannot remove video of another pod, blacklist it' }) | |
252 | .end() | |
6d33593a C |
253 | } |
254 | ||
6fcd19ba C |
255 | // Check if the user can delete the video |
256 | // The user can delete it if s/he is an admin | |
257 | // Or if s/he is the video's author | |
6d33593a | 258 | if (user.isAdmin() === false && res.locals.video.Author.userId !== res.locals.oauth.token.User.id) { |
bfb3a98f C |
259 | return res.status(403) |
260 | .json({ error: 'Cannot remove video of another user' }) | |
261 | .end() | |
198b205c | 262 | } |
198b205c | 263 | |
6fcd19ba C |
264 | // If we reach this comment, we can delete the video |
265 | callback() | |
266 | }) | |
267 | .catch(err => { | |
ad0997ad | 268 | logger.error('Error in video request validator.', err) |
6fcd19ba C |
269 | return res.sendStatus(500) |
270 | }) | |
198b205c GS |
271 | } |
272 | ||
69818c93 | 273 | function checkVideoIsBlacklistable (req: express.Request, res: express.Response, callback: () => void) { |
198b205c | 274 | if (res.locals.video.isOwned() === true) { |
bfb3a98f C |
275 | return res.status(403) |
276 | .json({ error: 'Cannot blacklist a local video' }) | |
277 | .end() | |
198b205c GS |
278 | } |
279 | ||
280 | callback() | |
281 | } |