Skip to content

Commit

Permalink
Merge pull request #206 from Decatur-Robotics/slack-for-other-teams
Browse files Browse the repository at this point in the history
  • Loading branch information
renatodellosso authored Jun 26, 2024
2 parents 8178f75 + 707c05f commit 2621d5c
Show file tree
Hide file tree
Showing 13 changed files with 3,461 additions and 536 deletions.
64 changes: 0 additions & 64 deletions index.js

This file was deleted.

97 changes: 97 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { join } from "path";
import { SlashCommand, AckFn, RespondArguments, RespondFn } from '@slack/bolt';
import { createServer } from "https";
import { parse } from "url";
import next from "next";
import fs from "fs";
import { App } from "@slack/bolt";
import SlackCommands from "./lib/SlackCommands";
import { IncomingMessage, ServerResponse } from "http";
import { WebClientEvent } from "@slack/web-api";

console.log("Starting server...");

const dev = process.env.NODE_ENV !== "production";
const port = 443;
const app = next({ dev });
const handle = app.getRequestHandler();

console.log("Constants set");

const httpsOptions = {
key: dev
? fs.readFileSync("./certs/localhost-key.pem")
: fs.readFileSync("./certs/production-key.pem"),
cert: dev
? fs.readFileSync("./certs/localhost.pem")
: fs.readFileSync("./certs/production.pem"),
};

console.log("HTTPS options set");

app.prepare().then(() => {
console.log("App prepared. Creating server...");

try {
const server = createServer(httpsOptions, async (req: IncomingMessage, res: ServerResponse<IncomingMessage>) => {
if (!req.url)
return;

const parsedUrl = parse(req.url, true);
const { pathname } = parsedUrl;

if (pathname && (pathname === '/sw.js' || /^\/(workbox|worker|fallback)-\w+\.js$/.test(pathname))) {
const filePath = join(__dirname, '.next', pathname);
(app as any).serveStatic(req, res, filePath);
} else {
handle(req, res, parsedUrl);
}
}).listen(port, () => {
console.log(
process.env.NODE_ENV +
" HTTPS Server Running At: https://localhost:" +
port,
);
}).on("error", (err: Error) => {
console.log(err);
throw err;
});

console.log("Server created. Listening: " + server.listening);
} catch (err) {
console.log(err);
throw err;
}
});

console.log("App preparing...");

// Slack bot

const slackApp = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
socketMode: true,
appToken: process.env.SLACK_APP_TOKEN,
});

slackApp.command(/\/.*/, async (props: { command: SlashCommand, ack: AckFn<string | RespondArguments>, respond: RespondFn }) => {
const { command, ack, respond } = props;

const commandName = command.command.replace("/", "");
const handler = SlackCommands[commandName];

if (handler) {
handler(command, ack, respond);
}
else {
await ack();
await respond(`Command not found: ` + commandName);
}
});

async function startSlackApp() {
await slackApp.start(port);
console.log("Slack bot is running!");
}
startSlackApp();
26 changes: 17 additions & 9 deletions lib/API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,12 +680,20 @@ export namespace API {
return res.status(200).send({ result: "success" });
},

