diff --git a/test/api/v3/integration/tasks/POST-tasks.test.js b/test/api/v3/integration/tasks/POST-tasks.test.js index c8b9e9a37a..51999bc8a2 100644 --- a/test/api/v3/integration/tasks/POST-tasks.test.js +++ b/test/api/v3/integration/tasks/POST-tasks.test.js @@ -54,6 +54,21 @@ describe('POST /tasks', () => { }); }); + it('does not update user.tasksOrder.{taskType} when the task is not saved because invalid', async () => { + let originalHabitsOrder = (await user.get('/user')).tasksOrder.habits; + return expect(user.post('/tasks', { + type: 'habit', + })).to.eventually.be.rejected.and.eql({ // this block is necessary + code: 400, + error: 'BadRequest', + message: 'habit validation failed', + }).then(async () => { + let updatedHabitsOrder = (await user.get('/user')).tasksOrder.habits; + + expect(updatedHabitsOrder).to.eql(originalHabitsOrder); + }); + }); + it('automatically sets "task.userId" to user\'s uuid', async () => { let task = await user.post('/tasks', { text: 'test habit', diff --git a/website/src/controllers/api-v3/tasks.js b/website/src/controllers/api-v3/tasks.js index 25b5245a04..84ccf0a221 100644 --- a/website/src/controllers/api-v3/tasks.js +++ b/website/src/controllers/api-v3/tasks.js @@ -32,16 +32,28 @@ api.createTask = { let user = res.locals.user; let toSave = tasksData.map(taskData => { + // Validate that task.type is valid if (!taskData || Tasks.tasksTypes.indexOf(taskData.type) === -1) throw new BadRequest(res.t('invalidTaskType')); let taskType = taskData.type; let newTask = new Tasks[taskType](Tasks.Task.sanitizeCreate(taskData)); newTask.userId = user._id; + + // Validate that the task is valid and throw if it isn't + // otherwise since we're saving user and task in parallel it could save the user with a tasksOrder that doens't match reality + let validationErrors = newTask.validateSync(); + if (validationErrors) throw validationErrors; + + // Otherwise update the user user.tasksOrder[`${taskType}s`].unshift(newTask._id); - return newTask.save(); + return newTask; }); + // If all tasks are valid, save everything, withough running validation again + toSave = toSave.map(task => task.save({ + validateBeforeSave: false, + })); toSave.unshift(user.save()); let results = await Q.all(toSave);