diff --git a/server/controllers/api/v1/videos.js b/server/controllers/api/v1/videos.js index b6e3de08f..0e058836e 100644 --- a/server/controllers/api/v1/videos.js +++ b/server/controllers/api/v1/videos.js @@ -11,7 +11,10 @@ const logger = require('../../../helpers/logger') const friends = require('../../../lib/friends') const middlewares = require('../../../middlewares') const oAuth2 = middlewares.oauth2 -const reqValidator = middlewares.reqValidators.videos +const pagination = middlewares.pagination +const reqValidator = middlewares.reqValidators +const reqValidatorPagination = reqValidator.pagination +const reqValidatorVideos = reqValidator.videos const utils = require('../../../helpers/utils') const Videos = require('../../../models/videos') // model const videos = require('../../../lib/videos') @@ -41,11 +44,32 @@ const storage = multer.diskStorage({ const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }]) const thumbnailsDir = path.join(__dirname, '..', '..', '..', '..', config.get('storage.thumbnails')) -router.get('/', listVideos) -router.post('/', oAuth2.authenticate, reqFiles, reqValidator.videosAdd, addVideo) -router.get('/:id', reqValidator.videosGet, getVideos) -router.delete('/:id', oAuth2.authenticate, reqValidator.videosRemove, removeVideo) -router.get('/search/:name', reqValidator.videosSearch, searchVideos) +router.get('/', + reqValidatorPagination.pagination, + pagination.setPagination, + listVideos +) +router.post('/', + oAuth2.authenticate, + reqFiles, + reqValidatorVideos.videosAdd, + addVideo +) +router.get('/:id', + reqValidatorVideos.videosGet, + getVideos +) +router.delete('/:id', + oAuth2.authenticate, + reqValidatorVideos.videosRemove, + removeVideo +) +router.get('/search/:name', + reqValidatorVideos.videosSearch, + reqValidatorPagination.pagination, + pagination.setPagination, + searchVideos +) // --------------------------------------------------------------------------- @@ -129,7 +153,7 @@ function getVideos (req, res, next) { } function listVideos (req, res, next) { - Videos.list(function (err, videosList) { + Videos.list(req.query.start, req.query.count, function (err, videosList) { if (err) return next(err) res.json(getFormatedVideos(videosList)) @@ -162,7 +186,7 @@ function removeVideo (req, res, next) { } function searchVideos (req, res, next) { - Videos.search(req.params.name, function (err, videosList) { + Videos.search(req.params.name, req.query.start, req.query.count, function (err, videosList) { if (err) return next(err) res.json(getFormatedVideos(videosList)) diff --git a/server/middlewares/index.js b/server/middlewares/index.js index ffd19337c..f0fad3418 100644 --- a/server/middlewares/index.js +++ b/server/middlewares/index.js @@ -1,11 +1,13 @@ 'use strict' const oauth2 = require('./oauth2') +const pagination = require('./pagination') const reqValidatorsMiddleware = require('./reqValidators') const secureMiddleware = require('./secure') const middlewares = { oauth2: oauth2, + pagination: pagination, reqValidators: reqValidatorsMiddleware, secure: secureMiddleware } diff --git a/server/middlewares/pagination.js b/server/middlewares/pagination.js new file mode 100644 index 000000000..2a426ec28 --- /dev/null +++ b/server/middlewares/pagination.js @@ -0,0 +1,18 @@ +'use strict' + +const paginationMiddleware = { + setPagination: setPagination +} + +function setPagination (req, res, next) { + if (!req.query.start) req.query.start = 0 + else req.query.start = parseInt(req.query.start) + if (!req.query.count) req.query.count = 15 + else req.query.count = parseInt(req.query.count) + + return next() +} + +// --------------------------------------------------------------------------- + +module.exports = paginationMiddleware diff --git a/server/middlewares/reqValidators/index.js b/server/middlewares/reqValidators/index.js index c6c5e1309..b732a27b6 100644 --- a/server/middlewares/reqValidators/index.js +++ b/server/middlewares/reqValidators/index.js @@ -1,10 +1,12 @@ 'use strict' +const paginationReqValidators = require('./pagination') const podsReqValidators = require('./pods') const remoteReqValidators = require('./remote') const videosReqValidators = require('./videos') const reqValidators = { + pagination: paginationReqValidators, pods: podsReqValidators, remote: remoteReqValidators, videos: videosReqValidators diff --git a/server/middlewares/reqValidators/pagination.js b/server/middlewares/reqValidators/pagination.js new file mode 100644 index 000000000..ca8375396 --- /dev/null +++ b/server/middlewares/reqValidators/pagination.js @@ -0,0 +1,21 @@ +'use strict' + +const checkErrors = require('./utils').checkErrors +const logger = require('../../helpers/logger') + +const reqValidatorsPagination = { + pagination: pagination +} + +function pagination (req, res, next) { + req.checkParams('start', 'Should have a number start').optional().isInt() + req.checkParams('count', 'Should have a number count').optional().isInt() + + logger.debug('Checking pagination parameters', { parameters: req.params }) + + checkErrors(req, res, next) +} + +// --------------------------------------------------------------------------- + +module.exports = reqValidatorsPagination diff --git a/server/models/videos.js b/server/models/videos.js index eaea35b7f..aa9ed687d 100644 --- a/server/models/videos.js +++ b/server/models/videos.js @@ -76,8 +76,8 @@ function get (id, callback) { }) } -function list (callback) { - VideosDB.find(function (err, videosList) { +function list (start, count, callback) { + VideosDB.find({}).skip(start).limit(start + count).exec(function (err, videosList) { if (err) { logger.error('Cannot get the list of the videos.') return callback(err) @@ -125,8 +125,9 @@ function removeByIds (ids, callback) { VideosDB.remove({ _id: { $in: ids } }, callback) } -function search (name, callback) { - VideosDB.find({ name: new RegExp(name) }, function (err, videos) { +function search (name, start, count, callback) { + VideosDB.find({ name: new RegExp(name) }).skip(start).limit(start + count) + .exec(function (err, videos) { if (err) { logger.error('Cannot search the videos.') return callback(err) diff --git a/server/tests/api/singlePod.js b/server/tests/api/singlePod.js index 0d0e6a82e..d377bdf45 100644 --- a/server/tests/api/singlePod.js +++ b/server/tests/api/singlePod.js @@ -15,6 +15,7 @@ const utils = require('./utils') describe('Test a single pod', function () { let server = null let videoId = -1 + let videosListBase = null before(function (done) { this.timeout(20000) @@ -215,7 +216,11 @@ describe('Test a single pod', function () { it('Should have the correct thumbnails', function (done) { utils.getVideosList(server.url, function (err, res) { + if (err) throw err + const videos = res.body + // For the next test + videosListBase = videos async.each(videos, function (video, callbackEach) { if (err) throw err @@ -231,6 +236,81 @@ describe('Test a single pod', function () { }) }) + it('Should list only the two first videos', function (done) { + utils.getVideosListPagination(server.url, 0, 2, function (err, res) { + if (err) throw err + + const videos = res.body + expect(videos.length).to.equal(2) + expect(videos[0].name === videosListBase[0].name) + expect(videos[1].name === videosListBase[1].name) + + done() + }) + }) + + it('Should list only the next three videos', function (done) { + utils.getVideosListPagination(server.url, 2, 3, function (err, res) { + if (err) throw err + + const videos = res.body + expect(videos.length).to.equal(4) + expect(videos[0].name === videosListBase[2].name) + expect(videos[1].name === videosListBase[3].name) + expect(videos[2].name === videosListBase[4].name) + + done() + }) + }) + + it('Should list the last video', function (done) { + utils.getVideosListPagination(server.url, 5, 6, function (err, res) { + if (err) throw err + + const videos = res.body + expect(videos.length).to.equal(1) + expect(videos[0].name === videosListBase[5].name) + + done() + }) + }) + + it('Should search the first video', function (done) { + utils.searchVideoWithPagination(server.url, 'webm', 0, 1, function (err, res) { + if (err) throw err + + const videos = res.body + expect(videos.length).to.equal(1) + expect(videos[0].name === 'video_short.webm name') + + done() + }) + }) + + it('Should search the last two videos', function (done) { + utils.searchVideoWithPagination(server.url, 'webm', 2, 2, function (err, res) { + if (err) throw err + + const videos = res.body + expect(videos.length).to.equal(2) + expect(videos[0].name === 'video_short2.webm name') + expect(videos[1].name === 'video_short3.webm name') + + done() + }) + }) + + it('Should search all the videos', function (done) { + utils.searchVideoWithPagination(server.url, 'webm', 0, 15, function (err, res) { + if (err) throw err + + const videos = res.body + expect(videos.length).to.equal(4) + + done() + }) + }) + after(function (done) { process.kill(-server.app.pid) process.kill(-webtorrent.app.pid) diff --git a/server/tests/api/utils.js b/server/tests/api/utils.js index 9c5e4ee61..f0b1c3653 100644 --- a/server/tests/api/utils.js +++ b/server/tests/api/utils.js @@ -12,6 +12,7 @@ const testUtils = { getFriendsList: getFriendsList, getVideo: getVideo, getVideosList: getVideosList, + getVideosListPagination: getVideosListPagination, login: login, loginAndGetAccessToken: loginAndGetAccessToken, makeFriends: makeFriends, @@ -20,6 +21,7 @@ const testUtils = { flushAndRunMultipleServers: flushAndRunMultipleServers, runServer: runServer, searchVideo: searchVideo, + searchVideoWithPagination: searchVideoWithPagination, testImage: testImage, uploadVideo: uploadVideo } @@ -63,6 +65,19 @@ function getVideosList (url, end) { .end(end) } +function getVideosListPagination (url, start, count, end) { + const path = '/api/v1/videos' + + request(url) + .get(path) + .query({ start: start }) + .query({ count: count }) + .set('Accept', 'application/json') + .expect(200) + .expect('Content-Type', /json/) + .end(end) +} + function login (url, client, user, expectedStatus, end) { if (!end) { end = expectedStatus @@ -261,6 +276,19 @@ function searchVideo (url, search, end) { .end(end) } +function searchVideoWithPagination (url, search, start, count, end) { + const path = '/api/v1/videos' + + request(url) + .get(path + '/search/' + search) + .query({ start: start }) + .query({ count: count }) + .set('Accept', 'application/json') + .expect(200) + .expect('Content-Type', /json/) + .end(end) +} + function testImage (url, videoName, imagePath, callback) { request(url) .get(imagePath)