From d5751837ed212c04cd6a2229ea4c76bcf5a78356 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 25 Jan 2016 17:23:01 +0100 Subject: [PATCH] add clearCompletedTodos route with tests, add test for getting completed todos, misc fixes --- .../integration/tasks/GET-tasks_user.test.js | 19 ++++++++++-- website/src/controllers/api-v3/tasks.js | 31 ++++++++++++++++++- website/src/middlewares/api-v3/cron.js | 2 +- website/src/models/group.js | 2 +- website/src/models/task.js | 4 +-- 5 files changed, 51 insertions(+), 7 deletions(-) diff --git a/test/api/v3/integration/tasks/GET-tasks_user.test.js b/test/api/v3/integration/tasks/GET-tasks_user.test.js index fb6c7c84f5..a206d7b3ce 100644 --- a/test/api/v3/integration/tasks/GET-tasks_user.test.js +++ b/test/api/v3/integration/tasks/GET-tasks_user.test.js @@ -22,6 +22,21 @@ describe('GET /tasks/user', () => { expect(tasks[0]._id).to.equal(createdTasks[0]._id); }); - // TODO complete after task scoring is done - it('returns completed todos sorted by creation date if req.query.includeCompletedTodos is specified'); + it('returns completed todos sorted by completion date if req.query.includeCompletedTodos is specified', async () => { + let todo1 = await user.post('/tasks/user', {text: 'todo to complete 1', type: 'todo'}); + let todo2 = await user.post('/tasks/user', {text: 'todo to complete 2', type: 'todo'}); + + await user.sync(); + let initialTodoCount = user.tasksOrder.todos.length; + + await user.post(`/tasks/${todo2._id}/score/up`); + await user.post(`/tasks/${todo1._id}/score/up`); + await user.sync(); + + expect(user.tasksOrder.todos.length).to.equal(initialTodoCount - 2); + + let allTodos = await user.get('/tasks/user?type=todo&includeCompletedTodos=true'); + expect(allTodos.length).to.equal(initialTodoCount); + expect(allTodos[allTodos.length - 1].text).to.equal('todo to complete 1'); // last is the todo that was completed later + }); }); diff --git a/website/src/controllers/api-v3/tasks.js b/website/src/controllers/api-v3/tasks.js index acdd456beb..020ae5061b 100644 --- a/website/src/controllers/api-v3/tasks.js +++ b/website/src/controllers/api-v3/tasks.js @@ -129,6 +129,7 @@ async function _getTasks (req, res, user, challenge) { if (challenge) throw new BadRequest(res.t('noCompletedTodosChallenge')); // no completed todos for challenges let queryCompleted = Tasks.Task.find({ + userId: user._id, type: 'todo', completed: true, }).limit(30).sort({ // TODO add ability to pick more than 30 completed todos @@ -837,7 +838,35 @@ api.unlinkTask = { }; /** - * @api {delete} /task/:taskId Delete a user task given its id + * @api {post} /tasks/clearCompletedTodos Delete user's completed todos + * @apiVersion 3.0.0 + * @apiName ClearCompletedTodos + * @apiGroup Task + * + * @apiSuccess {object} empty An empty object + */ +api.clearCompletedTodos = { + method: 'POST', + url: '/tasks/clearCompletedTodos', + middlewares: [authWithHeaders(), cron], + async handler (req, res) { + let user = res.locals.user; + + // Clear completed todos + // Do not delete challenges completed todos TODO unless the task is broken? + await Tasks.Task.remove({ + userId: user._id, + type: 'todo', + completed: true, + 'challenge.id': {$exists: false}, + }).exec(); + + res.respond(200, {}); + }, +}; + +/** + * @api {delete} /tasks/:taskId Delete a user task given its id * @apiVersion 3.0.0 * @apiName DeleteTask * @apiGroup Task diff --git a/website/src/middlewares/api-v3/cron.js b/website/src/middlewares/api-v3/cron.js index aaebc476dc..288452e670 100644 --- a/website/src/middlewares/api-v3/cron.js +++ b/website/src/middlewares/api-v3/cron.js @@ -34,7 +34,7 @@ export default function cronMiddleware (req, res, next) { // Run cron cron({user, tasksByType, now, daysMissed, analytics}); - // Clean completed todos - 30 days for free users, 90 for subscribers + // Clear old completed todos - 30 days for free users, 90 for subscribers // Do not delete challenges completed todos TODO unless the task is broken? Task.remove({ userId: user._id, diff --git a/website/src/models/group.js b/website/src/models/group.js index 246a2f0625..d5d83b19b1 100644 --- a/website/src/models/group.js +++ b/website/src/models/group.js @@ -79,7 +79,7 @@ schema.plugin(baseModel, { // A list of additional fields that cannot be updated (but can be set on creation) let noUpdate = ['privacy', 'type']; schema.statics.sanitizeUpdate = function sanitizeUpdate (updateObj) { - return model.sanitize(updateObj, noUpdate); // eslint-disable-line no-use-before-define + return this.sanitize(updateObj, noUpdate); }; // TODO migration diff --git a/website/src/models/task.js b/website/src/models/task.js index 3fd574af93..c6a326999a 100644 --- a/website/src/models/task.js +++ b/website/src/models/task.js @@ -48,13 +48,13 @@ TaskSchema.plugin(baseModel, { // A list of additional fields that cannot be set on creation (but can be set on updare) let noCreate = ['completed']; // TODO completed should be removed for updates too? TaskSchema.statics.sanitizeCreate = function sanitizeCreate (createObj) { - return Task.sanitize(createObj, noCreate); // eslint-disable-line no-use-before-define + return this.sanitize(createObj, noCreate); }; // A list of additional fields that cannot be updated (but can be set on creation) let noUpdate = ['_id', 'type']; TaskSchema.statics.sanitizeUpdate = function sanitizeUpdate (updateObj) { - return Task.sanitize(updateObj, noUpdate); // eslint-disable-line no-use-before-define + return this.sanitize(updateObj, noUpdate); }; // Sanitize checklist objects (disallowing _id)