From 3f307c3b554e367cdabae6e82f78249f23d0688f Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Tue, 22 Oct 2019 18:36:26 -0400 Subject: [PATCH 01/10] Fixed error regarding how map() is not a function of getChores() --- utilities/getChores.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utilities/getChores.js b/utilities/getChores.js index 7404dc8..53948b4 100644 --- a/utilities/getChores.js +++ b/utilities/getChores.js @@ -39,7 +39,8 @@ const getChores = async () => { const getTodaysChores = async () => { const today = moment().format("YYYY-MM-DD"); - const todaysChores = await getChores().map(c => c[0] === today ? c[1] : null); + let todaysChores = await getChores(); + todaysChores = todaysChores.map(c => c[0] === today ? c[1] : null); return todaysChores.length === 0 ? -1 : todaysChores; }; From e9c6aa9a370c1d36b9b296dd14e07255cf5d93d7 Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Tue, 22 Oct 2019 18:38:38 -0400 Subject: [PATCH 02/10] Updated so that when a chore is completed, the username and userid of the individual is logged in the Spreadsheet in Column C and D respectively. --- server.js | 4 +- utilities/markChoreDone.js | 79 ++++++++++++++++++++++++++++++++------ 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/server.js b/server.js index 9b6663e..d0cfc1d 100644 --- a/server.js +++ b/server.js @@ -36,9 +36,9 @@ app.action( }, async ({ action, body }) => { if (!action || !body || !body.user || !body.channel || !body.message) return; - markChoreDone(action.action_id, body.user.id, body.channel.id, body.message.ts, + await markChoreDone(action.action_id, body.user, body.channel.id, body.message.ts, body.message.blocks); } ); -cron.schedule(process.env.CRON_SCHEDULE, runChores); +cron.schedule(process.env.CRON_SCHEDULE, runChores); \ No newline at end of file diff --git a/utilities/markChoreDone.js b/utilities/markChoreDone.js index d2bf5f9..2e3ccac 100644 --- a/utilities/markChoreDone.js +++ b/utilities/markChoreDone.js @@ -1,26 +1,83 @@ +//node packages +const {google} = require("googleapis"); +require("dotenv").config(); + //local packages const { - app: { - client: { - chat: { update } + app: { + client: { + chat: { update } + } } - } } = require("./bolt.js"); //globals const TOKEN = process.env.SLACK_BOT_TOKEN; +const privatekey = require("../keys/sheets-api.json"); +const SPREADSHEET_ID = process.env.SPREADSHEET_ID; +const GDRIVE_EMAIL = process.env.GDRIVE_EMAIL; + +const jwtClient = new google.auth.JWT( + privatekey.client_email, + null, + privatekey.private_key, + ["https://www.googleapis.com/auth/spreadsheets"], + GDRIVE_EMAIL +); + +const markChoreUser = async (user, date, choretext) => { + const sheets = google.sheets({ + version: "v4", + auth: jwtClient + }); + + jwtClient.authorize(err => console.log(err ? err : "Successfully connected!")); + + try { + const {data} = await sheets.spreadsheets.values.get({ + spreadsheetId: SPREADSHEET_ID, + range: "A2:B" + }); + for (let n = 0; n < data.values.length; n++) { + if (data.values[n][1] === choretext && data.values[n][0] === date) { + await sheets.spreadsheets.values.update({ + spreadsheetId: SPREADSHEET_ID, + range: `Sheet1!C${n + 2}:D${n + 2}`, + valueInputOption: 'USER_ENTERED', + resource: {values: [[user.name, user.id]]} + }); + } + } + } catch (error) { + console.error(error); + } +}; //helper functions const crossOffAndTag = (user, index, blocks) => { - const choreText = blocks[index + 2].text.text.replace(">", ""); - blocks[index + 2].text.text = `>~${choreText}~ Completed by <@${user}>`; - delete blocks[index + 2].accessory; - return blocks; + const choreText = blocks[index + 2].text.text.replace(">", ""); + blocks[index + 2].text.text = `>~${choreText}~ Completed by <@${user}>`; + delete blocks[index + 2].accessory; + return blocks; }; -const markChoreDone = (index, user, channel, ts, initialBlocks) => { - const blocks = crossOffAndTag(user, parseInt(index), initialBlocks); - update({ token: TOKEN, channel, ts, blocks }); +const markChoreDone = async (index, user, channel, ts, initialBlocks) => { + await markChoreUser(user, formatDate(new Date(ts * 1000)), initialBlocks[parseInt(index) + 2].text.text.replace(">", "")); + const blocks = crossOffAndTag(user.id, parseInt(index), initialBlocks); + update({ token: TOKEN, channel, ts, blocks }); }; +function formatDate(date) { + var d = new Date(date), + month = '' + (d.getMonth() + 1), + day = '' + d.getDate(), + year = d.getFullYear(); + + if (month.length < 2) + month = '0' + month; + if (day.length < 2) + day = '0' + day; + + return [year, month, day].join('-'); +} module.exports = { markChoreDone }; From 5c0336787ae005b458ca88034970ce61615b32da Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Tue, 22 Oct 2019 18:39:08 -0400 Subject: [PATCH 03/10] Fixed misspelling of packages --- utilities/getChores.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/getChores.js b/utilities/getChores.js index 53948b4..53a430c 100644 --- a/utilities/getChores.js +++ b/utilities/getChores.js @@ -1,4 +1,4 @@ -//node pacakges +//node packages const { google } = require("googleapis"); const moment = require("moment-timezone"); require("dotenv").config(); From 28ae71cee5afaf1b82aeee11869a347409943459 Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Tue, 22 Oct 2019 18:50:26 -0400 Subject: [PATCH 04/10] Added that the service account will need both read and write permissions. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57b577b..2286868 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Note the format of the date (`YYYY-MM-DD`) and the fact that multiple chores can ##### Service account -Create a service account using [these instructions](https://developers.google.com/android/management/service-account). Once it's created, share the previously created spreadsheet with the service account's address. View-only permissions should be fine; we're only reading data from the sheet. +Create a service account using [these instructions](https://developers.google.com/android/management/service-account). Once it's created, share the previously created spreadsheet with the service account's address. You will need both Read and Write permissions for this to work. #### Your server From ac6b681b74787bdce6733aae45c71bf46a80b2d5 Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Tue, 22 Oct 2019 19:03:39 -0400 Subject: [PATCH 05/10] Moved privatekey to local packages. Turned format date into arrow function. Updated package-lock.json --- package-lock.json | 6 +++--- utilities/markChoreDone.js | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79cc926..fd521f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -674,9 +674,9 @@ } }, "https-proxy-agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", - "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.3.tgz", + "integrity": "sha512-Ytgnz23gm2DVftnzqRRz2dOXZbGd2uiajSw/95bPp6v53zPRspQjLm/AfBgqbJ2qfeRXWIOMVLpp86+/5yX39Q==", "requires": { "agent-base": "^4.3.0", "debug": "^3.1.0" diff --git a/utilities/markChoreDone.js b/utilities/markChoreDone.js index 2e3ccac..33fded8 100644 --- a/utilities/markChoreDone.js +++ b/utilities/markChoreDone.js @@ -10,10 +10,10 @@ const { } } } = require("./bolt.js"); +const privatekey = require("../keys/sheets-api.json"); //globals const TOKEN = process.env.SLACK_BOT_TOKEN; -const privatekey = require("../keys/sheets-api.json"); const SPREADSHEET_ID = process.env.SPREADSHEET_ID; const GDRIVE_EMAIL = process.env.GDRIVE_EMAIL; @@ -67,7 +67,7 @@ const markChoreDone = async (index, user, channel, ts, initialBlocks) => { update({ token: TOKEN, channel, ts, blocks }); }; -function formatDate(date) { +const formatDate = (date) => { var d = new Date(date), month = '' + (d.getMonth() + 1), day = '' + d.getDate(), @@ -79,5 +79,6 @@ function formatDate(date) { day = '0' + day; return [year, month, day].join('-'); -} +}; + module.exports = { markChoreDone }; From 8bbd04b057e95137cb354805d1e03358dc41f611 Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Tue, 22 Oct 2019 19:21:40 -0400 Subject: [PATCH 06/10] End for loop when cells are located. --- utilities/markChoreDone.js | 1 + 1 file changed, 1 insertion(+) diff --git a/utilities/markChoreDone.js b/utilities/markChoreDone.js index 33fded8..503e1a5 100644 --- a/utilities/markChoreDone.js +++ b/utilities/markChoreDone.js @@ -46,6 +46,7 @@ const markChoreUser = async (user, date, choretext) => { valueInputOption: 'USER_ENTERED', resource: {values: [[user.name, user.id]]} }); + break; } } } catch (error) { From 415e91b8c33220184bac095a6fbe8dc32422c435 Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Tue, 22 Oct 2019 20:31:28 -0400 Subject: [PATCH 07/10] Renamed markChoreUser() to setCompletedBy() Split up line 66. --- utilities/markChoreDone.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utilities/markChoreDone.js b/utilities/markChoreDone.js index 503e1a5..6ed4dd1 100644 --- a/utilities/markChoreDone.js +++ b/utilities/markChoreDone.js @@ -25,7 +25,7 @@ const jwtClient = new google.auth.JWT( GDRIVE_EMAIL ); -const markChoreUser = async (user, date, choretext) => { +const setCompletedBy = async (user, date, choretext) => { const sheets = google.sheets({ version: "v4", auth: jwtClient @@ -63,7 +63,8 @@ const crossOffAndTag = (user, index, blocks) => { }; const markChoreDone = async (index, user, channel, ts, initialBlocks) => { - await markChoreUser(user, formatDate(new Date(ts * 1000)), initialBlocks[parseInt(index) + 2].text.text.replace(">", "")); + await setCompletedBy(user, formatDate(new Date(ts * 1000)), initialBlocks[parseInt(index) + 2] + .text.text.replace(">", "")); const blocks = crossOffAndTag(user.id, parseInt(index), initialBlocks); update({ token: TOKEN, channel, ts, blocks }); }; From d977641a48aee51e6dbdafd5dfce3001406a3e74 Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Thu, 24 Oct 2019 20:17:51 -0400 Subject: [PATCH 08/10] Added () around await getChores() to fix map() error Removed null from array, to prevent posting of null chores --- utilities/getChores.js | 3 +-- utilities/notify.js | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/utilities/getChores.js b/utilities/getChores.js index 53a430c..608463c 100644 --- a/utilities/getChores.js +++ b/utilities/getChores.js @@ -39,8 +39,7 @@ const getChores = async () => { const getTodaysChores = async () => { const today = moment().format("YYYY-MM-DD"); - let todaysChores = await getChores(); - todaysChores = todaysChores.map(c => c[0] === today ? c[1] : null); + let todaysChores = (await getChores()).map(c => c[0] === today ? c[1] : null); return todaysChores.length === 0 ? -1 : todaysChores; }; diff --git a/utilities/notify.js b/utilities/notify.js index 3458851..b2acbbe 100644 --- a/utilities/notify.js +++ b/utilities/notify.js @@ -50,8 +50,8 @@ const sendNoChores = () => postSlackMessage("No chores tonight!", [ const postToSlack = chores => postSlackMessage("Today's chores have been posted!", [ buildMarkdownSection(randomPhrase("greeting")), buildMarkdownSection("Tonight's chores:"), - ...chores.map((c, i) => buildChoreElement(c, i)), - buildMarkdownSection(randomPhrase("request") + " If you have any questions " + + ...chores.filter(x => x).map((c, i) => buildChoreElement(c, i)), + buildMarkdownSection(randomPhrase("request") + " If you have any questions " + ":thinking_face: please reach out to the vice president!") ]); From 82c7c36665b9d6704b1c98f9640e1a948bc8bcd1 Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Fri, 25 Oct 2019 21:23:17 -0400 Subject: [PATCH 09/10] Added scope needed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2286868..665eaa9 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Note the format of the date (`YYYY-MM-DD`) and the fact that multiple chores can ##### Service account -Create a service account using [these instructions](https://developers.google.com/android/management/service-account). Once it's created, share the previously created spreadsheet with the service account's address. You will need both Read and Write permissions for this to work. +Create a service account using [these instructions](https://developers.google.com/android/management/service-account). Once it's created, share the previously created spreadsheet with the service account's address. You will need both Read and Write permissions (`https://www.googleapis.com/auth/spreadsheets`) for this to work. #### Your server From e5b754f4b5ebb1eb20bca65de1f7fbecbc1f09b4 Mon Sep 17 00:00:00 2001 From: Zapdos26 Date: Fri, 1 Nov 2019 18:43:55 -0400 Subject: [PATCH 10/10] Removed filter since its no longer necessary here. --- utilities/notify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/notify.js b/utilities/notify.js index b2acbbe..44ab42c 100644 --- a/utilities/notify.js +++ b/utilities/notify.js @@ -50,7 +50,7 @@ const sendNoChores = () => postSlackMessage("No chores tonight!", [ const postToSlack = chores => postSlackMessage("Today's chores have been posted!", [ buildMarkdownSection(randomPhrase("greeting")), buildMarkdownSection("Tonight's chores:"), - ...chores.filter(x => x).map((c, i) => buildChoreElement(c, i)), + ...chores.map((c, i) => buildChoreElement(c, i)), buildMarkdownSection(randomPhrase("request") + " If you have any questions " + ":thinking_face: please reach out to the vice president!") ]);