diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/videos.js | 85 | ||||
-rw-r--r-- | server/lib/friends.js | 7 | ||||
-rw-r--r-- | server/middlewares/validators/videos.js | 41 | ||||
-rw-r--r-- | server/models/video.js | 21 | ||||
-rw-r--r-- | server/tests/api/check-params.js | 101 | ||||
-rw-r--r-- | server/tests/api/single-pod.js | 76 | ||||
-rw-r--r-- | server/tests/utils/videos.js | 28 |
7 files changed, 344 insertions, 15 deletions
diff --git a/server/controllers/api/videos.js b/server/controllers/api/videos.js index f29edac74..1b306d1cf 100644 --- a/server/controllers/api/videos.js +++ b/server/controllers/api/videos.js | |||
@@ -50,6 +50,12 @@ router.get('/', | |||
50 | pagination.setPagination, | 50 | pagination.setPagination, |
51 | listVideos | 51 | listVideos |
52 | ) | 52 | ) |
53 | router.put('/:id', | ||
54 | oAuth.authenticate, | ||
55 | reqFiles, | ||
56 | validatorsVideos.videosUpdate, | ||
57 | updateVideo | ||
58 | ) | ||
53 | router.post('/', | 59 | router.post('/', |
54 | oAuth.authenticate, | 60 | oAuth.authenticate, |
55 | reqFiles, | 61 | reqFiles, |
@@ -165,7 +171,7 @@ function addVideo (req, res, next) { | |||
165 | }, | 171 | }, |
166 | 172 | ||
167 | function sendToFriends (t, video, callback) { | 173 | function sendToFriends (t, video, callback) { |
168 | video.toRemoteJSON(function (err, remoteVideo) { | 174 | video.toAddRemoteJSON(function (err, remoteVideo) { |
169 | if (err) return callback(err) | 175 | if (err) return callback(err) |
170 | 176 | ||
171 | // Now we'll add the video's meta data to our friends | 177 | // Now we'll add the video's meta data to our friends |
@@ -193,6 +199,83 @@ function addVideo (req, res, next) { | |||
193 | }) | 199 | }) |
194 | } | 200 | } |
195 | 201 | ||
202 | function updateVideo (req, res, next) { | ||
203 | let videoInstance = res.locals.video | ||
204 | const videoInfosToUpdate = req.body | ||
205 | |||
206 | waterfall([ | ||
207 | |||
208 | function startTransaction (callback) { | ||
209 | db.sequelize.transaction().asCallback(function (err, t) { | ||
210 | return callback(err, t) | ||
211 | }) | ||
212 | }, | ||
213 | |||
214 | function findOrCreateTags (t, callback) { | ||
215 | if (videoInfosToUpdate.tags) { | ||
216 | db.Tag.findOrCreateTags(videoInfosToUpdate.tags, t, function (err, tagInstances) { | ||
217 | return callback(err, t, tagInstances) | ||
218 | }) | ||
219 | } else { | ||
220 | return callback(null, t, null) | ||
221 | } | ||
222 | }, | ||
223 | |||
224 | function updateVideoIntoDB (t, tagInstances, callback) { | ||
225 | const options = { transaction: t } | ||
226 | |||
227 | if (videoInfosToUpdate.name) videoInstance.set('name', videoInfosToUpdate.name) | ||
228 | if (videoInfosToUpdate.description) videoInstance.set('description', videoInfosToUpdate.description) | ||
229 | |||
230 | // Add tags association | ||
231 | videoInstance.save(options).asCallback(function (err) { | ||
232 | if (err) return callback(err) | ||
233 | |||
234 | return callback(err, t, tagInstances) | ||
235 | }) | ||
236 | }, | ||
237 | |||
238 | function associateTagsToVideo (t, tagInstances, callback) { | ||
239 | if (tagInstances) { | ||
240 | const options = { transaction: t } | ||
241 | |||
242 | videoInstance.setTags(tagInstances, options).asCallback(function (err) { | ||
243 | videoInstance.Tags = tagInstances | ||
244 | |||
245 | return callback(err, t) | ||
246 | }) | ||
247 | } else { | ||
248 | return callback(null, t) | ||
249 | } | ||
250 | }, | ||
251 | |||
252 | function sendToFriends (t, callback) { | ||
253 | const json = videoInstance.toUpdateRemoteJSON() | ||
254 | |||
255 | // Now we'll update the video's meta data to our friends | ||
256 | friends.updateVideoToFriends(json) | ||
257 | |||
258 | return callback(null, t) | ||
259 | } | ||
260 | |||
261 | ], function andFinally (err, t) { | ||
262 | if (err) { | ||
263 | logger.error('Cannot insert the video.') | ||
264 | |||
265 | // Abort transaction? | ||
266 | if (t) t.rollback() | ||
267 | |||
268 | return next(err) | ||
269 | } | ||
270 | |||
271 | // Commit transaction | ||
272 | t.commit() | ||
273 | |||
274 | // TODO : include Location of the new video -> 201 | ||
275 | return res.type('json').status(204).end() | ||
276 | }) | ||
277 | } | ||
278 | |||
196 | function getVideo (req, res, next) { | 279 | function getVideo (req, res, next) { |
197 | db.Video.loadAndPopulateAuthorAndPodAndTags(req.params.id, function (err, video) { | 280 | db.Video.loadAndPopulateAuthorAndPodAndTags(req.params.id, function (err, video) { |
198 | if (err) return next(err) | 281 | if (err) return next(err) |
diff --git a/server/lib/friends.js b/server/lib/friends.js index ad9e4fdae..589b79660 100644 --- a/server/lib/friends.js +++ b/server/lib/friends.js | |||
@@ -14,6 +14,7 @@ const requests = require('../helpers/requests') | |||
14 | 14 | ||
15 | const friends = { | 15 | const friends = { |
16 | addVideoToFriends, | 16 | addVideoToFriends, |
17 | updateVideoToFriends, | ||
17 | hasFriends, | 18 | hasFriends, |
18 | getMyCertificate, | 19 | getMyCertificate, |
19 | makeFriends, | 20 | makeFriends, |
@@ -26,6 +27,10 @@ function addVideoToFriends (video) { | |||
26 | createRequest('add', constants.REQUEST_ENDPOINTS.VIDEOS, video) | 27 | createRequest('add', constants.REQUEST_ENDPOINTS.VIDEOS, video) |
27 | } | 28 | } |
28 | 29 | ||
30 | function updateVideoToFriends (video) { | ||
31 | createRequest('update', constants.REQUEST_ENDPOINTS.VIDEOS, video) | ||
32 | } | ||
33 | |||
29 | function hasFriends (callback) { | 34 | function hasFriends (callback) { |
30 | db.Pod.countAll(function (err, count) { | 35 | db.Pod.countAll(function (err, count) { |
31 | if (err) return callback(err) | 36 | if (err) return callback(err) |
@@ -127,7 +132,7 @@ function sendOwnedVideosToPod (podId) { | |||
127 | } | 132 | } |
128 | 133 | ||
129 | videosList.forEach(function (video) { | 134 | videosList.forEach(function (video) { |
130 | video.toRemoteJSON(function (err, remoteVideo) { | 135 | video.toAddRemoteJSON(function (err, remoteVideo) { |
131 | if (err) { | 136 | if (err) { |
132 | logger.error('Cannot convert video to remote.', { error: err }) | 137 | logger.error('Cannot convert video to remote.', { error: err }) |
133 | // Don't break the process | 138 | // Don't break the process |
diff --git a/server/middlewares/validators/videos.js b/server/middlewares/validators/videos.js index 7e90ca047..09a188c76 100644 --- a/server/middlewares/validators/videos.js +++ b/server/middlewares/validators/videos.js | |||
@@ -8,6 +8,7 @@ const logger = require('../../helpers/logger') | |||
8 | 8 | ||
9 | const validatorsVideos = { | 9 | const validatorsVideos = { |
10 | videosAdd, | 10 | videosAdd, |
11 | videosUpdate, | ||
11 | videosGet, | 12 | videosGet, |
12 | videosRemove, | 13 | videosRemove, |
13 | videosSearch | 14 | videosSearch |
@@ -41,22 +42,26 @@ function videosAdd (req, res, next) { | |||
41 | }) | 42 | }) |
42 | } | 43 | } |
43 | 44 | ||
44 | function videosGet (req, res, next) { | 45 | function videosUpdate (req, res, next) { |
45 | req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) | 46 | req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) |
47 | req.checkBody('name', 'Should have a valid name').optional().isVideoNameValid() | ||
48 | req.checkBody('description', 'Should have a valid description').optional().isVideoDescriptionValid() | ||
49 | req.checkBody('tags', 'Should have correct tags').optional().isVideoTagsValid() | ||
46 | 50 | ||
47 | logger.debug('Checking videosGet parameters', { parameters: req.params }) | 51 | logger.debug('Checking videosUpdate parameters', { parameters: req.body }) |
48 | 52 | ||
49 | checkErrors(req, res, function () { | 53 | checkErrors(req, res, function () { |
50 | db.Video.load(req.params.id, function (err, video) { | 54 | checkVideoExists(req.params.id, res, next) |
51 | if (err) { | 55 | }) |
52 | logger.error('Error in videosGet request validator.', { error: err }) | 56 | } |
53 | return res.sendStatus(500) | ||
54 | } | ||
55 | 57 | ||
56 | if (!video) return res.status(404).send('Video not found') | 58 | function videosGet (req, res, next) { |
59 | req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) | ||
57 | 60 | ||
58 | next() | 61 | logger.debug('Checking videosGet parameters', { parameters: req.params }) |
59 | }) | 62 | |
63 | checkErrors(req, res, function () { | ||
64 | checkVideoExists(req.params.id, res, next) | ||
60 | }) | 65 | }) |
61 | } | 66 | } |
62 | 67 | ||
@@ -94,3 +99,19 @@ function videosSearch (req, res, next) { | |||
94 | // --------------------------------------------------------------------------- | 99 | // --------------------------------------------------------------------------- |
95 | 100 | ||
96 | module.exports = validatorsVideos | 101 | module.exports = validatorsVideos |
102 | |||
103 | // --------------------------------------------------------------------------- | ||
104 | |||
105 | function checkVideoExists (id, res, callback) { | ||
106 | db.Video.loadAndPopulateAuthorAndPodAndTags(id, function (err, video) { | ||
107 | if (err) { | ||
108 | logger.error('Error in video request validator.', { error: err }) | ||
109 | return res.sendStatus(500) | ||
110 | } | ||
111 | |||
112 | if (!video) return res.status(404).send('Video not found') | ||
113 | |||
114 | res.locals.video = video | ||
115 | callback() | ||
116 | }) | ||
117 | } | ||
diff --git a/server/models/video.js b/server/models/video.js index 0e84e8986..14fbe2f71 100644 --- a/server/models/video.js +++ b/server/models/video.js | |||
@@ -127,7 +127,8 @@ module.exports = function (sequelize, DataTypes) { | |||
127 | getTorrentName, | 127 | getTorrentName, |
128 | isOwned, | 128 | isOwned, |
129 | toFormatedJSON, | 129 | toFormatedJSON, |
130 | toRemoteJSON | 130 | toAddRemoteJSON, |
131 | toUpdateRemoteJSON | ||
131 | }, | 132 | }, |
132 | hooks: { | 133 | hooks: { |
133 | beforeValidate, | 134 | beforeValidate, |
@@ -334,7 +335,7 @@ function toFormatedJSON () { | |||
334 | return json | 335 | return json |
335 | } | 336 | } |
336 | 337 | ||
337 | function toRemoteJSON (callback) { | 338 | function toAddRemoteJSON (callback) { |
338 | const self = this | 339 | const self = this |
339 | 340 | ||
340 | // Get thumbnail data to send to the other pod | 341 | // Get thumbnail data to send to the other pod |
@@ -362,6 +363,22 @@ function toRemoteJSON (callback) { | |||
362 | }) | 363 | }) |
363 | } | 364 | } |
364 | 365 | ||
366 | function toUpdateRemoteJSON (callback) { | ||
367 | const json = { | ||
368 | name: this.name, | ||
369 | description: this.description, | ||
370 | infoHash: this.infoHash, | ||
371 | remoteId: this.id, | ||
372 | author: this.Author.name, | ||
373 | duration: this.duration, | ||
374 | tags: map(this.Tags, 'name'), | ||
375 | createdAt: this.createdAt, | ||
376 | extname: this.extname | ||
377 | } | ||
378 | |||
379 | return json | ||
380 | } | ||
381 | |||
365 | // ------------------------------ STATICS ------------------------------ | 382 | // ------------------------------ STATICS ------------------------------ |
366 | 383 | ||
367 | function generateThumbnailFromData (video, thumbnailData, callback) { | 384 | function generateThumbnailFromData (video, thumbnailData, callback) { |
diff --git a/server/tests/api/check-params.js b/server/tests/api/check-params.js index 9aecc3720..e8f2aa821 100644 --- a/server/tests/api/check-params.js +++ b/server/tests/api/check-params.js | |||
@@ -10,6 +10,7 @@ const loginUtils = require('../utils/login') | |||
10 | const requestsUtils = require('../utils/requests') | 10 | const requestsUtils = require('../utils/requests') |
11 | const serversUtils = require('../utils/servers') | 11 | const serversUtils = require('../utils/servers') |
12 | const usersUtils = require('../utils/users') | 12 | const usersUtils = require('../utils/users') |
13 | const videosUtils = require('../utils/videos') | ||
13 | 14 | ||
14 | describe('Test parameters validator', function () { | 15 | describe('Test parameters validator', function () { |
15 | let server = null | 16 | let server = null |
@@ -439,6 +440,106 @@ describe('Test parameters validator', function () { | |||
439 | }) | 440 | }) |
440 | }) | 441 | }) |
441 | 442 | ||
443 | describe('When updating a video', function () { | ||
444 | let videoId | ||
445 | |||
446 | before(function (done) { | ||
447 | videosUtils.getVideosList(server.url, function (err, res) { | ||
448 | if (err) throw err | ||
449 | |||
450 | videoId = res.body.data[0].id | ||
451 | |||
452 | return done() | ||
453 | }) | ||
454 | }) | ||
455 | |||
456 | it('Should fail with nothing', function (done) { | ||
457 | const data = {} | ||
458 | requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) | ||
459 | }) | ||
460 | |||
461 | it('Should fail without a valid uuid', function (done) { | ||
462 | const data = { | ||
463 | description: 'my super description', | ||
464 | tags: [ 'tag1', 'tag2' ] | ||
465 | } | ||
466 | requestsUtils.makePutBodyRequest(server.url, path + 'blabla', server.accessToken, data, done) | ||
467 | }) | ||
468 | |||
469 | it('Should fail with an unknown id', function (done) { | ||
470 | const data = { | ||
471 | description: 'my super description', | ||
472 | tags: [ 'tag1', 'tag2' ] | ||
473 | } | ||
474 | requestsUtils.makePutBodyRequest(server.url, path + '4da6fde3-88f7-4d16-b119-108df5630b06', server.accessToken, data, done) | ||
475 | }) | ||
476 | |||
477 | it('Should fail with a long name', function (done) { | ||
478 | const data = { | ||
479 | name: 'My very very very very very very very very very very very very very very very very long name', | ||
480 | description: 'my super description', | ||
481 | tags: [ 'tag1', 'tag2' ] | ||
482 | } | ||
483 | requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) | ||
484 | }) | ||
485 | |||
486 | it('Should fail with a long description', function (done) { | ||
487 | const data = { | ||
488 | name: 'my super name', | ||
489 | description: 'my super description which is very very very very very very very very very very very very very very' + | ||
490 | 'very very very very very very very very very very very very very very very very very very very very very' + | ||
491 | 'very very very very very very very very very very very very very very very long', | ||
492 | tags: [ 'tag1', 'tag2' ] | ||
493 | } | ||
494 | requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) | ||
495 | }) | ||
496 | |||
497 | it('Should fail with too many tags', function (done) { | ||
498 | const data = { | ||
499 | name: 'my super name', | ||
500 | description: 'my super description', | ||
501 | tags: [ 'tag1', 'tag2', 'tag3', 'tag4' ] | ||
502 | } | ||
503 | requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) | ||
504 | }) | ||
505 | |||
506 | it('Should fail with not enough tags', function (done) { | ||
507 | const data = { | ||
508 | name: 'my super name', | ||
509 | description: 'my super description', | ||
510 | tags: [ ] | ||
511 | } | ||
512 | requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) | ||
513 | }) | ||
514 | |||
515 | it('Should fail with a tag length too low', function (done) { | ||
516 | const data = { | ||
517 | name: 'my super name', | ||
518 | description: 'my super description', | ||
519 | tags: [ 'tag1', 't' ] | ||
520 | } | ||
521 | requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) | ||
522 | }) | ||
523 | |||
524 | it('Should fail with a tag length too big', function (done) { | ||
525 | const data = { | ||
526 | name: 'my super name', | ||
527 | description: 'my super description', | ||
528 | tags: [ 'mysupertagtoolong', 'tag1' ] | ||
529 | } | ||
530 | requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) | ||
531 | }) | ||
532 | |||
533 | it('Should fail with malformed tags', function (done) { | ||
534 | const data = { | ||
535 | name: 'my super name', | ||
536 | description: 'my super description', | ||
537 | tags: [ 'my tag' ] | ||
538 | } | ||
539 | requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) | ||
540 | }) | ||
541 | }) | ||
542 | |||
442 | describe('When getting a video', function () { | 543 | describe('When getting a video', function () { |
443 | it('Should return the list of the videos with nothing', function (done) { | 544 | it('Should return the list of the videos with nothing', function (done) { |
444 | request(server.url) | 545 | request(server.url) |
diff --git a/server/tests/api/single-pod.js b/server/tests/api/single-pod.js index 66b762f82..57146900d 100644 --- a/server/tests/api/single-pod.js +++ b/server/tests/api/single-pod.js | |||
@@ -495,10 +495,86 @@ describe('Test a single pod', function () { | |||
495 | expect(videos[2].name === 'video_short2.webm name') | 495 | expect(videos[2].name === 'video_short2.webm name') |
496 | expect(videos[3].name === 'video_short3.webm name') | 496 | expect(videos[3].name === 'video_short3.webm name') |
497 | 497 | ||
498 | videoId = videos[3].id | ||
499 | |||
498 | done() | 500 | done() |
499 | }) | 501 | }) |
500 | }) | 502 | }) |
501 | 503 | ||
504 | it('Should update a video', function (done) { | ||
505 | const name = 'my super video updated' | ||
506 | const description = 'my super description updated' | ||
507 | const tags = [ 'tagup1', 'tagup2' ] | ||
508 | |||
509 | videosUtils.updateVideo(server.url, server.accessToken, videoId, name, description, tags, done) | ||
510 | }) | ||
511 | |||
512 | it('Should have the video updated', function (done) { | ||
513 | videosUtils.getVideo(server.url, videoId, function (err, res) { | ||
514 | if (err) throw err | ||
515 | |||
516 | const video = res.body | ||
517 | |||
518 | expect(video.name).to.equal('my super video updated') | ||
519 | expect(video.description).to.equal('my super description updated') | ||
520 | expect(video.podHost).to.equal('localhost:9001') | ||
521 | expect(video.author).to.equal('root') | ||
522 | expect(video.isLocal).to.be.true | ||
523 | expect(video.tags).to.deep.equal([ 'tagup1', 'tagup2' ]) | ||
524 | expect(miscsUtils.dateIsValid(video.createdAt)).to.be.true | ||
525 | |||
526 | done() | ||
527 | }) | ||
528 | }) | ||
529 | |||
530 | it('Should update only the tags of a video', function (done) { | ||
531 | const tags = [ 'tag1', 'tag2', 'supertag' ] | ||
532 | |||
533 | videosUtils.updateVideo(server.url, server.accessToken, videoId, null, null, tags, function (err) { | ||
534 | if (err) throw err | ||
535 | |||
536 | videosUtils.getVideo(server.url, videoId, function (err, res) { | ||
537 | if (err) throw err | ||
538 | |||
539 | const video = res.body | ||
540 | |||
541 | expect(video.name).to.equal('my super video updated') | ||
542 | expect(video.description).to.equal('my super description updated') | ||
543 | expect(video.podHost).to.equal('localhost:9001') | ||
544 | expect(video.author).to.equal('root') | ||
545 | expect(video.isLocal).to.be.true | ||
546 | expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ]) | ||
547 | expect(miscsUtils.dateIsValid(video.createdAt)).to.be.true | ||
548 | |||
549 | done() | ||
550 | }) | ||
551 | }) | ||
552 | }) | ||
553 | |||
554 | it('Should update only the description of a video', function (done) { | ||
555 | const description = 'hello everybody' | ||
556 | |||
557 | videosUtils.updateVideo(server.url, server.accessToken, videoId, null, description, null, function (err) { | ||
558 | if (err) throw err | ||
559 | |||
560 | videosUtils.getVideo(server.url, videoId, function (err, res) { | ||
561 | if (err) throw err | ||
562 | |||
563 | const video = res.body | ||
564 | |||
565 | expect(video.name).to.equal('my super video updated') | ||
566 | expect(video.description).to.equal('hello everybody') | ||
567 | expect(video.podHost).to.equal('localhost:9001') | ||
568 | expect(video.author).to.equal('root') | ||
569 | expect(video.isLocal).to.be.true | ||
570 | expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ]) | ||
571 | expect(miscsUtils.dateIsValid(video.createdAt)).to.be.true | ||
572 | |||
573 | done() | ||
574 | }) | ||
575 | }) | ||
576 | }) | ||
577 | |||
502 | after(function (done) { | 578 | after(function (done) { |
503 | process.kill(-server.app.pid) | 579 | process.kill(-server.app.pid) |
504 | 580 | ||
diff --git a/server/tests/utils/videos.js b/server/tests/utils/videos.js index 5c120597f..beafd3cf5 100644 --- a/server/tests/utils/videos.js +++ b/server/tests/utils/videos.js | |||
@@ -15,7 +15,8 @@ const videosUtils = { | |||
15 | searchVideoWithPagination, | 15 | searchVideoWithPagination, |
16 | searchVideoWithSort, | 16 | searchVideoWithSort, |
17 | testVideoImage, | 17 | testVideoImage, |
18 | uploadVideo | 18 | uploadVideo, |
19 | updateVideo | ||
19 | } | 20 | } |
20 | 21 | ||
21 | // ---------------------- Export functions -------------------- | 22 | // ---------------------- Export functions -------------------- |
@@ -194,6 +195,31 @@ function uploadVideo (url, accessToken, name, description, tags, fixture, specia | |||
194 | .end(end) | 195 | .end(end) |
195 | } | 196 | } |
196 | 197 | ||
198 | function updateVideo (url, accessToken, id, name, description, tags, specialStatus, end) { | ||
199 | if (!end) { | ||
200 | end = specialStatus | ||
201 | specialStatus = 204 | ||
202 | } | ||
203 | |||
204 | const path = '/api/v1/videos/' + id | ||
205 | |||
206 | const req = request(url) | ||
207 | .put(path) | ||
208 | .set('Accept', 'application/json') | ||
209 | .set('Authorization', 'Bearer ' + accessToken) | ||
210 | |||
211 | if (name) req.field('name', name) | ||
212 | if (description) req.field('description', description) | ||
213 | |||
214 | if (tags) { | ||
215 | for (let i = 0; i < tags.length; i++) { | ||
216 | req.field('tags[' + i + ']', tags[i]) | ||
217 | } | ||
218 | } | ||
219 | |||
220 | req.expect(specialStatus).end(end) | ||
221 | } | ||
222 | |||
197 | // --------------------------------------------------------------------------- | 223 | // --------------------------------------------------------------------------- |
198 | 224 | ||
199 | module.exports = videosUtils | 225 | module.exports = videosUtils |