feat:update form
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
import { db } from "@/db";
|
||||
import { unlink } from "fs/promises";
|
||||
import path from "path";
|
||||
import { questions } from "@/db/schema";
|
||||
import type { QuestionType } from "@/db/schema";
|
||||
import { cdn, questions } from "@/db/schema";
|
||||
import type { ImageAnswerMode, QuestionType } from "@/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { requireAdmin } from "@/lib/auth";
|
||||
@@ -55,6 +55,7 @@ export async function updateQuestion(
|
||||
options: string[];
|
||||
imageUrl: string | null;
|
||||
allowOther: boolean;
|
||||
imageAnswerMode: ImageAnswerMode;
|
||||
}>
|
||||
) {
|
||||
await requireAdmin();
|
||||
@@ -91,6 +92,7 @@ export async function bulkUpdateQuestions(
|
||||
displayOrder: number;
|
||||
options: string[];
|
||||
allowOther: boolean;
|
||||
imageAnswerMode: ImageAnswerMode;
|
||||
}[]
|
||||
) {
|
||||
await requireAdmin();
|
||||
@@ -107,6 +109,7 @@ export async function bulkUpdateQuestions(
|
||||
displayOrder: u.displayOrder,
|
||||
options: u.options ?? [],
|
||||
allowOther: u.allowOther,
|
||||
imageAnswerMode: u.imageAnswerMode,
|
||||
})
|
||||
.where(eq(questions.id, u.id))
|
||||
)
|
||||
@@ -123,6 +126,14 @@ export async function bulkUpdateQuestions(
|
||||
|
||||
async function deleteImageFile(imageUrl: string | null) {
|
||||
if (!imageUrl) return;
|
||||
if (imageUrl.startsWith("/cdn/")) {
|
||||
const id = imageUrl.split("/").pop();
|
||||
if (id) {
|
||||
await db.delete(cdn).where(eq(cdn.id, id));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const filename = imageUrl.split("/").pop();
|
||||
if (filename) {
|
||||
|
||||
+71
-18
@@ -8,13 +8,17 @@ import { getServerSession } from "next-auth";
|
||||
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 { normalizeSubmissionAnswers } from "@/lib/submission-intake";
|
||||
import type { FormAnswerPayload } from "@/lib/form-answer-values";
|
||||
import {
|
||||
normalizeSubmissionAnswers,
|
||||
type StoredAnswerSnapshot,
|
||||
} from "@/lib/submission-intake";
|
||||
import { submissionWebhookMessage } from "@/lib/submission-webhook";
|
||||
|
||||
export async function submitForm(
|
||||
formId: string,
|
||||
answersList: { questionId: string; value: FormAnswerValue }[]
|
||||
answersList: FormAnswerPayload[],
|
||||
targetSubmissionId?: string | null
|
||||
) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user) throw new Error("Not authenticated");
|
||||
@@ -33,17 +37,49 @@ export async function submitForm(
|
||||
}
|
||||
|
||||
const normalizedAnswers = normalizeSubmissionAnswers(questionsList, answersList);
|
||||
const imageCdnIds = [
|
||||
...new Set(normalizedAnswers.map((answer) => answer.imageCdnId).filter(Boolean)),
|
||||
] as string[];
|
||||
|
||||
if (imageCdnIds.length > 0) {
|
||||
const ownedImages = await db.query.cdn.findMany({
|
||||
where: (record, { and, eq, inArray }) =>
|
||||
and(
|
||||
inArray(record.id, imageCdnIds),
|
||||
eq(record.ownerDiscordId, discordId)
|
||||
),
|
||||
columns: { id: true },
|
||||
});
|
||||
if (ownedImages.length !== imageCdnIds.length) {
|
||||
throw new Error("ข้อมูลรูปภาพไม่ถูกต้อง");
|
||||
}
|
||||
}
|
||||
|
||||
const result = await db.transaction(async (tx) => {
|
||||
const existingSubmission = await tx.query.submissions.findFirst({
|
||||
where: (submission, { eq, and }) =>
|
||||
and(eq(submission.formId, formId), eq(submission.userDiscordId, discordId)),
|
||||
});
|
||||
const existingSubmission = form.allowMultipleSubmissions
|
||||
? targetSubmissionId
|
||||
? await tx.query.submissions.findFirst({
|
||||
where: (submission, { eq, and }) =>
|
||||
and(
|
||||
eq(submission.id, targetSubmissionId),
|
||||
eq(submission.formId, formId),
|
||||
eq(submission.userDiscordId, discordId)
|
||||
),
|
||||
})
|
||||
: null
|
||||
: await tx.query.submissions.findFirst({
|
||||
where: (submission, { eq, and }) =>
|
||||
and(eq(submission.formId, formId), eq(submission.userDiscordId, discordId)),
|
||||
});
|
||||
|
||||
if (form.allowMultipleSubmissions && targetSubmissionId && !existingSubmission) {
|
||||
throw new Error("ไม่พบคำตอบที่ต้องการแก้ไข");
|
||||
}
|
||||
|
||||
let submissionId = "";
|
||||
let submittedAt = new Date();
|
||||
const isUpdate = Boolean(existingSubmission);
|
||||
let oldAnswersDict: Record<string, string> = {};
|
||||
let oldAnswersDict: Record<string, StoredAnswerSnapshot> = {};
|
||||
|
||||
if (existingSubmission) {
|
||||
submissionId = existingSubmission.id;
|
||||
@@ -53,8 +89,11 @@ export async function submitForm(
|
||||
where: (answer, { eq }) => eq(answer.submissionId, submissionId),
|
||||
});
|
||||
|
||||
oldAnswersDict = oldAnswersList.reduce<Record<string, string>>((acc, curr) => {
|
||||
acc[curr.questionId] = curr.value;
|
||||
oldAnswersDict = oldAnswersList.reduce<Record<string, StoredAnswerSnapshot>>((acc, curr) => {
|
||||
acc[curr.questionId] = {
|
||||
value: curr.value,
|
||||
imageCdnId: curr.imageCdnId ?? null,
|
||||
};
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
@@ -91,6 +130,7 @@ export async function submitForm(
|
||||
submissionId,
|
||||
questionId: answer.questionId,
|
||||
value: answer.value,
|
||||
imageCdnId: answer.imageCdnId,
|
||||
}))
|
||||
);
|
||||
}
|
||||
@@ -207,19 +247,32 @@ export async function deleteAllSubmissions(formId: string) {
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
export async function deleteOwnSubmission(formId: string) {
|
||||
export async function deleteOwnSubmission(formId: string, submissionId?: string | null) {
|
||||
const discordId = await requireDiscordId();
|
||||
|
||||
const { and } = await import("drizzle-orm");
|
||||
const form = await requireFormAccess(formId, discordId);
|
||||
if (form.allowMultipleSubmissions && !submissionId) {
|
||||
throw new Error("ไม่พบคำตอบที่ต้องการลบ");
|
||||
}
|
||||
|
||||
await db.delete(submissions).where(
|
||||
and(
|
||||
eq(submissions.formId, formId),
|
||||
eq(submissions.userDiscordId, discordId)
|
||||
)
|
||||
);
|
||||
const where = form.allowMultipleSubmissions
|
||||
? and(
|
||||
eq(submissions.id, submissionId!),
|
||||
eq(submissions.formId, formId),
|
||||
eq(submissions.userDiscordId, discordId)
|
||||
)
|
||||
: and(
|
||||
eq(submissions.formId, formId),
|
||||
eq(submissions.userDiscordId, discordId)
|
||||
);
|
||||
|
||||
const deleted = await db.delete(submissions).where(where).returning({ id: submissions.id });
|
||||
if (form.allowMultipleSubmissions && deleted.length === 0) {
|
||||
throw new Error("ไม่พบคำตอบที่ต้องการลบ");
|
||||
}
|
||||
void sse.submissions.pub("update", {
|
||||
formId,
|
||||
submissionId: submissionId ?? undefined,
|
||||
action: "deleted",
|
||||
});
|
||||
revalidatePath(`/form`);
|
||||
|
||||
Reference in New Issue
Block a user