first commit
This commit is contained in:
commit
12837b171d
8 changed files with 2385 additions and 0 deletions
7
.glitch-assets
Normal file
7
.glitch-assets
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{"name":"drag-in-files.svg","date":"2016-10-22T16:17:49.954Z","url":"https://cdn.hyperdev.com/drag-in-files.svg","type":"image/svg","size":7646,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/drag-in-files.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(102, 153, 205)","uuid":"adSBq97hhhpFNUna"}
|
||||||
|
{"name":"click-me.svg","date":"2016-10-23T16:17:49.954Z","url":"https://cdn.hyperdev.com/click-me.svg","type":"image/svg","size":7116,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/click-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(243, 185, 186)","uuid":"adSBq97hhhpFNUnb"}
|
||||||
|
{"name":"paste-me.svg","date":"2016-10-24T16:17:49.954Z","url":"https://cdn.hyperdev.com/paste-me.svg","type":"image/svg","size":7242,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/paste-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(42, 179, 185)","uuid":"adSBq97hhhpFNUnc"}
|
||||||
|
{"uuid":"adSBq97hhhpFNUna","deleted":true}
|
||||||
|
{"uuid":"adSBq97hhhpFNUnb","deleted":true}
|
||||||
|
{"uuid":"adSBq97hhhpFNUnc","deleted":true}
|
||||||
|
{"name":"botdemo.png","date":"2020-07-17T01:20:39.444Z","url":"https://cdn.glitch.com/95c2faf1-779e-4e08-b219-8a122cdceefe%2Fbotdemo.png","type":"image/png","size":65589,"imageWidth":842,"imageHeight":290,"thumbnail":"https://cdn.glitch.com/95c2faf1-779e-4e08-b219-8a122cdceefe%2Fthumbnails%2Fbotdemo.png","thumbnailWidth":330,"thumbnailHeight":114,"uuid":"7cdZLaCux0c3Mte2"}
|
2
.replit
Normal file
2
.replit
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
language = "nodejs"
|
||||||
|
run = "node app.js"
|
18
README.md
Normal file
18
README.md
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Million Stats
|
||||||
|
|
||||||
|
This is an app for the #counttoamillion channel in Hack Club's Slack workspace. You can also clone this for anything that involves counting to a very high number :)
|
||||||
|
Every midnight, it gives a report on the progress the channel's made and the average daily speed:
|
||||||
|
![shows the day's increase, the average daily speed, and the predicted amount of time needed to reach the next thousand/tenthousand](https://cdn.glitch.com/95c2faf1-779e-4e08-b219-8a122cdceefe%2Fbotdemo.png?v=1594948839444)
|
||||||
|
It also adds an emoji reaction at every number ending with 69, every 1000, and every 5000.
|
||||||
|
|
||||||
|
## Modifying this thing
|
||||||
|
|
||||||
|
- `app.js` contains the primary Bolt app. It imports the Bolt package (`@slack/bolt`) and starts the Bolt app's server.
|
||||||
|
- `.env` is where you'll put your Slack app's authorization token and signing secret.
|
||||||
|
|
||||||
|
### Packages used:
|
||||||
|
- [moment.js](https://momentjs.com/)
|
||||||
|
- [node-schedule](https://www.npmjs.com/package/node-schedule)
|
||||||
|
- [Slack's Bolt API](https://slack.dev/bolt-js/tutorial/getting-started)
|
||||||
|
|
||||||
|
\ ゜ o ゜)ノ
|
187
app.js
Normal file
187
app.js
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
// Require the Bolt package (github.com/slackapi/bolt)
|
||||||
|
const { App } = require("@slack/bolt");
|
||||||
|
const keep_alive = require('./keep_alive.js')
|
||||||
|
const schedule = require('node-schedule');
|
||||||
|
const moment = require('moment');
|
||||||
|
const token = process.env.SLACK_BOT_TOKEN;
|
||||||
|
const channel = "CDJMS683D";
|
||||||
|
const Airtable = require('airtable');
|
||||||
|
Airtable.configure({
|
||||||
|
endpointUrl: 'https://api.airtable.com',
|
||||||
|
apiKey: process.env.AIRTABLE_API_KEY
|
||||||
|
});
|
||||||
|
const base = Airtable.base('appogmRaVRo5ElVH7');
|
||||||
|
let speedArr = [];
|
||||||
|
let latest;
|
||||||
|
let averageSpeed;
|
||||||
|
|
||||||
|
const app = new App({
|
||||||
|
token: token,
|
||||||
|
signingSecret: process.env.SLACK_SIGNING_SECRET
|
||||||
|
});
|
||||||
|
|
||||||
|
function extractNumber(txt) {
|
||||||
|
let array = ["\n", " ", "-"]
|
||||||
|
for (let i of array) {
|
||||||
|
if (txt.includes(i)) {
|
||||||
|
return txt.split(i)[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchLatest(id) {
|
||||||
|
try {
|
||||||
|
const result = await app.client.conversations.history({
|
||||||
|
token: token,
|
||||||
|
channel: id,
|
||||||
|
limit: 1,
|
||||||
|
});
|
||||||
|
const number = extractNumber(result.messages[0].text)
|
||||||
|
return number;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchOldest(id) {
|
||||||
|
try {
|
||||||
|
let last24Hrs;
|
||||||
|
const result = await app.client.conversations.history({
|
||||||
|
token: token,
|
||||||
|
channel: id,
|
||||||
|
oldest: Math.floor(Date.now() / 1000) - 86400, //debug: 1596326400, actual: Math.floor(Date.now() / 1000) - 86400
|
||||||
|
inclusive: false
|
||||||
|
});
|
||||||
|
const number = extractNumber(result.messages[result.messages.length - 2].text);
|
||||||
|
return number - 1;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function publishMessage(id, text) {
|
||||||
|
try {
|
||||||
|
const result = await app.client.chat.postMessage({
|
||||||
|
token: token,
|
||||||
|
channel: id,
|
||||||
|
text: text
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function postReaction(id, emoji, ts) {
|
||||||
|
try {
|
||||||
|
const result = await app.client.reactions.add({
|
||||||
|
token: token,
|
||||||
|
channel: id,
|
||||||
|
name: emoji,
|
||||||
|
timestamp: ts
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pinMessage(id, ts) {
|
||||||
|
try {
|
||||||
|
const result = await app.client.pins.add({
|
||||||
|
token: token,
|
||||||
|
channel: id,
|
||||||
|
timestamp: ts
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findMean(arr) {
|
||||||
|
let totalSum = 0;
|
||||||
|
for (let i of arr) {
|
||||||
|
totalSum += i;
|
||||||
|
}
|
||||||
|
return totalSum / arr.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function predictTime(goal) {
|
||||||
|
let daysLeft = (goal - latest) / averageSpeed
|
||||||
|
let unix = new Date(Date.now() + daysLeft * 86400000)
|
||||||
|
return moment(unix).fromNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function report() {
|
||||||
|
let oldest = await fetchOldest(channel);
|
||||||
|
latest = await fetchLatest(channel);
|
||||||
|
let diff = latest - oldest;
|
||||||
|
speedArr.push(diff);
|
||||||
|
// base('increase').create({
|
||||||
|
// "Date":
|
||||||
|
// })
|
||||||
|
averageSpeed = findMean(speedArr).toFixed(3);
|
||||||
|
let thousandsGoal = Math.ceil(latest / 1000) * 1000;
|
||||||
|
let thousandsTime = predictTime(thousandsGoal)
|
||||||
|
let tenThousandsGoal = Math.ceil(latest / 5000) * 5000;
|
||||||
|
let pastThousandsGoal = Math.floor(latest / 1000) * 1000;
|
||||||
|
let tenThousandsTime = predictTime(tenThousandsGoal)
|
||||||
|
let message =
|
||||||
|
"Nice! Today we've went from *" +
|
||||||
|
oldest +
|
||||||
|
"* to *" +
|
||||||
|
latest +
|
||||||
|
"*! \n - :arrow_upper_right: The day's progress: *+" +
|
||||||
|
diff +
|
||||||
|
"*\n - :chart_with_upwards_trend: Average daily speed: *" +
|
||||||
|
averageSpeed +
|
||||||
|
"*\n - :round_pushpin: At the avg speed, we'll reach " +
|
||||||
|
thousandsGoal +
|
||||||
|
" *" +
|
||||||
|
thousandsTime +
|
||||||
|
"*\n - :calendar: At the avg speed, we'll reach " +
|
||||||
|
tenThousandsGoal +
|
||||||
|
" *" +
|
||||||
|
tenThousandsTime +
|
||||||
|
"* \n :fastparrot: KEEP IT GOING GUYS!";
|
||||||
|
if (pastThousandsGoal > oldest && pastThousandsGoal <= newest) {
|
||||||
|
let messageWithCelebration = ":tada: YAY! We've went past " + pastThousandsGoal + "! :tada: \n" + message;
|
||||||
|
publishMessage(channel, messageWithCelebration);
|
||||||
|
} else {
|
||||||
|
publishMessage(channel,message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
app.event('message', async (body) => {
|
||||||
|
try {
|
||||||
|
let e = body.event;
|
||||||
|
if (typeof e.subtype === "undefined" && /\d/.test(e.text[0])) {
|
||||||
|
let number = extractNumber(e.text);
|
||||||
|
let ts = e.ts;
|
||||||
|
let c = e.channel;
|
||||||
|
if (number % 1000 === 0) {
|
||||||
|
postReaction(c, "tada", ts);
|
||||||
|
}
|
||||||
|
if (number % 5000 === 0) {
|
||||||
|
pinMessage(c, ts);
|
||||||
|
}
|
||||||
|
let l = number.length;
|
||||||
|
if (number[l - 2] == 6 && number[l - 1] == 9) {
|
||||||
|
postReaction(c, "ok_hand", ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(async (req, res) => {
|
||||||
|
// Start your app
|
||||||
|
try {
|
||||||
|
await app.start(process.env.PORT || 3000);
|
||||||
|
let j = schedule.scheduleJob('0 0 * * *', report); // */1 * * * * for debugging, 0 0 * * * actual
|
||||||
|
publishMessage('C017W4PHYKS', 'running every midnight!')
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
})();
|
5
keep_alive.js
Normal file
5
keep_alive.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const http = require('http');
|
||||||
|
http.createServer(function(req, res) {
|
||||||
|
res.write("I'm alive");
|
||||||
|
res.end();
|
||||||
|
}).listen(8080);
|
1099
package-lock.json
generated
Normal file
1099
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
26
package.json
Normal file
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "bolt-app-template",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "A basic template to spin up a Bolt app for Slack",
|
||||||
|
"main": "app.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node app.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@slack/bolt": "^2.2.3",
|
||||||
|
"airtable": "^0.9.0",
|
||||||
|
"moment": "^2.27.0",
|
||||||
|
"node-schedule": "^1.3.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "11.x"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"url": "https://glitch.com/edit/#!/bolt-app-template"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"node",
|
||||||
|
"express"
|
||||||
|
]
|
||||||
|
}
|
1041
shrinkwrap.yaml
Normal file
1041
shrinkwrap.yaml
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue