backend-manager 5.0.149 → 5.0.150
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 +13 -0
- package/package.json +1 -1
- package/src/manager/functions/core/actions/api/general/add-marketing-contact.js +0 -2
- package/src/manager/functions/core/actions/api/general/remove-marketing-contact.js +1 -2
- package/src/manager/libraries/email/constants.js +0 -3
- package/src/manager/libraries/email/index.js +9 -18
- package/src/manager/libraries/email/marketing/index.js +29 -36
- package/src/manager/libraries/email/providers/beehiiv.js +16 -0
- package/src/manager/routes/marketing/contact/delete.js +1 -2
- package/src/manager/routes/marketing/contact/post.js +0 -3
- package/src/manager/schemas/marketing/contact/delete.js +0 -3
- package/src/manager/schemas/marketing/contact/post.js +0 -3
- package/templates/backend-manager-config.json +9 -0
- package/test/functions/general/add-marketing-contact.js +1 -40
- package/test/routes/marketing/contact.js +1 -38
- /package/src/manager/schemas/{app → brand}/get.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
14
14
|
- `Fixed` for any bug fixes.
|
|
15
15
|
- `Security` in case of vulnerabilities.
|
|
16
16
|
|
|
17
|
+
# [5.0.150] - 2026-03-16
|
|
18
|
+
### Added
|
|
19
|
+
- `marketing` config section in `backend-manager-config.json` — per-brand control over SendGrid and Beehiiv provider availability
|
|
20
|
+
- Beehiiv provider reads `publicationId` from config (skips fuzzy-match API call) with in-memory cache
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Provider availability resolved once in Marketing constructor from `config.marketing` + env vars instead of per-request
|
|
24
|
+
- Removed `providers` parameter from `add()`, `sync()`, `remove()` and all route/schema callers
|
|
25
|
+
|
|
26
|
+
### Removed
|
|
27
|
+
- `DEFAULT_PROVIDERS` constant — no longer needed with config-driven provider resolution
|
|
28
|
+
- Provider-selection tests — no longer applicable
|
|
29
|
+
|
|
17
30
|
# [5.0.149] - 2026-03-14
|
|
18
31
|
### Added
|
|
19
32
|
- Modular email library (`libraries/email/`) — replaces monolithic `libraries/email.js` with provider-based architecture
|
package/package.json
CHANGED
|
@@ -29,7 +29,6 @@ Module.prototype.main = function () {
|
|
|
29
29
|
|
|
30
30
|
// Admin-only options
|
|
31
31
|
const tags = isAdmin ? (requestPayload.tags || []) : [];
|
|
32
|
-
const providers = isAdmin ? (requestPayload.providers || ['sendgrid', 'beehiiv']) : ['sendgrid', 'beehiiv'];
|
|
33
32
|
const skipValidation = isAdmin ? (requestPayload.skipValidation || false) : false;
|
|
34
33
|
|
|
35
34
|
// Validate email is provided
|
|
@@ -114,7 +113,6 @@ Module.prototype.main = function () {
|
|
|
114
113
|
firstName,
|
|
115
114
|
lastName,
|
|
116
115
|
source,
|
|
117
|
-
providers,
|
|
118
116
|
});
|
|
119
117
|
}
|
|
120
118
|
|
|
@@ -22,7 +22,6 @@ Module.prototype.main = function () {
|
|
|
22
22
|
|
|
23
23
|
// Extract parameters
|
|
24
24
|
const email = (requestPayload.email || '').trim().toLowerCase();
|
|
25
|
-
const providers = requestPayload.providers || ['sendgrid', 'beehiiv'];
|
|
26
25
|
|
|
27
26
|
// Validate email is provided
|
|
28
27
|
if (!email) {
|
|
@@ -31,7 +30,7 @@ Module.prototype.main = function () {
|
|
|
31
30
|
|
|
32
31
|
// Remove from providers
|
|
33
32
|
const mailer = Manager.Email(assistant);
|
|
34
|
-
const providerResults = await mailer.remove(email
|
|
33
|
+
const providerResults = await mailer.remove(email);
|
|
35
34
|
|
|
36
35
|
// Log result
|
|
37
36
|
assistant.log('remove-marketing-contact result:', {
|
|
@@ -84,8 +84,6 @@ const SENDERS = {
|
|
|
84
84
|
},
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
// Default marketing providers — SSOT for all provider loops
|
|
88
|
-
const DEFAULT_PROVIDERS = ['sendgrid', 'beehiiv'];
|
|
89
87
|
|
|
90
88
|
// SendGrid limit for scheduled emails (72 hours, but use 71 for buffer)
|
|
91
89
|
const SEND_AT_LIMIT = 71;
|
|
@@ -234,7 +232,6 @@ module.exports = {
|
|
|
234
232
|
GROUPS,
|
|
235
233
|
SENDERS,
|
|
236
234
|
FIELDS,
|
|
237
|
-
DEFAULT_PROVIDERS,
|
|
238
235
|
SEND_AT_LIMIT,
|
|
239
236
|
sanitizeImagesForEmail,
|
|
240
237
|
encode,
|
|
@@ -74,16 +74,9 @@ Email.prototype.build = function (settings) {
|
|
|
74
74
|
};
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
77
|
+
* Add a new contact to enabled marketing providers (lightweight, no full user doc needed).
|
|
78
78
|
*
|
|
79
|
-
* @param {object}
|
|
80
|
-
* @param {object} [options] - { providers: array of provider names (default: DEFAULT_PROVIDERS) }
|
|
81
|
-
* @returns {{ sendgrid?: object, beehiiv?: object }}
|
|
82
|
-
*/
|
|
83
|
-
/**
|
|
84
|
-
* Add a new contact to marketing providers (lightweight, no full user doc needed).
|
|
85
|
-
*
|
|
86
|
-
* @param {object} options - { email, firstName, lastName, source, customFields, providers }
|
|
79
|
+
* @param {object} options - { email, firstName, lastName, source, customFields }
|
|
87
80
|
* @returns {{ sendgrid?: object, beehiiv?: object }}
|
|
88
81
|
*/
|
|
89
82
|
Email.prototype.add = function (options) {
|
|
@@ -91,25 +84,23 @@ Email.prototype.add = function (options) {
|
|
|
91
84
|
};
|
|
92
85
|
|
|
93
86
|
/**
|
|
94
|
-
* Sync a user's full data to marketing providers
|
|
87
|
+
* Sync a user's full data to enabled marketing providers.
|
|
95
88
|
*
|
|
96
|
-
* @param {object}
|
|
97
|
-
* @param {object} [options] - { providers: array of provider names (default: DEFAULT_PROVIDERS) }
|
|
89
|
+
* @param {string|object} userDocOrUid - UID string or full user document from Firestore
|
|
98
90
|
* @returns {{ sendgrid?: object, beehiiv?: object }}
|
|
99
91
|
*/
|
|
100
|
-
Email.prototype.sync = function (
|
|
101
|
-
return this._marketing.sync(
|
|
92
|
+
Email.prototype.sync = function (userDocOrUid) {
|
|
93
|
+
return this._marketing.sync(userDocOrUid);
|
|
102
94
|
};
|
|
103
95
|
|
|
104
96
|
/**
|
|
105
|
-
* Remove a contact from all marketing providers.
|
|
97
|
+
* Remove a contact from all enabled marketing providers.
|
|
106
98
|
*
|
|
107
99
|
* @param {string} email - Email address to remove
|
|
108
|
-
* @param {object} [options] - { providers: array of provider names (default: DEFAULT_PROVIDERS) }
|
|
109
100
|
* @returns {{ sendgrid?: object, beehiiv?: object }}
|
|
110
101
|
*/
|
|
111
|
-
Email.prototype.remove = function (email
|
|
112
|
-
return this._marketing.remove(email
|
|
102
|
+
Email.prototype.remove = function (email) {
|
|
103
|
+
return this._marketing.remove(email);
|
|
113
104
|
};
|
|
114
105
|
|
|
115
106
|
/**
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
const _ = require('lodash');
|
|
27
27
|
|
|
28
|
-
const { TEMPLATES, GROUPS, SENDERS
|
|
28
|
+
const { TEMPLATES, GROUPS, SENDERS } = require('../constants.js');
|
|
29
29
|
const sendgridProvider = require('../providers/sendgrid.js');
|
|
30
30
|
const beehiivProvider = require('../providers/beehiiv.js');
|
|
31
31
|
|
|
@@ -36,11 +36,19 @@ function Marketing(assistant) {
|
|
|
36
36
|
self.Manager = assistant.Manager;
|
|
37
37
|
self.admin = self.Manager.libraries.admin;
|
|
38
38
|
|
|
39
|
+
// Resolve provider availability from config + env
|
|
40
|
+
const marketing = self.Manager.config?.marketing || {};
|
|
41
|
+
|
|
42
|
+
self.providers = {
|
|
43
|
+
sendgrid: marketing.sendgrid?.enabled !== false && !!process.env.SENDGRID_API_KEY,
|
|
44
|
+
beehiiv: marketing.beehiiv?.enabled !== false && !!process.env.BEEHIIV_API_KEY,
|
|
45
|
+
};
|
|
46
|
+
|
|
39
47
|
return self;
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
/**
|
|
43
|
-
* Add a new contact to
|
|
51
|
+
* Add a new contact to enabled providers (lightweight — no full user doc needed).
|
|
44
52
|
* Used by newsletter subscribe and admin bulk import.
|
|
45
53
|
*
|
|
46
54
|
* @param {object} options
|
|
@@ -49,33 +57,29 @@ function Marketing(assistant) {
|
|
|
49
57
|
* @param {string} [options.lastName]
|
|
50
58
|
* @param {string} [options.source] - UTM source
|
|
51
59
|
* @param {object} [options.customFields] - Extra SendGrid custom fields (keyed by field ID)
|
|
52
|
-
* @param {Array<string>} [options.providers] - Which providers (default: all available)
|
|
53
60
|
* @returns {{ sendgrid?: object, beehiiv?: object }}
|
|
54
61
|
*/
|
|
55
62
|
Marketing.prototype.add = async function (options) {
|
|
56
63
|
const self = this;
|
|
57
64
|
const assistant = self.assistant;
|
|
58
|
-
const { email, firstName, lastName, source, customFields
|
|
65
|
+
const { email, firstName, lastName, source, customFields } = options;
|
|
59
66
|
|
|
60
67
|
if (!email) {
|
|
61
68
|
assistant.warn('Marketing.add(): No email provided, skipping');
|
|
62
69
|
return {};
|
|
63
70
|
}
|
|
64
71
|
|
|
65
|
-
|
|
66
|
-
const addProviders = providers || DEFAULT_PROVIDERS;
|
|
67
|
-
const results = {};
|
|
68
|
-
|
|
69
|
-
if (!shouldAdd) {
|
|
72
|
+
if (assistant.isTesting() && !process.env.TEST_EXTENDED_MODE) {
|
|
70
73
|
assistant.log('Marketing.add(): Skipping providers (testing mode)');
|
|
71
|
-
return
|
|
74
|
+
return {};
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
assistant.log('Marketing.add():', { email });
|
|
75
78
|
|
|
79
|
+
const results = {};
|
|
76
80
|
const promises = [];
|
|
77
81
|
|
|
78
|
-
if (
|
|
82
|
+
if (self.providers.sendgrid) {
|
|
79
83
|
promises.push(
|
|
80
84
|
sendgridProvider.addContact({
|
|
81
85
|
email,
|
|
@@ -86,7 +90,7 @@ Marketing.prototype.add = async function (options) {
|
|
|
86
90
|
);
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
if (
|
|
93
|
+
if (self.providers.beehiiv) {
|
|
90
94
|
promises.push(
|
|
91
95
|
beehiivProvider.addContact({
|
|
92
96
|
email,
|
|
@@ -109,14 +113,11 @@ Marketing.prototype.add = async function (options) {
|
|
|
109
113
|
* Upserts the contact with all custom fields derived from the user doc.
|
|
110
114
|
*
|
|
111
115
|
* @param {string|object} userDocOrUid - UID string (fetches from Firestore) or full user document object
|
|
112
|
-
* @param {object} [options]
|
|
113
|
-
* @param {Array<string>} [options.providers] - Which providers to sync to (default: all available)
|
|
114
116
|
* @returns {{ sendgrid?: object, beehiiv?: object }}
|
|
115
117
|
*/
|
|
116
|
-
Marketing.prototype.sync = async function (userDocOrUid
|
|
118
|
+
Marketing.prototype.sync = async function (userDocOrUid) {
|
|
117
119
|
const self = this;
|
|
118
120
|
const assistant = self.assistant;
|
|
119
|
-
const { providers } = options || {};
|
|
120
121
|
|
|
121
122
|
// Resolve UID to user doc if string
|
|
122
123
|
let userDoc;
|
|
@@ -145,13 +146,9 @@ Marketing.prototype.sync = async function (userDocOrUid, options) {
|
|
|
145
146
|
return {};
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
const syncProviders = providers || DEFAULT_PROVIDERS;
|
|
150
|
-
const results = {};
|
|
151
|
-
|
|
152
|
-
if (!shouldSync) {
|
|
149
|
+
if (assistant.isTesting() && !process.env.TEST_EXTENDED_MODE) {
|
|
153
150
|
assistant.log('Marketing.sync(): Skipping providers (testing mode)');
|
|
154
|
-
return
|
|
151
|
+
return {};
|
|
155
152
|
}
|
|
156
153
|
|
|
157
154
|
assistant.log('Marketing.sync():', { email });
|
|
@@ -159,9 +156,10 @@ Marketing.prototype.sync = async function (userDocOrUid, options) {
|
|
|
159
156
|
const firstName = _.get(userDoc, 'personal.name.first');
|
|
160
157
|
const lastName = _.get(userDoc, 'personal.name.last');
|
|
161
158
|
const source = _.get(userDoc, 'attribution.utm.tags.utm_source');
|
|
159
|
+
const results = {};
|
|
162
160
|
const promises = [];
|
|
163
161
|
|
|
164
|
-
if (
|
|
162
|
+
if (self.providers.sendgrid) {
|
|
165
163
|
promises.push(
|
|
166
164
|
sendgridProvider.buildFields(userDoc).then((customFields) =>
|
|
167
165
|
sendgridProvider.addContact({
|
|
@@ -174,7 +172,7 @@ Marketing.prototype.sync = async function (userDocOrUid, options) {
|
|
|
174
172
|
);
|
|
175
173
|
}
|
|
176
174
|
|
|
177
|
-
if (
|
|
175
|
+
if (self.providers.beehiiv) {
|
|
178
176
|
promises.push(
|
|
179
177
|
beehiivProvider.addContact({
|
|
180
178
|
email,
|
|
@@ -194,38 +192,33 @@ Marketing.prototype.sync = async function (userDocOrUid, options) {
|
|
|
194
192
|
};
|
|
195
193
|
|
|
196
194
|
/**
|
|
197
|
-
* Remove a contact from all providers.
|
|
195
|
+
* Remove a contact from all enabled providers.
|
|
198
196
|
*
|
|
199
197
|
* @param {string} email - Email address to remove
|
|
200
|
-
* @param {object} [options]
|
|
201
|
-
* @param {Array<string>} [options.providers] - Which providers to remove from (default: all available)
|
|
202
198
|
* @returns {{ sendgrid?: object, beehiiv?: object }}
|
|
203
199
|
*/
|
|
204
|
-
Marketing.prototype.remove = async function (email
|
|
200
|
+
Marketing.prototype.remove = async function (email) {
|
|
205
201
|
const self = this;
|
|
206
202
|
const assistant = self.assistant;
|
|
207
|
-
const { providers } = options || {};
|
|
208
203
|
|
|
209
204
|
if (!email) {
|
|
210
205
|
assistant.warn('Marketing.remove(): No email provided, skipping');
|
|
211
206
|
return {};
|
|
212
207
|
}
|
|
213
208
|
|
|
214
|
-
const removeProviders = providers || DEFAULT_PROVIDERS;
|
|
215
|
-
const results = {};
|
|
216
|
-
|
|
217
209
|
assistant.log('Marketing.remove():', { email });
|
|
218
210
|
|
|
211
|
+
const results = {};
|
|
219
212
|
const promises = [];
|
|
220
213
|
|
|
221
|
-
if (
|
|
214
|
+
if (self.providers.sendgrid) {
|
|
222
215
|
promises.push(
|
|
223
216
|
sendgridProvider.removeContact(email)
|
|
224
217
|
.then((r) => { results.sendgrid = r; })
|
|
225
218
|
);
|
|
226
219
|
}
|
|
227
220
|
|
|
228
|
-
if (
|
|
221
|
+
if (self.providers.beehiiv) {
|
|
229
222
|
promises.push(
|
|
230
223
|
beehiivProvider.removeContact(email)
|
|
231
224
|
.then((r) => { results.beehiiv = r; })
|
|
@@ -259,8 +252,8 @@ Marketing.prototype.sendCampaign = async function (settings) {
|
|
|
259
252
|
const Manager = self.Manager;
|
|
260
253
|
const assistant = self.assistant;
|
|
261
254
|
|
|
262
|
-
if (!
|
|
263
|
-
return { success: false, error: '
|
|
255
|
+
if (!self.providers.sendgrid) {
|
|
256
|
+
return { success: false, error: 'SendGrid not enabled' };
|
|
264
257
|
}
|
|
265
258
|
|
|
266
259
|
const templateId = TEMPLATES[settings.template] || settings.template || TEMPLATES['default'];
|
|
@@ -136,7 +136,22 @@ async function removeSubscriber(email, publicationId) {
|
|
|
136
136
|
* @param {string} brandName
|
|
137
137
|
* @returns {string|null} Publication ID or null
|
|
138
138
|
*/
|
|
139
|
+
let _publicationIdCache = null;
|
|
140
|
+
|
|
139
141
|
async function getPublicationId() {
|
|
142
|
+
if (_publicationIdCache) {
|
|
143
|
+
return _publicationIdCache;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Use publicationId from config if set (skips API call)
|
|
147
|
+
const configPubId = Manager.config?.marketing?.beehiiv?.publicationId;
|
|
148
|
+
|
|
149
|
+
if (configPubId) {
|
|
150
|
+
_publicationIdCache = configPubId;
|
|
151
|
+
return configPubId;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Fuzzy-match by brand name
|
|
140
155
|
const brandName = Manager.config.brand?.name;
|
|
141
156
|
|
|
142
157
|
if (!brandName) {
|
|
@@ -168,6 +183,7 @@ async function getPublicationId() {
|
|
|
168
183
|
);
|
|
169
184
|
|
|
170
185
|
if (matchedPub) {
|
|
186
|
+
_publicationIdCache = matchedPub.id;
|
|
171
187
|
return matchedPub.id;
|
|
172
188
|
}
|
|
173
189
|
|
|
@@ -18,7 +18,6 @@ module.exports = async ({ assistant, Manager, settings, analytics }) => {
|
|
|
18
18
|
|
|
19
19
|
// Extract parameters
|
|
20
20
|
const email = (settings.email || '').trim().toLowerCase();
|
|
21
|
-
const providers = settings.providers;
|
|
22
21
|
|
|
23
22
|
// Validate email is provided
|
|
24
23
|
if (!email) {
|
|
@@ -27,7 +26,7 @@ module.exports = async ({ assistant, Manager, settings, analytics }) => {
|
|
|
27
26
|
|
|
28
27
|
// Remove from providers
|
|
29
28
|
const mailer = Manager.Email(assistant);
|
|
30
|
-
const providerResults = await mailer.remove(email
|
|
29
|
+
const providerResults = await mailer.remove(email);
|
|
31
30
|
|
|
32
31
|
// Log result
|
|
33
32
|
assistant.log('marketing/contact delete result:', {
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
const recaptcha = require('../../../libraries/recaptcha.js');
|
|
6
6
|
const { validate: validateEmail, ALL_CHECKS } = require('../../../libraries/email/validation.js');
|
|
7
7
|
const { inferContact } = require('../../../libraries/infer-contact.js');
|
|
8
|
-
const { DEFAULT_PROVIDERS } = require('../../../libraries/email/constants.js');
|
|
9
8
|
|
|
10
9
|
module.exports = async ({ assistant, Manager, settings, analytics }) => {
|
|
11
10
|
|
|
@@ -23,7 +22,6 @@ module.exports = async ({ assistant, Manager, settings, analytics }) => {
|
|
|
23
22
|
|
|
24
23
|
// Admin-only options
|
|
25
24
|
const tags = isAdmin ? settings.tags : [];
|
|
26
|
-
const providers = isAdmin ? settings.providers : DEFAULT_PROVIDERS;
|
|
27
25
|
const skipValidation = isAdmin ? settings.skipValidation : false;
|
|
28
26
|
|
|
29
27
|
// Email validation — run free checks before reCAPTCHA/rate limit
|
|
@@ -105,7 +103,6 @@ module.exports = async ({ assistant, Manager, settings, analytics }) => {
|
|
|
105
103
|
firstName,
|
|
106
104
|
lastName,
|
|
107
105
|
source,
|
|
108
|
-
providers,
|
|
109
106
|
});
|
|
110
107
|
}
|
|
111
108
|
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Schema for DELETE /marketing/contact
|
|
3
3
|
*/
|
|
4
|
-
const { DEFAULT_PROVIDERS } = require('../../../libraries/email/constants.js');
|
|
5
|
-
|
|
6
4
|
module.exports = () => ({
|
|
7
5
|
email: { types: ['string'], default: undefined, required: true },
|
|
8
|
-
providers: { types: ['array'], default: DEFAULT_PROVIDERS },
|
|
9
6
|
});
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Schema for POST /marketing/contact
|
|
3
3
|
*/
|
|
4
|
-
const { DEFAULT_PROVIDERS } = require('../../../libraries/email/constants.js');
|
|
5
|
-
|
|
6
4
|
module.exports = () => ({
|
|
7
5
|
email: { types: ['string'], default: undefined, required: true },
|
|
8
6
|
firstName: { types: ['string'], default: '' },
|
|
9
7
|
lastName: { types: ['string'], default: '' },
|
|
10
8
|
source: { types: ['string'], default: 'unknown' },
|
|
11
9
|
tags: { types: ['array'], default: [] },
|
|
12
|
-
providers: { types: ['array'], default: DEFAULT_PROVIDERS },
|
|
13
10
|
skipValidation: { types: ['boolean'], default: false },
|
|
14
11
|
'g-recaptcha-response': { types: ['string'], default: undefined },
|
|
15
12
|
});
|
|
@@ -122,6 +122,15 @@
|
|
|
122
122
|
// Add more products/tiers here
|
|
123
123
|
],
|
|
124
124
|
},
|
|
125
|
+
marketing: {
|
|
126
|
+
sendgrid: {
|
|
127
|
+
enabled: true,
|
|
128
|
+
},
|
|
129
|
+
beehiiv: {
|
|
130
|
+
enabled: false,
|
|
131
|
+
// publicationId: 'pub_xxxxx', // Set to skip fuzzy-match API call
|
|
132
|
+
},
|
|
133
|
+
},
|
|
125
134
|
firebaseConfig: {
|
|
126
135
|
apiKey: '123-456',
|
|
127
136
|
authDomain: 'PROJECT-ID.firebaseapp.com',
|
|
@@ -206,46 +206,7 @@ module.exports = {
|
|
|
206
206
|
},
|
|
207
207
|
},
|
|
208
208
|
|
|
209
|
-
// Test 7:
|
|
210
|
-
{
|
|
211
|
-
name: 'admin-specify-providers',
|
|
212
|
-
auth: 'admin',
|
|
213
|
-
timeout: 30000,
|
|
214
|
-
|
|
215
|
-
async run({ http, assert, config, state }) {
|
|
216
|
-
const testEmail = TEST_EMAILS.valid(config.domain);
|
|
217
|
-
state.testEmail = testEmail;
|
|
218
|
-
|
|
219
|
-
const response = await http.command('general:add-marketing-contact', {
|
|
220
|
-
email: testEmail,
|
|
221
|
-
source: 'bem-test',
|
|
222
|
-
providers: ['sendgrid'], // Only SendGrid, not Beehiiv
|
|
223
|
-
// No firstName/lastName - should be inferred as "Rachel Greene"
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
assert.isSuccess(response, 'Add marketing contact with specific providers should succeed');
|
|
227
|
-
|
|
228
|
-
// Only check providers if TEST_EXTENDED_MODE is set (external APIs are called)
|
|
229
|
-
if (process.env.TEST_EXTENDED_MODE) {
|
|
230
|
-
// Should only have sendgrid result
|
|
231
|
-
if (response.data?.providers) {
|
|
232
|
-
assert.hasProperty(response.data.providers, 'sendgrid', 'Should have SendGrid result');
|
|
233
|
-
}
|
|
234
|
-
state.sendgridAdded = response.data?.providers?.sendgrid?.success;
|
|
235
|
-
// Beehiiv not called since we only specified sendgrid
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
|
|
239
|
-
async cleanup({ state, http }) {
|
|
240
|
-
if (!process.env.TEST_EXTENDED_MODE || !state.testEmail) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
await http.command('general:remove-marketing-contact', { email: state.testEmail });
|
|
245
|
-
},
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
// Test 8: Mailbox verification (only runs if TEST_EXTENDED_MODE and ZEROBOUNCE_API_KEY are set)
|
|
209
|
+
// Test 7: Mailbox verification (only runs if TEST_EXTENDED_MODE and ZEROBOUNCE_API_KEY are set)
|
|
249
210
|
{
|
|
250
211
|
name: 'mailbox-validation',
|
|
251
212
|
auth: 'admin',
|
|
@@ -208,44 +208,7 @@ module.exports = {
|
|
|
208
208
|
},
|
|
209
209
|
},
|
|
210
210
|
|
|
211
|
-
// Test 7:
|
|
212
|
-
{
|
|
213
|
-
name: 'add-admin-specify-providers',
|
|
214
|
-
auth: 'admin',
|
|
215
|
-
timeout: 30000,
|
|
216
|
-
|
|
217
|
-
async run({ http, assert, config, state }) {
|
|
218
|
-
const testEmail = TEST_EMAILS.valid(config.domain);
|
|
219
|
-
state.testEmail = testEmail;
|
|
220
|
-
|
|
221
|
-
const response = await http.post('marketing/contact', {
|
|
222
|
-
email: testEmail,
|
|
223
|
-
source: 'bem-test',
|
|
224
|
-
providers: ['sendgrid'], // Only SendGrid, not Beehiiv
|
|
225
|
-
// No firstName/lastName - should be inferred as "Rachel Greene"
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
assert.isSuccess(response, 'Add marketing contact with specific providers should succeed');
|
|
229
|
-
|
|
230
|
-
// Provider calls only happen in extended mode
|
|
231
|
-
if (process.env.TEST_EXTENDED_MODE) {
|
|
232
|
-
// Should only have sendgrid result (since we specified providers: ['sendgrid'])
|
|
233
|
-
assert.hasProperty(response.data.providers, 'sendgrid', 'Should have SendGrid result');
|
|
234
|
-
state.sendgridAdded = response.data?.providers?.sendgrid?.success;
|
|
235
|
-
// Beehiiv not called since we only specified sendgrid
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
|
|
239
|
-
async cleanup({ state, http }) {
|
|
240
|
-
if (!process.env.TEST_EXTENDED_MODE || !state.testEmail) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
await http.delete('marketing/contact', { email: state.testEmail });
|
|
245
|
-
},
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
// Test 8: Mailbox verification (only runs if TEST_EXTENDED_MODE and ZEROBOUNCE_API_KEY are set)
|
|
211
|
+
// Test 7: Mailbox verification (only runs if TEST_EXTENDED_MODE and ZEROBOUNCE_API_KEY are set)
|
|
249
212
|
{
|
|
250
213
|
name: 'add-mailbox-validation',
|
|
251
214
|
auth: 'admin',
|
|
File without changes
|