mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 15:17:25 +01:00
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:
61
migrations/archive/2020/20201111_api_date.js
Normal file
61
migrations/archive/2020/20201111_api_date.js
Normal 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());
|
||||||
|
}
|
||||||
@@ -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', () => {
|
context('sending task activity webhooks', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ const requiredGroupFields = '_id leader tasksOrder name';
|
|||||||
* "per", "con"
|
* "per", "con"
|
||||||
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
|
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
|
||||||
* @apiParam (Body) {String} [notes] Extra notes
|
* @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,
|
* @apiParam (Body) {Number="0.1","1","1.5","2"} [priority=1] Difficulty, options are 0.1, 1,
|
||||||
* 1.5, 2; eqivalent of Trivial,
|
* 1.5, 2; eqivalent of Trivial,
|
||||||
* Easy, Medium, Hard.
|
* Easy, Medium, Hard.
|
||||||
@@ -253,7 +253,7 @@ api.createUserTasks = {
|
|||||||
* "int", "per", "con".
|
* "int", "per", "con".
|
||||||
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
|
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
|
||||||
* @apiParam (Body) {String} [notes] Extra notes
|
* @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,
|
* @apiParam (Body) {Number="0.1","1","1.5","2"} [priority=1] Difficulty, options are 0.1, 1,
|
||||||
* 1.5, 2; eqivalent of Trivial,
|
* 1.5, 2; eqivalent of Trivial,
|
||||||
* Easy, Medium, Hard.
|
* Easy, Medium, Hard.
|
||||||
@@ -567,7 +567,7 @@ api.getTask = {
|
|||||||
* "per", "con".
|
* "per", "con".
|
||||||
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
|
* @apiParam (Body) {Boolean} [collapseChecklist=false] Determines if a checklist will be displayed
|
||||||
* @apiParam (Body) {String} [notes] Extra notes
|
* @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,
|
* @apiParam (Body) {Number="0.1","1","1.5","2"} [priority=1] Difficulty, options are 0.1, 1,
|
||||||
* 1.5, 2; eqivalent of Trivial,
|
* 1.5, 2; eqivalent of Trivial,
|
||||||
* Easy, Medium, Hard.
|
* Easy, Medium, Hard.
|
||||||
|
|||||||
@@ -404,8 +404,7 @@ export const daily = Task.discriminator('daily', DailySchema);
|
|||||||
|
|
||||||
export const TodoSchema = new Schema(_.defaults({
|
export const TodoSchema = new Schema(_.defaults({
|
||||||
dateCompleted: Date,
|
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: Date, // due date for todos
|
||||||
date: String, // due date for todos
|
|
||||||
}, dailyTodoSchema()), subDiscriminatorOptions);
|
}, dailyTodoSchema()), subDiscriminatorOptions);
|
||||||
export const todo = Task.discriminator('todo', TodoSchema);
|
export const todo = Task.discriminator('todo', TodoSchema);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user