diff --git a/src/routes/tasks.js b/src/routes/tasks.js index 290e770de..e6ae15dca 100644 --- a/src/routes/tasks.js +++ b/src/routes/tasks.js @@ -2,7 +2,8 @@ exports = module.exports = { get: get, - stopTask: stopTask + stopTask: stopTask, + list: list }; let assert = require('assert'), @@ -31,10 +32,27 @@ function stopTask(req, res, next) { function get(req, res, next) { assert.strictEqual(typeof req.params.taskId, 'string'); - tasks.get(req.params.taskId, function (error, progress) { + tasks.get(req.params.taskId, function (error, task) { if (error && error.reason === TaskError.NOT_FOUND) return next(new HttpError(404, 'No such task')); if (error) return next(new HttpError(500, error)); - next(new HttpSuccess(200, progress)); + next(new HttpSuccess(200, task)); + }); +} + +function list(req, res, next) { + var page = typeof req.query.page !== 'undefined' ? parseInt(req.query.page) : 1; + if (!page || page < 0) return next(new HttpError(400, 'page query param has to be a postive number')); + + var perPage = typeof req.query.per_page !== 'undefined'? parseInt(req.query.per_page) : 25; + if (!perPage || perPage < 0) return next(new HttpError(400, 'per_page query param has to be a postive number')); + + if (req.query.type && typeof req.query.type !== 'string') return next(new HttpError(400, 'type must be a string')); + + tasks.listPaged(req.query.type || null, page, perPage, function (error, tasks) { + if (error && error.reason === TaskError.NOT_FOUND) return next(new HttpError(404, 'No such task')); + if (error) return next(new HttpError(500, error)); + + next(new HttpSuccess(200, { tasks })); }); } diff --git a/src/server.js b/src/server.js index e061f138b..7c8d2961f 100644 --- a/src/server.js +++ b/src/server.js @@ -136,6 +136,7 @@ function initializeExpressSync() { router.get ('/api/v1/cloudron/eventlog', cloudronScope, routes.eventlog.get); // tasks + router.get ('/api/v1/tasks', settingsScope, routes.tasks.list); router.get ('/api/v1/tasks/:taskId', settingsScope, routes.tasks.get); router.post('/api/v1/tasks/:taskId/stop', settingsScope, routes.tasks.stopTask); diff --git a/src/taskdb.js b/src/taskdb.js index 99250c0c9..c2e0c9260 100644 --- a/src/taskdb.js +++ b/src/taskdb.js @@ -4,7 +4,8 @@ exports = module.exports = { get: get, add: add, update: update, - del: del + del: del, + listPaged: listPaged }; let assert = require('assert'), @@ -84,3 +85,31 @@ function del(id, callback) { callback(null); }); } + +function listPaged(type, page, perPage, callback) { + assert(typeof type === 'string' || type === null); + assert.strictEqual(typeof page, 'number'); + assert.strictEqual(typeof perPage, 'number'); + assert.strictEqual(typeof callback, 'function'); + + var data = []; + var query = 'SELECT ' + TASKS_FIELDS + ' FROM tasks'; + + if (type) { + query += ' WHERE TYPE=?'; + data.push(type); + } + + query += ' ORDER BY creationTime DESC LIMIT ?,?'; + + data.push((page-1)*perPage); + data.push(perPage); + + database.query(query, data, function (error, results) { + if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + + results.forEach(postProcess); + + callback(null, results); + }); +} diff --git a/src/tasks.js b/src/tasks.js index 8e6a47ad9..1a94fdc8b 100644 --- a/src/tasks.js +++ b/src/tasks.js @@ -3,6 +3,7 @@ exports = module.exports = { get: get, update: update, + listPaged: listPaged, startTask: startTask, stopTask: stopTask, @@ -170,3 +171,16 @@ function stopTask(id, auditSource, callback) { callback(null); } + +function listPaged(type, page, perPage, callback) { + assert(typeof type === 'string' || type === null); + assert.strictEqual(typeof page, 'number'); + assert.strictEqual(typeof perPage, 'number'); + assert.strictEqual(typeof callback, 'function'); + + taskdb.listPaged(type, page, perPage, function (error, tasks) { + if (error) return callback(new TaskError(TaskError.INTERNAL_ERROR, error)); + + callback(null, tasks); + }); +} diff --git a/src/test/database-test.js b/src/test/database-test.js index a020303f7..2fe8d4b0a 100644 --- a/src/test/database-test.js +++ b/src/test/database-test.js @@ -1138,6 +1138,32 @@ describe('database', function () { }); }); + it('list succeeds - does not exist', function (done) { + taskdb.listPaged('randomtask', 1, 1, function (error, tasks) { + expect(error).to.be(null); + expect(tasks.length).to.be(0); + done(); + }); + }); + + it('list succeeds - by type', function (done) { + taskdb.listPaged(TASK.type, 1, 1, function (error, tasks) { + expect(error).to.be(null); + expect(tasks.length).to.be(1); + expect(_.pick(tasks[0], Object.keys(TASK))).to.eql(TASK); + done(); + }); + }); + + it('list succeeds - all', function (done) { + taskdb.listPaged(null, 1, 1, function (error, tasks) { + expect(error).to.be(null); + expect(tasks.length).to.be(1); + expect(_.pick(tasks[0], Object.keys(TASK))).to.eql(TASK); + done(); + }); + }); + it('del succeeds', function (done) { taskdb.del(taskId, function (error) { expect(error).to.be(null);