mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
Added nextDue field
This commit is contained in:
@@ -215,6 +215,13 @@ describe('POST /tasks/:id/score/:direction', () => {
|
|||||||
expect(task.isDue).to.equal(true);
|
expect(task.isDue).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('computes nextDue', async () => {
|
||||||
|
await user.post(`/tasks/${daily._id}/score/up`);
|
||||||
|
let task = await user.get(`/tasks/${daily._id}`);
|
||||||
|
|
||||||
|
expect(task.nextDue.length).to.eql(3);
|
||||||
|
});
|
||||||
|
|
||||||
it('scores up daily even if it is already completed'); // Yes?
|
it('scores up daily even if it is already completed'); // Yes?
|
||||||
|
|
||||||
it('scores down daily even if it is already uncompleted'); // Yes?
|
it('scores down daily even if it is already uncompleted'); // Yes?
|
||||||
|
|||||||
@@ -510,6 +510,7 @@ describe('POST /tasks/user', () => {
|
|||||||
expect(task.weeksOfMonth).to.eql([3]);
|
expect(task.weeksOfMonth).to.eql([3]);
|
||||||
expect(new Date(task.startDate)).to.eql(now);
|
expect(new Date(task.startDate)).to.eql(now);
|
||||||
expect(task.isDue).to.be.true;
|
expect(task.isDue).to.be.true;
|
||||||
|
expect(task.nextDue.length).to.eql(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates multiple dailys', async () => {
|
it('creates multiple dailys', async () => {
|
||||||
|
|||||||
@@ -404,6 +404,7 @@ describe('PUT /tasks/:id', () => {
|
|||||||
expect(savedDaily.frequency).to.eql('daily');
|
expect(savedDaily.frequency).to.eql('daily');
|
||||||
expect(savedDaily.everyX).to.eql(5);
|
expect(savedDaily.everyX).to.eql(5);
|
||||||
expect(savedDaily.isDue).to.be.false;
|
expect(savedDaily.isDue).to.be.false;
|
||||||
|
expect(savedDaily.nextDue.length).to.eql(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can update checklists (replace it)', async () => {
|
it('can update checklists (replace it)', async () => {
|
||||||
|
|||||||
@@ -366,6 +366,14 @@ describe('cron', () => {
|
|||||||
expect(tasksByType.dailys[0].isDue).to.be.false;
|
expect(tasksByType.dailys[0].isDue).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('computes nextDue', () => {
|
||||||
|
tasksByType.dailys[0].frequency = 'daily';
|
||||||
|
tasksByType.dailys[0].everyX = 5;
|
||||||
|
tasksByType.dailys[0].startDate = moment().add(1, 'days').toDate();
|
||||||
|
cron({user, tasksByType, daysMissed, analytics});
|
||||||
|
expect(tasksByType.dailys[0].nextDue.length).to.eql(3);
|
||||||
|
});
|
||||||
|
|
||||||
it('should add history', () => {
|
it('should add history', () => {
|
||||||
cron({user, tasksByType, daysMissed, analytics});
|
cron({user, tasksByType, daysMissed, analytics});
|
||||||
expect(tasksByType.dailys[0].history).to.be.lengthOf(1);
|
expect(tasksByType.dailys[0].history).to.be.lengthOf(1);
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export function shouldDo (day, dailyTask, options = {}) {
|
|||||||
|
|
||||||
let startDate = moment(dailyTask.startDate).zone(o.timezoneOffset).startOf('day');
|
let startDate = moment(dailyTask.startDate).zone(o.timezoneOffset).startOf('day');
|
||||||
|
|
||||||
if (startDate > startOfDayWithCDSTime.startOf('day')) {
|
if (startDate > startOfDayWithCDSTime.startOf('day') && !options.nextDue) {
|
||||||
return false; // Daily starts in the future
|
return false; // Daily starts in the future
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +121,9 @@ export function shouldDo (day, dailyTask, options = {}) {
|
|||||||
if (!dailyTask.everyX) return false; // error condition
|
if (!dailyTask.everyX) return false; // error condition
|
||||||
let schedule = moment(startDate).recur()
|
let schedule = moment(startDate).recur()
|
||||||
.every(dailyTask.everyX).days();
|
.every(dailyTask.everyX).days();
|
||||||
|
|
||||||
|
if (options.nextDue) return schedule.next(3, 'L');
|
||||||
|
|
||||||
return schedule.matches(startOfDayWithCDSTime);
|
return schedule.matches(startOfDayWithCDSTime);
|
||||||
} else if (dailyTask.frequency === 'weekly') {
|
} else if (dailyTask.frequency === 'weekly') {
|
||||||
let schedule = moment(startDate).recur();
|
let schedule = moment(startDate).recur();
|
||||||
@@ -131,6 +134,8 @@ export function shouldDo (day, dailyTask, options = {}) {
|
|||||||
|
|
||||||
schedule = schedule.every(daysOfTheWeek).daysOfWeek();
|
schedule = schedule.every(daysOfTheWeek).daysOfWeek();
|
||||||
|
|
||||||
|
if (options.nextDue) return schedule.next(3, 'L');
|
||||||
|
|
||||||
return schedule.matches(startOfDayWithCDSTime);
|
return schedule.matches(startOfDayWithCDSTime);
|
||||||
} else if (dailyTask.frequency === 'monthly') {
|
} else if (dailyTask.frequency === 'monthly') {
|
||||||
let schedule = moment(startDate).recur();
|
let schedule = moment(startDate).recur();
|
||||||
@@ -145,12 +150,16 @@ export function shouldDo (day, dailyTask, options = {}) {
|
|||||||
schedule = schedule.every(dailyTask.daysOfMonth).daysOfMonth();
|
schedule = schedule.every(dailyTask.daysOfMonth).daysOfMonth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.nextDue) return schedule.next(3, 'L');
|
||||||
|
|
||||||
return schedule.matches(startOfDayWithCDSTime) && matchEveryX;
|
return schedule.matches(startOfDayWithCDSTime) && matchEveryX;
|
||||||
} else if (dailyTask.frequency === 'yearly') {
|
} else if (dailyTask.frequency === 'yearly') {
|
||||||
let schedule = moment(startDate).recur();
|
let schedule = moment(startDate).recur();
|
||||||
|
|
||||||
schedule = schedule.every(dailyTask.everyX).years();
|
schedule = schedule.every(dailyTask.everyX).years();
|
||||||
|
|
||||||
|
if (options.nextDue) return schedule.next(3, 'L');
|
||||||
|
|
||||||
return schedule.matches(startOfDayWithCDSTime);
|
return schedule.matches(startOfDayWithCDSTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
import common from '../../../common';
|
import common from '../../../common';
|
||||||
import Bluebird from 'bluebird';
|
import Bluebird from 'bluebird';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import logger from '../../libs/logger';
|
import logger from '../../libs/logger';
|
||||||
|
|
||||||
const MAX_SCORE_NOTES_LENGTH = 256;
|
const MAX_SCORE_NOTES_LENGTH = 256;
|
||||||
@@ -457,7 +458,13 @@ api.updateTask = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sanitizedObj.type === 'daily') {
|
if (sanitizedObj.type === 'daily') {
|
||||||
task.isDue = common.shouldDo(Date.now(), sanitizedObj, user.preferences);
|
let optionsForShouldDo = cloneDeep(user.preferences.toObject());
|
||||||
|
task.isDue = common.shouldDo(Date.now(), sanitizedObj, optionsForShouldDo);
|
||||||
|
optionsForShouldDo.nextDue = true;
|
||||||
|
let nextDue = common.shouldDo(Date.now(), sanitizedObj, optionsForShouldDo);
|
||||||
|
if (nextDue && nextDue.length > 0) {
|
||||||
|
task.nextDue = nextDue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let savedTask = await task.save();
|
let savedTask = await task.save();
|
||||||
@@ -590,7 +597,13 @@ api.scoreTask = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (task.type === 'daily') {
|
if (task.type === 'daily') {
|
||||||
task.isDue = common.shouldDo(Date.now(), task, user.preferences);
|
let optionsForShouldDo = cloneDeep(user.preferences.toObject());
|
||||||
|
task.isDue = common.shouldDo(Date.now(), task, optionsForShouldDo);
|
||||||
|
optionsForShouldDo.nextDue = true;
|
||||||
|
let nextDue = common.shouldDo(Date.now(), task, optionsForShouldDo);
|
||||||
|
if (nextDue && nextDue.length > 0) {
|
||||||
|
task.nextDue = nextDue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let results = await Bluebird.all([
|
let results = await Bluebird.all([
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { model as User } from '../models/user';
|
|||||||
import common from '../../common/';
|
import common from '../../common/';
|
||||||
import { preenUserHistory } from '../libs/preening';
|
import { preenUserHistory } from '../libs/preening';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
|
|
||||||
const CRON_SAFE_MODE = nconf.get('CRON_SAFE_MODE') === 'true';
|
const CRON_SAFE_MODE = nconf.get('CRON_SAFE_MODE') === 'true';
|
||||||
@@ -314,7 +315,15 @@ export function cron (options = {}) {
|
|||||||
value: task.value,
|
value: task.value,
|
||||||
});
|
});
|
||||||
task.completed = false;
|
task.completed = false;
|
||||||
task.isDue = common.shouldDo(Date.now(), task, user.preferences);
|
|
||||||
|
let optionsForShouldDo = cloneDeep(user.preferences.toObject());
|
||||||
|
task.isDue = common.shouldDo(now, task, optionsForShouldDo);
|
||||||
|
optionsForShouldDo.nextDue = true;
|
||||||
|
let nextDue = common.shouldDo(now, task, optionsForShouldDo);
|
||||||
|
|
||||||
|
if (nextDue && nextDue.length > 0) {
|
||||||
|
task.nextDue = nextDue;
|
||||||
|
}
|
||||||
|
|
||||||
if (completed || scheduleMisses > 0) {
|
if (completed || scheduleMisses > 0) {
|
||||||
if (task.checklist) {
|
if (task.checklist) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
} from './errors';
|
} from './errors';
|
||||||
import Bluebird from 'bluebird';
|
import Bluebird from 'bluebird';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import shared from '../../common';
|
import shared from '../../common';
|
||||||
|
|
||||||
async function _validateTaskAlias (tasks, res) {
|
async function _validateTaskAlias (tasks, res) {
|
||||||
@@ -64,7 +65,15 @@ export async function createTasks (req, res, options = {}) {
|
|||||||
newTask.userId = user._id;
|
newTask.userId = user._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newTask.type === 'daily') newTask.isDue = shared.shouldDo(Date.now(), newTask, user.preferences);
|
if (newTask.type === 'daily') {
|
||||||
|
let optionsForShouldDo = cloneDeep(user.preferences.toObject());
|
||||||
|
newTask.isDue = shared.shouldDo(Date.now(), newTask, optionsForShouldDo);
|
||||||
|
optionsForShouldDo.nextDue = true;
|
||||||
|
let nextDue = shared.shouldDo(Date.now(), newTask, optionsForShouldDo);
|
||||||
|
if (nextDue && nextDue.length > 0) {
|
||||||
|
newTask.nextDue = nextDue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate that the task is valid and throw if it isn't
|
// Validate that the task is valid and throw if it isn't
|
||||||
// otherwise since we're saving user/challenge/group and task in parallel it could save the user/challenge/group with a tasksOrder that doens't match reality
|
// otherwise since we're saving user/challenge/group and task in parallel it could save the user/challenge/group with a tasksOrder that doens't match reality
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ export let DailySchema = new Schema(_.defaults({
|
|||||||
daysOfMonth: {type: [Number], default: []}, // Days of the month that the daily should repeat on
|
daysOfMonth: {type: [Number], default: []}, // Days of the month that the daily should repeat on
|
||||||
weeksOfMonth: {type: [Number], default: []}, // Weeks of the month that the daily should repeat on
|
weeksOfMonth: {type: [Number], default: []}, // Weeks of the month that the daily should repeat on
|
||||||
isDue: {type: Boolean},
|
isDue: {type: Boolean},
|
||||||
|
nextDue: [{type: String}],
|
||||||
}, habitDailySchema(), dailyTodoSchema()), subDiscriminatorOptions);
|
}, habitDailySchema(), dailyTodoSchema()), subDiscriminatorOptions);
|
||||||
export let daily = Task.discriminator('daily', DailySchema);
|
export let daily = Task.discriminator('daily', DailySchema);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user