mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
feat: fieldMeta parsing
This commit is contained in:
@ -9,7 +9,7 @@ import { getEnvelopeWhereInput } from '@documenso/lib/server-only/envelope/get-e
|
|||||||
import { createEnvelopeFields } from '@documenso/lib/server-only/field/create-envelope-fields';
|
import { createEnvelopeFields } from '@documenso/lib/server-only/field/create-envelope-fields';
|
||||||
import { createDocumentRecipients } from '@documenso/lib/server-only/recipient/create-document-recipients';
|
import { createDocumentRecipients } from '@documenso/lib/server-only/recipient/create-document-recipients';
|
||||||
import { createTemplateRecipients } from '@documenso/lib/server-only/recipient/create-template-recipients';
|
import { createTemplateRecipients } from '@documenso/lib/server-only/recipient/create-template-recipients';
|
||||||
import type { TFieldAndMeta } from '@documenso/lib/types/field-meta';
|
import { type TFieldAndMeta, ZFieldAndMetaSchema } from '@documenso/lib/types/field-meta';
|
||||||
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||||
import type { EnvelopeIdOptions } from '@documenso/lib/utils/envelope';
|
import type { EnvelopeIdOptions } from '@documenso/lib/utils/envelope';
|
||||||
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
|
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
|
||||||
@ -33,14 +33,12 @@ type PlaceholderInfo = {
|
|||||||
placeholder: string;
|
placeholder: string;
|
||||||
fieldType: string;
|
fieldType: string;
|
||||||
recipient: string;
|
recipient: string;
|
||||||
isRequired: string;
|
fieldMeta: Record<string, string>;
|
||||||
page: number;
|
page: number;
|
||||||
// PDF2JSON coordinates (in page units - these are relative to page dimensions)
|
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
// Page dimensions from PDF2JSON (in page units)
|
|
||||||
pageWidth: number;
|
pageWidth: number;
|
||||||
pageHeight: number;
|
pageHeight: number;
|
||||||
};
|
};
|
||||||
@ -121,7 +119,9 @@ export const extractPlaceholdersFromPDF = async (pdf: Buffer): Promise<Placehold
|
|||||||
const placeholder = match[0];
|
const placeholder = match[0];
|
||||||
const placeholderData = match[1].split(',').map((part) => part.trim());
|
const placeholderData = match[1].split(',').map((part) => part.trim());
|
||||||
|
|
||||||
const [fieldType, recipient, isRequired] = placeholderData;
|
const [fieldType, recipient, ...fieldMetaData] = placeholderData;
|
||||||
|
|
||||||
|
const fieldMeta = Object.fromEntries(fieldMetaData.map((meta) => meta.split('=')));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find the position of where the placeholder starts in the text
|
Find the position of where the placeholder starts in the text
|
||||||
@ -157,7 +157,7 @@ export const extractPlaceholdersFromPDF = async (pdf: Buffer): Promise<Placehold
|
|||||||
placeholder,
|
placeholder,
|
||||||
fieldType,
|
fieldType,
|
||||||
recipient,
|
recipient,
|
||||||
isRequired,
|
fieldMeta,
|
||||||
page: pageIndex + 1,
|
page: pageIndex + 1,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
@ -272,6 +272,51 @@ const parseFieldType = (fieldTypeString: string): FieldType => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Transform raw field metadata from placeholder format to schema format.
|
||||||
|
Users should provide properly capitalized property names (e.g., readOnly, fontSize, textAlign).
|
||||||
|
Converts string values to proper types (booleans, numbers).
|
||||||
|
*/
|
||||||
|
const transformFieldMeta = (
|
||||||
|
rawMeta: Record<string, string>,
|
||||||
|
fieldType: FieldType,
|
||||||
|
): Record<string, unknown> | undefined => {
|
||||||
|
if (fieldType === FieldType.SIGNATURE || fieldType === FieldType.FREE_SIGNATURE) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(rawMeta).length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldTypeString = String(fieldType).toLowerCase();
|
||||||
|
|
||||||
|
const transformed: Record<string, unknown> = {
|
||||||
|
type: fieldTypeString,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(rawMeta)) {
|
||||||
|
if (key === 'readOnly' || key === 'required') {
|
||||||
|
transformed[key] = value === 'true';
|
||||||
|
} else if (
|
||||||
|
key === 'fontSize' ||
|
||||||
|
key === 'maxValue' ||
|
||||||
|
key === 'minValue' ||
|
||||||
|
key === 'characterLimit'
|
||||||
|
) {
|
||||||
|
const numValue = Number(value);
|
||||||
|
|
||||||
|
if (!Number.isNaN(numValue)) {
|
||||||
|
transformed[key] = numValue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transformed[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformed;
|
||||||
|
};
|
||||||
|
|
||||||
export const insertFieldsFromPlaceholdersInPDF = async (
|
export const insertFieldsFromPlaceholdersInPDF = async (
|
||||||
pdf: Buffer,
|
pdf: Buffer,
|
||||||
userId: number,
|
userId: number,
|
||||||
@ -349,7 +394,7 @@ export const insertFieldsFromPlaceholdersInPDF = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
createdRecipients = recipients;
|
createdRecipients = recipients;
|
||||||
} else {
|
} else if (envelope.type === EnvelopeType.TEMPLATE) {
|
||||||
const templateId =
|
const templateId =
|
||||||
envelopeId.type === 'templateId'
|
envelopeId.type === 'templateId'
|
||||||
? envelopeId.id
|
? envelopeId.id
|
||||||
@ -363,6 +408,10 @@ export const insertFieldsFromPlaceholdersInPDF = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
createdRecipients = recipients;
|
createdRecipients = recipients;
|
||||||
|
} else {
|
||||||
|
throw new AppError(AppErrorCode.INVALID_BODY, {
|
||||||
|
message: `Invalid envelope type: ${envelope.type}`,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const fieldsToCreate: FieldToCreate[] = [];
|
const fieldsToCreate: FieldToCreate[] = [];
|
||||||
@ -396,19 +445,21 @@ export const insertFieldsFromPlaceholdersInPDF = async (
|
|||||||
// Default height percentage if too small (use 2% as a reasonable default)
|
// Default height percentage if too small (use 2% as a reasonable default)
|
||||||
const finalHeightPercent = heightPercent > 0.01 ? heightPercent : 2;
|
const finalHeightPercent = heightPercent > 0.01 ? heightPercent : 2;
|
||||||
|
|
||||||
const baseField = {
|
const transformedFieldMeta = transformFieldMeta(placeholder.fieldMeta, fieldType);
|
||||||
|
|
||||||
|
const baseFieldAndMeta: TFieldAndMeta = ZFieldAndMetaSchema.parse({
|
||||||
|
type: fieldType,
|
||||||
|
fieldMeta: transformedFieldMeta,
|
||||||
|
});
|
||||||
|
|
||||||
|
fieldsToCreate.push({
|
||||||
|
...baseFieldAndMeta,
|
||||||
recipientId,
|
recipientId,
|
||||||
pageNumber: placeholder.page,
|
pageNumber: placeholder.page,
|
||||||
pageX: xPercent,
|
pageX: xPercent,
|
||||||
pageY: yPercent,
|
pageY: yPercent,
|
||||||
width: widthPercent,
|
width: widthPercent,
|
||||||
height: finalHeightPercent,
|
height: finalHeightPercent,
|
||||||
};
|
|
||||||
|
|
||||||
fieldsToCreate.push({
|
|
||||||
type: fieldType,
|
|
||||||
fieldMeta: undefined,
|
|
||||||
...baseField,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user