Skip to content

Commit cde60aa

Browse files
committed
Init commit
0 parents  commit cde60aa

File tree

10 files changed

+1846
-0
lines changed

10 files changed

+1846
-0
lines changed

.gitignore

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
.pnpm-debug.log*
9+
10+
# Diagnostic reports (https://nodejs.org/api/report.html)
11+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12+
13+
# Runtime data
14+
pids
15+
*.pid
16+
*.seed
17+
*.pid.lock
18+
19+
# Directory for instrumented libs generated by jscoverage/JSCover
20+
lib-cov
21+
22+
# Coverage directory used by tools like istanbul
23+
coverage
24+
*.lcov
25+
26+
# nyc test coverage
27+
.nyc_output
28+
29+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30+
.grunt
31+
32+
# Bower dependency directory (https://bower.io/)
33+
bower_components
34+
35+
# node-waf configuration
36+
.lock-wscript
37+
38+
# Compiled binary addons (https://nodejs.org/api/addons.html)
39+
build/Release
40+
41+
# Dependency directories
42+
node_modules/
43+
jspm_packages/
44+
45+
# Snowpack dependency directory (https://snowpack.dev/)
46+
web_modules/
47+
48+
# TypeScript cache
49+
*.tsbuildinfo
50+
51+
# Optional npm cache directory
52+
.npm
53+
54+
# Optional eslint cache
55+
.eslintcache
56+
57+
# Optional stylelint cache
58+
.stylelintcache
59+
60+
# Microbundle cache
61+
.rpt2_cache/
62+
.rts2_cache_cjs/
63+
.rts2_cache_es/
64+
.rts2_cache_umd/
65+
66+
# Optional REPL history
67+
.node_repl_history
68+
69+
# Output of 'npm pack'
70+
*.tgz
71+
72+
# Yarn Integrity file
73+
.yarn-integrity
74+
75+
# dotenv environment variable files
76+
.env
77+
.env.development.local
78+
.env.test.local
79+
.env.production.local
80+
.env.local
81+
82+
# parcel-bundler cache (https://parceljs.org/)
83+
.cache
84+
.parcel-cache
85+
86+
# Next.js build output
87+
.next
88+
out
89+
90+
# Nuxt.js build / generate output
91+
.nuxt
92+
dist
93+
94+
# Gatsby files
95+
.cache/
96+
# Comment in the public line in if your project uses Gatsby and not Next.js
97+
# https://nextjs.org/blog/next-9-1#public-directory-support
98+
# public
99+
100+
# vuepress build output
101+
.vuepress/dist
102+
103+
# vuepress v2.x temp and cache directory
104+
.temp
105+
.cache
106+
107+
# Docusaurus cache and generated files
108+
.docusaurus
109+
110+
# Serverless directories
111+
.serverless/
112+
113+
# FuseBox cache
114+
.fusebox/
115+
116+
# DynamoDB Local files
117+
.dynamodb/
118+
119+
# TernJS port file
120+
.tern-port
121+
122+
# Stores VSCode versions used for testing VSCode extensions
123+
.vscode-test
124+
125+
# yarn v2
126+
.yarn/cache
127+
.yarn/unplugged
128+
.yarn/build-state.yml
129+
.yarn/install-state.gz
130+
.pnp.*

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Hack Club
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# directory
2+
3+
This is the directory bot for Hack Club.

index.js

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
require("dotenv").config();
2+
const { App } = require("@slack/bolt");
3+
const fs = require("fs");
4+
const app = new App({
5+
token: process.env.SLACK_BOT_TOKEN,
6+
signingSecret: process.env.SLACK_SIGNING_SECRET,
7+
socketMode: true,
8+
appToken: process.env.SLACK_APP_TOKEN,
9+
});
10+
11+
(async () => {
12+
await app.start(process.env.PORT || 3000);
13+
async function pull() {
14+
var blocks = [];
15+
let sPromises = fs
16+
.readdirSync("./sections")
17+
.filter((str) => str.endsWith(".js"))
18+
.sort()
19+
.map(async (fn) => {
20+
const section = await require(`./sections/${fn}`);
21+
const text = (await section.render({ app })).trim();
22+
blocks.push({
23+
type: "section",
24+
text: {
25+
type: "plain_text",
26+
text: section.title,
27+
emoji: true,
28+
},
29+
});
30+
blocks.push({
31+
type: "section",
32+
text: {
33+
type: "mrkdwn",
34+
text: text,
35+
},
36+
});
37+
blocks.push({
38+
type: "divider",
39+
});
40+
});
41+
42+
await Promise.all(sPromises);
43+
44+
const data = await app.client.conversations.history({
45+
channel: process.env.SLACK_CHANNEL,
46+
});
47+
const { messages } = data;
48+
49+
await Promise.all(
50+
messages.map((message) =>
51+
app.client.chat
52+
.delete({
53+
token: process.env.SLACK_USER_TOKEN,
54+
channel: process.env.SLACK_CHANNEL,
55+
ts: message?.ts,
56+
thread_ts: message?.thread_ts,
57+
})
58+
.catch((e) => {
59+
console.warn(e);
60+
}),
61+
),
62+
);
63+
blocks.push({
64+
type: "section",
65+
text: {
66+
type: "mrkdwn",
67+
text: `Last Updated on ${new Date().toLocaleString("en-US", { timeZone: "America/New_York", timeStyle: "short", dateStyle: "long" })} (EST)`,
68+
},
69+
});
70+
app.client.chat.postMessage({
71+
channel: process.env.SLACK_CHANNEL,
72+
blocks,
73+
});
74+
}
75+
pull();
76+
setInterval(pull, 1000 * 30);
77+
console.log("⚡️ Bolt app is running!");
78+
})();

