Skip to content

Commit

Permalink
Add undo ability for reviewers (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
anirudhb authored Oct 4, 2023
2 parents 1c0f3a9 + 2570122 commit 74e4041
Show file tree
Hide file tree
Showing 10 changed files with 1,232 additions and 878 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ secrets.json
*.jsx.map
*.js
*.js.map

.idea
142 changes: 142 additions & 0 deletions lib/interaction_handlers/block_action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { BlockActionInteraction, InteractionHandler } from "../../pages/api/interaction_work";
import { stageConfession, viewConfession, web } from "../main";
import { Blocks, InputSection, MarkdownText, PlainText, PlainTextInput, TextSection } from "../block_builder";
import getRepository from "../db";
import { approve_tw_id, undo_confirm_id } from "./view_submission";

const block_action: InteractionHandler<BlockActionInteraction> = async data => {
console.log(`Block action!`);
const repo = await getRepository();
if (data.actions.length <= 0) {
console.log(`No action found`);
return false;
}
const action = data.actions[0].value;
switch(action) {
case "approve": {
console.log(`Approval of message ts=${data.message.ts}`);
await viewConfession(repo, data.message.ts, true, data.user.id);
break;
}
case "disapprove": {
console.log(`Disapproval of message ts=${data.message.ts}`);
await viewConfession(repo, data.message.ts, false, data.user.id);
break;
}
case "approve:tw": {
console.log(`Trigger Warning Approval!`);
const resp = await web.views.open({
trigger_id: data.trigger_id,
view: {
callback_id: approve_tw_id(data.message.ts),
type: "modal",
title: new PlainText(`Approve with TW`).render(),
submit: new PlainText("Approve").render(),
close: new PlainText("Cancel").render(),
blocks: new Blocks([
new InputSection(
new PlainTextInput("approve_tw_input", true),
new PlainText("TW"),
"tw"
)
]).render()
}
});
if (!resp.ok) {
throw "Failed to open modal";
}
break;
}
case "stage": {
console.log(`Stage of message thread_ts=${data.message.thread_ts}`);
// Get message contents
const resp = await web.conversations.history({
channel: data.channel.id,
inclusive: true,
latest: data.message.thread_ts,
limit: 1
});
if (!resp.ok) {
throw `Failed to fetch message contents!`;
}
const message_contents = (resp as any).messages[0].text;
// Stage
const id = await stageConfession(
repo,
message_contents,
data.user.id
);
// Edit
const resp2 = await web.chat.update({
channel: data.channel.id,
ts: data.message.ts,
text: "",
blocks: new Blocks([
new TextSection(
new MarkdownText(`:true: Staged as confession #${id}`),
null,
null
)
]).render()
});
if (!resp2.ok) {
throw `Failed to update message!`;
}
break;
}
case "undo": {
console.log(`Undo staging of message ts=${data.message.ts}`);
const blocks = (data.message as any).blocks;
const reviewer_uid = (/by <@([A-Za-z0-9]+)>/g).exec(blocks[blocks.length - 2].text.text)?.[1] ?? "";
const undoer_uid = data.user.id;

// await unviewConfession(repo, data.message.ts, reviewer_uid, undoer_uid);

const resp = await web.views.open({
trigger_id: data.trigger_id,
view: {
callback_id: undo_confirm_id({
ts: data.message.ts,
reviewer_uid,
undoer_uid
}),
type: "modal",
title: new PlainText(`Undo confession review`).render(),
submit: new PlainText("Undo").render(),
close: new PlainText("Cancel").render(),
blocks: new Blocks([
// text
new TextSection(
new MarkdownText(
"Undoing approval is undoable, however replies will not be preserved."
)
)
]).render()
}
});
if (!resp.ok) {
throw "Failed to open modal";
}

break;
}
case "cancel": {
console.log(`Cancel of message thread_ts=${data.message.thread_ts}`);
const resp = await web.chat.delete({
channel: data.channel.id,
ts: data.message.ts
});
if (!resp.ok) {
throw `Failed to delete message!`;
}
break;
}
default: {
console.log(`Unknown value ${action}`);
}
}

return true;
};

export default block_action;
111 changes: 111 additions & 0 deletions lib/interaction_handlers/message_action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { confessions_channel } from "../secrets_wrapper";
import { sameUser, succeedRequest, web } from "../main";
import { Blocks, ExternalSelectAction, InputSection, PlainText, PlainTextInput, TextSection } from "../block_builder";
import { In } from "typeorm";
import { InteractionHandler, MessageActionInteraction } from "../../pages/api/interaction_work";
import getRepository from "../db";
import { react_modal_id, reply_modal_id } from "./view_submission";

const message_action: InteractionHandler<MessageActionInteraction> = async (data, res) => {
if (data.channel.id != confessions_channel) {
throw "Invalid channel ID";
}
switch(data.callback_id) {
case "reply_anonymous": {
// try to fetch record
const repo = await getRepository();
const record = await repo.findOne({ published_ts: data.message.ts });
if (record === undefined) {
throw `Failed to find single Postgres record with published_ts=${data.message.ts}`;
}

// Check user...
if (!sameUser(record, data.user.id)) {
await succeedRequest(
data.response_url,
"You are not the original poster of the confession, so you cannot reply anonymously."
);
res.writeHead(200).end();
return false;
}

if(!record.published_ts) throw "No published_ts";

const resp = await web.views.open({
trigger_id: data.trigger_id,
view: {
callback_id: reply_modal_id(record.published_ts),
type: "modal",
title: new PlainText(`Replying to #${record.id}`).render(),
submit: new PlainText("Reply").render(),
close: new PlainText("Cancel").render(),
blocks: new Blocks([
new InputSection(
new PlainTextInput("confession_reply", true),
new PlainText("Reply"),
"reply"
),
]).render(),
},
});
if (!resp.ok) {
throw "Failed to open modal";
}
break;
}
case "react_anonymous": {
// try to fetch record
let valid_ts = [data.message.ts];
if (data.message.thread_ts !== undefined)
valid_ts.push(data.message.thread_ts);
const repo = await getRepository();
const record = await repo.findOne({ published_ts: In(valid_ts) });
if (record === undefined) {
throw `Failed to find single Postgres record with published_ts=${data.message.ts}`;
}

// Check user...
if (!sameUser(record, data.user.id)) {
await succeedRequest(
data.response_url,
"You are not the original poster of the confession, so you cannot react anonymously."
);
res.writeHead(200).end();
return false;
}

if(!record.published_ts) throw "No published_ts";

const modal_res = await web.views.open({
trigger_id: data.trigger_id,
view: {
type: "modal",
callback_id: react_modal_id({ published_ts: record.published_ts, thread_ts: data.message.ts }),
title: new PlainText(`Reacting to #${record.id}`).render(),
submit: new PlainText("React").render(),
close: new PlainText("Cancel").render(),
blocks: new Blocks([
new TextSection(
new PlainText("Pick an emoji to react with"),
"emoji",
new ExternalSelectAction(
new PlainText("Select an emoji"),
2,
"emoji"
)
),
]).render(),
},
});
if (!modal_res.ok) throw `Failed to open modal`;
break;
}
default: {
console.log(`Unknown callback ${data.callback_id}`);
}
}

return true;
};

export default message_action;
Loading

1 comment on commit 74e4041

@vercel
Copy link

@vercel vercel bot commented on 74e4041 Oct 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

prox2 – ./

prox2.vercel.app
prox2-git-master-anirudhb1.vercel.app
prox2-anirudhb1.vercel.app

Please sign in to comment.