aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/api')
-rw-r--r--server/controllers/api/videos/abuse.js112
-rw-r--r--server/controllers/api/videos/blacklist.js43
-rw-r--r--server/controllers/api/videos/index.js (renamed from server/controllers/api/videos.js)279
-rw-r--r--server/controllers/api/videos/rate.js169
4 files changed, 339 insertions, 264 deletions
diff --git a/server/controllers/api/videos/abuse.js b/server/controllers/api/videos/abuse.js
new file mode 100644
index 000000000..0fb44bb14
--- /dev/null
+++ b/server/controllers/api/videos/abuse.js
@@ -0,0 +1,112 @@
1'use strict'
2
3const express = require('express')
4const waterfall = require('async/waterfall')
5
6const db = require('../../../initializers/database')
7const logger = require('../../../helpers/logger')
8const friends = require('../../../lib/friends')
9const middlewares = require('../../../middlewares')
10const admin = middlewares.admin
11const oAuth = middlewares.oauth
12const pagination = middlewares.pagination
13const validators = middlewares.validators
14const validatorsPagination = validators.pagination
15const validatorsSort = validators.sort
16const validatorsVideos = validators.videos
17const sort = middlewares.sort
18const databaseUtils = require('../../../helpers/database-utils')
19const utils = require('../../../helpers/utils')
20
21const router = express.Router()
22
23router.get('/abuse',
24 oAuth.authenticate,
25 admin.ensureIsAdmin,
26 validatorsPagination.pagination,
27 validatorsSort.videoAbusesSort,
28 sort.setVideoAbusesSort,
29 pagination.setPagination,
30 listVideoAbuses
31)
32router.post('/:id/abuse',
33 oAuth.authenticate,
34 validatorsVideos.videoAbuseReport,
35 reportVideoAbuseRetryWrapper
36)
37
38// ---------------------------------------------------------------------------
39
40module.exports = router
41
42// ---------------------------------------------------------------------------
43
44function listVideoAbuses (req, res, next) {
45 db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort, function (err, abusesList, abusesTotal) {
46 if (err) return next(err)
47
48 res.json(utils.getFormatedObjects(abusesList, abusesTotal))
49 })
50}
51
52function reportVideoAbuseRetryWrapper (req, res, next) {
53 const options = {
54 arguments: [ req, res ],
55 errorMessage: 'Cannot report abuse to the video with many retries.'
56 }
57
58 databaseUtils.retryTransactionWrapper(reportVideoAbuse, options, function (err) {
59 if (err) return next(err)
60
61 return res.type('json').status(204).end()
62 })
63}
64
65function reportVideoAbuse (req, res, finalCallback) {
66 const videoInstance = res.locals.video
67 const reporterUsername = res.locals.oauth.token.User.username
68
69 const abuse = {
70 reporterUsername,
71 reason: req.body.reason,
72 videoId: videoInstance.id,
73 reporterPodId: null // This is our pod that reported this abuse
74 }
75
76 waterfall([
77
78 databaseUtils.startSerializableTransaction,
79
80 function createAbuse (t, callback) {
81 db.VideoAbuse.create(abuse).asCallback(function (err, abuse) {
82 return callback(err, t, abuse)
83 })
84 },
85
86 function sendToFriendsIfNeeded (t, abuse, callback) {
87 // We send the information to the destination pod
88 if (videoInstance.isOwned() === false) {
89 const reportData = {
90 reporterUsername,
91 reportReason: abuse.reason,
92 videoRemoteId: videoInstance.remoteId
93 }
94
95 friends.reportAbuseVideoToFriend(reportData, videoInstance)
96 }
97
98 return callback(null, t)
99 },
100
101 databaseUtils.commitTransaction
102
103 ], function andFinally (err, t) {
104 if (err) {
105 logger.debug('Cannot update the video.', { error: err })
106 return databaseUtils.rollbackTransaction(err, t, finalCallback)
107 }
108
109 logger.info('Abuse report for video %s created.', videoInstance.name)
110 return finalCallback(null)
111 })
112}
diff --git a/server/controllers/api/videos/blacklist.js b/server/controllers/api/videos/blacklist.js
new file mode 100644
index 000000000..8c3e2a69d
--- /dev/null
+++ b/server/controllers/api/videos/blacklist.js
@@ -0,0 +1,43 @@
1'use strict'
2
3const express = require('express')
4
5const db = require('../../../initializers/database')
6const logger = require('../../../helpers/logger')
7const middlewares = require('../../../middlewares')
8const admin = middlewares.admin
9const oAuth = middlewares.oauth
10const validators = middlewares.validators
11const validatorsVideos = validators.videos
12
13const router = express.Router()
14
15router.post('/:id/blacklist',
16 oAuth.authenticate,
17 admin.ensureIsAdmin,
18 validatorsVideos.videosBlacklist,
19 addVideoToBlacklist
20)
21
22// ---------------------------------------------------------------------------
23
24module.exports = router
25
26// ---------------------------------------------------------------------------
27
28function addVideoToBlacklist (req, res, next) {
29 const videoInstance = res.locals.video
30
31 const toCreate = {
32 videoId: videoInstance.id
33 }
34
35 db.BlacklistedVideo.create(toCreate).asCallback(function (err) {
36 if (err) {
37 logger.error('Errors when blacklisting video ', { error: err })
38 return next(err)
39 }
40
41 return res.type('json').status(204).end()
42 })
43}
diff --git a/server/controllers/api/videos.js b/server/controllers/api/videos/index.js
index aeefaa555..8de44d5ac 100644
--- a/server/controllers/api/videos.js
+++ b/server/controllers/api/videos/index.js
@@ -6,12 +6,11 @@ const multer = require('multer')
6const path = require('path') 6const path = require('path')
7const waterfall = require('async/waterfall') 7const waterfall = require('async/waterfall')
8 8
9const constants = require('../../initializers/constants') 9const constants = require('../../../initializers/constants')
10const db = require('../../initializers/database') 10const db = require('../../../initializers/database')
11const logger = require('../../helpers/logger') 11const logger = require('../../../helpers/logger')
12const friends = require('../../lib/friends') 12const friends = require('../../../lib/friends')
13const middlewares = require('../../middlewares') 13const middlewares = require('../../../middlewares')
14const admin = middlewares.admin
15const oAuth = middlewares.oauth 14const oAuth = middlewares.oauth
16const pagination = middlewares.pagination 15const pagination = middlewares.pagination
17const validators = middlewares.validators 16const validators = middlewares.validators
@@ -20,8 +19,12 @@ const validatorsSort = validators.sort
20const validatorsVideos = validators.videos 19const validatorsVideos = validators.videos
21const search = middlewares.search 20const search = middlewares.search
22const sort = middlewares.sort 21const sort = middlewares.sort
23const databaseUtils = require('../../helpers/database-utils') 22const databaseUtils = require('../../../helpers/database-utils')
24const utils = require('../../helpers/utils') 23const utils = require('../../../helpers/utils')
24
25const abuseController = require('./abuse')
26const blacklistController = require('./blacklist')
27const rateController = require('./rate')
25 28
26const router = express.Router() 29const router = express.Router()
27 30
@@ -45,31 +48,14 @@ const storage = multer.diskStorage({
45 48
46const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }]) 49const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }])
47 50
51router.use('/', abuseController)
52router.use('/', blacklistController)
53router.use('/', rateController)
54
48router.get('/categories', listVideoCategories) 55router.get('/categories', listVideoCategories)
49router.get('/licences', listVideoLicences) 56router.get('/licences', listVideoLicences)
50router.get('/languages', listVideoLanguages) 57router.get('/languages', listVideoLanguages)
51 58
52router.get('/abuse',
53 oAuth.authenticate,
54 admin.ensureIsAdmin,
55 validatorsPagination.pagination,
56 validatorsSort.videoAbusesSort,
57 sort.setVideoAbusesSort,
58 pagination.setPagination,
59 listVideoAbuses
60)
61router.post('/:id/abuse',
62 oAuth.authenticate,
63 validatorsVideos.videoAbuseReport,
64 reportVideoAbuseRetryWrapper
65)
66
67router.put('/:id/rate',
68 oAuth.authenticate,
69 validatorsVideos.videoRate,
70 rateVideoRetryWrapper
71)
72
73router.get('/', 59router.get('/',
74 validatorsPagination.pagination, 60 validatorsPagination.pagination,
75 validatorsSort.videosSort, 61 validatorsSort.videosSort,
@@ -110,13 +96,6 @@ router.get('/search/:value',
110 searchVideos 96 searchVideos
111) 97)
112 98
113router.post('/:id/blacklist',
114 oAuth.authenticate,
115 admin.ensureIsAdmin,
116 validatorsVideos.videosBlacklist,
117 addVideoToBlacklist
118)
119
120// --------------------------------------------------------------------------- 99// ---------------------------------------------------------------------------
121 100
122module.exports = router 101module.exports = router
@@ -135,147 +114,6 @@ function listVideoLanguages (req, res, next) {
135 res.json(constants.VIDEO_LANGUAGES) 114 res.json(constants.VIDEO_LANGUAGES)
136} 115}
137 116
138function 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
151function 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 117// 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 118// We need this because we run the transaction in SERIALIZABLE isolation that can fail
281function addVideoRetryWrapper (req, res, next) { 119function addVideoRetryWrapper (req, res, next) {
@@ -564,90 +402,3 @@ function searchVideos (req, res, next) {
564 } 402 }
565 ) 403 )
566} 404}
567
568function 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
576function 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
589function 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
638function 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}
diff --git a/server/controllers/api/videos/rate.js b/server/controllers/api/videos/rate.js
new file mode 100644
index 000000000..df8a69a1d
--- /dev/null
+++ b/server/controllers/api/videos/rate.js
@@ -0,0 +1,169 @@
1'use strict'
2
3const express = require('express')
4const waterfall = require('async/waterfall')
5
6const constants = require('../../../initializers/constants')
7const db = require('../../../initializers/database')
8const logger = require('../../../helpers/logger')
9const friends = require('../../../lib/friends')
10const middlewares = require('../../../middlewares')
11const oAuth = middlewares.oauth
12const validators = middlewares.validators
13const validatorsVideos = validators.videos
14const databaseUtils = require('../../../helpers/database-utils')
15
16const router = express.Router()
17
18router.put('/:id/rate',
19 oAuth.authenticate,
20 validatorsVideos.videoRate,
21 rateVideoRetryWrapper
22)
23
24// ---------------------------------------------------------------------------
25
26module.exports = router
27
28// ---------------------------------------------------------------------------
29
30function rateVideoRetryWrapper (req, res, next) {
31 const options = {
32 arguments: [ req, res ],
33 errorMessage: 'Cannot update the user video rate.'
34 }
35
36 databaseUtils.retryTransactionWrapper(rateVideo, options, function (err) {
37 if (err) return next(err)
38
39 return res.type('json').status(204).end()
40 })
41}
42
43function rateVideo (req, res, finalCallback) {
44 const rateType = req.body.rating
45 const videoInstance = res.locals.video
46 const userInstance = res.locals.oauth.token.User
47
48 waterfall([
49 databaseUtils.startSerializableTransaction,
50
51 function findPreviousRate (t, callback) {
52 db.UserVideoRate.load(userInstance.id, videoInstance.id, t, function (err, previousRate) {
53 return callback(err, t, previousRate)
54 })
55 },
56
57 function insertUserRateIntoDB (t, previousRate, callback) {
58 const options = { transaction: t }
59
60 let likesToIncrement = 0
61 let dislikesToIncrement = 0
62
63 if (rateType === constants.VIDEO_RATE_TYPES.LIKE) likesToIncrement++
64 else if (rateType === constants.VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
65
66 // There was a previous rate, update it
67 if (previousRate) {
68 // We will remove the previous rate, so we will need to remove it from the video attribute
69 if (previousRate.type === constants.VIDEO_RATE_TYPES.LIKE) likesToIncrement--
70 else if (previousRate.type === constants.VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
71
72 previousRate.type = rateType
73
74 previousRate.save(options).asCallback(function (err) {
75 return callback(err, t, likesToIncrement, dislikesToIncrement)
76 })
77 } else { // There was not a previous rate, insert a new one
78 const query = {
79 userId: userInstance.id,
80 videoId: videoInstance.id,
81 type: rateType
82 }
83
84 db.UserVideoRate.create(query, options).asCallback(function (err) {
85 return callback(err, t, likesToIncrement, dislikesToIncrement)
86 })
87 }
88 },
89
90 function updateVideoAttributeDB (t, likesToIncrement, dislikesToIncrement, callback) {
91 const options = { transaction: t }
92 const incrementQuery = {
93 likes: likesToIncrement,
94 dislikes: dislikesToIncrement
95 }
96
97 // Even if we do not own the video we increment the attributes
98 // It is usefull for the user to have a feedback
99 videoInstance.increment(incrementQuery, options).asCallback(function (err) {
100 return callback(err, t, likesToIncrement, dislikesToIncrement)
101 })
102 },
103
104 function sendEventsToFriendsIfNeeded (t, likesToIncrement, dislikesToIncrement, callback) {
105 // No need for an event type, we own the video
106 if (videoInstance.isOwned()) return callback(null, t, likesToIncrement, dislikesToIncrement)
107
108 const eventsParams = []
109
110 if (likesToIncrement !== 0) {
111 eventsParams.push({
112 videoId: videoInstance.id,
113 type: constants.REQUEST_VIDEO_EVENT_TYPES.LIKES,
114 count: likesToIncrement
115 })
116 }
117
118 if (dislikesToIncrement !== 0) {
119 eventsParams.push({
120 videoId: videoInstance.id,
121 type: constants.REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
122 count: dislikesToIncrement
123 })
124 }
125
126 friends.addEventsToRemoteVideo(eventsParams, t, function (err) {
127 return callback(err, t, likesToIncrement, dislikesToIncrement)
128 })
129 },
130
131 function sendQaduToFriendsIfNeeded (t, likesToIncrement, dislikesToIncrement, callback) {
132 // We do not own the video, there is no need to send a quick and dirty update to friends
133 // Our rate was already sent by the addEvent function
134 if (videoInstance.isOwned() === false) return callback(null, t)
135
136 const qadusParams = []
137
138 if (likesToIncrement !== 0) {
139 qadusParams.push({
140 videoId: videoInstance.id,
141 type: constants.REQUEST_VIDEO_QADU_TYPES.LIKES
142 })
143 }
144
145 if (dislikesToIncrement !== 0) {
146 qadusParams.push({
147 videoId: videoInstance.id,
148 type: constants.REQUEST_VIDEO_QADU_TYPES.DISLIKES
149 })
150 }
151
152 friends.quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) {
153 return callback(err, t)
154 })
155 },
156
157 databaseUtils.commitTransaction
158
159 ], function (err, t) {
160 if (err) {
161 // This is just a debug because we will retry the insert
162 logger.debug('Cannot add the user video rate.', { error: err })
163 return databaseUtils.rollbackTransaction(err, t, finalCallback)
164 }
165
166 logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username)
167 return finalCallback(null)
168 })
169}