Skip to content

Instantly share code, notes, and snippets.

@calebhearth
Created October 2, 2020 03:08
Show Gist options
  • Save calebhearth/109cd341c1cb6721fae83dad92c7d51d to your computer and use it in GitHub Desktop.
Save calebhearth/109cd341c1cb6721fae83dad92c7d51d to your computer and use it in GitHub Desktop.
import { WebClient, WebAPICallResult, LogLevel } from '@slack/web-api';
import express from 'express';
import fetch from "node-fetch";
import pgPromise from 'pg-promise';
const slack = new WebClient(process.env.SLACK_TOKEN, { logLevel: LogLevel.DEBUG });
var dbu: string
if (process.env.DATABASE_URL !== undefined)
dbu = process.env.DATABASE_URL
else
console.log("DATABASE_URL not set");
process.exit(1);
if (process.env.ENV == "production") {
dbu+="?ssl=true"
}
interface DBScopes {
createInitiative(ts: string, name: string, initiative: number | undefined): Promise<any>;
initiativeExists(ts: string): Promise<boolean>;
initiativesForTs(ts: string): Promise<inititiativeLineItem[]>;
}
const pgpOptions: pgPromise.IInitOptions<DBScopes> = {
extend(db) {
db.createInitiative = (ts: string, name: string, initiative: number | undefined) => {
return db.one(
"INSERT INTO initiatives(ts, name, initiative) \
VALUES(${ts}, ${name}, ${initiative}) \
RETURNING id;",
{ ts: ts, name: name, initiative: initiative }
);
}
db.initiativeExists = (ts: string) => {
return db.one(
"SELECT exists(SELECT 1 FROM initiatives WHERE ts = ${ts});",
{ ts: ts }
)
}
}
}
var pgp = pgPromise(pgpOptions)
const QueryResultError = pgp.errors.QueryResultError;
var db = pgp(dbu);
const app: express.Application = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
type inititiativeLineItem = {
name: string;
bonus: number;
initiative?: number;
}
app.post("/initiative", (req, resp) => {
console.log("BODY:", req.body);
resp.status(200).send()
var items = parseInitiative(req.body.text)
var lines: string[] = [];
items.forEach((item: inititiativeLineItem) => {
item.initiative = Math.ceil(Math.random() * 20) + item.bonus
lines.push(`• ${item.initiative} ${item.name}\n`)
});
var response: string = lines.sort().reverse().join("\n")
console.log("WILL RESPOND WITH: ", response)
slack.chat.postMessage({channel: req.body.channel_id, text: response})
.then(body => {
console.log(body)
var msg: message = body.message!
return items.forEach((item: inititiativeLineItem) => {
db.createInitiative(msg.ts, item.name, item.initiative);
});
});
// TODO: set up to read thread responses and add to message
});
app.post("/slack-events", (req, resp) => {
console.log("EVENT: ", req.body);
if (req.body.type == "url_verification")
resp.status(200).send(req.body.challenge);
return;
switch (req.body.event?.type) {
case "message":
var inInitiativeThread: boolean = db.initiativeExists(req.body.event.thread_ts!)
.then((data: any) => data.exists!)
.catch(error => console.log(error));
break;
default:
resp.status(200).send();
console.log("Unable to process event.");
break;
}
});
app.post("/*", (req, resp) => {
console.log("UNKNOWN: ", req.body);
resp.send("???")
});
interface ChatPostMessageResult extends WebAPICallResult {
channel: string;
ts: string;
message: {
text: string;
}
}
interface message {
ts: string;
}
// 0 or more [<number>x]<name>[[+/-]<bonus>] entries separated by whitespace
// 2xGoblin+2 => 2 goblins each with a +2 bonus
// Bugbear => 1 Bugbear with a 0 bonus
function parseInitiative(text: string): inititiativeLineItem[] {
const re = /((?<number>\d+)x)?(?<name>[A-Za-z][A-Za-z\s]+[A-Za-z])(?<bonus>[+-]\d+)?/g
var lineItems: inititiativeLineItem[] = [];
for (var match of text.matchAll(re)) {
var number: number = +(match?.groups?.number ?? 1);
for (let i: number = 0; i < number; i++) {
var name = match?.groups?.name ?? "No name"
if (number > 1) name += ` ${i+1}`
lineItems.push({ name: name, bonus: +(match?.groups?.bonus ?? 0) });
}
}
return lineItems;
}
app.listen(process.env.PORT, ()=> {
console.log(`Server listening on :${process.env.PORT}`);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment