Skip to content

Commit 4efa525

Browse files
feat: add potato when reacting to message (#8)
1 parent ea2bb79 commit 4efa525

3 files changed

Lines changed: 84 additions & 28 deletions

File tree

slack-service/app.js

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Sentry
22
const Sentry = require("@sentry/node");
33

4+
// lodash
5+
const _ = require("lodash");
6+
47
// UUID
58
const { v4: uuid } = require("uuid");
69

@@ -126,7 +129,10 @@ async function getUserNameBySlackId(userId) {
126129
});
127130
return result["user"]["real_name"];
128131
} catch (error) {
129-
console.error(error); // Maybe do some proper error handling here
132+
// Maybe do some proper error handling here
133+
console.error(error);
134+
Sentry.captureException(error);
135+
130136
return "";
131137
}
132138
}
@@ -149,44 +155,53 @@ async function getUserDbId(slackId) {
149155
}
150156
}
151157

152-
// Listens to incoming messages that contain "hello"
153-
app.message(":potato:", async ({ message, say }) => {
154-
const senderSlackId = message.user;
155-
const text = message.text;
158+
/// Figure out who gets potato
159+
async function givePotato({user, text, channel, ts}) {
160+
const senderSlackId = user;
156161
const senderDBId = await getUserDbId(senderSlackId);
157162

158-
const regex = /<.*?>/g; // Regex to find all the mentions
163+
// Regex to find all the mentions
164+
const regex = /<.*?>/g;
159165
const userSlackIdsFound = text.match(regex);
160166

161167
// Extract the ids from the mention
162-
const receiverSlackIds = userSlackIdsFound
163-
.filter((item, index) => userSlackIdsFound.indexOf(item) === index) // Remove duplicate ids
164-
.map((t) => t.substring(2, t.length - 1)) // Remove the <@ >
165-
.filter((t) => t !== senderSlackId); // Remove the sender if he is in the message
168+
let receiverSlackIds = userSlackIdsFound
169+
// Remove duplicate ids
170+
.filter((item, index) => userSlackIdsFound.indexOf(item) === index)
171+
// Remove the <@ >
172+
.map((t) => t.substring(2, t.length - 1));
166173

167174
const postEphemeral = async (text) => {
168175
return app.client.chat.postEphemeral({
169-
channel: message.channel,
176+
channel: channel,
170177
user: senderSlackId,
171178
text,
172179
});
173180
};
174181

182+
// Check if the only person recieving a potato is the creator of the message
183+
// and blame them...
184+
if (_.isEqual(receiverSlackIds, [`${senderSlackId}`])) {
185+
await postEphemeral("You cannot gib potato to yourself :face_with_raised_eyebrow:");
186+
return;
187+
}
188+
189+
// Remove the sender if they are in the message
190+
receiverSlackIds = receiverSlackIds.filter((t) => t !== senderSlackId);
191+
175192
if (!receiverSlackIds || receiverSlackIds.length == 0) {
176-
// Check needed for the length
177-
await postEphemeral("To gib people potato, you habe to @ someone");
193+
await postEphemeral("To gib people potato, you have to @ someone");
178194
return;
179195
}
180196

181197
const receiversCount = receiverSlackIds.length;
182198
const potatoCount = (text.match(/:potato:/g) || []).length;
183199

184-
// TODO: Check that there are potatos left to give for the sender (sender ids)
185-
// one more check
200+
// Check that there are potatos left to give for the sender (sender ids)
186201
const potatoesGivenToday = await getPotatoesGivenToday(senderDBId);
187202

188203
if (potatoesGivenToday > maxPotato) {
189-
await postEphemeral("You already have gib 5 potato today");
204+
await postEphemeral("You already have gib out 5 potato today");
190205
return;
191206
}
192207

@@ -199,7 +214,8 @@ app.message(":potato:", async ({ message, say }) => {
199214
let userDBIds = [];
200215

201216
for (const userSlackId of receiverSlackIds) {
202-
userDBIds.push(await getUserDbId(userSlackId)); // Adds the users to the Db if they are not in there yet
217+
// Adds the users to the Db if they are not in there yet
218+
userDBIds.push(await getUserDbId(userSlackId));
203219
}
204220

205221
// Add the message's to the DB
@@ -208,8 +224,8 @@ app.message(":potato:", async ({ message, say }) => {
208224
});
209225

210226
const permalinkToMessage = await app.client.chat.getPermalink({
211-
channel: message.channel,
212-
message_ts: message.ts
227+
channel: channel,
228+
message_ts: ts
213229
})
214230

215231
// This is just to check that we can find all the people -> Seems to work
@@ -222,31 +238,59 @@ app.message(":potato:", async ({ message, say }) => {
222238
});
223239
} catch (error) {
224240
console.error(error);
241+
Sentry.captureException(error);
225242
}
226243
receivers += `<@${userSlackId}> `;
227244
});
228245

229-
// Send the a Message to the sender of the Potatoes
230-
try {
246+
// Send the a Message to the sender of the Potatoes
247+
try {
231248
app.client.chat.postMessage({
232249
channel: senderSlackId,
233250
text: `You send *${potatoCount*receiversCount} potato* to ${receivers}\nYou have *${(maxPotato - potatoesGivenToday) - (potatoCount*receiversCount)} potato* left.\n>${permalinkToMessage.permalink}`,
234251
});
235252
} catch (error) {
236253
console.error(error);
254+
Sentry.captureException(error);
255+
}
256+
}
257+
258+
/// Listens to incoming messages that contain :potato:
259+
app.message(":potato:", async ({message}) => await givePotato({
260+
user: message.user,
261+
text: message.text,
262+
channel: message.channel,
263+
ts: message.ts,
264+
})
265+
);
266+
267+
268+
/// Listens to incoming :potato: reactions
269+
app.event("reaction_added", async ({ event }) => {
270+
if (event.reaction === "potato") {
271+
await givePotato({
272+
user: event.user,
273+
// Set the text of the message to the slack user_id of the creator
274+
// of the message the reaction was added to.
275+
// We do this messy stuff to be able to work with the same interface
276+
// givePotato() provides.
277+
text: `<@${event.item_user}> :${event.reaction}:`,
278+
channel: event.item.channel,
279+
ts: event.item.ts,
280+
});
237281
}
238282
});
239283

240-
/// Handle the messages
284+
/// Handle direct messages send to the bot
241285
app.event("message", async ({ event, client, context }) => {
242286
if (event["channel_type"] === "im") {
243-
if (event["text"] === "potatoes") {
287+
if (event["text"] === "potato") {
244288
const cur = newUTCDate();
245289
const userID = await getUserDbId(event["user"]);
246290
const potatoesGivenSoFar = await getPotatoesGivenToday(userID);
247291
client.chat.postMessage({
248292
channel: event["channel"],
249-
text: `You habe *${
293+
text: `You have *${
250294
maxPotato - potatoesGivenSoFar
251295
}* potato left to gib today. Your potato will reset in ${
252296
23 - cur.getUTCHours()
@@ -256,7 +300,7 @@ app.event("message", async ({ event, client, context }) => {
256300
}
257301
});
258302

259-
// Listen to app home opened event
303+
/// Listen to app home opened event
260304
app.event("app_home_opened", async ({ event, client, context }) => {
261305
const userSlackId = event["user"]
262306
const userDbId = await getUserDbId(userSlackId)
@@ -343,13 +387,13 @@ app.event("app_home_opened", async ({ event, client, context }) => {
343387
},
344388
});
345389
} catch (error) {
390+
console.log(error);
346391
Sentry.captureException(error);
347392
}
348393
});
349394

350395
(async () => {
351-
// Start your app
352396
await app.start(process.env.PORT || 3000);
353397

354-
console.log("⚡️ Bolt app is running!");
355-
})();
398+
console.log("🥔 GibPotato app is running!");
399+
})();

slack-service/package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

slack-service/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@sentry/node": "^7.11.1",
1414
"@slack/bolt": "^3.12.1",
1515
"dotenv": "^16.0.1",
16+
"lodash": "^4.17.21",
1617
"prisma": "^4.2.1",
1718
"uuidv4": "^6.2.13"
1819
},

0 commit comments

Comments
 (0)