backend-manager 3.2.32 → 3.2.34
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/package.json +2 -2
- package/src/manager/functions/core/actions/api/user/sign-up copy.js +544 -0
- package/src/manager/functions/core/actions/api/user/sign-up.js +58 -504
- package/src/manager/functions/core/events/auth/before-create.js +5 -6
- package/src/manager/functions/core/events/auth/before-signin.js +3 -4
- package/src/manager/functions/core/events/auth/on-create copy.js +121 -0
- package/src/manager/functions/core/events/auth/on-create.js +466 -19
- package/src/manager/functions/core/events/auth/on-delete.js +8 -6
- package/src/manager/helpers/usage.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backend-manager",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.34",
|
|
4
4
|
"description": "Quick tools for developing Firebase functions",
|
|
5
5
|
"main": "src/manager/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -70,4 +70,4 @@
|
|
|
70
70
|
"wonderful-log": "^1.0.5",
|
|
71
71
|
"yargs": "^17.7.2"
|
|
72
72
|
}
|
|
73
|
-
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
const _ = require('lodash')
|
|
2
|
+
const fetch = require('wonderful-fetch');
|
|
3
|
+
const moment = require('moment');
|
|
4
|
+
|
|
5
|
+
const MAX_SIGNUPS = 3;
|
|
6
|
+
const MAX_AGE = 30;
|
|
7
|
+
|
|
8
|
+
function Module() {
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
Module.prototype.main = function () {
|
|
13
|
+
const self = this;
|
|
14
|
+
|
|
15
|
+
return new Promise(async function(resolve, reject) {
|
|
16
|
+
const Manager = self.Manager;
|
|
17
|
+
const assistant = self.assistant;
|
|
18
|
+
const Api = self.Api;
|
|
19
|
+
const payload = self.payload;
|
|
20
|
+
|
|
21
|
+
Api.resolveUser({adminRequired: true})
|
|
22
|
+
.then(async (user) => {
|
|
23
|
+
// ⛔️⛔️⛔️ This function could be triggered when the user signs up with Google after already having a email/password account
|
|
24
|
+
// Get auth user from firebase
|
|
25
|
+
const ip = assistant.request.geolocation.ip;
|
|
26
|
+
const authUser = await Manager.libraries.admin.auth().getUser(user.auth.uid).catch(e => e);
|
|
27
|
+
const usage = await Manager.Usage().init(assistant, {log: true, key: ip});
|
|
28
|
+
|
|
29
|
+
if (authUser instanceof Error) {
|
|
30
|
+
return reject(assistant.errorify(`Failed to get auth user: ${authUser}`, {code: 500}));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Age in seconds
|
|
34
|
+
const ageInSeconds = (Date.now() - new Date(authUser.metadata.creationTime)) / 1000;
|
|
35
|
+
|
|
36
|
+
// If the user is not new, reject
|
|
37
|
+
if (ageInSeconds >= MAX_AGE) {
|
|
38
|
+
return reject(assistant.errorify(`User is not new.`, {code: 400}));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Check if IP has signed up too many times
|
|
42
|
+
const signups = usage.getUsage('signups');
|
|
43
|
+
|
|
44
|
+
// Log the signup
|
|
45
|
+
assistant.log(`Validating signups ${signups}/${MAX_SIGNUPS} for ip ${ip}`, user);
|
|
46
|
+
|
|
47
|
+
// If over limit, reject and delete the user
|
|
48
|
+
if (signups >= MAX_SIGNUPS) {
|
|
49
|
+
await Api.import('user:delete')
|
|
50
|
+
.then(async (lib) => {
|
|
51
|
+
await lib.main().catch(e => e);
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
await self.sendRateEmail(user).catch(e => e);
|
|
55
|
+
|
|
56
|
+
// Reject
|
|
57
|
+
return reject(assistant.errorify(`Too many signups from this IP (${ip}).`, {code: 429}));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Increment signups
|
|
61
|
+
usage.increment('signups');
|
|
62
|
+
|
|
63
|
+
// Update signups
|
|
64
|
+
await usage.update();
|
|
65
|
+
|
|
66
|
+
// Send welcome email
|
|
67
|
+
await self.sendWelcomeEmail(user).catch(e => e);
|
|
68
|
+
await self.sendCheckupEmail(user).catch(e => e);
|
|
69
|
+
await self.sendFeedbackEmail(user).catch(e => e);
|
|
70
|
+
|
|
71
|
+
await self.signUp({
|
|
72
|
+
auth: {
|
|
73
|
+
uid: user?.auth?.uid,
|
|
74
|
+
email: user?.auth?.email,
|
|
75
|
+
},
|
|
76
|
+
affiliate: {
|
|
77
|
+
referrer: payload?.data?.payload?.affiliateCode || null,
|
|
78
|
+
},
|
|
79
|
+
})
|
|
80
|
+
.then(async function (result) {
|
|
81
|
+
// Skip if not a newsletter sign up
|
|
82
|
+
if (!payload?.data?.payload?.newsletterSignUp) {
|
|
83
|
+
return resolve({data: result});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Add to SendGrid list
|
|
87
|
+
await self.addToSendGridList(user)
|
|
88
|
+
.then((r) => {
|
|
89
|
+
assistant.log('addToSendGridList(): Success', r)
|
|
90
|
+
})
|
|
91
|
+
.catch((e) => {
|
|
92
|
+
assistant.log('Failed to add user to MC list.', e)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Resolve
|
|
96
|
+
return resolve({data: result});
|
|
97
|
+
})
|
|
98
|
+
.catch((e) => {
|
|
99
|
+
return reject(assistant.errorify(`Failed to sign up: ${e}`, {code: 500}));
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
.catch((e) => {
|
|
103
|
+
return reject(e);
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
Module.prototype.signUp = function (payload) {
|
|
111
|
+
const self = this;
|
|
112
|
+
|
|
113
|
+
return new Promise(async function(resolve, reject) {
|
|
114
|
+
const Manager = self.Manager;
|
|
115
|
+
const assistant = self.assistant;
|
|
116
|
+
const Api = self.Api;
|
|
117
|
+
|
|
118
|
+
const result = {
|
|
119
|
+
signedUp: false,
|
|
120
|
+
referrerUid: null,
|
|
121
|
+
// updatedReferral: true,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
payload = payload || {};
|
|
125
|
+
|
|
126
|
+
assistant.log(`signUp(): payload`, payload)
|
|
127
|
+
|
|
128
|
+
// Check if the user has a UID and email
|
|
129
|
+
if (!payload?.auth?.uid || !payload?.auth?.email) {
|
|
130
|
+
return reject(new Error('Cannot create user without UID and email.'))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Update the user who referred this user
|
|
134
|
+
await self.updateReferral({
|
|
135
|
+
affiliateCode: _.get(payload, 'affiliate.referrer', null),
|
|
136
|
+
uid: payload.auth.uid,
|
|
137
|
+
})
|
|
138
|
+
.then((r) => {
|
|
139
|
+
payload.affiliate.referrer = r.referrerUid;
|
|
140
|
+
result.referrerUid = payload.affiliate.referrer;
|
|
141
|
+
})
|
|
142
|
+
.catch((e) => {
|
|
143
|
+
payload.affiliate.referrer = null;
|
|
144
|
+
|
|
145
|
+
assistant.error('Failed to update affiliate code', e)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
// Merge the payload and the default user object
|
|
149
|
+
const user = {
|
|
150
|
+
activity: {
|
|
151
|
+
geolocation: assistant.request.geolocation,
|
|
152
|
+
client: assistant.request.client,
|
|
153
|
+
},
|
|
154
|
+
affiliate: {
|
|
155
|
+
referrer: payload.affiliate.referrer,
|
|
156
|
+
},
|
|
157
|
+
metadata: Manager.Metadata().set({tag: 'user:sign-up'}),
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
assistant.log(`signUp(): user`, user);
|
|
161
|
+
|
|
162
|
+
// Set the user
|
|
163
|
+
self.libraries.admin.firestore().doc(`users/${payload.auth.uid}`)
|
|
164
|
+
.set(user, { merge: true })
|
|
165
|
+
.then((data) => {
|
|
166
|
+
result.signedUp = true;
|
|
167
|
+
|
|
168
|
+
return resolve(result);
|
|
169
|
+
})
|
|
170
|
+
.catch((e) => {
|
|
171
|
+
return reject(e);
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
Module.prototype.updateReferral = function (payload) {
|
|
178
|
+
const self = this;
|
|
179
|
+
|
|
180
|
+
return new Promise(function(resolve, reject) {
|
|
181
|
+
const Manager = self.Manager;
|
|
182
|
+
const assistant = self.assistant;
|
|
183
|
+
const Api = self.Api;
|
|
184
|
+
|
|
185
|
+
const result = {
|
|
186
|
+
count: 0,
|
|
187
|
+
updatedReferral: false,
|
|
188
|
+
referrerUid: null,
|
|
189
|
+
}
|
|
190
|
+
payload = payload || {};
|
|
191
|
+
|
|
192
|
+
assistant.log(`updateReferral(): payload`, payload)
|
|
193
|
+
|
|
194
|
+
self.libraries.admin.firestore().collection('users')
|
|
195
|
+
.where('affiliate.code', '==', payload.affiliateCode)
|
|
196
|
+
.get()
|
|
197
|
+
.then(async (snapshot) => {
|
|
198
|
+
if (snapshot.empty) {
|
|
199
|
+
return resolve(result)
|
|
200
|
+
}
|
|
201
|
+
let count = 0;
|
|
202
|
+
let found = false;
|
|
203
|
+
let error = null;
|
|
204
|
+
|
|
205
|
+
for (var i = 0; i < snapshot.size; i++) {
|
|
206
|
+
const doc = snapshot.docs[i];
|
|
207
|
+
if (!found) {
|
|
208
|
+
let data = doc.data() || {};
|
|
209
|
+
|
|
210
|
+
let referrals = data.affiliate && data.affiliate.referrals ? data.affiliate.referrals : [];
|
|
211
|
+
referrals = Array.isArray(referrals) ? referrals : [];
|
|
212
|
+
count = referrals.length;
|
|
213
|
+
referrals = referrals.concat({
|
|
214
|
+
uid: payload.uid,
|
|
215
|
+
timestamp: self.assistant.meta.startTime.timestamp,
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
assistant.log(`updateReferral(): appending referrals...`, doc.ref.id, referrals)
|
|
219
|
+
|
|
220
|
+
await self.libraries.admin.firestore().doc(`users/${doc.ref.id}`)
|
|
221
|
+
.set({
|
|
222
|
+
affiliate: {
|
|
223
|
+
referrals: referrals,
|
|
224
|
+
}
|
|
225
|
+
}, {merge: true})
|
|
226
|
+
.catch(e => {
|
|
227
|
+
self.assistant.error('Error updating referral', e);
|
|
228
|
+
|
|
229
|
+
error = e;
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
result.count = count;
|
|
233
|
+
result.updatedReferral = true;
|
|
234
|
+
result.referrerUid = doc.ref.id;
|
|
235
|
+
found = true
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (error) {
|
|
239
|
+
return reject(error);
|
|
240
|
+
}
|
|
241
|
+
return resolve(result)
|
|
242
|
+
})
|
|
243
|
+
.catch(e => {
|
|
244
|
+
return reject(e);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
Module.prototype.addToSendGridList = function (user) {
|
|
250
|
+
const self = this;
|
|
251
|
+
|
|
252
|
+
return new Promise(async function(resolve, reject) {
|
|
253
|
+
const Manager = self.Manager;
|
|
254
|
+
const assistant = self.assistant;
|
|
255
|
+
const Api = self.Api;
|
|
256
|
+
|
|
257
|
+
if (!user?.auth?.email) {
|
|
258
|
+
return reject(new Error('Cannot add user to SendGrid list without email.'))
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Add to SendGrid list
|
|
262
|
+
fetch('https://api.itwcreativeworks.com/wrapper', {
|
|
263
|
+
method: 'post',
|
|
264
|
+
response: 'json',
|
|
265
|
+
body: {
|
|
266
|
+
backendManagerKey: Manager.config.backend_manager.key,
|
|
267
|
+
service: 'sendgrid',
|
|
268
|
+
command: `v3/marketing/contacts`,
|
|
269
|
+
method: `put`,
|
|
270
|
+
supplemental: {
|
|
271
|
+
user: user,
|
|
272
|
+
},
|
|
273
|
+
body: {
|
|
274
|
+
contacts: [
|
|
275
|
+
{
|
|
276
|
+
email: user?.auth?.email,
|
|
277
|
+
address_line_1: undefined,
|
|
278
|
+
address_line_2: undefined,
|
|
279
|
+
// alternate_emails: [],
|
|
280
|
+
city: user?.activity?.geolocation?.city,
|
|
281
|
+
country: user?.activity?.geolocation?.country,
|
|
282
|
+
first_name: undefined,
|
|
283
|
+
last_name: undefined,
|
|
284
|
+
postal_code: undefined,
|
|
285
|
+
state_province_region: user?.activity?.geolocation?.region,
|
|
286
|
+
|
|
287
|
+
custom_fields: {
|
|
288
|
+
app: Manager.config.app.id,
|
|
289
|
+
user: user?.auth?.uid,
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
})
|
|
296
|
+
.then((r) => {
|
|
297
|
+
assistant.log('addToSendGridList(): Success', r)
|
|
298
|
+
return resolve(res);
|
|
299
|
+
})
|
|
300
|
+
.catch((e) => {
|
|
301
|
+
assistant.error('addToSendGridList(): Failed', e)
|
|
302
|
+
return resolve(e);
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
// await self.libraries.sendgrid.request({
|
|
306
|
+
// method: 'post',
|
|
307
|
+
// url: `/v3/contactdb/recipients`,
|
|
308
|
+
// body: [{
|
|
309
|
+
// email: email,
|
|
310
|
+
// }],
|
|
311
|
+
// })
|
|
312
|
+
// .then(function (res) {
|
|
313
|
+
// assistant.log('Sucessfully added user to SendGrid list.')
|
|
314
|
+
// return resolve(res);
|
|
315
|
+
// })
|
|
316
|
+
// .catch(function (e) {
|
|
317
|
+
// assistant.log('Failed to add user to SendGrid list.', e)
|
|
318
|
+
// return resolve(e);
|
|
319
|
+
// })
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
Module.prototype.sendRateEmail = function (user) {
|
|
324
|
+
const self = this;
|
|
325
|
+
|
|
326
|
+
return new Promise(async function(resolve, reject) {
|
|
327
|
+
const Manager = self.Manager;
|
|
328
|
+
const assistant = self.assistant;
|
|
329
|
+
|
|
330
|
+
// Send email
|
|
331
|
+
fetch(`https://us-central1-itw-creative-works.cloudfunctions.net/sendEmail`, {
|
|
332
|
+
method: 'post',
|
|
333
|
+
response: 'json',
|
|
334
|
+
log: true,
|
|
335
|
+
body: {
|
|
336
|
+
backendManagerKey: Manager.config.backend_manager.key,
|
|
337
|
+
app: Manager.config.app.id,
|
|
338
|
+
to: {
|
|
339
|
+
email: user.auth.email,
|
|
340
|
+
},
|
|
341
|
+
categories: [`account/too-many-signups`],
|
|
342
|
+
subject: `Your ${Manager.config.brand.name} account has been deleted [${user.auth.uid}]`,
|
|
343
|
+
template: 'd-b7f8da3c98ad49a2ad1e187f3a67b546',
|
|
344
|
+
group: 25927,
|
|
345
|
+
copy: true,
|
|
346
|
+
data: {
|
|
347
|
+
email: {
|
|
348
|
+
preview: `You have signed up for too many accounts at ${Manager.config.brand.name}! Your account has been deleted.`,
|
|
349
|
+
},
|
|
350
|
+
body: {
|
|
351
|
+
title: `${Manager.config.brand.name} account deleted`,
|
|
352
|
+
message: `
|
|
353
|
+
Your account at <strong>${Manager.config.brand.name}</strong> has been <strong>deleted</strong> because you have signed up for too many accounts.
|
|
354
|
+
<br>
|
|
355
|
+
<br>
|
|
356
|
+
If you believe this is a mistake, please contact us at ${Manager.config.brand.email}.
|
|
357
|
+
<br>
|
|
358
|
+
<br>
|
|
359
|
+
<strong>User Details</strong>:
|
|
360
|
+
<br>
|
|
361
|
+
<strong>UID</strong>: ${user.auth.uid}
|
|
362
|
+
<br>
|
|
363
|
+
<strong>Email</strong>: ${user.auth.email}
|
|
364
|
+
<br>
|
|
365
|
+
`,
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
})
|
|
370
|
+
.then((json) => {
|
|
371
|
+
assistant.log('sendEmail(): Success', json)
|
|
372
|
+
return resolve(json);
|
|
373
|
+
})
|
|
374
|
+
.catch((e) => {
|
|
375
|
+
assistant.error('sendEmail(): Failed', e)
|
|
376
|
+
return resolve(e);
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
Module.prototype.sendWelcomeEmail = function (user) {
|
|
382
|
+
const self = this;
|
|
383
|
+
|
|
384
|
+
return new Promise(async function(resolve, reject) {
|
|
385
|
+
const Manager = self.Manager;
|
|
386
|
+
const assistant = self.assistant;
|
|
387
|
+
|
|
388
|
+
// Send email
|
|
389
|
+
fetch(`https://us-central1-itw-creative-works.cloudfunctions.net/sendEmail`, {
|
|
390
|
+
method: 'post',
|
|
391
|
+
response: 'json',
|
|
392
|
+
log: true,
|
|
393
|
+
body: {
|
|
394
|
+
backendManagerKey: Manager.config.backend_manager.key,
|
|
395
|
+
app: Manager.config.app.id,
|
|
396
|
+
to: {
|
|
397
|
+
email: user.auth.email,
|
|
398
|
+
},
|
|
399
|
+
categories: [`account/welcome`],
|
|
400
|
+
subject: `Welcome to ${Manager.config.brand.name}!`,
|
|
401
|
+
template: 'd-b7f8da3c98ad49a2ad1e187f3a67b546',
|
|
402
|
+
group: 25928,
|
|
403
|
+
copy: false,
|
|
404
|
+
sendAt: moment().add(1, 'hour').unix(),
|
|
405
|
+
data: {
|
|
406
|
+
email: {
|
|
407
|
+
preview: `Welcome aboard! I'm Ian, the CEO and founder of ${Manager.config.brand.name}. I'm here to ensure your journey with us gets off to a great start.`,
|
|
408
|
+
},
|
|
409
|
+
body: {
|
|
410
|
+
title: `Welcome to ${Manager.config.brand.name}!`,
|
|
411
|
+
message: `
|
|
412
|
+
Welcome aboard!
|
|
413
|
+
<br><br>
|
|
414
|
+
I'm Ian, the founder and CEO of <strong>${Manager.config.brand.name}</strong>, and I'm thrilled to have you with us.
|
|
415
|
+
Your journey begins today, and we are committed to supporting you every step of the way.
|
|
416
|
+
<br><br>
|
|
417
|
+
Feel free to reply directly to this email with any questions you may have.
|
|
418
|
+
Our team and I are dedicated to ensuring your experience is exceptional.
|
|
419
|
+
<br><br>
|
|
420
|
+
Thank you for choosing <strong>${Manager.config.brand.name}</strong>. Here's to new beginnings!
|
|
421
|
+
`
|
|
422
|
+
},
|
|
423
|
+
signoff: {
|
|
424
|
+
type: 'personal',
|
|
425
|
+
image: undefined,
|
|
426
|
+
name: 'Ian Wiedenman, CEO',
|
|
427
|
+
url: `https://ianwiedenman.com?utm_source=welcome-email&utm_medium=email&utm_campaign=${Manager.config.app.id}`,
|
|
428
|
+
urlText: '@ianwieds',
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
})
|
|
433
|
+
.then((json) => {
|
|
434
|
+
assistant.log('sendEmail(): Success', json)
|
|
435
|
+
return resolve(json);
|
|
436
|
+
})
|
|
437
|
+
.catch((e) => {
|
|
438
|
+
assistant.error('sendEmail(): Failed', e)
|
|
439
|
+
return resolve(e);
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
Module.prototype.sendCheckupEmail = function (user) {
|
|
445
|
+
const self = this;
|
|
446
|
+
|
|
447
|
+
return new Promise(async function(resolve, reject) {
|
|
448
|
+
const Manager = self.Manager;
|
|
449
|
+
const assistant = self.assistant;
|
|
450
|
+
|
|
451
|
+
// Send email
|
|
452
|
+
fetch(`https://us-central1-itw-creative-works.cloudfunctions.net/sendEmail`, {
|
|
453
|
+
method: 'post',
|
|
454
|
+
response: 'json',
|
|
455
|
+
log: true,
|
|
456
|
+
body: {
|
|
457
|
+
backendManagerKey: Manager.config.backend_manager.key,
|
|
458
|
+
app: Manager.config.app.id,
|
|
459
|
+
to: {
|
|
460
|
+
email: user.auth.email,
|
|
461
|
+
},
|
|
462
|
+
categories: [`account/checkup`],
|
|
463
|
+
subject: `How's your experience with ${Manager.config.brand.name}?`,
|
|
464
|
+
template: 'd-b7f8da3c98ad49a2ad1e187f3a67b546',
|
|
465
|
+
group: 25928,
|
|
466
|
+
copy: false,
|
|
467
|
+
sendAt: moment().add(7, 'days').unix(),
|
|
468
|
+
data: {
|
|
469
|
+
email: {
|
|
470
|
+
preview: `Checking in from ${Manager.config.brand.name} to see how things are going. Let us know if you have any questions or feedback!`,
|
|
471
|
+
},
|
|
472
|
+
body: {
|
|
473
|
+
title: `How's everything going?`,
|
|
474
|
+
message: `
|
|
475
|
+
Hi there,
|
|
476
|
+
<br><br>
|
|
477
|
+
It's Ian again from <strong>${Manager.config.brand.name}</strong>. Just checking in to see how things are going for you.
|
|
478
|
+
<br><br>
|
|
479
|
+
Have you had a chance to explore all our features? Any questions or feedback for us?
|
|
480
|
+
<br><br>
|
|
481
|
+
We're always here to help, so don't hesitate to reach out. Just reply to this email and we'll get back to you as soon as possible.
|
|
482
|
+
<br><br>
|
|
483
|
+
Thank you for choosing <strong>${Manager.config.brand.name}</strong>. Here's to new beginnings!
|
|
484
|
+
`
|
|
485
|
+
},
|
|
486
|
+
signoff: {
|
|
487
|
+
type: 'personal',
|
|
488
|
+
image: undefined,
|
|
489
|
+
name: 'Ian Wiedenman, CEO',
|
|
490
|
+
url: `https://ianwiedenman.com?utm_source=checkup-email&utm_medium=email&utm_campaign=${Manager.config.app.id}`,
|
|
491
|
+
urlText: '@ianwieds',
|
|
492
|
+
},
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
})
|
|
496
|
+
.then((json) => {
|
|
497
|
+
assistant.log('sendEmail(): Success', json)
|
|
498
|
+
return resolve(json);
|
|
499
|
+
})
|
|
500
|
+
.catch((e) => {
|
|
501
|
+
assistant.error('sendEmail(): Failed', e)
|
|
502
|
+
return resolve(e);
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
Module.prototype.sendFeedbackEmail = function (user) {
|
|
508
|
+
const self = this;
|
|
509
|
+
|
|
510
|
+
return new Promise(async function(resolve, reject) {
|
|
511
|
+
const Manager = self.Manager;
|
|
512
|
+
const assistant = self.assistant;
|
|
513
|
+
|
|
514
|
+
// Send email
|
|
515
|
+
fetch(`https://us-central1-itw-creative-works.cloudfunctions.net/sendEmail`, {
|
|
516
|
+
method: 'post',
|
|
517
|
+
response: 'json',
|
|
518
|
+
log: true,
|
|
519
|
+
body: {
|
|
520
|
+
backendManagerKey: Manager.config.backend_manager.key,
|
|
521
|
+
app: Manager.config.app.id,
|
|
522
|
+
to: {
|
|
523
|
+
email: user.auth.email,
|
|
524
|
+
},
|
|
525
|
+
categories: [`engagement/feedback`],
|
|
526
|
+
subject: `Want to share your feedback about ${Manager.config.brand.name}?`,
|
|
527
|
+
template: 'd-c1522214c67b47058669acc5a81ed663',
|
|
528
|
+
group: 25928,
|
|
529
|
+
copy: false,
|
|
530
|
+
sendAt: moment().add(14, 'days').unix(),
|
|
531
|
+
},
|
|
532
|
+
})
|
|
533
|
+
.then((json) => {
|
|
534
|
+
assistant.log('sendEmail(): Success', json)
|
|
535
|
+
return resolve(json);
|
|
536
|
+
})
|
|
537
|
+
.catch((e) => {
|
|
538
|
+
assistant.error('sendEmail(): Failed', e)
|
|
539
|
+
return resolve(e);
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
module.exports = Module;
|