From 7b1f49de22c40ae121ddb3c399b2540ba56fd414 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 29 Dec 2016 19:07:05 +0100 Subject: Server: add ability to update a video --- server/controllers/api/videos.js | 85 ++++++++++++++++++++++++++- server/lib/friends.js | 7 ++- server/middlewares/validators/videos.js | 41 +++++++++---- server/models/video.js | 21 ++++++- server/tests/api/check-params.js | 101 ++++++++++++++++++++++++++++++++ server/tests/api/single-pod.js | 76 ++++++++++++++++++++++++ server/tests/utils/videos.js | 28 ++++++++- 7 files changed, 344 insertions(+), 15 deletions(-) (limited to 'server') 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('/', pagination.setPagination, listVideos ) +router.put('/:id', + oAuth.authenticate, + reqFiles, + validatorsVideos.videosUpdate, + updateVideo +) router.post('/', oAuth.authenticate, reqFiles, @@ -165,7 +171,7 @@ function addVideo (req, res, next) { }, function sendToFriends (t, video, callback) { - video.toRemoteJSON(function (err, remoteVideo) { + video.toAddRemoteJSON(function (err, remoteVideo) { if (err) return callback(err) // Now we'll add the video's meta data to our friends @@ -193,6 +199,83 @@ function addVideo (req, res, next) { }) } +function updateVideo (req, res, next) { + let videoInstance = res.locals.video + const videoInfosToUpdate = req.body + + waterfall([ + + function startTransaction (callback) { + db.sequelize.transaction().asCallback(function (err, t) { + return callback(err, t) + }) + }, + + function findOrCreateTags (t, callback) { + if (videoInfosToUpdate.tags) { + db.Tag.findOrCreateTags(videoInfosToUpdate.tags, t, function (err, tagInstances) { + return callback(err, t, tagInstances) + }) + } else { + return callback(null, t, null) + } + }, + + function updateVideoIntoDB (t, tagInstances, callback) { + const options = { transaction: t } + + if (videoInfosToUpdate.name) videoInstance.set('name', videoInfosToUpdate.name) + if (videoInfosToUpdate.description) videoInstance.set('description', videoInfosToUpdate.description) + + // Add tags association + videoInstance.save(options).asCallback(function (err) { + if (err) return callback(err) + + return callback(err, t, tagInstances) + }) + }, + + function associateTagsToVideo (t, tagInstances, callback) { + if (tagInstances) { + const options = { transaction: t } + + videoInstance.setTags(tagInstances, options).asCallback(function (err) { + videoInstance.Tags = tagInstances + + return callback(err, t) + }) + } else { + return callback(null, t) + } + }, + + function sendToFriends (t, callback) { + const json = videoInstance.toUpdateRemoteJSON() + + // Now we'll update the video's meta data to our friends + friends.updateVideoToFriends(json) + + return callback(null, t) + } + + ], function andFinally (err, t) { + if (err) { + logger.error('Cannot insert the video.') + + // Abort transaction? + if (t) t.rollback() + + return next(err) + } + + // Commit transaction + t.commit() + + // TODO : include Location of the new video -> 201 + return res.type('json').status(204).end() + }) +} + function getVideo (req, res, next) { db.Video.loadAndPopulateAuthorAndPodAndTags(req.params.id, function (err, video) { 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') const friends = { addVideoToFriends, + updateVideoToFriends, hasFriends, getMyCertificate, makeFriends, @@ -26,6 +27,10 @@ function addVideoToFriends (video) { createRequest('add', constants.REQUEST_ENDPOINTS.VIDEOS, video) } +function updateVideoToFriends (video) { + createRequest('update', constants.REQUEST_ENDPOINTS.VIDEOS, video) +} + function hasFriends (callback) { db.Pod.countAll(function (err, count) { if (err) return callback(err) @@ -127,7 +132,7 @@ function sendOwnedVideosToPod (podId) { } videosList.forEach(function (video) { - video.toRemoteJSON(function (err, remoteVideo) { + video.toAddRemoteJSON(function (err, remoteVideo) { if (err) { logger.error('Cannot convert video to remote.', { error: err }) // 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') const validatorsVideos = { videosAdd, + videosUpdate, videosGet, videosRemove, videosSearch @@ -41,22 +42,26 @@ function videosAdd (req, res, next) { }) } -function videosGet (req, res, next) { +function videosUpdate (req, res, next) { req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) + req.checkBody('name', 'Should have a valid name').optional().isVideoNameValid() + req.checkBody('description', 'Should have a valid description').optional().isVideoDescriptionValid() + req.checkBody('tags', 'Should have correct tags').optional().isVideoTagsValid() - logger.debug('Checking videosGet parameters', { parameters: req.params }) + logger.debug('Checking videosUpdate parameters', { parameters: req.body }) checkErrors(req, res, function () { - db.Video.load(req.params.id, function (err, video) { - if (err) { - logger.error('Error in videosGet request validator.', { error: err }) - return res.sendStatus(500) - } + checkVideoExists(req.params.id, res, next) + }) +} - if (!video) return res.status(404).send('Video not found') +function videosGet (req, res, next) { + req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) - next() - }) + logger.debug('Checking videosGet parameters', { parameters: req.params }) + + checkErrors(req, res, function () { + checkVideoExists(req.params.id, res, next) }) } @@ -94,3 +99,19 @@ function videosSearch (req, res, next) { // --------------------------------------------------------------------------- module.exports = validatorsVideos + +// --------------------------------------------------------------------------- + +function checkVideoExists (id, res, callback) { + db.Video.loadAndPopulateAuthorAndPodAndTags(id, function (err, video) { + if (err) { + logger.error('Error in video request validator.', { error: err }) + return res.sendStatus(500) + } + + if (!video) return res.status(404).send('Video not found') + + res.locals.video = video + callback() + }) +} 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) { getTorrentName, isOwned, toFormatedJSON, - toRemoteJSON + toAddRemoteJSON, + toUpdateRemoteJSON }, hooks: { beforeValidate, @@ -334,7 +335,7 @@ function toFormatedJSON () { return json } -function toRemoteJSON (callback) { +function toAddRemoteJSON (callback) { const self = this // Get thumbnail data to send to the other pod @@ -362,6 +363,22 @@ function toRemoteJSON (callback) { }) } +function toUpdateRemoteJSON (callback) { + const json = { + name: this.name, + description: this.description, + infoHash: this.infoHash, + remoteId: this.id, + author: this.Author.name, + duration: this.duration, + tags: map(this.Tags, 'name'), + createdAt: this.createdAt, + extname: this.extname + } + + return json +} + // ------------------------------ STATICS ------------------------------ 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') const requestsUtils = require('../utils/requests') const serversUtils = require('../utils/servers') const usersUtils = require('../utils/users') +const videosUtils = require('../utils/videos') describe('Test parameters validator', function () { let server = null @@ -439,6 +440,106 @@ describe('Test parameters validator', function () { }) }) + describe('When updating a video', function () { + let videoId + + before(function (done) { + videosUtils.getVideosList(server.url, function (err, res) { + if (err) throw err + + videoId = res.body.data[0].id + + return done() + }) + }) + + it('Should fail with nothing', function (done) { + const data = {} + requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) + }) + + it('Should fail without a valid uuid', function (done) { + const data = { + description: 'my super description', + tags: [ 'tag1', 'tag2' ] + } + requestsUtils.makePutBodyRequest(server.url, path + 'blabla', server.accessToken, data, done) + }) + + it('Should fail with an unknown id', function (done) { + const data = { + description: 'my super description', + tags: [ 'tag1', 'tag2' ] + } + requestsUtils.makePutBodyRequest(server.url, path + '4da6fde3-88f7-4d16-b119-108df5630b06', server.accessToken, data, done) + }) + + it('Should fail with a long name', function (done) { + const data = { + name: 'My very very very very very very very very very very very very very very very very long name', + description: 'my super description', + tags: [ 'tag1', 'tag2' ] + } + requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) + }) + + it('Should fail with a long description', function (done) { + const data = { + name: 'my super name', + description: 'my super description which is very very very very very very very very very very very very very very' + + 'very very very very very very very very very very very very very very very very very very very very very' + + 'very very very very very very very very very very very very very very very long', + tags: [ 'tag1', 'tag2' ] + } + requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) + }) + + it('Should fail with too many tags', function (done) { + const data = { + name: 'my super name', + description: 'my super description', + tags: [ 'tag1', 'tag2', 'tag3', 'tag4' ] + } + requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) + }) + + it('Should fail with not enough tags', function (done) { + const data = { + name: 'my super name', + description: 'my super description', + tags: [ ] + } + requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) + }) + + it('Should fail with a tag length too low', function (done) { + const data = { + name: 'my super name', + description: 'my super description', + tags: [ 'tag1', 't' ] + } + requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) + }) + + it('Should fail with a tag length too big', function (done) { + const data = { + name: 'my super name', + description: 'my super description', + tags: [ 'mysupertagtoolong', 'tag1' ] + } + requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) + }) + + it('Should fail with malformed tags', function (done) { + const data = { + name: 'my super name', + description: 'my super description', + tags: [ 'my tag' ] + } + requestsUtils.makePutBodyRequest(server.url, path + videoId, server.accessToken, data, done) + }) + }) + describe('When getting a video', function () { it('Should return the list of the videos with nothing', function (done) { 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 () { expect(videos[2].name === 'video_short2.webm name') expect(videos[3].name === 'video_short3.webm name') + videoId = videos[3].id + done() }) }) + it('Should update a video', function (done) { + const name = 'my super video updated' + const description = 'my super description updated' + const tags = [ 'tagup1', 'tagup2' ] + + videosUtils.updateVideo(server.url, server.accessToken, videoId, name, description, tags, done) + }) + + it('Should have the video updated', function (done) { + videosUtils.getVideo(server.url, videoId, function (err, res) { + if (err) throw err + + const video = res.body + + expect(video.name).to.equal('my super video updated') + expect(video.description).to.equal('my super description updated') + expect(video.podHost).to.equal('localhost:9001') + expect(video.author).to.equal('root') + expect(video.isLocal).to.be.true + expect(video.tags).to.deep.equal([ 'tagup1', 'tagup2' ]) + expect(miscsUtils.dateIsValid(video.createdAt)).to.be.true + + done() + }) + }) + + it('Should update only the tags of a video', function (done) { + const tags = [ 'tag1', 'tag2', 'supertag' ] + + videosUtils.updateVideo(server.url, server.accessToken, videoId, null, null, tags, function (err) { + if (err) throw err + + videosUtils.getVideo(server.url, videoId, function (err, res) { + if (err) throw err + + const video = res.body + + expect(video.name).to.equal('my super video updated') + expect(video.description).to.equal('my super description updated') + expect(video.podHost).to.equal('localhost:9001') + expect(video.author).to.equal('root') + expect(video.isLocal).to.be.true + expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ]) + expect(miscsUtils.dateIsValid(video.createdAt)).to.be.true + + done() + }) + }) + }) + + it('Should update only the description of a video', function (done) { + const description = 'hello everybody' + + videosUtils.updateVideo(server.url, server.accessToken, videoId, null, description, null, function (err) { + if (err) throw err + + videosUtils.getVideo(server.url, videoId, function (err, res) { + if (err) throw err + + const video = res.body + + expect(video.name).to.equal('my super video updated') + expect(video.description).to.equal('hello everybody') + expect(video.podHost).to.equal('localhost:9001') + expect(video.author).to.equal('root') + expect(video.isLocal).to.be.true + expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ]) + expect(miscsUtils.dateIsValid(video.createdAt)).to.be.true + + done() + }) + }) + }) + after(function (done) { process.kill(-server.app.pid) 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 = { searchVideoWithPagination, searchVideoWithSort, testVideoImage, - uploadVideo + uploadVideo, + updateVideo } // ---------------------- Export functions -------------------- @@ -194,6 +195,31 @@ function uploadVideo (url, accessToken, name, description, tags, fixture, specia .end(end) } +function updateVideo (url, accessToken, id, name, description, tags, specialStatus, end) { + if (!end) { + end = specialStatus + specialStatus = 204 + } + + const path = '/api/v1/videos/' + id + + const req = request(url) + .put(path) + .set('Accept', 'application/json') + .set('Authorization', 'Bearer ' + accessToken) + + if (name) req.field('name', name) + if (description) req.field('description', description) + + if (tags) { + for (let i = 0; i < tags.length; i++) { + req.field('tags[' + i + ']', tags[i]) + } + } + + req.expect(specialStatus).end(end) +} + // --------------------------------------------------------------------------- module.exports = videosUtils -- cgit v1.2.3