@payloadcms/plugin-form-builder 4.0.0-internal.c7d5de4 → 4.0.0-internal.cb69780
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collections/FormSubmissions/hooks/handleUploads.d.ts.map +1 -1
- package/dist/collections/FormSubmissions/hooks/handleUploads.js +4 -0
- package/dist/collections/FormSubmissions/hooks/handleUploads.js.map +1 -1
- package/dist/collections/FormSubmissions/hooks/sendEmail.d.ts.map +1 -1
- package/dist/collections/FormSubmissions/hooks/sendEmail.js +1 -0
- package/dist/collections/FormSubmissions/hooks/sendEmail.js.map +1 -1
- package/dist/collections/FormSubmissions/index.d.ts.map +1 -1
- package/dist/collections/FormSubmissions/index.js +2 -1
- package/dist/collections/FormSubmissions/index.js.map +1 -1
- package/dist/collections/Forms/DynamicPriceSelector.d.ts +3 -2
- package/dist/collections/Forms/DynamicPriceSelector.d.ts.map +1 -1
- package/dist/collections/Forms/DynamicPriceSelector.js +1 -1
- package/dist/collections/Forms/DynamicPriceSelector.js.map +1 -1
- package/dist/collections/Forms/index.js +1 -1
- package/dist/collections/Forms/index.js.map +1 -1
- package/dist/utilities/lexical/converters/link.js +1 -0
- package/dist/utilities/lexical/converters/link.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleUploads.d.ts","sourceRoot":"","sources":["../../../../src/collections/FormSubmissions/hooks/handleUploads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAK3B,MAAM,SAAS,CAAA;AAKhB,OAAO,KAAK,EACV,uBAAuB,EAIxB,MAAM,mBAAmB,CAAA;AAE1B,KAAK,kBAAkB,GAAG,UAAU,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAA;AAOnE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,uBACJ,kBAAkB,cAC1B,uBAAuB,
|
|
1
|
+
{"version":3,"file":"handleUploads.d.ts","sourceRoot":"","sources":["../../../../src/collections/FormSubmissions/hooks/handleUploads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAK3B,MAAM,SAAS,CAAA;AAKhB,OAAO,KAAK,EACV,uBAAuB,EAIxB,MAAM,mBAAmB,CAAA;AAE1B,KAAK,kBAAkB,GAAG,UAAU,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAA;AAOnE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,uBACJ,kBAAkB,cAC1B,uBAAuB,0BAoSpC,CAAA"}
|
|
@@ -28,6 +28,7 @@ import { validateMimeType } from 'payload/shared';
|
|
|
28
28
|
form = await payload.findByID({
|
|
29
29
|
id: formID,
|
|
30
30
|
collection: formSlug,
|
|
31
|
+
overrideAccess: true,
|
|
31
32
|
req
|
|
32
33
|
});
|
|
33
34
|
} catch {
|
|
@@ -124,6 +125,7 @@ import { validateMimeType } from 'payload/shared';
|
|
|
124
125
|
mimetype: requestFile.mimetype,
|
|
125
126
|
size: requestFile.size
|
|
126
127
|
},
|
|
128
|
+
overrideAccess: true,
|
|
127
129
|
req
|
|
128
130
|
});
|
|
129
131
|
createdDocs.push({
|
|
@@ -176,6 +178,7 @@ import { validateMimeType } from 'payload/shared';
|
|
|
176
178
|
fileDoc = await payload.findByID({
|
|
177
179
|
id: fileId,
|
|
178
180
|
collection: uploadCollection,
|
|
181
|
+
overrideAccess: true,
|
|
179
182
|
req
|
|
180
183
|
});
|
|
181
184
|
} catch {
|
|
@@ -242,6 +245,7 @@ import { validateMimeType } from 'payload/shared';
|
|
|
242
245
|
await payload.delete({
|
|
243
246
|
id: doc.id,
|
|
244
247
|
collection: doc.collection,
|
|
248
|
+
overrideAccess: true,
|
|
245
249
|
req
|
|
246
250
|
});
|
|
247
251
|
} catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/collections/FormSubmissions/hooks/handleUploads.ts"],"sourcesContent":["import type {\n CollectionBeforeChangeHook,\n File,\n FileData,\n TypeWithID,\n UploadCollectionSlug,\n} from 'payload'\n\nimport { ValidationError } from 'payload'\nimport { validateMimeType } from 'payload/shared'\n\nimport type {\n FormBuilderPluginConfig,\n SubmissionUploadItem,\n SubmissionValue,\n UploadField,\n} from '../../../types.js'\n\ntype BeforeChangeParams = Parameters<CollectionBeforeChangeHook>[0]\n\ninterface UploadError {\n field: string\n message: string\n}\n\n/**\n * Handles upload fields in form submissions.\n *\n * This hook:\n * 1. Checks req.files for files matching upload field names (supports multiple files per field)\n * 2. Validates MIME types and file sizes before uploading\n * 3. Creates media documents in the appropriate upload collection\n * 4. Populates submissionUploads with proper Payload upload relationships\n * 5. Strips upload fields from submissionData (they live in submissionUploads only)\n * 6. Validates pre-uploaded file IDs for backwards compatibility\n */\nexport const handleUploads = async (\n beforeChangeParams: BeforeChangeParams,\n formConfig: FormBuilderPluginConfig,\n) => {\n const { data, operation, req } = beforeChangeParams\n const { payload } = req\n\n // Only handle on create\n if (operation !== 'create') {\n return data\n }\n\n const { form: formID, submissionData } = data || {}\n\n if (!formID || !submissionData) {\n return data\n }\n\n const formSlug = formConfig?.formOverrides?.slug || 'forms'\n\n // Fetch the form to get field configurations\n let form\n try {\n form = await payload.findByID({\n id: formID,\n collection: formSlug,\n req,\n })\n } catch {\n // If form doesn't exist, let the form relationship validation handle it\n return data\n }\n\n const formFields = form?.fields || []\n const uploadFields = formFields.filter(\n (field: { blockType: string }) => field.blockType === 'upload',\n ) as UploadField[]\n\n if (uploadFields.length === 0) {\n return data\n }\n\n const submissionDataArray = submissionData as SubmissionValue[]\n\n // Build a map of pre-uploaded file IDs for backwards-compat lookup\n const submissionMap = new Map<string, { index: number; value: unknown }>()\n for (let i = 0; i < submissionDataArray.length; i++) {\n const item = submissionDataArray[i]\n if (item) {\n submissionMap.set(item.field, { index: i, value: item.value })\n }\n }\n\n // Get files from request (populated by addDataAndFileToRequest).\n // Multiple files with the same field name are stored as an array by buildFields.\n const requestFiles = req.files || {}\n\n const errors: UploadError[] = []\n // Accumulate upload items per field — one entry per upload field in the form\n const uploadsByField = new Map<string, SubmissionUploadItem[]>()\n // Track docs created during this hook so we can delete them if a later error causes rollback\n const createdDocs: Array<{ collection: string; id: number | string }> = []\n\n for (const uploadField of uploadFields) {\n const { name, maxFileSize, mimeTypes, multiple, required, uploadCollection } = uploadField\n const fieldLabel = uploadField.label || name\n\n uploadsByField.set(name, [])\n\n // Validate uploadCollection is configured in this plugin (defence-in-depth against tampered form docs)\n if (!formConfig.uploadCollections?.includes(uploadCollection)) {\n errors.push({\n field: name,\n message: `Upload collection \"${uploadCollection}\" is not configured in this plugin`,\n })\n continue\n }\n\n // Normalize: multiple files with the same field name arrive as an array\n const rawFile = requestFiles[name]\n const requestFileList: File[] = rawFile ? (Array.isArray(rawFile) ? rawFile : [rawFile]) : []\n\n const existingSubmission = submissionMap.get(name)\n\n if (requestFileList.length > 0) {\n // Guard: reject multiple files when the field doesn't allow them\n if (!multiple && requestFileList.length > 1) {\n errors.push({\n field: name,\n message: `${fieldLabel} does not allow multiple files`,\n })\n continue\n }\n\n // Direct file upload(s) from request\n for (const requestFile of requestFileList) {\n // Validate MIME type before uploading\n if (mimeTypes && mimeTypes.length > 0) {\n const allowedPatterns = mimeTypes.map((m) => m.mimeType)\n\n if (!validateMimeType(requestFile.mimetype, allowedPatterns)) {\n errors.push({\n field: name,\n message: `${fieldLabel}: File type \"${requestFile.mimetype}\" is not allowed. Allowed types: ${allowedPatterns.join(', ')}`,\n })\n continue\n }\n }\n\n // Validate file size before uploading\n if (maxFileSize && maxFileSize > 0 && requestFile.size > maxFileSize) {\n const maxSizeMB = (maxFileSize / (1024 * 1024)).toFixed(2)\n const fileSizeMB = (requestFile.size / (1024 * 1024)).toFixed(2)\n\n errors.push({\n field: name,\n message: `${fieldLabel}: File size (${fileSizeMB}MB) exceeds maximum allowed size (${maxSizeMB}MB)`,\n })\n continue\n }\n\n // Create the media document.\n // Note: payload.create writes the file to storage before the DB row exists. If\n // the DB write throws, createdDocs never records the entry and the file on disk\n // will not be cleaned up by the rollback loop below. Payload core owns that\n // rollback path — we only clean up docs we successfully created here.\n try {\n const mediaDoc = await payload.create({\n collection: uploadCollection,\n data: {},\n file: {\n name: requestFile.name,\n data: requestFile.data,\n mimetype: requestFile.mimetype,\n size: requestFile.size,\n },\n req,\n })\n\n createdDocs.push({ id: mediaDoc.id, collection: uploadCollection })\n uploadsByField.get(name)!.push({ relationTo: uploadCollection, value: mediaDoc.id })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error'\n\n errors.push({\n field: name,\n message: `${fieldLabel}: Failed to upload file - ${errorMessage}`,\n })\n }\n }\n } else if (existingSubmission && existingSubmission.value) {\n // Backwards compatibility: validate pre-uploaded file IDs\n const submittedValue = existingSubmission.value\n const submittedValueStr =\n typeof submittedValue === 'string' || typeof submittedValue === 'number'\n ? String(submittedValue)\n : ''\n\n if (!submittedValueStr) {\n if (required) {\n errors.push({ field: name, message: `${fieldLabel} is required` })\n }\n continue\n }\n\n // Guard: reject comma-separated IDs when the field doesn't allow multiple files.\n // Assumes IDs never contain literal commas — true for ObjectIDs/UUIDs and any numeric ID.\n if (!multiple && submittedValueStr.includes(',')) {\n errors.push({\n field: name,\n message: `${fieldLabel} does not allow multiple files`,\n })\n continue\n }\n\n // Parse file IDs (comma-separated for multiple files)\n const fileIds = multiple\n ? submittedValueStr\n .split(',')\n .map((id) => id.trim())\n .filter(Boolean)\n : [submittedValueStr]\n\n // Validate each file\n for (const fileId of fileIds) {\n let fileDoc: (FileData & TypeWithID) | null = null\n let fileIsValid = true\n\n try {\n fileDoc = (await payload.findByID({\n id: fileId,\n collection: uploadCollection,\n req,\n })) as FileData & TypeWithID\n } catch {\n errors.push({\n field: name,\n message: `${fieldLabel}: File with ID \"${fileId}\" not found in collection \"${uploadCollection}\"`,\n })\n fileIsValid = false\n continue\n }\n\n if (!fileDoc) {\n errors.push({\n field: name,\n message: `${fieldLabel}: File with ID \"${fileId}\" not found`,\n })\n fileIsValid = false\n continue\n }\n\n // Validate mimeType\n if (mimeTypes && mimeTypes.length > 0) {\n const allowedPatterns = mimeTypes.map((m) => m.mimeType)\n const fileMimeType = fileDoc.mimeType\n\n if (fileMimeType && !validateMimeType(fileMimeType, allowedPatterns)) {\n errors.push({\n field: name,\n message: `${fieldLabel}: File type \"${fileMimeType}\" is not allowed. Allowed types: ${allowedPatterns.join(', ')}`,\n })\n fileIsValid = false\n continue\n }\n }\n\n // Validate file size\n if (maxFileSize && maxFileSize > 0) {\n const fileSize = fileDoc.filesize\n\n if (fileSize && fileSize > maxFileSize) {\n const maxSizeMB = (maxFileSize / (1024 * 1024)).toFixed(2)\n const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2)\n\n errors.push({\n field: name,\n message: `${fieldLabel}: File size (${fileSizeMB}MB) exceeds maximum allowed size (${maxSizeMB}MB)`,\n })\n fileIsValid = false\n }\n }\n\n if (fileIsValid) {\n uploadsByField.get(name)!.push({ relationTo: uploadCollection, value: fileDoc.id })\n }\n }\n } else if (required) {\n // No file in request and no pre-uploaded file ID, but field is required\n errors.push({\n field: name,\n message: `${fieldLabel} is required`,\n })\n }\n }\n\n if (errors.length > 0) {\n // Best-effort cleanup of any docs created before the error was detected\n for (const doc of createdDocs) {\n try {\n await payload.delete({ id: doc.id, collection: doc.collection, req })\n } catch {\n // best-effort — don't mask the original validation error\n }\n }\n\n throw new ValidationError({\n collection: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',\n errors: errors.map((error) => ({\n message: error.message,\n path: error.field,\n })),\n })\n }\n\n // Strip upload fields from submissionData — they are stored in submissionUploads only\n const uploadFieldNames = new Set(uploadFields.map((f) => f.name))\n const cleanedSubmissionData = submissionDataArray.filter(\n (item) => !uploadFieldNames.has(item.field),\n )\n\n // One entry per upload field; omit fields with no successful uploads\n const updatedSubmissionUploads = Array.from(uploadsByField.entries())\n .filter(([, items]) => items.length > 0)\n .map(([field, value]) => ({ field, value }))\n\n return {\n ...data,\n submissionData: cleanedSubmissionData,\n submissionUploads: updatedSubmissionUploads,\n }\n}\n"],"names":["ValidationError","validateMimeType","handleUploads","beforeChangeParams","formConfig","data","operation","req","payload","form","formID","submissionData","formSlug","formOverrides","slug","findByID","id","collection","formFields","fields","uploadFields","filter","field","blockType","length","submissionDataArray","submissionMap","Map","i","item","set","index","value","requestFiles","files","errors","uploadsByField","createdDocs","uploadField","name","maxFileSize","mimeTypes","multiple","required","uploadCollection","fieldLabel","label","uploadCollections","includes","push","message","rawFile","requestFileList","Array","isArray","existingSubmission","get","requestFile","allowedPatterns","map","m","mimeType","mimetype","join","size","maxSizeMB","toFixed","fileSizeMB","mediaDoc","create","file","relationTo","err","errorMessage","Error","submittedValue","submittedValueStr","String","fileIds","split","trim","Boolean","fileId","fileDoc","fileIsValid","fileMimeType","fileSize","filesize","doc","delete","formSubmissionOverrides","error","path","uploadFieldNames","Set","f","cleanedSubmissionData","has","updatedSubmissionUploads","from","entries","items","submissionUploads"],"mappings":"AAQA,SAASA,eAAe,QAAQ,UAAS;AACzC,SAASC,gBAAgB,QAAQ,iBAAgB;AAgBjD;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,gBAAgB,OAC3BC,oBACAC;IAEA,MAAM,EAAEC,IAAI,EAAEC,SAAS,EAAEC,GAAG,EAAE,GAAGJ;IACjC,MAAM,EAAEK,OAAO,EAAE,GAAGD;IAEpB,wBAAwB;IACxB,IAAID,cAAc,UAAU;QAC1B,OAAOD;IACT;IAEA,MAAM,EAAEI,MAAMC,MAAM,EAAEC,cAAc,EAAE,GAAGN,QAAQ,CAAC;IAElD,IAAI,CAACK,UAAU,CAACC,gBAAgB;QAC9B,OAAON;IACT;IAEA,MAAMO,WAAWR,YAAYS,eAAeC,QAAQ;IAEpD,6CAA6C;IAC7C,IAAIL;IACJ,IAAI;QACFA,OAAO,MAAMD,QAAQO,QAAQ,CAAC;YAC5BC,IAAIN;YACJO,YAAYL;YACZL;QACF;IACF,EAAE,OAAM;QACN,wEAAwE;QACxE,OAAOF;IACT;IAEA,MAAMa,aAAaT,MAAMU,UAAU,EAAE;IACrC,MAAMC,eAAeF,WAAWG,MAAM,CACpC,CAACC,QAAiCA,MAAMC,SAAS,KAAK;IAGxD,IAAIH,aAAaI,MAAM,KAAK,GAAG;QAC7B,OAAOnB;IACT;IAEA,MAAMoB,sBAAsBd;IAE5B,mEAAmE;IACnE,MAAMe,gBAAgB,IAAIC;IAC1B,IAAK,IAAIC,IAAI,GAAGA,IAAIH,oBAAoBD,MAAM,EAAEI,IAAK;QACnD,MAAMC,OAAOJ,mBAAmB,CAACG,EAAE;QACnC,IAAIC,MAAM;YACRH,cAAcI,GAAG,CAACD,KAAKP,KAAK,EAAE;gBAAES,OAAOH;gBAAGI,OAAOH,KAAKG,KAAK;YAAC;QAC9D;IACF;IAEA,iEAAiE;IACjE,iFAAiF;IACjF,MAAMC,eAAe1B,IAAI2B,KAAK,IAAI,CAAC;IAEnC,MAAMC,SAAwB,EAAE;IAChC,6EAA6E;IAC7E,MAAMC,iBAAiB,IAAIT;IAC3B,6FAA6F;IAC7F,MAAMU,cAAkE,EAAE;IAE1E,KAAK,MAAMC,eAAelB,aAAc;QACtC,MAAM,EAAEmB,IAAI,EAAEC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,gBAAgB,EAAE,GAAGN;QAC/E,MAAMO,aAAaP,YAAYQ,KAAK,IAAIP;QAExCH,eAAeN,GAAG,CAACS,MAAM,EAAE;QAE3B,uGAAuG;QACvG,IAAI,CAACnC,WAAW2C,iBAAiB,EAAEC,SAASJ,mBAAmB;YAC7DT,OAAOc,IAAI,CAAC;gBACV3B,OAAOiB;gBACPW,SAAS,CAAC,mBAAmB,EAAEN,iBAAiB,kCAAkC,CAAC;YACrF;YACA;QACF;QAEA,wEAAwE;QACxE,MAAMO,UAAUlB,YAAY,CAACM,KAAK;QAClC,MAAMa,kBAA0BD,UAAWE,MAAMC,OAAO,CAACH,WAAWA,UAAU;YAACA;SAAQ,GAAI,EAAE;QAE7F,MAAMI,qBAAqB7B,cAAc8B,GAAG,CAACjB;QAE7C,IAAIa,gBAAgB5B,MAAM,GAAG,GAAG;YAC9B,iEAAiE;YACjE,IAAI,CAACkB,YAAYU,gBAAgB5B,MAAM,GAAG,GAAG;gBAC3CW,OAAOc,IAAI,CAAC;oBACV3B,OAAOiB;oBACPW,SAAS,GAAGL,WAAW,8BAA8B,CAAC;gBACxD;gBACA;YACF;YAEA,qCAAqC;YACrC,KAAK,MAAMY,eAAeL,gBAAiB;gBACzC,sCAAsC;gBACtC,IAAIX,aAAaA,UAAUjB,MAAM,GAAG,GAAG;oBACrC,MAAMkC,kBAAkBjB,UAAUkB,GAAG,CAAC,CAACC,IAAMA,EAAEC,QAAQ;oBAEvD,IAAI,CAAC5D,iBAAiBwD,YAAYK,QAAQ,EAAEJ,kBAAkB;wBAC5DvB,OAAOc,IAAI,CAAC;4BACV3B,OAAOiB;4BACPW,SAAS,GAAGL,WAAW,aAAa,EAAEY,YAAYK,QAAQ,CAAC,iCAAiC,EAAEJ,gBAAgBK,IAAI,CAAC,OAAO;wBAC5H;wBACA;oBACF;gBACF;gBAEA,sCAAsC;gBACtC,IAAIvB,eAAeA,cAAc,KAAKiB,YAAYO,IAAI,GAAGxB,aAAa;oBACpE,MAAMyB,YAAY,AAACzB,CAAAA,cAAe,CAAA,OAAO,IAAG,CAAC,EAAG0B,OAAO,CAAC;oBACxD,MAAMC,aAAa,AAACV,CAAAA,YAAYO,IAAI,GAAI,CAAA,OAAO,IAAG,CAAC,EAAGE,OAAO,CAAC;oBAE9D/B,OAAOc,IAAI,CAAC;wBACV3B,OAAOiB;wBACPW,SAAS,GAAGL,WAAW,aAAa,EAAEsB,WAAW,kCAAkC,EAAEF,UAAU,GAAG,CAAC;oBACrG;oBACA;gBACF;gBAEA,6BAA6B;gBAC7B,+EAA+E;gBAC/E,gFAAgF;gBAChF,4EAA4E;gBAC5E,sEAAsE;gBACtE,IAAI;oBACF,MAAMG,WAAW,MAAM5D,QAAQ6D,MAAM,CAAC;wBACpCpD,YAAY2B;wBACZvC,MAAM,CAAC;wBACPiE,MAAM;4BACJ/B,MAAMkB,YAAYlB,IAAI;4BACtBlC,MAAMoD,YAAYpD,IAAI;4BACtByD,UAAUL,YAAYK,QAAQ;4BAC9BE,MAAMP,YAAYO,IAAI;wBACxB;wBACAzD;oBACF;oBAEA8B,YAAYY,IAAI,CAAC;wBAAEjC,IAAIoD,SAASpD,EAAE;wBAAEC,YAAY2B;oBAAiB;oBACjER,eAAeoB,GAAG,CAACjB,MAAOU,IAAI,CAAC;wBAAEsB,YAAY3B;wBAAkBZ,OAAOoC,SAASpD,EAAE;oBAAC;gBACpF,EAAE,OAAOwD,KAAK;oBACZ,MAAMC,eAAeD,eAAeE,QAAQF,IAAItB,OAAO,GAAG;oBAE1Df,OAAOc,IAAI,CAAC;wBACV3B,OAAOiB;wBACPW,SAAS,GAAGL,WAAW,0BAA0B,EAAE4B,cAAc;oBACnE;gBACF;YACF;QACF,OAAO,IAAIlB,sBAAsBA,mBAAmBvB,KAAK,EAAE;YACzD,0DAA0D;YAC1D,MAAM2C,iBAAiBpB,mBAAmBvB,KAAK;YAC/C,MAAM4C,oBACJ,OAAOD,mBAAmB,YAAY,OAAOA,mBAAmB,WAC5DE,OAAOF,kBACP;YAEN,IAAI,CAACC,mBAAmB;gBACtB,IAAIjC,UAAU;oBACZR,OAAOc,IAAI,CAAC;wBAAE3B,OAAOiB;wBAAMW,SAAS,GAAGL,WAAW,YAAY,CAAC;oBAAC;gBAClE;gBACA;YACF;YAEA,iFAAiF;YACjF,0FAA0F;YAC1F,IAAI,CAACH,YAAYkC,kBAAkB5B,QAAQ,CAAC,MAAM;gBAChDb,OAAOc,IAAI,CAAC;oBACV3B,OAAOiB;oBACPW,SAAS,GAAGL,WAAW,8BAA8B,CAAC;gBACxD;gBACA;YACF;YAEA,sDAAsD;YACtD,MAAMiC,UAAUpC,WACZkC,kBACGG,KAAK,CAAC,KACNpB,GAAG,CAAC,CAAC3C,KAAOA,GAAGgE,IAAI,IACnB3D,MAAM,CAAC4D,WACV;gBAACL;aAAkB;YAEvB,qBAAqB;YACrB,KAAK,MAAMM,UAAUJ,QAAS;gBAC5B,IAAIK,UAA0C;gBAC9C,IAAIC,cAAc;gBAElB,IAAI;oBACFD,UAAW,MAAM3E,QAAQO,QAAQ,CAAC;wBAChCC,IAAIkE;wBACJjE,YAAY2B;wBACZrC;oBACF;gBACF,EAAE,OAAM;oBACN4B,OAAOc,IAAI,CAAC;wBACV3B,OAAOiB;wBACPW,SAAS,GAAGL,WAAW,gBAAgB,EAAEqC,OAAO,2BAA2B,EAAEtC,iBAAiB,CAAC,CAAC;oBAClG;oBACAwC,cAAc;oBACd;gBACF;gBAEA,IAAI,CAACD,SAAS;oBACZhD,OAAOc,IAAI,CAAC;wBACV3B,OAAOiB;wBACPW,SAAS,GAAGL,WAAW,gBAAgB,EAAEqC,OAAO,WAAW,CAAC;oBAC9D;oBACAE,cAAc;oBACd;gBACF;gBAEA,oBAAoB;gBACpB,IAAI3C,aAAaA,UAAUjB,MAAM,GAAG,GAAG;oBACrC,MAAMkC,kBAAkBjB,UAAUkB,GAAG,CAAC,CAACC,IAAMA,EAAEC,QAAQ;oBACvD,MAAMwB,eAAeF,QAAQtB,QAAQ;oBAErC,IAAIwB,gBAAgB,CAACpF,iBAAiBoF,cAAc3B,kBAAkB;wBACpEvB,OAAOc,IAAI,CAAC;4BACV3B,OAAOiB;4BACPW,SAAS,GAAGL,WAAW,aAAa,EAAEwC,aAAa,iCAAiC,EAAE3B,gBAAgBK,IAAI,CAAC,OAAO;wBACpH;wBACAqB,cAAc;wBACd;oBACF;gBACF;gBAEA,qBAAqB;gBACrB,IAAI5C,eAAeA,cAAc,GAAG;oBAClC,MAAM8C,WAAWH,QAAQI,QAAQ;oBAEjC,IAAID,YAAYA,WAAW9C,aAAa;wBACtC,MAAMyB,YAAY,AAACzB,CAAAA,cAAe,CAAA,OAAO,IAAG,CAAC,EAAG0B,OAAO,CAAC;wBACxD,MAAMC,aAAa,AAACmB,CAAAA,WAAY,CAAA,OAAO,IAAG,CAAC,EAAGpB,OAAO,CAAC;wBAEtD/B,OAAOc,IAAI,CAAC;4BACV3B,OAAOiB;4BACPW,SAAS,GAAGL,WAAW,aAAa,EAAEsB,WAAW,kCAAkC,EAAEF,UAAU,GAAG,CAAC;wBACrG;wBACAmB,cAAc;oBAChB;gBACF;gBAEA,IAAIA,aAAa;oBACfhD,eAAeoB,GAAG,CAACjB,MAAOU,IAAI,CAAC;wBAAEsB,YAAY3B;wBAAkBZ,OAAOmD,QAAQnE,EAAE;oBAAC;gBACnF;YACF;QACF,OAAO,IAAI2B,UAAU;YACnB,wEAAwE;YACxER,OAAOc,IAAI,CAAC;gBACV3B,OAAOiB;gBACPW,SAAS,GAAGL,WAAW,YAAY,CAAC;YACtC;QACF;IACF;IAEA,IAAIV,OAAOX,MAAM,GAAG,GAAG;QACrB,wEAAwE;QACxE,KAAK,MAAMgE,OAAOnD,YAAa;YAC7B,IAAI;gBACF,MAAM7B,QAAQiF,MAAM,CAAC;oBAAEzE,IAAIwE,IAAIxE,EAAE;oBAAEC,YAAYuE,IAAIvE,UAAU;oBAAEV;gBAAI;YACrE,EAAE,OAAM;YACN,yDAAyD;YAC3D;QACF;QAEA,MAAM,IAAIP,gBAAgB;YACxBiB,YAAYb,YAAYsF,yBAAyB5E,QAAQ;YACzDqB,QAAQA,OAAOwB,GAAG,CAAC,CAACgC,QAAW,CAAA;oBAC7BzC,SAASyC,MAAMzC,OAAO;oBACtB0C,MAAMD,MAAMrE,KAAK;gBACnB,CAAA;QACF;IACF;IAEA,sFAAsF;IACtF,MAAMuE,mBAAmB,IAAIC,IAAI1E,aAAauC,GAAG,CAAC,CAACoC,IAAMA,EAAExD,IAAI;IAC/D,MAAMyD,wBAAwBvE,oBAAoBJ,MAAM,CACtD,CAACQ,OAAS,CAACgE,iBAAiBI,GAAG,CAACpE,KAAKP,KAAK;IAG5C,qEAAqE;IACrE,MAAM4E,2BAA2B7C,MAAM8C,IAAI,CAAC/D,eAAegE,OAAO,IAC/D/E,MAAM,CAAC,CAAC,GAAGgF,MAAM,GAAKA,MAAM7E,MAAM,GAAG,GACrCmC,GAAG,CAAC,CAAC,CAACrC,OAAOU,MAAM,GAAM,CAAA;YAAEV;YAAOU;QAAM,CAAA;IAE3C,OAAO;QACL,GAAG3B,IAAI;QACPM,gBAAgBqF;QAChBM,mBAAmBJ;IACrB;AACF,EAAC"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/collections/FormSubmissions/hooks/handleUploads.ts"],"sourcesContent":["import type {\n CollectionBeforeChangeHook,\n File,\n FileData,\n TypeWithID,\n UploadCollectionSlug,\n} from 'payload'\n\nimport { ValidationError } from 'payload'\nimport { validateMimeType } from 'payload/shared'\n\nimport type {\n FormBuilderPluginConfig,\n SubmissionUploadItem,\n SubmissionValue,\n UploadField,\n} from '../../../types.js'\n\ntype BeforeChangeParams = Parameters<CollectionBeforeChangeHook>[0]\n\ninterface UploadError {\n field: string\n message: string\n}\n\n/**\n * Handles upload fields in form submissions.\n *\n * This hook:\n * 1. Checks req.files for files matching upload field names (supports multiple files per field)\n * 2. Validates MIME types and file sizes before uploading\n * 3. Creates media documents in the appropriate upload collection\n * 4. Populates submissionUploads with proper Payload upload relationships\n * 5. Strips upload fields from submissionData (they live in submissionUploads only)\n * 6. Validates pre-uploaded file IDs for backwards compatibility\n */\nexport const handleUploads = async (\n beforeChangeParams: BeforeChangeParams,\n formConfig: FormBuilderPluginConfig,\n) => {\n const { data, operation, req } = beforeChangeParams\n const { payload } = req\n\n // Only handle on create\n if (operation !== 'create') {\n return data\n }\n\n const { form: formID, submissionData } = data || {}\n\n if (!formID || !submissionData) {\n return data\n }\n\n const formSlug = formConfig?.formOverrides?.slug || 'forms'\n\n // Fetch the form to get field configurations\n let form\n try {\n form = await payload.findByID({\n id: formID,\n collection: formSlug,\n overrideAccess: true,\n req,\n })\n } catch {\n // If form doesn't exist, let the form relationship validation handle it\n return data\n }\n\n const formFields = form?.fields || []\n const uploadFields = formFields.filter(\n (field: { blockType: string }) => field.blockType === 'upload',\n ) as UploadField[]\n\n if (uploadFields.length === 0) {\n return data\n }\n\n const submissionDataArray = submissionData as SubmissionValue[]\n\n // Build a map of pre-uploaded file IDs for backwards-compat lookup\n const submissionMap = new Map<string, { index: number; value: unknown }>()\n for (let i = 0; i < submissionDataArray.length; i++) {\n const item = submissionDataArray[i]\n if (item) {\n submissionMap.set(item.field, { index: i, value: item.value })\n }\n }\n\n // Get files from request (populated by addDataAndFileToRequest).\n // Multiple files with the same field name are stored as an array by buildFields.\n const requestFiles = req.files || {}\n\n const errors: UploadError[] = []\n // Accumulate upload items per field — one entry per upload field in the form\n const uploadsByField = new Map<string, SubmissionUploadItem[]>()\n // Track docs created during this hook so we can delete them if a later error causes rollback\n const createdDocs: Array<{ collection: string; id: number | string }> = []\n\n for (const uploadField of uploadFields) {\n const { name, maxFileSize, mimeTypes, multiple, required, uploadCollection } = uploadField\n const fieldLabel = uploadField.label || name\n\n uploadsByField.set(name, [])\n\n // Validate uploadCollection is configured in this plugin (defence-in-depth against tampered form docs)\n if (!formConfig.uploadCollections?.includes(uploadCollection)) {\n errors.push({\n field: name,\n message: `Upload collection \"${uploadCollection}\" is not configured in this plugin`,\n })\n continue\n }\n\n // Normalize: multiple files with the same field name arrive as an array\n const rawFile = requestFiles[name]\n const requestFileList: File[] = rawFile ? (Array.isArray(rawFile) ? rawFile : [rawFile]) : []\n\n const existingSubmission = submissionMap.get(name)\n\n if (requestFileList.length > 0) {\n // Guard: reject multiple files when the field doesn't allow them\n if (!multiple && requestFileList.length > 1) {\n errors.push({\n field: name,\n message: `${fieldLabel} does not allow multiple files`,\n })\n continue\n }\n\n // Direct file upload(s) from request\n for (const requestFile of requestFileList) {\n // Validate MIME type before uploading\n if (mimeTypes && mimeTypes.length > 0) {\n const allowedPatterns = mimeTypes.map((m) => m.mimeType)\n\n if (!validateMimeType(requestFile.mimetype, allowedPatterns)) {\n errors.push({\n field: name,\n message: `${fieldLabel}: File type \"${requestFile.mimetype}\" is not allowed. Allowed types: ${allowedPatterns.join(', ')}`,\n })\n continue\n }\n }\n\n // Validate file size before uploading\n if (maxFileSize && maxFileSize > 0 && requestFile.size > maxFileSize) {\n const maxSizeMB = (maxFileSize / (1024 * 1024)).toFixed(2)\n const fileSizeMB = (requestFile.size / (1024 * 1024)).toFixed(2)\n\n errors.push({\n field: name,\n message: `${fieldLabel}: File size (${fileSizeMB}MB) exceeds maximum allowed size (${maxSizeMB}MB)`,\n })\n continue\n }\n\n // Create the media document.\n // Note: payload.create writes the file to storage before the DB row exists. If\n // the DB write throws, createdDocs never records the entry and the file on disk\n // will not be cleaned up by the rollback loop below. Payload core owns that\n // rollback path — we only clean up docs we successfully created here.\n try {\n const mediaDoc = await payload.create({\n collection: uploadCollection,\n data: {},\n file: {\n name: requestFile.name,\n data: requestFile.data,\n mimetype: requestFile.mimetype,\n size: requestFile.size,\n },\n overrideAccess: true,\n req,\n })\n\n createdDocs.push({ id: mediaDoc.id, collection: uploadCollection })\n uploadsByField.get(name)!.push({ relationTo: uploadCollection, value: mediaDoc.id })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error'\n\n errors.push({\n field: name,\n message: `${fieldLabel}: Failed to upload file - ${errorMessage}`,\n })\n }\n }\n } else if (existingSubmission && existingSubmission.value) {\n // Backwards compatibility: validate pre-uploaded file IDs\n const submittedValue = existingSubmission.value\n const submittedValueStr =\n typeof submittedValue === 'string' || typeof submittedValue === 'number'\n ? String(submittedValue)\n : ''\n\n if (!submittedValueStr) {\n if (required) {\n errors.push({ field: name, message: `${fieldLabel} is required` })\n }\n continue\n }\n\n // Guard: reject comma-separated IDs when the field doesn't allow multiple files.\n // Assumes IDs never contain literal commas — true for ObjectIDs/UUIDs and any numeric ID.\n if (!multiple && submittedValueStr.includes(',')) {\n errors.push({\n field: name,\n message: `${fieldLabel} does not allow multiple files`,\n })\n continue\n }\n\n // Parse file IDs (comma-separated for multiple files)\n const fileIds = multiple\n ? submittedValueStr\n .split(',')\n .map((id) => id.trim())\n .filter(Boolean)\n : [submittedValueStr]\n\n // Validate each file\n for (const fileId of fileIds) {\n let fileDoc: (FileData & TypeWithID) | null = null\n let fileIsValid = true\n\n try {\n fileDoc = (await payload.findByID({\n id: fileId,\n collection: uploadCollection,\n overrideAccess: true,\n req,\n })) as FileData & TypeWithID\n } catch {\n errors.push({\n field: name,\n message: `${fieldLabel}: File with ID \"${fileId}\" not found in collection \"${uploadCollection}\"`,\n })\n fileIsValid = false\n continue\n }\n\n if (!fileDoc) {\n errors.push({\n field: name,\n message: `${fieldLabel}: File with ID \"${fileId}\" not found`,\n })\n fileIsValid = false\n continue\n }\n\n // Validate mimeType\n if (mimeTypes && mimeTypes.length > 0) {\n const allowedPatterns = mimeTypes.map((m) => m.mimeType)\n const fileMimeType = fileDoc.mimeType\n\n if (fileMimeType && !validateMimeType(fileMimeType, allowedPatterns)) {\n errors.push({\n field: name,\n message: `${fieldLabel}: File type \"${fileMimeType}\" is not allowed. Allowed types: ${allowedPatterns.join(', ')}`,\n })\n fileIsValid = false\n continue\n }\n }\n\n // Validate file size\n if (maxFileSize && maxFileSize > 0) {\n const fileSize = fileDoc.filesize\n\n if (fileSize && fileSize > maxFileSize) {\n const maxSizeMB = (maxFileSize / (1024 * 1024)).toFixed(2)\n const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2)\n\n errors.push({\n field: name,\n message: `${fieldLabel}: File size (${fileSizeMB}MB) exceeds maximum allowed size (${maxSizeMB}MB)`,\n })\n fileIsValid = false\n }\n }\n\n if (fileIsValid) {\n uploadsByField.get(name)!.push({ relationTo: uploadCollection, value: fileDoc.id })\n }\n }\n } else if (required) {\n // No file in request and no pre-uploaded file ID, but field is required\n errors.push({\n field: name,\n message: `${fieldLabel} is required`,\n })\n }\n }\n\n if (errors.length > 0) {\n // Best-effort cleanup of any docs created before the error was detected\n for (const doc of createdDocs) {\n try {\n await payload.delete({ id: doc.id, collection: doc.collection, overrideAccess: true, req })\n } catch {\n // best-effort — don't mask the original validation error\n }\n }\n\n throw new ValidationError({\n collection: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',\n errors: errors.map((error) => ({\n message: error.message,\n path: error.field,\n })),\n })\n }\n\n // Strip upload fields from submissionData — they are stored in submissionUploads only\n const uploadFieldNames = new Set(uploadFields.map((f) => f.name))\n const cleanedSubmissionData = submissionDataArray.filter(\n (item) => !uploadFieldNames.has(item.field),\n )\n\n // One entry per upload field; omit fields with no successful uploads\n const updatedSubmissionUploads = Array.from(uploadsByField.entries())\n .filter(([, items]) => items.length > 0)\n .map(([field, value]) => ({ field, value }))\n\n return {\n ...data,\n submissionData: cleanedSubmissionData,\n submissionUploads: updatedSubmissionUploads,\n }\n}\n"],"names":["ValidationError","validateMimeType","handleUploads","beforeChangeParams","formConfig","data","operation","req","payload","form","formID","submissionData","formSlug","formOverrides","slug","findByID","id","collection","overrideAccess","formFields","fields","uploadFields","filter","field","blockType","length","submissionDataArray","submissionMap","Map","i","item","set","index","value","requestFiles","files","errors","uploadsByField","createdDocs","uploadField","name","maxFileSize","mimeTypes","multiple","required","uploadCollection","fieldLabel","label","uploadCollections","includes","push","message","rawFile","requestFileList","Array","isArray","existingSubmission","get","requestFile","allowedPatterns","map","m","mimeType","mimetype","join","size","maxSizeMB","toFixed","fileSizeMB","mediaDoc","create","file","relationTo","err","errorMessage","Error","submittedValue","submittedValueStr","String","fileIds","split","trim","Boolean","fileId","fileDoc","fileIsValid","fileMimeType","fileSize","filesize","doc","delete","formSubmissionOverrides","error","path","uploadFieldNames","Set","f","cleanedSubmissionData","has","updatedSubmissionUploads","from","entries","items","submissionUploads"],"mappings":"AAQA,SAASA,eAAe,QAAQ,UAAS;AACzC,SAASC,gBAAgB,QAAQ,iBAAgB;AAgBjD;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,gBAAgB,OAC3BC,oBACAC;IAEA,MAAM,EAAEC,IAAI,EAAEC,SAAS,EAAEC,GAAG,EAAE,GAAGJ;IACjC,MAAM,EAAEK,OAAO,EAAE,GAAGD;IAEpB,wBAAwB;IACxB,IAAID,cAAc,UAAU;QAC1B,OAAOD;IACT;IAEA,MAAM,EAAEI,MAAMC,MAAM,EAAEC,cAAc,EAAE,GAAGN,QAAQ,CAAC;IAElD,IAAI,CAACK,UAAU,CAACC,gBAAgB;QAC9B,OAAON;IACT;IAEA,MAAMO,WAAWR,YAAYS,eAAeC,QAAQ;IAEpD,6CAA6C;IAC7C,IAAIL;IACJ,IAAI;QACFA,OAAO,MAAMD,QAAQO,QAAQ,CAAC;YAC5BC,IAAIN;YACJO,YAAYL;YACZM,gBAAgB;YAChBX;QACF;IACF,EAAE,OAAM;QACN,wEAAwE;QACxE,OAAOF;IACT;IAEA,MAAMc,aAAaV,MAAMW,UAAU,EAAE;IACrC,MAAMC,eAAeF,WAAWG,MAAM,CACpC,CAACC,QAAiCA,MAAMC,SAAS,KAAK;IAGxD,IAAIH,aAAaI,MAAM,KAAK,GAAG;QAC7B,OAAOpB;IACT;IAEA,MAAMqB,sBAAsBf;IAE5B,mEAAmE;IACnE,MAAMgB,gBAAgB,IAAIC;IAC1B,IAAK,IAAIC,IAAI,GAAGA,IAAIH,oBAAoBD,MAAM,EAAEI,IAAK;QACnD,MAAMC,OAAOJ,mBAAmB,CAACG,EAAE;QACnC,IAAIC,MAAM;YACRH,cAAcI,GAAG,CAACD,KAAKP,KAAK,EAAE;gBAAES,OAAOH;gBAAGI,OAAOH,KAAKG,KAAK;YAAC;QAC9D;IACF;IAEA,iEAAiE;IACjE,iFAAiF;IACjF,MAAMC,eAAe3B,IAAI4B,KAAK,IAAI,CAAC;IAEnC,MAAMC,SAAwB,EAAE;IAChC,6EAA6E;IAC7E,MAAMC,iBAAiB,IAAIT;IAC3B,6FAA6F;IAC7F,MAAMU,cAAkE,EAAE;IAE1E,KAAK,MAAMC,eAAelB,aAAc;QACtC,MAAM,EAAEmB,IAAI,EAAEC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,gBAAgB,EAAE,GAAGN;QAC/E,MAAMO,aAAaP,YAAYQ,KAAK,IAAIP;QAExCH,eAAeN,GAAG,CAACS,MAAM,EAAE;QAE3B,uGAAuG;QACvG,IAAI,CAACpC,WAAW4C,iBAAiB,EAAEC,SAASJ,mBAAmB;YAC7DT,OAAOc,IAAI,CAAC;gBACV3B,OAAOiB;gBACPW,SAAS,CAAC,mBAAmB,EAAEN,iBAAiB,kCAAkC,CAAC;YACrF;YACA;QACF;QAEA,wEAAwE;QACxE,MAAMO,UAAUlB,YAAY,CAACM,KAAK;QAClC,MAAMa,kBAA0BD,UAAWE,MAAMC,OAAO,CAACH,WAAWA,UAAU;YAACA;SAAQ,GAAI,EAAE;QAE7F,MAAMI,qBAAqB7B,cAAc8B,GAAG,CAACjB;QAE7C,IAAIa,gBAAgB5B,MAAM,GAAG,GAAG;YAC9B,iEAAiE;YACjE,IAAI,CAACkB,YAAYU,gBAAgB5B,MAAM,GAAG,GAAG;gBAC3CW,OAAOc,IAAI,CAAC;oBACV3B,OAAOiB;oBACPW,SAAS,GAAGL,WAAW,8BAA8B,CAAC;gBACxD;gBACA;YACF;YAEA,qCAAqC;YACrC,KAAK,MAAMY,eAAeL,gBAAiB;gBACzC,sCAAsC;gBACtC,IAAIX,aAAaA,UAAUjB,MAAM,GAAG,GAAG;oBACrC,MAAMkC,kBAAkBjB,UAAUkB,GAAG,CAAC,CAACC,IAAMA,EAAEC,QAAQ;oBAEvD,IAAI,CAAC7D,iBAAiByD,YAAYK,QAAQ,EAAEJ,kBAAkB;wBAC5DvB,OAAOc,IAAI,CAAC;4BACV3B,OAAOiB;4BACPW,SAAS,GAAGL,WAAW,aAAa,EAAEY,YAAYK,QAAQ,CAAC,iCAAiC,EAAEJ,gBAAgBK,IAAI,CAAC,OAAO;wBAC5H;wBACA;oBACF;gBACF;gBAEA,sCAAsC;gBACtC,IAAIvB,eAAeA,cAAc,KAAKiB,YAAYO,IAAI,GAAGxB,aAAa;oBACpE,MAAMyB,YAAY,AAACzB,CAAAA,cAAe,CAAA,OAAO,IAAG,CAAC,EAAG0B,OAAO,CAAC;oBACxD,MAAMC,aAAa,AAACV,CAAAA,YAAYO,IAAI,GAAI,CAAA,OAAO,IAAG,CAAC,EAAGE,OAAO,CAAC;oBAE9D/B,OAAOc,IAAI,CAAC;wBACV3B,OAAOiB;wBACPW,SAAS,GAAGL,WAAW,aAAa,EAAEsB,WAAW,kCAAkC,EAAEF,UAAU,GAAG,CAAC;oBACrG;oBACA;gBACF;gBAEA,6BAA6B;gBAC7B,+EAA+E;gBAC/E,gFAAgF;gBAChF,4EAA4E;gBAC5E,sEAAsE;gBACtE,IAAI;oBACF,MAAMG,WAAW,MAAM7D,QAAQ8D,MAAM,CAAC;wBACpCrD,YAAY4B;wBACZxC,MAAM,CAAC;wBACPkE,MAAM;4BACJ/B,MAAMkB,YAAYlB,IAAI;4BACtBnC,MAAMqD,YAAYrD,IAAI;4BACtB0D,UAAUL,YAAYK,QAAQ;4BAC9BE,MAAMP,YAAYO,IAAI;wBACxB;wBACA/C,gBAAgB;wBAChBX;oBACF;oBAEA+B,YAAYY,IAAI,CAAC;wBAAElC,IAAIqD,SAASrD,EAAE;wBAAEC,YAAY4B;oBAAiB;oBACjER,eAAeoB,GAAG,CAACjB,MAAOU,IAAI,CAAC;wBAAEsB,YAAY3B;wBAAkBZ,OAAOoC,SAASrD,EAAE;oBAAC;gBACpF,EAAE,OAAOyD,KAAK;oBACZ,MAAMC,eAAeD,eAAeE,QAAQF,IAAItB,OAAO,GAAG;oBAE1Df,OAAOc,IAAI,CAAC;wBACV3B,OAAOiB;wBACPW,SAAS,GAAGL,WAAW,0BAA0B,EAAE4B,cAAc;oBACnE;gBACF;YACF;QACF,OAAO,IAAIlB,sBAAsBA,mBAAmBvB,KAAK,EAAE;YACzD,0DAA0D;YAC1D,MAAM2C,iBAAiBpB,mBAAmBvB,KAAK;YAC/C,MAAM4C,oBACJ,OAAOD,mBAAmB,YAAY,OAAOA,mBAAmB,WAC5DE,OAAOF,kBACP;YAEN,IAAI,CAACC,mBAAmB;gBACtB,IAAIjC,UAAU;oBACZR,OAAOc,IAAI,CAAC;wBAAE3B,OAAOiB;wBAAMW,SAAS,GAAGL,WAAW,YAAY,CAAC;oBAAC;gBAClE;gBACA;YACF;YAEA,iFAAiF;YACjF,0FAA0F;YAC1F,IAAI,CAACH,YAAYkC,kBAAkB5B,QAAQ,CAAC,MAAM;gBAChDb,OAAOc,IAAI,CAAC;oBACV3B,OAAOiB;oBACPW,SAAS,GAAGL,WAAW,8BAA8B,CAAC;gBACxD;gBACA;YACF;YAEA,sDAAsD;YACtD,MAAMiC,UAAUpC,WACZkC,kBACGG,KAAK,CAAC,KACNpB,GAAG,CAAC,CAAC5C,KAAOA,GAAGiE,IAAI,IACnB3D,MAAM,CAAC4D,WACV;gBAACL;aAAkB;YAEvB,qBAAqB;YACrB,KAAK,MAAMM,UAAUJ,QAAS;gBAC5B,IAAIK,UAA0C;gBAC9C,IAAIC,cAAc;gBAElB,IAAI;oBACFD,UAAW,MAAM5E,QAAQO,QAAQ,CAAC;wBAChCC,IAAImE;wBACJlE,YAAY4B;wBACZ3B,gBAAgB;wBAChBX;oBACF;gBACF,EAAE,OAAM;oBACN6B,OAAOc,IAAI,CAAC;wBACV3B,OAAOiB;wBACPW,SAAS,GAAGL,WAAW,gBAAgB,EAAEqC,OAAO,2BAA2B,EAAEtC,iBAAiB,CAAC,CAAC;oBAClG;oBACAwC,cAAc;oBACd;gBACF;gBAEA,IAAI,CAACD,SAAS;oBACZhD,OAAOc,IAAI,CAAC;wBACV3B,OAAOiB;wBACPW,SAAS,GAAGL,WAAW,gBAAgB,EAAEqC,OAAO,WAAW,CAAC;oBAC9D;oBACAE,cAAc;oBACd;gBACF;gBAEA,oBAAoB;gBACpB,IAAI3C,aAAaA,UAAUjB,MAAM,GAAG,GAAG;oBACrC,MAAMkC,kBAAkBjB,UAAUkB,GAAG,CAAC,CAACC,IAAMA,EAAEC,QAAQ;oBACvD,MAAMwB,eAAeF,QAAQtB,QAAQ;oBAErC,IAAIwB,gBAAgB,CAACrF,iBAAiBqF,cAAc3B,kBAAkB;wBACpEvB,OAAOc,IAAI,CAAC;4BACV3B,OAAOiB;4BACPW,SAAS,GAAGL,WAAW,aAAa,EAAEwC,aAAa,iCAAiC,EAAE3B,gBAAgBK,IAAI,CAAC,OAAO;wBACpH;wBACAqB,cAAc;wBACd;oBACF;gBACF;gBAEA,qBAAqB;gBACrB,IAAI5C,eAAeA,cAAc,GAAG;oBAClC,MAAM8C,WAAWH,QAAQI,QAAQ;oBAEjC,IAAID,YAAYA,WAAW9C,aAAa;wBACtC,MAAMyB,YAAY,AAACzB,CAAAA,cAAe,CAAA,OAAO,IAAG,CAAC,EAAG0B,OAAO,CAAC;wBACxD,MAAMC,aAAa,AAACmB,CAAAA,WAAY,CAAA,OAAO,IAAG,CAAC,EAAGpB,OAAO,CAAC;wBAEtD/B,OAAOc,IAAI,CAAC;4BACV3B,OAAOiB;4BACPW,SAAS,GAAGL,WAAW,aAAa,EAAEsB,WAAW,kCAAkC,EAAEF,UAAU,GAAG,CAAC;wBACrG;wBACAmB,cAAc;oBAChB;gBACF;gBAEA,IAAIA,aAAa;oBACfhD,eAAeoB,GAAG,CAACjB,MAAOU,IAAI,CAAC;wBAAEsB,YAAY3B;wBAAkBZ,OAAOmD,QAAQpE,EAAE;oBAAC;gBACnF;YACF;QACF,OAAO,IAAI4B,UAAU;YACnB,wEAAwE;YACxER,OAAOc,IAAI,CAAC;gBACV3B,OAAOiB;gBACPW,SAAS,GAAGL,WAAW,YAAY,CAAC;YACtC;QACF;IACF;IAEA,IAAIV,OAAOX,MAAM,GAAG,GAAG;QACrB,wEAAwE;QACxE,KAAK,MAAMgE,OAAOnD,YAAa;YAC7B,IAAI;gBACF,MAAM9B,QAAQkF,MAAM,CAAC;oBAAE1E,IAAIyE,IAAIzE,EAAE;oBAAEC,YAAYwE,IAAIxE,UAAU;oBAAEC,gBAAgB;oBAAMX;gBAAI;YAC3F,EAAE,OAAM;YACN,yDAAyD;YAC3D;QACF;QAEA,MAAM,IAAIP,gBAAgB;YACxBiB,YAAYb,YAAYuF,yBAAyB7E,QAAQ;YACzDsB,QAAQA,OAAOwB,GAAG,CAAC,CAACgC,QAAW,CAAA;oBAC7BzC,SAASyC,MAAMzC,OAAO;oBACtB0C,MAAMD,MAAMrE,KAAK;gBACnB,CAAA;QACF;IACF;IAEA,sFAAsF;IACtF,MAAMuE,mBAAmB,IAAIC,IAAI1E,aAAauC,GAAG,CAAC,CAACoC,IAAMA,EAAExD,IAAI;IAC/D,MAAMyD,wBAAwBvE,oBAAoBJ,MAAM,CACtD,CAACQ,OAAS,CAACgE,iBAAiBI,GAAG,CAACpE,KAAKP,KAAK;IAG5C,qEAAqE;IACrE,MAAM4E,2BAA2B7C,MAAM8C,IAAI,CAAC/D,eAAegE,OAAO,IAC/D/E,MAAM,CAAC,CAAC,GAAGgF,MAAM,GAAKA,MAAM7E,MAAM,GAAG,GACrCmC,GAAG,CAAC,CAAC,CAACrC,OAAOU,MAAM,GAAM,CAAA;YAAEV;YAAOU;QAAM,CAAA;IAE3C,OAAO;QACL,GAAG5B,IAAI;QACPM,gBAAgBsF;QAChBM,mBAAmBJ;IACrB;AACF,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sendEmail.d.ts","sourceRoot":"","sources":["../../../../src/collections/FormSubmissions/hooks/sendEmail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AAExD,OAAO,KAAK,EAAyB,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAKvF,KAAK,iBAAiB,GAAG,UAAU,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAA;AAEjE,eAAO,MAAM,SAAS,0BACG,iBAAiB,cAC5B,uBAAuB,
|
|
1
|
+
{"version":3,"file":"sendEmail.d.ts","sourceRoot":"","sources":["../../../../src/collections/FormSubmissions/hooks/sendEmail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AAExD,OAAO,KAAK,EAAyB,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAKvF,KAAK,iBAAiB,GAAG,UAAU,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAA;AAEjE,eAAO,MAAM,SAAS,0BACG,iBAAiB,cAC5B,uBAAuB,kBA+FpC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/collections/FormSubmissions/hooks/sendEmail.ts"],"sourcesContent":["import type { CollectionAfterChangeHook } from 'payload'\n\nimport type { Email, FormattedEmail, FormBuilderPluginConfig } from '../../../types.js'\n\nimport { serializeLexical } from '../../../utilities/lexical/serializeLexical.js'\nimport { replaceDoubleCurlys } from '../../../utilities/replaceDoubleCurlys.js'\n\ntype AfterChangeParams = Parameters<CollectionAfterChangeHook>[0]\n\nexport const sendEmail = async (\n afterChangeParameters: AfterChangeParams,\n formConfig: FormBuilderPluginConfig,\n) => {\n if (afterChangeParameters.operation === 'create') {\n const {\n data,\n doc: { id: formSubmissionID },\n req: { locale, payload },\n req,\n } = afterChangeParameters\n\n const { form: formID, submissionData: submissionDataFromProps } = data || {}\n const { beforeEmail, defaultToEmail, formOverrides } = formConfig || {}\n\n try {\n const form = await payload.findByID({\n id: formID,\n collection: formOverrides?.slug || 'forms',\n locale,\n req,\n })\n\n const emails = form.emails as Email[]\n\n const submissionData = [\n ...submissionDataFromProps,\n {\n field: 'formSubmissionID',\n value: String(formSubmissionID),\n },\n ]\n\n if (emails && emails.length) {\n const formattedEmails: FormattedEmail[] = await Promise.all(\n emails.map(async (email: Email): Promise<FormattedEmail> => {\n const {\n bcc: emailBCC,\n cc: emailCC,\n emailFrom,\n emailTo: emailToFromConfig,\n message,\n replyTo: emailReplyTo,\n subject,\n } = email\n\n const emailTo = emailToFromConfig || defaultToEmail || payload.email.defaultFromAddress\n\n const to = replaceDoubleCurlys(emailTo, submissionData)\n const cc = emailCC ? replaceDoubleCurlys(emailCC, submissionData) : ''\n const bcc = emailBCC ? replaceDoubleCurlys(emailBCC, submissionData) : ''\n const from = replaceDoubleCurlys(emailFrom, submissionData)\n const replyTo = replaceDoubleCurlys(emailReplyTo || emailFrom, submissionData)\n\n const serializedMessage = await serializeLexical(message, submissionData)\n\n return {\n bcc,\n cc,\n from,\n html: `<div>${serializedMessage}</div>`,\n replyTo,\n subject: replaceDoubleCurlys(subject, submissionData),\n to,\n }\n }),\n )\n\n let emailsToSend = formattedEmails\n\n if (typeof beforeEmail === 'function') {\n emailsToSend = await beforeEmail(formattedEmails, afterChangeParameters)\n }\n\n await Promise.all(\n emailsToSend.map(async (email) => {\n const { to } = email\n try {\n const emailPromise = await payload.sendEmail(email)\n return emailPromise\n } catch (err: unknown) {\n payload.logger.error({\n err,\n msg: `Error while sending email to address: ${to}. Email not sent.`,\n })\n }\n }),\n )\n } else {\n payload.logger.info({ msg: 'No emails to send.' })\n }\n } catch (err: unknown) {\n const msg = `Error while sending one or more emails in form submission id: ${formSubmissionID}.`\n payload.logger.error({ err, msg })\n }\n }\n}\n"],"names":["serializeLexical","replaceDoubleCurlys","sendEmail","afterChangeParameters","formConfig","operation","data","doc","id","formSubmissionID","req","locale","payload","form","formID","submissionData","submissionDataFromProps","beforeEmail","defaultToEmail","formOverrides","findByID","collection","slug","emails","field","value","String","length","formattedEmails","Promise","all","map","email","bcc","emailBCC","cc","emailCC","emailFrom","emailTo","emailToFromConfig","message","replyTo","emailReplyTo","subject","defaultFromAddress","to","from","serializedMessage","html","emailsToSend","emailPromise","err","logger","error","msg","info"],"mappings":"AAIA,SAASA,gBAAgB,QAAQ,iDAAgD;AACjF,SAASC,mBAAmB,QAAQ,4CAA2C;AAI/E,OAAO,MAAMC,YAAY,OACvBC,uBACAC;IAEA,IAAID,sBAAsBE,SAAS,KAAK,UAAU;QAChD,MAAM,EACJC,IAAI,EACJC,KAAK,EAAEC,IAAIC,gBAAgB,EAAE,EAC7BC,KAAK,EAAEC,MAAM,EAAEC,OAAO,EAAE,EACxBF,GAAG,EACJ,GAAGP;QAEJ,MAAM,EAAEU,MAAMC,MAAM,EAAEC,gBAAgBC,uBAAuB,EAAE,GAAGV,QAAQ,CAAC;QAC3E,MAAM,EAAEW,WAAW,EAAEC,cAAc,EAAEC,aAAa,EAAE,GAAGf,cAAc,CAAC;QAEtE,IAAI;YACF,MAAMS,OAAO,MAAMD,QAAQQ,QAAQ,CAAC;gBAClCZ,IAAIM;gBACJO,YAAYF,eAAeG,QAAQ;gBACnCX;
|
|
1
|
+
{"version":3,"sources":["../../../../src/collections/FormSubmissions/hooks/sendEmail.ts"],"sourcesContent":["import type { CollectionAfterChangeHook } from 'payload'\n\nimport type { Email, FormattedEmail, FormBuilderPluginConfig } from '../../../types.js'\n\nimport { serializeLexical } from '../../../utilities/lexical/serializeLexical.js'\nimport { replaceDoubleCurlys } from '../../../utilities/replaceDoubleCurlys.js'\n\ntype AfterChangeParams = Parameters<CollectionAfterChangeHook>[0]\n\nexport const sendEmail = async (\n afterChangeParameters: AfterChangeParams,\n formConfig: FormBuilderPluginConfig,\n) => {\n if (afterChangeParameters.operation === 'create') {\n const {\n data,\n doc: { id: formSubmissionID },\n req: { locale, payload },\n req,\n } = afterChangeParameters\n\n const { form: formID, submissionData: submissionDataFromProps } = data || {}\n const { beforeEmail, defaultToEmail, formOverrides } = formConfig || {}\n\n try {\n const form = await payload.findByID({\n id: formID,\n collection: formOverrides?.slug || 'forms',\n locale,\n overrideAccess: true,\n req,\n })\n\n const emails = form.emails as Email[]\n\n const submissionData = [\n ...submissionDataFromProps,\n {\n field: 'formSubmissionID',\n value: String(formSubmissionID),\n },\n ]\n\n if (emails && emails.length) {\n const formattedEmails: FormattedEmail[] = await Promise.all(\n emails.map(async (email: Email): Promise<FormattedEmail> => {\n const {\n bcc: emailBCC,\n cc: emailCC,\n emailFrom,\n emailTo: emailToFromConfig,\n message,\n replyTo: emailReplyTo,\n subject,\n } = email\n\n const emailTo = emailToFromConfig || defaultToEmail || payload.email.defaultFromAddress\n\n const to = replaceDoubleCurlys(emailTo, submissionData)\n const cc = emailCC ? replaceDoubleCurlys(emailCC, submissionData) : ''\n const bcc = emailBCC ? replaceDoubleCurlys(emailBCC, submissionData) : ''\n const from = replaceDoubleCurlys(emailFrom, submissionData)\n const replyTo = replaceDoubleCurlys(emailReplyTo || emailFrom, submissionData)\n\n const serializedMessage = await serializeLexical(message, submissionData)\n\n return {\n bcc,\n cc,\n from,\n html: `<div>${serializedMessage}</div>`,\n replyTo,\n subject: replaceDoubleCurlys(subject, submissionData),\n to,\n }\n }),\n )\n\n let emailsToSend = formattedEmails\n\n if (typeof beforeEmail === 'function') {\n emailsToSend = await beforeEmail(formattedEmails, afterChangeParameters)\n }\n\n await Promise.all(\n emailsToSend.map(async (email) => {\n const { to } = email\n try {\n const emailPromise = await payload.sendEmail(email)\n return emailPromise\n } catch (err: unknown) {\n payload.logger.error({\n err,\n msg: `Error while sending email to address: ${to}. Email not sent.`,\n })\n }\n }),\n )\n } else {\n payload.logger.info({ msg: 'No emails to send.' })\n }\n } catch (err: unknown) {\n const msg = `Error while sending one or more emails in form submission id: ${formSubmissionID}.`\n payload.logger.error({ err, msg })\n }\n }\n}\n"],"names":["serializeLexical","replaceDoubleCurlys","sendEmail","afterChangeParameters","formConfig","operation","data","doc","id","formSubmissionID","req","locale","payload","form","formID","submissionData","submissionDataFromProps","beforeEmail","defaultToEmail","formOverrides","findByID","collection","slug","overrideAccess","emails","field","value","String","length","formattedEmails","Promise","all","map","email","bcc","emailBCC","cc","emailCC","emailFrom","emailTo","emailToFromConfig","message","replyTo","emailReplyTo","subject","defaultFromAddress","to","from","serializedMessage","html","emailsToSend","emailPromise","err","logger","error","msg","info"],"mappings":"AAIA,SAASA,gBAAgB,QAAQ,iDAAgD;AACjF,SAASC,mBAAmB,QAAQ,4CAA2C;AAI/E,OAAO,MAAMC,YAAY,OACvBC,uBACAC;IAEA,IAAID,sBAAsBE,SAAS,KAAK,UAAU;QAChD,MAAM,EACJC,IAAI,EACJC,KAAK,EAAEC,IAAIC,gBAAgB,EAAE,EAC7BC,KAAK,EAAEC,MAAM,EAAEC,OAAO,EAAE,EACxBF,GAAG,EACJ,GAAGP;QAEJ,MAAM,EAAEU,MAAMC,MAAM,EAAEC,gBAAgBC,uBAAuB,EAAE,GAAGV,QAAQ,CAAC;QAC3E,MAAM,EAAEW,WAAW,EAAEC,cAAc,EAAEC,aAAa,EAAE,GAAGf,cAAc,CAAC;QAEtE,IAAI;YACF,MAAMS,OAAO,MAAMD,QAAQQ,QAAQ,CAAC;gBAClCZ,IAAIM;gBACJO,YAAYF,eAAeG,QAAQ;gBACnCX;gBACAY,gBAAgB;gBAChBb;YACF;YAEA,MAAMc,SAASX,KAAKW,MAAM;YAE1B,MAAMT,iBAAiB;mBAClBC;gBACH;oBACES,OAAO;oBACPC,OAAOC,OAAOlB;gBAChB;aACD;YAED,IAAIe,UAAUA,OAAOI,MAAM,EAAE;gBAC3B,MAAMC,kBAAoC,MAAMC,QAAQC,GAAG,CACzDP,OAAOQ,GAAG,CAAC,OAAOC;oBAChB,MAAM,EACJC,KAAKC,QAAQ,EACbC,IAAIC,OAAO,EACXC,SAAS,EACTC,SAASC,iBAAiB,EAC1BC,OAAO,EACPC,SAASC,YAAY,EACrBC,OAAO,EACR,GAAGX;oBAEJ,MAAMM,UAAUC,qBAAqBtB,kBAAkBN,QAAQqB,KAAK,CAACY,kBAAkB;oBAEvF,MAAMC,KAAK7C,oBAAoBsC,SAASxB;oBACxC,MAAMqB,KAAKC,UAAUpC,oBAAoBoC,SAAStB,kBAAkB;oBACpE,MAAMmB,MAAMC,WAAWlC,oBAAoBkC,UAAUpB,kBAAkB;oBACvE,MAAMgC,OAAO9C,oBAAoBqC,WAAWvB;oBAC5C,MAAM2B,UAAUzC,oBAAoB0C,gBAAgBL,WAAWvB;oBAE/D,MAAMiC,oBAAoB,MAAMhD,iBAAiByC,SAAS1B;oBAE1D,OAAO;wBACLmB;wBACAE;wBACAW;wBACAE,MAAM,CAAC,KAAK,EAAED,kBAAkB,MAAM,CAAC;wBACvCN;wBACAE,SAAS3C,oBAAoB2C,SAAS7B;wBACtC+B;oBACF;gBACF;gBAGF,IAAII,eAAerB;gBAEnB,IAAI,OAAOZ,gBAAgB,YAAY;oBACrCiC,eAAe,MAAMjC,YAAYY,iBAAiB1B;gBACpD;gBAEA,MAAM2B,QAAQC,GAAG,CACfmB,aAAalB,GAAG,CAAC,OAAOC;oBACtB,MAAM,EAAEa,EAAE,EAAE,GAAGb;oBACf,IAAI;wBACF,MAAMkB,eAAe,MAAMvC,QAAQV,SAAS,CAAC+B;wBAC7C,OAAOkB;oBACT,EAAE,OAAOC,KAAc;wBACrBxC,QAAQyC,MAAM,CAACC,KAAK,CAAC;4BACnBF;4BACAG,KAAK,CAAC,sCAAsC,EAAET,GAAG,iBAAiB,CAAC;wBACrE;oBACF;gBACF;YAEJ,OAAO;gBACLlC,QAAQyC,MAAM,CAACG,IAAI,CAAC;oBAAED,KAAK;gBAAqB;YAClD;QACF,EAAE,OAAOH,KAAc;YACrB,MAAMG,MAAM,CAAC,8DAA8D,EAAE9C,iBAAiB,CAAC,CAAC;YAChGG,QAAQyC,MAAM,CAACC,KAAK,CAAC;gBAAEF;gBAAKG;YAAI;QAClC;IACF;AACF,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/collections/FormSubmissions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8B,gBAAgB,EAAS,MAAM,SAAS,CAAA;AAElF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAQ7D,eAAO,MAAM,4BAA4B,eAC3B,uBAAuB,KAClC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/collections/FormSubmissions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8B,gBAAgB,EAAS,MAAM,SAAS,CAAA;AAElF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAQ7D,eAAO,MAAM,4BAA4B,eAC3B,uBAAuB,KAClC,gBAkIF,CAAA"}
|
|
@@ -24,6 +24,7 @@ export const generateSubmissionCollection = (formConfig)=>{
|
|
|
24
24
|
_existingForm = await payload.findByID({
|
|
25
25
|
id: value,
|
|
26
26
|
collection: formSlug,
|
|
27
|
+
overrideAccess: true,
|
|
27
28
|
req
|
|
28
29
|
});
|
|
29
30
|
return true;
|
|
@@ -91,7 +92,7 @@ export const generateSubmissionCollection = (formConfig)=>{
|
|
|
91
92
|
slug: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',
|
|
92
93
|
access: {
|
|
93
94
|
create: ()=>true,
|
|
94
|
-
read: ({ req
|
|
95
|
+
read: ({ req })=>req.user?.collection === req.payload.config.admin.user,
|
|
95
96
|
update: ()=>false,
|
|
96
97
|
...formConfig?.formSubmissionOverrides?.access || {}
|
|
97
98
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/collections/FormSubmissions/index.ts"],"sourcesContent":["import type { CollectionBeforeChangeHook, CollectionConfig, Field } from 'payload'\n\nimport type { FormBuilderPluginConfig } from '../../types.js'\n\nimport { defaultPaymentFields } from './fields/defaultPaymentFields.js'\nimport { createCharge } from './hooks/createCharge.js'\nimport { handleUploads } from './hooks/handleUploads.js'\nimport { sendEmail } from './hooks/sendEmail.js'\n\n// all settings can be overridden by the config\nexport const generateSubmissionCollection = (\n formConfig: FormBuilderPluginConfig,\n): CollectionConfig => {\n const formSlug = formConfig?.formOverrides?.slug || 'forms'\n\n const enablePaymentFields = Boolean(formConfig?.fields?.payment)\n\n const uploadCollections = formConfig?.uploadCollections\n\n const defaultFields: Field[] = [\n {\n name: 'form',\n type: 'relationship',\n relationTo: formSlug,\n required: true,\n // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve\n validate: async (value, { req: { payload }, req }) => {\n /* Don't run in the client side */\n if (!payload) {\n return true\n }\n\n if (payload) {\n let _existingForm\n\n try {\n _existingForm = await payload.findByID({\n id: value,\n collection: formSlug,\n req,\n })\n\n return true\n } catch (_error) {\n return 'Cannot create this submission because this form does not exist.'\n }\n }\n },\n },\n {\n name: 'submissionData',\n type: 'array',\n fields: [\n {\n name: 'field',\n type: 'text',\n required: true,\n },\n {\n name: 'value',\n type: 'textarea',\n required: true,\n validate: (value: unknown) => {\n // TODO:\n // create a validation function that dynamically\n // relies on the field type and its options as configured.\n\n // How to access sibling data from this field?\n // Need the `name` of the field in order to validate it.\n\n // Might not be possible to use this validation function.\n // Instead, might need to do all validation in a `beforeValidate` collection hook.\n\n if (typeof value !== 'undefined') {\n return true\n }\n\n return 'This field is required.'\n },\n },\n ],\n },\n ...(uploadCollections && uploadCollections.length > 0\n ? ([\n {\n name: 'submissionUploads',\n type: 'array',\n fields: [\n {\n name: 'field',\n type: 'text',\n required: true,\n },\n {\n name: 'value',\n type: 'upload',\n hasMany: true,\n relationTo: uploadCollections,\n required: true,\n },\n ],\n },\n ] as Field[])\n : []),\n ...(enablePaymentFields ? [defaultPaymentFields] : []),\n ]\n\n const newConfig: CollectionConfig = {\n ...(formConfig?.formSubmissionOverrides || {}),\n slug: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',\n access: {\n create: () => true,\n read: ({ req
|
|
1
|
+
{"version":3,"sources":["../../../src/collections/FormSubmissions/index.ts"],"sourcesContent":["import type { CollectionBeforeChangeHook, CollectionConfig, Field } from 'payload'\n\nimport type { FormBuilderPluginConfig } from '../../types.js'\n\nimport { defaultPaymentFields } from './fields/defaultPaymentFields.js'\nimport { createCharge } from './hooks/createCharge.js'\nimport { handleUploads } from './hooks/handleUploads.js'\nimport { sendEmail } from './hooks/sendEmail.js'\n\n// all settings can be overridden by the config\nexport const generateSubmissionCollection = (\n formConfig: FormBuilderPluginConfig,\n): CollectionConfig => {\n const formSlug = formConfig?.formOverrides?.slug || 'forms'\n\n const enablePaymentFields = Boolean(formConfig?.fields?.payment)\n\n const uploadCollections = formConfig?.uploadCollections\n\n const defaultFields: Field[] = [\n {\n name: 'form',\n type: 'relationship',\n relationTo: formSlug,\n required: true,\n // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve\n validate: async (value, { req: { payload }, req }) => {\n /* Don't run in the client side */\n if (!payload) {\n return true\n }\n\n if (payload) {\n let _existingForm\n\n try {\n _existingForm = await payload.findByID({\n id: value,\n collection: formSlug,\n overrideAccess: true,\n req,\n })\n\n return true\n } catch (_error) {\n return 'Cannot create this submission because this form does not exist.'\n }\n }\n },\n },\n {\n name: 'submissionData',\n type: 'array',\n fields: [\n {\n name: 'field',\n type: 'text',\n required: true,\n },\n {\n name: 'value',\n type: 'textarea',\n required: true,\n validate: (value: unknown) => {\n // TODO:\n // create a validation function that dynamically\n // relies on the field type and its options as configured.\n\n // How to access sibling data from this field?\n // Need the `name` of the field in order to validate it.\n\n // Might not be possible to use this validation function.\n // Instead, might need to do all validation in a `beforeValidate` collection hook.\n\n if (typeof value !== 'undefined') {\n return true\n }\n\n return 'This field is required.'\n },\n },\n ],\n },\n ...(uploadCollections && uploadCollections.length > 0\n ? ([\n {\n name: 'submissionUploads',\n type: 'array',\n fields: [\n {\n name: 'field',\n type: 'text',\n required: true,\n },\n {\n name: 'value',\n type: 'upload',\n hasMany: true,\n relationTo: uploadCollections,\n required: true,\n },\n ],\n },\n ] as Field[])\n : []),\n ...(enablePaymentFields ? [defaultPaymentFields] : []),\n ]\n\n const newConfig: CollectionConfig = {\n ...(formConfig?.formSubmissionOverrides || {}),\n slug: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',\n access: {\n create: () => true,\n read: ({ req }) => req.user?.collection === req.payload.config.admin.user,\n update: () => false,\n ...(formConfig?.formSubmissionOverrides?.access || {}),\n },\n admin: {\n ...(formConfig?.formSubmissionOverrides?.admin || {}),\n enableRichTextRelationship: false,\n },\n fields:\n formConfig?.formSubmissionOverrides?.fields &&\n typeof formConfig?.formSubmissionOverrides?.fields === 'function'\n ? formConfig.formSubmissionOverrides.fields({ defaultFields })\n : defaultFields,\n hooks: {\n ...(formConfig?.formSubmissionOverrides?.hooks || {}),\n afterChange: [\n (data) => sendEmail(data, formConfig),\n ...(formConfig?.formSubmissionOverrides?.hooks?.afterChange || []),\n ],\n beforeChange: [\n ...(uploadCollections && uploadCollections.length > 0\n ? [(data: Parameters<CollectionBeforeChangeHook>[0]) => handleUploads(data, formConfig)]\n : []),\n (data) => createCharge(data, formConfig),\n ...(formConfig?.formSubmissionOverrides?.hooks?.beforeChange || []),\n ],\n },\n }\n return newConfig\n}\n"],"names":["defaultPaymentFields","createCharge","handleUploads","sendEmail","generateSubmissionCollection","formConfig","formSlug","formOverrides","slug","enablePaymentFields","Boolean","fields","payment","uploadCollections","defaultFields","name","type","relationTo","required","validate","value","req","payload","_existingForm","findByID","id","collection","overrideAccess","_error","length","hasMany","newConfig","formSubmissionOverrides","access","create","read","user","config","admin","update","enableRichTextRelationship","hooks","afterChange","data","beforeChange"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { TextFieldClientProps } from 'payload';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export declare const DynamicPriceSelector: React.FC<TextFieldClientProps>;
|
|
3
4
|
//# sourceMappingURL=DynamicPriceSelector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DynamicPriceSelector.d.ts","sourceRoot":"","sources":["../../../src/collections/Forms/DynamicPriceSelector.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAQ,
|
|
1
|
+
{"version":3,"file":"DynamicPriceSelector.d.ts","sourceRoot":"","sources":["../../../src/collections/Forms/DynamicPriceSelector.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAQ,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAGzD,OAAO,KAA8B,MAAM,OAAO,CAAA;AAOlD,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2D/D,CAAA"}
|
|
@@ -36,7 +36,7 @@ export const DynamicPriceSelector = (props)=>{
|
|
|
36
36
|
...props
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
-
const localeCode =
|
|
39
|
+
const localeCode = locale?.code ?? 'en';
|
|
40
40
|
const localLabels = typeof field.label === 'object' ? field.label : {
|
|
41
41
|
[localeCode]: field.label
|
|
42
42
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/collections/Forms/DynamicPriceSelector.tsx"],"sourcesContent":["'use client'\n\nimport type { Data,
|
|
1
|
+
{"version":3,"sources":["../../../src/collections/Forms/DynamicPriceSelector.tsx"],"sourcesContent":["'use client'\n\nimport type { Data, TextFieldClientProps } from 'payload'\n\nimport { TextField, useLocale, useWatchForm } from '@payloadcms/ui'\nimport React, { useEffect, useState } from 'react'\n\ntype FieldWithID = {\n id: string\n name: string\n}\n\nexport const DynamicPriceSelector: React.FC<TextFieldClientProps> = (props) => {\n const { field, path } = props\n\n const { fields, getData, getDataByPath } = useWatchForm()\n\n const locale = useLocale()\n\n const [isNumberField, setIsNumberField] = useState<boolean>()\n const [valueType, setValueType] = useState<'static' | 'valueOfField'>()\n\n // only number fields can use 'valueOfField`\n useEffect(() => {\n if (path) {\n const parentPath = path.split('.').slice(0, -1).join('.')\n const paymentFieldData: any = getDataByPath(parentPath)\n\n if (paymentFieldData) {\n const { fieldToUse, valueType } = paymentFieldData\n\n setValueType(valueType)\n\n const { fields: allFields }: Data = getData()\n const field = allFields.find((field: FieldWithID) => field.name === fieldToUse)\n\n if (field) {\n const { blockType } = field\n setIsNumberField(blockType === 'number')\n }\n }\n }\n }, [fields, getDataByPath, getData, path])\n\n // TODO: make this a number field, block by Payload\n if (valueType === 'static') {\n return <TextField {...props} />\n }\n\n const localeCode = locale?.code ?? 'en'\n\n const localLabels = typeof field.label === 'object' ? field.label : { [localeCode]: field.label }\n\n const labelValue = localLabels[localeCode] || localLabels['en'] || ''\n\n if (valueType === 'valueOfField' && !isNumberField) {\n return (\n <div>\n <div>{String(labelValue)}</div>\n <div\n style={{\n color: '#9A9A9A',\n }}\n >\n The selected field must be a number field.\n </div>\n </div>\n )\n }\n\n return null\n}\n"],"names":["TextField","useLocale","useWatchForm","React","useEffect","useState","DynamicPriceSelector","props","field","path","fields","getData","getDataByPath","locale","isNumberField","setIsNumberField","valueType","setValueType","parentPath","split","slice","join","paymentFieldData","fieldToUse","allFields","find","name","blockType","localeCode","code","localLabels","label","labelValue","div","String","style","color"],"mappings":"AAAA;;AAIA,SAASA,SAAS,EAAEC,SAAS,EAAEC,YAAY,QAAQ,iBAAgB;AACnE,OAAOC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAOlD,OAAO,MAAMC,uBAAuD,CAACC;IACnE,MAAM,EAAEC,KAAK,EAAEC,IAAI,EAAE,GAAGF;IAExB,MAAM,EAAEG,MAAM,EAAEC,OAAO,EAAEC,aAAa,EAAE,GAAGV;IAE3C,MAAMW,SAASZ;IAEf,MAAM,CAACa,eAAeC,iBAAiB,GAAGV;IAC1C,MAAM,CAACW,WAAWC,aAAa,GAAGZ;IAElC,4CAA4C;IAC5CD,UAAU;QACR,IAAIK,MAAM;YACR,MAAMS,aAAaT,KAAKU,KAAK,CAAC,KAAKC,KAAK,CAAC,GAAG,CAAC,GAAGC,IAAI,CAAC;YACrD,MAAMC,mBAAwBV,cAAcM;YAE5C,IAAII,kBAAkB;gBACpB,MAAM,EAAEC,UAAU,EAAEP,SAAS,EAAE,GAAGM;gBAElCL,aAAaD;gBAEb,MAAM,EAAEN,QAAQc,SAAS,EAAE,GAASb;gBACpC,MAAMH,QAAQgB,UAAUC,IAAI,CAAC,CAACjB,QAAuBA,MAAMkB,IAAI,KAAKH;gBAEpE,IAAIf,OAAO;oBACT,MAAM,EAAEmB,SAAS,EAAE,GAAGnB;oBACtBO,iBAAiBY,cAAc;gBACjC;YACF;QACF;IACF,GAAG;QAACjB;QAAQE;QAAeD;QAASF;KAAK;IAEzC,mDAAmD;IACnD,IAAIO,cAAc,UAAU;QAC1B,qBAAO,KAAChB;YAAW,GAAGO,KAAK;;IAC7B;IAEA,MAAMqB,aAAaf,QAAQgB,QAAQ;IAEnC,MAAMC,cAAc,OAAOtB,MAAMuB,KAAK,KAAK,WAAWvB,MAAMuB,KAAK,GAAG;QAAE,CAACH,WAAW,EAAEpB,MAAMuB,KAAK;IAAC;IAEhG,MAAMC,aAAaF,WAAW,CAACF,WAAW,IAAIE,WAAW,CAAC,KAAK,IAAI;IAEnE,IAAId,cAAc,kBAAkB,CAACF,eAAe;QAClD,qBACE,MAACmB;;8BACC,KAACA;8BAAKC,OAAOF;;8BACb,KAACC;oBACCE,OAAO;wBACLC,OAAO;oBACT;8BACD;;;;IAKP;IAEA,OAAO;AACT,EAAC"}
|
|
@@ -178,7 +178,7 @@ export const generateFormCollection = (formConfig, collections)=>{
|
|
|
178
178
|
name: 'emails',
|
|
179
179
|
type: 'array',
|
|
180
180
|
access: {
|
|
181
|
-
read: ({ req
|
|
181
|
+
read: ({ req })=>req.user?.collection === req.payload.config.admin.user
|
|
182
182
|
},
|
|
183
183
|
admin: {
|
|
184
184
|
description: ({ t })=>// @ts-expect-error - translations are not typed in plugins yet
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/collections/Forms/index.ts"],"sourcesContent":["import type { Block, CollectionConfig, Config, Field } from 'payload'\n\nimport { deepMergeWithSourceArrays } from 'payload'\n\nimport type { FormBuilderPluginConfig } from '../../types.js'\n\nimport { fields } from './fields.js'\n\nconst applyUploadCollectionLabels = (args: {\n block: Block\n collections: Config['collections']\n uploadCollections: FormBuilderPluginConfig['uploadCollections']\n}): Block => {\n const { block, collections, uploadCollections } = args\n const collectionsBySlug = new Map(\n (collections || []).map((collection) => [collection.slug, collection]),\n )\n\n for (const field of block.fields) {\n if ('name' in field && field.name === 'uploadCollection' && field.type === 'select') {\n // Replace the default slug labels with the source collection's labels.singular.\n // Select option labels accept strings, locale records and label functions —\n // Payload's admin resolves them at render time via getTranslation.\n field.options = (uploadCollections || []).map((slug) => {\n const singular = collectionsBySlug.get(slug)?.labels?.singular\n return { label: singular ?? slug, value: slug }\n })\n break\n }\n }\n\n return block\n}\n\n// all settings can be overridden by the config\nexport const generateFormCollection = (\n formConfig: FormBuilderPluginConfig,\n collections?: Config['collections'],\n): CollectionConfig => {\n const redirect: Field = {\n name: 'redirect',\n type: 'group',\n admin: {\n condition: (_, siblingData) => siblingData?.confirmationType === 'redirect',\n hideGutter: true,\n },\n fields: [\n {\n name: 'url',\n type: 'text',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:urlToRedirectTo'),\n required: true,\n },\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:redirect'),\n }\n\n if (formConfig.redirectRelationships) {\n redirect.fields.unshift({\n name: 'reference',\n type: 'relationship',\n admin: {\n condition: (_, siblingData) => siblingData?.type === 'reference',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:documentToLinkTo'),\n maxDepth: 2,\n relationTo: formConfig.redirectRelationships,\n required: true,\n })\n\n redirect.fields.unshift({\n name: 'type',\n type: 'radio',\n admin: {\n layout: 'horizontal',\n },\n defaultValue: 'reference',\n options: [\n {\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:internalLink'),\n value: 'reference',\n },\n {\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:customURL'),\n value: 'custom',\n },\n ],\n })\n\n if (redirect.fields[2]!.type !== 'row') {\n redirect.fields[2]!.label = ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:customURL')\n }\n\n redirect.fields[2]!.admin = {\n condition: (_, siblingData) => siblingData?.type === 'custom',\n }\n }\n\n const defaultFields: Field[] = [\n {\n name: 'title',\n type: 'text',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:title'),\n required: true,\n },\n {\n name: 'fields',\n type: 'blocks',\n blocks: Object.entries(formConfig?.fields || {})\n .map(([fieldKey, fieldConfig]) => {\n // let the config enable/disable fields with either boolean values or objects\n if (fieldConfig !== false) {\n const block = fields[fieldKey]\n\n if (block === undefined && typeof fieldConfig === 'object') {\n return fieldConfig\n }\n\n if (typeof block === 'object' && typeof fieldConfig === 'object') {\n return deepMergeWithSourceArrays(block, fieldConfig)\n }\n\n if (typeof block === 'function') {\n // Special handling for upload field - factory takes slug list; after it runs,\n // inject resolved collection labels into the uploadCollection select.\n if (fieldKey === 'upload') {\n return applyUploadCollectionLabels({\n block: block(formConfig.uploadCollections || []),\n collections,\n uploadCollections: formConfig.uploadCollections,\n })\n }\n return block(fieldConfig)\n }\n\n return block\n }\n\n return null\n })\n .filter(Boolean) as Block[],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:fields'),\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:fields'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:field'),\n },\n },\n {\n name: 'submitButtonLabel',\n type: 'text',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:submitButton'),\n localized: true,\n },\n {\n name: 'confirmationType',\n type: 'radio',\n admin: {\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:chooseConfirmationType'),\n layout: 'horizontal',\n },\n defaultValue: 'message',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:confirmationType'),\n options: [\n {\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:message'),\n value: 'message',\n },\n {\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:redirect'),\n value: 'redirect',\n },\n ],\n },\n {\n name: 'confirmationMessage',\n type: 'richText',\n admin: {\n condition: (_, siblingData) => siblingData?.confirmationType === 'message',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:confirmationMessage'),\n localized: true,\n required: true,\n },\n redirect,\n {\n name: 'emails',\n type: 'array',\n access: {\n read: ({ req: { user } }) => !!user,\n },\n admin: {\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:emailsDescription'),\n },\n fields: [\n {\n type: 'row',\n fields: [\n {\n name: 'emailTo',\n type: 'text',\n admin: {\n placeholder: '\"Email Sender\" <sender@email.com>',\n width: '100%',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:emailTo'),\n },\n {\n name: 'cc',\n type: 'text',\n admin: {\n style: {\n maxWidth: '50%',\n },\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:cc'),\n },\n {\n name: 'bcc',\n type: 'text',\n admin: {\n style: {\n maxWidth: '50%',\n },\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:bcc'),\n },\n ],\n },\n {\n type: 'row',\n fields: [\n {\n name: 'replyTo',\n type: 'text',\n admin: {\n placeholder: '\"Reply To\" <reply-to@email.com>',\n width: '50%',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:replyTo'),\n },\n {\n name: 'emailFrom',\n type: 'text',\n admin: {\n placeholder: '\"Email From\" <email-from@email.com>',\n width: '50%',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:emailFrom'),\n },\n ],\n },\n {\n name: 'subject',\n type: 'text',\n defaultValue: \"You've received a new message.\",\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:subject'),\n localized: true,\n required: true,\n },\n {\n name: 'message',\n type: 'richText',\n admin: {\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:messageDescription'),\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:message'),\n localized: true,\n },\n ],\n },\n ]\n\n const config: CollectionConfig = {\n ...(formConfig?.formOverrides || {}),\n slug: formConfig?.formOverrides?.slug || 'forms',\n access: {\n read: () => true,\n ...(formConfig?.formOverrides?.access || {}),\n },\n admin: {\n enableRichTextRelationship: false,\n useAsTitle: 'title',\n ...(formConfig?.formOverrides?.admin || {}),\n },\n fields:\n formConfig?.formOverrides?.fields && typeof formConfig?.formOverrides?.fields === 'function'\n ? formConfig.formOverrides.fields({ defaultFields })\n : defaultFields,\n }\n\n return config\n}\n"],"names":["deepMergeWithSourceArrays","fields","applyUploadCollectionLabels","args","block","collections","uploadCollections","collectionsBySlug","Map","map","collection","slug","field","name","type","options","singular","get","labels","label","value","generateFormCollection","formConfig","redirect","admin","condition","_","siblingData","confirmationType","hideGutter","t","required","redirectRelationships","unshift","maxDepth","relationTo","layout","defaultValue","defaultFields","blocks","Object","entries","fieldKey","fieldConfig","undefined","filter","Boolean","plural","localized","description","access","read","req","user","placeholder","width","style","maxWidth","config","formOverrides","enableRichTextRelationship","useAsTitle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/collections/Forms/index.ts"],"sourcesContent":["import type { Block, CollectionConfig, Config, Field } from 'payload'\n\nimport { deepMergeWithSourceArrays } from 'payload'\n\nimport type { FormBuilderPluginConfig } from '../../types.js'\n\nimport { fields } from './fields.js'\n\nconst applyUploadCollectionLabels = (args: {\n block: Block\n collections: Config['collections']\n uploadCollections: FormBuilderPluginConfig['uploadCollections']\n}): Block => {\n const { block, collections, uploadCollections } = args\n const collectionsBySlug = new Map(\n (collections || []).map((collection) => [collection.slug, collection]),\n )\n\n for (const field of block.fields) {\n if ('name' in field && field.name === 'uploadCollection' && field.type === 'select') {\n // Replace the default slug labels with the source collection's labels.singular.\n // Select option labels accept strings, locale records and label functions —\n // Payload's admin resolves them at render time via getTranslation.\n field.options = (uploadCollections || []).map((slug) => {\n const singular = collectionsBySlug.get(slug)?.labels?.singular\n return { label: singular ?? slug, value: slug }\n })\n break\n }\n }\n\n return block\n}\n\n// all settings can be overridden by the config\nexport const generateFormCollection = (\n formConfig: FormBuilderPluginConfig,\n collections?: Config['collections'],\n): CollectionConfig => {\n const redirect: Field = {\n name: 'redirect',\n type: 'group',\n admin: {\n condition: (_, siblingData) => siblingData?.confirmationType === 'redirect',\n hideGutter: true,\n },\n fields: [\n {\n name: 'url',\n type: 'text',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:urlToRedirectTo'),\n required: true,\n },\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:redirect'),\n }\n\n if (formConfig.redirectRelationships) {\n redirect.fields.unshift({\n name: 'reference',\n type: 'relationship',\n admin: {\n condition: (_, siblingData) => siblingData?.type === 'reference',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:documentToLinkTo'),\n maxDepth: 2,\n relationTo: formConfig.redirectRelationships,\n required: true,\n })\n\n redirect.fields.unshift({\n name: 'type',\n type: 'radio',\n admin: {\n layout: 'horizontal',\n },\n defaultValue: 'reference',\n options: [\n {\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:internalLink'),\n value: 'reference',\n },\n {\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:customURL'),\n value: 'custom',\n },\n ],\n })\n\n if (redirect.fields[2]!.type !== 'row') {\n redirect.fields[2]!.label = ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:customURL')\n }\n\n redirect.fields[2]!.admin = {\n condition: (_, siblingData) => siblingData?.type === 'custom',\n }\n }\n\n const defaultFields: Field[] = [\n {\n name: 'title',\n type: 'text',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:title'),\n required: true,\n },\n {\n name: 'fields',\n type: 'blocks',\n blocks: Object.entries(formConfig?.fields || {})\n .map(([fieldKey, fieldConfig]) => {\n // let the config enable/disable fields with either boolean values or objects\n if (fieldConfig !== false) {\n const block = fields[fieldKey]\n\n if (block === undefined && typeof fieldConfig === 'object') {\n return fieldConfig\n }\n\n if (typeof block === 'object' && typeof fieldConfig === 'object') {\n return deepMergeWithSourceArrays(block, fieldConfig)\n }\n\n if (typeof block === 'function') {\n // Special handling for upload field - factory takes slug list; after it runs,\n // inject resolved collection labels into the uploadCollection select.\n if (fieldKey === 'upload') {\n return applyUploadCollectionLabels({\n block: block(formConfig.uploadCollections || []),\n collections,\n uploadCollections: formConfig.uploadCollections,\n })\n }\n return block(fieldConfig)\n }\n\n return block\n }\n\n return null\n })\n .filter(Boolean) as Block[],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:fields'),\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:fields'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:field'),\n },\n },\n {\n name: 'submitButtonLabel',\n type: 'text',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:submitButton'),\n localized: true,\n },\n {\n name: 'confirmationType',\n type: 'radio',\n admin: {\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:chooseConfirmationType'),\n layout: 'horizontal',\n },\n defaultValue: 'message',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:confirmationType'),\n options: [\n {\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:message'),\n value: 'message',\n },\n {\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:redirect'),\n value: 'redirect',\n },\n ],\n },\n {\n name: 'confirmationMessage',\n type: 'richText',\n admin: {\n condition: (_, siblingData) => siblingData?.confirmationType === 'message',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:confirmationMessage'),\n localized: true,\n required: true,\n },\n redirect,\n {\n name: 'emails',\n type: 'array',\n access: {\n read: ({ req }) => req.user?.collection === req.payload.config.admin.user,\n },\n admin: {\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:emailsDescription'),\n },\n fields: [\n {\n type: 'row',\n fields: [\n {\n name: 'emailTo',\n type: 'text',\n admin: {\n placeholder: '\"Email Sender\" <sender@email.com>',\n width: '100%',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:emailTo'),\n },\n {\n name: 'cc',\n type: 'text',\n admin: {\n style: {\n maxWidth: '50%',\n },\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:cc'),\n },\n {\n name: 'bcc',\n type: 'text',\n admin: {\n style: {\n maxWidth: '50%',\n },\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:bcc'),\n },\n ],\n },\n {\n type: 'row',\n fields: [\n {\n name: 'replyTo',\n type: 'text',\n admin: {\n placeholder: '\"Reply To\" <reply-to@email.com>',\n width: '50%',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:replyTo'),\n },\n {\n name: 'emailFrom',\n type: 'text',\n admin: {\n placeholder: '\"Email From\" <email-from@email.com>',\n width: '50%',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:emailFrom'),\n },\n ],\n },\n {\n name: 'subject',\n type: 'text',\n defaultValue: \"You've received a new message.\",\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:subject'),\n localized: true,\n required: true,\n },\n {\n name: 'message',\n type: 'richText',\n admin: {\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:messageDescription'),\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-form-builder:message'),\n localized: true,\n },\n ],\n },\n ]\n\n const config: CollectionConfig = {\n ...(formConfig?.formOverrides || {}),\n slug: formConfig?.formOverrides?.slug || 'forms',\n access: {\n read: () => true,\n ...(formConfig?.formOverrides?.access || {}),\n },\n admin: {\n enableRichTextRelationship: false,\n useAsTitle: 'title',\n ...(formConfig?.formOverrides?.admin || {}),\n },\n fields:\n formConfig?.formOverrides?.fields && typeof formConfig?.formOverrides?.fields === 'function'\n ? formConfig.formOverrides.fields({ defaultFields })\n : defaultFields,\n }\n\n return config\n}\n"],"names":["deepMergeWithSourceArrays","fields","applyUploadCollectionLabels","args","block","collections","uploadCollections","collectionsBySlug","Map","map","collection","slug","field","name","type","options","singular","get","labels","label","value","generateFormCollection","formConfig","redirect","admin","condition","_","siblingData","confirmationType","hideGutter","t","required","redirectRelationships","unshift","maxDepth","relationTo","layout","defaultValue","defaultFields","blocks","Object","entries","fieldKey","fieldConfig","undefined","filter","Boolean","plural","localized","description","access","read","req","user","payload","config","placeholder","width","style","maxWidth","formOverrides","enableRichTextRelationship","useAsTitle"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/utilities/lexical/converters/link.ts"],"sourcesContent":["import escapeHTML from 'escape-html'\nimport { sanitizeUrl } from 'payload/shared'\n\nimport type { HTMLConverter } from '../types.js'\n\nimport { replaceDoubleCurlys } from '../../replaceDoubleCurlys.js'\nimport { convertLexicalNodesToHTML } from '../serializeLexical.js'\n\nexport const LinkHTMLConverter: HTMLConverter<any> = {\n async converter({ converters, node, parent, submissionData }) {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n lexicalNodes: node.children,\n parent: {\n ...node,\n parent,\n },\n submissionData,\n })\n\n let href: string =\n node.fields.linkType === 'custom'\n ? (node.fields.url ?? '')\n : (node.fields.doc?.value?.id ?? '')\n\n if (submissionData) {\n href = replaceDoubleCurlys(href, submissionData)\n }\n\n const safeHref = escapeHTML(sanitizeUrl(href))\n\n return `<a href=\"${safeHref}\"${node.fields.newTab ? ' rel=\"noopener noreferrer\" target=\"_blank\"' : ''}>${childrenText}</a>`\n },\n nodeTypes: ['link'],\n}\n"],"names":["escapeHTML","sanitizeUrl","replaceDoubleCurlys","convertLexicalNodesToHTML","LinkHTMLConverter","converter","converters","node","parent","submissionData","childrenText","lexicalNodes","children","href","fields","linkType","url","doc","value","id","safeHref","newTab","nodeTypes"],"mappings":"AAAA,OAAOA,gBAAgB,cAAa;AACpC,SAASC,WAAW,QAAQ,iBAAgB;AAI5C,SAASC,mBAAmB,QAAQ,+BAA8B;AAClE,SAASC,yBAAyB,QAAQ,yBAAwB;AAElE,OAAO,MAAMC,oBAAwC;IACnD,MAAMC,WAAU,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAEC,cAAc,EAAE;QAC1D,MAAMC,eAAe,MAAMP,0BAA0B;YACnDG;YACAK,cAAcJ,KAAKK,QAAQ;YAC3BJ,QAAQ;gBACN,GAAGD,IAAI;gBACPC;YACF;YACAC;QACF;QAEA,IAAII,OACFN,KAAKO,MAAM,CAACC,QAAQ,KAAK,WACpBR,KAAKO,MAAM,CAACE,GAAG,IAAI,KACnBT,KAAKO,MAAM,CAACG,GAAG,EAAEC,OAAOC,MAAM;QAErC,IAAIV,gBAAgB;YAClBI,OAAOX,oBAAoBW,MAAMJ;QACnC;QAEA,MAAMW,WAAWpB,WAAWC,YAAYY;QAExC,OAAO,CAAC,SAAS,EAAEO,SAAS,CAAC,EAAEb,KAAKO,MAAM,CAACO,MAAM,GAAG,+CAA+C,GAAG,CAAC,EAAEX,aAAa,IAAI,CAAC;IAC7H;IACAY,WAAW;QAAC;KAAO;
|
|
1
|
+
{"version":3,"sources":["../../../../src/utilities/lexical/converters/link.ts"],"sourcesContent":["import escapeHTML from 'escape-html'\nimport { sanitizeUrl } from 'payload/shared'\n\nimport type { HTMLConverter } from '../types.js'\n\nimport { replaceDoubleCurlys } from '../../replaceDoubleCurlys.js'\nimport { convertLexicalNodesToHTML } from '../serializeLexical.js'\n\nexport const LinkHTMLConverter: HTMLConverter<any> = {\n async converter({ converters, node, parent, submissionData }) {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n lexicalNodes: node.children,\n parent: {\n ...node,\n parent,\n },\n submissionData,\n })\n\n let href: string =\n node.fields.linkType === 'custom'\n ? (node.fields.url ?? '')\n : (node.fields.doc?.value?.id ?? '')\n\n if (submissionData) {\n href = replaceDoubleCurlys(href, submissionData)\n }\n\n const safeHref = escapeHTML(sanitizeUrl(href))\n\n return `<a href=\"${safeHref}\"${node.fields.newTab ? ' rel=\"noopener noreferrer\" target=\"_blank\"' : ''}>${childrenText}</a>`\n },\n nodeTypes: ['autolink', 'link'],\n}\n"],"names":["escapeHTML","sanitizeUrl","replaceDoubleCurlys","convertLexicalNodesToHTML","LinkHTMLConverter","converter","converters","node","parent","submissionData","childrenText","lexicalNodes","children","href","fields","linkType","url","doc","value","id","safeHref","newTab","nodeTypes"],"mappings":"AAAA,OAAOA,gBAAgB,cAAa;AACpC,SAASC,WAAW,QAAQ,iBAAgB;AAI5C,SAASC,mBAAmB,QAAQ,+BAA8B;AAClE,SAASC,yBAAyB,QAAQ,yBAAwB;AAElE,OAAO,MAAMC,oBAAwC;IACnD,MAAMC,WAAU,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAEC,cAAc,EAAE;QAC1D,MAAMC,eAAe,MAAMP,0BAA0B;YACnDG;YACAK,cAAcJ,KAAKK,QAAQ;YAC3BJ,QAAQ;gBACN,GAAGD,IAAI;gBACPC;YACF;YACAC;QACF;QAEA,IAAII,OACFN,KAAKO,MAAM,CAACC,QAAQ,KAAK,WACpBR,KAAKO,MAAM,CAACE,GAAG,IAAI,KACnBT,KAAKO,MAAM,CAACG,GAAG,EAAEC,OAAOC,MAAM;QAErC,IAAIV,gBAAgB;YAClBI,OAAOX,oBAAoBW,MAAMJ;QACnC;QAEA,MAAMW,WAAWpB,WAAWC,YAAYY;QAExC,OAAO,CAAC,SAAS,EAAEO,SAAS,CAAC,EAAEb,KAAKO,MAAM,CAACO,MAAM,GAAG,+CAA+C,GAAG,CAAC,EAAEX,aAAa,IAAI,CAAC;IAC7H;IACAY,WAAW;QAAC;QAAY;KAAO;AACjC,EAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-form-builder",
|
|
3
|
-
"version": "4.0.0-internal.
|
|
3
|
+
"version": "4.0.0-internal.cb69780",
|
|
4
4
|
"description": "Form builder plugin for Payload CMS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"payload",
|
|
@@ -63,22 +63,22 @@
|
|
|
63
63
|
],
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"escape-html": "^1.0.3",
|
|
66
|
-
"@payloadcms/
|
|
67
|
-
"@payloadcms/
|
|
66
|
+
"@payloadcms/ui": "4.0.0-internal.cb69780",
|
|
67
|
+
"@payloadcms/translations": "4.0.0-internal.cb69780"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/escape-html": "^1.0.4",
|
|
71
71
|
"@types/react": "19.2.14",
|
|
72
72
|
"@types/react-dom": "19.2.3",
|
|
73
|
-
"copyfiles": "
|
|
73
|
+
"copyfiles": "2.4.1",
|
|
74
74
|
"cross-env": "10.1.0",
|
|
75
|
-
"
|
|
76
|
-
"
|
|
75
|
+
"@payloadcms/eslint-config": "3.28.0",
|
|
76
|
+
"payload": "4.0.0-internal.cb69780"
|
|
77
77
|
},
|
|
78
78
|
"peerDependencies": {
|
|
79
79
|
"react": "^19.0.1 || ^19.1.2 || ^19.2.1",
|
|
80
80
|
"react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1",
|
|
81
|
-
"payload": "4.0.0-internal.
|
|
81
|
+
"payload": "4.0.0-internal.cb69780"
|
|
82
82
|
},
|
|
83
83
|
"publishConfig": {
|
|
84
84
|
"registry": "https://registry.npmjs.org/"
|