Skip to content

Commit 9ae10c8

Browse files
committed
Added email list methods, create guest ticket upon transaction, added mailing list endpoint, add email to list on transaction
1 parent a8e164a commit 9ae10c8

File tree

5 files changed

+90
-15
lines changed

5 files changed

+90
-15
lines changed

lib/routes/sites.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
const sitesRouter = require('express').Router(),
22
{ authorizeUser } = require('../middleware/auth'),
3-
{ getSites, getSite, getSiteSettings } = require('../services/sites');
3+
{ getSites, getSite, getSiteSettings } = require('../services/sites'),
4+
{ upsertEmailSubscriber } = require('../services/email');
5+
6+
// TODO: make this configurable at some point
7+
const EMAIL_LIST = {
8+
'mustachebash.com': '90392ecd5e'
9+
};
410

511
sitesRouter.route('/')
612
.get(authorizeUser, async (req, res, next) => {
@@ -26,6 +32,19 @@ sitesRouter.route('/:id')
2632
}
2733
});
2834

35+
sitesRouter.route('/:id/mailing-list')
36+
.post(async (req, res, next) => {
37+
if(!req.body.email || !req.body.firstName || !req.body.lastName) return next(400);
38+
39+
try {
40+
await upsertEmailSubscriber(EMAIL_LIST[req.params.id], {...req.body, tags: [`Site '${req.params.id}' Form Opt-In`]});
41+
42+
res.status(204).end();
43+
} catch(e) {
44+
next(e);
45+
}
46+
});
47+
2948
sitesRouter.route('/:id/settings')
3049
.get(async (req, res, next) => {
3150
try {

lib/routes/transactions.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
const transactionsRouter = require('express').Router(),
22
{ authorizeUser } = require('../middleware/auth'),
33
{ createTransaction, getTransactions, getTransaction } = require('../services/transactions'),
4-
{ sendReceipt } = require('../services/email');
4+
{ sendReceipt, upsertEmailSubscriber } = require('../services/email');
5+
6+
// TODO: make this configurable at some point
7+
const EMAIL_LIST = '90392ecd5e',
8+
EMAIL_TAG = 'Mustache Bash 2020 Attendee';
59

610
transactionsRouter.route('/')
711
.get(authorizeUser, async (req, res, next) => {
@@ -17,10 +21,13 @@ transactionsRouter.route('/')
1721
if(!req.body) return next(400);
1822

1923
try {
20-
const transaction = await createTransaction({...req.body});
24+
const transaction = await createTransaction({...req.body}),
25+
{ email, firstName, lastName } = transaction;
2126

2227
// Send a receipt email
23-
sendReceipt(transaction.firstName, transaction.lastName, transaction.email, transaction.braintreeTransactionId, transaction.amount);
28+
sendReceipt(firstName, lastName, email, transaction.braintreeTransactionId, transaction.amount);
29+
// Add them to the mailing list and tag as an attendee
30+
upsertEmailSubscriber(EMAIL_LIST, {email, firstName, lastName, tags: [EMAIL_TAG]});
2431

2532
res.location(`https://${req.get('host')}${req.baseUrl}/${transaction.id}`);
2633
res.status(201).json(transaction.braintreeTransactionId);

lib/services/email.js

+43-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,51 @@
33
* @type {Object}
44
*/
55

6-
const config = require('../config'),
7-
mailgun = require('mailgun-js')({apiKey: config.mailgun.apiKey, domain: config.mailgun.domain});
6+
const crypto = require('crypto'),
7+
config = require('../config'),
8+
mailgun = require('mailgun-js')({apiKey: config.mailgun.apiKey, domain: config.mailgun.domain}),
9+
MailChimpClient = require('mailchimp-api-v3');
10+
11+
const mailchimp = new MailChimpClient(config.mailchimp.apiKey),
12+
md5 = string => crypto.createHash('md5').update(string).digest('hex');
13+
814
/* eslint-disable max-len */
915
module.exports = {
16+
/**
17+
* This will upsert a member into a list with first and last names, subscribe by default (but leave existing statuses in place)
18+
* then apply all tags listed
19+
* @param {string} listId Mailchimp list id
20+
* @param {string} email subscriber email
21+
* @param {string} firstName subscriber first name
22+
* @param {string} lastName subscriber last name
23+
* @param {Array} [tags=[] string }] tags to apply to member
24+
* @return {Promise}
25+
*/
26+
async upsertEmailSubscriber(listId, { email, firstName, lastName, tags = [] }) {
27+
const memberHash = md5(email.toLowerCase());
28+
29+
try {
30+
const member = await mailchimp.put(`/lists/${listId}/members/${memberHash}`, {
31+
email_address: email,
32+
status_if_new: 'subscribed',
33+
merge_fields: {
34+
FNAME: firstName,
35+
LNAME: lastName
36+
}
37+
});
38+
39+
if(tags.length) {
40+
await mailchimp.post(`/lists/${listId}/members/${memberHash}/tags`, {
41+
tags: tags.map(tag => ({name: tag, status: 'active'}))
42+
});
43+
}
44+
45+
console.log(member);
46+
} catch(e) {
47+
console.error(e);
48+
}
49+
},
50+
1051
sendReceipt(guestFirstName, guestLastName, guestEmail, confirmation, amount) {
1152
mailgun.messages().send({
1253
from: 'Mustache Bash Tickets <[email protected]>',

lib/services/guests.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ module.exports = {
8787
return generateQRDataURI(JSON.stringify(createTicketToken(ticket)));
8888
},
8989

90-
async createGuestTicket(guestId, { createdBy }) {
90+
async createGuestTicket(guestId, { createdBy = 'purchase' } = {}) {
9191
const guest = await run(r.table('guests').get(guestId));
9292

9393
if(guest.checkedIn) throw new GuestsServiceError('Could not create ticket - guest already checked in', 'LOCKED');

lib/services/transactions.js

+16-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55
const braintree = require('braintree'),
66
{ run, r } = require('../utils/db'),
7-
{ createGuest } = require('../services/guests'),
7+
{ createGuest, createGuestTicket } = require('../services/guests'),
88
{ braintree: btConfig, donationProductId } = require('../config');
99

1010
const gateway = braintree.connect({
@@ -182,13 +182,21 @@ module.exports = {
182182
orderDetails.forEach(i => {
183183
if(i.product.type === 'ticket') {
184184
for (let j = 0; j < i.quantity; j++) {
185-
createGuest({
186-
firstName: customer.firstName,
187-
lastName: customer.lastName + (j > 0 ? ` Guest ${j}` : ''),
188-
eventId: i.product.eventId,
189-
transactionId: changes[0].new_val.id,
190-
confirmationId: braintreeTransaction.id
191-
}).catch(console.error);
185+
(async () => {
186+
try {
187+
const { id: guestId } = await createGuest({
188+
firstName: customer.firstName,
189+
lastName: customer.lastName + (j > 0 ? ` Guest ${j}` : ''),
190+
eventId: i.product.eventId,
191+
transactionId: changes[0].new_val.id,
192+
confirmationId: braintreeTransaction.id
193+
});
194+
195+
await createGuestTicket(guestId);
196+
} catch(e) {
197+
console.error(e);
198+
}
199+
})();
192200
}
193201
}
194202
});

0 commit comments

Comments
 (0)