Skip to content

Commit

Permalink
feat: adding help balance and deduct slash commands
Browse files Browse the repository at this point in the history
  • Loading branch information
zjorge96 committed Oct 19, 2023
1 parent cfea27f commit fc9b692
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 177 deletions.
184 changes: 68 additions & 116 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ const {
maximum,

Check failure on line 7 in app.js

View workflow job for this annotation

GitHub Actions / lint

'maximum' is assigned a value but never used
reactionEmoji,

Check failure on line 8 in app.js

View workflow job for this annotation

GitHub Actions / lint

'reactionEmoji' is assigned a value but never used
goldenRecognizeEmoji,

Check failure on line 9 in app.js

View workflow job for this annotation

GitHub Actions / lint

'goldenRecognizeEmoji' is assigned a value but never used
usersDeduction,
slashCommand,
} = require("./config");
const { respondToHelp, respondToEasterEgg } = require("./features/help");
const { respondToBalance } = require("./features/balance");
const { createDeduction } = require("./service/deduction");

const app = new App({
token: process.env.BOT_USER_OAUTH_ACCESS_TOKEN,
Expand Down Expand Up @@ -65,39 +69,17 @@ webserver.get("/health", async (req, res) => {
winston.debug("Health check passed");
});

var normalizedPath = require("path").join(__dirname, "features");
require("fs")
.readdirSync(normalizedPath)
.forEach(function (file) {
require("./features/" + file)(app);
});
// var normalizedPath = require("path").join(__dirname, "features");
// require("fs")
// .readdirSync(normalizedPath)
// .forEach(function (file) {
// require("./features/" + file)(app);
// });

/// ////////////////////////////////////////////////////////////
// Slash Command Logic //
/// ////////////////////////////////////////////////////////////

app.command(slashCommand, async ({ command, ack, respond }) => {
await ack();
const userCommand = parseCommand(command);

switch (userCommand.command) {
case "help":
await respond(helpMarkdown);
}
});

(async () => {
await app.start(3000);
webserver.listen(process.env.PORT || 3000);

winston.info("⚡️ Bolt app is running!");
})();

/// ////////////////////////////////////////////////////////////
// Functions //
/// ////////////////////////////////////////////////////////////

// Parse Command Function
function parseCommand(command) {
const parsed = {
// Default values for each parameter
Expand All @@ -113,101 +95,71 @@ function parseCommand(command) {
case "help":
parsed.valid = true; // command is valid, but doesn't require any additional info
break;
case "thunderfury":
parsed.valid = true;
break;
case "balance":
parsed.valid = true;
break;
case "deduct":
if (raw.length === 3) {
parsed.valid = true;
parsed.user = raw[1];
parsed.value = raw[2];
}
break;
}

// if none of the above cases are true, parsed.valid will stay false

return parsed;
}

/// ////////////////////////////////////////////////////////////
// Variables //
/// ////////////////////////////////////////////////////////////

// Text is rendered into help command
const helpMarkdown = `
:wave: Hi there! Let's take a look at what I can do!
*Give Recognition*
You can give up to ${maximum} recognitions per day.
First, make sure I have been invited to the channel you want to recognize \
someone in. Then, write a brief message describing what someone did, \
\`@mention\` them and include the ${recognizeEmoji} emoji...I'll take it from there!
> Thanks @alice for helping me fix my pom.xml ${recognizeEmoji}
Recognize multiple people at once!
> @bob and @alice crushed that showcase! ${recognizeEmoji}
Use \`#tags\` to call out specific Liatrio values!
> I love the #energy in your Terraform demo @alice! ${recognizeEmoji}
The more emojis you add, the more recognition they get!
> @alice just pushed the cleanest code I've ever seen! ${recognizeEmoji} ${recognizeEmoji} ${recognizeEmoji}
Use multipliers to give more recognition!
> @alice presented an amazing demo at a conference! ${recognizeEmoji} x2
or
> @alice presented an amazing demo at a conference! x2 ${recognizeEmoji}
If someone else has given a ${recognizeEmoji} to someone, and you'd like to \
give one of your own for the same reason, you can react to the message with \
a ${reactionEmoji}. Gratibot will record your shout-out as though you sent \
the same message that you reacted to.
*Redeeming*
Send me a direct message with 'redeem' and I'll give you the options for prizes to redeem! Once you've selcted an item then I'll start a MPIM with the redemption admins to promote the dialog to acknowledge and receive your item.
Refunds can be given via the 'refund' command if the item redeem can't be fulfilled for whatever reason. Only redemption admins can give refunds. Deduction ID is sent as part of the MPIM when an item is redeemed
> @gratibot refund DEDUCTIONID
*View Balance*
Send me a direct message with 'balance' and I'll let you know how many \
recognitions you have left to give and how many you have received.
> You have received 0 ${recognizeEmoji} and you have ${maximum} ${recognizeEmoji} remaining to \
give away today
*View Leaderboard*
Send me a direct message with 'leaderboard' and I'll show you who is giving \
and receiving the most recognition. I'll also show who currently holds the :goldenfistbump:!
*View Metrics*
Send me a direct message with 'metrics' and I'll show you how many times \
people have given recognitions over the last month.
*Give Golden Recognition*
The golden fistbump ${goldenRecognizeEmoji} is a special recognition that can only be held by one user at a time. Only the current holder of the golden recognition can give the golden recognition.
app.command(slashCommand, async ({ command, ack, respond }) => {
await ack();
const userCommand = parseCommand(command);

Giving a golden fistbump is the same as giving a normal fistbump
switch (userCommand.command) {
case "help":
helpResponse = await respondToHelp({ user: command.user_id });

Check failure on line 124 in app.js

View workflow job for this annotation

GitHub Actions / lint

'helpResponse' is not defined
await respond(helpResponse);

Check failure on line 125 in app.js

View workflow job for this annotation

GitHub Actions / lint

'helpResponse' is not defined
break;
case "thunderfury":
thunderfuryResponse = await respondToEasterEgg({ user: command.user_id });

Check failure on line 128 in app.js

View workflow job for this annotation

GitHub Actions / lint

'thunderfuryResponse' is not defined
await respond(thunderfuryResponse);

Check failure on line 129 in app.js

View workflow job for this annotation

GitHub Actions / lint

'thunderfuryResponse' is not defined
break;
case "balance":
balanceResponse = await respondToBalance({ user: command.user_id, client: app.client });

Check failure on line 132 in app.js

View workflow job for this annotation

GitHub Actions / lint

'balanceResponse' is not defined

Check failure on line 132 in app.js

View workflow job for this annotation

GitHub Actions / lint

Replace `·user:·command.user_id,·client:·app.client` with `⏎········user:·command.user_id,⏎········client:·app.client,⏎·····`
await respond(balanceResponse);
break;
case "deduct":
if (
userCommand.user === "" ||
userCommand.value === "" ||
userCommand.length < 3
) {
await respond(
"Invalid command. Please use the format `/gratibot deduct [@USER] [VALUE]`."
);
break;
}
if (!usersDeduction.includes(command.user_id)) {
await respond("The `deduct` command is not available to you.");
break;
}
if (userCommand.valid) {
await respond(
`Deducting ${userCommand.value} from ${userCommand.user}`
);
await createDeduction(userCommand.user, userCommand.value);
break;
}
}
});

> Thanks @alice for helping fix the prod issues! ${goldenRecognizeEmoji}
(async () => {
await app.start(3000);
webserver.listen(process.env.PORT || 3000);

Upon receiving the golden fistbump, the user will receive 20 fistbumps and will have a 2X multiplier applied to all incoming fistbumps while the golden fistbump is held.
`;
winston.info("⚡️ Bolt app is running!");
})();
8 changes: 4 additions & 4 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ config.redemptionAdmins = process.env.REDEMPTION_ADMINS?.split(",") || [
"U04666K57CP",
];

config.usersDeduction = process.env.USERS_DEDUCTION?.split(",") || [
"U04666K57CP", // Danielle
"U8T585Y8J", // Jeremy
"U02KPMFA9DG", // Smith
config.usersDeduction = process.env.DEDUCTION_USERS?.split(",") || [
"U04666K57CP",
"U8T585Y8J",
"U02KPMFA9DG",
];

module.exports = config;
1 change: 1 addition & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ services:
- REDEMPTION_ADMINS
- BOT_NAME
- SLASH_COMMAND
- DEDUCTION_USERS
mongodb:
ports:
- 27017:27017
Expand Down
49 changes: 16 additions & 33 deletions features/balance.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,31 @@
const balance = require("../service/balance");
const winston = require("../winston");
const { directMention } = require("@slack/bolt");
const { directMessage, anyOf } = require("../middleware");

module.exports = function (app) {
app.message(
"balance",
anyOf(directMention(), directMessage()),
respondToBalance
);

module.exports = {
respondToBalance,
};

async function respondToBalance({ message, client }) {
winston.info("@gratibot balance Called", {
async function respondToBalance({ user, client }) {
winston.info("/gratibot balance Called", {
func: "feature.balance.respondToBalance",
callingUser: message.user,
slackMessage: message.text,
callingUser: user,
});

const userInfo = await client.users.info({ user: message.user });
const userInfo = await client.users.info({ user });
if (!userInfo.ok) {
winston.error("Slack API returned error from users.info", {
func: "feature.balance.respondToBalance",
callingUser: message.user,
slackMessage: message.text,
callingUser: user,
error: userInfo.error,
});
await client.chat.postEphemeral({
channel: message.channel,
user: message.user,
text: `Something went wrong while obtaining your balance. When retreiving user information from Slack, the API responded with the following error: ${userInfo.error}`,
});
return;

return `Something went wrong while obtaining your balance. When retreiving user information from Slack, the API responded with the following error: ${userInfo.error}`;
}

const currentBalance = await balance.currentBalance(message.user);
const lifetimeTotal = await balance.lifetimeEarnings(message.user);
const currentBalance = await balance.currentBalance(user);
const lifetimeTotal = await balance.lifetimeEarnings(user);
const remainingToday = await balance.dailyGratitudeRemaining(
message.user,
user,
userInfo.user.tz,
1
);
Expand All @@ -48,15 +36,10 @@ async function respondToBalance({ message, client }) {
`You have \`${remainingToday}\` left to give away today.`,
].join("\n");

await client.chat.postEphemeral({
channel: message.channel,
user: message.user,
text: response,
});

winston.debug("successfully posted ephemeral balance result to Slack", {
func: "feature.balance.respondToBalance",
callingUser: message.user,
slackMessage: message.text,
callingUser: user,
});

return response;
}
40 changes: 16 additions & 24 deletions features/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ const {
maximum,
reactionEmoji,
goldenRecognizeEmoji,
slashCommand,
} = require("../config");
const winston = require("../winston");
const { directMention } = require("@slack/bolt");
const { anyOf, directMessage } = require("../middleware");

module.exports = function (app) {
app.message("help", anyOf(directMention(), directMessage()), respondToHelp);
app.message(/(thunderfury|Thunderfury)/, respondToEasterEgg);
module.exports = {
respondToHelp,
respondToEasterEgg,
};

const helpMarkdown = `
Expand Down Expand Up @@ -66,7 +65,7 @@ Refunds can be given via the 'refund' command if the item redeem can't be fulfil
*View Balance*
Send me a direct message with 'balance' and I'll let you know how many \
Use the \`${slashCommand} balance\` command and I'll let you know how many \
recognitions you have left to give and how many you have received.
> You have received 0 ${recognizeEmoji} and you have ${maximum} ${recognizeEmoji} remaining to \
Expand Down Expand Up @@ -100,23 +99,18 @@ Giving a golden fistbump is the same as giving a normal fistbump
Upon receiving the golden fistbump, the user will receive 20 fistbumps and will have a 2X multiplier applied to all incoming fistbumps while the golden fistbump is held.
`;

async function respondToHelp({ message, client }) {
winston.info("@gratibot help Called", {
async function respondToHelp({ user }) {
winston.info("/gratibot help Called", {
func: "feature.help.respondToHelp",
callingUser: message.user,
slackMessage: message.text,
});
await client.chat.postEphemeral({
channel: message.channel,
user: message.user,
text: helpMarkdown,
callingUser: user,
});

winston.debug("successfully posted ephemeral help message to Slack", {
func: "feature.help.respondToHelp",
callingUser: message.user,
slackMessage: message.text,
callingUser: user,
});

return helpMarkdown;
}

const thunderfuryResponse = [
Expand All @@ -126,17 +120,15 @@ const thunderfuryResponse = [
":thunderfury_blessed_blade_of_the_windseeker:?",
].join(" ");

async function respondToEasterEgg({ message, say }) {
async function respondToEasterEgg({ user, say }) {
winston.info("heard reference to thunderfury", {
callingUser: message.user,
slackMessage: message.text,
callingUser: user,
});

await say(thunderfuryResponse);

winston.debug("successfully posted thunderfury message to Slack", {
func: "feature.help.respondToEasterEgg",
callingUser: message.user,
slackMessage: message.text,
callingUser: user,
});

return thunderfuryResponse;
}

0 comments on commit fc9b692

Please sign in to comment.