Add Discord review threads and a Resend reply loop for submitted hacks (#76)
Some checks are pending
Deploy Supabase Migrations to Production / migrate (push) Waiting to run

* Add a Discord review thread and Resend reply loop for submitted hacks.

Admins can email submitters from a forum thread and inbound replies land back in that same thread.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add an admin endpoint to register Discord guild commands.

Local still uses the npm script; production can hit /api/discord/register while logged in as an admin.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add an admin backup to create a missing Discord review thread.

If submit fails to open a thread, an admin can create one from the hack details menu.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Match inbound review replies when the plus-address token is lowercased.

Mail delivers To in lowercase, so tokens are now hex and lookups are case-insensitive.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Use distinct review embeds for /reply and inbound creator mail.

/reply posts a green embed with subject, Discord avatar, and the creator username; thread replies drop the To field.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Gate /reply by Discord role and mark inbound From as verified.

DISCORD_REPLY_ROLE_IDS is required; creator mail still posts when the address does not match the account.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Retry inbound review mail when Discord does not post the embed.

A failed thread post no longer records the email as processed or returns 200 to Resend.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Notify the admin webhook when a review thread cannot be loaded.

Patch upload no longer stays silent if getHackReviewThread throws.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Keep the /reply ack honest after the review email is sent.

A later Discord or deferred-response failure no longer claims the email failed.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Make the admin review message stand out in the reply email.

The quote sits in a rose-tinted box so it is not just another paragraph.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Tag review threads as claimed or unclaimed and announce claims.

New and backup-created threads get the matching forum tag; dashboard claims swap Unclaimed to Claimed.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jared Schoeny
2026-08-22 22:07:33 -06:00
committed by GitHub
parent d07230a0c4
commit e0747efb82
19 changed files with 1411 additions and 46 deletions

View File

@@ -0,0 +1,33 @@
import { discordGuildCommands } from "../src/utils/discord-commands.mjs";
const requiredEnvironment = [
"DISCORD_APPLICATION_ID",
"DISCORD_GUILD_ID",
"DISCORD_BOT_TOKEN",
];
const missingEnvironment = requiredEnvironment.filter((name) => !process.env[name]);
if (missingEnvironment.length > 0) {
console.error(`Missing Discord environment: ${missingEnvironment.join(", ")}`);
process.exit(1);
}
const response = await fetch(
`https://discord.com/api/v10/applications/${process.env.DISCORD_APPLICATION_ID}/guilds/${process.env.DISCORD_GUILD_ID}/commands`,
{
method: "PUT",
headers: {
Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(discordGuildCommands),
},
);
if (!response.ok) {
console.error(`Discord command registration failed (${response.status}): ${await response.text()}`);
process.exit(1);
}
const registered = await response.json();
console.log(`Registered ${registered.length} guild command(s).`);