strapi-plugin-hubspot 0.16.5 → 0.16.8
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/CHANGELOG.md +27 -0
- package/dist/_chunks/{Forms-DyV6KyiO.mjs → Forms-CUNHDvhI.mjs} +52 -6
- package/dist/_chunks/{Forms-uUN4XjhW.js → Forms-CylJ0nD3.js} +52 -6
- package/dist/_chunks/{HubspotFormInput-BkWat_wu.js → HubspotFormInput-D2H2u9fZ.js} +1 -1
- package/dist/_chunks/{HubspotFormInput-DEXPX-6j.mjs → HubspotFormInput-Dppgr_rd.mjs} +1 -1
- package/dist/_chunks/{HubspotObjectInput-CFDYW-TM.js → HubspotObjectInput-BjRCaqXr.js} +3 -3
- package/dist/_chunks/{HubspotObjectInput-DL8fYK2x.mjs → HubspotObjectInput-CWFddNNw.mjs} +3 -3
- package/dist/_chunks/{HubspotPropertyInput-CFMkbQeT.js → HubspotPropertyInput-BlDarkcj.js} +3 -3
- package/dist/_chunks/{HubspotPropertyInput-WU5FMJj3.mjs → HubspotPropertyInput-TGG9ozTa.mjs} +3 -3
- package/dist/_chunks/{Settings-B_hhdpHa.js → Settings-DOx7YSqA.js} +2 -2
- package/dist/_chunks/{Settings-CiXEps_C.mjs → Settings-tct49GYU.mjs} +2 -2
- package/dist/_chunks/{index-BeBn7bJa.mjs → index-Au3W85GX.mjs} +5 -5
- package/dist/_chunks/{index-CG_WQzSa.js → index-DhGVA3ZL.js} +5 -5
- package/dist/_chunks/{objectLabels-CS_0QCNz.mjs → objectLabels-3rnJ0WUc.mjs} +1 -1
- package/dist/_chunks/{objectLabels-BGq-Ypgn.js → objectLabels-Bx7x8fFO.js} +1 -1
- package/dist/_chunks/{useHubspotSchema-CP7LRdzO.mjs → useHubspotSchema-BlVXfwju.mjs} +1 -1
- package/dist/_chunks/{useHubspotSchema-BZP2qkAu.js → useHubspotSchema-DrGeidXC.js} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/builder/types.d.ts +2 -1
- package/dist/server/index.js +293 -43
- package/dist/server/index.mjs +293 -43
- package/dist/server/src/conditions.d.ts +1 -0
- package/dist/server/src/formSync.d.ts +20 -0
- package/dist/server/src/formsAdmin.d.ts +1 -0
- package/dist/server/src/hsforms.d.ts +35 -7
- package/dist/server/src/importHubspot.d.ts +2 -1
- package/dist/server/src/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -1600,6 +1600,48 @@ function missingMappedFields(definition, existingNames) {
|
|
|
1600
1600
|
const existing = new Set(existingNames);
|
|
1601
1601
|
return mappedContactFields(definition).filter((field) => !existing.has(field.property));
|
|
1602
1602
|
}
|
|
1603
|
+
const OBJECT_TYPE_BY_NAME = {
|
|
1604
|
+
contact: "0-1",
|
|
1605
|
+
company: "0-2"
|
|
1606
|
+
};
|
|
1607
|
+
function collectedHubspotKeys(definition) {
|
|
1608
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1609
|
+
const add = (object, property) => {
|
|
1610
|
+
const typeId = OBJECT_TYPE_BY_NAME[object] || object;
|
|
1611
|
+
if (property) keys.add(`${typeId}:${property}`);
|
|
1612
|
+
};
|
|
1613
|
+
for (const step of definition.steps ?? []) {
|
|
1614
|
+
for (const fld of step.fields ?? []) {
|
|
1615
|
+
if (fld.type === "company") {
|
|
1616
|
+
const map = fld.companyMap ?? {};
|
|
1617
|
+
for (const slot of Object.values(map)) {
|
|
1618
|
+
if (slot?.property?.trim()) add(slot.object?.trim() || "company", slot.property.trim());
|
|
1619
|
+
}
|
|
1620
|
+
continue;
|
|
1621
|
+
}
|
|
1622
|
+
const mapping = fld.hubspot ?? {};
|
|
1623
|
+
const object = mapping.object?.trim() || "contact";
|
|
1624
|
+
const property = mapping.property?.trim() || fld.name;
|
|
1625
|
+
if (property) add(object, property);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
return keys;
|
|
1629
|
+
}
|
|
1630
|
+
function missingRequiredHubspotFields(definition, required) {
|
|
1631
|
+
const collected = collectedHubspotKeys(definition);
|
|
1632
|
+
const missing = [];
|
|
1633
|
+
for (const field of required) {
|
|
1634
|
+
if (!field.name) continue;
|
|
1635
|
+
const objectTypeId = field.objectTypeId?.trim() || "0-1";
|
|
1636
|
+
if (collected.has(`${objectTypeId}:${field.name}`)) continue;
|
|
1637
|
+
missing.push({
|
|
1638
|
+
name: field.name,
|
|
1639
|
+
objectTypeId,
|
|
1640
|
+
object: objectTypeId === "0-2" ? "company" : "contact"
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
return missing;
|
|
1644
|
+
}
|
|
1603
1645
|
function hsFieldType(type, options) {
|
|
1604
1646
|
switch (type) {
|
|
1605
1647
|
case "email":
|
|
@@ -1650,6 +1692,74 @@ function appendFieldGroups(existing, extra) {
|
|
|
1650
1692
|
}))
|
|
1651
1693
|
];
|
|
1652
1694
|
}
|
|
1695
|
+
function conditionToHubspot(condition, parentId) {
|
|
1696
|
+
const rules = (condition.rules ?? []).filter((rule) => rule.field === parentId);
|
|
1697
|
+
if (!rules.length || rules.length !== (condition.rules ?? []).length) return null;
|
|
1698
|
+
const op = rules[0]?.operator;
|
|
1699
|
+
if (rules.some((rule) => rule.operator !== op)) return null;
|
|
1700
|
+
const values = rules.map((rule) => rule.value).filter((value) => Boolean(value));
|
|
1701
|
+
switch (op) {
|
|
1702
|
+
case "eq":
|
|
1703
|
+
return { operator: values.length > 1 ? "SET_ANY" : "EQ", values };
|
|
1704
|
+
case "neq":
|
|
1705
|
+
return { operator: values.length > 1 ? "NOT_SET_ANY" : "NEQ", values };
|
|
1706
|
+
case "contains":
|
|
1707
|
+
return { operator: "CONTAINS", values };
|
|
1708
|
+
case "gt":
|
|
1709
|
+
return { operator: "GT", values };
|
|
1710
|
+
case "lt":
|
|
1711
|
+
return { operator: "LT", values };
|
|
1712
|
+
case "notEmpty":
|
|
1713
|
+
return { operator: "SET", values: [] };
|
|
1714
|
+
case "empty":
|
|
1715
|
+
return { operator: "NOT_SET", values: [] };
|
|
1716
|
+
default:
|
|
1717
|
+
return null;
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
function applyVisibleIfToFieldGroups(groups, definition) {
|
|
1721
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1722
|
+
for (const step of definition.steps ?? []) {
|
|
1723
|
+
for (const fld of step.fields ?? []) {
|
|
1724
|
+
const mapping = fld.hubspot ?? {};
|
|
1725
|
+
byId.set(fld.id, { name: fld.name, property: mapping.property?.trim() || fld.name });
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
const moves = /* @__PURE__ */ new Map();
|
|
1729
|
+
for (const step of definition.steps ?? []) {
|
|
1730
|
+
for (const fld of step.fields ?? []) {
|
|
1731
|
+
const visibleIf = fld.visibleIf;
|
|
1732
|
+
const parentId = visibleIf?.rules?.[0]?.field;
|
|
1733
|
+
if (!visibleIf || !parentId) continue;
|
|
1734
|
+
const converted = conditionToHubspot(visibleIf, parentId);
|
|
1735
|
+
const parent = byId.get(parentId);
|
|
1736
|
+
const mapping = fld.hubspot ?? {};
|
|
1737
|
+
const property = mapping.property?.trim() || fld.name;
|
|
1738
|
+
if (!converted || !parent) continue;
|
|
1739
|
+
moves.set(property, { parent: parent.property, ...converted });
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
if (!moves.size) return groups;
|
|
1743
|
+
const cloned = JSON.parse(JSON.stringify(groups));
|
|
1744
|
+
const flat = [];
|
|
1745
|
+
for (const group of cloned) {
|
|
1746
|
+
(group.fields ?? []).forEach((field, index2) => flat.push({ group, index: index2, field }));
|
|
1747
|
+
}
|
|
1748
|
+
for (const [property, move] of moves) {
|
|
1749
|
+
const child = flat.find((item) => item.field.name === property);
|
|
1750
|
+
const parent = flat.find((item) => item.field.name === move.parent);
|
|
1751
|
+
if (!child || !parent || child === parent) continue;
|
|
1752
|
+
parent.field.dependentFields = [
|
|
1753
|
+
...parent.field.dependentFields ?? [],
|
|
1754
|
+
{
|
|
1755
|
+
dependentCondition: { operator: move.operator, values: move.values },
|
|
1756
|
+
field: child.field
|
|
1757
|
+
}
|
|
1758
|
+
];
|
|
1759
|
+
child.group.fields?.splice(child.index, 1);
|
|
1760
|
+
}
|
|
1761
|
+
return cloned;
|
|
1762
|
+
}
|
|
1653
1763
|
const HS_BASE$2 = "https://api.hubapi.com";
|
|
1654
1764
|
const OBJECT_BY_TYPE_ID = {
|
|
1655
1765
|
"0-1": "contact",
|
|
@@ -1731,7 +1841,7 @@ function convertField(raw, ctx) {
|
|
|
1731
1841
|
helpText: raw.description || void 0,
|
|
1732
1842
|
...options.length ? { options } : {},
|
|
1733
1843
|
hubspot: { object, property: name },
|
|
1734
|
-
...ctx.parentCondition ? { visibleIf: ctx.parentCondition } : {}
|
|
1844
|
+
...ctx.parentCondition ? { visibleIf: ctx.parentCondition, visibleIfSource: "hubspot" } : {}
|
|
1735
1845
|
};
|
|
1736
1846
|
const out = [field];
|
|
1737
1847
|
for (const dependent of raw.dependentFields ?? []) {
|
|
@@ -1754,6 +1864,12 @@ function convertHubspotForm(raw) {
|
|
|
1754
1864
|
const usedNames = /* @__PURE__ */ new Set();
|
|
1755
1865
|
const fields = [];
|
|
1756
1866
|
for (const group of raw.fieldGroups ?? []) {
|
|
1867
|
+
if (group.groupType === "progressive" || group.groupType === "queued") {
|
|
1868
|
+
skipped.push({
|
|
1869
|
+
code: "progressive",
|
|
1870
|
+
detail: group.groupType
|
|
1871
|
+
});
|
|
1872
|
+
}
|
|
1757
1873
|
if (group.richText && !(group.fields ?? []).length) {
|
|
1758
1874
|
skipped.push({ code: "rich-text", detail: group.richText.slice(0, 80) });
|
|
1759
1875
|
continue;
|
|
@@ -1825,7 +1941,10 @@ function mergeHubspotImport(current, incoming) {
|
|
|
1825
1941
|
existing.helpText = next.helpText;
|
|
1826
1942
|
if (next.options) existing.options = next.options;
|
|
1827
1943
|
else delete existing.options;
|
|
1828
|
-
if (
|
|
1944
|
+
if (next.visibleIf && (existing.visibleIfSource === "hubspot" || !existing.visibleIf)) {
|
|
1945
|
+
existing.visibleIf = next.visibleIf;
|
|
1946
|
+
if (existing.visibleIfSource !== "editor") existing.visibleIfSource = "hubspot";
|
|
1947
|
+
}
|
|
1829
1948
|
updated.push(key);
|
|
1830
1949
|
continue;
|
|
1831
1950
|
}
|
|
@@ -1923,10 +2042,6 @@ function formsSubmitUrl(portalId, formGuid, region = "eu1") {
|
|
|
1923
2042
|
function toHsFields(props) {
|
|
1924
2043
|
return Object.entries(props).filter(([, value]) => value !== "").map(([name, value]) => ({ name, value }));
|
|
1925
2044
|
}
|
|
1926
|
-
function filterToFormFields(fields, allowed) {
|
|
1927
|
-
if (!allowed) return fields;
|
|
1928
|
-
return fields.filter((field) => allowed.has(field.name));
|
|
1929
|
-
}
|
|
1930
2045
|
function formFieldNames(raw) {
|
|
1931
2046
|
const names = [];
|
|
1932
2047
|
for (const group of raw.fieldGroups ?? []) {
|
|
@@ -1936,20 +2051,42 @@ function formFieldNames(raw) {
|
|
|
1936
2051
|
}
|
|
1937
2052
|
return names;
|
|
1938
2053
|
}
|
|
1939
|
-
|
|
1940
|
-
|
|
2054
|
+
const OBJECT_BAG = {
|
|
2055
|
+
"0-1": "contact",
|
|
2056
|
+
"0-2": "company"
|
|
2057
|
+
};
|
|
2058
|
+
function formShapeFields(raw) {
|
|
2059
|
+
const fields = [];
|
|
1941
2060
|
for (const group of raw.fieldGroups ?? []) {
|
|
1942
2061
|
for (const field of group.fields ?? []) {
|
|
1943
|
-
if (field.name
|
|
2062
|
+
if (!field.name) continue;
|
|
2063
|
+
fields.push({
|
|
2064
|
+
name: field.name,
|
|
2065
|
+
objectTypeId: field.objectTypeId?.trim() || "0-1",
|
|
2066
|
+
required: Boolean(field.required)
|
|
2067
|
+
});
|
|
1944
2068
|
}
|
|
1945
2069
|
}
|
|
1946
|
-
return
|
|
2070
|
+
return fields;
|
|
2071
|
+
}
|
|
2072
|
+
function fieldsForHubspotForm(bags, shape, extra = {}) {
|
|
2073
|
+
const contact = { ...bags.contact ?? {}, ...extra };
|
|
2074
|
+
if (!shape?.fields.length) {
|
|
2075
|
+
return toHsFields(contact).map((field) => ({ ...field, objectTypeId: "0-1" }));
|
|
2076
|
+
}
|
|
2077
|
+
const out = [];
|
|
2078
|
+
for (const field of shape.fields) {
|
|
2079
|
+
const bagName = OBJECT_BAG[field.objectTypeId] || "contact";
|
|
2080
|
+
const value = bags[bagName]?.[field.name] ?? contact[field.name];
|
|
2081
|
+
if (!value) continue;
|
|
2082
|
+
out.push({ name: field.name, value, objectTypeId: field.objectTypeId || "0-1" });
|
|
2083
|
+
}
|
|
2084
|
+
return out;
|
|
1947
2085
|
}
|
|
1948
2086
|
function parseFormShape(raw) {
|
|
1949
2087
|
const legal = raw.legalConsentOptions;
|
|
1950
|
-
const
|
|
1951
|
-
|
|
1952
|
-
);
|
|
2088
|
+
const legalType = typeof legal?.type === "string" ? legal.type : void 0;
|
|
2089
|
+
const hasLegalConsent = Boolean(legalType && legalType !== "none");
|
|
1953
2090
|
const communications = [];
|
|
1954
2091
|
for (const box of legal?.communicationsCheckboxes ?? []) {
|
|
1955
2092
|
const id = Number(box.subscriptionTypeId ?? box.communicationTypeId);
|
|
@@ -1959,12 +2096,21 @@ function parseFormShape(raw) {
|
|
|
1959
2096
|
text: String(box.label || box.text || "").trim() || "I agree to receive communications."
|
|
1960
2097
|
});
|
|
1961
2098
|
}
|
|
2099
|
+
const subscriptionTypeIds = (legal?.subscriptionTypeIds ?? []).map((id) => Number(id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
1962
2100
|
const consentToProcessText = legal?.consentToProcessText?.trim();
|
|
2101
|
+
const privacyText = legal?.privacyText?.trim();
|
|
2102
|
+
const lawfulRaw = String(legal?.lawfulBasis || "").toUpperCase();
|
|
2103
|
+
const fields = formShapeFields(raw);
|
|
1963
2104
|
return {
|
|
1964
|
-
names: new Set(
|
|
1965
|
-
required: new Set(
|
|
2105
|
+
names: new Set(fields.map((field) => field.name)),
|
|
2106
|
+
required: new Set(fields.filter((field) => field.required).map((field) => field.name)),
|
|
2107
|
+
fields,
|
|
1966
2108
|
hasLegalConsent,
|
|
1967
|
-
|
|
2109
|
+
...legalType ? { legalType } : {},
|
|
2110
|
+
lawfulBasis: lawfulRaw.includes("CUSTOMER") ? "CUSTOMER" : "LEAD",
|
|
2111
|
+
subscriptionTypeIds,
|
|
2112
|
+
...privacyText ? { privacyText } : {},
|
|
2113
|
+
captcha: raw.configuration?.recaptchaEnabled === true || raw.configuration?.captchaEnabled === true,
|
|
1968
2114
|
...consentToProcessText ? { consentToProcessText } : {},
|
|
1969
2115
|
communications
|
|
1970
2116
|
};
|
|
@@ -1976,9 +2122,22 @@ function canRetryEmailOnly(required) {
|
|
|
1976
2122
|
function buildLegalConsent(shape, given, fallbackText) {
|
|
1977
2123
|
if (!given) return void 0;
|
|
1978
2124
|
if (shape && !shape.hasLegalConsent) return void 0;
|
|
2125
|
+
const fallback = fallbackText?.trim() || DEFAULT_CONSENT_TEXT;
|
|
2126
|
+
if (shape?.legalType === "legitimate_interest") {
|
|
2127
|
+
const subscriptionTypeId = shape.subscriptionTypeIds[0];
|
|
2128
|
+
if (!subscriptionTypeId) return void 0;
|
|
2129
|
+
return {
|
|
2130
|
+
legitimateInterest: {
|
|
2131
|
+
value: true,
|
|
2132
|
+
subscriptionTypeId,
|
|
2133
|
+
legalBasis: shape.lawfulBasis || "LEAD",
|
|
2134
|
+
text: shape.privacyText?.trim() || fallback
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2137
|
+
}
|
|
1979
2138
|
const consent = {
|
|
1980
2139
|
consentToProcess: true,
|
|
1981
|
-
text: shape?.consentToProcessText?.trim() ||
|
|
2140
|
+
text: shape?.consentToProcessText?.trim() || fallback
|
|
1982
2141
|
};
|
|
1983
2142
|
if (shape?.communications.length) {
|
|
1984
2143
|
consent.communications = shape.communications.map((item) => ({
|
|
@@ -2106,13 +2265,62 @@ async function submitMarketingForm(input) {
|
|
|
2106
2265
|
async function syncFieldsToHubspotForm(apiKey, formGuid, definition) {
|
|
2107
2266
|
const raw = await fetchHubspotForm(apiKey, formGuid);
|
|
2108
2267
|
const extra = missingMappedFields(definition, formFieldNames(raw));
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2268
|
+
const fieldGroups = applyVisibleIfToFieldGroups(
|
|
2269
|
+
appendFieldGroups(raw.fieldGroups ?? [], extra),
|
|
2270
|
+
definition
|
|
2271
|
+
);
|
|
2272
|
+
if (!extra.length && JSON.stringify(fieldGroups) === JSON.stringify(appendFieldGroups(raw.fieldGroups ?? [], []))) {
|
|
2273
|
+
return [];
|
|
2274
|
+
}
|
|
2275
|
+
await patchHubspotForm(apiKey, formGuid, { fieldGroups });
|
|
2113
2276
|
clearFormShapeCache(formGuid);
|
|
2114
2277
|
return extra.map((field) => field.property);
|
|
2115
2278
|
}
|
|
2279
|
+
async function createMarketingForm(apiKey, name, definition) {
|
|
2280
|
+
const fields = mappedContactFields(definition).map((field) => toHsFormField(field));
|
|
2281
|
+
if (!fields.length) {
|
|
2282
|
+
throw new Error("Add at least one mapped contact field before creating a HubSpot form");
|
|
2283
|
+
}
|
|
2284
|
+
const res = await fetch("https://api.hubapi.com/marketing/v3/forms", {
|
|
2285
|
+
method: "POST",
|
|
2286
|
+
headers: {
|
|
2287
|
+
Authorization: `Bearer ${apiKey}`,
|
|
2288
|
+
"Content-Type": "application/json"
|
|
2289
|
+
},
|
|
2290
|
+
body: JSON.stringify({
|
|
2291
|
+
name,
|
|
2292
|
+
formType: "hubspot",
|
|
2293
|
+
fieldGroups: applyVisibleIfToFieldGroups(
|
|
2294
|
+
fields.map((field) => ({
|
|
2295
|
+
groupType: "default_group",
|
|
2296
|
+
richTextType: "text",
|
|
2297
|
+
fields: [field]
|
|
2298
|
+
})),
|
|
2299
|
+
definition
|
|
2300
|
+
),
|
|
2301
|
+
configuration: {
|
|
2302
|
+
language: "fr",
|
|
2303
|
+
recaptchaEnabled: false,
|
|
2304
|
+
createNewContactForNewEmail: true,
|
|
2305
|
+
prePopulateKnownValues: true,
|
|
2306
|
+
notifyContactOwner: false,
|
|
2307
|
+
notifyRecipients: [],
|
|
2308
|
+
editable: true,
|
|
2309
|
+
archivable: true,
|
|
2310
|
+
cloneable: true,
|
|
2311
|
+
allowLinkToResetKnownValues: false,
|
|
2312
|
+
postSubmitAction: { type: "thank_you", value: "Merci." }
|
|
2313
|
+
},
|
|
2314
|
+
displayOptions: { submitButtonText: "Envoyer", style: { submitButtonText: "Envoyer" } },
|
|
2315
|
+
legalConsentOptions: { type: "none" }
|
|
2316
|
+
})
|
|
2317
|
+
});
|
|
2318
|
+
const body = await res.json().catch(() => ({}));
|
|
2319
|
+
if (!res.ok || !body.id) {
|
|
2320
|
+
throw new Error(body.message || `HubSpot ${res.status}`);
|
|
2321
|
+
}
|
|
2322
|
+
return body.id;
|
|
2323
|
+
}
|
|
2116
2324
|
function publicForm(entry) {
|
|
2117
2325
|
return {
|
|
2118
2326
|
slug: entry.slug,
|
|
@@ -2126,7 +2334,9 @@ function publicForm(entry) {
|
|
|
2126
2334
|
steps: (entry.definition?.steps ?? []).map((step) => ({
|
|
2127
2335
|
...step,
|
|
2128
2336
|
// The CRM mappings are the server's business — never the browser's.
|
|
2129
|
-
fields: (step.fields ?? []).map(
|
|
2337
|
+
fields: (step.fields ?? []).map(
|
|
2338
|
+
({ hubspot: _hubspot, companyMap: _companyMap, visibleIfSource: _source, ...fld }) => fld
|
|
2339
|
+
)
|
|
2130
2340
|
}))
|
|
2131
2341
|
};
|
|
2132
2342
|
}
|
|
@@ -2500,12 +2710,16 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2500
2710
|
if (tryFormsApi && portalId && formGuid) {
|
|
2501
2711
|
try {
|
|
2502
2712
|
const shape = await loadFormShape(apiKey, formGuid);
|
|
2503
|
-
const fields =
|
|
2504
|
-
|
|
2505
|
-
|
|
2713
|
+
const fields = fieldsForHubspotForm(
|
|
2714
|
+
{
|
|
2715
|
+
contact: contactProps,
|
|
2716
|
+
company: stringProps(partition.accepted.company ?? {})
|
|
2717
|
+
},
|
|
2718
|
+
shape,
|
|
2719
|
+
{ email }
|
|
2506
2720
|
);
|
|
2507
2721
|
if (fields.length && !fields.some((f) => f.name === "email")) {
|
|
2508
|
-
fields.unshift({ name: "email", value: email });
|
|
2722
|
+
fields.unshift({ name: "email", value: email, objectTypeId: "0-1" });
|
|
2509
2723
|
}
|
|
2510
2724
|
sentFieldNames = fields.map((f) => f.name);
|
|
2511
2725
|
const submitted = await submitMarketingForm({
|
|
@@ -2513,7 +2727,7 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2513
2727
|
portalId,
|
|
2514
2728
|
formGuid,
|
|
2515
2729
|
region,
|
|
2516
|
-
fields: fields.length ? fields : [{ name: "email", value: email }],
|
|
2730
|
+
fields: fields.length ? fields : [{ name: "email", value: email, objectTypeId: "0-1" }],
|
|
2517
2731
|
context: {
|
|
2518
2732
|
hutk: sanitizeHutk(meta.hutk),
|
|
2519
2733
|
pageUri: typeof meta.pageUrl === "string" ? meta.pageUrl : void 0,
|
|
@@ -2866,6 +3080,22 @@ function createFormsAdminController(strapi) {
|
|
|
2866
3080
|
ctx.body = { errors: structural, problems: mappings };
|
|
2867
3081
|
return;
|
|
2868
3082
|
}
|
|
3083
|
+
const { apiKey } = await resolveApiKey(strapi);
|
|
3084
|
+
const account = await resolveAccount(strapi);
|
|
3085
|
+
const ownGuid = typeof entry.hubspotFormId === "string" ? entry.hubspotFormId.trim() : "";
|
|
3086
|
+
const formGuid = isFormGuid(ownGuid) ? ownGuid : isFormGuid(account.defaultFormId) ? account.defaultFormId.trim() : "";
|
|
3087
|
+
if (apiKey && formGuid) {
|
|
3088
|
+
const shape = await loadFormShape(apiKey, formGuid);
|
|
3089
|
+
const missingHubspot = shape ? missingRequiredHubspotFields(
|
|
3090
|
+
entry.definition ?? EMPTY_DEFINITION,
|
|
3091
|
+
[...shape.fields.filter((field) => field.required)]
|
|
3092
|
+
) : [];
|
|
3093
|
+
if (missingHubspot.length) {
|
|
3094
|
+
ctx.status = 400;
|
|
3095
|
+
ctx.body = { errors: structural, problems: mappings, missingHubspot };
|
|
3096
|
+
return;
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
2869
3099
|
await documents().publish({
|
|
2870
3100
|
documentId: ctx.params.documentId,
|
|
2871
3101
|
locale: ctx.query.locale
|
|
@@ -2873,22 +3103,16 @@ function createFormsAdminController(strapi) {
|
|
|
2873
3103
|
const policy = await resolvePolicy(strapi);
|
|
2874
3104
|
let addedFields = [];
|
|
2875
3105
|
let syncWarning;
|
|
2876
|
-
if (policy.syncFieldsOnPublish) {
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
entry.definition ?? EMPTY_DEFINITION
|
|
2887
|
-
);
|
|
2888
|
-
} catch (err) {
|
|
2889
|
-
syncWarning = err.message;
|
|
2890
|
-
strapi.log.warn(`[hubspot] field sync on publish failed — ${syncWarning}`);
|
|
2891
|
-
}
|
|
3106
|
+
if (policy.syncFieldsOnPublish && apiKey && formGuid) {
|
|
3107
|
+
try {
|
|
3108
|
+
addedFields = await syncFieldsToHubspotForm(
|
|
3109
|
+
apiKey,
|
|
3110
|
+
formGuid,
|
|
3111
|
+
entry.definition ?? EMPTY_DEFINITION
|
|
3112
|
+
);
|
|
3113
|
+
} catch (err) {
|
|
3114
|
+
syncWarning = err.message;
|
|
3115
|
+
strapi.log.warn(`[hubspot] field sync on publish failed — ${syncWarning}`);
|
|
2892
3116
|
}
|
|
2893
3117
|
}
|
|
2894
3118
|
ctx.body = {
|
|
@@ -2897,6 +3121,31 @@ function createFormsAdminController(strapi) {
|
|
|
2897
3121
|
...syncWarning ? { syncWarning } : {}
|
|
2898
3122
|
};
|
|
2899
3123
|
},
|
|
3124
|
+
async createInHubspot(ctx) {
|
|
3125
|
+
const entry = await documents().findOne({
|
|
3126
|
+
documentId: ctx.params.documentId,
|
|
3127
|
+
locale: ctx.query.locale,
|
|
3128
|
+
status: "draft"
|
|
3129
|
+
});
|
|
3130
|
+
if (!entry) ctx.throw(404, "Form not found");
|
|
3131
|
+
const { apiKey } = await resolveApiKey(strapi);
|
|
3132
|
+
if (!apiKey) ctx.throw(400, "HubSpot API key is missing");
|
|
3133
|
+
try {
|
|
3134
|
+
const id = await createMarketingForm(
|
|
3135
|
+
apiKey,
|
|
3136
|
+
entry.name || entry.slug || "Formulaire",
|
|
3137
|
+
entry.definition ?? EMPTY_DEFINITION
|
|
3138
|
+
);
|
|
3139
|
+
const updated = await documents().update({
|
|
3140
|
+
documentId: ctx.params.documentId,
|
|
3141
|
+
locale: ctx.query.locale,
|
|
3142
|
+
data: { hubspotFormId: id }
|
|
3143
|
+
});
|
|
3144
|
+
ctx.body = { form: updated, hubspotFormId: id };
|
|
3145
|
+
} catch (err) {
|
|
3146
|
+
ctx.throw(400, err.message);
|
|
3147
|
+
}
|
|
3148
|
+
},
|
|
2900
3149
|
async unpublish(ctx) {
|
|
2901
3150
|
await documents().unpublish({
|
|
2902
3151
|
documentId: ctx.params.documentId,
|
|
@@ -3663,6 +3912,7 @@ const routes = {
|
|
|
3663
3912
|
adminRoute("GET", "/builder/forms/:documentId", "formsAdmin.findOne", [FORMS_ACTION]),
|
|
3664
3913
|
adminRoute("PUT", "/builder/forms/:documentId", "formsAdmin.update", [FORMS_ACTION]),
|
|
3665
3914
|
adminRoute("POST", "/builder/forms/:documentId/publish", "formsAdmin.publish", [FORMS_ACTION]),
|
|
3915
|
+
adminRoute("POST", "/builder/forms/:documentId/create-hubspot", "formsAdmin.createInHubspot", [FORMS_ACTION]),
|
|
3666
3916
|
adminRoute("POST", "/builder/forms/:documentId/unpublish", "formsAdmin.unpublish", [FORMS_ACTION]),
|
|
3667
3917
|
adminRoute("DELETE", "/builder/forms/:documentId", "formsAdmin.remove", [FORMS_ACTION]),
|
|
3668
3918
|
adminRoute("POST", "/builder/forms/:documentId/duplicate", "formsAdmin.duplicate", [FORMS_ACTION]),
|