package.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "directory",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"license": "MIT",
6+
"scripts": {
7+
"start": "node .",
8+
"fmt": "npx prettier --write '**/*.js'",
9+
"dev": "npx nodemon ."
10+
},
11+
"dependencies": {
12+
"@prisma/client": "5.15.0",
13+
"@slack/bolt": "^3.18.0",
14+
"dotenv": "^16.4.5",
15+
"pretty-ms": "7.0.1",
16+
"prisma": "^5.15.0"
17+
}
18+
}

prisma/schema.prisma

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
generator client {
2+
provider = "prisma-client-js"
3+
}
4+
5+
datasource db {
6+
provider = "postgresql"
7+
url = env("DATABASE_URL")
8+
}
9+
10+
model Channel {
11+
id String @unique @id
12+
createdAt DateTime @default(now())
13+
location String
14+
optout Boolean @default(false)
15+
}

sections/1-featured.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module.exports = {
2+
title: "⭐ Featured Channels",
3+
description: "Channels featured by Hack Club",
4+
/**
5+
* @param {{app: import('@slack/bolt').App}} param1
6+
*/
7+
render: async function ({ app }) {
8+
return (text = `<#C75M7C0SY> - Introduce yourself to the community here
9+
<#C0266FRGV> - Meet new people here
10+
<#C0266FRGT> - Get updates about Hack Club
11+
<#C06SBHMQU8G> - Every hour more power: Get rewarded with cool prizes for working on your own projects
12+
<#C05T8E9GY64> - Days of Service a program to support girls and non-binary people learning to code.`);
13+
},
14+
};

sections/2-recent.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const pms = require("pretty-ms");
2+
const utils = require("../utils");
3+
module.exports = {
4+
title: "🆕 Most Recent Activity",
5+
description: "This gets the most recently updates channels",
6+
/**
7+
* @param {{app: import('@slack/bolt').App}} param1
8+
*/
9+
render: async function ({ app }) {
10+
const query = "-is:dm";
11+
let messages = await app.client.search.messages({
12+
query,
13+
sort: "timestamp",
14+
sort_dir: "desc",
15+
count: 100,
16+
token: process.env.SLACK_USER_TOKEN,
17+
});
18+
var text = `:siren-real: Latest message: ${pms(Date.now() - Math.floor(messages.messages.matches[0].ts * 1000))} ago (from *now*)\n\n`;
19+
20+
const channels = messages.messages.matches
21+
.filter(
22+
(match) =>
23+
match.channel.is_channel &&
24+
!match.channel.is_private &&
25+
!utils.blockedChannels.includes(match.channel.id),
26+
)
27+
.map((match) => match.channel.id)
28+
.reduce((acc, channel) => {
29+
acc[channel] = (acc[channel] || 0) + 1;
30+
return acc;
31+
}, {});
32+
const sortedChannels = Object.keys(channels).sort(
33+
(a, b) => channels[b] - channels[a],
34+
);
35+
36+
sortedChannels.forEach((channel) => {
37+
text += `<#${channel}> `;
38+
});
39+
return text;
40+
},
41+
};

utils.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = {
2+
blockedChannels: [
3+
"C05G25Y9M6V", // #infra-alerts
4+
"CLU651WHY", // #orpheus-internals
5+
"CNMU9L92Q", // #confessions
6+
"CCZ5LRL6P", // #politics
7+
"C0159TSJVH8", // #what-is-my-slack-id
8+
"C077R6LC3C1", // #directory (this bot!)
9+
"CT0BV6UMV", // #confessions-meta,
10+
"C0188CY57PZ", // #meta
11+
12+
// Introducing: Bot hell
13+
// Too lazy to type names for all bot channels ever, so...
14+
"C0P5NE354",
15+
"C06QL7WMRLK",
16+
"C02HSS9Q3D5",
17+
],
18+
};

0 commit comments

Comments
 (0)