aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2016-10-02 15:39:09 +0200
committerChocobozzz <florian.bigard@gmail.com>2016-10-02 15:39:09 +0200
commita6375e69668ea42e19531c6bc68dcd37f3f7cbd7 (patch)
tree03204a408d56311692c3528bedcf95d2455e94f2 /server
parent052937db8a8d282eccdbdf38d487ed8d85d3c0a7 (diff)
parentc4403b29ad4db097af528a7f04eea07e0ed320d0 (diff)
downloadPeerTube-a6375e69668ea42e19531c6bc68dcd37f3f7cbd7.tar.gz
PeerTube-a6375e69668ea42e19531c6bc68dcd37f3f7cbd7.tar.zst
PeerTube-a6375e69668ea42e19531c6bc68dcd37f3f7cbd7.zip
Merge branch 'master' into webseed-merged
Diffstat (limited to 'server')
-rw-r--r--server/controllers/api/v1/clients.js41
-rw-r--r--server/controllers/api/v1/index.js4
-rw-r--r--server/controllers/api/v1/pods.js62
-rw-r--r--server/controllers/api/v1/remote.js1
-rw-r--r--server/controllers/api/v1/requests.js38
-rw-r--r--server/controllers/api/v1/users.js165
-rw-r--r--server/controllers/api/v1/videos.js7
-rw-r--r--server/helpers/custom-validators/index.js17
-rw-r--r--server/helpers/custom-validators/misc.js18
-rw-r--r--server/helpers/custom-validators/pods.js21
-rw-r--r--server/helpers/custom-validators/users.js31
-rw-r--r--server/helpers/custom-validators/videos.js (renamed from server/helpers/custom-validators.js)105
-rw-r--r--server/helpers/logger.js10
-rw-r--r--server/helpers/peertube-crypto.js60
-rw-r--r--server/helpers/requests.js15
-rw-r--r--server/helpers/utils.js4
-rw-r--r--server/initializers/checker.js14
-rw-r--r--server/initializers/constants.js175
-rw-r--r--server/initializers/database.js11
-rw-r--r--server/initializers/installer.js22
-rw-r--r--server/initializers/migrations/0005-create-application.js17
-rw-r--r--server/initializers/migrations/0010-users-password.js22
-rw-r--r--server/initializers/migrations/0015-admin-role.js16
-rw-r--r--server/initializers/migrator.js56
-rw-r--r--server/lib/friends.js34
-rw-r--r--server/lib/oauth-model.js29
-rw-r--r--server/middlewares/admin.js22
-rw-r--r--server/middlewares/index.js24
-rw-r--r--server/middlewares/oauth.js6
-rw-r--r--server/middlewares/pagination.js2
-rw-r--r--server/middlewares/pods.js62
-rw-r--r--server/middlewares/search.js2
-rw-r--r--server/middlewares/secure.js42
-rw-r--r--server/middlewares/sort.js9
-rw-r--r--server/middlewares/validators/index.js2
-rw-r--r--server/middlewares/validators/pagination.js2
-rw-r--r--server/middlewares/validators/pods.js34
-rw-r--r--server/middlewares/validators/remote.js7
-rw-r--r--server/middlewares/validators/sort.js13
-rw-r--r--server/middlewares/validators/users.js67
-rw-r--r--server/middlewares/validators/utils.js2
-rw-r--r--server/middlewares/validators/videos.js16
-rw-r--r--server/models/application.js31
-rw-r--r--server/models/oauth-client.js6
-rw-r--r--server/models/oauth-token.js11
-rw-r--r--server/models/pods.js44
-rw-r--r--server/models/request.js43
-rw-r--r--server/models/user.js86
-rw-r--r--server/models/utils.js30
-rw-r--r--server/models/video.js85
-rw-r--r--server/tests/api/check-params.js746
-rw-r--r--server/tests/api/checkParams.js456
-rw-r--r--server/tests/api/friends-advanced.js (renamed from server/tests/api/friendsAdvanced.js)23
-rw-r--r--server/tests/api/friends-basic.js (renamed from server/tests/api/friendsBasic.js)59
-rw-r--r--server/tests/api/index.js10
-rw-r--r--server/tests/api/multiple-pods.js (renamed from server/tests/api/multiplePods.js)62
-rw-r--r--server/tests/api/requests.js128
-rw-r--r--server/tests/api/single-pod.js (renamed from server/tests/api/singlePod.js)101
-rw-r--r--server/tests/api/users.js210
-rw-r--r--server/tests/api/utils.js419
-rw-r--r--server/tests/real-world/real-world.js31
-rw-r--r--server/tests/utils/clients.js24
-rw-r--r--server/tests/utils/login.js48
-rw-r--r--server/tests/utils/miscs.js21
-rw-r--r--server/tests/utils/pods.js95
-rw-r--r--server/tests/utils/requests.js68
-rw-r--r--server/tests/utils/servers.js115
-rw-r--r--server/tests/utils/users.js100
-rw-r--r--server/tests/utils/videos.js199
69 files changed, 3158 insertions, 1400 deletions
diff --git a/server/controllers/api/v1/clients.js b/server/controllers/api/v1/clients.js
new file mode 100644
index 000000000..5b460db2e
--- /dev/null
+++ b/server/controllers/api/v1/clients.js
@@ -0,0 +1,41 @@
1'use strict'
2
3const express = require('express')
4const mongoose = require('mongoose')
5
6const constants = require('../../../initializers/constants')
7
8const Client = mongoose.model('OAuthClient')
9
10const router = express.Router()
11
12router.get('/local', getLocalClient)
13
14// Get the client credentials for the PeerTube front end
15function getLocalClient (req, res, next) {
16 const serverHost = constants.CONFIG.WEBSERVER.HOST
17 const serverPort = constants.CONFIG.WEBSERVER.PORT
18 let headerHostShouldBe = serverHost
19 if (serverPort !== 80 && serverPort !== 443) {
20 headerHostShouldBe += ':' + serverPort
21 }
22
23 // Don't make this check if this is a test instance
24 if (process.env.NODE_ENV !== 'test' && req.get('host') !== headerHostShouldBe) {
25 return res.type('json').status(403).end()
26 }
27
28 Client.loadFirstClient(function (err, client) {
29 if (err) return next(err)
30 if (!client) return next(new Error('No client available.'))
31
32 res.json({
33 client_id: client._id,
34 client_secret: client.clientSecret
35 })
36 })
37}
38
39// ---------------------------------------------------------------------------
40
41module.exports = router
diff --git a/server/controllers/api/v1/index.js b/server/controllers/api/v1/index.js
index e0c29a8a2..2e4fb2dab 100644
--- a/server/controllers/api/v1/index.js
+++ b/server/controllers/api/v1/index.js
@@ -4,13 +4,17 @@ const express = require('express')
4 4
5const router = express.Router() 5const router = express.Router()
6 6
7const clientsController = require('./clients')
7const podsController = require('./pods') 8const podsController = require('./pods')
8const remoteController = require('./remote') 9const remoteController = require('./remote')
10const requestsController = require('./requests')
9const usersController = require('./users') 11const usersController = require('./users')
10const videosController = require('./videos') 12const videosController = require('./videos')
11 13
14router.use('/clients', clientsController)
12router.use('/pods', podsController) 15router.use('/pods', podsController)
13router.use('/remote', remoteController) 16router.use('/remote', remoteController)
17router.use('/requests', requestsController)
14router.use('/users', usersController) 18router.use('/users', usersController)
15router.use('/videos', videosController) 19router.use('/videos', videosController)
16router.use('/*', badRequest) 20router.use('/*', badRequest)
diff --git a/server/controllers/api/v1/pods.js b/server/controllers/api/v1/pods.js
index 2bc761fef..8ffade578 100644
--- a/server/controllers/api/v1/pods.js
+++ b/server/controllers/api/v1/pods.js
@@ -8,7 +8,10 @@ const waterfall = require('async/waterfall')
8const logger = require('../../../helpers/logger') 8const logger = require('../../../helpers/logger')
9const friends = require('../../../lib/friends') 9const friends = require('../../../lib/friends')
10const middlewares = require('../../../middlewares') 10const middlewares = require('../../../middlewares')
11const admin = middlewares.admin
11const oAuth = middlewares.oauth 12const oAuth = middlewares.oauth
13const podsMiddleware = middlewares.pods
14const checkSignature = middlewares.secure.checkSignature
12const validators = middlewares.validators.pods 15const validators = middlewares.validators.pods
13const signatureValidator = middlewares.validators.remote.signature 16const signatureValidator = middlewares.validators.remote.signature
14 17
@@ -16,12 +19,30 @@ const router = express.Router()
16const Pod = mongoose.model('Pod') 19const Pod = mongoose.model('Pod')
17const Video = mongoose.model('Video') 20const Video = mongoose.model('Video')
18 21
19router.get('/', listPodsUrl) 22router.get('/', listPods)
20router.post('/', validators.podsAdd, addPods) 23router.post('/',
21router.get('/makefriends', oAuth.authenticate, validators.makeFriends, makeFriends) 24 validators.podsAdd,
22router.get('/quitfriends', oAuth.authenticate, quitFriends) 25 podsMiddleware.setBodyUrlPort,
26 addPods
27)
28router.post('/makefriends',
29 oAuth.authenticate,
30 admin.ensureIsAdmin,
31 validators.makeFriends,
32 podsMiddleware.setBodyUrlsPort,
33 makeFriends
34)
35router.get('/quitfriends',
36 oAuth.authenticate,
37 admin.ensureIsAdmin,
38 quitFriends
39)
23// Post because this is a secured request 40// Post because this is a secured request
24router.post('/remove', signatureValidator, removePods) 41router.post('/remove',
42 signatureValidator,
43 checkSignature,
44 removePods
45)
25 46
26// --------------------------------------------------------------------------- 47// ---------------------------------------------------------------------------
27 48
@@ -64,20 +85,27 @@ function addPods (req, res, next) {
64 }) 85 })
65} 86}
66 87
67function listPodsUrl (req, res, next) { 88function listPods (req, res, next) {
68 Pod.listOnlyUrls(function (err, podsUrlList) { 89 Pod.list(function (err, podsUrlList) {
69 if (err) return next(err) 90 if (err) return next(err)
70 91
71 res.json(podsUrlList) 92 res.json(getFormatedPods(podsUrlList))
72 }) 93 })
73} 94}
74 95
75function makeFriends (req, res, next) { 96function makeFriends (req, res, next) {
76 friends.makeFriends(function (err) { 97 const urls = req.body.urls
77 if (err) return next(err)
78 98
79 res.type('json').status(204).end() 99 friends.makeFriends(urls, function (err) {
100 if (err) {
101 logger.error('Could not make friends.', { error: err })
102 return
103 }
104
105 logger.info('Made friends!')
80 }) 106 })
107
108 res.type('json').status(204).end()
81} 109}
82 110
83function removePods (req, res, next) { 111function removePods (req, res, next) {
@@ -125,3 +153,15 @@ function quitFriends (req, res, next) {
125 res.type('json').status(204).end() 153 res.type('json').status(204).end()
126 }) 154 })
127} 155}
156
157// ---------------------------------------------------------------------------
158
159function getFormatedPods (pods) {
160 const formatedPods = []
161
162 pods.forEach(function (pod) {
163 formatedPods.push(pod.toFormatedJSON())
164 })
165
166 return formatedPods
167}
diff --git a/server/controllers/api/v1/remote.js b/server/controllers/api/v1/remote.js
index f452986b8..a22c5d151 100644
--- a/server/controllers/api/v1/remote.js
+++ b/server/controllers/api/v1/remote.js
@@ -16,6 +16,7 @@ const Video = mongoose.model('Video')
16router.post('/videos', 16router.post('/videos',
17 validators.signature, 17 validators.signature,
18 validators.dataToDecrypt, 18 validators.dataToDecrypt,
19 secureMiddleware.checkSignature,
19 secureMiddleware.decryptBody, 20 secureMiddleware.decryptBody,
20 validators.remoteVideos, 21 validators.remoteVideos,
21 remoteVideos 22 remoteVideos
diff --git a/server/controllers/api/v1/requests.js b/server/controllers/api/v1/requests.js
new file mode 100644
index 000000000..97616424d
--- /dev/null
+++ b/server/controllers/api/v1/requests.js
@@ -0,0 +1,38 @@
1'use strict'
2
3const express = require('express')
4const mongoose = require('mongoose')
5
6const constants = require('../../../initializers/constants')
7const middlewares = require('../../../middlewares')
8const admin = middlewares.admin
9const oAuth = middlewares.oauth
10
11const Request = mongoose.model('Request')
12
13const router = express.Router()
14
15router.get('/stats',
16 oAuth.authenticate,
17 admin.ensureIsAdmin,
18 getStatsRequests
19)
20
21// ---------------------------------------------------------------------------
22
23module.exports = router
24
25// ---------------------------------------------------------------------------
26
27function getStatsRequests (req, res, next) {
28 Request.list(function (err, requests) {
29 if (err) return next(err)
30
31 return res.json({
32 requests: requests,
33 maxRequestsInParallel: constants.REQUESTS_IN_PARALLEL,
34 remainingMilliSeconds: Request.remainingMilliSeconds(),
35 milliSecondsInterval: constants.REQUESTS_INTERVAL
36 })
37 })
38}
diff --git a/server/controllers/api/v1/users.js b/server/controllers/api/v1/users.js
index fbbe6e472..975e25e68 100644
--- a/server/controllers/api/v1/users.js
+++ b/server/controllers/api/v1/users.js
@@ -1,18 +1,59 @@
1'use strict' 1'use strict'
2 2
3const config = require('config') 3const each = require('async/each')
4const mongoose = require('mongoose')
5const express = require('express') 4const express = require('express')
5const mongoose = require('mongoose')
6const waterfall = require('async/waterfall')
6 7
7const oAuth = require('../../../middlewares').oauth 8const constants = require('../../../initializers/constants')
9const friends = require('../../../lib/friends')
10const logger = require('../../../helpers/logger')
11const middlewares = require('../../../middlewares')
12const admin = middlewares.admin
13const oAuth = middlewares.oauth
14const pagination = middlewares.pagination
15const sort = middlewares.sort
16const validatorsPagination = middlewares.validators.pagination
17const validatorsSort = middlewares.validators.sort
18const validatorsUsers = middlewares.validators.users
8 19
9const Client = mongoose.model('OAuthClient') 20const User = mongoose.model('User')
21const Video = mongoose.model('Video')
10 22
11const router = express.Router() 23const router = express.Router()
12 24
13router.get('/client', getAngularClient) 25router.get('/me', oAuth.authenticate, getUserInformation)
26
27router.get('/',
28 validatorsPagination.pagination,
29 validatorsSort.usersSort,
30 sort.setUsersSort,
31 pagination.setPagination,
32 listUsers
33)
34
35router.post('/',
36 oAuth.authenticate,
37 admin.ensureIsAdmin,
38 validatorsUsers.usersAdd,
39 createUser
40)
41
42router.put('/:id',
43 oAuth.authenticate,
44 validatorsUsers.usersUpdate,
45 updateUser
46)
47
48router.delete('/:id',
49 oAuth.authenticate,
50 admin.ensureIsAdmin,
51 validatorsUsers.usersRemove,
52 removeUser
53)
54
14router.post('/token', oAuth.token, success) 55router.post('/token', oAuth.token, success)
15// TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged,, implement revoke token route 56// TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged, implement revoke token route
16 57
17// --------------------------------------------------------------------------- 58// ---------------------------------------------------------------------------
18 59
@@ -20,26 +61,91 @@ module.exports = router
20 61
21// --------------------------------------------------------------------------- 62// ---------------------------------------------------------------------------
22 63
23function getAngularClient (req, res, next) { 64function createUser (req, res, next) {
24 const serverHost = config.get('webserver.host') 65 const user = new User({
25 const serverPort = config.get('webserver.port') 66 username: req.body.username,
26 let headerHostShouldBe = serverHost 67 password: req.body.password,
27 if (serverPort !== 80 && serverPort !== 443) { 68 role: constants.USER_ROLES.USER
28 headerHostShouldBe += ':' + serverPort 69 })
29 }
30 70
31 // Don't make this check if this is a test instance 71 user.save(function (err, createdUser) {
32 if (process.env.NODE_ENV !== 'test' && req.get('host') !== headerHostShouldBe) { 72 if (err) return next(err)
33 return res.type('json').status(403).end()
34 }
35 73
36 Client.loadFirstClient(function (err, client) { 74 return res.type('json').status(204).end()
75 })
76}
77
78function getUserInformation (req, res, next) {
79 User.loadByUsername(res.locals.oauth.token.user.username, function (err, user) {
37 if (err) return next(err) 80 if (err) return next(err)
38 if (!client) return next(new Error('No client available.'))
39 81
40 res.json({ 82 return res.json(user.toFormatedJSON())
41 client_id: client._id, 83 })
42 client_secret: client.clientSecret 84}
85
86function listUsers (req, res, next) {
87 User.listForApi(req.query.start, req.query.count, req.query.sort, function (err, usersList, usersTotal) {
88 if (err) return next(err)
89
90 res.json(getFormatedUsers(usersList, usersTotal))
91 })
92}
93
94function removeUser (req, res, next) {
95 waterfall([
96 function getUser (callback) {
97 User.loadById(req.params.id, callback)
98 },
99
100 function getVideos (user, callback) {
101 Video.listOwnedByAuthor(user.username, function (err, videos) {
102 return callback(err, user, videos)
103 })
104 },
105
106 function removeVideosFromDB (user, videos, callback) {
107 each(videos, function (video, callbackEach) {
108 video.remove(callbackEach)
109 }, function (err) {
110 return callback(err, user, videos)
111 })
112 },
113
114 function sendInformationToFriends (user, videos, callback) {
115 videos.forEach(function (video) {
116 const params = {
117 name: video.name,
118 magnetUri: video.magnetUri
119 }
120
121 friends.removeVideoToFriends(params)
122 })
123
124 return callback(null, user)
125 },
126
127 function removeUserFromDB (user, callback) {
128 user.remove(callback)
129 }
130 ], function andFinally (err) {
131 if (err) {
132 logger.error('Errors when removed the user.', { error: err })
133 return next(err)
134 }
135
136 return res.sendStatus(204)
137 })
138}
139
140function updateUser (req, res, next) {
141 User.loadByUsername(res.locals.oauth.token.user.username, function (err, user) {
142 if (err) return next(err)
143
144 user.password = req.body.password
145 user.save(function (err) {
146 if (err) return next(err)
147
148 return res.sendStatus(204)
43 }) 149 })
44 }) 150 })
45} 151}
@@ -47,3 +153,18 @@ function getAngularClient (req, res, next) {
47function success (req, res, next) { 153function success (req, res, next) {
48 res.end() 154 res.end()
49} 155}
156
157// ---------------------------------------------------------------------------
158
159function getFormatedUsers (users, usersTotal) {
160 const formatedUsers = []
161
162 users.forEach(function (user) {
163 formatedUsers.push(user.toFormatedJSON())
164 })
165
166 return {
167 total: usersTotal,
168 data: formatedUsers
169 }
170}
diff --git a/server/controllers/api/v1/videos.js b/server/controllers/api/v1/videos.js
index 1f939b077..70d22f139 100644
--- a/server/controllers/api/v1/videos.js
+++ b/server/controllers/api/v1/videos.js
@@ -1,11 +1,11 @@
1'use strict' 1'use strict'
2 2
3const config = require('config')
4const express = require('express') 3const express = require('express')
5const mongoose = require('mongoose') 4const mongoose = require('mongoose')
6const multer = require('multer') 5const multer = require('multer')
7const waterfall = require('async/waterfall') 6const waterfall = require('async/waterfall')
8 7
8const constants = require('../../../initializers/constants')
9const logger = require('../../../helpers/logger') 9const logger = require('../../../helpers/logger')
10const friends = require('../../../lib/friends') 10const friends = require('../../../lib/friends')
11const middlewares = require('../../../middlewares') 11const middlewares = require('../../../middlewares')
@@ -20,13 +20,12 @@ const sort = middlewares.sort
20const utils = require('../../../helpers/utils') 20const utils = require('../../../helpers/utils')
21 21
22const router = express.Router() 22const router = express.Router()
23const uploads = config.get('storage.uploads')
24const Video = mongoose.model('Video') 23const Video = mongoose.model('Video')
25 24
26// multer configuration 25// multer configuration
27const storage = multer.diskStorage({ 26const storage = multer.diskStorage({
28 destination: function (req, file, cb) { 27 destination: function (req, file, cb) {
29 cb(null, uploads) 28 cb(null, constants.CONFIG.STORAGE.UPLOAD_DIR)
30 }, 29 },
31 30
32 filename: function (req, file, cb) { 31 filename: function (req, file, cb) {
@@ -142,7 +141,7 @@ function getVideo (req, res, next) {
142} 141}
143 142
144function listVideos (req, res, next) { 143function listVideos (req, res, next) {
145 Video.list(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) { 144 Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) {
146 if (err) return next(err) 145 if (err) return next(err)
147 146
148 res.json(getFormatedVideos(videosList, videosTotal)) 147 res.json(getFormatedVideos(videosList, videosTotal))
diff --git a/server/helpers/custom-validators/index.js b/server/helpers/custom-validators/index.js
new file mode 100644
index 000000000..96b5b20b9
--- /dev/null
+++ b/server/helpers/custom-validators/index.js
@@ -0,0 +1,17 @@
1'use strict'
2
3const miscValidators = require('./misc')
4const podsValidators = require('./pods')
5const usersValidators = require('./users')
6const videosValidators = require('./videos')
7
8const validators = {
9 misc: miscValidators,
10 pods: podsValidators,
11 users: usersValidators,
12 videos: videosValidators
13}
14
15// ---------------------------------------------------------------------------
16
17module.exports = validators
diff --git a/server/helpers/custom-validators/misc.js b/server/helpers/custom-validators/misc.js
new file mode 100644
index 000000000..052726241
--- /dev/null
+++ b/server/helpers/custom-validators/misc.js
@@ -0,0 +1,18 @@
1'use strict'
2
3const miscValidators = {
4 exists,
5 isArray
6}
7
8function exists (value) {
9 return value !== undefined && value !== null
10}
11
12function isArray (value) {
13 return Array.isArray(value)
14}
15
16// ---------------------------------------------------------------------------
17
18module.exports = miscValidators
diff --git a/server/helpers/custom-validators/pods.js b/server/helpers/custom-validators/pods.js
new file mode 100644
index 000000000..40f8b5d0b
--- /dev/null
+++ b/server/helpers/custom-validators/pods.js
@@ -0,0 +1,21 @@
1'use strict'
2
3const validator = require('express-validator').validator
4
5const miscValidators = require('./misc')
6
7const podsValidators = {
8 isEachUniqueUrlValid
9}
10
11function isEachUniqueUrlValid (urls) {
12 return miscValidators.isArray(urls) &&
13 urls.length !== 0 &&
14 urls.every(function (url) {
15 return validator.isURL(url) && urls.indexOf(url) === urls.lastIndexOf(url)
16 })
17}
18
19// ---------------------------------------------------------------------------
20
21module.exports = podsValidators
diff --git a/server/helpers/custom-validators/users.js b/server/helpers/custom-validators/users.js
new file mode 100644
index 000000000..88fa1592e
--- /dev/null
+++ b/server/helpers/custom-validators/users.js
@@ -0,0 +1,31 @@
1'use strict'
2
3const validator = require('express-validator').validator
4const values = require('lodash/values')
5
6const constants = require('../../initializers/constants')
7const USERS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.USERS
8
9const usersValidators = {
10 isUserPasswordValid,
11 isUserRoleValid,
12 isUserUsernameValid
13}
14
15function isUserPasswordValid (value) {
16 return validator.isLength(value, USERS_CONSTRAINTS_FIELDS.PASSWORD)
17}
18
19function isUserRoleValid (value) {
20 return values(constants.USER_ROLES).indexOf(value) !== -1
21}
22
23function isUserUsernameValid (value) {
24 const max = USERS_CONSTRAINTS_FIELDS.USERNAME.max
25 const min = USERS_CONSTRAINTS_FIELDS.USERNAME.min
26 return validator.matches(value, new RegExp(`^[a-zA-Z0-9._]{${min},${max}}$`))
27}
28
29// ---------------------------------------------------------------------------
30
31module.exports = usersValidators
diff --git a/server/helpers/custom-validators.js b/server/helpers/custom-validators/videos.js
index b666644c0..a507ff686 100644
--- a/server/helpers/custom-validators.js
+++ b/server/helpers/custom-validators/videos.js
@@ -2,66 +2,51 @@
2 2
3const validator = require('express-validator').validator 3const validator = require('express-validator').validator
4 4
5const constants = require('../initializers/constants') 5const constants = require('../../initializers/constants')
6const VIDEOS_CONSTRAINTS_FIELDS = constants.VIDEOS_CONSTRAINTS_FIELDS 6const usersValidators = require('./users')
7 7const miscValidators = require('./misc')
8const customValidators = { 8const VIDEOS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEOS
9 exists: exists, 9
10 isEachRemoteVideosValid: isEachRemoteVideosValid, 10const videosValidators = {
11 isArray: isArray, 11 isEachRemoteVideosValid,
12 isVideoAuthorValid: isVideoAuthorValid, 12 isVideoAuthorValid,
13 isVideoDateValid: isVideoDateValid, 13 isVideoDateValid,
14 isVideoDescriptionValid: isVideoDescriptionValid, 14 isVideoDescriptionValid,
15 isVideoDurationValid: isVideoDurationValid, 15 isVideoDurationValid,
16 isVideoMagnetUriValid: isVideoMagnetUriValid, 16 isVideoMagnetUriValid,
17 isVideoNameValid: isVideoNameValid, 17 isVideoNameValid,
18 isVideoPodUrlValid: isVideoPodUrlValid, 18 isVideoPodUrlValid,
19 isVideoTagsValid: isVideoTagsValid, 19 isVideoTagsValid,
20 isVideoThumbnailValid: isVideoThumbnailValid, 20 isVideoThumbnailValid,
21 isVideoThumbnail64Valid: isVideoThumbnail64Valid 21 isVideoThumbnail64Valid
22}
23
24function exists (value) {
25 return value !== undefined && value !== null
26} 22}
27 23
28function isEachRemoteVideosValid (requests) { 24function isEachRemoteVideosValid (requests) {
29 return requests.every(function (request) { 25 return miscValidators.isArray(requests) &&
30 const video = request.data 26 requests.every(function (request) {
31 return ( 27 const video = request.data
32 isRequestTypeAddValid(request.type) && 28 return (
33 isVideoAuthorValid(video.author) && 29 isRequestTypeAddValid(request.type) &&
34 isVideoDateValid(video.createdDate) && 30 isVideoAuthorValid(video.author) &&
35 isVideoDescriptionValid(video.description) && 31 isVideoDateValid(video.createdDate) &&
36 isVideoDurationValid(video.duration) && 32 isVideoDescriptionValid(video.description) &&
37 isVideoMagnetUriValid(video.magnetUri) && 33 isVideoDurationValid(video.duration) &&
38 isVideoNameValid(video.name) && 34 isVideoMagnetUriValid(video.magnetUri) &&
39 isVideoPodUrlValid(video.podUrl) && 35 isVideoNameValid(video.name) &&
40 isVideoTagsValid(video.tags) && 36 isVideoPodUrlValid(video.podUrl) &&
41 isVideoThumbnail64Valid(video.thumbnailBase64) 37 isVideoTagsValid(video.tags) &&
42 ) || 38 isVideoThumbnail64Valid(video.thumbnailBase64)
43 ( 39 ) ||
44 isRequestTypeRemoveValid(request.type) && 40 (
45 isVideoNameValid(video.name) && 41 isRequestTypeRemoveValid(request.type) &&
46 isVideoMagnetUriValid(video.magnetUri) 42 isVideoNameValid(video.name) &&
47 ) 43 isVideoMagnetUriValid(video.magnetUri)
48 }) 44 )
49} 45 })
50
51function isArray (value) {
52 return Array.isArray(value)
53}
54
55function isRequestTypeAddValid (value) {
56 return value === 'add'
57}
58
59function isRequestTypeRemoveValid (value) {
60 return value === 'remove'
61} 46}
62 47
63function isVideoAuthorValid (value) { 48function isVideoAuthorValid (value) {
64 return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.AUTHOR) 49 return usersValidators.isUserUsernameValid(value)
65} 50}
66 51
67function isVideoDateValid (value) { 52function isVideoDateValid (value) {
@@ -90,7 +75,7 @@ function isVideoPodUrlValid (value) {
90} 75}
91 76
92function isVideoTagsValid (tags) { 77function isVideoTagsValid (tags) {
93 return isArray(tags) && 78 return miscValidators.isArray(tags) &&
94 validator.isInt(tags.length, VIDEOS_CONSTRAINTS_FIELDS.TAGS) && 79 validator.isInt(tags.length, VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
95 tags.every(function (tag) { 80 tags.every(function (tag) {
96 return validator.isAlphanumeric(tag) && 81 return validator.isAlphanumeric(tag) &&
@@ -109,6 +94,14 @@ function isVideoThumbnail64Valid (value) {
109 94
110// --------------------------------------------------------------------------- 95// ---------------------------------------------------------------------------
111 96
112module.exports = customValidators 97module.exports = videosValidators
113 98
114// --------------------------------------------------------------------------- 99// ---------------------------------------------------------------------------
100
101function isRequestTypeAddValid (value) {
102 return value === 'add'
103}
104
105function isRequestTypeRemoveValid (value) {
106 return value === 'remove'
107}
diff --git a/server/helpers/logger.js b/server/helpers/logger.js
index 8ae90a4b2..590ceaeb6 100644
--- a/server/helpers/logger.js
+++ b/server/helpers/logger.js
@@ -1,23 +1,23 @@
1// Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/ 1// Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/
2'use strict' 2'use strict'
3 3
4const config = require('config')
5const mkdirp = require('mkdirp') 4const mkdirp = require('mkdirp')
6const path = require('path') 5const path = require('path')
7const winston = require('winston') 6const winston = require('winston')
8winston.emitErrs = true 7winston.emitErrs = true
9 8
10const logDir = path.join(__dirname, '..', '..', config.get('storage.logs')) 9const constants = require('../initializers/constants')
11const label = config.get('webserver.host') + ':' + config.get('webserver.port') 10
11const label = constants.CONFIG.WEBSERVER.HOST + ':' + constants.CONFIG.WEBSERVER.PORT
12 12
13// Create the directory if it does not exist 13// Create the directory if it does not exist
14mkdirp.sync(logDir) 14mkdirp.sync(constants.CONFIG.STORAGE.LOG_DIR)
15 15
16const logger = new winston.Logger({ 16const logger = new winston.Logger({
17 transports: [ 17 transports: [
18 new winston.transports.File({ 18 new winston.transports.File({
19 level: 'debug', 19 level: 'debug',
20 filename: path.join(logDir, 'all-logs.log'), 20 filename: path.join(constants.CONFIG.STORAGE.LOG_DIR, 'all-logs.log'),
21 handleExceptions: true, 21 handleExceptions: true,
22 json: true, 22 json: true,
23 maxsize: 5242880, 23 maxsize: 5242880,
diff --git a/server/helpers/peertube-crypto.js b/server/helpers/peertube-crypto.js
index 46dff8d03..1ff638b04 100644
--- a/server/helpers/peertube-crypto.js
+++ b/server/helpers/peertube-crypto.js
@@ -1,24 +1,24 @@
1'use strict' 1'use strict'
2 2
3const config = require('config') 3const bcrypt = require('bcrypt')
4const crypto = require('crypto') 4const crypto = require('crypto')
5const fs = require('fs') 5const fs = require('fs')
6const openssl = require('openssl-wrapper') 6const openssl = require('openssl-wrapper')
7const path = require('path')
8const ursa = require('ursa') 7const ursa = require('ursa')
9 8
9const constants = require('../initializers/constants')
10const logger = require('./logger') 10const logger = require('./logger')
11 11
12const certDir = path.join(__dirname, '..', '..', config.get('storage.certs'))
13const algorithm = 'aes-256-ctr' 12const algorithm = 'aes-256-ctr'
14 13
15const peertubeCrypto = { 14const peertubeCrypto = {
16 checkSignature: checkSignature, 15 checkSignature,
17 createCertsIfNotExist: createCertsIfNotExist, 16 comparePassword,
18 decrypt: decrypt, 17 createCertsIfNotExist,
19 encrypt: encrypt, 18 cryptPassword,
20 getCertDir: getCertDir, 19 decrypt,
21 sign: sign 20 encrypt,
21 sign
22} 22}
23 23
24function checkSignature (publicKey, rawData, hexSignature) { 24function checkSignature (publicKey, rawData, hexSignature) {
@@ -27,6 +27,14 @@ function checkSignature (publicKey, rawData, hexSignature) {
27 return isValid 27 return isValid
28} 28}
29 29
30function comparePassword (plainPassword, hashPassword, callback) {
31 bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) {
32 if (err) return callback(err)
33
34 return callback(null, isPasswordMatch)
35 })
36}
37
30function createCertsIfNotExist (callback) { 38function createCertsIfNotExist (callback) {
31 certsExist(function (exist) { 39 certsExist(function (exist) {
32 if (exist === true) { 40 if (exist === true) {
@@ -39,8 +47,18 @@ function createCertsIfNotExist (callback) {
39 }) 47 })
40} 48}
41 49
50function cryptPassword (password, callback) {
51 bcrypt.genSalt(constants.BCRYPT_SALT_SIZE, function (err, salt) {
52 if (err) return callback(err)
53
54 bcrypt.hash(password, salt, function (err, hash) {
55 return callback(err, hash)
56 })
57 })
58}
59
42function decrypt (key, data, callback) { 60function decrypt (key, data, callback) {
43 fs.readFile(getCertDir() + 'peertube.key.pem', function (err, file) { 61 fs.readFile(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem', function (err, file) {
44 if (err) return callback(err) 62 if (err) return callback(err)
45 63
46 const myPrivateKey = ursa.createPrivateKey(file) 64 const myPrivateKey = ursa.createPrivateKey(file)
@@ -67,12 +85,8 @@ function encrypt (publicKey, data, callback) {
67 }) 85 })
68} 86}
69 87
70function getCertDir () {
71 return certDir
72}
73
74function sign (data) { 88function sign (data) {
75 const myKey = ursa.createPrivateKey(fs.readFileSync(certDir + 'peertube.key.pem')) 89 const myKey = ursa.createPrivateKey(fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem'))
76 const signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex') 90 const signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex')
77 91
78 return signature 92 return signature
@@ -85,7 +99,7 @@ module.exports = peertubeCrypto
85// --------------------------------------------------------------------------- 99// ---------------------------------------------------------------------------
86 100
87function certsExist (callback) { 101function certsExist (callback) {
88 fs.exists(certDir + 'peertube.key.pem', function (exists) { 102 fs.exists(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem', function (exists) {
89 return callback(exists) 103 return callback(exists)
90 }) 104 })
91} 105}
@@ -99,15 +113,25 @@ function createCerts (callback) {
99 } 113 }
100 114
101 logger.info('Generating a RSA key...') 115 logger.info('Generating a RSA key...')
102 openssl.exec('genrsa', { 'out': certDir + 'peertube.key.pem', '2048': false }, function (err) { 116
117 let options = {
118 'out': constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem',
119 '2048': false
120 }
121 openssl.exec('genrsa', options, function (err) {
103 if (err) { 122 if (err) {
104 logger.error('Cannot create private key on this pod.') 123 logger.error('Cannot create private key on this pod.')
105 return callback(err) 124 return callback(err)
106 } 125 }
107 logger.info('RSA key generated.') 126 logger.info('RSA key generated.')
108 127
128 options = {
129 'in': constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem',
130 'pubout': true,
131 'out': constants.CONFIG.STORAGE.CERT_DIR + 'peertube.pub'
132 }
109 logger.info('Manage public key...') 133 logger.info('Manage public key...')
110 openssl.exec('rsa', { 'in': certDir + 'peertube.key.pem', 'pubout': true, 'out': certDir + 'peertube.pub' }, function (err) { 134 openssl.exec('rsa', options, function (err) {
111 if (err) { 135 if (err) {
112 logger.error('Cannot create public key on this pod.') 136 logger.error('Cannot create public key on this pod.')
113 return callback(err) 137 return callback(err)
diff --git a/server/helpers/requests.js b/server/helpers/requests.js
index 547230adc..95775c981 100644
--- a/server/helpers/requests.js
+++ b/server/helpers/requests.js
@@ -1,19 +1,14 @@
1'use strict' 1'use strict'
2 2
3const config = require('config')
4const replay = require('request-replay') 3const replay = require('request-replay')
5const request = require('request') 4const request = require('request')
6 5
7const constants = require('../initializers/constants') 6const constants = require('../initializers/constants')
8const peertubeCrypto = require('./peertube-crypto') 7const peertubeCrypto = require('./peertube-crypto')
9 8
10const http = config.get('webserver.https') ? 'https' : 'http'
11const host = config.get('webserver.host')
12const port = config.get('webserver.port')
13
14const requests = { 9const requests = {
15 makeRetryRequest: makeRetryRequest, 10 makeRetryRequest,
16 makeSecureRequest: makeSecureRequest 11 makeSecureRequest
17} 12}
18 13
19function makeRetryRequest (params, callback) { 14function makeRetryRequest (params, callback) {
@@ -29,8 +24,6 @@ function makeRetryRequest (params, callback) {
29} 24}
30 25
31function makeSecureRequest (params, callback) { 26function makeSecureRequest (params, callback) {
32 const myUrl = http + '://' + host + ':' + port
33
34 const requestParams = { 27 const requestParams = {
35 url: params.toPod.url + params.path 28 url: params.toPod.url + params.path
36 } 29 }
@@ -42,8 +35,8 @@ function makeSecureRequest (params, callback) {
42 // Add signature if it is specified in the params 35 // Add signature if it is specified in the params
43 if (params.sign === true) { 36 if (params.sign === true) {
44 requestParams.json.signature = { 37 requestParams.json.signature = {
45 url: myUrl, 38 url: constants.CONFIG.WEBSERVER.URL,
46 signature: peertubeCrypto.sign(myUrl) 39 signature: peertubeCrypto.sign(constants.CONFIG.WEBSERVER.URL)
47 } 40 }
48 } 41 }
49 42
diff --git a/server/helpers/utils.js b/server/helpers/utils.js
index a77116e08..9c2d402e3 100644
--- a/server/helpers/utils.js
+++ b/server/helpers/utils.js
@@ -5,8 +5,8 @@ const crypto = require('crypto')
5const logger = require('./logger') 5const logger = require('./logger')
6 6
7const utils = { 7const utils = {
8 cleanForExit: cleanForExit, 8 cleanForExit,
9 generateRandomString: generateRandomString 9 generateRandomString
10} 10}
11 11
12function generateRandomString (size, callback) { 12function generateRandomString (size, callback) {
diff --git a/server/initializers/checker.js b/server/initializers/checker.js
index 3831efb8d..91fbcfaf9 100644
--- a/server/initializers/checker.js
+++ b/server/initializers/checker.js
@@ -7,9 +7,9 @@ const Client = mongoose.model('OAuthClient')
7const User = mongoose.model('User') 7const User = mongoose.model('User')
8 8
9const checker = { 9const checker = {
10 checkConfig: checkConfig, 10 checkConfig,
11 clientsExist: clientsExist, 11 clientsExist,
12 usersExist: usersExist 12 usersExist
13} 13}
14 14
15// Check the config files 15// Check the config files
@@ -17,8 +17,8 @@ function checkConfig () {
17 const required = [ 'listen.port', 17 const required = [ 'listen.port',
18 'webserver.https', 'webserver.host', 'webserver.port', 18 'webserver.https', 'webserver.host', 'webserver.port',
19 'database.host', 'database.port', 'database.suffix', 19 'database.host', 'database.port', 'database.suffix',
20 'storage.certs', 'storage.uploads', 'storage.logs', 20 'storage.certs', 'storage.uploads', 'storage.logs', 'storage.thumbnails',
21 'network.friends', 'electron.debug' ] 21 'electron.debug' ]
22 const miss = [] 22 const miss = []
23 23
24 for (const key of required) { 24 for (const key of required) {
@@ -39,10 +39,10 @@ function clientsExist (callback) {
39} 39}
40 40
41function usersExist (callback) { 41function usersExist (callback) {
42 User.list(function (err, users) { 42 User.countTotal(function (err, totalUsers) {
43 if (err) return callback(err) 43 if (err) return callback(err)
44 44
45 return callback(null, users.length !== 0) 45 return callback(null, totalUsers !== 0)
46 }) 46 })
47} 47}
48 48
diff --git a/server/initializers/constants.js b/server/initializers/constants.js
index e0ea188af..be2e3e943 100644
--- a/server/initializers/constants.js
+++ b/server/initializers/constants.js
@@ -1,24 +1,103 @@
1'use strict' 1'use strict'
2 2
3// API version of our pod 3const config = require('config')
4const path = require('path')
5
6// ---------------------------------------------------------------------------
7
8// API version
4const API_VERSION = 'v1' 9const API_VERSION = 'v1'
5 10
6// Score a pod has when we create it as a friend 11// Number of results by default for the pagination
7const FRIEND_SCORE = { 12const PAGINATION_COUNT_DEFAULT = 15
8 BASE: 100, 13
9 MAX: 1000 14// Sortable columns per schema
15const SEARCHABLE_COLUMNS = {
16 VIDEOS: [ 'name', 'magnetUri', 'podUrl', 'author', 'tags' ]
10} 17}
11 18
12// Time to wait between requests to the friends (10 min) 19// Sortable columns per schema
13let INTERVAL = 600000 20const SORTABLE_COLUMNS = {
21 USERS: [ 'username', '-username', 'createdDate', '-createdDate' ],
22 VIDEOS: [ 'name', '-name', 'duration', '-duration', 'createdDate', '-createdDate' ]
23}
14 24
15const OAUTH_LIFETIME = { 25const OAUTH_LIFETIME = {
16 ACCESS_TOKEN: 3600 * 4, // 4 hours 26 ACCESS_TOKEN: 3600 * 4, // 4 hours
17 REFRESH_TOKEN: 1209600 // 2 weeks 27 REFRESH_TOKEN: 1209600 // 2 weeks
18} 28}
19 29
20// Number of results by default for the pagination 30// ---------------------------------------------------------------------------
21const PAGINATION_COUNT_DEFAULT = 15 31
32const CONFIG = {
33 DATABASE: {
34 DBNAME: 'peertube' + config.get('database.suffix'),
35 HOST: config.get('database.host'),
36 PORT: config.get('database.port')
37 },
38 ELECTRON: {
39 DEBUG: config.get('electron.debug')
40 },
41 STORAGE: {
42 CERT_DIR: path.join(__dirname, '..', '..', config.get('storage.certs')),
43 LOG_DIR: path.join(__dirname, '..', '..', config.get('storage.logs')),
44 UPLOAD_DIR: path.join(__dirname, '..', '..', config.get('storage.uploads')),
45 THUMBNAILS_DIR: path.join(__dirname, '..', '..', config.get('storage.thumbnails'))
46 },
47 WEBSERVER: {
48 SCHEME: config.get('webserver.https') === true ? 'https' : 'http',
49 HOST: config.get('webserver.host'),
50 PORT: config.get('webserver.port')
51 }
52}
53CONFIG.WEBSERVER.URL = CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOST + ':' + CONFIG.WEBSERVER.PORT
54
55// ---------------------------------------------------------------------------
56
57const CONSTRAINTS_FIELDS = {
58 USERS: {
59 USERNAME: { min: 3, max: 20 }, // Length
60 PASSWORD: { min: 6, max: 255 } // Length
61 },
62 VIDEOS: {
63 NAME: { min: 3, max: 50 }, // Length
64 DESCRIPTION: { min: 3, max: 250 }, // Length
65 MAGNET_URI: { min: 10 }, // Length
66 DURATION: { min: 1, max: 7200 }, // Number
67 TAGS: { min: 1, max: 3 }, // Number of total tags
68 TAG: { min: 2, max: 10 }, // Length
69 THUMBNAIL: { min: 2, max: 30 },
70 THUMBNAIL64: { min: 0, max: 20000 } // Bytes
71 }
72}
73
74// ---------------------------------------------------------------------------
75
76// Score a pod has when we create it as a friend
77const FRIEND_SCORE = {
78 BASE: 100,
79 MAX: 1000
80}
81
82// ---------------------------------------------------------------------------
83
84const MONGO_MIGRATION_SCRIPTS = [
85 {
86 script: '0005-create-application',
87 version: 5
88 },
89 {
90 script: '0010-users-password',
91 version: 10
92 },
93 {
94 script: '0015-admin-role',
95 version: 15
96 }
97]
98const LAST_MONGO_SCHEMA_VERSION = 15
99
100// ---------------------------------------------------------------------------
22 101
23// Number of points we add/remove from a friend after a successful/bad request 102// Number of points we add/remove from a friend after a successful/bad request
24const PODS_SCORE = { 103const PODS_SCORE = {
@@ -26,28 +105,22 @@ const PODS_SCORE = {
26 BONUS: 10 105 BONUS: 10
27} 106}
28 107
108// Time to wait between requests to the friends (10 min)
109let REQUESTS_INTERVAL = 600000
110
29// Number of requests in parallel we can make 111// Number of requests in parallel we can make
30const REQUESTS_IN_PARALLEL = 10 112const REQUESTS_IN_PARALLEL = 10
31 113
32// How many requests we put in request (request scheduler) 114// How many requests we put in request
33const REQUESTS_LIMIT = 10 115const REQUESTS_LIMIT = 10
34 116
35// Number of requests to retry for replay requests module 117// Number of requests to retry for replay requests module
36const RETRY_REQUESTS = 5 118const RETRY_REQUESTS = 5
37 119
38// Sortable columns per schema 120// ---------------------------------------------------------------------------
39const SEARCHABLE_COLUMNS = {
40 VIDEOS: [ 'name', 'magnetUri', 'podUrl', 'author', 'tags' ]
41}
42
43// Seeds in parallel we send to electron when "seed all"
44// Once a video is in seeding state we seed another video etc
45const SEEDS_IN_PARALLEL = 3
46 121
47// Sortable columns per schema 122// Password encryption
48const SORTABLE_COLUMNS = { 123const BCRYPT_SALT_SIZE = 10
49 VIDEOS: [ 'name', '-name', 'duration', '-duration', 'createdDate', '-createdDate' ]
50}
51 124
52// Express static paths (router) 125// Express static paths (router)
53const STATIC_PATHS = { 126const STATIC_PATHS = {
@@ -59,43 +132,47 @@ const STATIC_PATHS = {
59// Videos thumbnail size 132// Videos thumbnail size
60const THUMBNAILS_SIZE = '200x110' 133const THUMBNAILS_SIZE = '200x110'
61 134
62const VIDEOS_CONSTRAINTS_FIELDS = { 135const USER_ROLES = {
63 NAME: { min: 3, max: 50 }, // Length 136 ADMIN: 'admin',
64 DESCRIPTION: { min: 3, max: 250 }, // Length 137 USER: 'user'
65 MAGNET_URI: { min: 10 }, // Length
66 DURATION: { min: 1, max: 7200 }, // Number
67 AUTHOR: { min: 3, max: 20 }, // Length
68 TAGS: { min: 1, max: 3 }, // Number of total tags
69 TAG: { min: 2, max: 10 }, // Length
70 THUMBNAIL: { min: 2, max: 30 },
71 THUMBNAIL64: { min: 0, max: 20000 } // Bytes
72} 138}
73 139
140// Seeds in parallel we send to electron when "seed all"
141// Once a video is in seeding state we seed another video etc
142const SEEDS_IN_PARALLEL = 3
143
144// ---------------------------------------------------------------------------
145
74// Special constants for a test instance 146// Special constants for a test instance
75if (isTestInstance() === true) { 147if (isTestInstance() === true) {
148 CONSTRAINTS_FIELDS.VIDEOS.DURATION.max = 14
76 FRIEND_SCORE.BASE = 20 149 FRIEND_SCORE.BASE = 20
77 INTERVAL = 10000 150 REQUESTS_INTERVAL = 10000
78 VIDEOS_CONSTRAINTS_FIELDS.DURATION.max = 14
79} 151}
80 152
81// --------------------------------------------------------------------------- 153// ---------------------------------------------------------------------------
82 154
83module.exports = { 155module.exports = {
84 API_VERSION: API_VERSION, 156 API_VERSION,
85 FRIEND_SCORE: FRIEND_SCORE, 157 BCRYPT_SALT_SIZE,
86 INTERVAL: INTERVAL, 158 CONFIG,
87 OAUTH_LIFETIME: OAUTH_LIFETIME, 159 CONSTRAINTS_FIELDS,
88 PAGINATION_COUNT_DEFAULT: PAGINATION_COUNT_DEFAULT, 160 FRIEND_SCORE,
89 PODS_SCORE: PODS_SCORE, 161 LAST_MONGO_SCHEMA_VERSION,
90 REQUESTS_IN_PARALLEL: REQUESTS_IN_PARALLEL, 162 MONGO_MIGRATION_SCRIPTS,
91 REQUESTS_LIMIT: REQUESTS_LIMIT, 163 OAUTH_LIFETIME,
92 RETRY_REQUESTS: RETRY_REQUESTS, 164 PAGINATION_COUNT_DEFAULT,
93 SEARCHABLE_COLUMNS: SEARCHABLE_COLUMNS, 165 PODS_SCORE,
94 SEEDS_IN_PARALLEL: SEEDS_IN_PARALLEL, 166 REQUESTS_IN_PARALLEL,
95 SORTABLE_COLUMNS: SORTABLE_COLUMNS, 167 REQUESTS_INTERVAL,
96 STATIC_PATHS: STATIC_PATHS, 168 REQUESTS_LIMIT,
97 THUMBNAILS_SIZE: THUMBNAILS_SIZE, 169 RETRY_REQUESTS,
98 VIDEOS_CONSTRAINTS_FIELDS: VIDEOS_CONSTRAINTS_FIELDS 170 SEARCHABLE_COLUMNS,
171 SEEDS_IN_PARALLEL,
172 SORTABLE_COLUMNS,
173 STATIC_PATHS,
174 THUMBNAILS_SIZE,
175 USER_ROLES
99} 176}
100 177
101// --------------------------------------------------------------------------- 178// ---------------------------------------------------------------------------
diff --git a/server/initializers/database.js b/server/initializers/database.js
index 8626895ee..45c8a240d 100644
--- a/server/initializers/database.js
+++ b/server/initializers/database.js
@@ -1,30 +1,27 @@
1'use strict' 1'use strict'
2 2
3const config = require('config')
4const mongoose = require('mongoose') 3const mongoose = require('mongoose')
5 4
5const constants = require('../initializers/constants')
6const logger = require('../helpers/logger') 6const logger = require('../helpers/logger')
7 7
8// Bootstrap models 8// Bootstrap models
9require('../models/application')
10require('../models/oauth-token')
9require('../models/user') 11require('../models/user')
10require('../models/oauth-client') 12require('../models/oauth-client')
11require('../models/oauth-token')
12require('../models/pods') 13require('../models/pods')
13require('../models/video') 14require('../models/video')
14// Request model needs Video model 15// Request model needs Video model
15require('../models/request') 16require('../models/request')
16 17
17const dbname = 'peertube' + config.get('database.suffix')
18const host = config.get('database.host')
19const port = config.get('database.port')
20
21const database = { 18const database = {
22 connect: connect 19 connect: connect
23} 20}
24 21
25function connect () { 22function connect () {
26 mongoose.Promise = global.Promise 23 mongoose.Promise = global.Promise
27 mongoose.connect('mongodb://' + host + ':' + port + '/' + dbname) 24 mongoose.connect('mongodb://' + constants.CONFIG.DATABASE.HOST + ':' + constants.CONFIG.DATABASE.PORT + '/' + constants.CONFIG.DATABASE.DBNAME)
28 mongoose.connection.on('error', function () { 25 mongoose.connection.on('error', function () {
29 throw new Error('Mongodb connection error.') 26 throw new Error('Mongodb connection error.')
30 }) 27 })
diff --git a/server/initializers/installer.js b/server/initializers/installer.js
index 32830d4da..1df300ba8 100644
--- a/server/initializers/installer.js
+++ b/server/initializers/installer.js
@@ -9,14 +9,16 @@ const path = require('path')
9const series = require('async/series') 9const series = require('async/series')
10 10
11const checker = require('./checker') 11const checker = require('./checker')
12const constants = require('./constants')
12const logger = require('../helpers/logger') 13const logger = require('../helpers/logger')
13const peertubeCrypto = require('../helpers/peertube-crypto') 14const peertubeCrypto = require('../helpers/peertube-crypto')
14 15
16const Application = mongoose.model('Application')
15const Client = mongoose.model('OAuthClient') 17const Client = mongoose.model('OAuthClient')
16const User = mongoose.model('User') 18const User = mongoose.model('User')
17 19
18const installer = { 20const installer = {
19 installApplication: installApplication 21 installApplication
20} 22}
21 23
22function installApplication (callback) { 24function installApplication (callback) {
@@ -34,7 +36,7 @@ function installApplication (callback) {
34 }, 36 },
35 37
36 function createOAuthUser (callbackAsync) { 38 function createOAuthUser (callbackAsync) {
37 createOAuthUserIfNotExist(callbackAsync) 39 createOAuthAdminIfNotExist(callbackAsync)
38 } 40 }
39 ], callback) 41 ], callback)
40} 42}
@@ -80,7 +82,7 @@ function createOAuthClientIfNotExist (callback) {
80 }) 82 })
81} 83}
82 84
83function createOAuthUserIfNotExist (callback) { 85function createOAuthAdminIfNotExist (callback) {
84 checker.usersExist(function (err, exist) { 86 checker.usersExist(function (err, exist) {
85 if (err) return callback(err) 87 if (err) return callback(err)
86 88
@@ -90,6 +92,7 @@ function createOAuthUserIfNotExist (callback) {
90 logger.info('Creating the administrator.') 92 logger.info('Creating the administrator.')
91 93
92 const username = 'root' 94 const username = 'root'
95 const role = constants.USER_ROLES.ADMIN
93 let password = '' 96 let password = ''
94 97
95 // Do not generate a random password for tests 98 // Do not generate a random password for tests
@@ -104,17 +107,20 @@ function createOAuthUserIfNotExist (callback) {
104 } 107 }
105 108
106 const user = new User({ 109 const user = new User({
107 username: username, 110 username,
108 password: password 111 password,
112 role
109 }) 113 })
110 114
111 user.save(function (err, createdUser) { 115 user.save(function (err, createdUser) {
112 if (err) return callback(err) 116 if (err) return callback(err)
113 117
114 logger.info('Username: ' + createdUser.username) 118 logger.info('Username: ' + username)
115 logger.info('User password: ' + createdUser.password) 119 logger.info('User password: ' + password)
116 120
117 return callback(null) 121 logger.info('Creating Application collection.')
122 const application = new Application({ mongoSchemaVersion: constants.LAST_MONGO_SCHEMA_VERSION })
123 application.save(callback)
118 }) 124 })
119 }) 125 })
120} 126}
diff --git a/server/initializers/migrations/0005-create-application.js b/server/initializers/migrations/0005-create-application.js
new file mode 100644
index 000000000..e99dec019
--- /dev/null
+++ b/server/initializers/migrations/0005-create-application.js
@@ -0,0 +1,17 @@
1/*
2 Create the application collection in MongoDB.
3 Used to store the actual MongoDB scheme version.
4*/
5
6const mongoose = require('mongoose')
7
8const Application = mongoose.model('Application')
9
10exports.up = function (callback) {
11 const application = new Application()
12 application.save(callback)
13}
14
15exports.down = function (callback) {
16 throw new Error('Not implemented.')
17}
diff --git a/server/initializers/migrations/0010-users-password.js b/server/initializers/migrations/0010-users-password.js
new file mode 100644
index 000000000..a0616a269
--- /dev/null
+++ b/server/initializers/migrations/0010-users-password.js
@@ -0,0 +1,22 @@
1/*
2 Convert plain user password to encrypted user password.
3*/
4
5const eachSeries = require('async/eachSeries')
6const mongoose = require('mongoose')
7
8const User = mongoose.model('User')
9
10exports.up = function (callback) {
11 User.list(function (err, users) {
12 if (err) return callback(err)
13
14 eachSeries(users, function (user, callbackEach) {
15 user.save(callbackEach)
16 }, callback)
17 })
18}
19
20exports.down = function (callback) {
21 throw new Error('Not implemented.')
22}
diff --git a/server/initializers/migrations/0015-admin-role.js b/server/initializers/migrations/0015-admin-role.js
new file mode 100644
index 000000000..af06dca9e
--- /dev/null
+++ b/server/initializers/migrations/0015-admin-role.js
@@ -0,0 +1,16 @@
1/*
2 Set the admin role to the root user.
3*/
4
5const constants = require('../constants')
6const mongoose = require('mongoose')
7
8const User = mongoose.model('User')
9
10exports.up = function (callback) {
11 User.update({ username: 'root' }, { role: constants.USER_ROLES.ADMIN }, callback)
12}
13
14exports.down = function (callback) {
15 throw new Error('Not implemented.')
16}
diff --git a/server/initializers/migrator.js b/server/initializers/migrator.js
new file mode 100644
index 000000000..6b31d994f
--- /dev/null
+++ b/server/initializers/migrator.js
@@ -0,0 +1,56 @@
1'use strict'
2
3const eachSeries = require('async/eachSeries')
4const mongoose = require('mongoose')
5const path = require('path')
6
7const constants = require('./constants')
8const logger = require('../helpers/logger')
9
10const Application = mongoose.model('Application')
11
12const migrator = {
13 migrate: migrate
14}
15
16function migrate (callback) {
17 Application.loadMongoSchemaVersion(function (err, actualVersion) {
18 if (err) return callback(err)
19
20 // If there are a new mongo schemas
21 if (!actualVersion || actualVersion < constants.LAST_MONGO_SCHEMA_VERSION) {
22 logger.info('Begin migrations.')
23
24 eachSeries(constants.MONGO_MIGRATION_SCRIPTS, function (entity, callbackEach) {
25 const versionScript = entity.version
26
27 // Do not execute old migration scripts
28 if (versionScript <= actualVersion) return callbackEach(null)
29
30 // Load the migration module and run it
31 const migrationScriptName = entity.script
32 logger.info('Executing %s migration script.', migrationScriptName)
33
34 const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName))
35 migrationScript.up(function (err) {
36 if (err) return callbackEach(err)
37
38 // Update the new mongo version schema
39 Application.updateMongoSchemaVersion(versionScript, callbackEach)
40 })
41 }, function (err) {
42 if (err) return callback(err)
43
44 logger.info('Migrations finished. New mongo version schema: %s', constants.LAST_MONGO_SCHEMA_VERSION)
45 return callback(null)
46 })
47 } else {
48 return callback(null)
49 }
50 })
51}
52
53// ---------------------------------------------------------------------------
54
55module.exports = migrator
56
diff --git a/server/lib/friends.js b/server/lib/friends.js
index 6e1516b94..556d2e773 100644
--- a/server/lib/friends.js
+++ b/server/lib/friends.js
@@ -1,6 +1,5 @@
1'use strict' 1'use strict'
2 2
3const config = require('config')
4const each = require('async/each') 3const each = require('async/each')
5const eachLimit = require('async/eachLimit') 4const eachLimit = require('async/eachLimit')
6const eachSeries = require('async/eachSeries') 5const eachSeries = require('async/eachSeries')
@@ -11,24 +10,20 @@ const waterfall = require('async/waterfall')
11 10
12const constants = require('../initializers/constants') 11const constants = require('../initializers/constants')
13const logger = require('../helpers/logger') 12const logger = require('../helpers/logger')
14const peertubeCrypto = require('../helpers/peertube-crypto')
15const requests = require('../helpers/requests') 13const requests = require('../helpers/requests')
16 14
17const http = config.get('webserver.https') ? 'https' : 'http'
18const host = config.get('webserver.host')
19const port = config.get('webserver.port')
20const Pod = mongoose.model('Pod') 15const Pod = mongoose.model('Pod')
21const Request = mongoose.model('Request') 16const Request = mongoose.model('Request')
22const Video = mongoose.model('Video') 17const Video = mongoose.model('Video')
23 18
24const friends = { 19const friends = {
25 addVideoToFriends: addVideoToFriends, 20 addVideoToFriends,
26 hasFriends: hasFriends, 21 hasFriends,
27 getMyCertificate: getMyCertificate, 22 getMyCertificate,
28 makeFriends: makeFriends, 23 makeFriends,
29 quitFriends: quitFriends, 24 quitFriends,
30 removeVideoToFriends: removeVideoToFriends, 25 removeVideoToFriends,
31 sendOwnedVideosToPod: sendOwnedVideosToPod 26 sendOwnedVideosToPod
32} 27}
33 28
34function addVideoToFriends (video) { 29function addVideoToFriends (video) {
@@ -45,10 +40,10 @@ function hasFriends (callback) {
45} 40}
46 41
47function getMyCertificate (callback) { 42function getMyCertificate (callback) {
48 fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', callback) 43 fs.readFile(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.pub', 'utf8', callback)
49} 44}
50 45
51function makeFriends (callback) { 46function makeFriends (urls, callback) {
52 const podsScore = {} 47 const podsScore = {}
53 48
54 logger.info('Make friends!') 49 logger.info('Make friends!')
@@ -58,8 +53,6 @@ function makeFriends (callback) {
58 return callback(err) 53 return callback(err)
59 } 54 }
60 55
61 const urls = config.get('network.friends')
62
63 eachSeries(urls, function (url, callbackEach) { 56 eachSeries(urls, function (url, callbackEach) {
64 computeForeignPodsList(url, podsScore, callbackEach) 57 computeForeignPodsList(url, podsScore, callbackEach)
65 }, function (err) { 58 }, function (err) {
@@ -205,7 +198,12 @@ function getForeignPodsList (url, callback) {
205 request.get(url + path, function (err, response, body) { 198 request.get(url + path, function (err, response, body) {
206 if (err) return callback(err) 199 if (err) return callback(err)
207 200
208 callback(null, JSON.parse(body)) 201 try {
202 const json = JSON.parse(body)
203 return callback(null, json)
204 } catch (err) {
205 return callback(err)
206 }
209 }) 207 })
210} 208}
211 209
@@ -220,7 +218,7 @@ function makeRequestsToWinningPods (cert, podsList, callback) {
220 url: pod.url + '/api/' + constants.API_VERSION + '/pods/', 218 url: pod.url + '/api/' + constants.API_VERSION + '/pods/',
221 method: 'POST', 219 method: 'POST',
222 json: { 220 json: {
223 url: http + '://' + host + ':' + port, 221 url: constants.CONFIG.WEBSERVER.URL,
224 publicKey: cert 222 publicKey: cert
225 } 223 }
226 } 224 }
diff --git a/server/lib/oauth-model.js b/server/lib/oauth-model.js
index d9f8b175a..45f796796 100644
--- a/server/lib/oauth-model.js
+++ b/server/lib/oauth-model.js
@@ -8,12 +8,12 @@ const User = mongoose.model('User')
8 8
9// See https://github.com/oauthjs/node-oauth2-server/wiki/Model-specification for the model specifications 9// See https://github.com/oauthjs/node-oauth2-server/wiki/Model-specification for the model specifications
10const OAuthModel = { 10const OAuthModel = {
11 getAccessToken: getAccessToken, 11 getAccessToken,
12 getClient: getClient, 12 getClient,
13 getRefreshToken: getRefreshToken, 13 getRefreshToken,
14 getUser: getUser, 14 getUser,
15 revokeToken: revokeToken, 15 revokeToken,
16 saveToken: saveToken 16 saveToken
17} 17}
18 18
19// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
@@ -41,7 +41,22 @@ function getRefreshToken (refreshToken, callback) {
41function getUser (username, password) { 41function getUser (username, password) {
42 logger.debug('Getting User (username: ' + username + ', password: ' + password + ').') 42 logger.debug('Getting User (username: ' + username + ', password: ' + password + ').')
43 43
44 return User.getByUsernameAndPassword(username, password) 44 return User.getByUsername(username).then(function (user) {
45 if (!user) return null
46
47 // We need to return a promise
48 return new Promise(function (resolve, reject) {
49 return user.isPasswordMatch(password, function (err, isPasswordMatch) {
50 if (err) return reject(err)
51
52 if (isPasswordMatch === true) {
53 return resolve(user)
54 }
55
56 return resolve(null)
57 })
58 })
59 })
45} 60}
46 61
47function revokeToken (token) { 62function revokeToken (token) {
diff --git a/server/middlewares/admin.js b/server/middlewares/admin.js
new file mode 100644
index 000000000..e6d9dc887
--- /dev/null
+++ b/server/middlewares/admin.js
@@ -0,0 +1,22 @@
1'use strict'
2
3const constants = require('../initializers/constants')
4const logger = require('../helpers/logger')
5
6const adminMiddleware = {
7 ensureIsAdmin
8}
9
10function ensureIsAdmin (req, res, next) {
11 const user = res.locals.oauth.token.user
12 if (user.role !== constants.USER_ROLES.ADMIN) {
13 logger.info('A non admin user is trying to access to an admin content.')
14 return res.sendStatus(403)
15 }
16
17 return next()
18}
19
20// ---------------------------------------------------------------------------
21
22module.exports = adminMiddleware
diff --git a/server/middlewares/index.js b/server/middlewares/index.js
index 0a233e701..3f253e31b 100644
--- a/server/middlewares/index.js
+++ b/server/middlewares/index.js
@@ -1,19 +1,23 @@
1'use strict' 1'use strict'
2 2
3const oauth = require('./oauth') 3const adminMiddleware = require('./admin')
4const pagination = require('./pagination') 4const oauthMiddleware = require('./oauth')
5const paginationMiddleware = require('./pagination')
6const podsMiddleware = require('./pods')
5const validatorsMiddleware = require('./validators') 7const validatorsMiddleware = require('./validators')
6const search = require('./search') 8const searchMiddleware = require('./search')
7const sort = require('./sort') 9const sortMiddleware = require('./sort')
8const secureMiddleware = require('./secure') 10const secureMiddleware = require('./secure')
9 11
10const middlewares = { 12const middlewares = {
11 oauth: oauth, 13 admin: adminMiddleware,
12 pagination: pagination, 14 oauth: oauthMiddleware,
13 validators: validatorsMiddleware, 15 pagination: paginationMiddleware,
14 search: search, 16 pods: podsMiddleware,
15 sort: sort, 17 search: searchMiddleware,
16 secure: secureMiddleware 18 secure: secureMiddleware,
19 sort: sortMiddleware,
20 validators: validatorsMiddleware
17} 21}
18 22
19// --------------------------------------------------------------------------- 23// ---------------------------------------------------------------------------
diff --git a/server/middlewares/oauth.js b/server/middlewares/oauth.js
index 91a990509..3a02b9b48 100644
--- a/server/middlewares/oauth.js
+++ b/server/middlewares/oauth.js
@@ -12,8 +12,8 @@ const oAuthServer = new OAuthServer({
12}) 12})
13 13
14const oAuth = { 14const oAuth = {
15 authenticate: authenticate, 15 authenticate,
16 token: token 16 token
17} 17}
18 18
19function authenticate (req, res, next) { 19function authenticate (req, res, next) {
@@ -23,7 +23,7 @@ function authenticate (req, res, next) {
23 return res.sendStatus(500) 23 return res.sendStatus(500)
24 } 24 }
25 25
26 if (res.statusCode === 401 || res.statusCode === 400) return res.end() 26 if (res.statusCode === 401 || res.statusCode === 400 || res.statusCode === 503) return res.end()
27 27
28 return next() 28 return next()
29 }) 29 })
diff --git a/server/middlewares/pagination.js b/server/middlewares/pagination.js
index a571e51f6..a90f60aab 100644
--- a/server/middlewares/pagination.js
+++ b/server/middlewares/pagination.js
@@ -3,7 +3,7 @@
3const constants = require('../initializers/constants') 3const constants = require('../initializers/constants')
4 4
5const paginationMiddleware = { 5const paginationMiddleware = {
6 setPagination: setPagination 6 setPagination
7} 7}
8 8
9function setPagination (req, res, next) { 9function setPagination (req, res, next) {
diff --git a/server/middlewares/pods.js b/server/middlewares/pods.js
new file mode 100644
index 000000000..6e0874a76
--- /dev/null
+++ b/server/middlewares/pods.js
@@ -0,0 +1,62 @@
1'use strict'
2
3const urlModule = require('url')
4
5const logger = require('../helpers/logger')
6
7const podsMiddleware = {
8 setBodyUrlsPort,
9 setBodyUrlPort
10}
11
12function setBodyUrlsPort (req, res, next) {
13 for (let i = 0; i < req.body.urls.length; i++) {
14 const urlWithPort = getUrlWithPort(req.body.urls[i])
15
16 // Problem with the url parsing?
17 if (urlWithPort === null) {
18 return res.sendStatus(500)
19 }
20
21 req.body.urls[i] = urlWithPort
22 }
23
24 return next()
25}
26
27function setBodyUrlPort (req, res, next) {
28 const urlWithPort = getUrlWithPort(req.body.url)
29
30 // Problem with the url parsing?
31 if (urlWithPort === null) {
32 return res.sendStatus(500)
33 }
34
35 req.body.url = urlWithPort
36
37 return next()
38}
39
40// ---------------------------------------------------------------------------
41
42module.exports = podsMiddleware
43
44// ---------------------------------------------------------------------------
45
46function getUrlWithPort (url) {
47 const urlObj = urlModule.parse(url)
48
49 // Add the port if it is not specified
50 if (urlObj.port === null) {
51 if (urlObj.protocol === 'http:') {
52 return url + ':80'
53 } else if (urlObj.protocol === 'https:') {
54 return url + ':443'
55 } else {
56 logger.error('Unknown url protocol: ' + urlObj.protocol)
57 return null
58 }
59 }
60
61 return url
62}
diff --git a/server/middlewares/search.js b/server/middlewares/search.js
index 89302a564..bb88faf54 100644
--- a/server/middlewares/search.js
+++ b/server/middlewares/search.js
@@ -1,7 +1,7 @@
1'use strict' 1'use strict'
2 2
3const searchMiddleware = { 3const searchMiddleware = {
4 setVideosSearch: setVideosSearch 4 setVideosSearch
5} 5}
6 6
7function setVideosSearch (req, res, next) { 7function setVideosSearch (req, res, next) {
diff --git a/server/middlewares/secure.js b/server/middlewares/secure.js
index 9779c14ac..58f824d14 100644
--- a/server/middlewares/secure.js
+++ b/server/middlewares/secure.js
@@ -7,10 +7,11 @@ const peertubeCrypto = require('../helpers/peertube-crypto')
7const Pod = mongoose.model('Pod') 7const Pod = mongoose.model('Pod')
8 8
9const secureMiddleware = { 9const secureMiddleware = {
10 decryptBody: decryptBody 10 checkSignature,
11 decryptBody
11} 12}
12 13
13function decryptBody (req, res, next) { 14function checkSignature (req, res, next) {
14 const url = req.body.signature.url 15 const url = req.body.signature.url
15 Pod.loadByUrl(url, function (err, pod) { 16 Pod.loadByUrl(url, function (err, pod) {
16 if (err) { 17 if (err) {
@@ -28,21 +29,30 @@ function decryptBody (req, res, next) {
28 const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, url, req.body.signature.signature) 29 const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, url, req.body.signature.signature)
29 30
30 if (signatureOk === true) { 31 if (signatureOk === true) {
31 peertubeCrypto.decrypt(req.body.key, req.body.data, function (err, decrypted) { 32 return next()
32 if (err) { 33 }
33 logger.error('Cannot decrypt data.', { error: err }) 34
34 return res.sendStatus(500) 35 logger.error('Signature is not okay in decryptBody for %s.', req.body.signature.url)
35 } 36 return res.sendStatus(403)
36 37 })
37 req.body.data = JSON.parse(decrypted) 38}
38 delete req.body.key 39
39 40function decryptBody (req, res, next) {
40 next() 41 peertubeCrypto.decrypt(req.body.key, req.body.data, function (err, decrypted) {
41 }) 42 if (err) {
42 } else { 43 logger.error('Cannot decrypt data.', { error: err })
43 logger.error('Signature is not okay in decryptBody for %s.', req.body.signature.url) 44 return res.sendStatus(500)
44 return res.sendStatus(403)
45 } 45 }
46
47 try {
48 req.body.data = JSON.parse(decrypted)
49 delete req.body.key
50 } catch (err) {
51 logger.error('Error in JSON.parse', { error: err })
52 return res.sendStatus(500)
53 }
54
55 next()
46 }) 56 })
47} 57}
48 58
diff --git a/server/middlewares/sort.js b/server/middlewares/sort.js
index 9f52290a6..f0b7274eb 100644
--- a/server/middlewares/sort.js
+++ b/server/middlewares/sort.js
@@ -1,7 +1,14 @@
1'use strict' 1'use strict'
2 2
3const sortMiddleware = { 3const sortMiddleware = {
4 setVideosSort: setVideosSort 4 setUsersSort,
5 setVideosSort
6}
7
8function setUsersSort (req, res, next) {
9 if (!req.query.sort) req.query.sort = '-createdDate'
10
11 return next()
5} 12}
6 13
7function setVideosSort (req, res, next) { 14function setVideosSort (req, res, next) {
diff --git a/server/middlewares/validators/index.js b/server/middlewares/validators/index.js
index 0471b3f92..6c3a9c2b4 100644
--- a/server/middlewares/validators/index.js
+++ b/server/middlewares/validators/index.js
@@ -4,6 +4,7 @@ const paginationValidators = require('./pagination')
4const podsValidators = require('./pods') 4const podsValidators = require('./pods')
5const remoteValidators = require('./remote') 5const remoteValidators = require('./remote')
6const sortValidators = require('./sort') 6const sortValidators = require('./sort')
7const usersValidators = require('./users')
7const videosValidators = require('./videos') 8const videosValidators = require('./videos')
8 9
9const validators = { 10const validators = {
@@ -11,6 +12,7 @@ const validators = {
11 pods: podsValidators, 12 pods: podsValidators,
12 remote: remoteValidators, 13 remote: remoteValidators,
13 sort: sortValidators, 14 sort: sortValidators,
15 users: usersValidators,
14 videos: videosValidators 16 videos: videosValidators
15} 17}
16 18
diff --git a/server/middlewares/validators/pagination.js b/server/middlewares/validators/pagination.js
index 8e9a01053..16682696e 100644
--- a/server/middlewares/validators/pagination.js
+++ b/server/middlewares/validators/pagination.js
@@ -4,7 +4,7 @@ const checkErrors = require('./utils').checkErrors
4const logger = require('../../helpers/logger') 4const logger = require('../../helpers/logger')
5 5
6const validatorsPagination = { 6const validatorsPagination = {
7 pagination: pagination 7 pagination
8} 8}
9 9
10function pagination (req, res, next) { 10function pagination (req, res, next) {
diff --git a/server/middlewares/validators/pods.js b/server/middlewares/validators/pods.js
index fda2e865f..fd3d1e2f2 100644
--- a/server/middlewares/validators/pods.js
+++ b/server/middlewares/validators/pods.js
@@ -5,23 +5,29 @@ const friends = require('../../lib/friends')
5const logger = require('../../helpers/logger') 5const logger = require('../../helpers/logger')
6 6
7const validatorsPod = { 7const validatorsPod = {
8 makeFriends: makeFriends, 8 makeFriends,
9 podsAdd: podsAdd 9 podsAdd
10} 10}
11 11
12function makeFriends (req, res, next) { 12function makeFriends (req, res, next) {
13 friends.hasFriends(function (err, hasFriends) { 13 req.checkBody('urls', 'Should have an array of unique urls').isEachUniqueUrlValid()
14 if (err) { 14
15 logger.error('Cannot know if we have friends.', { error: err }) 15 logger.debug('Checking makeFriends parameters', { parameters: req.body })
16 res.sendStatus(500) 16
17 } 17 checkErrors(req, res, function () {
18 18 friends.hasFriends(function (err, hasFriends) {
19 if (hasFriends === true) { 19 if (err) {
20 // We need to quit our friends before make new ones 20 logger.error('Cannot know if we have friends.', { error: err })
21 res.sendStatus(409) 21 res.sendStatus(500)
22 } else { 22 }
23 return next() 23
24 } 24 if (hasFriends === true) {
25 // We need to quit our friends before make new ones
26 res.sendStatus(409)
27 } else {
28 return next()
29 }
30 })
25 }) 31 })
26} 32}
27 33
diff --git a/server/middlewares/validators/remote.js b/server/middlewares/validators/remote.js
index 1be119458..8c29ef8ca 100644
--- a/server/middlewares/validators/remote.js
+++ b/server/middlewares/validators/remote.js
@@ -4,9 +4,9 @@ const checkErrors = require('./utils').checkErrors
4const logger = require('../../helpers/logger') 4const logger = require('../../helpers/logger')
5 5
6const validatorsRemote = { 6const validatorsRemote = {
7 dataToDecrypt: dataToDecrypt, 7 dataToDecrypt,
8 remoteVideos: remoteVideos, 8 remoteVideos,
9 signature: signature 9 signature
10} 10}
11 11
12function dataToDecrypt (req, res, next) { 12function dataToDecrypt (req, res, next) {
@@ -19,7 +19,6 @@ function dataToDecrypt (req, res, next) {
19} 19}
20 20
21function remoteVideos (req, res, next) { 21function remoteVideos (req, res, next) {
22 req.checkBody('data').isArray()
23 req.checkBody('data').isEachRemoteVideosValid() 22 req.checkBody('data').isEachRemoteVideosValid()
24 23
25 logger.debug('Checking remoteVideos parameters', { parameters: req.body }) 24 logger.debug('Checking remoteVideos parameters', { parameters: req.body })
diff --git a/server/middlewares/validators/sort.js b/server/middlewares/validators/sort.js
index 56b63cc8b..431d3fffd 100644
--- a/server/middlewares/validators/sort.js
+++ b/server/middlewares/validators/sort.js
@@ -5,7 +5,18 @@ const constants = require('../../initializers/constants')
5const logger = require('../../helpers/logger') 5const logger = require('../../helpers/logger')
6 6
7const validatorsSort = { 7const validatorsSort = {
8 videosSort: videosSort 8 usersSort,
9 videosSort
10}
11
12function usersSort (req, res, next) {
13 const sortableColumns = constants.SORTABLE_COLUMNS.USERS
14
15 req.checkQuery('sort', 'Should have correct sortable column').optional().isIn(sortableColumns)
16
17 logger.debug('Checking sort parameters', { parameters: req.query })
18
19 checkErrors(req, res, next)
9} 20}
10 21
11function videosSort (req, res, next) { 22function videosSort (req, res, next) {
diff --git a/server/middlewares/validators/users.js b/server/middlewares/validators/users.js
new file mode 100644
index 000000000..d541e9124
--- /dev/null
+++ b/server/middlewares/validators/users.js
@@ -0,0 +1,67 @@
1'use strict'
2
3const mongoose = require('mongoose')
4
5const checkErrors = require('./utils').checkErrors
6const logger = require('../../helpers/logger')
7
8const User = mongoose.model('User')
9
10const validatorsUsers = {
11 usersAdd,
12 usersRemove,
13 usersUpdate
14}
15
16function usersAdd (req, res, next) {
17 req.checkBody('username', 'Should have a valid username').isUserUsernameValid()
18 req.checkBody('password', 'Should have a valid password').isUserPasswordValid()
19
20 logger.debug('Checking usersAdd parameters', { parameters: req.body })
21
22 checkErrors(req, res, function () {
23 User.loadByUsername(req.body.username, function (err, user) {
24 if (err) {
25 logger.error('Error in usersAdd request validator.', { error: err })
26 return res.sendStatus(500)
27 }
28
29 if (user) return res.status(409).send('User already exists.')
30
31 next()
32 })
33 })
34}
35
36function usersRemove (req, res, next) {
37 req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId()
38
39 logger.debug('Checking usersRemove parameters', { parameters: req.params })
40
41 checkErrors(req, res, function () {
42 User.loadById(req.params.id, function (err, user) {
43 if (err) {
44 logger.error('Error in usersRemove request validator.', { error: err })
45 return res.sendStatus(500)
46 }
47
48 if (!user) return res.status(404).send('User not found')
49
50 next()
51 })
52 })
53}
54
55function usersUpdate (req, res, next) {
56 req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId()
57 // Add old password verification
58 req.checkBody('password', 'Should have a valid password').isUserPasswordValid()
59
60 logger.debug('Checking usersUpdate parameters', { parameters: req.body })
61
62 checkErrors(req, res, next)
63}
64
65// ---------------------------------------------------------------------------
66
67module.exports = validatorsUsers
diff --git a/server/middlewares/validators/utils.js b/server/middlewares/validators/utils.js
index f6e5b2b38..3741b84c6 100644
--- a/server/middlewares/validators/utils.js
+++ b/server/middlewares/validators/utils.js
@@ -5,7 +5,7 @@ const util = require('util')
5const logger = require('../../helpers/logger') 5const logger = require('../../helpers/logger')
6 6
7const validatorsUtils = { 7const validatorsUtils = {
8 checkErrors: checkErrors 8 checkErrors
9} 9}
10 10
11function checkErrors (req, res, next, statusCode) { 11function checkErrors (req, res, next, statusCode) {
diff --git a/server/middlewares/validators/videos.js b/server/middlewares/validators/videos.js
index 3e2af06fb..76e943e77 100644
--- a/server/middlewares/validators/videos.js
+++ b/server/middlewares/validators/videos.js
@@ -4,20 +4,21 @@ const mongoose = require('mongoose')
4 4
5const checkErrors = require('./utils').checkErrors 5const checkErrors = require('./utils').checkErrors
6const constants = require('../../initializers/constants') 6const constants = require('../../initializers/constants')
7const customValidators = require('../../helpers/custom-validators') 7const customVideosValidators = require('../../helpers/custom-validators').videos
8const logger = require('../../helpers/logger') 8const logger = require('../../helpers/logger')
9 9
10const Video = mongoose.model('Video') 10const Video = mongoose.model('Video')
11 11
12const validatorsVideos = { 12const validatorsVideos = {
13 videosAdd: videosAdd, 13 videosAdd,
14 videosGet: videosGet, 14 videosGet,
15 videosRemove: videosRemove, 15 videosRemove,
16 videosSearch: videosSearch 16 videosSearch
17} 17}
18 18
19function videosAdd (req, res, next) { 19function videosAdd (req, res, next) {
20 req.checkFiles('videofile[0].originalname', 'Should have an input video').notEmpty() 20 req.checkFiles('videofile[0].originalname', 'Should have an input video').notEmpty()
21 // TODO: move to constants and function
21 req.checkFiles('videofile[0].mimetype', 'Should have a correct mime type').matches(/video\/(webm)|(mp4)|(ogg)/i) 22 req.checkFiles('videofile[0].mimetype', 'Should have a correct mime type').matches(/video\/(webm)|(mp4)|(ogg)/i)
22 req.checkBody('name', 'Should have a valid name').isVideoNameValid() 23 req.checkBody('name', 'Should have a valid name').isVideoNameValid()
23 req.checkBody('description', 'Should have a valid description').isVideoDescriptionValid() 24 req.checkBody('description', 'Should have a valid description').isVideoDescriptionValid()
@@ -33,8 +34,8 @@ function videosAdd (req, res, next) {
33 return res.status(400).send('Cannot retrieve metadata of the file.') 34 return res.status(400).send('Cannot retrieve metadata of the file.')
34 } 35 }
35 36
36 if (!customValidators.isVideoDurationValid(duration)) { 37 if (!customVideosValidators.isVideoDurationValid(duration)) {
37 return res.status(400).send('Duration of the video file is too big (max: ' + constants.VIDEOS_CONSTRAINTS_FIELDS.DURATION.max + 's).') 38 return res.status(400).send('Duration of the video file is too big (max: ' + constants.CONSTRAINTS_FIELDS.VIDEOS.DURATION.max + 's).')
38 } 39 }
39 40
40 videoFile.duration = duration 41 videoFile.duration = duration
@@ -76,6 +77,7 @@ function videosRemove (req, res, next) {
76 77
77 if (!video) return res.status(404).send('Video not found') 78 if (!video) return res.status(404).send('Video not found')
78 else if (video.isOwned() === false) return res.status(403).send('Cannot remove video of another pod') 79 else if (video.isOwned() === false) return res.status(403).send('Cannot remove video of another pod')
80 else if (video.author !== res.locals.oauth.token.user.username) return res.status(403).send('Cannot remove video of another user')
79 81
80 next() 82 next()
81 }) 83 })
diff --git a/server/models/application.js b/server/models/application.js
new file mode 100644
index 000000000..452ac4283
--- /dev/null
+++ b/server/models/application.js
@@ -0,0 +1,31 @@
1const mongoose = require('mongoose')
2
3// ---------------------------------------------------------------------------
4
5const ApplicationSchema = mongoose.Schema({
6 mongoSchemaVersion: {
7 type: Number,
8 default: 0
9 }
10})
11
12ApplicationSchema.statics = {
13 loadMongoSchemaVersion,
14 updateMongoSchemaVersion
15}
16
17mongoose.model('Application', ApplicationSchema)
18
19// ---------------------------------------------------------------------------
20
21function loadMongoSchemaVersion (callback) {
22 return this.findOne({}, { mongoSchemaVersion: 1 }, function (err, data) {
23 const version = data ? data.mongoSchemaVersion : 0
24
25 return callback(err, version)
26 })
27}
28
29function updateMongoSchemaVersion (newVersion, callback) {
30 return this.update({}, { mongoSchemaVersion: newVersion }, callback)
31}
diff --git a/server/models/oauth-client.js b/server/models/oauth-client.js
index 45834c5a5..a1aefa985 100644
--- a/server/models/oauth-client.js
+++ b/server/models/oauth-client.js
@@ -11,9 +11,9 @@ const OAuthClientSchema = mongoose.Schema({
11OAuthClientSchema.path('clientSecret').required(true) 11OAuthClientSchema.path('clientSecret').required(true)
12 12
13OAuthClientSchema.statics = { 13OAuthClientSchema.statics = {
14 getByIdAndSecret: getByIdAndSecret, 14 getByIdAndSecret,
15 list: list, 15 list,
16 loadFirstClient: loadFirstClient 16 loadFirstClient
17} 17}
18 18
19mongoose.model('OAuthClient', OAuthClientSchema) 19mongoose.model('OAuthClient', OAuthClientSchema)
diff --git a/server/models/oauth-token.js b/server/models/oauth-token.js
index f6a814c36..5beb47bed 100644
--- a/server/models/oauth-token.js
+++ b/server/models/oauth-token.js
@@ -18,9 +18,10 @@ OAuthTokenSchema.path('client').required(true)
18OAuthTokenSchema.path('user').required(true) 18OAuthTokenSchema.path('user').required(true)
19 19
20OAuthTokenSchema.statics = { 20OAuthTokenSchema.statics = {
21 getByRefreshTokenAndPopulateClient: getByRefreshTokenAndPopulateClient, 21 getByRefreshTokenAndPopulateClient,
22 getByTokenAndPopulateUser: getByTokenAndPopulateUser, 22 getByTokenAndPopulateUser,
23 getByRefreshToken: getByRefreshToken 23 getByRefreshToken,
24 removeByUserId
24} 25}
25 26
26mongoose.model('OAuthToken', OAuthTokenSchema) 27mongoose.model('OAuthToken', OAuthTokenSchema)
@@ -53,3 +54,7 @@ function getByTokenAndPopulateUser (bearerToken) {
53function getByRefreshToken (refreshToken) { 54function getByRefreshToken (refreshToken) {
54 return this.findOne({ refreshToken: refreshToken }).exec() 55 return this.findOne({ refreshToken: refreshToken }).exec()
55} 56}
57
58function removeByUserId (userId, callback) {
59 return this.remove({ user: userId }, callback)
60}
diff --git a/server/models/pods.js b/server/models/pods.js
index bf43d7b25..4020a9603 100644
--- a/server/models/pods.js
+++ b/server/models/pods.js
@@ -11,7 +11,11 @@ const constants = require('../initializers/constants')
11const PodSchema = mongoose.Schema({ 11const PodSchema = mongoose.Schema({
12 url: String, 12 url: String,
13 publicKey: String, 13 publicKey: String,
14 score: { type: Number, max: constants.FRIEND_SCORE.MAX } 14 score: { type: Number, max: constants.FRIEND_SCORE.MAX },
15 createdDate: {
16 type: Date,
17 default: Date.now
18 }
15}) 19})
16 20
17// TODO: set options (TLD...) 21// TODO: set options (TLD...)
@@ -19,16 +23,19 @@ PodSchema.path('url').validate(validator.isURL)
19PodSchema.path('publicKey').required(true) 23PodSchema.path('publicKey').required(true)
20PodSchema.path('score').validate(function (value) { return !isNaN(value) }) 24PodSchema.path('score').validate(function (value) { return !isNaN(value) })
21 25
26PodSchema.methods = {
27 toFormatedJSON
28}
29
22PodSchema.statics = { 30PodSchema.statics = {
23 countAll: countAll, 31 countAll,
24 incrementScores: incrementScores, 32 incrementScores,
25 list: list, 33 list,
26 listAllIds: listAllIds, 34 listAllIds,
27 listOnlyUrls: listOnlyUrls, 35 listBadPods,
28 listBadPods: listBadPods, 36 load,
29 load: load, 37 loadByUrl,
30 loadByUrl: loadByUrl, 38 removeAll
31 removeAll: removeAll
32} 39}
33 40
34PodSchema.pre('save', function (next) { 41PodSchema.pre('save', function (next) {
@@ -46,6 +53,19 @@ PodSchema.pre('save', function (next) {
46 53
47const Pod = mongoose.model('Pod', PodSchema) 54const Pod = mongoose.model('Pod', PodSchema)
48 55
56// ------------------------------ METHODS ------------------------------
57
58function toFormatedJSON () {
59 const json = {
60 id: this._id,
61 url: this.url,
62 score: this.score,
63 createdDate: this.createdDate
64 }
65
66 return json
67}
68
49// ------------------------------ Statics ------------------------------ 69// ------------------------------ Statics ------------------------------
50 70
51function countAll (callback) { 71function countAll (callback) {
@@ -69,10 +89,6 @@ function listAllIds (callback) {
69 }) 89 })
70} 90}
71 91
72function listOnlyUrls (callback) {
73 return this.find({}, { _id: 0, url: 1 }, callback)
74}
75
76function listBadPods (callback) { 92function listBadPods (callback) {
77 return this.find({ score: 0 }, callback) 93 return this.find({ score: 0 }, callback)
78} 94}
diff --git a/server/models/request.js b/server/models/request.js
index 4d521919a..2d1c5af15 100644
--- a/server/models/request.js
+++ b/server/models/request.js
@@ -14,19 +14,22 @@ const Pod = mongoose.model('Pod')
14const Video = mongoose.model('Video') 14const Video = mongoose.model('Video')
15 15
16let timer = null 16let timer = null
17let lastRequestTimestamp = 0
17 18
18// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
19 20
20const RequestSchema = mongoose.Schema({ 21const RequestSchema = mongoose.Schema({
21 request: mongoose.Schema.Types.Mixed, 22 request: mongoose.Schema.Types.Mixed,
22 to: [ { type: mongoose.Schema.Types.ObjectId, ref: 'users' } ] 23 to: [ { type: mongoose.Schema.Types.ObjectId, ref: 'Pod' } ]
23}) 24})
24 25
25RequestSchema.statics = { 26RequestSchema.statics = {
26 activate, 27 activate,
27 deactivate, 28 deactivate,
28 flush, 29 flush,
29 forceSend 30 forceSend,
31 list,
32 remainingMilliSeconds
30} 33}
31 34
32RequestSchema.pre('save', function (next) { 35RequestSchema.pre('save', function (next) {
@@ -53,12 +56,19 @@ mongoose.model('Request', RequestSchema)
53 56
54function activate () { 57function activate () {
55 logger.info('Requests scheduler activated.') 58 logger.info('Requests scheduler activated.')
56 timer = setInterval(makeRequests.bind(this), constants.INTERVAL) 59 lastRequestTimestamp = Date.now()
60
61 const self = this
62 timer = setInterval(function () {
63 lastRequestTimestamp = Date.now()
64 makeRequests.call(self)
65 }, constants.REQUESTS_INTERVAL)
57} 66}
58 67
59function deactivate () { 68function deactivate () {
60 logger.info('Requests scheduler deactivated.') 69 logger.info('Requests scheduler deactivated.')
61 clearInterval(timer) 70 clearInterval(timer)
71 timer = null
62} 72}
63 73
64function flush () { 74function flush () {
@@ -72,6 +82,16 @@ function forceSend () {
72 makeRequests.call(this) 82 makeRequests.call(this)
73} 83}
74 84
85function list (callback) {
86 this.find({ }, callback)
87}
88
89function remainingMilliSeconds () {
90 if (timer === null) return -1
91
92 return constants.REQUESTS_INTERVAL - (Date.now() - lastRequestTimestamp)
93}
94
75// --------------------------------------------------------------------------- 95// ---------------------------------------------------------------------------
76 96
77// Make a requests to friends of a certain type 97// Make a requests to friends of a certain type
@@ -91,7 +111,13 @@ function makeRequest (toPod, requestsToMake, callback) {
91 // The function fire some useful callbacks 111 // The function fire some useful callbacks
92 requests.makeSecureRequest(params, function (err, res) { 112 requests.makeSecureRequest(params, function (err, res) {
93 if (err || (res.statusCode !== 200 && res.statusCode !== 201 && res.statusCode !== 204)) { 113 if (err || (res.statusCode !== 200 && res.statusCode !== 201 && res.statusCode !== 204)) {
94 logger.error('Error sending secure request to %s pod.', toPod.url, { error: err || new Error('Status code not 20x') }) 114 logger.error(
115 'Error sending secure request to %s pod.',
116 toPod.url,
117 {
118 error: err || new Error('Status code not 20x : ' + res.statusCode)
119 }
120 )
95 121
96 return callback(false) 122 return callback(false)
97 } 123 }
@@ -148,19 +174,14 @@ function makeRequests () {
148 return callbackEach() 174 return callbackEach()
149 } 175 }
150 176
151 // Maybe the pod is not our friend anymore so simply remove them 177 // Maybe the pod is not our friend anymore so simply remove it
152 if (!toPod) { 178 if (!toPod) {
179 logger.info('Removing %d requests of unexisting pod %s.', requestToMake.ids.length, toPodId)
153 removePodOf.call(self, requestToMake.ids, toPodId) 180 removePodOf.call(self, requestToMake.ids, toPodId)
154 return callbackEach() 181 return callbackEach()
155 } 182 }
156 183
157 makeRequest(toPod, requestToMake.datas, function (success) { 184 makeRequest(toPod, requestToMake.datas, function (success) {
158 if (err) {
159 logger.error('Errors when sent request to %s.', toPod.url, { error: err })
160 // Do not stop the process just for one error
161 return callbackEach()
162 }
163
164 if (success === true) { 185 if (success === true) {
165 logger.debug('Removing requests for %s pod.', toPodId, { requestsIds: requestToMake.ids }) 186 logger.debug('Removing requests for %s pod.', toPodId, { requestsIds: requestToMake.ids })
166 187
diff --git a/server/models/user.js b/server/models/user.js
index 14ffecbff..a19de7072 100644
--- a/server/models/user.js
+++ b/server/models/user.js
@@ -1,28 +1,98 @@
1const mongoose = require('mongoose') 1const mongoose = require('mongoose')
2 2
3const customUsersValidators = require('../helpers/custom-validators').users
4const modelUtils = require('./utils')
5const peertubeCrypto = require('../helpers/peertube-crypto')
6
7const OAuthToken = mongoose.model('OAuthToken')
8
3// --------------------------------------------------------------------------- 9// ---------------------------------------------------------------------------
4 10
5const UserSchema = mongoose.Schema({ 11const UserSchema = mongoose.Schema({
12 createdDate: {
13 type: Date,
14 default: Date.now
15 },
6 password: String, 16 password: String,
7 username: String 17 username: String,
18 role: String
8}) 19})
9 20
10UserSchema.path('password').required(true) 21UserSchema.path('password').required(customUsersValidators.isUserPasswordValid)
11UserSchema.path('username').required(true) 22UserSchema.path('username').required(customUsersValidators.isUserUsernameValid)
23UserSchema.path('role').validate(customUsersValidators.isUserRoleValid)
24
25UserSchema.methods = {
26 isPasswordMatch,
27 toFormatedJSON
28}
12 29
13UserSchema.statics = { 30UserSchema.statics = {
14 getByUsernameAndPassword: getByUsernameAndPassword, 31 countTotal,
15 list: list 32 getByUsername,
33 list,
34 listForApi,
35 loadById,
36 loadByUsername
16} 37}
17 38
39UserSchema.pre('save', function (next) {
40 const user = this
41
42 peertubeCrypto.cryptPassword(this.password, function (err, hash) {
43 if (err) return next(err)
44
45 user.password = hash
46
47 return next()
48 })
49})
50
51UserSchema.pre('remove', function (next) {
52 const user = this
53
54 OAuthToken.removeByUserId(user._id, next)
55})
56
18mongoose.model('User', UserSchema) 57mongoose.model('User', UserSchema)
19 58
20// --------------------------------------------------------------------------- 59// ------------------------------ METHODS ------------------------------
60
61function isPasswordMatch (password, callback) {
62 return peertubeCrypto.comparePassword(password, this.password, callback)
63}
64
65function toFormatedJSON () {
66 return {
67 id: this._id,
68 username: this.username,
69 role: this.role,
70 createdDate: this.createdDate
71 }
72}
73// ------------------------------ STATICS ------------------------------
74
75function countTotal (callback) {
76 return this.count(callback)
77}
78
79function getByUsername (username) {
80 return this.findOne({ username: username })
81}
21 82
22function list (callback) { 83function list (callback) {
23 return this.find(callback) 84 return this.find(callback)
24} 85}
25 86
26function getByUsernameAndPassword (username, password) { 87function listForApi (start, count, sort, callback) {
27 return this.findOne({ username: username, password: password }) 88 const query = {}
89 return modelUtils.listForApiWithCount.call(this, query, start, count, sort, callback)
90}
91
92function loadById (id, callback) {
93 return this.findById(id, callback)
94}
95
96function loadByUsername (username, callback) {
97 return this.findOne({ username: username }, callback)
28} 98}
diff --git a/server/models/utils.js b/server/models/utils.js
new file mode 100644
index 000000000..e798aabe6
--- /dev/null
+++ b/server/models/utils.js
@@ -0,0 +1,30 @@
1'use strict'
2
3const parallel = require('async/parallel')
4
5const utils = {
6 listForApiWithCount
7}
8
9function listForApiWithCount (query, start, count, sort, callback) {
10 const self = this
11
12 parallel([
13 function (asyncCallback) {
14 self.find(query).skip(start).limit(count).sort(sort).exec(asyncCallback)
15 },
16 function (asyncCallback) {
17 self.count(query, asyncCallback)
18 }
19 ], function (err, results) {
20 if (err) return callback(err)
21
22 const data = results[0]
23 const total = results[1]
24 return callback(null, data, total)
25 })
26}
27
28// ---------------------------------------------------------------------------
29
30module.exports = utils
diff --git a/server/models/video.js b/server/models/video.js
index 14e0df6f2..7d073cffa 100644
--- a/server/models/video.js
+++ b/server/models/video.js
@@ -11,8 +11,9 @@ const magnet = require('magnet-uri')
11const mongoose = require('mongoose') 11const mongoose = require('mongoose')
12 12
13const constants = require('../initializers/constants') 13const constants = require('../initializers/constants')
14const customValidators = require('../helpers/custom-validators') 14const customVideosValidators = require('../helpers/custom-validators').videos
15const logger = require('../helpers/logger') 15const logger = require('../helpers/logger')
16const modelUtils = require('./utils')
16const utils = require('../helpers/utils') 17const utils = require('../helpers/utils')
17 18
18const http = config.get('webserver.https') === true ? 'https' : 'http' 19const http = config.get('webserver.https') === true ? 'https' : 'http'
@@ -42,34 +43,35 @@ const VideoSchema = mongoose.Schema({
42 } 43 }
43}) 44})
44 45
45VideoSchema.path('name').validate(customValidators.isVideoNameValid) 46VideoSchema.path('name').validate(customVideosValidators.isVideoNameValid)
46VideoSchema.path('description').validate(customValidators.isVideoDescriptionValid) 47VideoSchema.path('description').validate(customVideosValidators.isVideoDescriptionValid)
47VideoSchema.path('magnetUri').validate(customValidators.isVideoMagnetUriValid) 48VideoSchema.path('magnetUri').validate(customVideosValidators.isVideoMagnetUriValid)
48VideoSchema.path('podUrl').validate(customValidators.isVideoPodUrlValid) 49VideoSchema.path('podUrl').validate(customVideosValidators.isVideoPodUrlValid)
49VideoSchema.path('author').validate(customValidators.isVideoAuthorValid) 50VideoSchema.path('author').validate(customVideosValidators.isVideoAuthorValid)
50VideoSchema.path('duration').validate(customValidators.isVideoDurationValid) 51VideoSchema.path('duration').validate(customVideosValidators.isVideoDurationValid)
51// The tumbnail can be the path or the data in base 64 52// The tumbnail can be the path or the data in base 64
52// The pre save hook will convert the base 64 data in a file on disk and replace the thumbnail key by the filename 53// The pre save hook will convert the base 64 data in a file on disk and replace the thumbnail key by the filename
53VideoSchema.path('thumbnail').validate(function (value) { 54VideoSchema.path('thumbnail').validate(function (value) {
54 return customValidators.isVideoThumbnailValid(value) || customValidators.isVideoThumbnail64Valid(value) 55 return customVideosValidators.isVideoThumbnailValid(value) || customVideosValidators.isVideoThumbnail64Valid(value)
55}) 56})
56VideoSchema.path('tags').validate(customValidators.isVideoTagsValid) 57VideoSchema.path('tags').validate(customVideosValidators.isVideoTagsValid)
57 58
58VideoSchema.methods = { 59VideoSchema.methods = {
59 isOwned: isOwned, 60 isOwned,
60 toFormatedJSON: toFormatedJSON, 61 toFormatedJSON,
61 toRemoteJSON: toRemoteJSON 62 toRemoteJSON
62} 63}
63 64
64VideoSchema.statics = { 65VideoSchema.statics = {
65 getDurationFromFile: getDurationFromFile, 66 getDurationFromFile,
66 list: list, 67 listForApi,
67 listByUrlAndMagnet: listByUrlAndMagnet, 68 listByUrlAndMagnet,
68 listByUrls: listByUrls, 69 listByUrls,
69 listOwned: listOwned, 70 listOwned,
70 listRemotes: listRemotes, 71 listOwnedByAuthor,
71 load: load, 72 listRemotes,
72 search: search 73 load,
74 search
73} 75}
74 76
75VideoSchema.pre('remove', function (next) { 77VideoSchema.pre('remove', function (next) {
@@ -101,8 +103,8 @@ VideoSchema.pre('save', function (next) {
101 const tasks = [] 103 const tasks = []
102 104
103 if (video.isOwned()) { 105 if (video.isOwned()) {
104 const videoPath = pathUtils.join(uploadsDir, video.filename) 106 const videoPath = pathUtils.join(constants.CONFIG.STORAGE.UPLOAD_DIR, video.filename)
105 this.podUrl = http + '://' + host + ':' + port 107 this.podUrl = constants.CONFIG.WEBSERVER.URL
106 108
107 tasks.push( 109 tasks.push(
108 // TODO: refractoring 110 // TODO: refractoring
@@ -174,7 +176,7 @@ function toRemoteJSON (callback) {
174 const self = this 176 const self = this
175 177
176 // Convert thumbnail to base64 178 // Convert thumbnail to base64
177 fs.readFile(pathUtils.join(thumbnailsDir, this.thumbnail), function (err, thumbnailData) { 179 fs.readFile(pathUtils.join(constants.CONFIG.STORAGE.THUMBNAILS_DIR, this.thumbnail), function (err, thumbnailData) {
178 if (err) { 180 if (err) {
179 logger.error('Cannot read the thumbnail of the video') 181 logger.error('Cannot read the thumbnail of the video')
180 return callback(err) 182 return callback(err)
@@ -207,9 +209,9 @@ function getDurationFromFile (videoPath, callback) {
207 }) 209 })
208} 210}
209 211
210function list (start, count, sort, callback) { 212function listForApi (start, count, sort, callback) {
211 const query = {} 213 const query = {}
212 return findWithCount.call(this, query, start, count, sort, callback) 214 return modelUtils.listForApiWithCount.call(this, query, start, count, sort, callback)
213} 215}
214 216
215function listByUrlAndMagnet (fromUrl, magnetUri, callback) { 217function listByUrlAndMagnet (fromUrl, magnetUri, callback) {
@@ -225,6 +227,10 @@ function listOwned (callback) {
225 this.find({ filename: { $ne: null } }, callback) 227 this.find({ filename: { $ne: null } }, callback)
226} 228}
227 229
230function listOwnedByAuthor (author, callback) {
231 this.find({ filename: { $ne: null }, author: author }, callback)
232}
233
228function listRemotes (callback) { 234function listRemotes (callback) {
229 this.find({ filename: null }, callback) 235 this.find({ filename: null }, callback)
230} 236}
@@ -242,36 +248,17 @@ function search (value, field, start, count, sort, callback) {
242 query[field] = new RegExp(value) 248 query[field] = new RegExp(value)
243 } 249 }
244 250
245 findWithCount.call(this, query, start, count, sort, callback) 251 modelUtils.listForApiWithCount.call(this, query, start, count, sort, callback)
246} 252}
247 253
248// --------------------------------------------------------------------------- 254// ---------------------------------------------------------------------------
249 255
250function findWithCount (query, start, count, sort, callback) {
251 const self = this
252
253 parallel([
254 function (asyncCallback) {
255 self.find(query).skip(start).limit(count).sort(sort).exec(asyncCallback)
256 },
257 function (asyncCallback) {
258 self.count(query, asyncCallback)
259 }
260 ], function (err, results) {
261 if (err) return callback(err)
262
263 const videos = results[0]
264 const totalVideos = results[1]
265 return callback(null, videos, totalVideos)
266 })
267}
268
269function removeThumbnail (video, callback) { 256function removeThumbnail (video, callback) {
270 fs.unlink(thumbnailsDir + video.thumbnail, callback) 257 fs.unlink(constants.CONFIG.STORAGE.THUMBNAILS_DIR + video.thumbnail, callback)
271} 258}
272 259
273function removeFile (video, callback) { 260function removeFile (video, callback) {
274 fs.unlink(uploadsDir + video.filename, callback) 261 fs.unlink(constants.CONFIG.STORAGE.UPLOAD_DIR + video.filename, callback)
275} 262}
276 263
277// Maybe the torrent is not seeded, but we catch the error to don't stop the removing process 264// Maybe the torrent is not seeded, but we catch the error to don't stop the removing process
@@ -288,7 +275,7 @@ function createThumbnail (videoPath, callback) {
288 }) 275 })
289 .thumbnail({ 276 .thumbnail({
290 count: 1, 277 count: 1,
291 folder: thumbnailsDir, 278 folder: constants.CONFIG.STORAGE.THUMBNAILS_DIR,
292 size: constants.THUMBNAILS_SIZE, 279 size: constants.THUMBNAILS_SIZE,
293 filename: filename 280 filename: filename
294 }) 281 })
@@ -300,7 +287,7 @@ function generateThumbnailFromBase64 (data, callback) {
300 if (err) return callback(err) 287 if (err) return callback(err)
301 288
302 const thumbnailName = randomString + '.jpg' 289 const thumbnailName = randomString + '.jpg'
303 fs.writeFile(thumbnailsDir + thumbnailName, data, { encoding: 'base64' }, function (err) { 290 fs.writeFile(constants.CONFIG.STORAGE.THUMBNAILS_DIR + thumbnailName, data, { encoding: 'base64' }, function (err) {
304 if (err) return callback(err) 291 if (err) return callback(err)
305 292
306 return callback(null, thumbnailName) 293 return callback(null, thumbnailName)
diff --git a/server/tests/api/check-params.js b/server/tests/api/check-params.js
new file mode 100644
index 000000000..57b5ca024
--- /dev/null
+++ b/server/tests/api/check-params.js
@@ -0,0 +1,746 @@
1'use strict'
2
3const chai = require('chai')
4const expect = chai.expect
5const pathUtils = require('path')
6const request = require('supertest')
7const series = require('async/series')
8
9const loginUtils = require('../utils/login')
10const requestsUtils = require('../utils/requests')
11const serversUtils = require('../utils/servers')
12const usersUtils = require('../utils/users')
13
14describe('Test parameters validator', function () {
15 let server = null
16 let userAccessToken = null
17
18 // ---------------------------------------------------------------
19
20 before(function (done) {
21 this.timeout(20000)
22
23 series([
24 function (next) {
25 serversUtils.flushTests(next)
26 },
27 function (next) {
28 serversUtils.runServer(1, function (server1) {
29 server = server1
30
31 next()
32 })
33 },
34 function (next) {
35 loginUtils.loginAndGetAccessToken(server, function (err, token) {
36 if (err) throw err
37 server.accessToken = token
38
39 next()
40 })
41 }
42 ], done)
43 })
44
45 describe('Of the pods API', function () {
46 const path = '/api/v1/pods/'
47
48 describe('When making friends', function () {
49 let userAccessToken = null
50
51 before(function (done) {
52 usersUtils.createUser(server.url, server.accessToken, 'user1', 'password', function () {
53 server.user = {
54 username: 'user1',
55 password: 'password'
56 }
57
58 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
59 if (err) throw err
60
61 userAccessToken = accessToken
62
63 done()
64 })
65 })
66 })
67
68 describe('When making friends', function () {
69 const body = {
70 urls: [ 'http://localhost:9002' ]
71 }
72
73 it('Should fail without urls', function (done) {
74 request(server.url)
75 .post(path + '/makefriends')
76 .set('Authorization', 'Bearer ' + server.accessToken)
77 .set('Accept', 'application/json')
78 .expect(400, done)
79 })
80
81 it('Should fail with urls is not an array', function (done) {
82 request(server.url)
83 .post(path + '/makefriends')
84 .send({ urls: 'http://localhost:9002' })
85 .set('Authorization', 'Bearer ' + server.accessToken)
86 .set('Accept', 'application/json')
87 .expect(400, done)
88 })
89
90 it('Should fail if the array is not composed by urls', function (done) {
91 request(server.url)
92 .post(path + '/makefriends')
93 .send({ urls: [ 'http://localhost:9002', 'localhost:coucou' ] })
94 .set('Authorization', 'Bearer ' + server.accessToken)
95 .set('Accept', 'application/json')
96 .expect(400, done)
97 })
98
99 it('Should fail if urls are not unique', function (done) {
100 request(server.url)
101 .post(path + '/makefriends')
102 .send({ urls: [ 'http://localhost:9002', 'http://localhost:9002' ] })
103 .set('Authorization', 'Bearer ' + server.accessToken)
104 .set('Accept', 'application/json')
105 .expect(400, done)
106 })
107
108 it('Should fail with a invalid token', function (done) {
109 request(server.url)
110 .post(path + '/makefriends')
111 .send(body)
112 .set('Authorization', 'Bearer faketoken')
113 .set('Accept', 'application/json')
114 .expect(401, done)
115 })
116
117 it('Should fail if the user is not an administrator', function (done) {
118 request(server.url)
119 .post(path + '/makefriends')
120 .send(body)
121 .set('Authorization', 'Bearer ' + userAccessToken)
122 .set('Accept', 'application/json')
123 .expect(403, done)
124 })
125 })
126
127 describe('When quitting friends', function () {
128 it('Should fail with a invalid token', function (done) {
129 request(server.url)
130 .get(path + '/quitfriends')
131 .query({ start: 'hello' })
132 .set('Authorization', 'Bearer faketoken')
133 .set('Accept', 'application/json')
134 .expect(401, done)
135 })
136
137 it('Should fail if the user is not an administrator', function (done) {
138 request(server.url)
139 .get(path + '/quitfriends')
140 .query({ start: 'hello' })
141 .set('Authorization', 'Bearer ' + userAccessToken)
142 .set('Accept', 'application/json')
143 .expect(403, done)
144 })
145 })
146 })
147
148 describe('When adding a pod', function () {
149 it('Should fail with nothing', function (done) {
150 const data = {}
151 requestsUtils.makePostBodyRequest(server.url, path, null, data, done)
152 })
153
154 it('Should fail without public key', function (done) {
155 const data = {
156 url: 'http://coucou.com'
157 }
158 requestsUtils.makePostBodyRequest(server.url, path, null, data, done)
159 })
160
161 it('Should fail without an url', function (done) {
162 const data = {
163 publicKey: 'mysuperpublickey'
164 }
165 requestsUtils.makePostBodyRequest(server.url, path, null, data, done)
166 })
167
168 it('Should fail with an incorrect url', function (done) {
169 const data = {
170 url: 'coucou.com',
171 publicKey: 'mysuperpublickey'
172 }
173 requestsUtils.makePostBodyRequest(server.url, path, null, data, function () {
174 data.url = 'http://coucou'
175 requestsUtils.makePostBodyRequest(server.url, path, null, data, function () {
176 data.url = 'coucou'
177 requestsUtils.makePostBodyRequest(server.url, path, null, data, done)
178 })
179 })
180 })
181
182 it('Should succeed with the correct parameters', function (done) {
183 const data = {
184 url: 'http://coucou.com',
185 publicKey: 'mysuperpublickey'
186 }
187 requestsUtils.makePostBodyRequest(server.url, path, null, data, done, 200)
188 })
189 })
190 })
191
192 describe('Of the videos API', function () {
193 const path = '/api/v1/videos/'
194
195 describe('When listing a video', function () {
196 it('Should fail with a bad start pagination', function (done) {
197 request(server.url)
198 .get(path)
199 .query({ start: 'hello' })
200 .set('Accept', 'application/json')
201 .expect(400, done)
202 })
203
204 it('Should fail with a bad count pagination', function (done) {
205 request(server.url)
206 .get(path)
207 .query({ count: 'hello' })
208 .set('Accept', 'application/json')
209 .expect(400, done)
210 })
211
212 it('Should fail with an incorrect sort', function (done) {
213 request(server.url)
214 .get(path)
215 .query({ sort: 'hello' })
216 .set('Accept', 'application/json')
217 .expect(400, done)
218 })
219 })
220
221 describe('When searching a video', function () {
222 it('Should fail with nothing', function (done) {
223 request(server.url)
224 .get(pathUtils.join(path, 'search'))
225 .set('Accept', 'application/json')
226 .expect(400, done)
227 })
228
229 it('Should fail with a bad start pagination', function (done) {
230 request(server.url)
231 .get(pathUtils.join(path, 'search', 'test'))
232 .query({ start: 'hello' })
233 .set('Accept', 'application/json')
234 .expect(400, done)
235 })
236
237 it('Should fail with a bad count pagination', function (done) {
238 request(server.url)
239 .get(pathUtils.join(path, 'search', 'test'))
240 .query({ count: 'hello' })
241 .set('Accept', 'application/json')
242 .expect(400, done)
243 })
244
245 it('Should fail with an incorrect sort', function (done) {
246 request(server.url)
247 .get(pathUtils.join(path, 'search', 'test'))
248 .query({ sort: 'hello' })
249 .set('Accept', 'application/json')
250 .expect(400, done)
251 })
252 })
253
254 describe('When adding a video', function () {
255 it('Should fail with nothing', function (done) {
256 const data = {}
257 const attach = {}
258 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
259 })
260
261 it('Should fail without name', function (done) {
262 const data = {
263 description: 'my super description',
264 tags: [ 'tag1', 'tag2' ]
265 }
266 const attach = {
267 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
268 }
269 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
270 })
271
272 it('Should fail with a long name', function (done) {
273 const data = {
274 name: 'My very very very very very very very very very very very very very very very very long name',
275 description: 'my super description',
276 tags: [ 'tag1', 'tag2' ]
277 }
278 const attach = {
279 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
280 }
281 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
282 })
283
284 it('Should fail without description', function (done) {
285 const data = {
286 name: 'my super name',
287 tags: [ 'tag1', 'tag2' ]
288 }
289 const attach = {
290 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
291 }
292 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
293 })
294
295 it('Should fail with a long description', function (done) {
296 const data = {
297 name: 'my super name',
298 description: 'my super description which is very very very very very very very very very very very very very very' +
299 'very very very very very very very very very very very very very very very very very very very very very' +
300 'very very very very very very very very very very very very very very very long',
301 tags: [ 'tag1', 'tag2' ]
302 }
303 const attach = {
304 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
305 }
306 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
307 })
308
309 it('Should fail without tags', function (done) {
310 const data = {
311 name: 'my super name',
312 description: 'my super description'
313 }
314 const attach = {
315 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
316 }
317 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
318 })
319
320 it('Should fail with too many tags', function (done) {
321 const data = {
322 name: 'my super name',
323 description: 'my super description',
324 tags: [ 'tag1', 'tag2', 'tag3', 'tag4' ]
325 }
326 const attach = {
327 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
328 }
329 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
330 })
331
332 it('Should fail with not enough tags', function (done) {
333 const data = {
334 name: 'my super name',
335 description: 'my super description',
336 tags: [ ]
337 }
338 const attach = {
339 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
340 }
341 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
342 })
343
344 it('Should fail with a tag length too low', function (done) {
345 const data = {
346 name: 'my super name',
347 description: 'my super description',
348 tags: [ 'tag1', 't' ]
349 }
350 const attach = {
351 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
352 }
353 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
354 })
355
356 it('Should fail with a tag length too big', function (done) {
357 const data = {
358 name: 'my super name',
359 description: 'my super description',
360 tags: [ 'mysupertagtoolong', 'tag1' ]
361 }
362 const attach = {
363 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
364 }
365 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
366 })
367
368 it('Should fail with malformed tags', function (done) {
369 const data = {
370 name: 'my super name',
371 description: 'my super description',
372 tags: [ 'my tag' ]
373 }
374 const attach = {
375 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
376 }
377 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
378 })
379
380 it('Should fail without an input file', function (done) {
381 const data = {
382 name: 'my super name',
383 description: 'my super description',
384 tags: [ 'tag1', 'tag2' ]
385 }
386 const attach = {}
387 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
388 })
389
390 it('Should fail without an incorrect input file', function (done) {
391 const data = {
392 name: 'my super name',
393 description: 'my super description',
394 tags: [ 'tag1', 'tag2' ]
395 }
396 const attach = {
397 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short_fake.webm')
398 }
399 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
400 })
401
402 it('Should fail with a too big duration', function (done) {
403 const data = {
404 name: 'my super name',
405 description: 'my super description',
406 tags: [ 'tag1', 'tag2' ]
407 }
408 const attach = {
409 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_too_long.webm')
410 }
411 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done)
412 })
413
414 it('Should succeed with the correct parameters', function (done) {
415 const data = {
416 name: 'my super name',
417 description: 'my super description',
418 tags: [ 'tag1', 'tag2' ]
419 }
420 const attach = {
421 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
422 }
423 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, function () {
424 attach.videofile = pathUtils.join(__dirname, 'fixtures', 'video_short.mp4')
425 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, function () {
426 attach.videofile = pathUtils.join(__dirname, 'fixtures', 'video_short.ogv')
427 requestsUtils.makePostUploadRequest(server.url, path, server.accessToken, data, attach, done, 204)
428 }, false)
429 }, false)
430 })
431 })
432
433 describe('When getting a video', function () {
434 it('Should return the list of the videos with nothing', function (done) {
435 request(server.url)
436 .get(path)
437 .set('Accept', 'application/json')
438 .expect(200)
439 .expect('Content-Type', /json/)
440 .end(function (err, res) {
441 if (err) throw err
442
443 expect(res.body.data).to.be.an('array')
444 expect(res.body.data.length).to.equal(3)
445
446 done()
447 })
448 })
449
450 it('Should fail without a mongodb id', function (done) {
451 request(server.url)
452 .get(path + 'coucou')
453 .set('Accept', 'application/json')
454 .expect(400, done)
455 })
456
457 it('Should return 404 with an incorrect video', function (done) {
458 request(server.url)
459 .get(path + '123456789012345678901234')
460 .set('Accept', 'application/json')
461 .expect(404, done)
462 })
463
464 it('Should succeed with the correct parameters')
465 })
466
467 describe('When removing a video', function () {
468 it('Should have 404 with nothing', function (done) {
469 request(server.url)
470 .delete(path)
471 .set('Authorization', 'Bearer ' + server.accessToken)
472 .expect(400, done)
473 })
474
475 it('Should fail without a mongodb id', function (done) {
476 request(server.url)
477 .delete(path + 'hello')
478 .set('Authorization', 'Bearer ' + server.accessToken)
479 .expect(400, done)
480 })
481
482 it('Should fail with a video which does not exist', function (done) {
483 request(server.url)
484 .delete(path + '123456789012345678901234')
485 .set('Authorization', 'Bearer ' + server.accessToken)
486 .expect(404, done)
487 })
488
489 it('Should fail with a video of another user')
490
491 it('Should fail with a video of another pod')
492
493 it('Should succeed with the correct parameters')
494 })
495 })
496
497 describe('Of the users API', function () {
498 const path = '/api/v1/users/'
499 let userId = null
500
501 describe('When listing users', function () {
502 it('Should fail with a bad start pagination', function (done) {
503 request(server.url)
504 .get(path)
505 .query({ start: 'hello' })
506 .set('Accept', 'application/json')
507 .expect(400, done)
508 })
509
510 it('Should fail with a bad count pagination', function (done) {
511 request(server.url)
512 .get(path)
513 .query({ count: 'hello' })
514 .set('Accept', 'application/json')
515 .expect(400, done)
516 })
517
518 it('Should fail with an incorrect sort', function (done) {
519 request(server.url)
520 .get(path)
521 .query({ sort: 'hello' })
522 .set('Accept', 'application/json')
523 .expect(400, done)
524 })
525 })
526
527 describe('When adding a new user', function () {
528 it('Should fail with a too small username', function (done) {
529 const data = {
530 username: 'ji',
531 password: 'mysuperpassword'
532 }
533
534 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done)
535 })
536
537 it('Should fail with a too long username', function (done) {
538 const data = {
539 username: 'mysuperusernamewhichisverylong',
540 password: 'mysuperpassword'
541 }
542
543 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done)
544 })
545
546 it('Should fail with an incorrect username', function (done) {
547 const data = {
548 username: 'my username',
549 password: 'mysuperpassword'
550 }
551
552 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done)
553 })
554
555 it('Should fail with a too small password', function (done) {
556 const data = {
557 username: 'myusername',
558 password: 'bla'
559 }
560
561 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done)
562 })
563
564 it('Should fail with a too long password', function (done) {
565 const data = {
566 username: 'myusername',
567 password: 'my super long password which is very very very very very very very very very very very very very very' +
568 'very very very very very very very very very very very very very very very veryv very very very very' +
569 'very very very very very very very very very very very very very very very very very very very very long'
570 }
571
572 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done)
573 })
574
575 it('Should fail with an non authenticated user', function (done) {
576 const data = {
577 username: 'myusername',
578 password: 'my super password'
579 }
580
581 requestsUtils.makePostBodyRequest(server.url, path, 'super token', data, done, 401)
582 })
583
584 it('Should fail if we add a user with the same username', function (done) {
585 const data = {
586 username: 'user1',
587 password: 'my super password'
588 }
589
590 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done, 409)
591 })
592
593 it('Should succeed with the correct params', function (done) {
594 const data = {
595 username: 'user2',
596 password: 'my super password'
597 }
598
599 requestsUtils.makePostBodyRequest(server.url, path, server.accessToken, data, done, 204)
600 })
601
602 it('Should fail with a non admin user', function (done) {
603 server.user = {
604 username: 'user1',
605 password: 'password'
606 }
607
608 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
609 if (err) throw err
610
611 userAccessToken = accessToken
612
613 const data = {
614 username: 'user3',
615 password: 'my super password'
616 }
617
618 requestsUtils.makePostBodyRequest(server.url, path, userAccessToken, data, done, 403)
619 })
620 })
621 })
622
623 describe('When updating a user', function () {
624 before(function (done) {
625 usersUtils.getUsersList(server.url, function (err, res) {
626 if (err) throw err
627
628 userId = res.body.data[1].id
629 done()
630 })
631 })
632
633 it('Should fail with a too small password', function (done) {
634 const data = {
635 password: 'bla'
636 }
637
638 requestsUtils.makePutBodyRequest(server.url, path + userId, userAccessToken, data, done)
639 })
640
641 it('Should fail with a too long password', function (done) {
642 const data = {
643 password: 'my super long password which is very very very very very very very very very very very very very very' +
644 'very very very very very very very very very very very very very very very veryv very very very very' +
645 'very very very very very very very very very very very very very very very very very very very very long'
646 }
647
648 requestsUtils.makePutBodyRequest(server.url, path + userId, userAccessToken, data, done)
649 })
650
651 it('Should fail with an non authenticated user', function (done) {
652 const data = {
653 password: 'my super password'
654 }
655
656 requestsUtils.makePutBodyRequest(server.url, path + userId, 'super token', data, done, 401)
657 })
658
659 it('Should succeed with the correct params', function (done) {
660 const data = {
661 password: 'my super password'
662 }
663
664 requestsUtils.makePutBodyRequest(server.url, path + userId, userAccessToken, data, done, 204)
665 })
666 })
667
668 describe('When getting my information', function () {
669 it('Should fail with a non authenticated user', function (done) {
670 request(server.url)
671 .get(path + 'me')
672 .set('Authorization', 'Bearer faketoken')
673 .set('Accept', 'application/json')
674 .expect(401, done)
675 })
676
677 it('Should success with the correct parameters', function (done) {
678 request(server.url)
679 .get(path + 'me')
680 .set('Authorization', 'Bearer ' + userAccessToken)
681 .set('Accept', 'application/json')
682 .expect(200, done)
683 })
684 })
685
686 describe('When removing an user', function () {
687 it('Should fail with an incorrect id', function (done) {
688 request(server.url)
689 .delete(path + 'bla-bla')
690 .set('Authorization', 'Bearer ' + server.accessToken)
691 .expect(400, done)
692 })
693
694 it('Should return 404 with a non existing id', function (done) {
695 request(server.url)
696 .delete(path + '579f982228c99c221d8092b8')
697 .set('Authorization', 'Bearer ' + server.accessToken)
698 .expect(404, done)
699 })
700 })
701 })
702
703 describe('Of the remote videos API', function () {
704 describe('When making a secure request', function () {
705 it('Should check a secure request')
706 })
707
708 describe('When adding a video', function () {
709 it('Should check when adding a video')
710 })
711
712 describe('When removing a video', function () {
713 it('Should check when removing a video')
714 })
715 })
716
717 describe('Of the requests API', function () {
718 const path = '/api/v1/requests/stats'
719
720 it('Should fail with an non authenticated user', function (done) {
721 request(server.url)
722 .get(path)
723 .set('Accept', 'application/json')
724 .expect(401, done)
725 })
726
727 it('Should fail with a non admin user', function (done) {
728 request(server.url)
729 .get(path)
730 .set('Authorization', 'Bearer ' + userAccessToken)
731 .set('Accept', 'application/json')
732 .expect(403, done)
733 })
734 })
735
736 after(function (done) {
737 process.kill(-server.app.pid)
738
739 // Keep the logs if the test failed
740 if (this.ok) {
741 serversUtils.flushTests(done)
742 } else {
743 done()
744 }
745 })
746})
diff --git a/server/tests/api/checkParams.js b/server/tests/api/checkParams.js
deleted file mode 100644
index c1ba9c2c0..000000000
--- a/server/tests/api/checkParams.js
+++ /dev/null
@@ -1,456 +0,0 @@
1'use strict'
2
3const chai = require('chai')
4const expect = chai.expect
5const pathUtils = require('path')
6const request = require('supertest')
7const series = require('async/series')
8
9const utils = require('./utils')
10
11describe('Test parameters validator', function () {
12 let server = null
13
14 function makePostRequest (path, token, fields, attaches, done, fail) {
15 let statusCode = 400
16 if (fail !== undefined && fail === false) statusCode = 204
17
18 const req = request(server.url)
19 .post(path)
20 .set('Accept', 'application/json')
21
22 if (token) req.set('Authorization', 'Bearer ' + token)
23
24 Object.keys(fields).forEach(function (field) {
25 const value = fields[field]
26
27 if (Array.isArray(value)) {
28 for (let i = 0; i < value.length; i++) {
29 req.field(field + '[' + i + ']', value[i])
30 }
31 } else {
32 req.field(field, value)
33 }
34 })
35
36 Object.keys(attaches).forEach(function (attach) {
37 const value = attaches[attach]
38 req.attach(attach, value)
39 })
40
41 req.expect(statusCode, done)
42 }
43
44 function makePostBodyRequest (path, fields, done, fail) {
45 let statusCode = 400
46 if (fail !== undefined && fail === false) statusCode = 200
47
48 request(server.url)
49 .post(path)
50 .set('Accept', 'application/json')
51 .send(fields)
52 .expect(statusCode, done)
53 }
54
55 // ---------------------------------------------------------------
56
57 before(function (done) {
58 this.timeout(20000)
59
60 series([
61 function (next) {
62 utils.flushTests(next)
63 },
64 function (next) {
65 utils.runServer(1, function (server1) {
66 server = server1
67
68 next()
69 })
70 },
71 function (next) {
72 utils.loginAndGetAccessToken(server, function (err, token) {
73 if (err) throw err
74 server.accessToken = token
75
76 next()
77 })
78 }
79 ], done)
80 })
81
82 describe('Of the pods API', function () {
83 const path = '/api/v1/pods/'
84
85 describe('When adding a pod', function () {
86 it('Should fail with nothing', function (done) {
87 const data = {}
88 makePostBodyRequest(path, data, done)
89 })
90
91 it('Should fail without public key', function (done) {
92 const data = {
93 url: 'http://coucou.com'
94 }
95 makePostBodyRequest(path, data, done)
96 })
97
98 it('Should fail without an url', function (done) {
99 const data = {
100 publicKey: 'mysuperpublickey'
101 }
102 makePostBodyRequest(path, data, done)
103 })
104
105 it('Should fail with an incorrect url', function (done) {
106 const data = {
107 url: 'coucou.com',
108 publicKey: 'mysuperpublickey'
109 }
110 makePostBodyRequest(path, data, function () {
111 data.url = 'http://coucou'
112 makePostBodyRequest(path, data, function () {
113 data.url = 'coucou'
114 makePostBodyRequest(path, data, done)
115 })
116 })
117 })
118
119 it('Should succeed with the correct parameters', function (done) {
120 const data = {
121 url: 'http://coucou.com',
122 publicKey: 'mysuperpublickey'
123 }
124 makePostBodyRequest(path, data, done, false)
125 })
126 })
127 })
128
129 describe('Of the videos API', function () {
130 const path = '/api/v1/videos/'
131
132 describe('When listing a video', function () {
133 it('Should fail with a bad start pagination', function (done) {
134 request(server.url)
135 .get(path)
136 .query({ start: 'hello' })
137 .set('Accept', 'application/json')
138 .expect(400, done)
139 })
140
141 it('Should fail with a bad count pagination', function (done) {
142 request(server.url)
143 .get(path)
144 .query({ count: 'hello' })
145 .set('Accept', 'application/json')
146 .expect(400, done)
147 })
148
149 it('Should fail with an incorrect sort', function (done) {
150 request(server.url)
151 .get(path)
152 .query({ sort: 'hello' })
153 .set('Accept', 'application/json')
154 .expect(400, done)
155 })
156 })
157
158 describe('When searching a video', function () {
159 it('Should fail with nothing', function (done) {
160 request(server.url)
161 .get(pathUtils.join(path, 'search'))
162 .set('Accept', 'application/json')
163 .expect(400, done)
164 })
165
166 it('Should fail with a bad start pagination', function (done) {
167 request(server.url)
168 .get(pathUtils.join(path, 'search', 'test'))
169 .query({ start: 'hello' })
170 .set('Accept', 'application/json')
171 .expect(400, done)
172 })
173
174 it('Should fail with a bad count pagination', function (done) {
175 request(server.url)
176 .get(pathUtils.join(path, 'search', 'test'))
177 .query({ count: 'hello' })
178 .set('Accept', 'application/json')
179 .expect(400, done)
180 })
181
182 it('Should fail with an incorrect sort', function (done) {
183 request(server.url)
184 .get(pathUtils.join(path, 'search', 'test'))
185 .query({ sort: 'hello' })
186 .set('Accept', 'application/json')
187 .expect(400, done)
188 })
189 })
190
191 describe('When adding a video', function () {
192 it('Should fail with nothing', function (done) {
193 const data = {}
194 const attach = {}
195 makePostRequest(path, server.accessToken, data, attach, done)
196 })
197
198 it('Should fail without name', function (done) {
199 const data = {
200 description: 'my super description',
201 tags: [ 'tag1', 'tag2' ]
202 }
203 const attach = {
204 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
205 }
206 makePostRequest(path, server.accessToken, data, attach, done)
207 })
208
209 it('Should fail with a long name', function (done) {
210 const data = {
211 name: 'My very very very very very very very very very very very very very very very very long name',
212 description: 'my super description',
213 tags: [ 'tag1', 'tag2' ]
214 }
215 const attach = {
216 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
217 }
218 makePostRequest(path, server.accessToken, data, attach, done)
219 })
220
221 it('Should fail without description', function (done) {
222 const data = {
223 name: 'my super name',
224 tags: [ 'tag1', 'tag2' ]
225 }
226 const attach = {
227 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
228 }
229 makePostRequest(path, server.accessToken, data, attach, done)
230 })
231
232 it('Should fail with a long description', function (done) {
233 const data = {
234 name: 'my super name',
235 description: 'my super description which is very very very very very very very very very very very very very very' +
236 'very very very very very very very very very very very very very very very very very very very very very' +
237 'very very very very very very very very very very very very very very very long',
238 tags: [ 'tag1', 'tag2' ]
239 }
240 const attach = {
241 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
242 }
243 makePostRequest(path, server.accessToken, data, attach, done)
244 })
245
246 it('Should fail without tags', function (done) {
247 const data = {
248 name: 'my super name',
249 description: 'my super description'
250 }
251 const attach = {
252 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
253 }
254 makePostRequest(path, server.accessToken, data, attach, done)
255 })
256
257 it('Should fail with too many tags', function (done) {
258 const data = {
259 name: 'my super name',
260 description: 'my super description',
261 tags: [ 'tag1', 'tag2', 'tag3', 'tag4' ]
262 }
263 const attach = {
264 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
265 }
266 makePostRequest(path, server.accessToken, data, attach, done)
267 })
268
269 it('Should fail with not enough tags', function (done) {
270 const data = {
271 name: 'my super name',
272 description: 'my super description',
273 tags: [ ]
274 }
275 const attach = {
276 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
277 }
278 makePostRequest(path, server.accessToken, data, attach, done)
279 })
280
281 it('Should fail with a tag length too low', function (done) {
282 const data = {
283 name: 'my super name',
284 description: 'my super description',
285 tags: [ 'tag1', 't' ]
286 }
287 const attach = {
288 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
289 }
290 makePostRequest(path, server.accessToken, data, attach, done)
291 })
292
293 it('Should fail with a tag length too big', function (done) {
294 const data = {
295 name: 'my super name',
296 description: 'my super description',
297 tags: [ 'mysupertagtoolong', 'tag1' ]
298 }
299 const attach = {
300 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
301 }
302 makePostRequest(path, server.accessToken, data, attach, done)
303 })
304
305 it('Should fail with malformed tags', function (done) {
306 const data = {
307 name: 'my super name',
308 description: 'my super description',
309 tags: [ 'my tag' ]
310 }
311 const attach = {
312 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
313 }
314 makePostRequest(path, server.accessToken, data, attach, done)
315 })
316
317 it('Should fail without an input file', function (done) {
318 const data = {
319 name: 'my super name',
320 description: 'my super description',
321 tags: [ 'tag1', 'tag2' ]
322 }
323 const attach = {}
324 makePostRequest(path, server.accessToken, data, attach, done)
325 })
326
327 it('Should fail without an incorrect input file', function (done) {
328 const data = {
329 name: 'my super name',
330 description: 'my super description',
331 tags: [ 'tag1', 'tag2' ]
332 }
333 const attach = {
334 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short_fake.webm')
335 }
336 makePostRequest(path, server.accessToken, data, attach, done)
337 })
338
339 it('Should fail with a too big duration', function (done) {
340 const data = {
341 name: 'my super name',
342 description: 'my super description',
343 tags: [ 'tag1', 'tag2' ]
344 }
345 const attach = {
346 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_too_long.webm')
347 }
348 makePostRequest(path, server.accessToken, data, attach, done)
349 })
350
351 it('Should succeed with the correct parameters', function (done) {
352 const data = {
353 name: 'my super name',
354 description: 'my super description',
355 tags: [ 'tag1', 'tag2' ]
356 }
357 const attach = {
358 'videofile': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
359 }
360 makePostRequest(path, server.accessToken, data, attach, function () {
361 attach.videofile = pathUtils.join(__dirname, 'fixtures', 'video_short.mp4')
362 makePostRequest(path, server.accessToken, data, attach, function () {
363 attach.videofile = pathUtils.join(__dirname, 'fixtures', 'video_short.ogv')
364 makePostRequest(path, server.accessToken, data, attach, done, false)
365 }, false)
366 }, false)
367 })
368 })
369
370 describe('When getting a video', function () {
371 it('Should return the list of the videos with nothing', function (done) {
372 request(server.url)
373 .get(path)
374 .set('Accept', 'application/json')
375 .expect(200)
376 .expect('Content-Type', /json/)
377 .end(function (err, res) {
378 if (err) throw err
379
380 expect(res.body.data).to.be.an('array')
381 expect(res.body.data.length).to.equal(3)
382
383 done()
384 })
385 })
386
387 it('Should fail without a mongodb id', function (done) {
388 request(server.url)
389 .get(path + 'coucou')
390 .set('Accept', 'application/json')
391 .expect(400, done)
392 })
393
394 it('Should return 404 with an incorrect video', function (done) {
395 request(server.url)
396 .get(path + '123456789012345678901234')
397 .set('Accept', 'application/json')
398 .expect(404, done)
399 })
400
401 it('Should succeed with the correct parameters')
402 })
403
404 describe('When removing a video', function () {
405 it('Should have 404 with nothing', function (done) {
406 request(server.url)
407 .delete(path)
408 .set('Authorization', 'Bearer ' + server.accessToken)
409 .expect(400, done)
410 })
411
412 it('Should fail without a mongodb id', function (done) {
413 request(server.url)
414 .delete(path + 'hello')
415 .set('Authorization', 'Bearer ' + server.accessToken)
416 .expect(400, done)
417 })
418
419 it('Should fail with a video which does not exist', function (done) {
420 request(server.url)
421 .delete(path + '123456789012345678901234')
422 .set('Authorization', 'Bearer ' + server.accessToken)
423 .expect(404, done)
424 })
425
426 it('Should fail with a video of another pod')
427
428 it('Should succeed with the correct parameters')
429 })
430 })
431
432 describe('Of the remote videos API', function () {
433 describe('When making a secure request', function () {
434 it('Should check a secure request')
435 })
436
437 describe('When adding a video', function () {
438 it('Should check when adding a video')
439 })
440
441 describe('When removing a video', function () {
442 it('Should check when removing a video')
443 })
444 })
445
446 after(function (done) {
447 process.kill(-server.app.pid)
448
449 // Keep the logs if the test failed
450 if (this.ok) {
451 utils.flushTests(done)
452 } else {
453 done()
454 }
455 })
456})
diff --git a/server/tests/api/friendsAdvanced.js b/server/tests/api/friends-advanced.js
index 603fbc16b..0d24481ef 100644
--- a/server/tests/api/friendsAdvanced.js
+++ b/server/tests/api/friends-advanced.js
@@ -5,24 +5,27 @@ const each = require('async/each')
5const expect = chai.expect 5const expect = chai.expect
6const series = require('async/series') 6const series = require('async/series')
7 7
8const utils = require('./utils') 8const loginUtils = require('../utils/login')
9const podsUtils = require('../utils/pods')
10const serversUtils = require('../utils/servers')
11const videosUtils = require('../utils/videos')
9 12
10describe('Test advanced friends', function () { 13describe('Test advanced friends', function () {
11 let servers = [] 14 let servers = []
12 15
13 function makeFriends (podNumber, callback) { 16 function makeFriends (podNumber, callback) {
14 const server = servers[podNumber - 1] 17 const server = servers[podNumber - 1]
15 return utils.makeFriends(server.url, server.accessToken, callback) 18 return podsUtils.makeFriends(server.url, server.accessToken, callback)
16 } 19 }
17 20
18 function quitFriends (podNumber, callback) { 21 function quitFriends (podNumber, callback) {
19 const server = servers[podNumber - 1] 22 const server = servers[podNumber - 1]
20 return utils.quitFriends(server.url, server.accessToken, callback) 23 return podsUtils.quitFriends(server.url, server.accessToken, callback)
21 } 24 }
22 25
23 function getFriendsList (podNumber, end) { 26 function getFriendsList (podNumber, end) {
24 const server = servers[podNumber - 1] 27 const server = servers[podNumber - 1]
25 return utils.getFriendsList(server.url, end) 28 return podsUtils.getFriendsList(server.url, end)
26 } 29 }
27 30
28 function uploadVideo (podNumber, callback) { 31 function uploadVideo (podNumber, callback) {
@@ -32,22 +35,22 @@ describe('Test advanced friends', function () {
32 const fixture = 'video_short.webm' 35 const fixture = 'video_short.webm'
33 const server = servers[podNumber - 1] 36 const server = servers[podNumber - 1]
34 37
35 return utils.uploadVideo(server.url, server.accessToken, name, description, tags, fixture, callback) 38 return videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, fixture, callback)
36 } 39 }
37 40
38 function getVideos (podNumber, callback) { 41 function getVideos (podNumber, callback) {
39 return utils.getVideosList(servers[podNumber - 1].url, callback) 42 return videosUtils.getVideosList(servers[podNumber - 1].url, callback)
40 } 43 }
41 44
42 // --------------------------------------------------------------- 45 // ---------------------------------------------------------------
43 46
44 before(function (done) { 47 before(function (done) {
45 this.timeout(30000) 48 this.timeout(30000)
46 utils.flushAndRunMultipleServers(6, function (serversRun, urlsRun) { 49 serversUtils.flushAndRunMultipleServers(6, function (serversRun, urlsRun) {
47 servers = serversRun 50 servers = serversRun
48 51
49 each(servers, function (server, callbackEach) { 52 each(servers, function (server, callbackEach) {
50 utils.loginAndGetAccessToken(server, function (err, accessToken) { 53 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
51 if (err) return callbackEach(err) 54 if (err) return callbackEach(err)
52 55
53 server.accessToken = accessToken 56 server.accessToken = accessToken
@@ -169,7 +172,7 @@ describe('Test advanced friends', function () {
169 }, 172 },
170 // Rerun server 4 173 // Rerun server 4
171 function (next) { 174 function (next) {
172 utils.runServer(4, function (server) { 175 serversUtils.runServer(4, function (server) {
173 servers[3].app = server.app 176 servers[3].app = server.app
174 next() 177 next()
175 }) 178 })
@@ -273,7 +276,7 @@ describe('Test advanced friends', function () {
273 }) 276 })
274 277
275 if (this.ok) { 278 if (this.ok) {
276 utils.flushTests(done) 279 serversUtils.flushTests(done)
277 } else { 280 } else {
278 done() 281 done()
279 } 282 }
diff --git a/server/tests/api/friendsBasic.js b/server/tests/api/friends-basic.js
index c74a7f224..f1393b5ec 100644
--- a/server/tests/api/friendsBasic.js
+++ b/server/tests/api/friends-basic.js
@@ -5,14 +5,17 @@ const each = require('async/each')
5const expect = chai.expect 5const expect = chai.expect
6const series = require('async/series') 6const series = require('async/series')
7 7
8const utils = require('./utils') 8const loginUtils = require('../utils/login')
9const miscsUtils = require('../utils/miscs')
10const podsUtils = require('../utils/pods')
11const serversUtils = require('../utils/servers')
9 12
10describe('Test basic friends', function () { 13describe('Test basic friends', function () {
11 let servers = [] 14 let servers = []
12 15
13 function makeFriends (podNumber, callback) { 16 function makeFriends (podNumber, callback) {
14 const server = servers[podNumber - 1] 17 const server = servers[podNumber - 1]
15 return utils.makeFriends(server.url, server.accessToken, callback) 18 return podsUtils.makeFriends(server.url, server.accessToken, callback)
16 } 19 }
17 20
18 function testMadeFriends (servers, serverToTest, callback) { 21 function testMadeFriends (servers, serverToTest, callback) {
@@ -22,7 +25,7 @@ describe('Test basic friends', function () {
22 friends.push(servers[i].url) 25 friends.push(servers[i].url)
23 } 26 }
24 27
25 utils.getFriendsList(serverToTest.url, function (err, res) { 28 podsUtils.getFriendsList(serverToTest.url, function (err, res) {
26 if (err) throw err 29 if (err) throw err
27 30
28 const result = res.body 31 const result = res.body
@@ -43,11 +46,11 @@ describe('Test basic friends', function () {
43 46
44 before(function (done) { 47 before(function (done) {
45 this.timeout(20000) 48 this.timeout(20000)
46 utils.flushAndRunMultipleServers(3, function (serversRun, urlsRun) { 49 serversUtils.flushAndRunMultipleServers(3, function (serversRun, urlsRun) {
47 servers = serversRun 50 servers = serversRun
48 51
49 each(servers, function (server, callbackEach) { 52 each(servers, function (server, callbackEach) {
50 utils.loginAndGetAccessToken(server, function (err, accessToken) { 53 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
51 if (err) return callbackEach(err) 54 if (err) return callbackEach(err)
52 55
53 server.accessToken = accessToken 56 server.accessToken = accessToken
@@ -59,7 +62,7 @@ describe('Test basic friends', function () {
59 62
60 it('Should not have friends', function (done) { 63 it('Should not have friends', function (done) {
61 each(servers, function (server, callback) { 64 each(servers, function (server, callback) {
62 utils.getFriendsList(server.url, function (err, res) { 65 podsUtils.getFriendsList(server.url, function (err, res) {
63 if (err) throw err 66 if (err) throw err
64 67
65 const result = res.body 68 const result = res.body
@@ -71,7 +74,7 @@ describe('Test basic friends', function () {
71 }) 74 })
72 75
73 it('Should make friends', function (done) { 76 it('Should make friends', function (done) {
74 this.timeout(10000) 77 this.timeout(40000)
75 78
76 series([ 79 series([
77 // The second pod make friend with the third 80 // The second pod make friend with the third
@@ -80,30 +83,38 @@ describe('Test basic friends', function () {
80 }, 83 },
81 // Wait for the request between pods 84 // Wait for the request between pods
82 function (next) { 85 function (next) {
83 setTimeout(next, 1000) 86 setTimeout(next, 11000)
84 }, 87 },
85 // The second pod should have the third as a friend 88 // The second pod should have the third as a friend
86 function (next) { 89 function (next) {
87 utils.getFriendsList(servers[1].url, function (err, res) { 90 podsUtils.getFriendsList(servers[1].url, function (err, res) {
88 if (err) throw err 91 if (err) throw err
89 92
90 const result = res.body 93 const result = res.body
91 expect(result).to.be.an('array') 94 expect(result).to.be.an('array')
92 expect(result.length).to.equal(1) 95 expect(result.length).to.equal(1)
93 expect(result[0].url).to.be.equal(servers[2].url) 96
97 const pod = result[0]
98 expect(pod.url).to.equal(servers[2].url)
99 expect(pod.score).to.equal(20)
100 expect(miscsUtils.dateIsValid(pod.createdDate)).to.be.true
94 101
95 next() 102 next()
96 }) 103 })
97 }, 104 },
98 // Same here, the third pod should have the second pod as a friend 105 // Same here, the third pod should have the second pod as a friend
99 function (next) { 106 function (next) {
100 utils.getFriendsList(servers[2].url, function (err, res) { 107 podsUtils.getFriendsList(servers[2].url, function (err, res) {
101 if (err) throw err 108 if (err) throw err
102 109
103 const result = res.body 110 const result = res.body
104 expect(result).to.be.an('array') 111 expect(result).to.be.an('array')
105 expect(result.length).to.equal(1) 112 expect(result.length).to.equal(1)
106 expect(result[0].url).to.be.equal(servers[1].url) 113
114 const pod = result[0]
115 expect(pod.url).to.equal(servers[1].url)
116 expect(pod.score).to.equal(20)
117 expect(miscsUtils.dateIsValid(pod.createdDate)).to.be.true
107 118
108 next() 119 next()
109 }) 120 })
@@ -114,7 +125,7 @@ describe('Test basic friends', function () {
114 }, 125 },
115 // Wait for the request between pods 126 // Wait for the request between pods
116 function (next) { 127 function (next) {
117 setTimeout(next, 1000) 128 setTimeout(next, 11000)
118 } 129 }
119 ], 130 ],
120 // Now each pod should be friend with the other ones 131 // Now each pod should be friend with the other ones
@@ -128,7 +139,7 @@ describe('Test basic friends', function () {
128 139
129 it('Should not be allowed to make friend again', function (done) { 140 it('Should not be allowed to make friend again', function (done) {
130 const server = servers[1] 141 const server = servers[1]
131 utils.makeFriends(server.url, server.accessToken, 409, done) 142 podsUtils.makeFriends(server.url, server.accessToken, 409, done)
132 }) 143 })
133 144
134 it('Should quit friends of pod 2', function (done) { 145 it('Should quit friends of pod 2', function (done) {
@@ -136,11 +147,11 @@ describe('Test basic friends', function () {
136 // Pod 1 quit friends 147 // Pod 1 quit friends
137 function (next) { 148 function (next) {
138 const server = servers[1] 149 const server = servers[1]
139 utils.quitFriends(server.url, server.accessToken, next) 150 podsUtils.quitFriends(server.url, server.accessToken, next)
140 }, 151 },
141 // Pod 1 should not have friends anymore 152 // Pod 1 should not have friends anymore
142 function (next) { 153 function (next) {
143 utils.getFriendsList(servers[1].url, function (err, res) { 154 podsUtils.getFriendsList(servers[1].url, function (err, res) {
144 if (err) throw err 155 if (err) throw err
145 156
146 const result = res.body 157 const result = res.body
@@ -153,7 +164,7 @@ describe('Test basic friends', function () {
153 // Other pods shouldn't have pod 1 too 164 // Other pods shouldn't have pod 1 too
154 function (next) { 165 function (next) {
155 each([ servers[0].url, servers[2].url ], function (url, callback) { 166 each([ servers[0].url, servers[2].url ], function (url, callback) {
156 utils.getFriendsList(url, function (err, res) { 167 podsUtils.getFriendsList(url, function (err, res) {
157 if (err) throw err 168 if (err) throw err
158 169
159 const result = res.body 170 const result = res.body
@@ -168,11 +179,15 @@ describe('Test basic friends', function () {
168 }) 179 })
169 180
170 it('Should allow pod 2 to make friend again', function (done) { 181 it('Should allow pod 2 to make friend again', function (done) {
182 this.timeout(20000)
183
171 const server = servers[1] 184 const server = servers[1]
172 utils.makeFriends(server.url, server.accessToken, function () { 185 podsUtils.makeFriends(server.url, server.accessToken, function () {
173 each(servers, function (server, callback) { 186 setTimeout(function () {
174 testMadeFriends(servers, server, callback) 187 each(servers, function (server, callback) {
175 }, done) 188 testMadeFriends(servers, server, callback)
189 }, done)
190 }, 11000)
176 }) 191 })
177 }) 192 })
178 193
@@ -182,7 +197,7 @@ describe('Test basic friends', function () {
182 }) 197 })
183 198
184 if (this.ok) { 199 if (this.ok) {
185 utils.flushTests(done) 200 serversUtils.flushTests(done)
186 } else { 201 } else {
187 done() 202 done()
188 } 203 }
diff --git a/server/tests/api/index.js b/server/tests/api/index.js
index 61c9a7aca..11f49e1e2 100644
--- a/server/tests/api/index.js
+++ b/server/tests/api/index.js
@@ -1,9 +1,9 @@
1'use strict' 1'use strict'
2 2
3// Order of the tests we want to execute 3// Order of the tests we want to execute
4require('./checkParams') 4require('./check-params')
5require('./friendsBasic') 5require('./friends-basic')
6require('./users') 6require('./users')
7require('./singlePod') 7require('./single-pod')
8require('./multiplePods') 8require('./multiple-pods')
9require('./friendsAdvanced') 9require('./friends-advanced')
diff --git a/server/tests/api/multiplePods.js b/server/tests/api/multiple-pods.js
index ac140f6bb..b86f88c22 100644
--- a/server/tests/api/multiplePods.js
+++ b/server/tests/api/multiple-pods.js
@@ -6,7 +6,11 @@ const expect = chai.expect
6const pathUtils = require('path') 6const pathUtils = require('path')
7const series = require('async/series') 7const series = require('async/series')
8 8
9const utils = require('./utils') 9const loginUtils = require('../utils/login')
10const miscsUtils = require('../utils/miscs')
11const podsUtils = require('../utils/pods')
12const serversUtils = require('../utils/servers')
13const videosUtils = require('../utils/videos')
10const webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent')) 14const webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent'))
11webtorrent.silent = true 15webtorrent.silent = true
12 16
@@ -20,7 +24,7 @@ describe('Test multiple pods', function () {
20 series([ 24 series([
21 // Run servers 25 // Run servers
22 function (next) { 26 function (next) {
23 utils.flushAndRunMultipleServers(3, function (serversRun) { 27 serversUtils.flushAndRunMultipleServers(3, function (serversRun) {
24 servers = serversRun 28 servers = serversRun
25 next() 29 next()
26 }) 30 })
@@ -28,7 +32,7 @@ describe('Test multiple pods', function () {
28 // Get the access tokens 32 // Get the access tokens
29 function (next) { 33 function (next) {
30 each(servers, function (server, callbackEach) { 34 each(servers, function (server, callbackEach) {
31 utils.loginAndGetAccessToken(server, function (err, accessToken) { 35 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
32 if (err) return callbackEach(err) 36 if (err) return callbackEach(err)
33 37
34 server.accessToken = accessToken 38 server.accessToken = accessToken
@@ -39,7 +43,7 @@ describe('Test multiple pods', function () {
39 // The second pod make friend with the third 43 // The second pod make friend with the third
40 function (next) { 44 function (next) {
41 const server = servers[1] 45 const server = servers[1]
42 utils.makeFriends(server.url, server.accessToken, next) 46 podsUtils.makeFriends(server.url, server.accessToken, next)
43 }, 47 },
44 // Wait for the request between pods 48 // Wait for the request between pods
45 function (next) { 49 function (next) {
@@ -48,7 +52,7 @@ describe('Test multiple pods', function () {
48 // Pod 1 make friends too 52 // Pod 1 make friends too
49 function (next) { 53 function (next) {
50 const server = servers[0] 54 const server = servers[0]
51 utils.makeFriends(server.url, server.accessToken, next) 55 podsUtils.makeFriends(server.url, server.accessToken, next)
52 }, 56 },
53 function (next) { 57 function (next) {
54 webtorrent.create({ host: 'client', port: '1' }, next) 58 webtorrent.create({ host: 'client', port: '1' }, next)
@@ -58,7 +62,7 @@ describe('Test multiple pods', function () {
58 62
59 it('Should not have videos for all pods', function (done) { 63 it('Should not have videos for all pods', function (done) {
60 each(servers, function (server, callback) { 64 each(servers, function (server, callback) {
61 utils.getVideosList(server.url, function (err, res) { 65 videosUtils.getVideosList(server.url, function (err, res) {
62 if (err) throw err 66 if (err) throw err
63 67
64 const videos = res.body.data 68 const videos = res.body.data
@@ -80,7 +84,7 @@ describe('Test multiple pods', function () {
80 const description = 'my super description for pod 1' 84 const description = 'my super description for pod 1'
81 const tags = [ 'tag1p1', 'tag2p1' ] 85 const tags = [ 'tag1p1', 'tag2p1' ]
82 const file = 'video_short1.webm' 86 const file = 'video_short1.webm'
83 utils.uploadVideo(servers[0].url, servers[0].accessToken, name, description, tags, file, next) 87 videosUtils.uploadVideo(servers[0].url, servers[0].accessToken, name, description, tags, file, next)
84 }, 88 },
85 function (next) { 89 function (next) {
86 setTimeout(next, 11000) 90 setTimeout(next, 11000)
@@ -92,7 +96,7 @@ describe('Test multiple pods', function () {
92 each(servers, function (server, callback) { 96 each(servers, function (server, callback) {
93 let baseMagnet = null 97 let baseMagnet = null
94 98
95 utils.getVideosList(server.url, function (err, res) { 99 videosUtils.getVideosList(server.url, function (err, res) {
96 if (err) throw err 100 if (err) throw err
97 101
98 const videos = res.body.data 102 const videos = res.body.data
@@ -105,7 +109,7 @@ describe('Test multiple pods', function () {
105 expect(video.magnetUri).to.exist 109 expect(video.magnetUri).to.exist
106 expect(video.duration).to.equal(10) 110 expect(video.duration).to.equal(10)
107 expect(video.tags).to.deep.equal([ 'tag1p1', 'tag2p1' ]) 111 expect(video.tags).to.deep.equal([ 'tag1p1', 'tag2p1' ])
108 expect(utils.dateIsValid(video.createdDate)).to.be.true 112 expect(miscsUtils.dateIsValid(video.createdDate)).to.be.true
109 expect(video.author).to.equal('root') 113 expect(video.author).to.equal('root')
110 114
111 if (server.url !== 'http://localhost:9001') { 115 if (server.url !== 'http://localhost:9001') {
@@ -121,7 +125,7 @@ describe('Test multiple pods', function () {
121 expect(video.magnetUri).to.equal.magnetUri 125 expect(video.magnetUri).to.equal.magnetUri
122 } 126 }
123 127
124 utils.testImage(server.url, 'video_short1.webm', video.thumbnailPath, function (err, test) { 128 videosUtils.testVideoImage(server.url, 'video_short1.webm', video.thumbnailPath, function (err, test) {
125 if (err) throw err 129 if (err) throw err
126 expect(test).to.equal(true) 130 expect(test).to.equal(true)
127 131
@@ -142,7 +146,7 @@ describe('Test multiple pods', function () {
142 const description = 'my super description for pod 2' 146 const description = 'my super description for pod 2'
143 const tags = [ 'tag1p2', 'tag2p2', 'tag3p2' ] 147 const tags = [ 'tag1p2', 'tag2p2', 'tag3p2' ]
144 const file = 'video_short2.webm' 148 const file = 'video_short2.webm'
145 utils.uploadVideo(servers[1].url, servers[1].accessToken, name, description, tags, file, next) 149 videosUtils.uploadVideo(servers[1].url, servers[1].accessToken, name, description, tags, file, next)
146 }, 150 },
147 function (next) { 151 function (next) {
148 setTimeout(next, 11000) 152 setTimeout(next, 11000)
@@ -154,7 +158,7 @@ describe('Test multiple pods', function () {
154 each(servers, function (server, callback) { 158 each(servers, function (server, callback) {
155 let baseMagnet = null 159 let baseMagnet = null
156 160
157 utils.getVideosList(server.url, function (err, res) { 161 videosUtils.getVideosList(server.url, function (err, res) {
158 if (err) throw err 162 if (err) throw err
159 163
160 const videos = res.body.data 164 const videos = res.body.data
@@ -167,7 +171,7 @@ describe('Test multiple pods', function () {
167 expect(video.magnetUri).to.exist 171 expect(video.magnetUri).to.exist
168 expect(video.duration).to.equal(5) 172 expect(video.duration).to.equal(5)
169 expect(video.tags).to.deep.equal([ 'tag1p2', 'tag2p2', 'tag3p2' ]) 173 expect(video.tags).to.deep.equal([ 'tag1p2', 'tag2p2', 'tag3p2' ])
170 expect(utils.dateIsValid(video.createdDate)).to.be.true 174 expect(miscsUtils.dateIsValid(video.createdDate)).to.be.true
171 expect(video.author).to.equal('root') 175 expect(video.author).to.equal('root')
172 176
173 if (server.url !== 'http://localhost:9002') { 177 if (server.url !== 'http://localhost:9002') {
@@ -183,7 +187,7 @@ describe('Test multiple pods', function () {
183 expect(video.magnetUri).to.equal.magnetUri 187 expect(video.magnetUri).to.equal.magnetUri
184 } 188 }
185 189
186 utils.testImage(server.url, 'video_short2.webm', video.thumbnailPath, function (err, test) { 190 videosUtils.testVideoImage(server.url, 'video_short2.webm', video.thumbnailPath, function (err, test) {
187 if (err) throw err 191 if (err) throw err
188 expect(test).to.equal(true) 192 expect(test).to.equal(true)
189 193
@@ -204,14 +208,14 @@ describe('Test multiple pods', function () {
204 const description = 'my super description for pod 3' 208 const description = 'my super description for pod 3'
205 const tags = [ 'tag1p3' ] 209 const tags = [ 'tag1p3' ]
206 const file = 'video_short3.webm' 210 const file = 'video_short3.webm'
207 utils.uploadVideo(servers[2].url, servers[2].accessToken, name, description, tags, file, next) 211 videosUtils.uploadVideo(servers[2].url, servers[2].accessToken, name, description, tags, file, next)
208 }, 212 },
209 function (next) { 213 function (next) {
210 const name = 'my super name for pod 3-2' 214 const name = 'my super name for pod 3-2'
211 const description = 'my super description for pod 3-2' 215 const description = 'my super description for pod 3-2'
212 const tags = [ 'tag2p3', 'tag3p3', 'tag4p3' ] 216 const tags = [ 'tag2p3', 'tag3p3', 'tag4p3' ]
213 const file = 'video_short.webm' 217 const file = 'video_short.webm'
214 utils.uploadVideo(servers[2].url, servers[2].accessToken, name, description, tags, file, next) 218 videosUtils.uploadVideo(servers[2].url, servers[2].accessToken, name, description, tags, file, next)
215 }, 219 },
216 function (next) { 220 function (next) {
217 setTimeout(next, 22000) 221 setTimeout(next, 22000)
@@ -222,7 +226,7 @@ describe('Test multiple pods', function () {
222 let baseMagnet = null 226 let baseMagnet = null
223 // All pods should have this video 227 // All pods should have this video
224 each(servers, function (server, callback) { 228 each(servers, function (server, callback) {
225 utils.getVideosList(server.url, function (err, res) { 229 videosUtils.getVideosList(server.url, function (err, res) {
226 if (err) throw err 230 if (err) throw err
227 231
228 const videos = res.body.data 232 const videos = res.body.data
@@ -247,7 +251,7 @@ describe('Test multiple pods', function () {
247 expect(video1.duration).to.equal(5) 251 expect(video1.duration).to.equal(5)
248 expect(video1.tags).to.deep.equal([ 'tag1p3' ]) 252 expect(video1.tags).to.deep.equal([ 'tag1p3' ])
249 expect(video1.author).to.equal('root') 253 expect(video1.author).to.equal('root')
250 expect(utils.dateIsValid(video1.createdDate)).to.be.true 254 expect(miscsUtils.dateIsValid(video1.createdDate)).to.be.true
251 255
252 expect(video2.name).to.equal('my super name for pod 3-2') 256 expect(video2.name).to.equal('my super name for pod 3-2')
253 expect(video2.description).to.equal('my super description for pod 3-2') 257 expect(video2.description).to.equal('my super description for pod 3-2')
@@ -256,7 +260,7 @@ describe('Test multiple pods', function () {
256 expect(video2.duration).to.equal(5) 260 expect(video2.duration).to.equal(5)
257 expect(video2.tags).to.deep.equal([ 'tag2p3', 'tag3p3', 'tag4p3' ]) 261 expect(video2.tags).to.deep.equal([ 'tag2p3', 'tag3p3', 'tag4p3' ])
258 expect(video2.author).to.equal('root') 262 expect(video2.author).to.equal('root')
259 expect(utils.dateIsValid(video2.createdDate)).to.be.true 263 expect(miscsUtils.dateIsValid(video2.createdDate)).to.be.true
260 264
261 if (server.url !== 'http://localhost:9003') { 265 if (server.url !== 'http://localhost:9003') {
262 expect(video1.isLocal).to.be.false 266 expect(video1.isLocal).to.be.false
@@ -273,11 +277,11 @@ describe('Test multiple pods', function () {
273 expect(video2.magnetUri).to.equal.magnetUri 277 expect(video2.magnetUri).to.equal.magnetUri
274 } 278 }
275 279
276 utils.testImage(server.url, 'video_short3.webm', video1.thumbnailPath, function (err, test) { 280 videosUtils.testVideoImage(server.url, 'video_short3.webm', video1.thumbnailPath, function (err, test) {
277 if (err) throw err 281 if (err) throw err
278 expect(test).to.equal(true) 282 expect(test).to.equal(true)
279 283
280 utils.testImage(server.url, 'video_short.webm', video2.thumbnailPath, function (err, test) { 284 videosUtils.testVideoImage(server.url, 'video_short.webm', video2.thumbnailPath, function (err, test) {
281 if (err) throw err 285 if (err) throw err
282 expect(test).to.equal(true) 286 expect(test).to.equal(true)
283 287
@@ -296,7 +300,7 @@ describe('Test multiple pods', function () {
296 // Yes, this could be long 300 // Yes, this could be long
297 this.timeout(200000) 301 this.timeout(200000)
298 302
299 utils.getVideosList(servers[2].url, function (err, res) { 303 videosUtils.getVideosList(servers[2].url, function (err, res) {
300 if (err) throw err 304 if (err) throw err
301 305
302 const video = res.body.data[0] 306 const video = res.body.data[0]
@@ -317,7 +321,7 @@ describe('Test multiple pods', function () {
317 // Yes, this could be long 321 // Yes, this could be long
318 this.timeout(200000) 322 this.timeout(200000)
319 323
320 utils.getVideosList(servers[0].url, function (err, res) { 324 videosUtils.getVideosList(servers[0].url, function (err, res) {
321 if (err) throw err 325 if (err) throw err
322 326
323 const video = res.body.data[1] 327 const video = res.body.data[1]
@@ -336,7 +340,7 @@ describe('Test multiple pods', function () {
336 // Yes, this could be long 340 // Yes, this could be long
337 this.timeout(200000) 341 this.timeout(200000)
338 342
339 utils.getVideosList(servers[1].url, function (err, res) { 343 videosUtils.getVideosList(servers[1].url, function (err, res) {
340 if (err) throw err 344 if (err) throw err
341 345
342 const video = res.body.data[2] 346 const video = res.body.data[2]
@@ -355,7 +359,7 @@ describe('Test multiple pods', function () {
355 // Yes, this could be long 359 // Yes, this could be long
356 this.timeout(200000) 360 this.timeout(200000)
357 361
358 utils.getVideosList(servers[0].url, function (err, res) { 362 videosUtils.getVideosList(servers[0].url, function (err, res) {
359 if (err) throw err 363 if (err) throw err
360 364
361 const video = res.body.data[3] 365 const video = res.body.data[3]
@@ -375,10 +379,10 @@ describe('Test multiple pods', function () {
375 379
376 series([ 380 series([
377 function (next) { 381 function (next) {
378 utils.removeVideo(servers[2].url, servers[2].accessToken, toRemove[0], next) 382 videosUtils.removeVideo(servers[2].url, servers[2].accessToken, toRemove[0], next)
379 }, 383 },
380 function (next) { 384 function (next) {
381 utils.removeVideo(servers[2].url, servers[2].accessToken, toRemove[1], next) 385 videosUtils.removeVideo(servers[2].url, servers[2].accessToken, toRemove[1], next)
382 }], 386 }],
383 function (err) { 387 function (err) {
384 if (err) throw err 388 if (err) throw err
@@ -389,7 +393,7 @@ describe('Test multiple pods', function () {
389 393
390 it('Should have videos 1 and 3 on each pod', function (done) { 394 it('Should have videos 1 and 3 on each pod', function (done) {
391 each(servers, function (server, callback) { 395 each(servers, function (server, callback) {
392 utils.getVideosList(server.url, function (err, res) { 396 videosUtils.getVideosList(server.url, function (err, res) {
393 if (err) throw err 397 if (err) throw err
394 398
395 const videos = res.body.data 399 const videos = res.body.data
@@ -415,7 +419,7 @@ describe('Test multiple pods', function () {
415 419
416 // Keep the logs if the test failed 420 // Keep the logs if the test failed
417 if (this.ok) { 421 if (this.ok) {
418 utils.flushTests(done) 422 serversUtils.flushTests(done)
419 } else { 423 } else {
420 done() 424 done()
421 } 425 }
diff --git a/server/tests/api/requests.js b/server/tests/api/requests.js
new file mode 100644
index 000000000..af36f6e34
--- /dev/null
+++ b/server/tests/api/requests.js
@@ -0,0 +1,128 @@
1'use strict'
2
3const chai = require('chai')
4const each = require('async/each')
5const expect = chai.expect
6const request = require('supertest')
7
8const loginUtils = require('../utils/login')
9const podsUtils = require('../utils/pods')
10const serversUtils = require('../utils/servers')
11const videosUtils = require('../utils/videos')
12
13describe('Test requests stats', function () {
14 const path = '/api/v1/requests/stats'
15 let servers = []
16
17 function uploadVideo (server, callback) {
18 const name = 'my super video'
19 const description = 'my super description'
20 const tags = [ 'tag1', 'tag2' ]
21 const fixture = 'video_short.webm'
22
23 videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, fixture, callback)
24 }
25
26 function getRequestsStats (server, callback) {
27 request(server.url)
28 .get(path)
29 .set('Accept', 'application/json')
30 .set('Authorization', 'Bearer ' + server.accessToken)
31 .expect(200)
32 .end(callback)
33 }
34
35 // ---------------------------------------------------------------
36
37 before(function (done) {
38 this.timeout(20000)
39 serversUtils.flushAndRunMultipleServers(2, function (serversRun, urlsRun) {
40 servers = serversRun
41
42 each(servers, function (server, callbackEach) {
43 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
44 if (err) return callbackEach(err)
45
46 server.accessToken = accessToken
47 callbackEach()
48 })
49 }, function (err) {
50 if (err) throw err
51
52 const server1 = servers[0]
53 podsUtils.makeFriends(server1.url, server1.accessToken, done)
54 })
55 })
56 })
57
58 it('Should have a correct timer', function (done) {
59 const server = servers[0]
60
61 getRequestsStats(server, function (err, res) {
62 if (err) throw err
63
64 const body = res.body
65 expect(body.remainingMilliSeconds).to.be.at.least(0)
66 expect(body.remainingMilliSeconds).to.be.at.most(10000)
67
68 done()
69 })
70 })
71
72 it('Should have the correct request', function (done) {
73 this.timeout(15000)
74
75 const server = servers[0]
76 // Ensure the requests of pod 1 won't be made
77 servers[1].app.kill()
78
79 uploadVideo(server, function (err) {
80 if (err) throw err
81
82 getRequestsStats(server, function (err, res) {
83 if (err) throw err
84
85 const body = res.body
86 expect(body.requests).to.have.lengthOf(1)
87
88 const request = body.requests[0]
89 expect(request.to).to.have.lengthOf(1)
90 expect(request.request.type).to.equal('add')
91
92 // Wait one cycle
93 setTimeout(done, 10000)
94 })
95 })
96 })
97
98 it('Should have the correct requests', function (done) {
99 const server = servers[0]
100
101 uploadVideo(server, function (err) {
102 if (err) throw err
103
104 getRequestsStats(server, function (err, res) {
105 if (err) throw err
106
107 const body = res.body
108 expect(body.requests).to.have.lengthOf(2)
109
110 const request = body.requests[1]
111 expect(request.to).to.have.lengthOf(1)
112 expect(request.request.type).to.equal('add')
113
114 done()
115 })
116 })
117 })
118
119 after(function (done) {
120 process.kill(-servers[0].app.pid)
121
122 if (this.ok) {
123 serversUtils.flushTests(done)
124 } else {
125 done()
126 }
127 })
128})
diff --git a/server/tests/api/singlePod.js b/server/tests/api/single-pod.js
index 6ed719f87..bdaaee46c 100644
--- a/server/tests/api/singlePod.js
+++ b/server/tests/api/single-pod.js
@@ -8,11 +8,13 @@ const keyBy = require('lodash/keyBy')
8const pathUtils = require('path') 8const pathUtils = require('path')
9const series = require('async/series') 9const series = require('async/series')
10 10
11const loginUtils = require('../utils/login')
12const miscsUtils = require('../utils/miscs')
13const serversUtils = require('../utils/servers')
14const videosUtils = require('../utils/videos')
11const webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent')) 15const webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent'))
12webtorrent.silent = true 16webtorrent.silent = true
13 17
14const utils = require('./utils')
15
16describe('Test a single pod', function () { 18describe('Test a single pod', function () {
17 let server = null 19 let server = null
18 let videoId = -1 20 let videoId = -1
@@ -23,16 +25,16 @@ describe('Test a single pod', function () {
23 25
24 series([ 26 series([
25 function (next) { 27 function (next) {
26 utils.flushTests(next) 28 serversUtils.flushTests(next)
27 }, 29 },
28 function (next) { 30 function (next) {
29 utils.runServer(1, function (server1) { 31 serversUtils.runServer(1, function (server1) {
30 server = server1 32 server = server1
31 next() 33 next()
32 }) 34 })
33 }, 35 },
34 function (next) { 36 function (next) {
35 utils.loginAndGetAccessToken(server, function (err, token) { 37 loginUtils.loginAndGetAccessToken(server, function (err, token) {
36 if (err) throw err 38 if (err) throw err
37 server.accessToken = token 39 server.accessToken = token
38 next() 40 next()
@@ -45,7 +47,7 @@ describe('Test a single pod', function () {
45 }) 47 })
46 48
47 it('Should not have videos', function (done) { 49 it('Should not have videos', function (done) {
48 utils.getVideosList(server.url, function (err, res) { 50 videosUtils.getVideosList(server.url, function (err, res) {
49 if (err) throw err 51 if (err) throw err
50 52
51 expect(res.body.total).to.equal(0) 53 expect(res.body.total).to.equal(0)
@@ -62,14 +64,14 @@ describe('Test a single pod', function () {
62 const description = 'my super description' 64 const description = 'my super description'
63 const tags = [ 'tag1', 'tag2', 'tag3' ] 65 const tags = [ 'tag1', 'tag2', 'tag3' ]
64 const file = 'video_short.webm' 66 const file = 'video_short.webm'
65 utils.uploadVideo(server.url, server.accessToken, name, description, tags, file, done) 67 videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, file, done)
66 }) 68 })
67 69
68 it('Should seed the uploaded video', function (done) { 70 it('Should seed the uploaded video', function (done) {
69 // Yes, this could be long 71 // Yes, this could be long
70 this.timeout(60000) 72 this.timeout(60000)
71 73
72 utils.getVideosList(server.url, function (err, res) { 74 videosUtils.getVideosList(server.url, function (err, res) {
73 if (err) throw err 75 if (err) throw err
74 76
75 expect(res.body.total).to.equal(1) 77 expect(res.body.total).to.equal(1)
@@ -84,9 +86,9 @@ describe('Test a single pod', function () {
84 expect(video.author).to.equal('root') 86 expect(video.author).to.equal('root')
85 expect(video.isLocal).to.be.true 87 expect(video.isLocal).to.be.true
86 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 88 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
87 expect(utils.dateIsValid(video.createdDate)).to.be.true 89 expect(miscsUtils.dateIsValid(video.createdDate)).to.be.true
88 90
89 utils.testImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) { 91 videosUtils.testVideoImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) {
90 if (err) throw err 92 if (err) throw err
91 expect(test).to.equal(true) 93 expect(test).to.equal(true)
92 94
@@ -97,8 +99,7 @@ describe('Test a single pod', function () {
97 expect(torrent.files.length).to.equal(1) 99 expect(torrent.files.length).to.equal(1)
98 expect(torrent.files[0].path).to.exist.and.to.not.equal('') 100 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
99 101
100 // We remove it because we'll add it again 102 done()
101 webtorrent.remove(video.magnetUri, done)
102 }) 103 })
103 }) 104 })
104 }) 105 })
@@ -108,7 +109,7 @@ describe('Test a single pod', function () {
108 // Yes, this could be long 109 // Yes, this could be long
109 this.timeout(60000) 110 this.timeout(60000)
110 111
111 utils.getVideo(server.url, videoId, function (err, res) { 112 videosUtils.getVideo(server.url, videoId, function (err, res) {
112 if (err) throw err 113 if (err) throw err
113 114
114 const video = res.body 115 const video = res.body
@@ -119,25 +120,19 @@ describe('Test a single pod', function () {
119 expect(video.author).to.equal('root') 120 expect(video.author).to.equal('root')
120 expect(video.isLocal).to.be.true 121 expect(video.isLocal).to.be.true
121 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 122 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
122 expect(utils.dateIsValid(video.createdDate)).to.be.true 123 expect(miscsUtils.dateIsValid(video.createdDate)).to.be.true
123 124
124 utils.testImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) { 125 videosUtils.testVideoImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) {
125 if (err) throw err 126 if (err) throw err
126 expect(test).to.equal(true) 127 expect(test).to.equal(true)
127 128
128 webtorrent.add(video.magnetUri, function (torrent) { 129 done()
129 expect(torrent.files).to.exist
130 expect(torrent.files.length).to.equal(1)
131 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
132
133 done()
134 })
135 }) 130 })
136 }) 131 })
137 }) 132 })
138 133
139 it('Should search the video by name by default', function (done) { 134 it('Should search the video by name by default', function (done) {
140 utils.searchVideo(server.url, 'my', function (err, res) { 135 videosUtils.searchVideo(server.url, 'my', function (err, res) {
141 if (err) throw err 136 if (err) throw err
142 137
143 expect(res.body.total).to.equal(1) 138 expect(res.body.total).to.equal(1)
@@ -151,9 +146,9 @@ describe('Test a single pod', function () {
151 expect(video.author).to.equal('root') 146 expect(video.author).to.equal('root')
152 expect(video.isLocal).to.be.true 147 expect(video.isLocal).to.be.true
153 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 148 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
154 expect(utils.dateIsValid(video.createdDate)).to.be.true 149 expect(miscsUtils.dateIsValid(video.createdDate)).to.be.true
155 150
156 utils.testImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) { 151 videosUtils.testVideoImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) {
157 if (err) throw err 152 if (err) throw err
158 expect(test).to.equal(true) 153 expect(test).to.equal(true)
159 154
@@ -163,7 +158,7 @@ describe('Test a single pod', function () {
163 }) 158 })
164 159
165 it('Should search the video by podUrl', function (done) { 160 it('Should search the video by podUrl', function (done) {
166 utils.searchVideo(server.url, '9001', 'podUrl', function (err, res) { 161 videosUtils.searchVideo(server.url, '9001', 'podUrl', function (err, res) {
167 if (err) throw err 162 if (err) throw err
168 163
169 expect(res.body.total).to.equal(1) 164 expect(res.body.total).to.equal(1)
@@ -177,9 +172,9 @@ describe('Test a single pod', function () {
177 expect(video.author).to.equal('root') 172 expect(video.author).to.equal('root')
178 expect(video.isLocal).to.be.true 173 expect(video.isLocal).to.be.true
179 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 174 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
180 expect(utils.dateIsValid(video.createdDate)).to.be.true 175 expect(miscsUtils.dateIsValid(video.createdDate)).to.be.true
181 176
182 utils.testImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) { 177 videosUtils.testVideoImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) {
183 if (err) throw err 178 if (err) throw err
184 expect(test).to.equal(true) 179 expect(test).to.equal(true)
185 180
@@ -189,7 +184,7 @@ describe('Test a single pod', function () {
189 }) 184 })
190 185
191 it('Should search the video by tag', function (done) { 186 it('Should search the video by tag', function (done) {
192 utils.searchVideo(server.url, 'tag1', 'tags', function (err, res) { 187 videosUtils.searchVideo(server.url, 'tag1', 'tags', function (err, res) {
193 if (err) throw err 188 if (err) throw err
194 189
195 expect(res.body.total).to.equal(1) 190 expect(res.body.total).to.equal(1)
@@ -203,9 +198,9 @@ describe('Test a single pod', function () {
203 expect(video.author).to.equal('root') 198 expect(video.author).to.equal('root')
204 expect(video.isLocal).to.be.true 199 expect(video.isLocal).to.be.true
205 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 200 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
206 expect(utils.dateIsValid(video.createdDate)).to.be.true 201 expect(miscsUtils.dateIsValid(video.createdDate)).to.be.true
207 202
208 utils.testImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) { 203 videosUtils.testVideoImage(server.url, 'video_short.webm', video.thumbnailPath, function (err, test) {
209 if (err) throw err 204 if (err) throw err
210 expect(test).to.equal(true) 205 expect(test).to.equal(true)
211 206
@@ -215,7 +210,7 @@ describe('Test a single pod', function () {
215 }) 210 })
216 211
217 it('Should not find a search by name by default', function (done) { 212 it('Should not find a search by name by default', function (done) {
218 utils.searchVideo(server.url, 'hello', function (err, res) { 213 videosUtils.searchVideo(server.url, 'hello', function (err, res) {
219 if (err) throw err 214 if (err) throw err
220 215
221 expect(res.body.total).to.equal(0) 216 expect(res.body.total).to.equal(0)
@@ -227,7 +222,7 @@ describe('Test a single pod', function () {
227 }) 222 })
228 223
229 it('Should not find a search by author', function (done) { 224 it('Should not find a search by author', function (done) {
230 utils.searchVideo(server.url, 'hello', 'author', function (err, res) { 225 videosUtils.searchVideo(server.url, 'hello', 'author', function (err, res) {
231 if (err) throw err 226 if (err) throw err
232 227
233 expect(res.body.total).to.equal(0) 228 expect(res.body.total).to.equal(0)
@@ -239,7 +234,7 @@ describe('Test a single pod', function () {
239 }) 234 })
240 235
241 it('Should not find a search by tag', function (done) { 236 it('Should not find a search by tag', function (done) {
242 utils.searchVideo(server.url, 'tag', 'tags', function (err, res) { 237 videosUtils.searchVideo(server.url, 'tag', 'tags', function (err, res) {
243 if (err) throw err 238 if (err) throw err
244 239
245 expect(res.body.total).to.equal(0) 240 expect(res.body.total).to.equal(0)
@@ -251,7 +246,7 @@ describe('Test a single pod', function () {
251 }) 246 })
252 247
253 it('Should remove the video', function (done) { 248 it('Should remove the video', function (done) {
254 utils.removeVideo(server.url, server.accessToken, videoId, function (err) { 249 videosUtils.removeVideo(server.url, server.accessToken, videoId, function (err) {
255 if (err) throw err 250 if (err) throw err
256 251
257 fs.readdir(pathUtils.join(__dirname, '../../../test1/uploads/'), function (err, files) { 252 fs.readdir(pathUtils.join(__dirname, '../../../test1/uploads/'), function (err, files) {
@@ -264,7 +259,7 @@ describe('Test a single pod', function () {
264 }) 259 })
265 260
266 it('Should not have videos', function (done) { 261 it('Should not have videos', function (done) {
267 utils.getVideosList(server.url, function (err, res) { 262 videosUtils.getVideosList(server.url, function (err, res) {
268 if (err) throw err 263 if (err) throw err
269 264
270 expect(res.body.total).to.equal(0) 265 expect(res.body.total).to.equal(0)
@@ -286,12 +281,12 @@ describe('Test a single pod', function () {
286 const description = video + ' description' 281 const description = video + ' description'
287 const tags = [ 'tag1', 'tag2', 'tag3' ] 282 const tags = [ 'tag1', 'tag2', 'tag3' ]
288 283
289 utils.uploadVideo(server.url, server.accessToken, name, description, tags, video, callbackEach) 284 videosUtils.uploadVideo(server.url, server.accessToken, name, description, tags, video, callbackEach)
290 }, done) 285 }, done)
291 }) 286 })
292 287
293 it('Should have the correct durations', function (done) { 288 it('Should have the correct durations', function (done) {
294 utils.getVideosList(server.url, function (err, res) { 289 videosUtils.getVideosList(server.url, function (err, res) {
295 if (err) throw err 290 if (err) throw err
296 291
297 expect(res.body.total).to.equal(6) 292 expect(res.body.total).to.equal(6)
@@ -312,7 +307,7 @@ describe('Test a single pod', function () {
312 }) 307 })
313 308
314 it('Should have the correct thumbnails', function (done) { 309 it('Should have the correct thumbnails', function (done) {
315 utils.getVideosList(server.url, function (err, res) { 310 videosUtils.getVideosList(server.url, function (err, res) {
316 if (err) throw err 311 if (err) throw err
317 312
318 const videos = res.body.data 313 const videos = res.body.data
@@ -323,7 +318,7 @@ describe('Test a single pod', function () {
323 if (err) throw err 318 if (err) throw err
324 const videoName = video.name.replace(' name', '') 319 const videoName = video.name.replace(' name', '')
325 320
326 utils.testImage(server.url, videoName, video.thumbnailPath, function (err, test) { 321 videosUtils.testVideoImage(server.url, videoName, video.thumbnailPath, function (err, test) {
327 if (err) throw err 322 if (err) throw err
328 323
329 expect(test).to.equal(true) 324 expect(test).to.equal(true)
@@ -334,7 +329,7 @@ describe('Test a single pod', function () {
334 }) 329 })
335 330
336 it('Should list only the two first videos', function (done) { 331 it('Should list only the two first videos', function (done) {
337 utils.getVideosListPagination(server.url, 0, 2, function (err, res) { 332 videosUtils.getVideosListPagination(server.url, 0, 2, function (err, res) {
338 if (err) throw err 333 if (err) throw err
339 334
340 const videos = res.body.data 335 const videos = res.body.data
@@ -348,7 +343,7 @@ describe('Test a single pod', function () {
348 }) 343 })
349 344
350 it('Should list only the next three videos', function (done) { 345 it('Should list only the next three videos', function (done) {
351 utils.getVideosListPagination(server.url, 2, 3, function (err, res) { 346 videosUtils.getVideosListPagination(server.url, 2, 3, function (err, res) {
352 if (err) throw err 347 if (err) throw err
353 348
354 const videos = res.body.data 349 const videos = res.body.data
@@ -363,7 +358,7 @@ describe('Test a single pod', function () {
363 }) 358 })
364 359
365 it('Should list the last video', function (done) { 360 it('Should list the last video', function (done) {
366 utils.getVideosListPagination(server.url, 5, 6, function (err, res) { 361 videosUtils.getVideosListPagination(server.url, 5, 6, function (err, res) {
367 if (err) throw err 362 if (err) throw err
368 363
369 const videos = res.body.data 364 const videos = res.body.data
@@ -376,7 +371,7 @@ describe('Test a single pod', function () {
376 }) 371 })
377 372
378 it('Should search the first video', function (done) { 373 it('Should search the first video', function (done) {
379 utils.searchVideoWithPagination(server.url, 'webm', 'name', 0, 1, function (err, res) { 374 videosUtils.searchVideoWithPagination(server.url, 'webm', 'name', 0, 1, function (err, res) {
380 if (err) throw err 375 if (err) throw err
381 376
382 const videos = res.body.data 377 const videos = res.body.data
@@ -389,7 +384,7 @@ describe('Test a single pod', function () {
389 }) 384 })
390 385
391 it('Should search the last two videos', function (done) { 386 it('Should search the last two videos', function (done) {
392 utils.searchVideoWithPagination(server.url, 'webm', 'name', 2, 2, function (err, res) { 387 videosUtils.searchVideoWithPagination(server.url, 'webm', 'name', 2, 2, function (err, res) {
393 if (err) throw err 388 if (err) throw err
394 389
395 const videos = res.body.data 390 const videos = res.body.data
@@ -403,7 +398,7 @@ describe('Test a single pod', function () {
403 }) 398 })
404 399
405 it('Should search all the webm videos', function (done) { 400 it('Should search all the webm videos', function (done) {
406 utils.searchVideoWithPagination(server.url, 'webm', 'name', 0, 15, function (err, res) { 401 videosUtils.searchVideoWithPagination(server.url, 'webm', 'name', 0, 15, function (err, res) {
407 if (err) throw err 402 if (err) throw err
408 403
409 const videos = res.body.data 404 const videos = res.body.data
@@ -415,7 +410,7 @@ describe('Test a single pod', function () {
415 }) 410 })
416 411
417 it('Should search all the root author videos', function (done) { 412 it('Should search all the root author videos', function (done) {
418 utils.searchVideoWithPagination(server.url, 'root', 'author', 0, 15, function (err, res) { 413 videosUtils.searchVideoWithPagination(server.url, 'root', 'author', 0, 15, function (err, res) {
419 if (err) throw err 414 if (err) throw err
420 415
421 const videos = res.body.data 416 const videos = res.body.data
@@ -427,7 +422,7 @@ describe('Test a single pod', function () {
427 }) 422 })
428 423
429 it('Should search all the 9001 port videos', function (done) { 424 it('Should search all the 9001 port videos', function (done) {
430 utils.searchVideoWithPagination(server.url, '9001', 'podUrl', 0, 15, function (err, res) { 425 videosUtils.searchVideoWithPagination(server.url, '9001', 'podUrl', 0, 15, function (err, res) {
431 if (err) throw err 426 if (err) throw err
432 427
433 const videos = res.body.data 428 const videos = res.body.data
@@ -439,7 +434,7 @@ describe('Test a single pod', function () {
439 }) 434 })
440 435
441 it('Should search all the localhost videos', function (done) { 436 it('Should search all the localhost videos', function (done) {
442 utils.searchVideoWithPagination(server.url, 'localhost', 'podUrl', 0, 15, function (err, res) { 437 videosUtils.searchVideoWithPagination(server.url, 'localhost', 'podUrl', 0, 15, function (err, res) {
443 if (err) throw err 438 if (err) throw err
444 439
445 const videos = res.body.data 440 const videos = res.body.data
@@ -452,7 +447,7 @@ describe('Test a single pod', function () {
452 447
453 it('Should search the good magnetUri video', function (done) { 448 it('Should search the good magnetUri video', function (done) {
454 const video = videosListBase[0] 449 const video = videosListBase[0]
455 utils.searchVideoWithPagination(server.url, encodeURIComponent(video.magnetUri), 'magnetUri', 0, 15, function (err, res) { 450 videosUtils.searchVideoWithPagination(server.url, encodeURIComponent(video.magnetUri), 'magnetUri', 0, 15, function (err, res) {
456 if (err) throw err 451 if (err) throw err
457 452
458 const videos = res.body.data 453 const videos = res.body.data
@@ -465,7 +460,7 @@ describe('Test a single pod', function () {
465 }) 460 })
466 461
467 it('Should list and sort by name in descending order', function (done) { 462 it('Should list and sort by name in descending order', function (done) {
468 utils.getVideosListSort(server.url, '-name', function (err, res) { 463 videosUtils.getVideosListSort(server.url, '-name', function (err, res) {
469 if (err) throw err 464 if (err) throw err
470 465
471 const videos = res.body.data 466 const videos = res.body.data
@@ -483,7 +478,7 @@ describe('Test a single pod', function () {
483 }) 478 })
484 479
485 it('Should search and sort by name in ascending order', function (done) { 480 it('Should search and sort by name in ascending order', function (done) {
486 utils.searchVideoWithSort(server.url, 'webm', 'name', function (err, res) { 481 videosUtils.searchVideoWithSort(server.url, 'webm', 'name', function (err, res) {
487 if (err) throw err 482 if (err) throw err
488 483
489 const videos = res.body.data 484 const videos = res.body.data
@@ -505,7 +500,7 @@ describe('Test a single pod', function () {
505 500
506 // Keep the logs if the test failed 501 // Keep the logs if the test failed
507 if (this.ok) { 502 if (this.ok) {
508 utils.flushTests(done) 503 serversUtils.flushTests(done)
509 } else { 504 } else {
510 done() 505 done()
511 } 506 }
diff --git a/server/tests/api/users.js b/server/tests/api/users.js
index 68ba9de33..c6c892bf2 100644
--- a/server/tests/api/users.js
+++ b/server/tests/api/users.js
@@ -5,25 +5,30 @@ const expect = chai.expect
5const pathUtils = require('path') 5const pathUtils = require('path')
6const series = require('async/series') 6const series = require('async/series')
7 7
8const loginUtils = require('../utils/login')
9const podsUtils = require('../utils/pods')
10const serversUtils = require('../utils/servers')
11const usersUtils = require('../utils/users')
12const videosUtils = require('../utils/videos')
8const webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent')) 13const webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent'))
9webtorrent.silent = true 14webtorrent.silent = true
10 15
11const utils = require('./utils')
12
13describe('Test users', function () { 16describe('Test users', function () {
14 let server = null 17 let server = null
15 let accessToken = null 18 let accessToken = null
16 let videoId 19 let accessTokenUser = null
20 let videoId = null
21 let userId = null
17 22
18 before(function (done) { 23 before(function (done) {
19 this.timeout(20000) 24 this.timeout(20000)
20 25
21 series([ 26 series([
22 function (next) { 27 function (next) {
23 utils.flushTests(next) 28 serversUtils.flushTests(next)
24 }, 29 },
25 function (next) { 30 function (next) {
26 utils.runServer(1, function (server1) { 31 serversUtils.runServer(1, function (server1) {
27 server = server1 32 server = server1
28 next() 33 next()
29 }) 34 })
@@ -39,7 +44,7 @@ describe('Test users', function () {
39 44
40 it('Should not login with an invalid client id', function (done) { 45 it('Should not login with an invalid client id', function (done) {
41 const client = { id: 'client', password: server.client.secret } 46 const client = { id: 'client', password: server.client.secret }
42 utils.login(server.url, client, server.user, 400, function (err, res) { 47 loginUtils.login(server.url, client, server.user, 400, function (err, res) {
43 if (err) throw err 48 if (err) throw err
44 49
45 expect(res.body.error).to.equal('invalid_client') 50 expect(res.body.error).to.equal('invalid_client')
@@ -49,7 +54,7 @@ describe('Test users', function () {
49 54
50 it('Should not login with an invalid client password', function (done) { 55 it('Should not login with an invalid client password', function (done) {
51 const client = { id: server.client.id, password: 'coucou' } 56 const client = { id: server.client.id, password: 'coucou' }
52 utils.login(server.url, client, server.user, 400, function (err, res) { 57 loginUtils.login(server.url, client, server.user, 400, function (err, res) {
53 if (err) throw err 58 if (err) throw err
54 59
55 expect(res.body.error).to.equal('invalid_client') 60 expect(res.body.error).to.equal('invalid_client')
@@ -59,7 +64,7 @@ describe('Test users', function () {
59 64
60 it('Should not login with an invalid username', function (done) { 65 it('Should not login with an invalid username', function (done) {
61 const user = { username: 'captain crochet', password: server.user.password } 66 const user = { username: 'captain crochet', password: server.user.password }
62 utils.login(server.url, server.client, user, 400, function (err, res) { 67 loginUtils.login(server.url, server.client, user, 400, function (err, res) {
63 if (err) throw err 68 if (err) throw err
64 69
65 expect(res.body.error).to.equal('invalid_grant') 70 expect(res.body.error).to.equal('invalid_grant')
@@ -69,7 +74,7 @@ describe('Test users', function () {
69 74
70 it('Should not login with an invalid password', function (done) { 75 it('Should not login with an invalid password', function (done) {
71 const user = { username: server.user.username, password: 'mewthree' } 76 const user = { username: server.user.username, password: 'mewthree' }
72 utils.login(server.url, server.client, user, 400, function (err, res) { 77 loginUtils.login(server.url, server.client, user, 400, function (err, res) {
73 if (err) throw err 78 if (err) throw err
74 79
75 expect(res.body.error).to.equal('invalid_grant') 80 expect(res.body.error).to.equal('invalid_grant')
@@ -84,21 +89,21 @@ describe('Test users', function () {
84 const description = 'my super description' 89 const description = 'my super description'
85 const tags = [ 'tag1', 'tag2' ] 90 const tags = [ 'tag1', 'tag2' ]
86 const video = 'video_short.webm' 91 const video = 'video_short.webm'
87 utils.uploadVideo(server.url, accessToken, name, description, tags, video, 401, done) 92 videosUtils.uploadVideo(server.url, accessToken, name, description, tags, video, 401, done)
88 }) 93 })
89 94
90 it('Should not be able to make friends', function (done) { 95 it('Should not be able to make friends', function (done) {
91 accessToken = 'mysupertoken' 96 accessToken = 'mysupertoken'
92 utils.makeFriends(server.url, accessToken, 401, done) 97 podsUtils.makeFriends(server.url, accessToken, 401, done)
93 }) 98 })
94 99
95 it('Should not be able to quit friends', function (done) { 100 it('Should not be able to quit friends', function (done) {
96 accessToken = 'mysupertoken' 101 accessToken = 'mysupertoken'
97 utils.quitFriends(server.url, accessToken, 401, done) 102 podsUtils.quitFriends(server.url, accessToken, 401, done)
98 }) 103 })
99 104
100 it('Should be able to login', function (done) { 105 it('Should be able to login', function (done) {
101 utils.login(server.url, server.client, server.user, 200, function (err, res) { 106 loginUtils.login(server.url, server.client, server.user, 200, function (err, res) {
102 if (err) throw err 107 if (err) throw err
103 108
104 accessToken = res.body.access_token 109 accessToken = res.body.access_token
@@ -111,10 +116,10 @@ describe('Test users', function () {
111 const description = 'my super description' 116 const description = 'my super description'
112 const tags = [ 'tag1', 'tag2' ] 117 const tags = [ 'tag1', 'tag2' ]
113 const video = 'video_short.webm' 118 const video = 'video_short.webm'
114 utils.uploadVideo(server.url, accessToken, name, description, tags, video, 204, function (err, res) { 119 videosUtils.uploadVideo(server.url, accessToken, name, description, tags, video, 204, function (err, res) {
115 if (err) throw err 120 if (err) throw err
116 121
117 utils.getVideosList(server.url, function (err, res) { 122 videosUtils.getVideosList(server.url, function (err, res) {
118 if (err) throw err 123 if (err) throw err
119 124
120 const video = res.body.data[0] 125 const video = res.body.data[0]
@@ -131,17 +136,17 @@ describe('Test users', function () {
131 const description = 'my super description 2' 136 const description = 'my super description 2'
132 const tags = [ 'tag1' ] 137 const tags = [ 'tag1' ]
133 const video = 'video_short.webm' 138 const video = 'video_short.webm'
134 utils.uploadVideo(server.url, accessToken, name, description, tags, video, 204, done) 139 videosUtils.uploadVideo(server.url, accessToken, name, description, tags, video, 204, done)
135 }) 140 })
136 141
137 it('Should not be able to remove the video with an incorrect token', function (done) { 142 it('Should not be able to remove the video with an incorrect token', function (done) {
138 utils.removeVideo(server.url, 'bad_token', videoId, 401, done) 143 videosUtils.removeVideo(server.url, 'bad_token', videoId, 401, done)
139 }) 144 })
140 145
141 it('Should not be able to remove the video with the token of another account') 146 it('Should not be able to remove the video with the token of another account')
142 147
143 it('Should be able to remove the video with the correct token', function (done) { 148 it('Should be able to remove the video with the correct token', function (done) {
144 utils.removeVideo(server.url, accessToken, videoId, done) 149 videosUtils.removeVideo(server.url, accessToken, videoId, done)
145 }) 150 })
146 151
147 it('Should logout (revoke token)') 152 it('Should logout (revoke token)')
@@ -158,12 +163,179 @@ describe('Test users', function () {
158 163
159 it('Should be able to upload a video again') 164 it('Should be able to upload a video again')
160 165
166 it('Should be able to create a new user', function (done) {
167 usersUtils.createUser(server.url, accessToken, 'user_1', 'super password', done)
168 })
169
170 it('Should be able to login with this user', function (done) {
171 server.user = {
172 username: 'user_1',
173 password: 'super password'
174 }
175
176 loginUtils.loginAndGetAccessToken(server, function (err, token) {
177 if (err) throw err
178
179 accessTokenUser = token
180
181 done()
182 })
183 })
184
185 it('Should be able to get the user informations', function (done) {
186 usersUtils.getUserInformation(server.url, accessTokenUser, function (err, res) {
187 if (err) throw err
188
189 const user = res.body
190
191 expect(user.username).to.equal('user_1')
192 expect(user.id).to.exist
193
194 done()
195 })
196 })
197
198 it('Should be able to upload a video with this user', function (done) {
199 this.timeout(5000)
200
201 const name = 'my super name'
202 const description = 'my super description'
203 const tags = [ 'tag1', 'tag2', 'tag3' ]
204 const file = 'video_short.webm'
205 videosUtils.uploadVideo(server.url, accessTokenUser, name, description, tags, file, done)
206 })
207
208 it('Should list all the users', function (done) {
209 usersUtils.getUsersList(server.url, function (err, res) {
210 if (err) throw err
211
212 const result = res.body
213 const total = result.total
214 const users = result.data
215
216 expect(total).to.equal(2)
217 expect(users).to.be.an('array')
218 expect(users.length).to.equal(2)
219
220 const user = users[0]
221 expect(user.username).to.equal('user_1')
222
223 const rootUser = users[1]
224 expect(rootUser.username).to.equal('root')
225 userId = user.id
226
227 done()
228 })
229 })
230
231 it('Should list only the first user by username asc', function (done) {
232 usersUtils.getUsersListPaginationAndSort(server.url, 0, 1, 'username', function (err, res) {
233 if (err) throw err
234
235 const result = res.body
236 const total = result.total
237 const users = result.data
238
239 expect(total).to.equal(2)
240 expect(users.length).to.equal(1)
241
242 const user = users[0]
243 expect(user.username).to.equal('root')
244
245 done()
246 })
247 })
248
249 it('Should list only the first user by username desc', function (done) {
250 usersUtils.getUsersListPaginationAndSort(server.url, 0, 1, '-username', function (err, res) {
251 if (err) throw err
252
253 const result = res.body
254 const total = result.total
255 const users = result.data
256
257 expect(total).to.equal(2)
258 expect(users.length).to.equal(1)
259
260 const user = users[0]
261 expect(user.username).to.equal('user_1')
262
263 done()
264 })
265 })
266
267 it('Should list only the second user by createdDate desc', function (done) {
268 usersUtils.getUsersListPaginationAndSort(server.url, 0, 1, '-createdDate', function (err, res) {
269 if (err) throw err
270
271 const result = res.body
272 const total = result.total
273 const users = result.data
274
275 expect(total).to.equal(2)
276 expect(users.length).to.equal(1)
277
278 const user = users[0]
279 expect(user.username).to.equal('user_1')
280
281 done()
282 })
283 })
284
285 it('Should list all the users by createdDate asc', function (done) {
286 usersUtils.getUsersListPaginationAndSort(server.url, 0, 2, 'createdDate', function (err, res) {
287 if (err) throw err
288
289 const result = res.body
290 const total = result.total
291 const users = result.data
292
293 expect(total).to.equal(2)
294 expect(users.length).to.equal(2)
295
296 expect(users[0].username).to.equal('root')
297 expect(users[1].username).to.equal('user_1')
298
299 done()
300 })
301 })
302
303 it('Should update the user password', function (done) {
304 usersUtils.updateUser(server.url, userId, accessTokenUser, 'new password', function (err, res) {
305 if (err) throw err
306
307 server.user.password = 'new password'
308 loginUtils.login(server.url, server.client, server.user, 200, done)
309 })
310 })
311
312 it('Should be able to remove this user', function (done) {
313 usersUtils.removeUser(server.url, userId, accessToken, done)
314 })
315
316 it('Should not be able to login with this user', function (done) {
317 // server.user is already set to user 1
318 loginUtils.login(server.url, server.client, server.user, 400, done)
319 })
320
321 it('Should not have videos of this user', function (done) {
322 videosUtils.getVideosList(server.url, function (err, res) {
323 if (err) throw err
324
325 expect(res.body.total).to.equal(1)
326 const video = res.body.data[0]
327 expect(video.author).to.equal('root')
328
329 done()
330 })
331 })
332
161 after(function (done) { 333 after(function (done) {
162 process.kill(-server.app.pid) 334 process.kill(-server.app.pid)
163 335
164 // Keep the logs if the test failed 336 // Keep the logs if the test failed
165 if (this.ok) { 337 if (this.ok) {
166 utils.flushTests(done) 338 serversUtils.flushTests(done)
167 } else { 339 } else {
168 done() 340 done()
169 } 341 }
diff --git a/server/tests/api/utils.js b/server/tests/api/utils.js
deleted file mode 100644
index 3cc769f26..000000000
--- a/server/tests/api/utils.js
+++ /dev/null
@@ -1,419 +0,0 @@
1'use strict'
2
3const childProcess = require('child_process')
4const exec = childProcess.exec
5const fork = childProcess.fork
6const fs = require('fs')
7const pathUtils = require('path')
8const request = require('supertest')
9
10const testUtils = {
11 dateIsValid: dateIsValid,
12 flushTests: flushTests,
13 getAllVideosListBy: getAllVideosListBy,
14 getClient: getClient,
15 getFriendsList: getFriendsList,
16 getVideo: getVideo,
17 getVideosList: getVideosList,
18 getVideosListPagination: getVideosListPagination,
19 getVideosListSort: getVideosListSort,
20 login: login,
21 loginAndGetAccessToken: loginAndGetAccessToken,
22 makeFriends: makeFriends,
23 quitFriends: quitFriends,
24 removeVideo: removeVideo,
25 flushAndRunMultipleServers: flushAndRunMultipleServers,
26 runServer: runServer,
27 searchVideo: searchVideo,
28 searchVideoWithPagination: searchVideoWithPagination,
29 searchVideoWithSort: searchVideoWithSort,
30 testImage: testImage,
31 uploadVideo: uploadVideo
32}
33
34// ---------------------- Export functions --------------------
35
36function dateIsValid (dateString) {
37 const dateToCheck = new Date(dateString)
38 const now = new Date()
39
40 // Check if the interval is more than 2 minutes
41 if (now - dateToCheck > 120000) return false
42
43 return true
44}
45
46function flushTests (callback) {
47 exec('npm run clean:server:test', callback)
48}
49
50function getAllVideosListBy (url, end) {
51 const path = '/api/v1/videos'
52
53 request(url)
54 .get(path)
55 .query({ sort: 'createdDate' })
56 .query({ start: 0 })
57 .query({ count: 10000 })
58 .set('Accept', 'application/json')
59 .expect(200)
60 .expect('Content-Type', /json/)
61 .end(end)
62}
63
64function getClient (url, end) {
65 const path = '/api/v1/users/client'
66
67 request(url)
68 .get(path)
69 .set('Accept', 'application/json')
70 .expect(200)
71 .expect('Content-Type', /json/)
72 .end(end)
73}
74
75function getFriendsList (url, end) {
76 const path = '/api/v1/pods/'
77
78 request(url)
79 .get(path)
80 .set('Accept', 'application/json')
81 .expect(200)
82 .expect('Content-Type', /json/)
83 .end(end)
84}
85
86function getVideo (url, id, end) {
87 const path = '/api/v1/videos/' + id
88
89 request(url)
90 .get(path)
91 .set('Accept', 'application/json')
92 .expect(200)
93 .expect('Content-Type', /json/)
94 .end(end)
95}
96
97function getVideosList (url, end) {
98 const path = '/api/v1/videos'
99
100 request(url)
101 .get(path)
102 .query({ sort: 'name' })
103 .set('Accept', 'application/json')
104 .expect(200)
105 .expect('Content-Type', /json/)
106 .end(end)
107}
108
109function getVideosListPagination (url, start, count, end) {
110 const path = '/api/v1/videos'
111
112 request(url)
113 .get(path)
114 .query({ start: start })
115 .query({ count: count })
116 .set('Accept', 'application/json')
117 .expect(200)
118 .expect('Content-Type', /json/)
119 .end(end)
120}
121
122function getVideosListSort (url, sort, end) {
123 const path = '/api/v1/videos'
124
125 request(url)
126 .get(path)
127 .query({ sort: sort })
128 .set('Accept', 'application/json')
129 .expect(200)
130 .expect('Content-Type', /json/)
131 .end(end)
132}
133
134function login (url, client, user, expectedStatus, end) {
135 if (!end) {
136 end = expectedStatus
137 expectedStatus = 200
138 }
139
140 const path = '/api/v1/users/token'
141
142 const body = {
143 client_id: client.id,
144 client_secret: client.secret,
145 username: user.username,
146 password: user.password,
147 response_type: 'code',
148 grant_type: 'password',
149 scope: 'upload'
150 }
151
152 request(url)
153 .post(path)
154 .type('form')
155 .send(body)
156 .expect(expectedStatus)
157 .end(end)
158}
159
160function loginAndGetAccessToken (server, callback) {
161 login(server.url, server.client, server.user, 200, function (err, res) {
162 if (err) return callback(err)
163
164 return callback(null, res.body.access_token)
165 })
166}
167
168function makeFriends (url, accessToken, expectedStatus, callback) {
169 if (!callback) {
170 callback = expectedStatus
171 expectedStatus = 204
172 }
173
174 const path = '/api/v1/pods/makefriends'
175
176 // The first pod make friend with the third
177 request(url)
178 .get(path)
179 .set('Accept', 'application/json')
180 .set('Authorization', 'Bearer ' + accessToken)
181 .expect(expectedStatus)
182 .end(function (err, res) {
183 if (err) throw err
184
185 // Wait for the request between pods
186 setTimeout(callback, 1000)
187 })
188}
189
190function quitFriends (url, accessToken, expectedStatus, callback) {
191 if (!callback) {
192 callback = expectedStatus
193 expectedStatus = 204
194 }
195
196 const path = '/api/v1/pods/quitfriends'
197
198 // The first pod make friend with the third
199 request(url)
200 .get(path)
201 .set('Accept', 'application/json')
202 .set('Authorization', 'Bearer ' + accessToken)
203 .expect(expectedStatus)
204 .end(function (err, res) {
205 if (err) throw err
206
207 // Wait for the request between pods
208 setTimeout(callback, 1000)
209 })
210}
211
212function removeVideo (url, token, id, expectedStatus, end) {
213 if (!end) {
214 end = expectedStatus
215 expectedStatus = 204
216 }
217
218 const path = '/api/v1/videos'
219
220 request(url)
221 .delete(path + '/' + id)
222 .set('Accept', 'application/json')
223 .set('Authorization', 'Bearer ' + token)
224 .expect(expectedStatus)
225 .end(end)
226}
227
228function flushAndRunMultipleServers (totalServers, serversRun) {
229 let apps = []
230 let urls = []
231 let i = 0
232
233 function anotherServerDone (number, app, url) {
234 apps[number - 1] = app
235 urls[number - 1] = url
236 i++
237 if (i === totalServers) {
238 serversRun(apps, urls)
239 }
240 }
241
242 flushTests(function () {
243 for (let j = 1; j <= totalServers; j++) {
244 // For the virtual buffer
245 setTimeout(function () {
246 runServer(j, function (app, url) {
247 anotherServerDone(j, app, url)
248 })
249 }, 1000 * j)
250 }
251 })
252}
253
254function runServer (number, callback) {
255 const server = {
256 app: null,
257 url: `http://localhost:${9000 + number}`,
258 client: {
259 id: null,
260 secret: null
261 },
262 user: {
263 username: null,
264 password: null
265 }
266 }
267
268 // These actions are async so we need to be sure that they have both been done
269 const serverRunString = {
270 'Connected to mongodb': false,
271 'Server listening on port': false
272 }
273
274 const regexps = {
275 client_id: 'Client id: ([a-f0-9]+)',
276 client_secret: 'Client secret: (.+)',
277 user_username: 'Username: (.+)',
278 user_password: 'User password: (.+)'
279 }
280
281 // Share the environment
282 const env = Object.create(process.env)
283 env.NODE_ENV = 'test'
284 env.NODE_APP_INSTANCE = number
285 const options = {
286 silent: true,
287 env: env,
288 detached: true
289 }
290
291 server.app = fork(pathUtils.join(__dirname, '../../../server.js'), [], options)
292 server.app.stdout.on('data', function onStdout (data) {
293 let dontContinue = false
294
295 // Capture things if we want to
296 for (const key of Object.keys(regexps)) {
297 const regexp = regexps[key]
298 const matches = data.toString().match(regexp)
299 if (matches !== null) {
300 if (key === 'client_id') server.client.id = matches[1]
301 else if (key === 'client_secret') server.client.secret = matches[1]
302 else if (key === 'user_username') server.user.username = matches[1]
303 else if (key === 'user_password') server.user.password = matches[1]
304 }
305 }
306
307 // Check if all required sentences are here
308 for (const key of Object.keys(serverRunString)) {
309 if (data.toString().indexOf(key) !== -1) serverRunString[key] = true
310 if (serverRunString[key] === false) dontContinue = true
311 }
312
313 // If no, there is maybe one thing not already initialized (mongodb...)
314 if (dontContinue === true) return
315
316 server.app.stdout.removeListener('data', onStdout)
317 callback(server)
318 })
319}
320
321function searchVideo (url, search, field, end) {
322 if (!end) {
323 end = field
324 field = null
325 }
326
327 const path = '/api/v1/videos'
328 const req = request(url)
329 .get(path + '/search/' + search)
330 .set('Accept', 'application/json')
331
332 if (field) req.query({ field: field })
333 req.expect(200)
334 .expect('Content-Type', /json/)
335 .end(end)
336}
337
338function searchVideoWithPagination (url, search, field, start, count, end) {
339 const path = '/api/v1/videos'
340
341 request(url)
342 .get(path + '/search/' + search)
343 .query({ start: start })
344 .query({ count: count })
345 .query({ field: field })
346 .set('Accept', 'application/json')
347 .expect(200)
348 .expect('Content-Type', /json/)
349 .end(end)
350}
351
352function searchVideoWithSort (url, search, sort, end) {
353 const path = '/api/v1/videos'
354
355 request(url)
356 .get(path + '/search/' + search)
357 .query({ sort: sort })
358 .set('Accept', 'application/json')
359 .expect(200)
360 .expect('Content-Type', /json/)
361 .end(end)
362}
363
364function testImage (url, videoName, imagePath, callback) {
365 // Don't test images if the node env is not set
366 // Because we need a special ffmpeg version for this test
367 if (process.env.NODE_TEST_IMAGE) {
368 request(url)
369 .get(imagePath)
370 .expect(200)
371 .end(function (err, res) {
372 if (err) return callback(err)
373
374 fs.readFile(pathUtils.join(__dirname, 'fixtures', videoName + '.jpg'), function (err, data) {
375 if (err) return callback(err)
376
377 callback(null, data.equals(res.body))
378 })
379 })
380 } else {
381 console.log('Do not test images. Enable it by setting NODE_TEST_IMAGE env variable.')
382 callback(null, true)
383 }
384}
385
386function uploadVideo (url, accessToken, name, description, tags, fixture, specialStatus, end) {
387 if (!end) {
388 end = specialStatus
389 specialStatus = 204
390 }
391
392 const path = '/api/v1/videos'
393
394 const req = request(url)
395 .post(path)
396 .set('Accept', 'application/json')
397 .set('Authorization', 'Bearer ' + accessToken)
398 .field('name', name)
399 .field('description', description)
400
401 for (let i = 0; i < tags.length; i++) {
402 req.field('tags[' + i + ']', tags[i])
403 }
404
405 let filepath = ''
406 if (pathUtils.isAbsolute(fixture)) {
407 filepath = fixture
408 } else {
409 filepath = pathUtils.join(__dirname, 'fixtures', fixture)
410 }
411
412 req.attach('videofile', filepath)
413 .expect(specialStatus)
414 .end(end)
415}
416
417// ---------------------------------------------------------------------------
418
419module.exports = testUtils
diff --git a/server/tests/real-world/real-world.js b/server/tests/real-world/real-world.js
index b28796852..dba1970c5 100644
--- a/server/tests/real-world/real-world.js
+++ b/server/tests/real-world/real-world.js
@@ -1,6 +1,6 @@
1'use strict' 1'use strict'
2 2
3const each = require('each') 3const each = require('async/each')
4const isEqual = require('lodash/isEqual') 4const isEqual = require('lodash/isEqual')
5const program = require('commander') 5const program = require('commander')
6const series = require('async/series') 6const series = require('async/series')
@@ -8,7 +8,10 @@ const series = require('async/series')
8process.env.NODE_ENV = 'test' 8process.env.NODE_ENV = 'test'
9const constants = require('../../initializers/constants') 9const constants = require('../../initializers/constants')
10 10
11const utils = require('../api/utils') 11const loginUtils = require('../utils/login')
12const podsUtils = require('../utils/pods')
13const serversUtils = require('../utils/servers')
14const videosUtils = require('../utils/videos')
12 15
13program 16program
14 .option('-c, --create [weight]', 'Weight for creating videos') 17 .option('-c, --create [weight]', 'Weight for creating videos')
@@ -97,7 +100,7 @@ function runServers (numberOfPods, callback) {
97 series([ 100 series([
98 // Run servers 101 // Run servers
99 function (next) { 102 function (next) {
100 utils.flushAndRunMultipleServers(numberOfPods, function (serversRun) { 103 serversUtils.flushAndRunMultipleServers(numberOfPods, function (serversRun) {
101 servers = serversRun 104 servers = serversRun
102 next() 105 next()
103 }) 106 })
@@ -105,7 +108,7 @@ function runServers (numberOfPods, callback) {
105 // Get the access tokens 108 // Get the access tokens
106 function (next) { 109 function (next) {
107 each(servers, function (server, callbackEach) { 110 each(servers, function (server, callbackEach) {
108 utils.loginAndGetAccessToken(server, function (err, accessToken) { 111 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
109 if (err) return callbackEach(err) 112 if (err) return callbackEach(err)
110 113
111 server.accessToken = accessToken 114 server.accessToken = accessToken
@@ -115,26 +118,26 @@ function runServers (numberOfPods, callback) {
115 }, 118 },
116 function (next) { 119 function (next) {
117 const server = servers[1] 120 const server = servers[1]
118 utils.makeFriends(server.url, server.accessToken, next) 121 podsUtils.makeFriends(server.url, server.accessToken, next)
119 }, 122 },
120 function (next) { 123 function (next) {
121 const server = servers[0] 124 const server = servers[0]
122 utils.makeFriends(server.url, server.accessToken, next) 125 podsUtils.makeFriends(server.url, server.accessToken, next)
123 }, 126 },
124 function (next) { 127 function (next) {
125 setTimeout(next, 1000) 128 setTimeout(next, 1000)
126 }, 129 },
127 function (next) { 130 function (next) {
128 const server = servers[3] 131 const server = servers[3]
129 utils.makeFriends(server.url, server.accessToken, next) 132 podsUtils.makeFriends(server.url, server.accessToken, next)
130 }, 133 },
131 function (next) { 134 function (next) {
132 const server = servers[5] 135 const server = servers[5]
133 utils.makeFriends(server.url, server.accessToken, next) 136 podsUtils.makeFriends(server.url, server.accessToken, next)
134 }, 137 },
135 function (next) { 138 function (next) {
136 const server = servers[4] 139 const server = servers[4]
137 utils.makeFriends(server.url, server.accessToken, next) 140 podsUtils.makeFriends(server.url, server.accessToken, next)
138 }, 141 },
139 function (next) { 142 function (next) {
140 setTimeout(next, 1000) 143 setTimeout(next, 1000)
@@ -151,7 +154,7 @@ function exitServers (servers, callback) {
151 if (server.app) process.kill(-server.app.pid) 154 if (server.app) process.kill(-server.app.pid)
152 }) 155 })
153 156
154 if (flushAtExit) utils.flushTests(callback) 157 if (flushAtExit) serversUtils.flushTests(callback)
155} 158}
156 159
157function upload (servers, numServer, callback) { 160function upload (servers, numServer, callback) {
@@ -164,13 +167,13 @@ function upload (servers, numServer, callback) {
164 167
165 console.log('Upload video to server ' + numServer) 168 console.log('Upload video to server ' + numServer)
166 169
167 utils.uploadVideo(servers[numServer].url, servers[numServer].accessToken, name, description, tags, file, callback) 170 videosUtils.uploadVideo(servers[numServer].url, servers[numServer].accessToken, name, description, tags, file, callback)
168} 171}
169 172
170function remove (servers, numServer, callback) { 173function remove (servers, numServer, callback) {
171 if (!callback) callback = function () {} 174 if (!callback) callback = function () {}
172 175
173 utils.getVideosList(servers[numServer].url, function (err, res) { 176 videosUtils.getVideosList(servers[numServer].url, function (err, res) {
174 if (err) throw err 177 if (err) throw err
175 178
176 const videos = res.body.data 179 const videos = res.body.data
@@ -179,14 +182,14 @@ function remove (servers, numServer, callback) {
179 const toRemove = videos[getRandomInt(0, videos.length)].id 182 const toRemove = videos[getRandomInt(0, videos.length)].id
180 183
181 console.log('Removing video from server ' + numServer) 184 console.log('Removing video from server ' + numServer)
182 utils.removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove, callback) 185 videosUtils.removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove, callback)
183 }) 186 })
184} 187}
185 188
186function checkIntegrity (servers, callback) { 189function checkIntegrity (servers, callback) {
187 const videos = [] 190 const videos = []
188 each(servers, function (server, callback) { 191 each(servers, function (server, callback) {
189 utils.getAllVideosListBy(server.url, function (err, res) { 192 videosUtils.getAllVideosListBy(server.url, function (err, res) {
190 if (err) throw err 193 if (err) throw err
191 const serverVideos = res.body.data 194 const serverVideos = res.body.data
192 for (const serverVideo of serverVideos) { 195 for (const serverVideo of serverVideos) {
diff --git a/server/tests/utils/clients.js b/server/tests/utils/clients.js
new file mode 100644
index 000000000..e3ded493e
--- /dev/null
+++ b/server/tests/utils/clients.js
@@ -0,0 +1,24 @@
1'use strict'
2
3const request = require('supertest')
4
5const clientsUtils = {
6 getClient: getClient
7}
8
9// ---------------------- Export functions --------------------
10
11function getClient (url, end) {
12 const path = '/api/v1/users/client'
13
14 request(url)
15 .get(path)
16 .set('Accept', 'application/json')
17 .expect(200)
18 .expect('Content-Type', /json/)
19 .end(end)
20}
21
22// ---------------------------------------------------------------------------
23
24module.exports = clientsUtils
diff --git a/server/tests/utils/login.js b/server/tests/utils/login.js
new file mode 100644
index 000000000..465564e14
--- /dev/null
+++ b/server/tests/utils/login.js
@@ -0,0 +1,48 @@
1'use strict'
2
3const request = require('supertest')
4
5const loginUtils = {
6 login,
7 loginAndGetAccessToken
8}
9
10// ---------------------- Export functions --------------------
11
12function login (url, client, user, expectedStatus, end) {
13 if (!end) {
14 end = expectedStatus
15 expectedStatus = 200
16 }
17
18 const path = '/api/v1/users/token'
19
20 const body = {
21 client_id: client.id,
22 client_secret: client.secret,
23 username: user.username,
24 password: user.password,
25 response_type: 'code',
26 grant_type: 'password',
27 scope: 'upload'
28 }
29
30 request(url)
31 .post(path)
32 .type('form')
33 .send(body)
34 .expect(expectedStatus)
35 .end(end)
36}
37
38function loginAndGetAccessToken (server, callback) {
39 login(server.url, server.client, server.user, 200, function (err, res) {
40 if (err) return callback(err)
41
42 return callback(null, res.body.access_token)
43 })
44}
45
46// ---------------------------------------------------------------------------
47
48module.exports = loginUtils
diff --git a/server/tests/utils/miscs.js b/server/tests/utils/miscs.js
new file mode 100644
index 000000000..4ceff65df
--- /dev/null
+++ b/server/tests/utils/miscs.js
@@ -0,0 +1,21 @@
1'use strict'
2
3const miscsUtils = {
4 dateIsValid
5}
6
7// ---------------------- Export functions --------------------
8
9function dateIsValid (dateString) {
10 const dateToCheck = new Date(dateString)
11 const now = new Date()
12
13 // Check if the interval is more than 2 minutes
14 if (now - dateToCheck > 120000) return false
15
16 return true
17}
18
19// ---------------------------------------------------------------------------
20
21module.exports = miscsUtils
diff --git a/server/tests/utils/pods.js b/server/tests/utils/pods.js
new file mode 100644
index 000000000..a8551a49d
--- /dev/null
+++ b/server/tests/utils/pods.js
@@ -0,0 +1,95 @@
1'use strict'
2
3const request = require('supertest')
4
5const podsUtils = {
6 getFriendsList,
7 makeFriends,
8 quitFriends
9}
10
11// ---------------------- Export functions --------------------
12
13function getFriendsList (url, end) {
14 const path = '/api/v1/pods/'
15
16 request(url)
17 .get(path)
18 .set('Accept', 'application/json')
19 .expect(200)
20 .expect('Content-Type', /json/)
21 .end(end)
22}
23
24function makeFriends (url, accessToken, expectedStatus, end) {
25 if (!end) {
26 end = expectedStatus
27 expectedStatus = 204
28 }
29
30 // Which pod makes friends with which pod
31 const friendsMatrix = {
32 'http://localhost:9001': [
33 'http://localhost:9002'
34 ],
35 'http://localhost:9002': [
36 'http://localhost:9003'
37 ],
38 'http://localhost:9003': [
39 'http://localhost:9001'
40 ],
41 'http://localhost:9004': [
42 'http://localhost:9002'
43 ],
44 'http://localhost:9005': [
45 'http://localhost:9001',
46 'http://localhost:9004'
47 ],
48 'http://localhost:9006': [
49 'http://localhost:9001',
50 'http://localhost:9002',
51 'http://localhost:9003'
52 ]
53 }
54 const path = '/api/v1/pods/makefriends'
55
56 // The first pod make friend with the third
57 request(url)
58 .post(path)
59 .set('Accept', 'application/json')
60 .set('Authorization', 'Bearer ' + accessToken)
61 .send({ 'urls': friendsMatrix[url] })
62 .expect(expectedStatus)
63 .end(function (err, res) {
64 if (err) throw err
65
66 // Wait for the request between pods
67 setTimeout(end, 1000)
68 })
69}
70
71function quitFriends (url, accessToken, expectedStatus, end) {
72 if (!end) {
73 end = expectedStatus
74 expectedStatus = 204
75 }
76
77 const path = '/api/v1/pods/quitfriends'
78
79 // The first pod make friend with the third
80 request(url)
81 .get(path)
82 .set('Accept', 'application/json')
83 .set('Authorization', 'Bearer ' + accessToken)
84 .expect(expectedStatus)
85 .end(function (err, res) {
86 if (err) throw err
87
88 // Wait for the request between pods
89 setTimeout(end, 1000)
90 })
91}
92
93// ---------------------------------------------------------------------------
94
95module.exports = podsUtils
diff --git a/server/tests/utils/requests.js b/server/tests/utils/requests.js
new file mode 100644
index 000000000..b1470814d
--- /dev/null
+++ b/server/tests/utils/requests.js
@@ -0,0 +1,68 @@
1'use strict'
2
3const request = require('supertest')
4
5const requestsUtils = {
6 makePostUploadRequest,
7 makePostBodyRequest,
8 makePutBodyRequest
9}
10
11// ---------------------- Export functions --------------------
12
13function makePostUploadRequest (url, path, token, fields, attaches, done, statusCodeExpected) {
14 if (!statusCodeExpected) statusCodeExpected = 400
15
16 const req = request(url)
17 .post(path)
18 .set('Accept', 'application/json')
19
20 if (token) req.set('Authorization', 'Bearer ' + token)
21
22 Object.keys(fields).forEach(function (field) {
23 const value = fields[field]
24
25 if (Array.isArray(value)) {
26 for (let i = 0; i < value.length; i++) {
27 req.field(field + '[' + i + ']', value[i])
28 }
29 } else {
30 req.field(field, value)
31 }
32 })
33
34 Object.keys(attaches).forEach(function (attach) {
35 const value = attaches[attach]
36 req.attach(attach, value)
37 })
38
39 req.expect(statusCodeExpected, done)
40}
41
42function makePostBodyRequest (url, path, token, fields, done, statusCodeExpected) {
43 if (!statusCodeExpected) statusCodeExpected = 400
44
45 const req = request(url)
46 .post(path)
47 .set('Accept', 'application/json')
48
49 if (token) req.set('Authorization', 'Bearer ' + token)
50
51 req.send(fields).expect(statusCodeExpected, done)
52}
53
54function makePutBodyRequest (url, path, token, fields, done, statusCodeExpected) {
55 if (!statusCodeExpected) statusCodeExpected = 400
56
57 const req = request(url)
58 .put(path)
59 .set('Accept', 'application/json')
60
61 if (token) req.set('Authorization', 'Bearer ' + token)
62
63 req.send(fields).expect(statusCodeExpected, done)
64}
65
66// ---------------------------------------------------------------------------
67
68module.exports = requestsUtils
diff --git a/server/tests/utils/servers.js b/server/tests/utils/servers.js
new file mode 100644
index 000000000..d62838bc7
--- /dev/null
+++ b/server/tests/utils/servers.js
@@ -0,0 +1,115 @@
1'use strict'
2
3const childProcess = require('child_process')
4const exec = childProcess.exec
5const fork = childProcess.fork
6const pathUtils = require('path')
7
8const serversUtils = {
9 flushAndRunMultipleServers,
10 flushTests,
11 runServer
12}
13
14// ---------------------- Export functions --------------------
15
16function flushAndRunMultipleServers (totalServers, serversRun) {
17 let apps = []
18 let urls = []
19 let i = 0
20
21 function anotherServerDone (number, app, url) {
22 apps[number - 1] = app
23 urls[number - 1] = url
24 i++
25 if (i === totalServers) {
26 serversRun(apps, urls)
27 }
28 }
29
30 flushTests(function () {
31 for (let j = 1; j <= totalServers; j++) {
32 // For the virtual buffer
33 setTimeout(function () {
34 runServer(j, function (app, url) {
35 anotherServerDone(j, app, url)
36 })
37 }, 1000 * j)
38 }
39 })
40}
41
42function flushTests (callback) {
43 exec('npm run clean:server:test', callback)
44}
45
46function runServer (number, callback) {
47 const server = {
48 app: null,
49 url: `http://localhost:${9000 + number}`,
50 client: {
51 id: null,
52 secret: null
53 },
54 user: {
55 username: null,
56 password: null
57 }
58 }
59
60 // These actions are async so we need to be sure that they have both been done
61 const serverRunString = {
62 'Connected to mongodb': false,
63 'Server listening on port': false
64 }
65
66 const regexps = {
67 client_id: 'Client id: ([a-f0-9]+)',
68 client_secret: 'Client secret: (.+)',
69 user_username: 'Username: (.+)',
70 user_password: 'User password: (.+)'
71 }
72
73 // Share the environment
74 const env = Object.create(process.env)
75 env.NODE_ENV = 'test'
76 env.NODE_APP_INSTANCE = number
77 const options = {
78 silent: true,
79 env: env,
80 detached: true
81 }
82
83 server.app = fork(pathUtils.join(__dirname, '../../../server.js'), [], options)
84 server.app.stdout.on('data', function onStdout (data) {
85 let dontContinue = false
86
87 // Capture things if we want to
88 for (const key of Object.keys(regexps)) {
89 const regexp = regexps[key]
90 const matches = data.toString().match(regexp)
91 if (matches !== null) {
92 if (key === 'client_id') server.client.id = matches[1]
93 else if (key === 'client_secret') server.client.secret = matches[1]
94 else if (key === 'user_username') server.user.username = matches[1]
95 else if (key === 'user_password') server.user.password = matches[1]
96 }
97 }
98
99 // Check if all required sentences are here
100 for (const key of Object.keys(serverRunString)) {
101 if (data.toString().indexOf(key) !== -1) serverRunString[key] = true
102 if (serverRunString[key] === false) dontContinue = true
103 }
104
105 // If no, there is maybe one thing not already initialized (mongodb...)
106 if (dontContinue === true) return
107
108 server.app.stdout.removeListener('data', onStdout)
109 callback(server)
110 })
111}
112
113// ---------------------------------------------------------------------------
114
115module.exports = serversUtils
diff --git a/server/tests/utils/users.js b/server/tests/utils/users.js
new file mode 100644
index 000000000..2bf9c6e3e
--- /dev/null
+++ b/server/tests/utils/users.js
@@ -0,0 +1,100 @@
1'use strict'
2
3const request = require('supertest')
4
5const usersUtils = {
6 createUser,
7 getUserInformation,
8 getUsersList,
9 getUsersListPaginationAndSort,
10 removeUser,
11 updateUser
12}
13
14// ---------------------- Export functions --------------------
15
16function createUser (url, accessToken, username, password, specialStatus, end) {
17 if (!end) {
18 end = specialStatus
19 specialStatus = 204
20 }
21
22 const path = '/api/v1/users'
23
24 request(url)
25 .post(path)
26 .set('Accept', 'application/json')
27 .set('Authorization', 'Bearer ' + accessToken)
28 .send({ username: username, password: password })
29 .expect(specialStatus)
30 .end(end)
31}
32
33function getUserInformation (url, accessToken, end) {
34 const path = '/api/v1/users/me'
35
36 request(url)
37 .get(path)
38 .set('Accept', 'application/json')
39 .set('Authorization', 'Bearer ' + accessToken)
40 .expect(200)
41 .expect('Content-Type', /json/)
42 .end(end)
43}
44
45function getUsersList (url, end) {
46 const path = '/api/v1/users'
47
48 request(url)
49 .get(path)
50 .set('Accept', 'application/json')
51 .expect(200)
52 .expect('Content-Type', /json/)
53 .end(end)
54}
55
56function getUsersListPaginationAndSort (url, start, count, sort, end) {
57 const path = '/api/v1/users'
58
59 request(url)
60 .get(path)
61 .query({ start: start })
62 .query({ count: count })
63 .query({ sort: sort })
64 .set('Accept', 'application/json')
65 .expect(200)
66 .expect('Content-Type', /json/)
67 .end(end)
68}
69
70function removeUser (url, userId, accessToken, expectedStatus, end) {
71 if (!end) {
72 end = expectedStatus
73 expectedStatus = 204
74 }
75
76 const path = '/api/v1/users'
77
78 request(url)
79 .delete(path + '/' + userId)
80 .set('Accept', 'application/json')
81 .set('Authorization', 'Bearer ' + accessToken)
82 .expect(expectedStatus)
83 .end(end)
84}
85
86function updateUser (url, userId, accessToken, newPassword, end) {
87 const path = '/api/v1/users/' + userId
88
89 request(url)
90 .put(path)
91 .set('Accept', 'application/json')
92 .set('Authorization', 'Bearer ' + accessToken)
93 .send({ password: newPassword })
94 .expect(204)
95 .end(end)
96}
97
98// ---------------------------------------------------------------------------
99
100module.exports = usersUtils
diff --git a/server/tests/utils/videos.js b/server/tests/utils/videos.js
new file mode 100644
index 000000000..536093db1
--- /dev/null
+++ b/server/tests/utils/videos.js
@@ -0,0 +1,199 @@
1'use strict'
2
3const fs = require('fs')
4const pathUtils = require('path')
5const request = require('supertest')
6
7const videosUtils = {
8 getAllVideosListBy,
9 getVideo,
10 getVideosList,
11 getVideosListPagination,
12 getVideosListSort,
13 removeVideo,
14 searchVideo,
15 searchVideoWithPagination,
16 searchVideoWithSort,
17 testVideoImage,
18 uploadVideo
19}
20
21// ---------------------- Export functions --------------------
22
23function getAllVideosListBy (url, end) {
24 const path = '/api/v1/videos'
25
26 request(url)
27 .get(path)
28 .query({ sort: 'createdDate' })
29 .query({ start: 0 })
30 .query({ count: 10000 })
31 .set('Accept', 'application/json')
32 .expect(200)
33 .expect('Content-Type', /json/)
34 .end(end)
35}
36
37function getVideo (url, id, end) {
38 const path = '/api/v1/videos/' + id
39
40 request(url)
41 .get(path)
42 .set('Accept', 'application/json')
43 .expect(200)
44 .expect('Content-Type', /json/)
45 .end(end)
46}
47
48function getVideosList (url, end) {
49 const path = '/api/v1/videos'
50
51 request(url)
52 .get(path)
53 .query({ sort: 'name' })
54 .set('Accept', 'application/json')
55 .expect(200)
56 .expect('Content-Type', /json/)
57 .end(end)
58}
59
60function getVideosListPagination (url, start, count, end) {
61 const path = '/api/v1/videos'
62
63 request(url)
64 .get(path)
65 .query({ start: start })
66 .query({ count: count })
67 .set('Accept', 'application/json')
68 .expect(200)
69 .expect('Content-Type', /json/)
70 .end(end)
71}
72
73function getVideosListSort (url, sort, end) {
74 const path = '/api/v1/videos'
75
76 request(url)
77 .get(path)
78 .query({ sort: sort })
79 .set('Accept', 'application/json')
80 .expect(200)
81 .expect('Content-Type', /json/)
82 .end(end)
83}
84
85function removeVideo (url, token, id, expectedStatus, end) {
86 if (!end) {
87 end = expectedStatus
88 expectedStatus = 204
89 }
90
91 const path = '/api/v1/videos'
92
93 request(url)
94 .delete(path + '/' + id)
95 .set('Accept', 'application/json')
96 .set('Authorization', 'Bearer ' + token)
97 .expect(expectedStatus)
98 .end(end)
99}
100
101function searchVideo (url, search, field, end) {
102 if (!end) {
103 end = field
104 field = null
105 }
106
107 const path = '/api/v1/videos'
108 const req = request(url)
109 .get(path + '/search/' + search)
110 .set('Accept', 'application/json')
111
112 if (field) req.query({ field: field })
113 req.expect(200)
114 .expect('Content-Type', /json/)
115 .end(end)
116}
117
118function searchVideoWithPagination (url, search, field, start, count, end) {
119 const path = '/api/v1/videos'
120
121 request(url)
122 .get(path + '/search/' + search)
123 .query({ start: start })
124 .query({ count: count })
125 .query({ field: field })
126 .set('Accept', 'application/json')
127 .expect(200)
128 .expect('Content-Type', /json/)
129 .end(end)
130}
131
132function searchVideoWithSort (url, search, sort, end) {
133 const path = '/api/v1/videos'
134
135 request(url)
136 .get(path + '/search/' + search)
137 .query({ sort: sort })
138 .set('Accept', 'application/json')
139 .expect(200)
140 .expect('Content-Type', /json/)
141 .end(end)
142}
143
144function testVideoImage (url, videoName, imagePath, callback) {
145 // Don't test images if the node env is not set
146 // Because we need a special ffmpeg version for this test
147 if (process.env.NODE_TEST_IMAGE) {
148 request(url)
149 .get(imagePath)
150 .expect(200)
151 .end(function (err, res) {
152 if (err) return callback(err)
153
154 fs.readFile(pathUtils.join(__dirname, '..', 'api', 'fixtures', videoName + '.jpg'), function (err, data) {
155 if (err) return callback(err)
156
157 callback(null, data.equals(res.body))
158 })
159 })
160 } else {
161 console.log('Do not test images. Enable it by setting NODE_TEST_IMAGE env variable.')
162 callback(null, true)
163 }
164}
165
166function uploadVideo (url, accessToken, name, description, tags, fixture, specialStatus, end) {
167 if (!end) {
168 end = specialStatus
169 specialStatus = 204
170 }
171
172 const path = '/api/v1/videos'
173
174 const req = request(url)
175 .post(path)
176 .set('Accept', 'application/json')
177 .set('Authorization', 'Bearer ' + accessToken)
178 .field('name', name)
179 .field('description', description)
180
181 for (let i = 0; i < tags.length; i++) {
182 req.field('tags[' + i + ']', tags[i])
183 }
184
185 let filepath = ''
186 if (pathUtils.isAbsolute(fixture)) {
187 filepath = fixture
188 } else {
189 filepath = pathUtils.join(__dirname, '..', 'api', 'fixtures', fixture)
190 }
191
192 req.attach('videofile', filepath)
193 .expect(specialStatus)
194 .end(end)
195}
196
197// ---------------------------------------------------------------------------
198
199module.exports = videosUtils