- Removed the `fields` parameter from the version upload form, as it is now extracted from the uploaded .docx file using the `extractContentControls` function. - Updated related types and interfaces to reflect the new structure of version fields. - Modified the OpenAPI specification to document the changes in the versioning process. - Adjusted tests to ensure compliance with the new behavior, including validation for the absence of the `fields` parameter. - Implemented a new function `extractDocumentSnapshot` to handle the extraction of content controls and document properties from .docx files. - Updated metadata and versioning services to align with the new extraction logic.
91 lines
4.3 KiB
TypeScript
91 lines
4.3 KiB
TypeScript
/**
|
|
* Type ตรงกับ response ของ backend (`Models/VersionDtos.cs` — ASP.NET Core serialize camelCase)
|
|
* พอร์ตดิบจาก D:\word-addin-poc\addin\src\models\versionRecord.ts
|
|
*/
|
|
|
|
/** response ของ POST /api/documents/{documentId}/versions */
|
|
export interface UploadVersionResult {
|
|
hasPdf: boolean;
|
|
versionId: string;
|
|
versionNumber: number;
|
|
}
|
|
|
|
/** field เดียวใน snapshot ของ version (เอกสารที่ผูก template) */
|
|
export interface FieldSnapshotEntry {
|
|
value: string;
|
|
missing: boolean;
|
|
}
|
|
|
|
/** fields ของ version รูปแบบปัจจุบัน — **ก้อนเดียวกับ return ของ `/api/template/extract`**
|
|
* ที่ server แกะจากไฟล์ .docx ฝั่ง server ตอนอัปโหลด (2026-10-30) · ค่าวันที่ใน
|
|
* properties มาเป็น ISO string ตาม DTO ของกลุ่ม docver */
|
|
export interface ExtractSnapshotFields {
|
|
/** ค่า Content Control `{ [tag]: text }` */
|
|
cc: Record<string, string>;
|
|
/** ข้อความใน bookmark `{ [name]: text }` */
|
|
bookmark: Record<string, string>;
|
|
/** document properties (standard/extended/custom) */
|
|
properties: {
|
|
standard?: Record<string, string | undefined>;
|
|
extended?: Record<string, number | string | undefined>;
|
|
custom?: Record<string, string | number | boolean | null>;
|
|
};
|
|
/** ผลตรวจ ticket ที่ stamp มากับไฟล์ (exp + HmacSha256 ด้วย secret ฝั่ง server) */
|
|
verify: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* snapshot fields ต่อ version — backend เก็บ 3 รูปแบบ:
|
|
* - ปัจจุบัน (2026-10-30): ก้อน extract snapshot `{cc, bookmark, properties, verify}`
|
|
* เหมือน return ของ /api/template/extract (server แกะจากไฟล์เอง)
|
|
* - เอกสารผูก template: `{ [fieldKey]: { value, missing } }`
|
|
* - เอกสารไม่ผูก template (track เองจาก add-in): map ดิบ `{ [tag]: text }`
|
|
* UI ต้อง handle ได้ทั้งหมด (ใช้ readSnapshotField ช่วยอ่าน)
|
|
*/
|
|
export type FieldsSnapshot =
|
|
| ExtractSnapshotFields
|
|
| Record<string, FieldSnapshotEntry>
|
|
| Record<string, string>;
|
|
|
|
/** item ของ GET /api/documents/{documentId}/versions */
|
|
export interface VersionRecord {
|
|
hasPdf?: boolean;
|
|
versionId: string;
|
|
versionNumber: number;
|
|
/** ISO-8601 */
|
|
createdAt: string;
|
|
createdByUserId: string;
|
|
/** ชื่อผู้สร้าง — ส่วนเสริมของ DTO กลุ่ม docver (mock/demo อาจไม่มี → UI fallback เป็น userId) */
|
|
createdByUserName?: string;
|
|
/** SHA256 hex */
|
|
contentHash: string;
|
|
fields: FieldsSnapshot | null;
|
|
/** คำอธิบาย version แบบ commit message ที่ผู้ใช้พิมพ์ตอนสร้าง (FR-13) — null ได้ */
|
|
message: string | null;
|
|
}
|
|
|
|
/** อ่านค่า + สถานะ missing ของ field หนึ่งจาก snapshot ไม่ว่าจะเก็บรูปแบบไหน — ไม่มี field นี้คืน null
|
|
* รูปแบบ extract snapshot (2026-10-30) ค่า CC อยู่ใต้ `cc` — อ่านซ้ำเข้า map ดิบรอบเดียวกัน */
|
|
export function readSnapshotField(
|
|
snapshot: FieldsSnapshot | null,
|
|
key: string
|
|
): FieldSnapshotEntry | null {
|
|
if (!snapshot) {
|
|
return null;
|
|
}
|
|
// Record ธรรมดาไม่ถูก `in` ตัดออกจาก union (มี index signature ครอบทุก key) — เช็คแล้ว
|
|
// บอกชนิดตรง ๆ ว่าเป็นก้อน extract snapshot (key "cc" ชนกับ tag ชื่อเดียวกันยอมรับเป็น
|
|
// edge case ของการเดารูปจากข้อมูลเก่า)
|
|
if ("cc" in snapshot) {
|
|
const cc = (snapshot as ExtractSnapshotFields).cc;
|
|
return readSnapshotField(cc, key);
|
|
}
|
|
const raw = snapshot[key];
|
|
if (raw === undefined) {
|
|
return null;
|
|
}
|
|
if (typeof raw === "string") {
|
|
return { value: raw, missing: false };
|
|
}
|
|
return { value: raw.value, missing: raw.missing };
|
|
}
|