-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add undo ability for reviewers (#88)
- Loading branch information
Showing
10 changed files
with
1,232 additions
and
878 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,3 +43,5 @@ secrets.json | |
*.jsx.map | ||
*.js | ||
*.js.map | ||
|
||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
Oops, something went wrong.
74e4041
There was a problem hiding this comment.
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