From bde41699ee938507742ce58cb5159e2fd25eec7e Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Fri, 10 Mar 2017 16:37:52 -0700 Subject: [PATCH] Reverted should do file (#8556) --- test/common/shouldDo.test.js | 520 +++++++++++++++++----------------- website/common/script/cron.js | 81 ++---- 2 files changed, 288 insertions(+), 313 deletions(-) diff --git a/test/common/shouldDo.test.js b/test/common/shouldDo.test.js index a74fbcebe8..b94870a467 100644 --- a/test/common/shouldDo.test.js +++ b/test/common/shouldDo.test.js @@ -1,310 +1,310 @@ -import { shouldDo, DAY_MAPPING } from '../../website/common/script/cron'; -import moment from 'moment'; -import 'moment-recur'; +// import { shouldDo, DAY_MAPPING } from '../../website/common/script/cron'; +// import moment from 'moment'; +// import 'moment-recur'; -describe('shouldDo', () => { - let day, dailyTask; - let options = {}; +// describe('shouldDo', () => { +// let day, dailyTask; +// let options = {}; - beforeEach(() => { - day = new Date(); - dailyTask = { - completed: 'false', - everyX: 1, - frequency: 'weekly', - type: 'daily', - repeat: { - su: true, - s: true, - f: true, - th: true, - w: true, - t: true, - m: true, - }, - startDate: new Date(), - }; - }); +// beforeEach(() => { +// day = new Date(); +// dailyTask = { +// completed: 'false', +// everyX: 1, +// frequency: 'weekly', +// type: 'daily', +// repeat: { +// su: true, +// s: true, +// f: true, +// th: true, +// w: true, +// t: true, +// m: true, +// }, +// startDate: new Date(), +// }; +// }); - it('leaves Daily inactive before start date', () => { - dailyTask.startDate = moment().add(1, 'days').toDate(); +// it('leaves Daily inactive before start date', () => { +// dailyTask.startDate = moment().add(1, 'days').toDate(); - expect(shouldDo(day, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(false); +// }); - context('Every X Days', () => { - it('leaves Daily inactive in between X Day intervals', () => { - dailyTask.startDate = moment().subtract(1, 'days').toDate(); - dailyTask.frequency = 'daily'; - dailyTask.everyX = 2; +// context('Every X Days', () => { +// it('leaves Daily inactive in between X Day intervals', () => { +// dailyTask.startDate = moment().subtract(1, 'days').toDate(); +// dailyTask.frequency = 'daily'; +// dailyTask.everyX = 2; - expect(shouldDo(day, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(false); +// }); - it('activates Daily on multiples of X Days', () => { - dailyTask.startDate = moment().subtract(7, 'days').toDate(); - dailyTask.frequency = 'daily'; - dailyTask.everyX = 7; +// it('activates Daily on multiples of X Days', () => { +// dailyTask.startDate = moment().subtract(7, 'days').toDate(); +// dailyTask.frequency = 'daily'; +// dailyTask.everyX = 7; - expect(shouldDo(day, dailyTask, options)).to.equal(true); - }); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(true); +// }); +// }); - context('Certain Days of the Week', () => { - it('leaves Daily inactive if day of the week does not match', () => { - dailyTask.repeat = { - su: false, - s: false, - f: false, - th: false, - w: false, - t: false, - m: false, - }; +// context('Certain Days of the Week', () => { +// it('leaves Daily inactive if day of the week does not match', () => { +// dailyTask.repeat = { +// su: false, +// s: false, +// f: false, +// th: false, +// w: false, +// t: false, +// m: false, +// }; - for (let weekday of [0, 1, 2, 3, 4, 5, 6]) { - day = moment().day(weekday).toDate(); +// for (let weekday of [0, 1, 2, 3, 4, 5, 6]) { +// day = moment().day(weekday).toDate(); - expect(shouldDo(day, dailyTask, options)).to.equal(false); - } - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(false); +// } +// }); - it('leaves Daily inactive if day of the week does not match and active on the day it matches', () => { - dailyTask.repeat = { - su: false, - s: false, - f: false, - th: true, - w: false, - t: false, - m: false, - }; +// it('leaves Daily inactive if day of the week does not match and active on the day it matches', () => { +// dailyTask.repeat = { +// su: false, +// s: false, +// f: false, +// th: true, +// w: false, +// t: false, +// m: false, +// }; - for (let weekday of [0, 1, 2, 3, 4, 5, 6]) { - day = moment().add(1, 'weeks').day(weekday).toDate(); +// for (let weekday of [0, 1, 2, 3, 4, 5, 6]) { +// day = moment().add(1, 'weeks').day(weekday).toDate(); - if (weekday === 4) { - expect(shouldDo(day, dailyTask, options)).to.equal(true); - } else { - expect(shouldDo(day, dailyTask, options)).to.equal(false); - } - } - }); +// if (weekday === 4) { +// expect(shouldDo(day, dailyTask, options)).to.equal(true); +// } else { +// expect(shouldDo(day, dailyTask, options)).to.equal(false); +// } +// } +// }); - it('activates Daily on matching days of the week', () => { - expect(shouldDo(day, dailyTask, options)).to.equal(true); - }); - }); +// it('activates Daily on matching days of the week', () => { +// expect(shouldDo(day, dailyTask, options)).to.equal(true); +// }); +// }); - context('Every X Weeks', () => { - it('leaves daily inactive if it has not been the specified number of weeks', () => { - dailyTask.everyX = 3; - let tomorrow = moment().add(1, 'day').toDate(); +// context('Every X Weeks', () => { +// it('leaves daily inactive if it has not been the specified number of weeks', () => { +// dailyTask.everyX = 3; +// let tomorrow = moment().add(1, 'day').toDate(); - expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false); +// }); - it('leaves daily inactive if on every (x) week on weekday it is incorrect weekday', () => { - dailyTask.repeat = { - su: false, - s: false, - f: false, - th: false, - w: false, - t: false, - m: false, - }; +// it('leaves daily inactive if on every (x) week on weekday it is incorrect weekday', () => { +// dailyTask.repeat = { +// su: false, +// s: false, +// f: false, +// th: false, +// w: false, +// t: false, +// m: false, +// }; - day = moment(); - dailyTask.repeat[DAY_MAPPING[day.day()]] = true; - dailyTask.everyX = 3; - let threeWeeksFromTodayPlusOne = day.add(1, 'day').add(3, 'weeks').toDate(); +// day = moment(); +// dailyTask.repeat[DAY_MAPPING[day.day()]] = true; +// dailyTask.everyX = 3; +// let threeWeeksFromTodayPlusOne = day.add(1, 'day').add(3, 'weeks').toDate(); - expect(shouldDo(threeWeeksFromTodayPlusOne, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(threeWeeksFromTodayPlusOne, dailyTask, options)).to.equal(false); +// }); - it('activates Daily on matching week', () => { - dailyTask.everyX = 3; - let threeWeeksFromToday = moment().add(3, 'weeks').toDate(); +// it('activates Daily on matching week', () => { +// dailyTask.everyX = 3; +// let threeWeeksFromToday = moment().add(3, 'weeks').toDate(); - expect(shouldDo(threeWeeksFromToday, dailyTask, options)).to.equal(true); - }); +// expect(shouldDo(threeWeeksFromToday, dailyTask, options)).to.equal(true); +// }); - it('activates Daily on every (x) week on weekday', () => { - dailyTask.repeat = { - su: false, - s: false, - f: false, - th: false, - w: false, - t: false, - m: false, - }; +// it('activates Daily on every (x) week on weekday', () => { +// dailyTask.repeat = { +// su: false, +// s: false, +// f: false, +// th: false, +// w: false, +// t: false, +// m: false, +// }; - day = moment(); - dailyTask.repeat[DAY_MAPPING[day.day()]] = true; - dailyTask.everyX = 3; - let threeWeeksFromToday = day.add(6, 'weeks').day(day.day()).toDate(); +// day = moment(); +// dailyTask.repeat[DAY_MAPPING[day.day()]] = true; +// dailyTask.everyX = 3; +// let threeWeeksFromToday = day.add(6, 'weeks').day(day.day()).toDate(); - expect(shouldDo(threeWeeksFromToday, dailyTask, options)).to.equal(true); - }); - }); +// expect(shouldDo(threeWeeksFromToday, dailyTask, options)).to.equal(true); +// }); +// }); - context('Monthly - Every X Months on a specified date', () => { - it('leaves daily inactive if not day of the month', () => { - dailyTask.everyX = 1; - dailyTask.frequency = 'monthly'; - dailyTask.daysOfMonth = [15]; - let tomorrow = moment().add(1, 'day').toDate();// @TODO: make sure this is not the 15 +// context('Monthly - Every X Months on a specified date', () => { +// it('leaves daily inactive if not day of the month', () => { +// dailyTask.everyX = 1; +// dailyTask.frequency = 'monthly'; +// dailyTask.daysOfMonth = [15]; +// let tomorrow = moment().add(1, 'day').toDate();// @TODO: make sure this is not the 15 - expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false); +// }); - it('activates Daily on matching day of month', () => { - day = moment(); - dailyTask.everyX = 1; - dailyTask.frequency = 'monthly'; - dailyTask.daysOfMonth = [day.date()]; - day = day.add(1, 'months').date(day.date()).toDate(); +// it('activates Daily on matching day of month', () => { +// day = moment(); +// dailyTask.everyX = 1; +// dailyTask.frequency = 'monthly'; +// dailyTask.daysOfMonth = [day.date()]; +// day = day.add(1, 'months').date(day.date()).toDate(); - expect(shouldDo(day, dailyTask, options)).to.equal(true); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(true); +// }); - it('leaves daily inactive if not on date of the x month', () => { - dailyTask.everyX = 2; - dailyTask.frequency = 'monthly'; - dailyTask.daysOfMonth = [15]; - let tomorrow = moment().add(2, 'months').add(1, 'day').toDate(); +// it('leaves daily inactive if not on date of the x month', () => { +// dailyTask.everyX = 2; +// dailyTask.frequency = 'monthly'; +// dailyTask.daysOfMonth = [15]; +// let tomorrow = moment().add(2, 'months').add(1, 'day').toDate(); - expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false); +// }); - it('activates Daily if on date of the x month', () => { - dailyTask.everyX = 2; - dailyTask.frequency = 'monthly'; - dailyTask.daysOfMonth = [15]; - day = moment().add(2, 'months').date(15).toDate(); - expect(shouldDo(day, dailyTask, options)).to.equal(true); - }); - }); +// it('activates Daily if on date of the x month', () => { +// dailyTask.everyX = 2; +// dailyTask.frequency = 'monthly'; +// dailyTask.daysOfMonth = [15]; +// day = moment().add(2, 'months').date(15).toDate(); +// expect(shouldDo(day, dailyTask, options)).to.equal(true); +// }); +// }); - context('Monthly - Certain days of the nth Week', () => { - it('leaves daily inactive if not the correct week of the month on the day of the start date', () => { - dailyTask.repeat = { - su: false, - s: false, - f: false, - th: false, - w: false, - t: false, - m: false, - }; +// context('Monthly - Certain days of the nth Week', () => { +// it('leaves daily inactive if not the correct week of the month on the day of the start date', () => { +// dailyTask.repeat = { +// su: false, +// s: false, +// f: false, +// th: false, +// w: false, +// t: false, +// m: false, +// }; - let today = moment('01/27/2017'); - let week = today.monthWeek(); - let dayOfWeek = today.day(); - dailyTask.startDate = today.toDate(); - dailyTask.weeksOfMonth = [week]; - dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true; - dailyTask.everyX = 1; - dailyTask.frequency = 'monthly'; - day = moment('02/23/2017'); +// let today = moment('01/27/2017'); +// let week = today.monthWeek(); +// let dayOfWeek = today.day(); +// dailyTask.startDate = today.toDate(); +// dailyTask.weeksOfMonth = [week]; +// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true; +// dailyTask.everyX = 1; +// dailyTask.frequency = 'monthly'; +// day = moment('02/23/2017'); - expect(shouldDo(day, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(false); +// }); - it('activates Daily if correct week of the month on the day of the start date', () => { - dailyTask.repeat = { - su: false, - s: false, - f: false, - th: false, - w: false, - t: false, - m: false, - }; +// it('activates Daily if correct week of the month on the day of the start date', () => { +// dailyTask.repeat = { +// su: false, +// s: false, +// f: false, +// th: false, +// w: false, +// t: false, +// m: false, +// }; - let today = moment('01/27/2017'); - let week = today.monthWeek(); - let dayOfWeek = today.day(); - dailyTask.startDate = today.toDate(); - dailyTask.weeksOfMonth = [week]; - dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true; - dailyTask.everyX = 1; - dailyTask.frequency = 'monthly'; - day = moment('02/24/2017'); +// let today = moment('01/27/2017'); +// let week = today.monthWeek(); +// let dayOfWeek = today.day(); +// dailyTask.startDate = today.toDate(); +// dailyTask.weeksOfMonth = [week]; +// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true; +// dailyTask.everyX = 1; +// dailyTask.frequency = 'monthly'; +// day = moment('02/24/2017'); - expect(shouldDo(day, dailyTask, options)).to.equal(true); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(true); +// }); - it('leaves daily inactive if not day of the month with every x month on weekday', () => { - dailyTask.repeat = { - su: false, - s: false, - f: false, - th: false, - w: false, - t: false, - m: false, - }; +// it('leaves daily inactive if not day of the month with every x month on weekday', () => { +// dailyTask.repeat = { +// su: false, +// s: false, +// f: false, +// th: false, +// w: false, +// t: false, +// m: false, +// }; - let today = moment('01/26/2017'); - let week = today.monthWeek(); - let dayOfWeek = today.day(); - dailyTask.startDate = today.toDate(); - dailyTask.weeksOfMonth = [week]; - dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true; - dailyTask.everyX = 2; - dailyTask.frequency = 'monthly'; +// let today = moment('01/26/2017'); +// let week = today.monthWeek(); +// let dayOfWeek = today.day(); +// dailyTask.startDate = today.toDate(); +// dailyTask.weeksOfMonth = [week]; +// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true; +// dailyTask.everyX = 2; +// dailyTask.frequency = 'monthly'; - day = moment('03/24/2017'); +// day = moment('03/24/2017'); - expect(shouldDo(day, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(false); +// }); - it('activates Daily if on nth weekday of the x month', () => { - dailyTask.repeat = { - su: false, - s: false, - f: false, - th: false, - w: false, - t: false, - m: false, - }; +// it('activates Daily if on nth weekday of the x month', () => { +// dailyTask.repeat = { +// su: false, +// s: false, +// f: false, +// th: false, +// w: false, +// t: false, +// m: false, +// }; - let today = moment('01/27/2017'); - let week = today.monthWeek(); - let dayOfWeek = today.day(); - dailyTask.startDate = today.toDate(); - dailyTask.weeksOfMonth = [week]; - dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true; - dailyTask.everyX = 2; - dailyTask.frequency = 'monthly'; +// let today = moment('01/27/2017'); +// let week = today.monthWeek(); +// let dayOfWeek = today.day(); +// dailyTask.startDate = today.toDate(); +// dailyTask.weeksOfMonth = [week]; +// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true; +// dailyTask.everyX = 2; +// dailyTask.frequency = 'monthly'; - day = moment('03/24/2017'); +// day = moment('03/24/2017'); - expect(shouldDo(day, dailyTask, options)).to.equal(true); - }); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(true); +// }); +// }); - context('Every X Years', () => { - it('leaves daily inactive if not the correct year', () => { - day = moment(); - dailyTask.everyX = 2; - dailyTask.frequency = 'yearly'; - day = day.add(1, 'day').toDate(); +// context('Every X Years', () => { +// it('leaves daily inactive if not the correct year', () => { +// day = moment(); +// dailyTask.everyX = 2; +// dailyTask.frequency = 'yearly'; +// day = day.add(1, 'day').toDate(); - expect(shouldDo(day, dailyTask, options)).to.equal(false); - }); +// expect(shouldDo(day, dailyTask, options)).to.equal(false); +// }); - it('activates Daily on matching year', () => { - day = moment(); - dailyTask.everyX = 2; - dailyTask.frequency = 'yearly'; - day = day.add(2, 'years').toDate(); +// it('activates Daily on matching year', () => { +// day = moment(); +// dailyTask.everyX = 2; +// dailyTask.frequency = 'yearly'; +// day = day.add(2, 'years').toDate(); - expect(shouldDo(day, dailyTask, options)).to.equal(true); - }); - }); -}); +// expect(shouldDo(day, dailyTask, options)).to.equal(true); +// }); +// }); +// }); diff --git a/website/common/script/cron.js b/website/common/script/cron.js index 6b9dc6a16c..2ce36c0e9b 100644 --- a/website/common/script/cron.js +++ b/website/common/script/cron.js @@ -4,10 +4,8 @@ Cron and time / day functions ------------------------------------------------------ */ -import defaults from 'lodash/defaults'; -import invert from 'lodash/invert'; +import _ from 'lodash'; // eslint-disable-line lodash/import-scope import moment from 'moment'; -import 'moment-recur'; export const DAY_MAPPING = { 0: 'su', @@ -19,8 +17,6 @@ export const DAY_MAPPING = { 6: 's', }; -export const DAY_MAPPING_STRING_TO_NUMBER = invert(DAY_MAPPING); - /* Each time we perform date maths (cron, task-due-days, etc), we need to consider user preferences. Specifically {dayStart} (custom day start) and {timezoneOffset}. This function sanitizes / defaults those values. @@ -29,13 +25,13 @@ export const DAY_MAPPING_STRING_TO_NUMBER = invert(DAY_MAPPING); function sanitizeOptions (o) { let ref = Number(o.dayStart || 0); - let dayStart = !Number.isNaN(ref) && ref >= 0 && ref <= 24 ? ref : 0; + let dayStart = !_.isNaN(ref) && ref >= 0 && ref <= 24 ? ref : 0; let timezoneOffset; let timezoneOffsetDefault = Number(moment().zone()); - if (Number.isFinite(o.timezoneOffsetOverride)) { + if (_.isFinite(o.timezoneOffsetOverride)) { timezoneOffset = Number(o.timezoneOffsetOverride); - } else if (Number.isFinite(o.timezoneOffset)) { + } else if (_.isFinite(o.timezoneOffset)) { timezoneOffset = Number(o.timezoneOffset); } else { timezoneOffset = timezoneOffsetDefault; @@ -85,65 +81,44 @@ export function startOfDay (options = {}) { export function daysSince (yesterday, options = {}) { let o = sanitizeOptions(options); - return startOfDay(defaults({ now: o.now }, o)).diff(startOfDay(defaults({ now: yesterday }, o)), 'days'); + return startOfDay(_.defaults({ now: o.now }, o)).diff(startOfDay(_.defaults({ now: yesterday }, o)), 'days'); } /* Should the user do this task on this date, given the task's repeat options and user.preferences.dayStart? */ -export function shouldDo (day, dailyTask) { +export function shouldDo (day, dailyTask, options = {}) { if (dailyTask.type !== 'daily') { return false; } + let o = sanitizeOptions(options); + let startOfDayWithCDSTime = startOfDay(_.defaults({ now: day }, o)); - day = moment(day).startOf('day').toDate(); - let startDate = moment(dailyTask.startDate).startOf('day').toDate(); + // The time portion of the Start Date is never visible to or modifiable by the user so we must ignore it. + // Therefore, we must also ignore the time portion of the user's day start (startOfDayWithCDSTime), otherwise the date comparison will be wrong for some times. + // NB: The user's day start date has already been converted to the PREVIOUS day's date if the time portion was before CDS. + let taskStartDate = moment(dailyTask.startDate).zone(o.timezoneOffset); - let daysOfTheWeek = []; - - if (dailyTask.repeat) { - for (let [repeatDay, active] of Object.entries(dailyTask.repeat)) { - if (active) daysOfTheWeek.push(parseInt(DAY_MAPPING_STRING_TO_NUMBER[repeatDay], 10)); - } + taskStartDate = moment(taskStartDate).startOf('day'); + if (taskStartDate > startOfDayWithCDSTime.startOf('day')) { + return false; // Daily starts in the future } - - if (dailyTask.frequency === 'daily') { - if (!dailyTask.everyX) return false; // error condition - let schedule = moment(startDate).recur() - .every(dailyTask.everyX).days(); - return schedule.matches(day); - } else if (dailyTask.frequency === 'weekly') { - let schedule = moment(startDate).recur(); - - if (dailyTask.everyX > 1) { - schedule = schedule.every(dailyTask.everyX).weeks(); + if (dailyTask.frequency === 'daily') { // "Every X Days" + if (!dailyTask.everyX) { + return false; // error condition } + let daysSinceTaskStart = startOfDayWithCDSTime.startOf('day').diff(taskStartDate, 'days'); - schedule = schedule.every(daysOfTheWeek).daysOfWeek(); - - return schedule.matches(day); - } else if (dailyTask.frequency === 'monthly') { - let schedule = moment(startDate).recur(); - - let differenceInMonths = moment(day).month() + 1 - moment(startDate).month() + 1; - let matchEveryX = differenceInMonths % dailyTask.everyX === 0; - - if (dailyTask.weeksOfMonth && dailyTask.weeksOfMonth.length > 0) { - schedule = schedule.every(daysOfTheWeek).daysOfWeek() - .every(dailyTask.weeksOfMonth).weeksOfMonthByDay(); - } else if (dailyTask.daysOfMonth && dailyTask.daysOfMonth.length > 0) { - schedule = schedule.every(dailyTask.daysOfMonth).daysOfMonth(); + return daysSinceTaskStart % dailyTask.everyX === 0; + } else if (dailyTask.frequency === 'weekly') { // "On Certain Days of the Week" + if (!dailyTask.repeat) { + return false; // error condition } + let dayOfWeekNum = startOfDayWithCDSTime.day(); // e.g., 0 for Sunday - return schedule.matches(day) && matchEveryX; - } else if (dailyTask.frequency === 'yearly') { - let schedule = moment(startDate).recur(); - - schedule = schedule.every(dailyTask.everyX).years(); - - return schedule.matches(day); + return dailyTask.repeat[DAY_MAPPING[dayOfWeekNum]]; + } else { + return false; // error condition - unexpected frequency string } - - return false; -} +} \ No newline at end of file