1
0
mirror of https://github.com/elisspace/FxLifeSheet.git synced 2026-08-29 15:44:00 +00:00

Initial scheduler implementation

This commit is contained in:
Felix Krause
2019-04-08 20:40:55 +02:00
parent cae7896988
commit 025d08b719
4 changed files with 180 additions and 19 deletions

View File

@@ -78,7 +78,6 @@ Available values for `schedule`:
- `fourTimesADay`
- `daily`
- `weekly`
- `monthly`
- `manual`
*Note*: `fourTimesADay` actually means 3 times a day, as the user will sleep while one of the questions is asked, depending on the time zone.

92
app.js
View File

@@ -11,11 +11,14 @@ var async = require("async");
// spreadsheet key is the long id in the sheets URL
console.log("Loading " + process.env.GOOGLE_SHEETS_SHEET_ID);
var doc = new GoogleSpreadsheet(process.env.GOOGLE_SHEETS_SHEET_ID);
var sheet;
var rawDataSheet;
var lastRunSheet;
// State
var currentlyAskedQuestionObject = null;
var currentlyAskedQuestionMessageId = null; // The Telegram message ID reference
var currentlyAskedQuestionQueue = []; // keep track of all the questions about to be asked
var cachedCtx = null; // TODO: this obviously hsa to be removed and replaced with something better
var lastCommandReminder = {}; // to not spam the user on each interval
var userConfig = require("./config.json");
console.log("Loaded user config:");
console.log(userConfig);
@@ -31,13 +34,14 @@ async.series([
function getInfoAndWorksheets(step) {
doc.getInfo(function (err, info) {
console.log("Loaded doc: " + info.title + " by " + info.author.email);
sheet = info.worksheets[0];
rawDataSheet = info.worksheets[0];
lastRunSheet = info.worksheets[1];
console.log("sheet 1: " +
sheet.title +
rawDataSheet.title +
" " +
sheet.rowCount +
rawDataSheet.rowCount +
"x" +
sheet.colCount);
rawDataSheet.colCount);
step();
});
}
@@ -49,6 +53,7 @@ async.series([
console.log("✅ Login successful, bot is running now");
// App logic
initBot();
initScheduler();
}
});
function getButtonText(number) {
@@ -95,7 +100,7 @@ function triggerNextQuestionFromQueue(ctx) {
var question = currentQuestion.question +
" (" +
currentlyAskedQuestionQueue.length +
" more)";
" more questions)";
ctx.reply(question, keyboard).then(function (_a) {
var message_id = _a.message_id;
currentlyAskedQuestionMessageId = message_id;
@@ -129,10 +134,11 @@ function initBot() {
Minute: dateToAdd.minutes(),
Week: dateToAdd.week(),
Quarter: dateToAdd.quarter(),
Type: currentlyAskedQuestionObject.key,
Key: currentlyAskedQuestionObject.key,
Type: currentlyAskedQuestionObject.type,
Value: userValue
};
sheet.addRow(row, function (error, row) {
rawDataSheet.addRow(row, function (error, row) {
// TODO: replace with editing the existing message (ID in currentlyAskedQuestionMessageId, however couldn't get it to work)
// ctx.reply("Success ✅", Extra.inReplyTo(currentlyAskedQuestionMessageId));
});
@@ -151,13 +157,14 @@ function initBot() {
});
});
bot.hears(/\/(\w+)/, function (ctx) {
console.log(ctx);
cachedCtx = ctx;
// user entered a command to start the survey
var command = ctx.match[1];
var matchingCommandObject = userConfig[command];
if (matchingCommandObject && matchingCommandObject.values) {
console.log("User wants to run:");
console.log(matchingCommandObject);
saveLastRun(command);
currentlyAskedQuestionQueue = currentlyAskedQuestionQueue.concat(matchingCommandObject.values.slice(0)); // slice is a poor human's .clone basically
if (currentlyAskedQuestionObject == null) {
triggerNextQuestionFromQueue(ctx);
@@ -171,3 +178,70 @@ function initBot() {
// has to be last
bot.launch();
}
function saveLastRun(command) {
// TODO: check for existing value
var row = {
Command: command,
LastRun: moment().valueOf() // unix timestamp
};
lastRunSheet.addRow(row, function (error, row) {
console.log("Stored timestamp of last run for " + command);
});
}
function initScheduler() {
// Cron job to check if we need to run a given question again
setInterval(function () {
lastRunSheet.getRows({
offset: 1,
limit: 100
}, function (error, rows) {
for (var i = 0; i < rows.length; i++) {
var currentRow = rows[i];
var command = currentRow.command;
var lastRun = moment(Number(currentRow.lastrun));
if (userConfig[command] == null) {
console.error("Error, command not found: " + command);
break;
}
var scheduleType = userConfig[command].schedule;
var timeDifferenceHours = moment().diff(moment(lastRun), "hours"); //hours
var shouldRemindUser = false;
if (scheduleType == "fourTimesADay") {
if (timeDifferenceHours >= 24 / 4) {
shouldRemindUser = true;
}
}
else if (scheduleType == "daily") {
if (timeDifferenceHours >= 24 * 1.1) {
shouldRemindUser = true;
}
}
else if (scheduleType == "weekly") {
if (timeDifferenceHours >= 24 * 7 * 1.05) {
shouldRemindUser = true;
}
}
else if (scheduleType == "manual") {
// Never remind the user
}
else {
console.error("Unknown schedule type " + scheduleType);
}
var lastReminderDiffInHours = 100; // not reminded yet by default
if (lastCommandReminder[command]) {
lastReminderDiffInHours = moment().diff(moment(Number(lastCommandReminder[command])), "hours");
}
if (shouldRemindUser &&
cachedCtx != null &&
lastReminderDiffInHours > 1) {
cachedCtx.reply("Please run /" +
command +
" again, it's been " +
timeDifferenceHours +
" hours since you last filled it out");
lastCommandReminder[command] = moment().valueOf(); // unix timestamp
}
}
});
}, 3000);
}

104
app.ts
View File

@@ -15,12 +15,15 @@ var async = require("async");
// spreadsheet key is the long id in the sheets URL
console.log("Loading " + process.env.GOOGLE_SHEETS_SHEET_ID);
var doc = new GoogleSpreadsheet(process.env.GOOGLE_SHEETS_SHEET_ID);
var sheet;
var rawDataSheet;
var lastRunSheet;
// State
var currentlyAskedQuestionObject: QuestionToAsk = null;
var currentlyAskedQuestionMessageId: String = null; // The Telegram message ID reference
let currentlyAskedQuestionQueue: Array<QuestionToAsk> = []; // keep track of all the questions about to be asked
var cachedCtx = null; // TODO: this obviously hsa to be removed and replaced with something better
var lastCommandReminder: { [key: string]: Number } = {}; // to not spam the user on each interval
interface QuestionToAsk {
key: String;
@@ -56,14 +59,15 @@ async.series(
function getInfoAndWorksheets(step) {
doc.getInfo(function(err, info) {
console.log("Loaded doc: " + info.title + " by " + info.author.email);
sheet = info.worksheets[0];
rawDataSheet = info.worksheets[0];
lastRunSheet = info.worksheets[1];
console.log(
"sheet 1: " +
sheet.title +
rawDataSheet.title +
" " +
sheet.rowCount +
rawDataSheet.rowCount +
"x" +
sheet.colCount
rawDataSheet.colCount
);
step();
});
@@ -76,6 +80,7 @@ async.series(
console.log("✅ Login successful, bot is running now");
// App logic
initBot();
initScheduler();
}
}
);
@@ -131,7 +136,7 @@ function triggerNextQuestionFromQueue(ctx) {
currentQuestion.question +
" (" +
currentlyAskedQuestionQueue.length +
" more)";
" more questions)";
ctx.reply(question, keyboard).then(({ message_id }) => {
currentlyAskedQuestionMessageId = message_id;
});
@@ -177,11 +182,12 @@ function initBot() {
Minute: dateToAdd.minutes(),
Week: dateToAdd.week(),
Quarter: dateToAdd.quarter(),
Type: currentlyAskedQuestionObject.key,
Key: currentlyAskedQuestionObject.key,
Type: currentlyAskedQuestionObject.type,
Value: userValue
};
sheet.addRow(row, function(error, row) {
rawDataSheet.addRow(row, function(error, row) {
// TODO: replace with editing the existing message (ID in currentlyAskedQuestionMessageId, however couldn't get it to work)
// ctx.reply("Success ✅", Extra.inReplyTo(currentlyAskedQuestionMessageId));
});
@@ -203,6 +209,7 @@ function initBot() {
});
bot.hears(/\/(\w+)/, ctx => {
cachedCtx = ctx;
// user entered a command to start the survey
let command = ctx.match[1];
let matchingCommandObject = userConfig[command];
@@ -210,6 +217,7 @@ function initBot() {
if (matchingCommandObject && matchingCommandObject.values) {
console.log("User wants to run:");
console.log(matchingCommandObject);
saveLastRun(command);
currentlyAskedQuestionQueue = currentlyAskedQuestionQueue.concat(
matchingCommandObject.values.slice(0)
); // slice is a poor human's .clone basically
@@ -228,3 +236,83 @@ function initBot() {
// has to be last
bot.launch();
}
function saveLastRun(command) {
// TODO: check for existing value
let row = {
Command: command,
LastRun: moment().valueOf() // unix timestamp
};
lastRunSheet.addRow(row, function(error, row) {
console.log("Stored timestamp of last run for " + command);
});
}
function initScheduler() {
// Cron job to check if we need to run a given question again
setInterval(function() {
lastRunSheet.getRows(
{
offset: 1,
limit: 100
},
function(error, rows) {
for (let i = 0; i < rows.length; i++) {
let currentRow = rows[i];
let command = currentRow.command;
let lastRun = moment(Number(currentRow.lastrun));
if (userConfig[command] == null) {
console.error("Error, command not found: " + command);
break;
}
let scheduleType = userConfig[command].schedule;
let timeDifferenceHours = moment().diff(moment(lastRun), "hours"); //hours
var shouldRemindUser = false;
if (scheduleType == "fourTimesADay") {
if (timeDifferenceHours >= 24 / 4) {
shouldRemindUser = true;
}
} else if (scheduleType == "daily") {
if (timeDifferenceHours >= 24 * 1.1) {
shouldRemindUser = true;
}
} else if (scheduleType == "weekly") {
if (timeDifferenceHours >= 24 * 7 * 1.05) {
shouldRemindUser = true;
}
} else if (scheduleType == "manual") {
// Never remind the user
} else {
console.error("Unknown schedule type " + scheduleType);
}
let lastReminderDiffInHours = 100; // not reminded yet by default
if (lastCommandReminder[command]) {
lastReminderDiffInHours = moment().diff(
moment(Number(lastCommandReminder[command])),
"hours"
);
}
if (
shouldRemindUser &&
cachedCtx != null &&
lastReminderDiffInHours > 1
) {
cachedCtx.reply(
"Please run /" +
command +
" again, it's been " +
timeDifferenceHours +
" hours since you last filled it out"
);
lastCommandReminder[command] = moment().valueOf(); // unix timestamp
}
}
}
);
}, 3000);
}

View File

@@ -35,4 +35,4 @@
]
},
"week": {}
}
}