Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update compliments with support for cron type date/time for selections, addition to just date. #3481

Merged
merged 23 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d3e47b9
add cron type date/time entries as an option in compliments module
sdetweil Jun 24, 2024
fd105f5
add support for cron type date/time events in compliments
sdetweil Jun 25, 2024
6621e18
Merge branch 'develop' into update_compliments
sdetweil Jun 25, 2024
83082fb
Update CHANGELOG.md
sdetweil Jun 25, 2024
3773da2
Update compliments.js
sdetweil Jun 25, 2024
c4b704c
Update compliments.js
sdetweil Jun 25, 2024
af0f2a7
fix e2e tests, and typo in electron tests
sdetweil Jun 25, 2024
6783ffe
after merge conflict
sdetweil Jun 25, 2024
568fa91
update e2e compliments test
sdetweil Jun 25, 2024
b1c81e2
comment out e2e testcases with date as helper doesn't accept date on…
sdetweil Jun 25, 2024
7d38bc0
add coverage for weather based key added dynamically by notification
sdetweil Jun 25, 2024
66aa2ca
move weather key check to inside existing check, eliminate duplicate …
sdetweil Jun 25, 2024
9e17228
Delete tests/e2e/modules/compliments_spec.js
sdetweil Jun 26, 2024
8836e8f
fix startup delay for cron entries to pass weather test
sdetweil Jun 26, 2024
945f8c2
Merge remote-tracking branch 'refs/remotes/origin/update_compliments'…
sdetweil Jun 26, 2024
4b37d9e
remove unneccessary updateInterval from testcases for pr #3471
sdetweil Jun 27, 2024
59c2c49
remove header comments
sdetweil Jun 27, 2024
c748025
remove updateInterval cron test config
sdetweil Jun 27, 2024
7149760
restore missing file
sdetweil Jun 27, 2024
5b6542e
restore date mask for non-date-time e2e tests
sdetweil Jun 27, 2024
dd1d4a8
add anytime cron test case as server date doesn't work
sdetweil Jun 27, 2024
b72feb3
fixes after review
sdetweil Jul 13, 2024
8ae8659
add comment global Cron to remove eslint-disable
sdetweil Jul 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Thanks to: @kleinmantara (to be continued before release)

### Added

