Change $type of date for todos (#12779)

* change $type to date for task and add new test

* adjust apidocs to reflect type change

* migration test for api date $type change

* minor fixes to migration

* unset instead of set empty string

* add type filter

* fix(todo date migration): make sure the update command works and limit update ops

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
This commit is contained in:
Shadow
2020-12-24 11:37:09 -06:00
committed by GitHub
parent 2c44f766cd
commit 7c0b3612f0
4 changed files with 77 additions and 5 deletions

View File

@@ -0,0 +1,61 @@
/*
* Fix dates in the database that were stored as $type string instead of Date
*/
/* eslint-disable no-console */
const MIGRATION_NAME = '20201111_api_date';
import * as Tasks from '../../../website/server/models/task';
const progressCount = 1000;
let count = 0;
async function updateUser (todo) {
count++;
if (count % progressCount === 0) console.warn(`${count} ${todo._id}`);
const newDate = new Date(todo.date);
if (isValidDate(newDate)) return;
return await Tasks.Task.update({_id: todo._id, type: 'todo'}, {$unset: {date: ''}}).exec();
}
module.exports = async function processUsers () {
let query = {
type: 'todo',
date: {$exists: true}
};
const fields = {
_id: 1,
type: 1,
date: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await Tasks.Task // eslint-disable-line no-await-in-loop
.find(query)
.select(fields)
.limit(250)
.sort({_id: 1})
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate tasks found and modified.');
console.warn(`\n${count} tasks processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1],
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
function isValidDate(d) {
return !isNaN(d.getTime());
}

View File

@@ -220,6 +220,18 @@ describe('POST /tasks/user', () => {
});
});
it('errors if todo due date supplied is an invalid date', async () => {
await expect(user.post('/tasks/user', {
type: 'todo',
text: 'todo text',
date: 'invalid date',
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: 'todo validation failed',
});
});
context('sending task activity webhooks', () => {
before(async () => {
await server.start();

View File

@@ -80,7 +80,7 @@ const requiredGroupFields = '_id leader tasksOrder name';
* "per", "con"
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
* @apiParam (Body) {String} [notes] Extra notes
* @apiParam (Body) {String} [date] Due date to be shown in task list. Only valid for type "todo."
* @apiParam (Body) {Date} [date] Due date to be shown in task list. Only valid for type "todo."
* @apiParam (Body) {Number="0.1","1","1.5","2"} [priority=1] Difficulty, options are 0.1, 1,
* 1.5, 2; eqivalent of Trivial,
* Easy, Medium, Hard.
@@ -253,7 +253,7 @@ api.createUserTasks = {
* "int", "per", "con".
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
* @apiParam (Body) {String} [notes] Extra notes
* @apiParam (Body) {String} [date] Due date to be shown in task list. Only valid for type "todo."
* @apiParam (Body) {Date} [date] Due date to be shown in task list. Only valid for type "todo."
* @apiParam (Body) {Number="0.1","1","1.5","2"} [priority=1] Difficulty, options are 0.1, 1,
* 1.5, 2; eqivalent of Trivial,
* Easy, Medium, Hard.
@@ -567,7 +567,7 @@ api.getTask = {
* "per", "con".
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
* @apiParam (Body) {String} [notes] Extra notes
* @apiParam (Body) {String} [date] Due date to be shown in task list. Only valid for type "todo."
* @apiParam (Body) {Date} [date] Due date to be shown in task list. Only valid for type "todo."
* @apiParam (Body) {Number="0.1","1","1.5","2"} [priority=1] Difficulty, options are 0.1, 1,
* 1.5, 2; eqivalent of Trivial,
* Easy, Medium, Hard.

View File

@@ -404,8 +404,7 @@ export const daily = Task.discriminator('daily', DailySchema);
export const TodoSchema = new Schema(_.defaults({
dateCompleted: Date,
// TODO we're getting parse errors, people have stored as "today" and "3/13". Need to run a migration & put this back to $type: Date see http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript
date: String, // due date for todos
date: Date, // due date for todos
}, dailyTodoSchema()), subDiscriminatorOptions);
export const todo = Task.discriminator('todo', TodoSchema);