diff --git a/Dockerfile b/Dockerfile index 8ec11da..896ecb5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,13 @@ +# syntax=docker/dockerfile:1 + # Stage 1: Install dependencies FROM oven/bun:alpine AS deps WORKDIR /app # Copy only package files to leverage Docker layer caching COPY package.json bun.lock ./ # Install dependencies -RUN bun install --frozen-lockfile +RUN --mount=type=cache,target=/root/.bun/install/cache \ + bun install --frozen-lockfile # Stage 2: Build the application FROM oven/bun:alpine AS builder @@ -12,7 +15,8 @@ WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . # Build Next.js -RUN bun run build +RUN --mount=type=cache,target=/app/.next/cache \ + bun run build # Stage 3: Production runner FROM oven/bun:alpine AS runner @@ -27,4 +31,4 @@ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/package.json ./package.json EXPOSE 3000 -CMD ["bun", "start"] \ No newline at end of file +CMD ["bun", "start"] diff --git a/app/actions/submissions.ts b/app/actions/submissions.ts index ccd1dd7..9f52889 100644 --- a/app/actions/submissions.ts +++ b/app/actions/submissions.ts @@ -9,11 +9,8 @@ import { authOptions } from "@/lib/auth-options"; import { requireAdmin, requireDiscordId, requireFormAccess } from "@/lib/auth"; import { sse } from "@/lib/sse"; import type { FormAnswerValue } from "@/lib/form-answer-values"; -import { - answersByTemplateIndex, - normalizeSubmissionAnswers, - submissionUpdateText, -} from "@/lib/submission-intake"; +import { normalizeSubmissionAnswers } from "@/lib/submission-intake"; +import { submissionWebhookMessage } from "@/lib/submission-webhook"; export async function submitForm( formId: string, @@ -132,30 +129,19 @@ export async function submitForm( ? form.discordWebhookUpdateTemplate : form.discordWebhookTemplate; - if (form.discordWebhookUrl && templateToUse) { + if (form.discordWebhookUrl) { try { - const answersDict = answersByTemplateIndex(questionsList, normalizedAnswers); - const updatesText = result.isUpdate - ? submissionUpdateText(questionsList, normalizedAnswers, result.oldAnswersDict) - : ""; - - let message = templateToUse; - // Replace {1}, {2}, etc. with value, and new variables - message = message.replace(/\{([^}]+)\}/g, (match: string, p1: string) => { - const key = p1.toLowerCase(); - if (key === "username" || key === "displayname") { - return session.user?.name || "Unknown User"; - } - if (key === "id") { - return discordId || "Unknown ID"; - } - if (key === "update") { - return updatesText; - } - return answersDict[p1] || "Not Provided"; + const message = submissionWebhookMessage({ + template: templateToUse, + isUpdate: result.isUpdate, + userName: session.user.name, + discordId, + questions: questionsList, + answers: normalizedAnswers, + oldAnswersByQuestionId: result.oldAnswersDict, }); - await fetch(form.discordWebhookUrl, { + const response = await fetch(form.discordWebhookUrl, { method: "POST", headers: { "Content-Type": "application/json", @@ -164,6 +150,14 @@ export async function submitForm( content: message, }), }); + if (!response.ok) { + const responseBody = await response.text(); + console.error("Discord webhook rejected submission notification", { + status: response.status, + statusText: response.statusText, + response: responseBody.slice(0, 500), + }); + } } catch (e) { console.error("Failed to send webhook", e); } diff --git a/app/admin/form/[id]/client.tsx b/app/admin/form/[id]/client.tsx index 943b9cd..300b481 100644 --- a/app/admin/form/[id]/client.tsx +++ b/app/admin/form/[id]/client.tsx @@ -473,7 +473,7 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC -