aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2017-01-04 20:59:23 +0100
committerChocobozzz <florian.bigard@gmail.com>2017-01-04 21:05:13 +0100
commit55fa55a9be566cca2ba95322f2ae23b434aed62a (patch)
treef51ef35c120ce8a928917a659418079538cdb8dc
parenta6fd2b30bf717eec14972a2175354781f5f43e77 (diff)
downloadPeerTube-55fa55a9be566cca2ba95322f2ae23b434aed62a.tar.gz
PeerTube-55fa55a9be566cca2ba95322f2ae23b434aed62a.tar.zst
PeerTube-55fa55a9be566cca2ba95322f2ae23b434aed62a.zip
Server: add video abuse support
-rw-r--r--client/src/app/admin/friends/friend-list/friend-list.component.ts2
-rw-r--r--client/src/app/admin/friends/shared/friend.service.ts16
-rw-r--r--config/default.yaml4
-rw-r--r--server.js3
-rw-r--r--server/controllers/api/pods.js17
-rw-r--r--server/controllers/api/remote/videos.js68
-rw-r--r--server/controllers/api/users.js18
-rw-r--r--server/controllers/api/videos.js61
-rw-r--r--server/helpers/custom-validators/index.js2
-rw-r--r--server/helpers/custom-validators/remote/index.js11
-rw-r--r--server/helpers/custom-validators/remote/videos.js74
-rw-r--r--server/helpers/custom-validators/videos.js66
-rw-r--r--server/helpers/utils.js16
-rw-r--r--server/initializers/constants.js4
-rw-r--r--server/lib/friends.js39
-rw-r--r--server/middlewares/sort.js7
-rw-r--r--server/middlewares/validators/remote/index.js13
-rw-r--r--server/middlewares/validators/remote/signature.js (renamed from server/middlewares/validators/remote.js)17
-rw-r--r--server/middlewares/validators/remote/videos.js20
-rw-r--r--server/middlewares/validators/sort.js23
-rw-r--r--server/middlewares/validators/videos.js15
-rw-r--r--server/models/request-to-pod.js (renamed from server/models/requestToPod.js)0
-rw-r--r--server/models/video-abuse.js113
-rw-r--r--server/models/video-tag.js (renamed from server/models/videoTag.js)0
-rw-r--r--server/models/video.js8
-rw-r--r--server/tests/api/check-params/index.js1
-rw-r--r--server/tests/api/check-params/remotes.js4
-rw-r--r--server/tests/api/check-params/video-abuses.js180
-rw-r--r--server/tests/api/friends-advanced.js10
-rw-r--r--server/tests/api/friends-basic.js12
-rw-r--r--server/tests/api/video-abuse.js191
-rw-r--r--server/tests/utils/video-abuses.js73
32 files changed, 917 insertions, 171 deletions
diff --git a/client/src/app/admin/friends/friend-list/friend-list.component.ts b/client/src/app/admin/friends/friend-list/friend-list.component.ts
index 88c4800ee..bec10162c 100644
--- a/client/src/app/admin/friends/friend-list/friend-list.component.ts
+++ b/client/src/app/admin/friends/friend-list/friend-list.component.ts
@@ -30,7 +30,7 @@ export class FriendListComponent implements OnInit {
30 30
31 private getFriends() { 31 private getFriends() {
32 this.friendService.getFriends().subscribe( 32 this.friendService.getFriends().subscribe(
33 friends => this.friends = friends, 33 res => this.friends = res.friends,
34 34
35 err => alert(err.text) 35 err => alert(err.text)
36 ); 36 );
diff --git a/client/src/app/admin/friends/shared/friend.service.ts b/client/src/app/admin/friends/shared/friend.service.ts
index 8a1ba6b02..85ac04ba0 100644
--- a/client/src/app/admin/friends/shared/friend.service.ts
+++ b/client/src/app/admin/friends/shared/friend.service.ts
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
2import { Observable } from 'rxjs/Observable'; 2import { Observable } from 'rxjs/Observable';
3 3
4import { Friend } from './friend.model'; 4import { Friend } from './friend.model';
5import { AuthHttp, RestExtractor } from '../../../shared'; 5import { AuthHttp, RestExtractor, ResultList } from '../../../shared';
6 6
7@Injectable() 7@Injectable()
8export class FriendService { 8export class FriendService {
@@ -13,11 +13,10 @@ export class FriendService {
13 private restExtractor: RestExtractor 13 private restExtractor: RestExtractor
14 ) {} 14 ) {}
15 15
16 getFriends(): Observable<Friend[]> { 16 getFriends() {
17 return this.authHttp.get(FriendService.BASE_FRIEND_URL) 17 return this.authHttp.get(FriendService.BASE_FRIEND_URL)
18 // Not implemented as a data list by the server yet 18 .map(this.restExtractor.extractDataList)
19 // .map(this.restExtractor.extractDataList) 19 .map(this.extractFriends)
20 .map((res) => res.json())
21 .catch((res) => this.restExtractor.handleError(res)); 20 .catch((res) => this.restExtractor.handleError(res));
22 } 21 }
23 22
@@ -36,4 +35,11 @@ export class FriendService {
36 .map(res => res.status) 35 .map(res => res.status)
37 .catch((res) => this.restExtractor.handleError(res)); 36 .catch((res) => this.restExtractor.handleError(res));
38 } 37 }
38
39 private extractFriends(result: ResultList) {
40 const friends: Friend[] = result.data;
41 const totalFriends = result.total;
42
43 return { friends, totalFriends };
44 }
39} 45}
diff --git a/config/default.yaml b/config/default.yaml
index 2dd5e05f9..0939ae4ba 100644
--- a/config/default.yaml
+++ b/config/default.yaml
@@ -10,8 +10,8 @@ database:
10 hostname: 'localhost' 10 hostname: 'localhost'
11 port: 5432 11 port: 5432
12 suffix: '_dev' 12 suffix: '_dev'
13 username: peertube 13 username: 'peertube'
14 password: peertube 14 password: 'peertube'
15 15
16# From the project root directory 16# From the project root directory
17storage: 17storage:
diff --git a/server.js b/server.js
index f4ca53907..7503072af 100644
--- a/server.js
+++ b/server.js
@@ -57,7 +57,8 @@ app.use(expressValidator({
57 customValidators.misc, 57 customValidators.misc,
58 customValidators.pods, 58 customValidators.pods,
59 customValidators.users, 59 customValidators.users,
60 customValidators.videos 60 customValidators.videos,
61 customValidators.remote.videos
61 ) 62 )
62})) 63}))
63 64
diff --git a/server/controllers/api/pods.js b/server/controllers/api/pods.js
index d9279f1d9..38702face 100644
--- a/server/controllers/api/pods.js
+++ b/server/controllers/api/pods.js
@@ -5,6 +5,7 @@ const waterfall = require('async/waterfall')
5 5
6const db = require('../../initializers/database') 6const db = require('../../initializers/database')
7const logger = require('../../helpers/logger') 7const logger = require('../../helpers/logger')
8const utils = require('../../helpers/utils')
8const friends = require('../../lib/friends') 9const friends = require('../../lib/friends')
9const middlewares = require('../../middlewares') 10const middlewares = require('../../middlewares')
10const admin = middlewares.admin 11const admin = middlewares.admin
@@ -36,7 +37,7 @@ router.get('/quitfriends',
36) 37)
37// Post because this is a secured request 38// Post because this is a secured request
38router.post('/remove', 39router.post('/remove',
39 signatureValidator, 40 signatureValidator.signature,
40 checkSignature, 41 checkSignature,
41 removePods 42 removePods
42) 43)
@@ -86,7 +87,7 @@ function listPods (req, res, next) {
86 db.Pod.list(function (err, podsList) { 87 db.Pod.list(function (err, podsList) {
87 if (err) return next(err) 88 if (err) return next(err)
88 89
89 res.json(getFormatedPods(podsList)) 90 res.json(utils.getFormatedObjects(podsList, podsList.length))
90 }) 91 })
91} 92}
92 93
@@ -130,15 +131,3 @@ function quitFriends (req, res, next) {
130 res.type('json').status(204).end() 131 res.type('json').status(204).end()
131 }) 132 })
132} 133}
133
134// ---------------------------------------------------------------------------
135
136function getFormatedPods (pods) {
137 const formatedPods = []
138
139 pods.forEach(function (pod) {
140 formatedPods.push(pod.toFormatedJSON())
141 })
142
143 return formatedPods
144}
diff --git a/server/controllers/api/remote/videos.js b/server/controllers/api/remote/videos.js
index 87c49bff9..d02da4463 100644
--- a/server/controllers/api/remote/videos.js
+++ b/server/controllers/api/remote/videos.js
@@ -7,15 +7,16 @@ const waterfall = require('async/waterfall')
7const db = require('../../../initializers/database') 7const db = require('../../../initializers/database')
8const middlewares = require('../../../middlewares') 8const middlewares = require('../../../middlewares')
9const secureMiddleware = middlewares.secure 9const secureMiddleware = middlewares.secure
10const validators = middlewares.validators.remote 10const videosValidators = middlewares.validators.remote.videos
11const signatureValidators = middlewares.validators.remote.signature
11const logger = require('../../../helpers/logger') 12const logger = require('../../../helpers/logger')
12 13
13const router = express.Router() 14const router = express.Router()
14 15
15router.post('/', 16router.post('/',
16 validators.signature, 17 signatureValidators.signature,
17 secureMiddleware.checkSignature, 18 secureMiddleware.checkSignature,
18 validators.remoteVideos, 19 videosValidators.remoteVideos,
19 remoteVideos 20 remoteVideos
20) 21)
21 22
@@ -32,19 +33,23 @@ function remoteVideos (req, res, next) {
32 // We need to process in the same order to keep consistency 33 // We need to process in the same order to keep consistency
33 // TODO: optimization 34 // TODO: optimization
34 eachSeries(requests, function (request, callbackEach) { 35 eachSeries(requests, function (request, callbackEach) {
35 const videoData = request.data 36 const data = request.data
36 37
37 switch (request.type) { 38 switch (request.type) {
38 case 'add': 39 case 'add':
39 addRemoteVideo(videoData, fromPod, callbackEach) 40 addRemoteVideo(data, fromPod, callbackEach)
40 break 41 break
41 42
42 case 'update': 43 case 'update':
43 updateRemoteVideo(videoData, fromPod, callbackEach) 44 updateRemoteVideo(data, fromPod, callbackEach)
44 break 45 break
45 46
46 case 'remove': 47 case 'remove':
47 removeRemoteVideo(videoData, fromPod, callbackEach) 48 removeRemoteVideo(data, fromPod, callbackEach)
49 break
50
51 case 'report-abuse':
52 reportAbuseRemoteVideo(data, fromPod, callbackEach)
48 break 53 break
49 54
50 default: 55 default:
@@ -164,13 +169,8 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
164 }, 169 },
165 170
166 function findVideo (t, callback) { 171 function findVideo (t, callback) {
167 db.Video.loadByHostAndRemoteId(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) { 172 fetchVideo(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) {
168 if (err || !videoInstance) { 173 return callback(err, t, videoInstance)
169 logger.error('Cannot load video from host and remote id.', { error: err.message })
170 return callback(err)
171 }
172
173 return callback(null, t, videoInstance)
174 }) 174 })
175 }, 175 },
176 176
@@ -225,13 +225,45 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
225 225
226function removeRemoteVideo (videoToRemoveData, fromPod, callback) { 226function removeRemoteVideo (videoToRemoveData, fromPod, callback) {
227 // We need the instance because we have to remove some other stuffs (thumbnail etc) 227 // We need the instance because we have to remove some other stuffs (thumbnail etc)
228 db.Video.loadByHostAndRemoteId(fromPod.host, videoToRemoveData.remoteId, function (err, video) { 228 fetchVideo(fromPod.host, videoToRemoveData.remoteId, function (err, video) {
229 if (err) return callback(err)
230
231 logger.debug('Removing remote video %s.', video.remoteId)
232 video.destroy().asCallback(callback)
233 })
234}
235
236function reportAbuseRemoteVideo (reportData, fromPod, callback) {
237 db.Video.load(reportData.videoRemoteId, function (err, video) {
229 if (err || !video) { 238 if (err || !video) {
230 logger.error('Cannot load video from host and remote id.', { error: err.message }) 239 if (!err) err = new Error('video not found')
240
241 logger.error('Cannot load video from host and remote id.', { error: err })
231 return callback(err) 242 return callback(err)
232 } 243 }
233 244
234 logger.debug('Removing remote video %s.', video.remoteId) 245 logger.debug('Reporting remote abuse for video %s.', video.id)
235 video.destroy().asCallback(callback) 246
247 const videoAbuseData = {
248 reporterUsername: reportData.reporterUsername,
249 reason: reportData.reportReason,
250 reporterPodId: fromPod.id,
251 videoId: video.id
252 }
253
254 db.VideoAbuse.create(videoAbuseData).asCallback(callback)
255 })
256}
257
258function fetchVideo (podHost, remoteId, callback) {
259 db.Video.loadByHostAndRemoteId(podHost, remoteId, function (err, video) {
260 if (err || !video) {
261 if (!err) err = new Error('video not found')
262
263 logger.error('Cannot load video from host and remote id.', { error: err })
264 return callback(err)
265 }
266
267 return callback(null, video)
236 }) 268 })
237} 269}
diff --git a/server/controllers/api/users.js b/server/controllers/api/users.js
index 53bf56790..6cd0e84f7 100644
--- a/server/controllers/api/users.js
+++ b/server/controllers/api/users.js
@@ -6,6 +6,7 @@ const waterfall = require('async/waterfall')
6const constants = require('../../initializers/constants') 6const constants = require('../../initializers/constants')
7const db = require('../../initializers/database') 7const db = require('../../initializers/database')
8const logger = require('../../helpers/logger') 8const logger = require('../../helpers/logger')
9const utils = require('../../helpers/utils')
9const middlewares = require('../../middlewares') 10const middlewares = require('../../middlewares')
10const admin = middlewares.admin 11const admin = middlewares.admin
11const oAuth = middlewares.oauth 12const oAuth = middlewares.oauth
@@ -82,7 +83,7 @@ function listUsers (req, res, next) {
82 db.User.listForApi(req.query.start, req.query.count, req.query.sort, function (err, usersList, usersTotal) { 83 db.User.listForApi(req.query.start, req.query.count, req.query.sort, function (err, usersList, usersTotal) {
83 if (err) return next(err) 84 if (err) return next(err)
84 85
85 res.json(getFormatedUsers(usersList, usersTotal)) 86 res.json(utils.getFormatedObjects(usersList, usersTotal))
86 }) 87 })
87} 88}
88 89
@@ -121,18 +122,3 @@ function updateUser (req, res, next) {
121function success (req, res, next) { 122function success (req, res, next) {
122 res.end() 123 res.end()
123} 124}
124
125// ---------------------------------------------------------------------------
126
127function getFormatedUsers (users, usersTotal) {
128 const formatedUsers = []
129
130 users.forEach(function (user) {
131 formatedUsers.push(user.toFormatedJSON())
132 })
133
134 return {
135 total: usersTotal,
136 data: formatedUsers
137 }
138}
diff --git a/server/controllers/api/videos.js b/server/controllers/api/videos.js
index 35d6979e5..6829804ec 100644
--- a/server/controllers/api/videos.js
+++ b/server/controllers/api/videos.js
@@ -11,6 +11,7 @@ const 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
14const oAuth = middlewares.oauth 15const oAuth = middlewares.oauth
15const pagination = middlewares.pagination 16const pagination = middlewares.pagination
16const validators = middlewares.validators 17const validators = middlewares.validators
@@ -43,6 +44,21 @@ const storage = multer.diskStorage({
43 44
44const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }]) 45const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }])
45 46
47router.get('/abuse',
48 oAuth.authenticate,
49 admin.ensureIsAdmin,
50 validatorsPagination.pagination,
51 validatorsSort.videoAbusesSort,
52 sort.setVideoAbusesSort,
53 pagination.setPagination,
54 listVideoAbuses
55)
56router.post('/:id/abuse',
57 oAuth.authenticate,
58 validatorsVideos.videoAbuseReport,
59 reportVideoAbuse
60)
61
46router.get('/', 62router.get('/',
47 validatorsPagination.pagination, 63 validatorsPagination.pagination,
48 validatorsSort.videosSort, 64 validatorsSort.videosSort,
@@ -283,7 +299,7 @@ function listVideos (req, res, next) {
283 db.Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) { 299 db.Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) {
284 if (err) return next(err) 300 if (err) return next(err)
285 301
286 res.json(getFormatedVideos(videosList, videosTotal)) 302 res.json(utils.getFormatedObjects(videosList, videosTotal))
287 }) 303 })
288} 304}
289 305
@@ -306,22 +322,45 @@ function searchVideos (req, res, next) {
306 function (err, videosList, videosTotal) { 322 function (err, videosList, videosTotal) {
307 if (err) return next(err) 323 if (err) return next(err)
308 324
309 res.json(getFormatedVideos(videosList, videosTotal)) 325 res.json(utils.getFormatedObjects(videosList, videosTotal))
310 } 326 }
311 ) 327 )
312} 328}
313 329
314// --------------------------------------------------------------------------- 330function listVideoAbuses (req, res, next) {
315 331 db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort, function (err, abusesList, abusesTotal) {
316function getFormatedVideos (videos, videosTotal) { 332 if (err) return next(err)
317 const formatedVideos = []
318 333
319 videos.forEach(function (video) { 334 res.json(utils.getFormatedObjects(abusesList, abusesTotal))
320 formatedVideos.push(video.toFormatedJSON())
321 }) 335 })
336}
322 337
323 return { 338function reportVideoAbuse (req, res, next) {
324 total: videosTotal, 339 const videoInstance = res.locals.video
325 data: formatedVideos 340 const reporterUsername = res.locals.oauth.token.User.username
341
342 const abuse = {
343 reporterUsername,
344 reason: req.body.reason,
345 videoId: videoInstance.id,
346 reporterPodId: null // This is our pod that reported this abuse
326 } 347 }
348
349 db.VideoAbuse.create(abuse).asCallback(function (err) {
350 if (err) return next(err)
351
352 // We send the information to the destination pod
353 if (videoInstance.isOwned() === false) {
354 const reportData = {
355 reporterUsername,
356 reportReason: abuse.reason,
357 videoRemoteId: videoInstance.remoteId
358 }
359
360 friends.reportAbuseVideoToFriend(reportData, videoInstance)
361 }
362
363 return res.type('json').status(204).end()
364 })
327} 365}
366
diff --git a/server/helpers/custom-validators/index.js b/server/helpers/custom-validators/index.js
index 96b5b20b9..9383e0304 100644
--- a/server/helpers/custom-validators/index.js
+++ b/server/helpers/custom-validators/index.js
@@ -2,12 +2,14 @@
2 2
3const miscValidators = require('./misc') 3const miscValidators = require('./misc')
4const podsValidators = require('./pods') 4const podsValidators = require('./pods')
5const remoteValidators = require('./remote')
5const usersValidators = require('./users') 6const usersValidators = require('./users')
6const videosValidators = require('./videos') 7const videosValidators = require('./videos')
7 8
8const validators = { 9const validators = {
9 misc: miscValidators, 10 misc: miscValidators,
10 pods: podsValidators, 11 pods: podsValidators,
12 remote: remoteValidators,
11 users: usersValidators, 13 users: usersValidators,
12 videos: videosValidators 14 videos: videosValidators
13} 15}
diff --git a/server/helpers/custom-validators/remote/index.js b/server/helpers/custom-validators/remote/index.js
new file mode 100644
index 000000000..1939a95f4
--- /dev/null
+++ b/server/helpers/custom-validators/remote/index.js
@@ -0,0 +1,11 @@
1'use strict'
2
3const remoteVideosValidators = require('./videos')
4
5const validators = {
6 videos: remoteVideosValidators
7}
8
9// ---------------------------------------------------------------------------
10
11module.exports = validators
diff --git a/server/helpers/custom-validators/remote/videos.js b/server/helpers/custom-validators/remote/videos.js
new file mode 100644
index 000000000..c3ca00e1c
--- /dev/null
+++ b/server/helpers/custom-validators/remote/videos.js
@@ -0,0 +1,74 @@
1'use strict'
2
3const videosValidators = require('../videos')
4const miscValidators = require('../misc')
5
6const remoteVideosValidators = {
7 isEachRemoteRequestVideosValid
8}
9
10function isEachRemoteRequestVideosValid (requests) {
11 return miscValidators.isArray(requests) &&
12 requests.every(function (request) {
13 const video = request.data
14 return (
15 isRequestTypeAddValid(request.type) &&
16 videosValidators.isVideoAuthorValid(video.author) &&
17 videosValidators.isVideoDateValid(video.createdAt) &&
18 videosValidators.isVideoDateValid(video.updatedAt) &&
19 videosValidators.isVideoDescriptionValid(video.description) &&
20 videosValidators.isVideoDurationValid(video.duration) &&
21 videosValidators.isVideoInfoHashValid(video.infoHash) &&
22 videosValidators.isVideoNameValid(video.name) &&
23 videosValidators.isVideoTagsValid(video.tags) &&
24 videosValidators.isVideoThumbnailDataValid(video.thumbnailData) &&
25 videosValidators.isVideoRemoteIdValid(video.remoteId) &&
26 videosValidators.isVideoExtnameValid(video.extname)
27 ) ||
28 (
29 isRequestTypeUpdateValid(request.type) &&
30 videosValidators.isVideoDateValid(video.createdAt) &&
31 videosValidators.isVideoDateValid(video.updatedAt) &&
32 videosValidators.isVideoDescriptionValid(video.description) &&
33 videosValidators.isVideoDurationValid(video.duration) &&
34 videosValidators.isVideoInfoHashValid(video.infoHash) &&
35 videosValidators.isVideoNameValid(video.name) &&
36 videosValidators.isVideoTagsValid(video.tags) &&
37 videosValidators.isVideoRemoteIdValid(video.remoteId) &&
38 videosValidators.isVideoExtnameValid(video.extname)
39 ) ||
40 (
41 isRequestTypeRemoveValid(request.type) &&
42 videosValidators.isVideoNameValid(video.name) &&
43 videosValidators.isVideoRemoteIdValid(video.remoteId)
44 ) ||
45 (
46 isRequestTypeReportAbuseValid(request.type) &&
47 videosValidators.isVideoRemoteIdValid(request.data.videoRemoteId) &&
48 videosValidators.isVideoAbuseReasonValid(request.data.reportReason) &&
49 videosValidators.isVideoAbuseReporterUsernameValid(request.data.reporterUsername)
50 )
51 })
52}
53
54// ---------------------------------------------------------------------------
55
56module.exports = remoteVideosValidators
57
58// ---------------------------------------------------------------------------
59
60function isRequestTypeAddValid (value) {
61 return value === 'add'
62}
63
64function isRequestTypeUpdateValid (value) {
65 return value === 'update'
66}
67
68function isRequestTypeRemoveValid (value) {
69 return value === 'remove'
70}
71
72function isRequestTypeReportAbuseValid (value) {
73 return value === 'report-abuse'
74}
diff --git a/server/helpers/custom-validators/videos.js b/server/helpers/custom-validators/videos.js
index 8448386d9..7f727854d 100644
--- a/server/helpers/custom-validators/videos.js
+++ b/server/helpers/custom-validators/videos.js
@@ -6,9 +6,9 @@ const constants = require('../../initializers/constants')
6const usersValidators = require('./users') 6const usersValidators = require('./users')
7const miscValidators = require('./misc') 7const miscValidators = require('./misc')
8const VIDEOS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEOS 8const VIDEOS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEOS
9const VIDEO_ABUSES_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEO_ABUSES
9 10
10const videosValidators = { 11const videosValidators = {
11 isEachRemoteVideosValid,
12 isVideoAuthorValid, 12 isVideoAuthorValid,
13 isVideoDateValid, 13 isVideoDateValid,
14 isVideoDescriptionValid, 14 isVideoDescriptionValid,
@@ -17,45 +17,11 @@ const videosValidators = {
17 isVideoNameValid, 17 isVideoNameValid,
18 isVideoTagsValid, 18 isVideoTagsValid,
19 isVideoThumbnailValid, 19 isVideoThumbnailValid,
20 isVideoThumbnailDataValid 20 isVideoThumbnailDataValid,
21} 21 isVideoExtnameValid,
22 22 isVideoRemoteIdValid,
23function isEachRemoteVideosValid (requests) { 23 isVideoAbuseReasonValid,
24 return miscValidators.isArray(requests) && 24 isVideoAbuseReporterUsernameValid
25 requests.every(function (request) {
26 const video = request.data
27 return (
28 isRequestTypeAddValid(request.type) &&
29 isVideoAuthorValid(video.author) &&
30 isVideoDateValid(video.createdAt) &&
31 isVideoDateValid(video.updatedAt) &&
32 isVideoDescriptionValid(video.description) &&
33 isVideoDurationValid(video.duration) &&
34 isVideoInfoHashValid(video.infoHash) &&
35 isVideoNameValid(video.name) &&
36 isVideoTagsValid(video.tags) &&
37 isVideoThumbnailDataValid(video.thumbnailData) &&
38 isVideoRemoteIdValid(video.remoteId) &&
39 isVideoExtnameValid(video.extname)
40 ) ||
41 (
42 isRequestTypeUpdateValid(request.type) &&
43 isVideoDateValid(video.createdAt) &&
44 isVideoDateValid(video.updatedAt) &&
45 isVideoDescriptionValid(video.description) &&
46 isVideoDurationValid(video.duration) &&
47 isVideoInfoHashValid(video.infoHash) &&
48 isVideoNameValid(video.name) &&
49 isVideoTagsValid(video.tags) &&
50 isVideoRemoteIdValid(video.remoteId) &&
51 isVideoExtnameValid(video.extname)
52 ) ||
53 (
54 isRequestTypeRemoveValid(request.type) &&
55 isVideoNameValid(video.name) &&
56 isVideoRemoteIdValid(video.remoteId)
57 )
58 })
59} 25}
60 26
61function isVideoAuthorValid (value) { 27function isVideoAuthorValid (value) {
@@ -107,20 +73,14 @@ function isVideoRemoteIdValid (value) {
107 return validator.isUUID(value, 4) 73 return validator.isUUID(value, 4)
108} 74}
109 75
110// --------------------------------------------------------------------------- 76function isVideoAbuseReasonValid (value) {
111 77 return validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
112module.exports = videosValidators
113
114// ---------------------------------------------------------------------------
115
116function isRequestTypeAddValid (value) {
117 return value === 'add'
118} 78}
119 79
120function isRequestTypeUpdateValid (value) { 80function isVideoAbuseReporterUsernameValid (value) {
121 return value === 'update' 81 return usersValidators.isUserUsernameValid(value)
122} 82}
123 83
124function isRequestTypeRemoveValid (value) { 84// ---------------------------------------------------------------------------
125 return value === 'remove' 85
126} 86module.exports = videosValidators
diff --git a/server/helpers/utils.js b/server/helpers/utils.js
index 7e0c9823c..9f4b14582 100644
--- a/server/helpers/utils.js
+++ b/server/helpers/utils.js
@@ -8,7 +8,8 @@ const utils = {
8 badRequest, 8 badRequest,
9 cleanForExit, 9 cleanForExit,
10 generateRandomString, 10 generateRandomString,
11 isTestInstance 11 isTestInstance,
12 getFormatedObjects
12} 13}
13 14
14function badRequest (req, res, next) { 15function badRequest (req, res, next) {
@@ -32,6 +33,19 @@ function isTestInstance () {
32 return (process.env.NODE_ENV === 'test') 33 return (process.env.NODE_ENV === 'test')
33} 34}
34 35
36function getFormatedObjects (objects, objectsTotal) {
37 const formatedObjects = []
38
39 objects.forEach(function (object) {
40 formatedObjects.push(object.toFormatedJSON())
41 })
42
43 return {
44 total: objectsTotal,
45 data: formatedObjects
46 }
47}
48
35// --------------------------------------------------------------------------- 49// ---------------------------------------------------------------------------
36 50
37module.exports = utils 51module.exports = utils
diff --git a/server/initializers/constants.js b/server/initializers/constants.js
index 474a37277..6ba8a9da0 100644
--- a/server/initializers/constants.js
+++ b/server/initializers/constants.js
@@ -19,6 +19,7 @@ const SEARCHABLE_COLUMNS = {
19// Sortable columns per schema 19// Sortable columns per schema
20const SORTABLE_COLUMNS = { 20const SORTABLE_COLUMNS = {
21 USERS: [ 'username', '-username', 'createdAt', '-createdAt' ], 21 USERS: [ 'username', '-username', 'createdAt', '-createdAt' ],
22 VIDEO_ABUSES: [ 'createdAt', '-createdAt' ],
22 VIDEOS: [ 'name', '-name', 'duration', '-duration', 'createdAt', '-createdAt' ] 23 VIDEOS: [ 'name', '-name', 'duration', '-duration', 'createdAt', '-createdAt' ]
23} 24}
24 25
@@ -65,6 +66,9 @@ const CONSTRAINTS_FIELDS = {
65 USERNAME: { min: 3, max: 20 }, // Length 66 USERNAME: { min: 3, max: 20 }, // Length
66 PASSWORD: { min: 6, max: 255 } // Length 67 PASSWORD: { min: 6, max: 255 } // Length
67 }, 68 },
69 VIDEO_ABUSES: {
70 REASON: { min: 2, max: 300 } // Length
71 },
68 VIDEOS: { 72 VIDEOS: {
69 NAME: { min: 3, max: 50 }, // Length 73 NAME: { min: 3, max: 50 }, // Length
70 DESCRIPTION: { min: 3, max: 250 }, // Length 74 DESCRIPTION: { min: 3, max: 250 }, // Length
diff --git a/server/lib/friends.js b/server/lib/friends.js
index 589b79660..4afb91b8b 100644
--- a/server/lib/friends.js
+++ b/server/lib/friends.js
@@ -15,6 +15,7 @@ const requests = require('../helpers/requests')
15const friends = { 15const friends = {
16 addVideoToFriends, 16 addVideoToFriends,
17 updateVideoToFriends, 17 updateVideoToFriends,
18 reportAbuseVideoToFriend,
18 hasFriends, 19 hasFriends,
19 getMyCertificate, 20 getMyCertificate,
20 makeFriends, 21 makeFriends,
@@ -23,12 +24,20 @@ const friends = {
23 sendOwnedVideosToPod 24 sendOwnedVideosToPod
24} 25}
25 26
26function addVideoToFriends (video) { 27function addVideoToFriends (videoData) {
27 createRequest('add', constants.REQUEST_ENDPOINTS.VIDEOS, video) 28 createRequest('add', constants.REQUEST_ENDPOINTS.VIDEOS, videoData)
28} 29}
29 30
30function updateVideoToFriends (video) { 31function updateVideoToFriends (videoData) {
31 createRequest('update', constants.REQUEST_ENDPOINTS.VIDEOS, video) 32 createRequest('update', constants.REQUEST_ENDPOINTS.VIDEOS, videoData)
33}
34
35function removeVideoToFriends (videoParams) {
36 createRequest('remove', constants.REQUEST_ENDPOINTS.VIDEOS, videoParams)
37}
38
39function reportAbuseVideoToFriend (reportData, video) {
40 createRequest('report-abuse', constants.REQUEST_ENDPOINTS.VIDEOS, reportData, [ video.Author.podId ])
32} 41}
33 42
34function hasFriends (callback) { 43function hasFriends (callback) {
@@ -120,10 +129,6 @@ function quitFriends (callback) {
120 }) 129 })
121} 130}
122 131
123function removeVideoToFriends (videoParams) {
124 createRequest('remove', constants.REQUEST_ENDPOINTS.VIDEOS, videoParams)
125}
126
127function sendOwnedVideosToPod (podId) { 132function sendOwnedVideosToPod (podId) {
128 db.Video.listOwnedAndPopulateAuthorAndTags(function (err, videosList) { 133 db.Video.listOwnedAndPopulateAuthorAndTags(function (err, videosList) {
129 if (err) { 134 if (err) {
@@ -152,10 +157,10 @@ module.exports = friends
152// --------------------------------------------------------------------------- 157// ---------------------------------------------------------------------------
153 158
154function computeForeignPodsList (host, podsScore, callback) { 159function computeForeignPodsList (host, podsScore, callback) {
155 getForeignPodsList(host, function (err, foreignPodsList) { 160 getForeignPodsList(host, function (err, res) {
156 if (err) return callback(err) 161 if (err) return callback(err)
157 162
158 if (!foreignPodsList) foreignPodsList = [] 163 const foreignPodsList = res.data
159 164
160 // Let's give 1 point to the pod we ask the friends list 165 // Let's give 1 point to the pod we ask the friends list
161 foreignPodsList.push({ host }) 166 foreignPodsList.push({ host })
@@ -252,11 +257,11 @@ function makeRequestsToWinningPods (cert, podsList, callback) {
252 }) 257 })
253} 258}
254 259
255// Wrapper that populate "to" argument with all our friends if it is not specified 260// Wrapper that populate "toIds" argument with all our friends if it is not specified
256function createRequest (type, endpoint, data, to) { 261function createRequest (type, endpoint, data, toIds) {
257 if (to) return _createRequest(type, endpoint, data, to) 262 if (toIds) return _createRequest(type, endpoint, data, toIds)
258 263
259 // If the "to" pods is not specified, we send the request to all our friends 264 // If the "toIds" pods is not specified, we send the request to all our friends
260 db.Pod.listAllIds(function (err, podIds) { 265 db.Pod.listAllIds(function (err, podIds) {
261 if (err) { 266 if (err) {
262 logger.error('Cannot get pod ids', { error: err }) 267 logger.error('Cannot get pod ids', { error: err })
@@ -267,13 +272,13 @@ function createRequest (type, endpoint, data, to) {
267 }) 272 })
268} 273}
269 274
270function _createRequest (type, endpoint, data, to) { 275function _createRequest (type, endpoint, data, toIds) {
271 const pods = [] 276 const pods = []
272 277
273 // If there are no destination pods abort 278 // If there are no destination pods abort
274 if (to.length === 0) return 279 if (toIds.length === 0) return
275 280
276 to.forEach(function (toPod) { 281 toIds.forEach(function (toPod) {
277 pods.push(db.Pod.build({ id: toPod })) 282 pods.push(db.Pod.build({ id: toPod }))
278 }) 283 })
279 284
diff --git a/server/middlewares/sort.js b/server/middlewares/sort.js
index 477e10571..39e167265 100644
--- a/server/middlewares/sort.js
+++ b/server/middlewares/sort.js
@@ -2,6 +2,7 @@
2 2
3const sortMiddleware = { 3const sortMiddleware = {
4 setUsersSort, 4 setUsersSort,
5 setVideoAbusesSort,
5 setVideosSort 6 setVideosSort
6} 7}
7 8
@@ -11,6 +12,12 @@ function setUsersSort (req, res, next) {
11 return next() 12 return next()
12} 13}
13 14
15function setVideoAbusesSort (req, res, next) {
16 if (!req.query.sort) req.query.sort = '-createdAt'
17
18 return next()
19}
20
14function setVideosSort (req, res, next) { 21function setVideosSort (req, res, next) {
15 if (!req.query.sort) req.query.sort = '-createdAt' 22 if (!req.query.sort) req.query.sort = '-createdAt'
16 23
diff --git a/server/middlewares/validators/remote/index.js b/server/middlewares/validators/remote/index.js
new file mode 100644
index 000000000..022a2fe50
--- /dev/null
+++ b/server/middlewares/validators/remote/index.js
@@ -0,0 +1,13 @@
1'use strict'
2
3const remoteSignatureValidators = require('./signature')
4const remoteVideosValidators = require('./videos')
5
6const validators = {
7 signature: remoteSignatureValidators,
8 videos: remoteVideosValidators
9}
10
11// ---------------------------------------------------------------------------
12
13module.exports = validators
diff --git a/server/middlewares/validators/remote.js b/server/middlewares/validators/remote/signature.js
index 858d193cc..5880a2c2c 100644
--- a/server/middlewares/validators/remote.js
+++ b/server/middlewares/validators/remote/signature.js
@@ -1,21 +1,12 @@
1'use strict' 1'use strict'
2 2
3const checkErrors = require('./utils').checkErrors 3const checkErrors = require('../utils').checkErrors
4const logger = require('../../helpers/logger') 4const logger = require('../../../helpers/logger')
5 5
6const validatorsRemote = { 6const validatorsRemoteSignature = {
7 remoteVideos,
8 signature 7 signature
9} 8}
10 9
11function remoteVideos (req, res, next) {
12 req.checkBody('data').isEachRemoteVideosValid()
13
14 logger.debug('Checking remoteVideos parameters', { parameters: req.body })
15
16 checkErrors(req, res, next)
17}
18
19function signature (req, res, next) { 10function signature (req, res, next) {
20 req.checkBody('signature.host', 'Should have a signature host').isURL() 11 req.checkBody('signature.host', 'Should have a signature host').isURL()
21 req.checkBody('signature.signature', 'Should have a signature').notEmpty() 12 req.checkBody('signature.signature', 'Should have a signature').notEmpty()
@@ -27,4 +18,4 @@ function signature (req, res, next) {
27 18
28// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
29 20
30module.exports = validatorsRemote 21module.exports = validatorsRemoteSignature
diff --git a/server/middlewares/validators/remote/videos.js b/server/middlewares/validators/remote/videos.js
new file mode 100644
index 000000000..cf9925b6c
--- /dev/null
+++ b/server/middlewares/validators/remote/videos.js
@@ -0,0 +1,20 @@
1'use strict'
2
3const checkErrors = require('../utils').checkErrors
4const logger = require('../../../helpers/logger')
5
6const validatorsRemoteVideos = {
7 remoteVideos
8}
9
10function remoteVideos (req, res, next) {
11 req.checkBody('data').isEachRemoteRequestVideosValid()
12
13 logger.debug('Checking remoteVideos parameters', { parameters: req.body })
14
15 checkErrors(req, res, next)
16}
17
18// ---------------------------------------------------------------------------
19
20module.exports = validatorsRemoteVideos
diff --git a/server/middlewares/validators/sort.js b/server/middlewares/validators/sort.js
index 431d3fffd..b7eec0316 100644
--- a/server/middlewares/validators/sort.js
+++ b/server/middlewares/validators/sort.js
@@ -6,29 +6,38 @@ const logger = require('../../helpers/logger')
6 6
7const validatorsSort = { 7const validatorsSort = {
8 usersSort, 8 usersSort,
9 videoAbusesSort,
9 videosSort 10 videosSort
10} 11}
11 12
12function usersSort (req, res, next) { 13function usersSort (req, res, next) {
13 const sortableColumns = constants.SORTABLE_COLUMNS.USERS 14 const sortableColumns = constants.SORTABLE_COLUMNS.USERS
14 15
15 req.checkQuery('sort', 'Should have correct sortable column').optional().isIn(sortableColumns) 16 checkSort(req, res, next, sortableColumns)
17}
16 18
17 logger.debug('Checking sort parameters', { parameters: req.query }) 19function videoAbusesSort (req, res, next) {
20 const sortableColumns = constants.SORTABLE_COLUMNS.VIDEO_ABUSES
18 21
19 checkErrors(req, res, next) 22 checkSort(req, res, next, sortableColumns)
20} 23}
21 24
22function videosSort (req, res, next) { 25function videosSort (req, res, next) {
23 const sortableColumns = constants.SORTABLE_COLUMNS.VIDEOS 26 const sortableColumns = constants.SORTABLE_COLUMNS.VIDEOS
24 27
28 checkSort(req, res, next, sortableColumns)
29}
30
31// ---------------------------------------------------------------------------
32
33module.exports = validatorsSort
34
35// ---------------------------------------------------------------------------
36
37function checkSort (req, res, next, sortableColumns) {
25 req.checkQuery('sort', 'Should have correct sortable column').optional().isIn(sortableColumns) 38 req.checkQuery('sort', 'Should have correct sortable column').optional().isIn(sortableColumns)
26 39
27 logger.debug('Checking sort parameters', { parameters: req.query }) 40 logger.debug('Checking sort parameters', { parameters: req.query })
28 41
29 checkErrors(req, res, next) 42 checkErrors(req, res, next)
30} 43}
31
32// ---------------------------------------------------------------------------
33
34module.exports = validatorsSort
diff --git a/server/middlewares/validators/videos.js b/server/middlewares/validators/videos.js
index 295ed05fa..ff18a99c2 100644
--- a/server/middlewares/validators/videos.js
+++ b/server/middlewares/validators/videos.js
@@ -11,7 +11,9 @@ const validatorsVideos = {
11 videosUpdate, 11 videosUpdate,
12 videosGet, 12 videosGet,
13 videosRemove, 13 videosRemove,
14 videosSearch 14 videosSearch,
15
16 videoAbuseReport
15} 17}
16 18
17function videosAdd (req, res, next) { 19function videosAdd (req, res, next) {
@@ -97,6 +99,17 @@ function videosSearch (req, res, next) {
97 checkErrors(req, res, next) 99 checkErrors(req, res, next)
98} 100}
99 101
102function videoAbuseReport (req, res, next) {
103 req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4)
104 req.checkBody('reason', 'Should have a valid reason').isVideoAbuseReasonValid()
105
106 logger.debug('Checking videoAbuseReport parameters', { parameters: req.body })
107
108 checkErrors(req, res, function () {
109 checkVideoExists(req.params.id, res, next)
110 })
111}
112
100// --------------------------------------------------------------------------- 113// ---------------------------------------------------------------------------
101 114
102module.exports = validatorsVideos 115module.exports = validatorsVideos
diff --git a/server/models/requestToPod.js b/server/models/request-to-pod.js
index f42a53458..f42a53458 100644
--- a/server/models/requestToPod.js
+++ b/server/models/request-to-pod.js
diff --git a/server/models/video-abuse.js b/server/models/video-abuse.js
new file mode 100644
index 000000000..766a7568d
--- /dev/null
+++ b/server/models/video-abuse.js
@@ -0,0 +1,113 @@
1'use strict'
2
3const constants = require('../initializers/constants')
4const modelUtils = require('./utils')
5const customVideosValidators = require('../helpers/custom-validators').videos
6
7module.exports = function (sequelize, DataTypes) {
8 const VideoAbuse = sequelize.define('VideoAbuse',
9 {
10 reporterUsername: {
11 type: DataTypes.STRING,
12 allowNull: false,
13 validate: {
14 reporterUsernameValid: function (value) {
15 const res = customVideosValidators.isVideoAbuseReporterUsernameValid(value)
16 if (res === false) throw new Error('Video abuse reporter username is not valid.')
17 }
18 }
19 },
20 reason: {
21 type: DataTypes.STRING,
22 allowNull: false,
23 validate: {
24 reasonValid: function (value) {
25 const res = customVideosValidators.isVideoAbuseReasonValid(value)
26 if (res === false) throw new Error('Video abuse reason is not valid.')
27 }
28 }
29 }
30 },
31 {
32 indexes: [
33 {
34 fields: [ 'videoId' ]
35 },
36 {
37 fields: [ 'reporterPodId' ]
38 }
39 ],
40 classMethods: {
41 associate,
42
43 listForApi
44 },
45 instanceMethods: {
46 toFormatedJSON
47 }
48 }
49 )
50
51 return VideoAbuse
52}
53
54// ---------------------------------------------------------------------------
55
56function associate (models) {
57 this.belongsTo(models.Pod, {
58 foreignKey: {
59 name: 'reporterPodId',
60 allowNull: true
61 },
62 onDelete: 'cascade'
63 })
64
65 this.belongsTo(models.Video, {
66 foreignKey: {
67 name: 'videoId',
68 allowNull: false
69 },
70 onDelete: 'cascade'
71 })
72}
73
74function listForApi (start, count, sort, callback) {
75 const query = {
76 offset: start,
77 limit: count,
78 order: [ modelUtils.getSort(sort) ],
79 include: [
80 {
81 model: this.sequelize.models.Pod,
82 required: false
83 }
84 ]
85 }
86
87 return this.findAndCountAll(query).asCallback(function (err, result) {
88 if (err) return callback(err)
89
90 return callback(null, result.rows, result.count)
91 })
92}
93
94function toFormatedJSON () {
95 let reporterPodHost
96
97 if (this.Pod) {
98 reporterPodHost = this.Pod.host
99 } else {
100 // It means it's our video
101 reporterPodHost = constants.CONFIG.WEBSERVER.HOST
102 }
103
104 const json = {
105 id: this.id,
106 reporterPodHost,
107 reason: this.reason,
108 reporterUsername: this.reporterUsername,
109 videoId: this.videoId
110 }
111
112 return json
113}
diff --git a/server/models/videoTag.js b/server/models/video-tag.js
index cd9277a6e..cd9277a6e 100644
--- a/server/models/videoTag.js
+++ b/server/models/video-tag.js
diff --git a/server/models/video.js b/server/models/video.js
index 3fe8368c7..4c197a835 100644
--- a/server/models/video.js
+++ b/server/models/video.js
@@ -248,6 +248,14 @@ function associate (models) {
248 through: models.VideoTag, 248 through: models.VideoTag,
249 onDelete: 'cascade' 249 onDelete: 'cascade'
250 }) 250 })
251
252 this.hasMany(models.VideoAbuse, {
253 foreignKey: {
254 name: 'videoId',
255 allowNull: false
256 },
257 onDelete: 'cascade'
258 })
251} 259}
252 260
253function generateMagnetUri () { 261function generateMagnetUri () {
diff --git a/server/tests/api/check-params/index.js b/server/tests/api/check-params/index.js
index 3d6f09267..d0824f08a 100644
--- a/server/tests/api/check-params/index.js
+++ b/server/tests/api/check-params/index.js
@@ -6,3 +6,4 @@ require('./remotes')
6require('./users') 6require('./users')
7require('./requests') 7require('./requests')
8require('./videos') 8require('./videos')
9require('./video-abuses')
diff --git a/server/tests/api/check-params/remotes.js b/server/tests/api/check-params/remotes.js
index 30ba3b697..c1ab9fb2b 100644
--- a/server/tests/api/check-params/remotes.js
+++ b/server/tests/api/check-params/remotes.js
@@ -47,6 +47,10 @@ describe('Test remote videos API validators', function () {
47 it('Should check when removing a video') 47 it('Should check when removing a video')
48 }) 48 })
49 49
50 describe('When reporting abuse on a video', function () {
51 it('Should check when reporting a video abuse')
52 })
53
50 after(function (done) { 54 after(function (done) {
51 process.kill(-server.app.pid) 55 process.kill(-server.app.pid)
52 56
diff --git a/server/tests/api/check-params/video-abuses.js b/server/tests/api/check-params/video-abuses.js
new file mode 100644
index 000000000..8cb4ccdc1
--- /dev/null
+++ b/server/tests/api/check-params/video-abuses.js
@@ -0,0 +1,180 @@
1'use strict'
2
3const request = require('supertest')
4const series = require('async/series')
5
6const loginUtils = require('../../utils/login')
7const requestsUtils = require('../../utils/requests')
8const serversUtils = require('../../utils/servers')
9const usersUtils = require('../../utils/users')
10const videosUtils = require('../../utils/videos')
11
12describe('Test video abuses API validators', function () {
13 let server = null
14 let userAccessToken = null
15
16 // ---------------------------------------------------------------
17
18 before(function (done) {
19 this.timeout(20000)
20
21 series([
22 function (next) {
23 serversUtils.flushTests(next)
24 },
25 function (next) {
26 serversUtils.runServer(1, function (server1) {
27 server = server1
28
29 next()
30 })
31 },
32 function (next) {
33 loginUtils.loginAndGetAccessToken(server, function (err, token) {
34 if (err) throw err
35 server.accessToken = token
36
37 next()
38 })
39 },
40 function (next) {
41 const username = 'user1'
42 const password = 'my super password'
43
44 usersUtils.createUser(server.url, server.accessToken, username, password, next)
45 },
46 function (next) {
47 const user = {
48 username: 'user1',
49 password: 'my super password'
50 }
51
52 loginUtils.getUserAccessToken(server, user, function (err, accessToken) {
53 if (err) throw err
54
55 userAccessToken = accessToken
56
57 next()
58 })
59 },
60 // Upload some videos on each pods
61 function (next) {
62 const name = 'my super name for pod'
63 const description = 'my super description for pod'
64 const tags = [ 'tag' ]
65 const file = 'video_short2.webm'
66 videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, file, next)
67 },
68 function (next) {
69 videosUtils.getVideosList(server.url, function (err, res) {
70 if (err) throw err
71
72 const videos = res.body.data
73 server.video = videos[0]
74
75 next()
76 })
77 }
78 ], done)
79 })
80
81 describe('When listing video abuses', function () {
82 const path = '/api/v1/videos/abuse'
83
84 it('Should fail with a bad start pagination', function (done) {
85 request(server.url)
86 .get(path)
87 .query({ start: 'hello' })
88 .set('Authorization', 'Bearer ' + server.accessToken)
89 .set('Accept', 'application/json')
90 .expect(400, done)
91 })
92
93 it('Should fail with a bad count pagination', function (done) {
94 request(server.url)
95 .get(path)
96 .query({ count: 'hello' })
97 .set('Accept', 'application/json')
98 .set('Authorization', 'Bearer ' + server.accessToken)
99 .expect(400, done)
100 })
101
102 it('Should fail with an incorrect sort', function (done) {
103 request(server.url)
104 .get(path)
105 .query({ sort: 'hello' })
106 .set('Accept', 'application/json')
107 .set('Authorization', 'Bearer ' + server.accessToken)
108 .expect(400, done)
109 })
110
111 it('Should fail with a non authenticated user', function (done) {
112 request(server.url)
113 .get(path)
114 .query({ sort: 'hello' })
115 .set('Accept', 'application/json')
116 .expect(401, done)
117 })
118
119 it('Should fail with a non admin user', function (done) {
120 request(server.url)
121 .get(path)
122 .query({ sort: 'hello' })
123 .set('Accept', 'application/json')
124 .set('Authorization', 'Bearer ' + userAccessToken)
125 .expect(403, done)
126 })
127 })
128
129 describe('When reporting a video abuse', function () {
130 const basePath = '/api/v1/videos/'
131
132 it('Should fail with nothing', function (done) {
133 const path = basePath + server.video + '/abuse'
134 const data = {}
135 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done)
136 })
137
138 it('Should fail with a wrong video', function (done) {
139 const wrongPath = '/api/v1/videos/blabla/abuse'
140 const data = {}
141 requestsUtils.makePostBodyRequest(server.url, wrongPath, server.accessToken, data, done)
142 })
143
144 it('Should fail with a non authenticated user', function (done) {
145 const data = {}
146 const path = basePath + server.video + '/abuse'
147 requestsUtils.makePostBodyRequest(server.url, path, 'hello', data, done, 401)
148 })
149
150 it('Should fail with a reason too short', function (done) {
151 const data = {
152 reason: 'h'
153 }
154 const path = basePath + server.video + '/abuse'
155 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done)
156 })
157
158 it('Should fail with a reason too big', function (done) {
159 const data = {
160 reason: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' +
161 '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' +
162 '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' +
163 '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
164 }
165 const path = basePath + server.video + '/abuse'
166 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done)
167 })
168 })
169
170 after(function (done) {
171 process.kill(-server.app.pid)
172
173 // Keep the logs if the test failed
174 if (this.ok) {
175 serversUtils.flushTests(done)
176 } else {
177 done()
178 }
179 })
180})
diff --git a/server/tests/api/friends-advanced.js b/server/tests/api/friends-advanced.js
index 0a2d58d82..708138bc9 100644
--- a/server/tests/api/friends-advanced.js
+++ b/server/tests/api/friends-advanced.js
@@ -86,7 +86,7 @@ describe('Test advanced friends', function () {
86 getFriendsList(5, function (err, res) { 86 getFriendsList(5, function (err, res) {
87 if (err) throw err 87 if (err) throw err
88 88
89 expect(res.body.length).to.equal(0) 89 expect(res.body.data.length).to.equal(0)
90 90
91 done() 91 done()
92 }) 92 })
@@ -111,7 +111,7 @@ describe('Test advanced friends', function () {
111 getFriendsList(i, function (err, res) { 111 getFriendsList(i, function (err, res) {
112 if (err) throw err 112 if (err) throw err
113 113
114 expect(res.body.length).to.equal(0) 114 expect(res.body.data.length).to.equal(0)
115 115
116 callback() 116 callback()
117 }) 117 })
@@ -140,7 +140,7 @@ describe('Test advanced friends', function () {
140 getFriendsList(i, function (err, res) { 140 getFriendsList(i, function (err, res) {
141 if (err) throw err 141 if (err) throw err
142 142
143 expect(res.body.length).to.equal(3) 143 expect(res.body.data.length).to.equal(3)
144 144
145 callback() 145 callback()
146 }) 146 })
@@ -182,7 +182,7 @@ describe('Test advanced friends', function () {
182 if (err) throw err 182 if (err) throw err
183 183
184 // Pod 4 didn't know pod 1 and 2 removed it 184 // Pod 4 didn't know pod 1 and 2 removed it
185 expect(res.body.length).to.equal(3) 185 expect(res.body.data.length).to.equal(3)
186 next() 186 next()
187 }) 187 })
188 }, 188 },
@@ -200,7 +200,7 @@ describe('Test advanced friends', function () {
200 if (err) throw err 200 if (err) throw err
201 201
202 // Pod 4 should not be our friend 202 // Pod 4 should not be our friend
203 const result = res.body 203 const result = res.body.data
204 expect(result.length).to.equal(3) 204 expect(result.length).to.equal(3)
205 for (const pod of result) { 205 for (const pod of result) {
206 expect(pod.host).not.equal(servers[3].host) 206 expect(pod.host).not.equal(servers[3].host)
diff --git a/server/tests/api/friends-basic.js b/server/tests/api/friends-basic.js
index 3a904dbd7..6f37ff291 100644
--- a/server/tests/api/friends-basic.js
+++ b/server/tests/api/friends-basic.js
@@ -28,7 +28,7 @@ describe('Test basic friends', function () {
28 podsUtils.getFriendsList(serverToTest.url, function (err, res) { 28 podsUtils.getFriendsList(serverToTest.url, function (err, res) {
29 if (err) throw err 29 if (err) throw err
30 30
31 const result = res.body 31 const result = res.body.data
32 expect(result).to.be.an('array') 32 expect(result).to.be.an('array')
33 expect(result.length).to.equal(2) 33 expect(result.length).to.equal(2)
34 34
@@ -65,7 +65,7 @@ describe('Test basic friends', function () {
65 podsUtils.getFriendsList(server.url, function (err, res) { 65 podsUtils.getFriendsList(server.url, function (err, res) {
66 if (err) throw err 66 if (err) throw err
67 67
68 const result = res.body 68 const result = res.body.data
69 expect(result).to.be.an('array') 69 expect(result).to.be.an('array')
70 expect(result.length).to.equal(0) 70 expect(result.length).to.equal(0)
71 callback() 71 callback()
@@ -90,7 +90,7 @@ describe('Test basic friends', function () {
90 podsUtils.getFriendsList(servers[1].url, function (err, res) { 90 podsUtils.getFriendsList(servers[1].url, function (err, res) {
91 if (err) throw err 91 if (err) throw err
92 92
93 const result = res.body 93 const result = res.body.data
94 expect(result).to.be.an('array') 94 expect(result).to.be.an('array')
95 expect(result.length).to.equal(1) 95 expect(result.length).to.equal(1)
96 96
@@ -107,7 +107,7 @@ describe('Test basic friends', function () {
107 podsUtils.getFriendsList(servers[2].url, function (err, res) { 107 podsUtils.getFriendsList(servers[2].url, function (err, res) {
108 if (err) throw err 108 if (err) throw err
109 109
110 const result = res.body 110 const result = res.body.data
111 expect(result).to.be.an('array') 111 expect(result).to.be.an('array')
112 expect(result.length).to.equal(1) 112 expect(result.length).to.equal(1)
113 113
@@ -154,7 +154,7 @@ describe('Test basic friends', function () {
154 podsUtils.getFriendsList(servers[1].url, function (err, res) { 154 podsUtils.getFriendsList(servers[1].url, function (err, res) {
155 if (err) throw err 155 if (err) throw err
156 156
157 const result = res.body 157 const result = res.body.data
158 expect(result).to.be.an('array') 158 expect(result).to.be.an('array')
159 expect(result.length).to.equal(0) 159 expect(result.length).to.equal(0)
160 160
@@ -167,7 +167,7 @@ describe('Test basic friends', function () {
167 podsUtils.getFriendsList(url, function (err, res) { 167 podsUtils.getFriendsList(url, function (err, res) {
168 if (err) throw err 168 if (err) throw err
169 169
170 const result = res.body 170 const result = res.body.data
171 expect(result).to.be.an('array') 171 expect(result).to.be.an('array')
172 expect(result.length).to.equal(1) 172 expect(result.length).to.equal(1)
173 expect(result[0].host).not.to.be.equal(servers[1].host) 173 expect(result[0].host).not.to.be.equal(servers[1].host)
diff --git a/server/tests/api/video-abuse.js b/server/tests/api/video-abuse.js
new file mode 100644
index 000000000..58db17c42
--- /dev/null
+++ b/server/tests/api/video-abuse.js
@@ -0,0 +1,191 @@
1'use strict'
2
3const chai = require('chai')
4const each = require('async/each')
5const expect = chai.expect
6const series = require('async/series')
7
8const loginUtils = require('../utils/login')
9const podsUtils = require('../utils/pods')
10const serversUtils = require('../utils/servers')
11const videosUtils = require('../utils/videos')
12const videoAbusesUtils = require('../utils/video-abuses')
13
14describe('Test video abuses', function () {
15 let servers = []
16
17 before(function (done) {
18 this.timeout(30000)
19
20 series([
21 // Run servers
22 function (next) {
23 serversUtils.flushAndRunMultipleServers(2, function (serversRun) {
24 servers = serversRun
25 next()
26 })
27 },
28 // Get the access tokens
29 function (next) {
30 each(servers, function (server, callbackEach) {
31 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
32 if (err) return callbackEach(err)
33
34 server.accessToken = accessToken
35 callbackEach()
36 })
37 }, next)
38 },
39 // Pod 1 make friends too
40 function (next) {
41 const server = servers[0]
42 podsUtils.makeFriends(server.url, server.accessToken, next)
43 },
44 // Upload some videos on each pods
45 function (next) {
46 const name = 'my super name for pod 1'
47 const description = 'my super description for pod 1'
48 const tags = [ 'tag' ]
49 const file = 'video_short2.webm'
50 videosUtils.uploadVideo(servers[0].url, servers[0].accessToken, name, description, tags, file, next)
51 },
52 function (next) {
53 const name = 'my super name for pod 2'
54 const description = 'my super description for pod 2'
55 const tags = [ 'tag' ]
56 const file = 'video_short2.webm'
57 videosUtils.uploadVideo(servers[1].url, servers[1].accessToken, name, description, tags, file, next)
58 },
59 // Wait videos propagation
60 function (next) {
61 setTimeout(next, 11000)
62 },
63 function (next) {
64 videosUtils.getVideosList(servers[0].url, function (err, res) {
65 if (err) throw err
66
67 const videos = res.body.data
68
69 expect(videos.length).to.equal(2)
70
71 servers[0].video = videos.find(function (video) { return video.name === 'my super name for pod 1' })
72 servers[1].video = videos.find(function (video) { return video.name === 'my super name for pod 2' })
73
74 next()
75 })
76 }
77 ], done)
78 })
79
80 it('Should not have video abuses', function (done) {
81 videoAbusesUtils.getVideoAbusesList(servers[0].url, servers[0].accessToken, function (err, res) {
82 if (err) throw err
83
84 expect(res.body.total).to.equal(0)
85 expect(res.body.data).to.be.an('array')
86 expect(res.body.data.length).to.equal(0)
87
88 done()
89 })
90 })
91
92 it('Should report abuse on a local video', function (done) {
93 this.timeout(15000)
94
95 const reason = 'my super bad reason'
96 videoAbusesUtils.reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason, function (err) {
97 if (err) throw err
98
99 // We wait requests propagation, even if the pod 1 is not supposed to make a request to pod 2
100 setTimeout(done, 11000)
101 })
102 })
103
104 it('Should have 1 video abuses on pod 1 and 0 on pod 2', function (done) {
105 videoAbusesUtils.getVideoAbusesList(servers[0].url, servers[0].accessToken, function (err, res) {
106 if (err) throw err
107
108 expect(res.body.total).to.equal(1)
109 expect(res.body.data).to.be.an('array')
110 expect(res.body.data.length).to.equal(1)
111
112 const abuse = res.body.data[0]
113 expect(abuse.reason).to.equal('my super bad reason')
114 expect(abuse.reporterUsername).to.equal('root')
115 expect(abuse.reporterPodHost).to.equal('localhost:9001')
116 expect(abuse.videoId).to.equal(servers[0].video.id)
117
118 videoAbusesUtils.getVideoAbusesList(servers[1].url, servers[1].accessToken, function (err, res) {
119 if (err) throw err
120
121 expect(res.body.total).to.equal(0)
122 expect(res.body.data).to.be.an('array')
123 expect(res.body.data.length).to.equal(0)
124
125 done()
126 })
127 })
128 })
129
130 it('Should report abuse on a remote video', function (done) {
131 this.timeout(15000)
132
133 const reason = 'my super bad reason 2'
134 videoAbusesUtils.reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[1].video.id, reason, function (err) {
135 if (err) throw err
136
137 // We wait requests propagation
138 setTimeout(done, 11000)
139 })
140 })
141
142 it('Should have 2 video abuse on pod 1 and 1 on pod 2', function (done) {
143 videoAbusesUtils.getVideoAbusesList(servers[0].url, servers[0].accessToken, function (err, res) {
144 if (err) throw err
145
146 expect(res.body.total).to.equal(2)
147 expect(res.body.data).to.be.an('array')
148 expect(res.body.data.length).to.equal(2)
149
150 let abuse = res.body.data[0]
151 expect(abuse.reason).to.equal('my super bad reason')
152 expect(abuse.reporterUsername).to.equal('root')
153 expect(abuse.reporterPodHost).to.equal('localhost:9001')
154 expect(abuse.videoId).to.equal(servers[0].video.id)
155
156 abuse = res.body.data[1]
157 expect(abuse.reason).to.equal('my super bad reason 2')
158 expect(abuse.reporterUsername).to.equal('root')
159 expect(abuse.reporterPodHost).to.equal('localhost:9001')
160 expect(abuse.videoId).to.equal(servers[1].video.id)
161
162 videoAbusesUtils.getVideoAbusesList(servers[1].url, servers[1].accessToken, function (err, res) {
163 if (err) throw err
164
165 expect(res.body.total).to.equal(1)
166 expect(res.body.data).to.be.an('array')
167 expect(res.body.data.length).to.equal(1)
168
169 let abuse = res.body.data[0]
170 expect(abuse.reason).to.equal('my super bad reason 2')
171 expect(abuse.reporterUsername).to.equal('root')
172 expect(abuse.reporterPodHost).to.equal('localhost:9001')
173
174 done()
175 })
176 })
177 })
178
179 after(function (done) {
180 servers.forEach(function (server) {
181 process.kill(-server.app.pid)
182 })
183
184 // Keep the logs if the test failed
185 if (this.ok) {
186 serversUtils.flushTests(done)
187 } else {
188 done()
189 }
190 })
191})
diff --git a/server/tests/utils/video-abuses.js b/server/tests/utils/video-abuses.js
new file mode 100644
index 000000000..596c824b3
--- /dev/null
+++ b/server/tests/utils/video-abuses.js
@@ -0,0 +1,73 @@
1'use strict'
2
3const request = require('supertest')
4
5const videosUtils = {
6 getVideoAbusesList,
7 getVideoAbusesListPagination,
8 getVideoAbusesListSort,
9 reportVideoAbuse
10}
11
12// ---------------------- Export functions --------------------
13
14function reportVideoAbuse (url, token, videoId, reason, specialStatus, end) {
15 if (!end) {
16 end = specialStatus
17 specialStatus = 204
18 }
19
20 const path = '/api/v1/videos/' + videoId + '/abuse'
21
22 request(url)
23 .post(path)
24 .set('Accept', 'application/json')
25 .set('Authorization', 'Bearer ' + token)
26 .send({ reason })
27 .expect(specialStatus)
28 .end(end)
29}
30
31function getVideoAbusesList (url, token, end) {
32 const path = '/api/v1/videos/abuse'
33
34 request(url)
35 .get(path)
36 .query({ sort: 'createdAt' })
37 .set('Accept', 'application/json')
38 .set('Authorization', 'Bearer ' + token)
39 .expect(200)
40 .expect('Content-Type', /json/)
41 .end(end)
42}
43
44function getVideoAbusesListPagination (url, token, start, count, end) {
45 const path = '/api/v1/videos/abuse'
46
47 request(url)
48 .get(path)
49 .query({ start: start })
50 .query({ count: count })
51 .set('Accept', 'application/json')
52 .set('Authorization', 'Bearer ' + token)
53 .expect(200)
54 .expect('Content-Type', /json/)
55 .end(end)
56}
57
58function getVideoAbusesListSort (url, token, sort, end) {
59 const path = '/api/v1/videos/abuse'
60
61 request(url)
62 .get(path)
63 .query({ sort: sort })
64 .set('Accept', 'application/json')
65 .set('Authorization', 'Bearer ' + token)
66 .expect(200)
67 .expect('Content-Type', /json/)
68 .end(end)
69}
70
71// ---------------------------------------------------------------------------
72
73module.exports = videosUtils