เพิ่มกลุ่ม API docx template สำหรับ wordaddin (WIP): - POST /api/template/extract ดึงค่า Content Control ทั้งหมดจาก .docx - POST /api/template/render แทนค่า JSON ลง template คืน .docx ใหม่ - GET /api/template/test ตรวจว่า service มีชีวิต logic แชร์ที่ app/api/template/lib-tmpl.ts (pizzip+xpath) ไม่แตะ DB เพิ่มหน้า Swagger UI ที่ GET /api/swagger — spec inline จาก lib/openapi.ts ครอบ API ทุกกลุ่ม (template + N10), asset self-host ที่ public/note/swagger-ui/ จาก postinstall scripts/copy-swagger-ui.mjs (intranet ไม่ใช้ CDN — หาไฟล์ไม่เจอหลังอัปเกรด = exit 1 เหมือน patch-pdf-worker, Docker build รัน script นี้ด้วยผ่าน web.Dockerfile) middleware เปิดกว้างให้ api/template, api/swagger, note/swagger-ui จาก code review: จำกัดไฟล์แนบ 100MB ทั้ง extract/render ก่อนอ่าน เข้าหน่วยความจำกัน DoS, คืน 400 แทน 500 เมื่อ JSON ผิด format, sync คำอธิบาย BadRequest ใน openapi spec ให้ตรง behavior ใหม่ Co-Authored-By: Claude Code <noreply@anthropic.com>
75 lines
No EOL
1.9 KiB
TypeScript
75 lines
No EOL
1.9 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { extractContentControls } from "../lib-tmpl";
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
const DOCX_CONTENT_TYPE =
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
|
|
// cap เดียวกับ N4 (app/actions/files.ts) — route นี้เปิดกว้างให้ภายนอกยิงได้
|
|
// ต้องเช็คขนาดก่อนอ่านเข้าหน่วยความจำ กัน DoS (bodySizeLimit ครอบเฉพาะ Server Actions)
|
|
const MAX_UPLOAD_BYTES = 100 * 1024 * 1024; // 100MB
|
|
|
|
export async function POST(request: Request) {
|
|
try {
|
|
const formData = await request.formData();
|
|
const file = formData.get("file");
|
|
|
|
if (!(file instanceof File)) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: 'Missing DOCX file in field "file".',
|
|
},
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
if (
|
|
file.type !== DOCX_CONTENT_TYPE &&
|
|
!file.name.toLowerCase().endsWith(".docx")
|
|
) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: 'Field "file" must be a .docx file.',
|
|
},
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
if (file.size > MAX_UPLOAD_BYTES) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: 'Field "file" exceeds the 100MB size limit.',
|
|
},
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
// File → Buffer
|
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
|
|
// ใช้ lib-tmpl.ts เดิม
|
|
const data = extractContentControls(buffer);
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
data,
|
|
});
|
|
} catch (error) {
|
|
console.error(error);
|
|
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error:
|
|
error instanceof Error
|
|
? error.message
|
|
: "Internal Server Error",
|
|
},
|
|
{ status: 500 },
|
|
);
|
|
}
|
|
} |