Skip to content

Commit ec15e93

Browse files
committed
move helper functions to methods block
1 parent d3ec473 commit ec15e93

1 file changed

Lines changed: 146 additions & 138 deletions

File tree

  • website/modules/@apostrophecms/form
Lines changed: 146 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,138 @@
11
const { google } = require('googleapis');
22
const postmark = require('postmark');
33

4+
// === Utility Functions ===
5+
6+
const createEmailHtml = function (submission) {
7+
let html = '<ul>';
8+
// Create a safe copy of submission object to iterate through
9+
const safeSubmission = { ...submission };
10+
// Use a safer method to avoid object injection
11+
const htmlItems = Object.entries(safeSubmission).map(
12+
([key, value]) => `<li><strong>${key}:</strong> ${value}</li>`,
13+
);
14+
html += htmlItems.join('');
15+
html += '</ul>';
16+
return html;
17+
};
18+
19+
const createPostmarkClient = function (apiKey) {
20+
return new postmark.ServerClient(apiKey);
21+
};
22+
23+
const findFieldValue = function (submission, fieldName) {
24+
if (fieldName && submission[fieldName] !== undefined) {
25+
return submission[fieldName];
26+
}
27+
return null;
28+
};
29+
30+
const prepareSheetData = function (submission) {
31+
const id = Date.now().toString();
32+
return [id, new Date().toISOString(), ...Object.values(submission)];
33+
};
34+
35+
const createSheetsClient = function (form) {
36+
const auth = new google.auth.JWT({
37+
email: form.serviceAccountEmail,
38+
key: form.serviceAccountPrivateKey.replace(/\\n/gu, '\n'),
39+
scopes: ['https://www.googleapis.com/auth/spreadsheets'],
40+
});
41+
42+
return google.sheets({ version: 'v4', auth });
43+
};
44+
45+
const createSendEmailFunction = function (self, postmarkClient) {
46+
return async (from, to, subject, htmlBody) => {
47+
try {
48+
const response = await postmarkClient.sendEmail({
49+
From: from,
50+
To: to,
51+
Subject: subject,
52+
HtmlBody: htmlBody,
53+
MessageStream: 'outbound',
54+
});
55+
self.apos.util.log(`Email sent successfully to ${to}`);
56+
if (response.ErrorCode) {
57+
self.apos.util.error(response.ErrorCode);
58+
}
59+
} catch (error) {
60+
self.apos.util.error(`Error sending email to ${to}`, error);
61+
}
62+
};
63+
};
64+
65+
const sendConfirmationEmail = async function (
66+
self,
67+
form,
68+
submission,
69+
sendEmailFunc,
70+
) {
71+
const confirmationFieldName = form.emailConfirmationField;
72+
const senderEmail = findFieldValue(submission, confirmationFieldName);
73+
if (!senderEmail) {
74+
self.apos.util.warn(
75+
`Email confirmation field "${form.emailConfirmationField}" not found in the submission.`,
76+
);
77+
return false;
78+
}
79+
const confirmationHtml =
80+
'<p>Thank you for your submission! We will review your message as soon as possible.</p>';
81+
await sendEmailFunc(
82+
form.fromEmail,
83+
senderEmail,
84+
'Confirmation of Form Submission from Procrea',
85+
confirmationHtml,
86+
);
87+
return true;
88+
};
89+
90+
const handlePostmark = async function (self, form, submission) {
91+
const emailSubject = `${form.title} Form (${form.domainName || 'defaultdomain.com'})`;
92+
const html = self.createEmailHtml(submission);
93+
const postmarkClient = self.createPostmarkClient(form.postmarkApiKey);
94+
const sendPostmarkEmail = self.createSendEmailFunction(postmarkClient);
95+
96+
try {
97+
await sendPostmarkEmail(form.fromEmail, form.toEmail, emailSubject, html);
98+
if (form.sendConfirmationEmail) {
99+
await self.sendConfirmationEmail(form, submission, sendPostmarkEmail);
100+
}
101+
} catch (error) {
102+
self.apos.util.error('Error processing email sending', error);
103+
}
104+
};
105+
106+
const handleSpreadsheet = async function (self, form, submission) {
107+
try {
108+
const sheets = self.createSheetsClient(form);
109+
const values = self.prepareSheetData(submission);
110+
const resource = { values: [values] };
111+
112+
await sheets.spreadsheets.values.append({
113+
spreadsheetId: form.spreadsheetId,
114+
range: 'Sheet1!A1',
115+
valueInputOption: 'RAW',
116+
resource,
117+
});
118+
self.apos.util.log('Data inserted into Google Sheets successfully.');
119+
} catch (error) {
120+
self.apos.util.error('Error Sheets data insertion', error);
121+
}
122+
};
123+
124+
const processSubmission = async function (self, form, submission) {
125+
if (form.enablePostmark) {
126+
await self.handlePostmark(form, submission);
127+
}
128+
129+
if (form.enableSpreadsheet) {
130+
await self.handleSpreadsheet(form, submission);
131+
}
132+
};
133+
134+
// === Module Export ===
135+
4136
module.exports = {
5137
options: {
6138
emailSubmissions: false,
@@ -120,147 +252,23 @@ module.exports = {
120252
},
121253
},
122254

123-
// Helper methods for email and spreadsheet functionality
124-
createEmailHtml(submission) {
125-
let html = '<ul>';
126-
// Create a safe copy of submission object to iterate through
127-
const safeSubmission = { ...submission };
128-
// Use a safer method to avoid object injection
129-
const htmlItems = Object.entries(safeSubmission).map(
130-
([key, value]) => `<li><strong>${key}:</strong> ${value}</li>`,
131-
);
132-
html += htmlItems.join('');
133-
html += '</ul>';
134-
return html;
135-
},
136-
137-
createPostmarkClient(apiKey) {
138-
return new postmark.ServerClient(apiKey);
139-
},
140-
141-
findFieldValue(submission, fieldName) {
142-
if (!fieldName) {
143-
return null;
144-
}
145-
146-
// Use direct property access instead of iteration
147-
if (submission[fieldName] !== undefined) {
148-
return submission[fieldName];
149-
}
150-
151-
return null;
152-
},
153-
154-
prepareSheetData(submission) {
155-
const id = Date.now().toString();
156-
return [id, new Date().toISOString(), ...Object.values(submission)];
157-
},
158-
159-
createSheetsClient(form) {
160-
const auth = new google.auth.JWT({
161-
email: form.serviceAccountEmail,
162-
key: form.serviceAccountPrivateKey.replace(/\\n/gu, '\n'),
163-
scopes: ['https://www.googleapis.com/auth/spreadsheets'],
164-
});
165-
166-
return google.sheets({
167-
version: 'v4',
168-
auth,
169-
});
170-
},
171-
172-
createSendEmailFunction(postmarkClient) {
173-
const { apos } = this;
174-
return async (from, to, subject, htmlBody) => {
175-
try {
176-
const response = await postmarkClient.sendEmail({
177-
From: from,
178-
To: to,
179-
Subject: subject,
180-
HtmlBody: htmlBody,
181-
MessageStream: 'outbound',
182-
});
183-
apos.util.log(`Email sent successfully to ${to}`);
184-
if (response.ErrorCode) {
185-
apos.util.error(response.ErrorCode);
186-
}
187-
} catch (error) {
188-
apos.util.error(`Error sending email to ${to}`, error);
189-
}
255+
methods(self) {
256+
return {
257+
createEmailHtml,
258+
createPostmarkClient,
259+
findFieldValue,
260+
prepareSheetData,
261+
createSheetsClient,
262+
createSendEmailFunction: (...args) =>
263+
createSendEmailFunction(self, ...args),
264+
sendConfirmationEmail: (...args) => sendConfirmationEmail(self, ...args),
265+
handlePostmark: (...args) => handlePostmark(self, ...args),
266+
handleSpreadsheet: (...args) => handleSpreadsheet(self, ...args),
267+
processSubmission: (...args) => processSubmission(self, ...args),
190268
};
191269
},
192270

193-
async sendConfirmationEmail(form, submission, sendEmailFunc) {
194-
const confirmationFieldName = form.emailConfirmationField;
195-
const senderEmail = this.findFieldValue(submission, confirmationFieldName);
196-
if (!senderEmail) {
197-
this.apos.util.warn(
198-
`Email confirmation field "${form.emailConfirmationField}" not found in the submission.`,
199-
);
200-
return false;
201-
}
202-
const confirmationHtml =
203-
'<p>Thank you for your submission! We will review your message as soon as possible.</p>';
204-
await sendEmailFunc(
205-
form.fromEmail,
206-
senderEmail,
207-
'Confirmation of Form Submission from Procrea',
208-
confirmationHtml,
209-
);
210-
return true;
211-
},
212-
213-
async handlePostmark(form, submission) {
214-
const emailSubject = `${form.title} Form (${form.domainName || 'defaultdomain.com'})`;
215-
const html = this.createEmailHtml(submission);
216-
const postmarkClient = this.createPostmarkClient(form.postmarkApiKey);
217-
const sendPostmarkEmail = this.createSendEmailFunction(postmarkClient);
218-
219-
try {
220-
// Send the main email
221-
await sendPostmarkEmail(form.fromEmail, form.toEmail, emailSubject, html);
222-
223-
// Send confirmation email if configured
224-
if (form.sendConfirmationEmail) {
225-
await this.sendConfirmationEmail(form, submission, sendPostmarkEmail);
226-
}
227-
} catch (error) {
228-
this.apos.util.error('Error processing email sending', error);
229-
}
230-
},
231-
232-
async handleSpreadsheet(form, submission) {
233-
try {
234-
const { spreadsheetId } = form;
235-
const range = 'Sheet1!A1';
236-
const sheets = this.createSheetsClient(form);
237-
const values = this.prepareSheetData(submission);
238-
const resource = { values: [values] };
239-
240-
await sheets.spreadsheets.values.append({
241-
spreadsheetId,
242-
range,
243-
valueInputOption: 'RAW',
244-
resource,
245-
});
246-
this.apos.util.log('Data inserted into Google Sheets successfully.');
247-
} catch (error) {
248-
this.apos.util.error('Error Sheets data insertion', error);
249-
}
250-
},
251-
252-
async processSubmission(req, form, submission) {
253-
if (form.enablePostmark) {
254-
await this.handlePostmark(form, submission);
255-
}
256-
257-
if (form.enableSpreadsheet) {
258-
await this.handleSpreadsheet(form, submission);
259-
}
260-
},
261-
262271
init(self) {
263-
// Register the event handler using the named function
264-
self.on('submission', self.processSubmission);
272+
self.on('submission', 'processSubmission');
265273
},
266274
};

0 commit comments

Comments
 (0)