remindSlack: async (req, res, { slackClient, data }) => {
await slackClient.chat.postMessage({
token: process.env.SLACK_KEY,
channel: process.env.SLACK_CHANNEL,
text: `<@${data.slackId}> Please report to our section and prepare for scouting. Sent by <@${data.senderSlackId}>`,
remindSlack: async (req, res, { db, slackClient, data }) => {
const team = await db.findObjectById<Team>(Collections.Teams, new ObjectId(data.teamId));
if (!team)
return res.status(200).send({ error: "Team not found" });
if (!team.slackChannel)
return res.status(200).send({ error: "Team has not linked their Slack channel" });

const msgRes = await slackClient.chat.postMessage({
token: process.env.SLACK_BOT_TOKEN,
channel: team.slackChannel,
text: `<@${data.slackId}>, please report to our section and prepare for scouting. Sent by <@${data.senderSlackId}>`,
});

return res.status(200).send({ result: "success", msgRes });
},

setSlackId: async (req, res, { db, data }) => {
Expand Down Expand Up @@ -809,18 +817,18 @@ export namespace API {

const { rankings } = tbaResult;

const rank = rankings.find((ranking) => ranking.team_key === `frc${data.team}`)?.rank;
const rank = rankings?.find((ranking) => ranking.team_key === `frc${data.team}`)?.rank;

if (!rank) {
return res.status(200).send({
place: "?",
max: rankings.length,
max: rankings?.length,
});
}

return res.status(200).send({
place: rankings.find((ranking) => ranking.team_key === `frc${data.team}`)?.rank,
max: rankings.length,
place: rankings?.find((ranking) => ranking.team_key === `frc${data.team}`)?.rank,
max: rankings?.length,
});
},

Expand Down
2 changes: 1 addition & 1 deletion lib/Auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const AuthenticationOptions: AuthOptions = {
);
user.id = profile.sub;
return user;
},
}
}),
],
callbacks: {
Expand Down
7 changes: 5 additions & 2 deletions lib/MongoDB.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import {
Db,
GridFSBucket,
MongoClient,
MongoClientOptions,
ObjectId,
UpdateResult,
} from "mongodb";

if (!process.env.MONGODB_URI) {
console.error('Invalid/Missing environment variable: "MONGODB_URI"');
// Necessary to allow connections from files running outside of Next
require("dotenv").config();

if (!process.env.MONGODB_URI)
console.error('Invalid/Missing environment variable: "MONGODB_URI"');
}

const uri = process.env.MONGODB_URI ?? "mongodb://localhost:27017";
Expand Down
57 changes: 57 additions & 0 deletions lib/SlackCommands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { AckFn, RespondArguments, RespondFn, SlashCommand } from "@slack/bolt";
import { Db, ObjectId } from "mongodb";
import { Collections, getDatabase } from "./MongoDB";
import { Team, User } from "./Types";

type SlackCommandDict = {
[command: string]:
(command: SlashCommand, acknowledge: AckFn<string | RespondArguments>, respond: RespondFn) => Promise<void>
};

const SlackCommands: SlackCommandDict = {
"link-notifications": async (command, acknowledge, respond) => {
await acknowledge();

if (!command.text || isNaN(+command.text)) {
await respond("Please provide a team number.");
return;
}

const teamNumber = +command.text;
const userId = command.user_id;

const db = await getDatabase();

const userPromise = db.findObject<User>(Collections.Users, { slackId: userId });
const teamPromise = db.findObject<Team>(Collections.Teams, { number: teamNumber });

const user = await userPromise;
const team = await teamPromise;

console.log(user, team);

if (!user) {
await respond("You are not registered in Gearbox. Please register first at https://4026.org.");
return;
}

if (!team) {
await respond(`Team ${teamNumber} does not exist.`);
return;
}

if (!team.owners.includes(user._id!.toString())) {
await respond(`You are not an owner of team ${teamNumber}.`);
return;
}

await db.updateObjectById<Team>(Collections.Teams, new ObjectId(team._id!), {
slackChannel: command.channel_id
});

db.client?.close();
await respond(`Linked channel for team ${teamNumber}. Make sure to run /invite @Gearbox to the channel to receive notifications.`);
}
}

export default SlackCommands;
6 changes: 5 additions & 1 deletion lib/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export class Team {

seasons: string[];

slackChannel: string | undefined;

constructor(
name: string,
slug: string | undefined,
Expand All @@ -89,7 +91,8 @@ export class Team {
scouters: string[] = [],
subjectiveScouters: string[] = [],
requests: string[] = [],
seasons: string[] = []
seasons: string[] = [],
slackChannel: string | undefined = undefined
) {
this.name = name;
this.slug = slug;
Expand All @@ -101,6 +104,7 @@ export class Team {
this.subjectiveScouters = subjectiveScouters;
this.seasons = seasons;
this.requests = requests;
this.slackChannel = slackChannel;
}
}

Expand Down
7 changes: 4 additions & 3 deletions lib/client/ClientAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,11 @@ export default class ClientAPI {
}

async remindSlack(
slackId: string | undefined,
senderSlackId: string | undefined
slackId: string,
senderSlackId: string,
teamId: string
) {
return await this.request("/remindSlack", { slackId, senderSlackId });
return await this.request("/remindSlack", { slackId, senderSlackId, teamId });
}

async setSlackId(userId: string | undefined, slackId: string | undefined) {
Expand Down
Loading

0 comments on commit 2621d5c

Please sign in to comment.