eCourt-Doc-Edit/addin/src/services/versioningService.ts

103 lines
4.1 KiB
TypeScript
Raw Normal View History

2026-08-19 21:35:07 +07:00
import { config } from "../config";
import { UploadVersionResult, VersionRecord } from "../models/versionRecord";
import { apiFetch, apiGetJson, apiSendExpectJson, ApiError, readErrorMessage } from "./apiClient";
import { generateGuid } from "./metadataService";
/**
* เรียก version API ของ backend (FR-5/6/7 ฝั่ง client)
* `fields` = map จาก `readContentControlFields()` ตาม FR-11
*/
/** FR-5 — อัปโหลดไฟล์ปัจจุบันเป็น version ใหม่ (แนบ fields map ถ้ามี)
* + FR-13: แนบ commit message ทางเลือกของผู้ใช้
* + FR-16: แนบ templateId เฉพาะตอน Start Versioning ของไฟล์ร่าง (backend ใช้ตอน auto-create Document) */
2026-08-19 21:35:07 +07:00
export async function uploadVersion(
documentId: string,
file: Blob,
clientVersionId: string,
fields?: Record<string, string>,
fileName?: string,
Phase 11: version PDF (FR-15) - เลข version ใหม่: เว็บ-generate = v0 ฉบับตั้งต้น (ไม่มี PDF), add-in save (Start Versioning + Save & Version) = v1+ มี PDF เสมอ - PDF ผลิตจาก Word จริงผ่าน task pane เท่านั้น (getFileAsync Pdf + runtime guard, manifest ไม่เพิ่ม requirement); capture/upload เป็น best-effort — docx ผ่านแม้ PDF ล้ม + MessageBar เตือนตาม hasPdf - Backend: DocumentVersion.PdfObjectKey (nullable, migration AddVersionPdf) + sibling .pdf ใน bucket docx-versions · multipart part pdf (ผิด type → 400) · /download + /download-link รับ ?format=pdf (ไม่มี → 404) · presigned ฝังชื่อไฟล์ไทย + _vN (RFC 5987) - Web: เปิดไฟล์แทน blob-download — PDF แท็บใหม่, docx ผ่าน ms-word:ofe|u| พร้อม heuristic fallback ลิงก์สำรอง (useVersionOpen, versionDownload) · ปุ่ม "เปิดใน Word" ที่หน้า success ของฟอร์มสร้างเอกสาร - Spec v7 + CONTEXT.md + ADR 0001 + แผน docs/plans/version-pdf.md - Automated QA: backend 68 / add-in 63 / web 55 ผ่าน · manual acceptance ผ่านบน Word for Mac (2026-09-08) รวม fidelity + track changes — ค้างเฉพาะ Windows / Word on the web Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-08 14:01:13 +07:00
message?: string,
pdf?: Blob,
templateId?: string
2026-08-19 21:35:07 +07:00
): Promise<UploadVersionResult> {
const form = new FormData();
form.append("file", file, fileName || `${documentId}.docx`);
form.append("clientVersionId", clientVersionId);
Phase 11: version PDF (FR-15) - เลข version ใหม่: เว็บ-generate = v0 ฉบับตั้งต้น (ไม่มี PDF), add-in save (Start Versioning + Save & Version) = v1+ มี PDF เสมอ - PDF ผลิตจาก Word จริงผ่าน task pane เท่านั้น (getFileAsync Pdf + runtime guard, manifest ไม่เพิ่ม requirement); capture/upload เป็น best-effort — docx ผ่านแม้ PDF ล้ม + MessageBar เตือนตาม hasPdf - Backend: DocumentVersion.PdfObjectKey (nullable, migration AddVersionPdf) + sibling .pdf ใน bucket docx-versions · multipart part pdf (ผิด type → 400) · /download + /download-link รับ ?format=pdf (ไม่มี → 404) · presigned ฝังชื่อไฟล์ไทย + _vN (RFC 5987) - Web: เปิดไฟล์แทน blob-download — PDF แท็บใหม่, docx ผ่าน ms-word:ofe|u| พร้อม heuristic fallback ลิงก์สำรอง (useVersionOpen, versionDownload) · ปุ่ม "เปิดใน Word" ที่หน้า success ของฟอร์มสร้างเอกสาร - Spec v7 + CONTEXT.md + ADR 0001 + แผน docs/plans/version-pdf.md - Automated QA: backend 68 / add-in 63 / web 55 ผ่าน · manual acceptance ผ่านบน Word for Mac (2026-09-08) รวม fidelity + track changes — ค้างเฉพาะ Windows / Word on the web Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-08 14:01:13 +07:00
if (pdf) form.append("pdf", pdf, `${documentId}.pdf`);
2026-08-19 21:35:07 +07:00
if (fields && Object.keys(fields).length > 0) {
form.append("fields", JSON.stringify(fields));
}
const trimmedMessage = message?.trim();
if (trimmedMessage) {
form.append("message", trimmedMessage);
}
if (templateId) {
form.append("templateId", templateId);
}
2026-08-19 21:35:07 +07:00
return apiSendExpectJson<UploadVersionResult>(
`/api/documents/${documentId}/versions`,
{ method: "POST", body: form },
"อัปโหลด version ไม่สำเร็จ"
);
}
/** FR-6 — version history เรียงใหม่ → เก่า */
export async function getVersions(documentId: string): Promise<VersionRecord[]> {
return apiGetJson<VersionRecord[]>(
`/api/documents/${documentId}/versions`,
"โหลด version history ไม่สำเร็จ"
);
}
/** FR-7 — URL ของ download endpoint (ผ่าน backend proxy เท่านั้น — MinIO ไม่ถูก expose) */
Phase 11: version PDF (FR-15) - เลข version ใหม่: เว็บ-generate = v0 ฉบับตั้งต้น (ไม่มี PDF), add-in save (Start Versioning + Save & Version) = v1+ มี PDF เสมอ - PDF ผลิตจาก Word จริงผ่าน task pane เท่านั้น (getFileAsync Pdf + runtime guard, manifest ไม่เพิ่ม requirement); capture/upload เป็น best-effort — docx ผ่านแม้ PDF ล้ม + MessageBar เตือนตาม hasPdf - Backend: DocumentVersion.PdfObjectKey (nullable, migration AddVersionPdf) + sibling .pdf ใน bucket docx-versions · multipart part pdf (ผิด type → 400) · /download + /download-link รับ ?format=pdf (ไม่มี → 404) · presigned ฝังชื่อไฟล์ไทย + _vN (RFC 5987) - Web: เปิดไฟล์แทน blob-download — PDF แท็บใหม่, docx ผ่าน ms-word:ofe|u| พร้อม heuristic fallback ลิงก์สำรอง (useVersionOpen, versionDownload) · ปุ่ม "เปิดใน Word" ที่หน้า success ของฟอร์มสร้างเอกสาร - Spec v7 + CONTEXT.md + ADR 0001 + แผน docs/plans/version-pdf.md - Automated QA: backend 68 / add-in 63 / web 55 ผ่าน · manual acceptance ผ่านบน Word for Mac (2026-09-08) รวม fidelity + track changes — ค้างเฉพาะ Windows / Word on the web Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-08 14:01:13 +07:00
export function buildDownloadUrl(
documentId: string,
versionId: string,
format?: "docx" | "pdf"
): string {
return `${config.apiBaseUrl}/api/documents/${documentId}/versions/${versionId}/download${format === "pdf" ? "?format=pdf" : ""}`;
2026-08-19 21:35:07 +07:00
}
2026-08-19 23:06:57 +07:00
export interface VersionDownloadLink {
url: string;
/** ISO-8601 เวลาที่ URL หมดอายุ */
expiresAt: string;
}
/**
* FR-7 — ขอ presigned URL อายุสั้นของ version หนึ่ง เพื่อเปิดในเบราว์เซอร์ของผู้ใช้
* (webview ของ Word ทิ้ง blob download เงียบๆ — ให้เบราว์เซอร์จริงจัดการแทน)
*/
export async function getDownloadLink(
documentId: string,
Phase 11: version PDF (FR-15) - เลข version ใหม่: เว็บ-generate = v0 ฉบับตั้งต้น (ไม่มี PDF), add-in save (Start Versioning + Save & Version) = v1+ มี PDF เสมอ - PDF ผลิตจาก Word จริงผ่าน task pane เท่านั้น (getFileAsync Pdf + runtime guard, manifest ไม่เพิ่ม requirement); capture/upload เป็น best-effort — docx ผ่านแม้ PDF ล้ม + MessageBar เตือนตาม hasPdf - Backend: DocumentVersion.PdfObjectKey (nullable, migration AddVersionPdf) + sibling .pdf ใน bucket docx-versions · multipart part pdf (ผิด type → 400) · /download + /download-link รับ ?format=pdf (ไม่มี → 404) · presigned ฝังชื่อไฟล์ไทย + _vN (RFC 5987) - Web: เปิดไฟล์แทน blob-download — PDF แท็บใหม่, docx ผ่าน ms-word:ofe|u| พร้อม heuristic fallback ลิงก์สำรอง (useVersionOpen, versionDownload) · ปุ่ม "เปิดใน Word" ที่หน้า success ของฟอร์มสร้างเอกสาร - Spec v7 + CONTEXT.md + ADR 0001 + แผน docs/plans/version-pdf.md - Automated QA: backend 68 / add-in 63 / web 55 ผ่าน · manual acceptance ผ่านบน Word for Mac (2026-09-08) รวม fidelity + track changes — ค้างเฉพาะ Windows / Word on the web Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-08 14:01:13 +07:00
versionId: string,
format?: "docx" | "pdf"
2026-08-19 23:06:57 +07:00
): Promise<VersionDownloadLink> {
return apiGetJson<VersionDownloadLink>(
Phase 11: version PDF (FR-15) - เลข version ใหม่: เว็บ-generate = v0 ฉบับตั้งต้น (ไม่มี PDF), add-in save (Start Versioning + Save & Version) = v1+ มี PDF เสมอ - PDF ผลิตจาก Word จริงผ่าน task pane เท่านั้น (getFileAsync Pdf + runtime guard, manifest ไม่เพิ่ม requirement); capture/upload เป็น best-effort — docx ผ่านแม้ PDF ล้ม + MessageBar เตือนตาม hasPdf - Backend: DocumentVersion.PdfObjectKey (nullable, migration AddVersionPdf) + sibling .pdf ใน bucket docx-versions · multipart part pdf (ผิด type → 400) · /download + /download-link รับ ?format=pdf (ไม่มี → 404) · presigned ฝังชื่อไฟล์ไทย + _vN (RFC 5987) - Web: เปิดไฟล์แทน blob-download — PDF แท็บใหม่, docx ผ่าน ms-word:ofe|u| พร้อม heuristic fallback ลิงก์สำรอง (useVersionOpen, versionDownload) · ปุ่ม "เปิดใน Word" ที่หน้า success ของฟอร์มสร้างเอกสาร - Spec v7 + CONTEXT.md + ADR 0001 + แผน docs/plans/version-pdf.md - Automated QA: backend 68 / add-in 63 / web 55 ผ่าน · manual acceptance ผ่านบน Word for Mac (2026-09-08) รวม fidelity + track changes — ค้างเฉพาะ Windows / Word on the web Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-08 14:01:13 +07:00
`/api/documents/${documentId}/versions/${versionId}/download-link${format === "pdf" ? "?format=pdf" : ""}`,
2026-08-19 23:06:57 +07:00
"ขอลิงก์ดาวน์โหลดไม่สำเร็จ"
);
}
2026-08-19 21:35:07 +07:00
/** FR-7 — ดาวน์โหลดไฟล์ของ version หนึ่งเป็น Blob (ต้องแนบ Bearer จึงต้อง fetch แทน link ตรง) */
Phase 11: version PDF (FR-15) - เลข version ใหม่: เว็บ-generate = v0 ฉบับตั้งต้น (ไม่มี PDF), add-in save (Start Versioning + Save & Version) = v1+ มี PDF เสมอ - PDF ผลิตจาก Word จริงผ่าน task pane เท่านั้น (getFileAsync Pdf + runtime guard, manifest ไม่เพิ่ม requirement); capture/upload เป็น best-effort — docx ผ่านแม้ PDF ล้ม + MessageBar เตือนตาม hasPdf - Backend: DocumentVersion.PdfObjectKey (nullable, migration AddVersionPdf) + sibling .pdf ใน bucket docx-versions · multipart part pdf (ผิด type → 400) · /download + /download-link รับ ?format=pdf (ไม่มี → 404) · presigned ฝังชื่อไฟล์ไทย + _vN (RFC 5987) - Web: เปิดไฟล์แทน blob-download — PDF แท็บใหม่, docx ผ่าน ms-word:ofe|u| พร้อม heuristic fallback ลิงก์สำรอง (useVersionOpen, versionDownload) · ปุ่ม "เปิดใน Word" ที่หน้า success ของฟอร์มสร้างเอกสาร - Spec v7 + CONTEXT.md + ADR 0001 + แผน docs/plans/version-pdf.md - Automated QA: backend 68 / add-in 63 / web 55 ผ่าน · manual acceptance ผ่านบน Word for Mac (2026-09-08) รวม fidelity + track changes — ค้างเฉพาะ Windows / Word on the web Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-08 14:01:13 +07:00
export async function downloadVersion(
documentId: string,
versionId: string,
format?: "docx" | "pdf"
): Promise<Blob> {
const response = await apiFetch(buildDownloadUrl(documentId, versionId, format));
2026-08-19 21:35:07 +07:00
if (!response.ok) {
throw new ApiError(
response.status,
await readErrorMessage(response, `ดาวน์โหลด version ไม่สำเร็จ (${response.status})`)
);
}
return response.blob();
}
/** สร้าง clientVersionId ใหม่สำหรับ upload ครั้งถัดไป */
export function newClientVersionId(): string {
return generateGuid();
}