Add account based multiplayer hosting and bug report retention

This commit is contained in:
2026-10-10 16:24:34 +05:00
parent 9af71c85c2
commit fc6da6756d
33 changed files with 1538 additions and 102 deletions

View File

@@ -3,6 +3,7 @@ import { z } from "zod";
import { admin, required } from "@/lib/supabase";
import { verifySupportWebhook } from "@/lib/support-signature";
import { supportCommand } from "@/shared/bug-reports";
import { reconcileBugStatus, scheduleBugCleanup } from "@/lib/bug-lifecycle";
export const runtime = "nodejs";
export async function POST(request: NextRequest) {
@@ -59,6 +60,17 @@ export async function POST(request: NextRequest) {
.safeParse(decoded);
if (!payload.success) return new NextResponse(null, { status: 400 });
const event = payload.data;
if (event.type === "Issue" && ["create", "update"].includes(event.action)) {
try {
await reconcileBugStatus(event.data.id, true);
return NextResponse.json({ ok: true });
} catch {
return NextResponse.json(
{ error: "Support status delivery failed" },
{ status: 503 },
);
}
}
// Only explicit new staff comments are public. Internal comments and user echoes stay private.
if (
event.action !== "create" ||
@@ -71,6 +83,16 @@ export async function POST(request: NextRequest) {
const command = supportCommand(event.data.body ?? "");
if (!command) return NextResponse.json({ ok: true });
try {
if (command.kind === "close") {
required(
await admin().rpc("receive_bug_close", {
p_report: event.data.issueId,
p_external: event.data.id,
}),
);
await scheduleBugCleanup(event.data.issueId);
return NextResponse.json({ ok: true });
}
required(
await admin().rpc("receive_bug_reply", {
p_report: event.data.issueId,

View File

@@ -2,6 +2,7 @@ import { getI18n } from "@/lib/i18n";
import { Header, Footer } from "@/components/Shell";
import { DraftEditor } from "@/components/DraftEditor";
import { user } from "@/lib/supabase";
import { accountProfile } from "@/lib/profile";
import { redirect } from "next/navigation";
export default async function Draft({
params,
@@ -10,15 +11,17 @@ export default async function Draft({
}) {
const { t } = await getI18n();
const { id } = await params;
if (!(await user()))
const account = await user();
if (!account)
redirect(`/log-in?next=${encodeURIComponent("/dashboard/" + id)}`);
const profile = await accountProfile(account);
return (
<>
<Header />
<main className="section page-content">
<span className="eyebrow">{t("YOUR WORLD · YOUR LOCATIONS")}</span>
<h1>{t("Map workshop")}</h1>
<DraftEditor id={id} />
<DraftEditor id={id} hostName={profile.display_name} />
</main>
<Footer />
</>

View File

@@ -8,6 +8,7 @@ import { getMap } from "@/lib/catalog";
import { ContributionInstructions } from "@/components/ContributionInstructions";
import { ReportContent } from "@/components/ReportContent";
import { user } from "@/lib/supabase";
import { accountProfile } from "@/lib/profile";
import { ExportMap } from "@/components/MapTransfer";
export default async function ServerPage({
params,
@@ -19,6 +20,7 @@ export default async function ServerPage({
const map = await getMap(id);
if (!map) notFound();
const account = await user();
const profile = account ? await accountProfile(account) : null;
return (
<>
<Header />
@@ -63,7 +65,7 @@ export default async function ServerPage({
</span>
</div>
</div>
<StartGame datasetId={id} />
<StartGame datasetId={id} hostName={profile?.display_name ?? null} />
</div>
{map.allow_contributions && (
<ContributionInstructions