diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-05-05 16:53:35 +0200 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-05-05 16:53:35 +0200 |
commit | d33242b047c68ae81c9657d05893d1838f1b1c89 (patch) | |
tree | 8c15535da8097b1ac3488d5b970e5aa69a035e4a /server/controllers/api/videos.js | |
parent | 1f0215a908c3b447cef03c10d4b089c0788922bd (diff) | |
download | PeerTube-d33242b047c68ae81c9657d05893d1838f1b1c89.tar.gz PeerTube-d33242b047c68ae81c9657d05893d1838f1b1c89.tar.zst PeerTube-d33242b047c68ae81c9657d05893d1838f1b1c89.zip |
Server: split videos controller
Diffstat (limited to 'server/controllers/api/videos.js')
-rw-r--r-- | server/controllers/api/videos.js | 653 |
1 files changed, 0 insertions, 653 deletions
diff --git a/server/controllers/api/videos.js b/server/controllers/api/videos.js deleted file mode 100644 index aeefaa555..000000000 --- a/server/controllers/api/videos.js +++ /dev/null | |||
@@ -1,653 +0,0 @@ | |||
1 | 'use strict' | ||
2 | |||
3 | const express = require('express') | ||
4 | const fs = require('fs') | ||
5 | const multer = require('multer') | ||
6 | const path = require('path') | ||
7 | const waterfall = require('async/waterfall') | ||
8 | |||
9 | const constants = require('../../initializers/constants') | ||
10 | const db = require('../../initializers/database') | ||
11 | const logger = require('../../helpers/logger') | ||
12 | const friends = require('../../lib/friends') | ||
13 | const middlewares = require('../../middlewares') | ||
14 | const admin = middlewares.admin | ||
15 | const oAuth = middlewares.oauth | ||
16 | const pagination = middlewares.pagination | ||
17 | const validators = middlewares.validators | ||
18 | const validatorsPagination = validators.pagination | ||
19 | const validatorsSort = validators.sort | ||
20 | const validatorsVideos = validators.videos | ||
21 | const search = middlewares.search | ||
22 | const sort = middlewares.sort | ||
23 | const databaseUtils = require('../../helpers/database-utils') | ||
24 | const utils = require('../../helpers/utils') | ||
25 | |||
26 | const router = express.Router() | ||
27 | |||
28 | // multer configuration | ||
29 | const storage = multer.diskStorage({ | ||
30 | destination: function (req, file, cb) { | ||
31 | cb(null, constants.CONFIG.STORAGE.VIDEOS_DIR) | ||
32 | }, | ||
33 | |||
34 | filename: function (req, file, cb) { | ||
35 | let extension = '' | ||
36 | if (file.mimetype === 'video/webm') extension = 'webm' | ||
37 | else if (file.mimetype === 'video/mp4') extension = 'mp4' | ||
38 | else if (file.mimetype === 'video/ogg') extension = 'ogv' | ||
39 | utils.generateRandomString(16, function (err, randomString) { | ||
40 | const fieldname = err ? undefined : randomString | ||
41 | cb(null, fieldname + '.' + extension) | ||
42 | }) | ||
43 | } | ||
44 | }) | ||
45 | |||
46 | const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }]) | ||
47 | |||
48 | router.get('/categories', listVideoCategories) | ||
49 | router.get('/licences', listVideoLicences) | ||
50 | router.get('/languages', listVideoLanguages) | ||
51 | |||
52 | router.get('/abuse', | ||
53 | oAuth.authenticate, | ||
54 | admin.ensureIsAdmin, | ||
55 | validatorsPagination.pagination, | ||
56 | validatorsSort.videoAbusesSort, | ||
57 | sort.setVideoAbusesSort, | ||
58 | pagination.setPagination, | ||
59 | listVideoAbuses | ||
60 | ) | ||
61 | router.post('/:id/abuse', | ||
62 | oAuth.authenticate, | ||
63 | validatorsVideos.videoAbuseReport, | ||
64 | reportVideoAbuseRetryWrapper | ||
65 | ) | ||
66 | |||
67 | router.put('/:id/rate', | ||
68 | oAuth.authenticate, | ||
69 | validatorsVideos.videoRate, | ||
70 | rateVideoRetryWrapper | ||
71 | ) | ||
72 | |||
73 | router.get('/', | ||
74 | validatorsPagination.pagination, | ||
75 | validatorsSort.videosSort, | ||
76 | sort.setVideosSort, | ||
77 | pagination.setPagination, | ||
78 | listVideos | ||
79 | ) | ||
80 | router.put('/:id', | ||
81 | oAuth.authenticate, | ||
82 | reqFiles, | ||
83 | validatorsVideos.videosUpdate, | ||
84 | updateVideoRetryWrapper | ||
85 | ) | ||
86 | router.post('/', | ||
87 | oAuth.authenticate, | ||
88 | reqFiles, | ||
89 | validatorsVideos.videosAdd, | ||
90 | addVideoRetryWrapper | ||
91 | ) | ||
92 | router.get('/:id', | ||
93 | validatorsVideos.videosGet, | ||
94 | getVideo | ||
95 | ) | ||
96 | |||
97 | router.delete('/:id', | ||
98 | oAuth.authenticate, | ||
99 | validatorsVideos.videosRemove, | ||
100 | removeVideo | ||
101 | ) | ||
102 | |||
103 | router.get('/search/:value', | ||
104 | validatorsVideos.videosSearch, | ||
105 | validatorsPagination.pagination, | ||
106 | validatorsSort.videosSort, | ||
107 | sort.setVideosSort, | ||
108 | pagination.setPagination, | ||
109 | search.setVideosSearch, | ||
110 | searchVideos | ||
111 | ) | ||
112 | |||
113 | router.post('/:id/blacklist', | ||
114 | oAuth.authenticate, | ||
115 | admin.ensureIsAdmin, | ||
116 | validatorsVideos.videosBlacklist, | ||
117 | addVideoToBlacklist | ||
118 | ) | ||
119 | |||
120 | // --------------------------------------------------------------------------- | ||
121 | |||
122 | module.exports = router | ||
123 | |||
124 | // --------------------------------------------------------------------------- | ||
125 | |||
126 | function listVideoCategories (req, res, next) { | ||
127 | res.json(constants.VIDEO_CATEGORIES) | ||
128 | } | ||
129 | |||
130 | function listVideoLicences (req, res, next) { | ||
131 | res.json(constants.VIDEO_LICENCES) | ||
132 | } | ||
133 | |||
134 | function listVideoLanguages (req, res, next) { | ||
135 | res.json(constants.VIDEO_LANGUAGES) | ||
136 | } | ||
137 | |||
138 | function rateVideoRetryWrapper (req, res, next) { | ||
139 | const options = { | ||
140 | arguments: [ req, res ], | ||
141 | errorMessage: 'Cannot update the user video rate.' | ||
142 | } | ||
143 | |||
144 | databaseUtils.retryTransactionWrapper(rateVideo, options, function (err) { | ||
145 | if (err) return next(err) | ||
146 | |||
147 | return res.type('json').status(204).end() | ||
148 | }) | ||
149 | } | ||
150 | |||
151 | function rateVideo (req, res, finalCallback) { | ||
152 | const rateType = req.body.rating | ||
153 | const videoInstance = res.locals.video | ||
154 | const userInstance = res.locals.oauth.token.User | ||
155 | |||
156 | waterfall([ | ||
157 | databaseUtils.startSerializableTransaction, | ||
158 | |||
159 | function findPreviousRate (t, callback) { | ||
160 | db.UserVideoRate.load(userInstance.id, videoInstance.id, t, function (err, previousRate) { | ||
161 | return callback(err, t, previousRate) | ||
162 | }) | ||
163 | }, | ||
164 | |||
165 | function insertUserRateIntoDB (t, previousRate, callback) { | ||
166 | const options = { transaction: t } | ||
167 | |||
168 | let likesToIncrement = 0 | ||
169 | let dislikesToIncrement = 0 | ||
170 | |||
171 | if (rateType === constants.VIDEO_RATE_TYPES.LIKE) likesToIncrement++ | ||
172 | else if (rateType === constants.VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++ | ||
173 | |||
174 | // There was a previous rate, update it | ||
175 | if (previousRate) { | ||
176 | // We will remove the previous rate, so we will need to remove it from the video attribute | ||
177 | if (previousRate.type === constants.VIDEO_RATE_TYPES.LIKE) likesToIncrement-- | ||
178 | else if (previousRate.type === constants.VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement-- | ||
179 | |||
180 | previousRate.type = rateType | ||
181 | |||
182 | previousRate.save(options).asCallback(function (err) { | ||
183 | return callback(err, t, likesToIncrement, dislikesToIncrement) | ||
184 | }) | ||
185 | } else { // There was not a previous rate, insert a new one | ||
186 | const query = { | ||
187 | userId: userInstance.id, | ||
188 | videoId: videoInstance.id, | ||
189 | type: rateType | ||
190 | } | ||
191 | |||
192 | db.UserVideoRate.create(query, options).asCallback(function (err) { | ||
193 | return callback(err, t, likesToIncrement, dislikesToIncrement) | ||
194 | }) | ||
195 | } | ||
196 | }, | ||
197 | |||
198 | function updateVideoAttributeDB (t, likesToIncrement, dislikesToIncrement, callback) { | ||
199 | const options = { transaction: t } | ||
200 | const incrementQuery = { | ||
201 | likes: likesToIncrement, | ||
202 | dislikes: dislikesToIncrement | ||
203 | } | ||
204 | |||
205 | // Even if we do not own the video we increment the attributes | ||
206 | // It is usefull for the user to have a feedback | ||
207 | videoInstance.increment(incrementQuery, options).asCallback(function (err) { | ||
208 | return callback(err, t, likesToIncrement, dislikesToIncrement) | ||
209 | }) | ||
210 | }, | ||
211 | |||
212 | function sendEventsToFriendsIfNeeded (t, likesToIncrement, dislikesToIncrement, callback) { | ||
213 | // No need for an event type, we own the video | ||
214 | if (videoInstance.isOwned()) return callback(null, t, likesToIncrement, dislikesToIncrement) | ||
215 | |||
216 | const eventsParams = [] | ||
217 | |||
218 | if (likesToIncrement !== 0) { | ||
219 | eventsParams.push({ | ||
220 | videoId: videoInstance.id, | ||
221 | type: constants.REQUEST_VIDEO_EVENT_TYPES.LIKES, | ||
222 | count: likesToIncrement | ||
223 | }) | ||
224 | } | ||
225 | |||
226 | if (dislikesToIncrement !== 0) { | ||
227 | eventsParams.push({ | ||
228 | videoId: videoInstance.id, | ||
229 | type: constants.REQUEST_VIDEO_EVENT_TYPES.DISLIKES, | ||
230 | count: dislikesToIncrement | ||
231 | }) | ||
232 | } | ||
233 | |||
234 | friends.addEventsToRemoteVideo(eventsParams, t, function (err) { | ||
235 | return callback(err, t, likesToIncrement, dislikesToIncrement) | ||
236 | }) | ||
237 | }, | ||
238 | |||
239 | function sendQaduToFriendsIfNeeded (t, likesToIncrement, dislikesToIncrement, callback) { | ||
240 | // We do not own the video, there is no need to send a quick and dirty update to friends | ||
241 | // Our rate was already sent by the addEvent function | ||
242 | if (videoInstance.isOwned() === false) return callback(null, t) | ||
243 | |||
244 | const qadusParams = [] | ||
245 | |||
246 | if (likesToIncrement !== 0) { | ||
247 | qadusParams.push({ | ||
248 | videoId: videoInstance.id, | ||
249 | type: constants.REQUEST_VIDEO_QADU_TYPES.LIKES | ||
250 | }) | ||
251 | } | ||
252 | |||
253 | if (dislikesToIncrement !== 0) { | ||
254 | qadusParams.push({ | ||
255 | videoId: videoInstance.id, | ||
256 | type: constants.REQUEST_VIDEO_QADU_TYPES.DISLIKES | ||
257 | }) | ||
258 | } | ||
259 | |||
260 | friends.quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) { | ||
261 | return callback(err, t) | ||
262 | }) | ||
263 | }, | ||
264 | |||
265 | databaseUtils.commitTransaction | ||
266 | |||
267 | ], function (err, t) { | ||
268 | if (err) { | ||
269 | // This is just a debug because we will retry the insert | ||
270 | logger.debug('Cannot add the user video rate.', { error: err }) | ||
271 | return databaseUtils.rollbackTransaction(err, t, finalCallback) | ||
272 | } | ||
273 | |||
274 | logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username) | ||
275 | return finalCallback(null) | ||
276 | }) | ||
277 | } | ||
278 | |||
279 | // Wrapper to video add that retry the function if there is a database error | ||
280 | // We need this because we run the transaction in SERIALIZABLE isolation that can fail | ||
281 | function addVideoRetryWrapper (req, res, next) { | ||
282 | const options = { | ||
283 | arguments: [ req, res, req.files.videofile[0] ], | ||
284 | errorMessage: 'Cannot insert the video with many retries.' | ||
285 | } | ||
286 | |||
287 | databaseUtils.retryTransactionWrapper(addVideo, options, function (err) { | ||
288 | if (err) return next(err) | ||
289 | |||
290 | // TODO : include Location of the new video -> 201 | ||
291 | return res.type('json').status(204).end() | ||
292 | }) | ||
293 | } | ||
294 | |||
295 | function addVideo (req, res, videoFile, finalCallback) { | ||
296 | const videoInfos = req.body | ||
297 | |||
298 | waterfall([ | ||
299 | |||
300 | databaseUtils.startSerializableTransaction, | ||
301 | |||
302 | function findOrCreateAuthor (t, callback) { | ||
303 | const user = res.locals.oauth.token.User | ||
304 | |||
305 | const name = user.username | ||
306 | // null because it is OUR pod | ||
307 | const podId = null | ||
308 | const userId = user.id | ||
309 | |||
310 | db.Author.findOrCreateAuthor(name, podId, userId, t, function (err, authorInstance) { | ||
311 | return callback(err, t, authorInstance) | ||
312 | }) | ||
313 | }, | ||
314 | |||
315 | function findOrCreateTags (t, author, callback) { | ||
316 | const tags = videoInfos.tags | ||
317 | |||
318 | db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) { | ||
319 | return callback(err, t, author, tagInstances) | ||
320 | }) | ||
321 | }, | ||
322 | |||
323 | function createVideoObject (t, author, tagInstances, callback) { | ||
324 | const videoData = { | ||
325 | name: videoInfos.name, | ||
326 | remoteId: null, | ||
327 | extname: path.extname(videoFile.filename), | ||
328 | category: videoInfos.category, | ||
329 | licence: videoInfos.licence, | ||
330 | language: videoInfos.language, | ||
331 | nsfw: videoInfos.nsfw, | ||
332 | description: videoInfos.description, | ||
333 | duration: videoFile.duration, | ||
334 | authorId: author.id | ||
335 | } | ||
336 | |||
337 | const video = db.Video.build(videoData) | ||
338 | |||
339 | return callback(null, t, author, tagInstances, video) | ||
340 | }, | ||
341 | |||
342 | // Set the videoname the same as the id | ||
343 | function renameVideoFile (t, author, tagInstances, video, callback) { | ||
344 | const videoDir = constants.CONFIG.STORAGE.VIDEOS_DIR | ||
345 | const source = path.join(videoDir, videoFile.filename) | ||
346 | const destination = path.join(videoDir, video.getVideoFilename()) | ||
347 | |||
348 | fs.rename(source, destination, function (err) { | ||
349 | if (err) return callback(err) | ||
350 | |||
351 | // This is important in case if there is another attempt | ||
352 | videoFile.filename = video.getVideoFilename() | ||
353 | return callback(null, t, author, tagInstances, video) | ||
354 | }) | ||
355 | }, | ||
356 | |||
357 | function insertVideoIntoDB (t, author, tagInstances, video, callback) { | ||
358 | const options = { transaction: t } | ||
359 | |||
360 | // Add tags association | ||
361 | video.save(options).asCallback(function (err, videoCreated) { | ||
362 | if (err) return callback(err) | ||
363 | |||
364 | // Do not forget to add Author informations to the created video | ||
365 | videoCreated.Author = author | ||
366 | |||
367 | return callback(err, t, tagInstances, videoCreated) | ||
368 | }) | ||
369 | }, | ||
370 | |||
371 | function associateTagsToVideo (t, tagInstances, video, callback) { | ||
372 | const options = { transaction: t } | ||
373 | |||
374 | video.setTags(tagInstances, options).asCallback(function (err) { | ||
375 | video.Tags = tagInstances | ||
376 | |||
377 | return callback(err, t, video) | ||
378 | }) | ||
379 | }, | ||
380 | |||
381 | function sendToFriends (t, video, callback) { | ||
382 | // Let transcoding job send the video to friends because the videofile extension might change | ||
383 | if (constants.CONFIG.TRANSCODING.ENABLED === true) return callback(null, t) | ||
384 | |||
385 | video.toAddRemoteJSON(function (err, remoteVideo) { | ||
386 | if (err) return callback(err) | ||
387 | |||
388 | // Now we'll add the video's meta data to our friends | ||
389 | friends.addVideoToFriends(remoteVideo, t, function (err) { | ||
390 | return callback(err, t) | ||
391 | }) | ||
392 | }) | ||
393 | }, | ||
394 | |||
395 | databaseUtils.commitTransaction | ||
396 | |||
397 | ], function andFinally (err, t) { | ||
398 | if (err) { | ||
399 | // This is just a debug because we will retry the insert | ||
400 | logger.debug('Cannot insert the video.', { error: err }) | ||
401 | return databaseUtils.rollbackTransaction(err, t, finalCallback) | ||
402 | } | ||
403 | |||
404 | logger.info('Video with name %s created.', videoInfos.name) | ||
405 | return finalCallback(null) | ||
406 | }) | ||
407 | } | ||
408 | |||
409 | function updateVideoRetryWrapper (req, res, next) { | ||
410 | const options = { | ||
411 | arguments: [ req, res ], | ||
412 | errorMessage: 'Cannot update the video with many retries.' | ||
413 | } | ||
414 | |||
415 | databaseUtils.retryTransactionWrapper(updateVideo, options, function (err) { | ||
416 | if (err) return next(err) | ||
417 | |||
418 | // TODO : include Location of the new video -> 201 | ||
419 | return res.type('json').status(204).end() | ||
420 | }) | ||
421 | } | ||
422 | |||
423 | function updateVideo (req, res, finalCallback) { | ||
424 | const videoInstance = res.locals.video | ||
425 | const videoFieldsSave = videoInstance.toJSON() | ||
426 | const videoInfosToUpdate = req.body | ||
427 | |||
428 | waterfall([ | ||
429 | |||
430 | databaseUtils.startSerializableTransaction, | ||
431 | |||
432 | function findOrCreateTags (t, callback) { | ||
433 | if (videoInfosToUpdate.tags) { | ||
434 | db.Tag.findOrCreateTags(videoInfosToUpdate.tags, t, function (err, tagInstances) { | ||
435 | return callback(err, t, tagInstances) | ||
436 | }) | ||
437 | } else { | ||
438 | return callback(null, t, null) | ||
439 | } | ||
440 | }, | ||
441 | |||
442 | function updateVideoIntoDB (t, tagInstances, callback) { | ||
443 | const options = { | ||
444 | transaction: t | ||
445 | } | ||
446 | |||
447 | if (videoInfosToUpdate.name !== undefined) videoInstance.set('name', videoInfosToUpdate.name) | ||
448 | if (videoInfosToUpdate.category !== undefined) videoInstance.set('category', videoInfosToUpdate.category) | ||
449 | if (videoInfosToUpdate.licence !== undefined) videoInstance.set('licence', videoInfosToUpdate.licence) | ||
450 | if (videoInfosToUpdate.language !== undefined) videoInstance.set('language', videoInfosToUpdate.language) | ||
451 | if (videoInfosToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfosToUpdate.nsfw) | ||
452 | if (videoInfosToUpdate.description !== undefined) videoInstance.set('description', videoInfosToUpdate.description) | ||
453 | |||
454 | videoInstance.save(options).asCallback(function (err) { | ||
455 | return callback(err, t, tagInstances) | ||
456 | }) | ||
457 | }, | ||
458 | |||
459 | function associateTagsToVideo (t, tagInstances, callback) { | ||
460 | if (tagInstances) { | ||
461 | const options = { transaction: t } | ||
462 | |||
463 | videoInstance.setTags(tagInstances, options).asCallback(function (err) { | ||
464 | videoInstance.Tags = tagInstances | ||
465 | |||
466 | return callback(err, t) | ||
467 | }) | ||
468 | } else { | ||
469 | return callback(null, t) | ||
470 | } | ||
471 | }, | ||
472 | |||
473 | function sendToFriends (t, callback) { | ||
474 | const json = videoInstance.toUpdateRemoteJSON() | ||
475 | |||
476 | // Now we'll update the video's meta data to our friends | ||
477 | friends.updateVideoToFriends(json, t, function (err) { | ||
478 | return callback(err, t) | ||
479 | }) | ||
480 | }, | ||
481 | |||
482 | databaseUtils.commitTransaction | ||
483 | |||
484 | ], function andFinally (err, t) { | ||
485 | if (err) { | ||
486 | logger.debug('Cannot update the video.', { error: err }) | ||
487 | |||
488 | // Force fields we want to update | ||
489 | // If the transaction is retried, sequelize will think the object has not changed | ||
490 | // So it will skip the SQL request, even if the last one was ROLLBACKed! | ||
491 | Object.keys(videoFieldsSave).forEach(function (key) { | ||
492 | const value = videoFieldsSave[key] | ||
493 | videoInstance.set(key, value) | ||
494 | }) | ||
495 | |||
496 | return databaseUtils.rollbackTransaction(err, t, finalCallback) | ||
497 | } | ||
498 | |||
499 | logger.info('Video with name %s updated.', videoInfosToUpdate.name) | ||
500 | return finalCallback(null) | ||
501 | }) | ||
502 | } | ||
503 | |||
504 | function getVideo (req, res, next) { | ||
505 | const videoInstance = res.locals.video | ||
506 | |||
507 | if (videoInstance.isOwned()) { | ||
508 | // The increment is done directly in the database, not using the instance value | ||
509 | videoInstance.increment('views').asCallback(function (err) { | ||
510 | if (err) { | ||
511 | logger.error('Cannot add view to video %d.', videoInstance.id) | ||
512 | return | ||
513 | } | ||
514 | |||
515 | // FIXME: make a real view system | ||
516 | // For example, only add a view when a user watch a video during 30s etc | ||
517 | const qaduParams = { | ||
518 | videoId: videoInstance.id, | ||
519 | type: constants.REQUEST_VIDEO_QADU_TYPES.VIEWS | ||
520 | } | ||
521 | friends.quickAndDirtyUpdateVideoToFriends(qaduParams) | ||
522 | }) | ||
523 | } else { | ||
524 | // Just send the event to our friends | ||
525 | const eventParams = { | ||
526 | videoId: videoInstance.id, | ||
527 | type: constants.REQUEST_VIDEO_EVENT_TYPES.VIEWS | ||
528 | } | ||
529 | friends.addEventToRemoteVideo(eventParams) | ||
530 | } | ||
531 | |||
532 | // Do not wait the view system | ||
533 | res.json(videoInstance.toFormatedJSON()) | ||
534 | } | ||
535 | |||
536 | function listVideos (req, res, next) { | ||
537 | db.Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) { | ||
538 | if (err) return next(err) | ||
539 | |||
540 | res.json(utils.getFormatedObjects(videosList, videosTotal)) | ||
541 | }) | ||
542 | } | ||
543 | |||
544 | function removeVideo (req, res, next) { | ||
545 | const videoInstance = res.locals.video | ||
546 | |||
547 | videoInstance.destroy().asCallback(function (err) { | ||
548 | if (err) { | ||
549 | logger.error('Errors when removed the video.', { error: err }) | ||
550 | return next(err) | ||
551 | } | ||
552 | |||
553 | return res.type('json').status(204).end() | ||
554 | }) | ||
555 | } | ||
556 | |||
557 | function searchVideos (req, res, next) { | ||
558 | db.Video.searchAndPopulateAuthorAndPodAndTags( | ||
559 | req.params.value, req.query.field, req.query.start, req.query.count, req.query.sort, | ||
560 | function (err, videosList, videosTotal) { | ||
561 | if (err) return next(err) | ||
562 | |||
563 | res.json(utils.getFormatedObjects(videosList, videosTotal)) | ||
564 | } | ||
565 | ) | ||
566 | } | ||
567 | |||
568 | function listVideoAbuses (req, res, next) { | ||
569 | db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort, function (err, abusesList, abusesTotal) { | ||
570 | if (err) return next(err) | ||
571 | |||
572 | res.json(utils.getFormatedObjects(abusesList, abusesTotal)) | ||
573 | }) | ||
574 | } | ||
575 | |||
576 | function reportVideoAbuseRetryWrapper (req, res, next) { | ||
577 | const options = { | ||
578 | arguments: [ req, res ], | ||
579 | errorMessage: 'Cannot report abuse to the video with many retries.' | ||
580 | } | ||
581 | |||
582 | databaseUtils.retryTransactionWrapper(reportVideoAbuse, options, function (err) { | ||
583 | if (err) return next(err) | ||
584 | |||
585 | return res.type('json').status(204).end() | ||
586 | }) | ||
587 | } | ||
588 | |||
589 | function reportVideoAbuse (req, res, finalCallback) { | ||
590 | const videoInstance = res.locals.video | ||
591 | const reporterUsername = res.locals.oauth.token.User.username | ||
592 | |||
593 | const abuse = { | ||
594 | reporterUsername, | ||
595 | reason: req.body.reason, | ||
596 | videoId: videoInstance.id, | ||
597 | reporterPodId: null // This is our pod that reported this abuse | ||
598 | } | ||
599 | |||
600 | waterfall([ | ||
601 | |||
602 | databaseUtils.startSerializableTransaction, | ||
603 | |||
604 | function createAbuse (t, callback) { | ||
605 | db.VideoAbuse.create(abuse).asCallback(function (err, abuse) { | ||
606 | return callback(err, t, abuse) | ||
607 | }) | ||
608 | }, | ||
609 | |||
610 | function sendToFriendsIfNeeded (t, abuse, callback) { | ||
611 | // We send the information to the destination pod | ||
612 | if (videoInstance.isOwned() === false) { | ||
613 | const reportData = { | ||
614 | reporterUsername, | ||
615 | reportReason: abuse.reason, | ||
616 | videoRemoteId: videoInstance.remoteId | ||
617 | } | ||
618 | |||
619 | friends.reportAbuseVideoToFriend(reportData, videoInstance) | ||
620 | } | ||
621 | |||
622 | return callback(null, t) | ||
623 | }, | ||
624 | |||
625 | databaseUtils.commitTransaction | ||
626 | |||
627 | ], function andFinally (err, t) { | ||
628 | if (err) { | ||
629 | logger.debug('Cannot update the video.', { error: err }) | ||
630 | return databaseUtils.rollbackTransaction(err, t, finalCallback) | ||
631 | } | ||
632 | |||
633 | logger.info('Abuse report for video %s created.', videoInstance.name) | ||
634 | return finalCallback(null) | ||
635 | }) | ||
636 | } | ||
637 | |||
638 | function addVideoToBlacklist (req, res, next) { | ||
639 | const videoInstance = res.locals.video | ||
640 | |||
641 | const toCreate = { | ||
642 | videoId: videoInstance.id | ||
643 | } | ||
644 | |||
645 | db.BlacklistedVideo.create(toCreate).asCallback(function (err) { | ||
646 | if (err) { | ||
647 | logger.error('Errors when blacklisting video ', { error: err }) | ||
648 | return next(err) | ||
649 | } | ||
650 | |||
651 | return res.type('json').status(204).end() | ||
652 | }) | ||
653 | } | ||