aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2016-08-04 22:32:36 +0200
committerChocobozzz <florian.bigard@gmail.com>2016-08-04 22:33:38 +0200
commit9bd2662976a75d3b03364cdbe6419e57c80f99a6 (patch)
tree0b5289660f843a8ba7f13aa79d458f53c94b36d9
parente4c556196d7b31111f17596840d2e1d60caa7dcb (diff)
downloadPeerTube-9bd2662976a75d3b03364cdbe6419e57c80f99a6.tar.gz
PeerTube-9bd2662976a75d3b03364cdbe6419e57c80f99a6.tar.zst
PeerTube-9bd2662976a75d3b03364cdbe6419e57c80f99a6.zip
Implement user API (create, update, remove, list)
-rw-r--r--server/controllers/api/v1/pods.js14
-rw-r--r--server/controllers/api/v1/users.js132
-rw-r--r--server/helpers/custom-validators/users.js15
-rw-r--r--server/helpers/custom-validators/videos.js2
-rw-r--r--server/initializers/constants.js8
-rw-r--r--server/initializers/installer.js9
-rw-r--r--server/middlewares/admin.js22
-rw-r--r--server/middlewares/index.js22
-rw-r--r--server/middlewares/validators/index.js2
-rw-r--r--server/middlewares/validators/users.js57
-rw-r--r--server/middlewares/validators/videos.js1
-rw-r--r--server/models/user.js33
-rw-r--r--server/models/video.js5
-rw-r--r--server/tests/api/checkParams.js268
-rw-r--r--server/tests/api/users.js83
-rw-r--r--server/tests/api/utils.js62
16 files changed, 688 insertions, 47 deletions
diff --git a/server/controllers/api/v1/pods.js b/server/controllers/api/v1/pods.js
index 2bc761fef..f61f2a483 100644
--- a/server/controllers/api/v1/pods.js
+++ b/server/controllers/api/v1/pods.js
@@ -8,6 +8,7 @@ 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
12const validators = middlewares.validators.pods 13const validators = middlewares.validators.pods
13const signatureValidator = middlewares.validators.remote.signature 14const signatureValidator = middlewares.validators.remote.signature
@@ -18,8 +19,17 @@ const Video = mongoose.model('Video')
18 19
19router.get('/', listPodsUrl) 20router.get('/', listPodsUrl)
20router.post('/', validators.podsAdd, addPods) 21router.post('/', validators.podsAdd, addPods)
21router.get('/makefriends', oAuth.authenticate, validators.makeFriends, makeFriends) 22router.get('/makefriends',
22router.get('/quitfriends', oAuth.authenticate, quitFriends) 23 oAuth.authenticate,
24 admin.ensureIsAdmin,
25 validators.makeFriends,
26 makeFriends
27)
28router.get('/quitfriends',
29 oAuth.authenticate,
30 admin.ensureIsAdmin,
31 quitFriends
32)
23// Post because this is a secured request 33// Post because this is a secured request
24router.post('/remove', signatureValidator, removePods) 34router.post('/remove', signatureValidator, removePods)
25 35
diff --git a/server/controllers/api/v1/users.js b/server/controllers/api/v1/users.js
index fbbe6e472..e084974ce 100644
--- a/server/controllers/api/v1/users.js
+++ b/server/controllers/api/v1/users.js
@@ -1,18 +1,49 @@
1'use strict' 1'use strict'
2 2
3const each = require('async/each')
3const config = require('config') 4const config = require('config')
4const mongoose = require('mongoose')
5const express = require('express') 5const express = require('express')
6const mongoose = require('mongoose')
7const waterfall = require('async/waterfall')
6 8
7const oAuth = require('../../../middlewares').oauth 9const constants = require('../../../initializers/constants')
10const friends = require('../../../lib/friends')
11const logger = require('../../../helpers/logger')
12const middlewares = require('../../../middlewares')
13const admin = middlewares.admin
14const oAuth = middlewares.oauth
15const validatorsUsers = middlewares.validators.users
8 16
9const Client = mongoose.model('OAuthClient') 17const Client = mongoose.model('OAuthClient')
18const User = mongoose.model('User')
19const Video = mongoose.model('Video')
10 20
11const router = express.Router() 21const router = express.Router()
12 22
23router.get('/', listUsers)
24
25router.post('/',
26 oAuth.authenticate,
27 admin.ensureIsAdmin,
28 validatorsUsers.usersAdd,
29 createUser
30)
31
32router.put('/:id',
33 oAuth.authenticate,
34 validatorsUsers.usersUpdate,
35 updateUser
36)
37
38router.delete('/:username',
39 oAuth.authenticate,
40 admin.ensureIsAdmin,
41 validatorsUsers.usersRemove,
42 removeUser
43)
13router.get('/client', getAngularClient) 44router.get('/client', getAngularClient)
14router.post('/token', oAuth.token, success) 45router.post('/token', oAuth.token, success)
15// TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged,, implement revoke token route 46// TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged, implement revoke token route
16 47
17// --------------------------------------------------------------------------- 48// ---------------------------------------------------------------------------
18 49
@@ -20,6 +51,20 @@ module.exports = router
20 51
21// --------------------------------------------------------------------------- 52// ---------------------------------------------------------------------------
22 53
54function createUser (req, res, next) {
55 const user = new User({
56 username: req.body.username,
57 password: req.body.password,
58 role: constants.USER_ROLES.USER
59 })
60
61 user.save(function (err, createdUser) {
62 if (err) return next(err)
63
64 return res.type('json').status(204).end()
65 })
66}
67
23function getAngularClient (req, res, next) { 68function getAngularClient (req, res, next) {
24 const serverHost = config.get('webserver.host') 69 const serverHost = config.get('webserver.host')
25 const serverPort = config.get('webserver.port') 70 const serverPort = config.get('webserver.port')
@@ -44,6 +89,87 @@ function getAngularClient (req, res, next) {
44 }) 89 })
45} 90}
46 91
92function listUsers (req, res, next) {
93 User.list(function (err, usersList) {
94 if (err) return next(err)
95
96 res.json(getFormatedUsers(usersList))
97 })
98}
99
100function removeUser (req, res, next) {
101 waterfall([
102 function getUser (callback) {
103 User.loadByUsername(req.params.username, callback)
104 },
105
106 function getVideos (user, callback) {
107 Video.listOwnedByAuthor(user.username, function (err, videos) {
108 return callback(err, user, videos)
109 })
110 },
111
112 function removeVideosFromDB (user, videos, callback) {
113 each(videos, function (video, callbackEach) {
114 video.remove(callbackEach)
115 }, function (err) {
116 return callback(err, user, videos)
117 })
118 },
119
120 function sendInformationToFriends (user, videos, callback) {
121 videos.forEach(function (video) {
122 const params = {
123 name: video.name,
124 magnetUri: video.magnetUri
125 }
126
127 friends.removeVideoToFriends(params)
128 })
129
130 return callback(null, user)
131 },
132
133 function removeUserFromDB (user, callback) {
134 user.remove(callback)
135 }
136 ], function andFinally (err) {
137 if (err) {
138 logger.error('Errors when removed the user.', { error: err })
139 return next(err)
140 }
141
142 return res.type('json').status(204).end()
143 })
144}
145
146function updateUser (req, res, next) {
147 User.loadByUsername(res.locals.oauth.token.user.username, function (err, user) {
148 if (err) return next(err)
149
150 user.password = req.body.password
151 user.save(function (err) {
152 if (err) return next(err)
153
154 return res.json('json').status(204).end()
155 })
156 })
157}
158
47function success (req, res, next) { 159function success (req, res, next) {
48 res.end() 160 res.end()
49} 161}
162
163// ---------------------------------------------------------------------------
164
165function getFormatedUsers (users) {
166 const formatedUsers = []
167
168 users.forEach(function (user) {
169 formatedUsers.push(user.toFormatedJSON())
170 })
171
172 return {
173 data: formatedUsers
174 }
175}
diff --git a/server/helpers/custom-validators/users.js b/server/helpers/custom-validators/users.js
index 41e00d046..0e92989e5 100644
--- a/server/helpers/custom-validators/users.js
+++ b/server/helpers/custom-validators/users.js
@@ -1,16 +1,29 @@
1'use strict' 1'use strict'
2 2
3const validator = require('express-validator').validator 3const validator = require('express-validator').validator
4const values = require('lodash/values')
4 5
5const constants = require('../../initializers/constants') 6const constants = require('../../initializers/constants')
6const USERS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.USERS 7const USERS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.USERS
7 8
8const usersValidators = { 9const usersValidators = {
10 isUserPasswordValid: isUserPasswordValid,
11 isUserRoleValid: isUserRoleValid,
9 isUserUsernameValid: isUserUsernameValid 12 isUserUsernameValid: isUserUsernameValid
10} 13}
11 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
12function isUserUsernameValid (value) { 23function isUserUsernameValid (value) {
13 return validator.isLength(value, USERS_CONSTRAINTS_FIELDS.USERNAME) 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}}$`))
14} 27}
15 28
16// --------------------------------------------------------------------------- 29// ---------------------------------------------------------------------------
diff --git a/server/helpers/custom-validators/videos.js b/server/helpers/custom-validators/videos.js
index 39a19cbd7..cffa973f8 100644
--- a/server/helpers/custom-validators/videos.js
+++ b/server/helpers/custom-validators/videos.js
@@ -45,7 +45,7 @@ function isEachRemoteVideosValid (requests) {
45} 45}
46 46
47function isVideoAuthorValid (value) { 47function isVideoAuthorValid (value) {
48 return usersValidators.isUserUsernameValid(usersValidators) 48 return usersValidators.isUserUsernameValid(value)
49} 49}
50 50
51function isVideoDateValid (value) { 51function isVideoDateValid (value) {
diff --git a/server/initializers/constants.js b/server/initializers/constants.js
index 5f4aeccc6..416356400 100644
--- a/server/initializers/constants.js
+++ b/server/initializers/constants.js
@@ -72,6 +72,11 @@ const THUMBNAILS_SIZE = '200x110'
72// Path for access to thumbnails with express router 72// Path for access to thumbnails with express router
73const THUMBNAILS_STATIC_PATH = '/static/thumbnails' 73const THUMBNAILS_STATIC_PATH = '/static/thumbnails'
74 74
75const USER_ROLES = {
76 ADMIN: 'admin',
77 USER: 'user'
78}
79
75// Special constants for a test instance 80// Special constants for a test instance
76if (isTestInstance() === true) { 81if (isTestInstance() === true) {
77 FRIEND_SCORE.BASE = 20 82 FRIEND_SCORE.BASE = 20
@@ -96,7 +101,8 @@ module.exports = {
96 SEEDS_IN_PARALLEL: SEEDS_IN_PARALLEL, 101 SEEDS_IN_PARALLEL: SEEDS_IN_PARALLEL,
97 SORTABLE_COLUMNS: SORTABLE_COLUMNS, 102 SORTABLE_COLUMNS: SORTABLE_COLUMNS,
98 THUMBNAILS_SIZE: THUMBNAILS_SIZE, 103 THUMBNAILS_SIZE: THUMBNAILS_SIZE,
99 THUMBNAILS_STATIC_PATH: THUMBNAILS_STATIC_PATH 104 THUMBNAILS_STATIC_PATH: THUMBNAILS_STATIC_PATH,
105 USER_ROLES: USER_ROLES
100} 106}
101 107
102// --------------------------------------------------------------------------- 108// ---------------------------------------------------------------------------
diff --git a/server/initializers/installer.js b/server/initializers/installer.js
index 32830d4da..c12187871 100644
--- a/server/initializers/installer.js
+++ b/server/initializers/installer.js
@@ -9,6 +9,7 @@ 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
@@ -34,7 +35,7 @@ function installApplication (callback) {
34 }, 35 },
35 36
36 function createOAuthUser (callbackAsync) { 37 function createOAuthUser (callbackAsync) {
37 createOAuthUserIfNotExist(callbackAsync) 38 createOAuthAdminIfNotExist(callbackAsync)
38 } 39 }
39 ], callback) 40 ], callback)
40} 41}
@@ -80,7 +81,7 @@ function createOAuthClientIfNotExist (callback) {
80 }) 81 })
81} 82}
82 83
83function createOAuthUserIfNotExist (callback) { 84function createOAuthAdminIfNotExist (callback) {
84 checker.usersExist(function (err, exist) { 85 checker.usersExist(function (err, exist) {
85 if (err) return callback(err) 86 if (err) return callback(err)
86 87
@@ -90,6 +91,7 @@ function createOAuthUserIfNotExist (callback) {
90 logger.info('Creating the administrator.') 91 logger.info('Creating the administrator.')
91 92
92 const username = 'root' 93 const username = 'root'
94 const role = constants.USER_ROLES.ADMIN
93 let password = '' 95 let password = ''
94 96
95 // Do not generate a random password for tests 97 // Do not generate a random password for tests
@@ -105,7 +107,8 @@ function createOAuthUserIfNotExist (callback) {
105 107
106 const user = new User({ 108 const user = new User({
107 username: username, 109 username: username,
108 password: password 110 password: password,
111 role: role
109 }) 112 })
110 113
111 user.save(function (err, createdUser) { 114 user.save(function (err, createdUser) {
diff --git a/server/middlewares/admin.js b/server/middlewares/admin.js
new file mode 100644
index 000000000..bcb60ab95
--- /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: 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..1e294de5f 100644
--- a/server/middlewares/index.js
+++ b/server/middlewares/index.js
@@ -1,19 +1,21 @@
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')
5const validatorsMiddleware = require('./validators') 6const validatorsMiddleware = require('./validators')
6const search = require('./search') 7const searchMiddleware = require('./search')
7const sort = require('./sort') 8const sortMiddleware = require('./sort')
8const secureMiddleware = require('./secure') 9const secureMiddleware = require('./secure')
9 10
10const middlewares = { 11const middlewares = {
11 oauth: oauth, 12 admin: adminMiddleware,
12 pagination: pagination, 13 oauth: oauthMiddleware,
13 validators: validatorsMiddleware, 14 pagination: paginationMiddleware,
14 search: search, 15 search: searchMiddleware,
15 sort: sort, 16 secure: secureMiddleware,
16 secure: secureMiddleware 17 sort: sortMiddleware,
18 validators: validatorsMiddleware
17} 19}
18 20
19// --------------------------------------------------------------------------- 21// ---------------------------------------------------------------------------
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/users.js b/server/middlewares/validators/users.js
new file mode 100644
index 000000000..175d90bcb
--- /dev/null
+++ b/server/middlewares/validators/users.js
@@ -0,0 +1,57 @@
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: usersAdd,
12 usersRemove: usersRemove,
13 usersUpdate: 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 // TODO: check we don't have already the same username
21
22 logger.debug('Checking usersAdd parameters', { parameters: req.body })
23
24 checkErrors(req, res, next)
25}
26
27function usersRemove (req, res, next) {
28 req.checkParams('username', 'Should have a valid username').isUserUsernameValid()
29
30 logger.debug('Checking usersRemove parameters', { parameters: req.params })
31
32 checkErrors(req, res, function () {
33 User.loadByUsername(req.params.username, function (err, user) {
34 if (err) {
35 logger.error('Error in usersRemove request validator.', { error: err })
36 return res.sendStatus(500)
37 }
38
39 if (!user) return res.status(404).send('User not found')
40
41 next()
42 })
43 })
44}
45
46function usersUpdate (req, res, next) {
47 // Add old password verification
48 req.checkBody('password', 'Should have a valid password').isUserPasswordValid()
49
50 logger.debug('Checking usersUpdate parameters', { parameters: req.body })
51
52 checkErrors(req, res, next)
53}
54
55// ---------------------------------------------------------------------------
56
57module.exports = validatorsUsers
diff --git a/server/middlewares/validators/videos.js b/server/middlewares/validators/videos.js
index 422f3642f..9d21ee16f 100644
--- a/server/middlewares/validators/videos.js
+++ b/server/middlewares/validators/videos.js
@@ -18,6 +18,7 @@ const validatorsVideos = {
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()
diff --git a/server/models/user.js b/server/models/user.js
index 14ffecbff..0bbd638d4 100644
--- a/server/models/user.js
+++ b/server/models/user.js
@@ -1,28 +1,49 @@
1const mongoose = require('mongoose') 1const mongoose = require('mongoose')
2 2
3const customUsersValidators = require('../helpers/custom-validators').users
4
3// --------------------------------------------------------------------------- 5// ---------------------------------------------------------------------------
4 6
5const UserSchema = mongoose.Schema({ 7const UserSchema = mongoose.Schema({
6 password: String, 8 password: String,
7 username: String 9 username: String,
10 role: String
8}) 11})
9 12
10UserSchema.path('password').required(true) 13UserSchema.path('password').required(customUsersValidators.isUserPasswordValid)
11UserSchema.path('username').required(true) 14UserSchema.path('username').required(customUsersValidators.isUserUsernameValid)
15UserSchema.path('role').validate(customUsersValidators.isUserRoleValid)
16
17UserSchema.methods = {
18 toFormatedJSON: toFormatedJSON
19}
12 20
13UserSchema.statics = { 21UserSchema.statics = {
14 getByUsernameAndPassword: getByUsernameAndPassword, 22 getByUsernameAndPassword: getByUsernameAndPassword,
15 list: list 23 list: list,
24 loadByUsername: loadByUsername
16} 25}
17 26
18mongoose.model('User', UserSchema) 27mongoose.model('User', UserSchema)
19 28
20// --------------------------------------------------------------------------- 29// ---------------------------------------------------------------------------
21 30
31function getByUsernameAndPassword (username, password) {
32 return this.findOne({ username: username, password: password })
33}
34
22function list (callback) { 35function list (callback) {
23 return this.find(callback) 36 return this.find(callback)
24} 37}
25 38
26function getByUsernameAndPassword (username, password) { 39function loadByUsername (username, callback) {
27 return this.findOne({ username: username, password: password }) 40 return this.findOne({ username: username }, callback)
41}
42
43function toFormatedJSON () {
44 return {
45 id: this._id,
46 username: this.username,
47 role: this.role
48 }
28} 49}
diff --git a/server/models/video.js b/server/models/video.js
index acb8353c2..14bc91b16 100644
--- a/server/models/video.js
+++ b/server/models/video.js
@@ -64,6 +64,7 @@ VideoSchema.statics = {
64 listByUrlAndMagnet: listByUrlAndMagnet, 64 listByUrlAndMagnet: listByUrlAndMagnet,
65 listByUrls: listByUrls, 65 listByUrls: listByUrls,
66 listOwned: listOwned, 66 listOwned: listOwned,
67 listOwnedByAuthor: listOwnedByAuthor,
67 listRemotes: listRemotes, 68 listRemotes: listRemotes,
68 load: load, 69 load: load,
69 search: search, 70 search: search,
@@ -211,6 +212,10 @@ function listOwned (callback) {
211 this.find({ filename: { $ne: null } }, callback) 212 this.find({ filename: { $ne: null } }, callback)
212} 213}
213 214
215function listOwnedByAuthor (author, callback) {
216 this.find({ filename: { $ne: null }, author: author }, callback)
217}
218
214function listRemotes (callback) { 219function listRemotes (callback) {
215 this.find({ filename: null }, callback) 220 this.find({ filename: null }, callback)
216} 221}
diff --git a/server/tests/api/checkParams.js b/server/tests/api/checkParams.js
index c1ba9c2c0..bd7227e9c 100644
--- a/server/tests/api/checkParams.js
+++ b/server/tests/api/checkParams.js
@@ -11,9 +11,8 @@ const utils = require('./utils')
11describe('Test parameters validator', function () { 11describe('Test parameters validator', function () {
12 let server = null 12 let server = null
13 13
14 function makePostRequest (path, token, fields, attaches, done, fail) { 14 function makePostRequest (path, token, fields, attaches, done, statusCodeExpected) {
15 let statusCode = 400 15 if (!statusCodeExpected) statusCodeExpected = 400
16 if (fail !== undefined && fail === false) statusCode = 204
17 16
18 const req = request(server.url) 17 const req = request(server.url)
19 .post(path) 18 .post(path)
@@ -38,18 +37,31 @@ describe('Test parameters validator', function () {
38 req.attach(attach, value) 37 req.attach(attach, value)
39 }) 38 })
40 39
41 req.expect(statusCode, done) 40 req.expect(statusCodeExpected, done)
42 } 41 }
43 42
44 function makePostBodyRequest (path, fields, done, fail) { 43 function makePostBodyRequest (path, token, fields, done, statusCodeExpected) {
45 let statusCode = 400 44 if (!statusCodeExpected) statusCodeExpected = 400
46 if (fail !== undefined && fail === false) statusCode = 200
47 45
48 request(server.url) 46 const req = request(server.url)
49 .post(path) 47 .post(path)
50 .set('Accept', 'application/json') 48 .set('Accept', 'application/json')
51 .send(fields) 49
52 .expect(statusCode, done) 50 if (token) req.set('Authorization', 'Bearer ' + token)
51
52 req.send(fields).expect(statusCodeExpected, done)
53 }
54
55 function makePutBodyRequest (path, token, fields, done, statusCodeExpected) {
56 if (!statusCodeExpected) statusCodeExpected = 400
57
58 const req = request(server.url)
59 .put(path)
60 .set('Accept', 'application/json')
61
62 if (token) req.set('Authorization', 'Bearer ' + token)
63
64 req.send(fields).expect(statusCodeExpected, done)
53 } 65 }
54 66
55 // --------------------------------------------------------------- 67 // ---------------------------------------------------------------
@@ -85,21 +97,21 @@ describe('Test parameters validator', function () {
85 describe('When adding a pod', function () { 97 describe('When adding a pod', function () {
86 it('Should fail with nothing', function (done) { 98 it('Should fail with nothing', function (done) {
87 const data = {} 99 const data = {}
88 makePostBodyRequest(path, data, done) 100 makePostBodyRequest(path, null, data, done)
89 }) 101 })
90 102
91 it('Should fail without public key', function (done) { 103 it('Should fail without public key', function (done) {
92 const data = { 104 const data = {
93 url: 'http://coucou.com' 105 url: 'http://coucou.com'
94 } 106 }
95 makePostBodyRequest(path, data, done) 107 makePostBodyRequest(path, null, data, done)
96 }) 108 })
97 109
98 it('Should fail without an url', function (done) { 110 it('Should fail without an url', function (done) {
99 const data = { 111 const data = {
100 publicKey: 'mysuperpublickey' 112 publicKey: 'mysuperpublickey'
101 } 113 }
102 makePostBodyRequest(path, data, done) 114 makePostBodyRequest(path, null, data, done)
103 }) 115 })
104 116
105 it('Should fail with an incorrect url', function (done) { 117 it('Should fail with an incorrect url', function (done) {
@@ -107,11 +119,11 @@ describe('Test parameters validator', function () {
107 url: 'coucou.com', 119 url: 'coucou.com',
108 publicKey: 'mysuperpublickey' 120 publicKey: 'mysuperpublickey'
109 } 121 }
110 makePostBodyRequest(path, data, function () { 122 makePostBodyRequest(path, null, data, function () {
111 data.url = 'http://coucou' 123 data.url = 'http://coucou'
112 makePostBodyRequest(path, data, function () { 124 makePostBodyRequest(path, null, data, function () {
113 data.url = 'coucou' 125 data.url = 'coucou'
114 makePostBodyRequest(path, data, done) 126 makePostBodyRequest(path, null, data, done)
115 }) 127 })
116 }) 128 })
117 }) 129 })
@@ -121,7 +133,68 @@ describe('Test parameters validator', function () {
121 url: 'http://coucou.com', 133 url: 'http://coucou.com',
122 publicKey: 'mysuperpublickey' 134 publicKey: 'mysuperpublickey'
123 } 135 }
124 makePostBodyRequest(path, data, done, false) 136 makePostBodyRequest(path, null, data, done, 200)
137 })
138 })
139
140 describe('For the friends API', function () {
141 let userAccessToken = null
142
143 before(function (done) {
144 utils.createUser(server.url, server.accessToken, 'user1', 'password', function () {
145 server.user = {
146 username: 'user1',
147 password: 'password'
148 }
149
150 utils.loginAndGetAccessToken(server, function (err, accessToken) {
151 if (err) throw err
152
153 userAccessToken = accessToken
154
155 done()
156 })
157 })
158 })
159
160 describe('When making friends', function () {
161 it('Should fail with a invalid token', function (done) {
162 request(server.url)
163 .get(path + '/makefriends')
164 .query({ start: 'hello' })
165 .set('Authorization', 'Bearer faketoken')
166 .set('Accept', 'application/json')
167 .expect(401, done)
168 })
169
170 it('Should fail if the user is not an administrator', function (done) {
171 request(server.url)
172 .get(path + '/makefriends')
173 .query({ start: 'hello' })
174 .set('Authorization', 'Bearer ' + userAccessToken)
175 .set('Accept', 'application/json')
176 .expect(403, done)
177 })
178 })
179
180 describe('When quitting friends', function () {
181 it('Should fail with a invalid token', function (done) {
182 request(server.url)
183 .get(path + '/quitfriends')
184 .query({ start: 'hello' })
185 .set('Authorization', 'Bearer faketoken')
186 .set('Accept', 'application/json')
187 .expect(401, done)
188 })
189
190 it('Should fail if the user is not an administrator', function (done) {
191 request(server.url)
192 .get(path + '/quitfriends')
193 .query({ start: 'hello' })
194 .set('Authorization', 'Bearer ' + userAccessToken)
195 .set('Accept', 'application/json')
196 .expect(403, done)
197 })
125 }) 198 })
126 }) 199 })
127 }) 200 })
@@ -361,7 +434,7 @@ describe('Test parameters validator', function () {
361 attach.videofile = pathUtils.join(__dirname, 'fixtures', 'video_short.mp4') 434 attach.videofile = pathUtils.join(__dirname, 'fixtures', 'video_short.mp4')
362 makePostRequest(path, server.accessToken, data, attach, function () { 435 makePostRequest(path, server.accessToken, data, attach, function () {
363 attach.videofile = pathUtils.join(__dirname, 'fixtures', 'video_short.ogv') 436 attach.videofile = pathUtils.join(__dirname, 'fixtures', 'video_short.ogv')
364 makePostRequest(path, server.accessToken, data, attach, done, false) 437 makePostRequest(path, server.accessToken, data, attach, done, 204)
365 }, false) 438 }, false)
366 }, false) 439 }, false)
367 }) 440 })
@@ -429,6 +502,165 @@ describe('Test parameters validator', function () {
429 }) 502 })
430 }) 503 })
431 504
505 describe('Of the users API', function () {
506 const path = '/api/v1/users/'
507
508 describe('When adding a new user', function () {
509 it('Should fail with a too small username', function (done) {
510 const data = {
511 username: 'ji',
512 password: 'mysuperpassword'
513 }
514
515 makePostBodyRequest(path, server.accessToken, data, done)
516 })
517
518 it('Should fail with a too long username', function (done) {
519 const data = {
520 username: 'mysuperusernamewhichisverylong',
521 password: 'mysuperpassword'
522 }
523
524 makePostBodyRequest(path, server.accessToken, data, done)
525 })
526
527 it('Should fail with an incorrect username', function (done) {
528 const data = {
529 username: 'my username',
530 password: 'mysuperpassword'
531 }
532
533 makePostBodyRequest(path, server.accessToken, data, done)
534 })
535
536 it('Should fail with a too small password', function (done) {
537 const data = {
538 username: 'myusername',
539 password: 'bla'
540 }
541
542 makePostBodyRequest(path, server.accessToken, data, done)
543 })
544
545 it('Should fail with a too long password', function (done) {
546 const data = {
547 username: 'myusername',
548 password: 'my super long password which is very very very very very very very very very very very very very very' +
549 'very very very very very very very very very very very very very very very veryv very very very very' +
550 'very very very very very very very very very very very very very very very very very very very very long'
551 }
552
553 makePostBodyRequest(path, server.accessToken, data, done)
554 })
555
556 it('Should fail with an non authenticated user', function (done) {
557 const data = {
558 username: 'myusername',
559 password: 'my super password'
560 }
561
562 makePostBodyRequest(path, 'super token', data, done, 401)
563 })
564
565 it('Should succeed with the correct params', function (done) {
566 const data = {
567 username: 'user1',
568 password: 'my super password'
569 }
570
571 makePostBodyRequest(path, server.accessToken, data, done, 204)
572 })
573
574 it('Should fail with a non admin user', function (done) {
575 server.user = {
576 username: 'user1',
577 password: 'my super password'
578 }
579
580 utils.loginAndGetAccessToken(server, function (err, accessToken) {
581 if (err) throw err
582
583 const data = {
584 username: 'user2',
585 password: 'my super password'
586 }
587
588 makePostBodyRequest(path, accessToken, data, done, 403)
589 })
590 })
591 })
592
593 describe('When updating a user', function () {
594 let userId = null
595
596 before(function (done) {
597 utils.getUsersList(server.url, function (err, res) {
598 if (err) throw err
599
600 userId = res.body.data[1].id
601 done()
602 })
603 })
604
605 it('Should fail with a too small password', function (done) {
606 const data = {
607 password: 'bla'
608 }
609
610 makePutBodyRequest(path + '/' + userId, server.accessToken, data, done)
611 })
612
613 it('Should fail with a too long password', function (done) {
614 const data = {
615 password: 'my super long password which is very very very very very very very very very very very very very very' +
616 'very very very very very very very very very very very very very very very veryv very very very very' +
617 'very very very very very very very very very very very very very very very very very very very very long'
618 }
619
620 makePutBodyRequest(path + '/' + userId, server.accessToken, data, done)
621 })
622
623 it('Should fail with an non authenticated user', function (done) {
624 const data = {
625 password: 'my super password'
626 }
627
628 makePutBodyRequest(path + '/' + userId, 'super token', data, done, 401)
629 })
630
631 it('Should succeed with the correct params', function (done) {
632 const data = {
633 password: 'my super password'
634 }
635
636 makePutBodyRequest(path + '/' + userId, server.accessToken, data, done, 204)
637 })
638 })
639
640 describe('When removing an user', function () {
641 it('Should fail with an incorrect username', function (done) {
642 request(server.url)
643 .delete(path + 'bla-bla')
644 .set('Authorization', 'Bearer ' + server.accessToken)
645 .expect(400, done)
646 })
647
648 it('Should return 404 with a non existing username', function (done) {
649 request(server.url)
650 .delete(path + 'qzzerg')
651 .set('Authorization', 'Bearer ' + server.accessToken)
652 .expect(404, done)
653 })
654
655 it('Should success with the correct parameters', function (done) {
656 request(server.url)
657 .delete(path + 'user1')
658 .set('Authorization', 'Bearer ' + server.accessToken)
659 .expect(204, done)
660 })
661 })
662 })
663
432 describe('Of the remote videos API', function () { 664 describe('Of the remote videos API', function () {
433 describe('When making a secure request', function () { 665 describe('When making a secure request', function () {
434 it('Should check a secure request') 666 it('Should check a secure request')
diff --git a/server/tests/api/users.js b/server/tests/api/users.js
index 68ba9de33..c711d6b64 100644
--- a/server/tests/api/users.js
+++ b/server/tests/api/users.js
@@ -13,7 +13,9 @@ const utils = require('./utils')
13describe('Test users', function () { 13describe('Test users', function () {
14 let server = null 14 let server = null
15 let accessToken = null 15 let accessToken = null
16 let videoId 16 let accessTokenUser = null
17 let videoId = null
18 let userId = null
17 19
18 before(function (done) { 20 before(function (done) {
19 this.timeout(20000) 21 this.timeout(20000)
@@ -158,6 +160,85 @@ describe('Test users', function () {
158 160
159 it('Should be able to upload a video again') 161 it('Should be able to upload a video again')
160 162
163 it('Should be able to create a new user', function (done) {
164 utils.createUser(server.url, accessToken, 'user_1', 'super password', done)
165 })
166
167 it('Should be able to login with this user', function (done) {
168 server.user = {
169 username: 'user_1',
170 password: 'super password'
171 }
172
173 utils.loginAndGetAccessToken(server, function (err, token) {
174 if (err) throw err
175
176 accessTokenUser = token
177
178 done()
179 })
180 })
181
182 it('Should be able to upload a video with this user', function (done) {
183 this.timeout(5000)
184
185 const name = 'my super name'
186 const description = 'my super description'
187 const tags = [ 'tag1', 'tag2', 'tag3' ]
188 const file = 'video_short.webm'
189 utils.uploadVideo(server.url, accessTokenUser, name, description, tags, file, done)
190 })
191
192 it('Should list all the users', function (done) {
193 utils.getUsersList(server.url, function (err, res) {
194 if (err) throw err
195
196 const users = res.body.data
197
198 expect(users).to.be.an('array')
199 expect(users.length).to.equal(2)
200
201 const rootUser = users[0]
202 expect(rootUser.username).to.equal('root')
203
204 const user = users[1]
205 expect(user.username).to.equal('user_1')
206 userId = user.id
207
208 done()
209 })
210 })
211
212 it('Should update the user password', function (done) {
213 utils.updateUser(server.url, userId, accessTokenUser, 'new password', function (err, res) {
214 if (err) throw err
215
216 server.user.password = 'new password'
217 utils.login(server.url, server.client, server.user, 200, done)
218 })
219 })
220
221 it('Should be able to remove this user', function (done) {
222 utils.removeUser(server.url, accessToken, 'user_1', done)
223 })
224
225 it('Should not be able to login with this user', function (done) {
226 // server.user is already set to user 1
227 utils.login(server.url, server.client, server.user, 400, done)
228 })
229
230 it('Should not have videos of this user', function (done) {
231 utils.getVideosList(server.url, function (err, res) {
232 if (err) throw err
233
234 expect(res.body.total).to.equal(1)
235 const video = res.body.data[0]
236 expect(video.author).to.equal('root')
237
238 done()
239 })
240 })
241
161 after(function (done) { 242 after(function (done) {
162 process.kill(-server.app.pid) 243 process.kill(-server.app.pid)
163 244
diff --git a/server/tests/api/utils.js b/server/tests/api/utils.js
index 3cc769f26..f34b81e4a 100644
--- a/server/tests/api/utils.js
+++ b/server/tests/api/utils.js
@@ -8,11 +8,13 @@ const pathUtils = require('path')
8const request = require('supertest') 8const request = require('supertest')
9 9
10const testUtils = { 10const testUtils = {
11 createUser: createUser,
11 dateIsValid: dateIsValid, 12 dateIsValid: dateIsValid,
12 flushTests: flushTests, 13 flushTests: flushTests,
13 getAllVideosListBy: getAllVideosListBy, 14 getAllVideosListBy: getAllVideosListBy,
14 getClient: getClient, 15 getClient: getClient,
15 getFriendsList: getFriendsList, 16 getFriendsList: getFriendsList,
17 getUsersList: getUsersList,
16 getVideo: getVideo, 18 getVideo: getVideo,
17 getVideosList: getVideosList, 19 getVideosList: getVideosList,
18 getVideosListPagination: getVideosListPagination, 20 getVideosListPagination: getVideosListPagination,
@@ -21,6 +23,7 @@ const testUtils = {
21 loginAndGetAccessToken: loginAndGetAccessToken, 23 loginAndGetAccessToken: loginAndGetAccessToken,
22 makeFriends: makeFriends, 24 makeFriends: makeFriends,
23 quitFriends: quitFriends, 25 quitFriends: quitFriends,
26 removeUser: removeUser,
24 removeVideo: removeVideo, 27 removeVideo: removeVideo,
25 flushAndRunMultipleServers: flushAndRunMultipleServers, 28 flushAndRunMultipleServers: flushAndRunMultipleServers,
26 runServer: runServer, 29 runServer: runServer,
@@ -28,11 +31,29 @@ const testUtils = {
28 searchVideoWithPagination: searchVideoWithPagination, 31 searchVideoWithPagination: searchVideoWithPagination,
29 searchVideoWithSort: searchVideoWithSort, 32 searchVideoWithSort: searchVideoWithSort,
30 testImage: testImage, 33 testImage: testImage,
31 uploadVideo: uploadVideo 34 uploadVideo: uploadVideo,
35 updateUser: updateUser
32} 36}
33 37
34// ---------------------- Export functions -------------------- 38// ---------------------- Export functions --------------------
35 39
40function createUser (url, accessToken, username, password, specialStatus, end) {
41 if (!end) {
42 end = specialStatus
43 specialStatus = 204
44 }
45
46 const path = '/api/v1/users'
47
48 request(url)
49 .post(path)
50 .set('Accept', 'application/json')
51 .set('Authorization', 'Bearer ' + accessToken)
52 .send({ username: username, password: password })
53 .expect(specialStatus)
54 .end(end)
55}
56
36function dateIsValid (dateString) { 57function dateIsValid (dateString) {
37 const dateToCheck = new Date(dateString) 58 const dateToCheck = new Date(dateString)
38 const now = new Date() 59 const now = new Date()
@@ -72,6 +93,17 @@ function getClient (url, end) {
72 .end(end) 93 .end(end)
73} 94}
74 95
96function getUsersList (url, end) {
97 const path = '/api/v1/users'
98
99 request(url)
100 .get(path)
101 .set('Accept', 'application/json')
102 .expect(200)
103 .expect('Content-Type', /json/)
104 .end(end)
105}
106
75function getFriendsList (url, end) { 107function getFriendsList (url, end) {
76 const path = '/api/v1/pods/' 108 const path = '/api/v1/pods/'
77 109
@@ -209,6 +241,22 @@ function quitFriends (url, accessToken, expectedStatus, callback) {
209 }) 241 })
210} 242}
211 243
244function removeUser (url, token, username, expectedStatus, end) {
245 if (!end) {
246 end = expectedStatus
247 expectedStatus = 204
248 }
249
250 const path = '/api/v1/users'
251
252 request(url)
253 .delete(path + '/' + username)
254 .set('Accept', 'application/json')
255 .set('Authorization', 'Bearer ' + token)
256 .expect(expectedStatus)
257 .end(end)
258}
259
212function removeVideo (url, token, id, expectedStatus, end) { 260function removeVideo (url, token, id, expectedStatus, end) {
213 if (!end) { 261 if (!end) {
214 end = expectedStatus 262 end = expectedStatus
@@ -414,6 +462,18 @@ function uploadVideo (url, accessToken, name, description, tags, fixture, specia
414 .end(end) 462 .end(end)
415} 463}
416 464
465function updateUser (url, userId, accessToken, newPassword, end) {
466 const path = '/api/v1/users/' + userId
467
468 request(url)
469 .put(path)
470 .set('Accept', 'application/json')
471 .set('Authorization', 'Bearer ' + accessToken)
472 .send({ password: newPassword })
473 .expect(200)
474 .end(end)
475}
476
417// --------------------------------------------------------------------------- 477// ---------------------------------------------------------------------------
418 478
419module.exports = testUtils 479module.exports = testUtils