- [compliments] Added support for cron type date/time format entries.. mm hh DD MM dow (minutes/hours/days/months and day of week) see https://crontab.cronhub.io for construction
- [calendar] Added config option "showEndsOnlyWithDuration" for default calendar
- [compliments] Added `specialDayUnique` config option, defaults to `false`. (#3465)

Expand Down
93 changes: 77 additions & 16 deletions modules/default/compliments/compliments.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ Module.register("compliments", {
lastIndexUsed: -1,
// Set currentweather from module
currentWeatherType: "",

cron_regex: /^(((\d+,)+\d+|((\d+|[*])[/]\d+|((JAN|FEB|APR|MA[RY]|JU[LN]|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|APR|MA[RY]|JU[LN]|AUG|SEP|OCT|NOV|DEC))?))|(\d+-\d+)|\d+(-\d+)?[/]\d+(-\d+)?|\d+|[*]|(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?) ?){5}$/i,
date_regex: "[1-9.][0-9.][0-9.]{2}-([0][1-9]|[1][0-2])-([1-2][0-9]|[0][1-9]|[3][0-1])",
pre_defined_types: ["anytime", "morning", "afternoon", "evening"],
// Define required scripts.
getScripts () {
return ["moment.js"];
return ["croner.js", "moment.js"];
},

// Define start sequence.
Expand All @@ -38,11 +40,40 @@ Module.register("compliments", {
this.config.compliments = JSON.parse(response);
this.updateDom();
}
let minute_sync_delay = 1;
// loop thru all the configured when events
for (let m of Object.keys(this.config.compliments)) {
// if one contains a space, its a cron entry
if (m.includes(" ")) {
// we need to synch our interval cycle to the minute
minute_sync_delay = (60 - (moment().second())) * 1000;
break;
}
}
// Schedule update timer. sync to the minute start (if needed), so minute based events happen on the minute start
setTimeout(() => {
setInterval(() => {
this.updateDom(this.config.fadeSpeed);
}, this.config.updateInterval); },
minute_sync_delay);
},

/**
* @param {string} cronExpression The cron expression. See https://croner.56k.guru/usage/pattern/
* @param {Date} [timestamp] The timestamp to check. Defaults to the current time.
* @returns {number} The number of seconds until the next cron run.
*/
getSecondsUntilNextCronRun (cronExpression, timestamp = new Date()) {
// Required for seconds precision
const adjustedTimestamp = new Date(timestamp.getTime() - 1000);

// Schedule update timer.
setInterval(() => {
this.updateDom(this.config.fadeSpeed);
}, this.config.updateInterval);
// https://www.npmjs.com/package/croner
sdetweil marked this conversation as resolved.
Show resolved Hide resolved
/*eslint-disable-next-line*/
sdetweil marked this conversation as resolved.
Show resolved Hide resolved
const cronJob = new Cron(cronExpression);
const nextRunTime = cronJob.nextRun(adjustedTimestamp);

let secondsDelta = (nextRunTime - adjustedTimestamp) / 1000;
sdetweil marked this conversation as resolved.
Show resolved Hide resolved
return secondsDelta;
},

/**
Expand All @@ -51,7 +82,7 @@ Module.register("compliments", {
* @returns {number} a random index of given array
*/
randomIndex (compliments) {
if (compliments.length <= 1) {
if (compliments.length === 1) {
sdetweil marked this conversation as resolved.
Show resolved Hide resolved
return 0;
}

Expand All @@ -75,8 +106,9 @@ Module.register("compliments", {
* @returns {string[]} array with compliments for the time of the day.
*/
complimentArray () {
const hour = moment().hour();
const date = moment().format("YYYY-MM-DD");
const now = moment();
const hour = now.hour();
const date = now.format("YYYY-MM-DD");
let compliments = [];

// Add time of day compliments
Expand All @@ -91,20 +123,49 @@ Module.register("compliments", {
// Add compliments based on weather
if (this.currentWeatherType in this.config.compliments) {
Array.prototype.push.apply(compliments, this.config.compliments[this.currentWeatherType]);
// if the predefine list doesn't include it (yet)
if (!this.pre_defined_types.includes(this.currentWeatherType)) {
// add it
this.pre_defined_types.push(this.currentWeatherType);
}
}

// Add compliments for anytime
Array.prototype.push.apply(compliments, this.config.compliments.anytime);

// get the list of just date entry keys
let temp_list = Object.keys(this.config.compliments).filter((k) => {
if (this.pre_defined_types.includes(k)) return false;
else return true;
});

let date_compliments = [];
// Add compliments for special days
for (let entry in this.config.compliments) {
if (new RegExp(entry).test(date)) {
// Only display compliments configured for the day if specialDayUnique is set to true
if (this.config.specialDayUnique) {
compliments.length = 0;
}
Array.prototype.push.apply(compliments, this.config.compliments[entry]);
for (let entry of temp_list) {
// check if this could be a cron type entry
if (entry.includes(" ")) {
sdetweil marked this conversation as resolved.
Show resolved Hide resolved
// make sure the regex is valid
if (new RegExp(this.cron_regex).test(entry)) {
// check if we are in the time range for the cron entry
if (this.getSecondsUntilNextCronRun(entry, now.set("seconds", 0).toDate()) <= 1) {
// if so, use its notice entries
Array.prototype.push.apply(date_compliments, this.config.compliments[entry]);
}
} else Log.error(`compliments cron syntax invalid=${JSON.stringify(entry)}`);
} else if (new RegExp(entry).test(date)) {
Array.prototype.push.apply(date_compliments, this.config.compliments[entry]);
}
}

// if we found any date compliments
if (date_compliments.length) {
// and the special flag is true
if (this.config.specialDayUnique) {
// clear the non-date compliments if any
compliments.length = 0;
}
// put the date based compliments on the list
Array.prototype.push.apply(compliments, date_compliments);
}

return compliments;
Expand Down
18 changes: 18 additions & 0 deletions tests/configs/modules/compliments/compliments_cron_entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
let config = {
modules: [
{
module: "compliments",
position: "middle_center",
config: {
specialDayUnique: true,
compliments: {
anytime: ["just a test"],
"00-10 16-19 * * fri": ["just pub time"]
}
}
}
]
};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") { module.exports = config; }
18 changes: 18 additions & 0 deletions tests/configs/modules/compliments/compliments_e2e_cron_entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
let config = {
modules: [
{
module: "compliments",
position: "middle_center",
config: {
specialDayUnique: true,
compliments: {
anytime: ["just a test"],
"* * * * *": ["anytime cron"]
}
}
}
]
};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") { module.exports = config; }
11 changes: 11 additions & 0 deletions tests/e2e/modules/compliments_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,16 @@ describe("Compliments module", () => {
await expect(doTest(["Special day message"])).resolves.toBe(true);
});
});

describe("cron type key", () => {
beforeAll(async () => {
await helpers.startApplication("tests/configs/modules/compliments/compliments_e2e_cron_entry.js");
await helpers.getDocument();
});

it("compliments array contains only special value", async () => {
await expect(doTest(["anytime cron"])).resolves.toBe(true);
});
});
});
});
36 changes: 36 additions & 0 deletions tests/electron/modules/compliments_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,41 @@ describe("Compliments module", () => {
await expect(doTest(["Happy new year!"])).resolves.toBe(true);
});
});

describe("Test only custom date events shown with new property", () => {
it("shows 'Special day message' on May 6", async () => {
await helpers.startApplication("tests/configs/modules/compliments/compliments_specialDayUnique_true.js", "06 May 2022 10:00:00 GMT");
await expect(doTest(["Special day message"])).resolves.toBe(true);
});
});

describe("Test all date events shown without neww property", () => {
it("shows 'any message' on May 6", async () => {
await helpers.startApplication("tests/configs/modules/compliments/compliments_specialDayUnique_false.js", "06 May 2022 10:00:00 GMT");
await expect(doTest(["Special day message", "Typical message 1", "Typical message 2", "Typical message 3"])).resolves.toBe(true);
});
});

describe("Test only custom cron date event shown with new property", () => {
it("shows 'any message' on May 6", async () => {
await helpers.startApplication("tests/configs/modules/compliments/compliments_cron_entry.js", "06 May 2022 17:03:00 GMT");
await expect(doTest(["just pub time"])).resolves.toBe(true);
});
});

describe("Test any event shows after time window", () => {
it("shows 'any message' on May 6", async () => {
await helpers.startApplication("tests/configs/modules/compliments/compliments_cron_entry.js", "06 May 2022 17:11:00 GMT");
await expect(doTest(["just a test"])).resolves.toBe(true);
});
});

describe("Test any event shows different day", () => {
it("shows 'any message' on May 5", async () => {
await helpers.startApplication("tests/configs/modules/compliments/compliments_cron_entry.js", "05 May 2022 17:00:00 GMT");
await expect(doTest(["just a test"])).resolves.toBe(true);
});
});

});
});
9 changes: 9 additions & 0 deletions vendor/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"dependencies": {
"@fortawesome/fontawesome-free": "^6.5.2",
"animate.css": "^4.1.1",
"croner": "^8.0.2",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
"nunjucks": "^3.2.4",
Expand Down
3 changes: 2 additions & 1 deletion vendor/vendor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const vendor = {
"weather-icons-wind.css": "node_modules/weathericons/css/weather-icons-wind.css",
"font-awesome.css": "css/font-awesome.css",
"nunjucks.js": "node_modules/nunjucks/browser/nunjucks.min.js",
"suncalc.js": "node_modules/suncalc/suncalc.js"
"suncalc.js": "node_modules/suncalc/suncalc.js",
"croner.js": "node_modules/croner/dist/croner.umd.min.js"
};

if (typeof module !== "undefined") {
Expand Down