Permalink
Browse files

fix: welcome email (#2859)

And add report for new customers to help narrow down fraud abuse
  • Loading branch information...
1 parent 8f224c0 commit c2a947a1d0ad3b3940ed47cc74ac28c973cc3ccc @remy remy committed on GitHub Aug 24, 2016
@@ -4,7 +4,7 @@
</td>
</tr>
<tr style="vertical-align: top; padding: 0;">
- <td class="container templateContainerPadding" align="center" valign="top" style="vertical-align: top; padding: 0 40px;">
+ <td class="container templateContainerPadding" align="center" valign="top" style="vertical-align: top; padding: 0;">
<table id="footerContent" style="border-spacing: 0; border-collapse: collapse; font-family: proxima-nova, 'helvetica neue', helvetica, arial, geneva, sans-serif; height: 100%; width: 100%; border-top-style: solid; border-top-color: #ebeaef; color: #999999; font-size: 12px; background: #ffffff; margin: 0; padding: 0; border-width: 1px 0 0;">
<tr style="vertical-align: top; padding: 0;">
<td valign="top" style="vertical-align: top; text-align: left; padding: 0;" align="left">
@@ -54,7 +54,11 @@
height: 100% !important; margin: 0; padding: 0; width: 100% !important;
}
#backgroundTable {
-color: #4c4c4c; background-color: #ffffff; font-family: proxima-nova, 'helvetica neue', helvetica, arial, geneva, sans-serif; font-size: 15px; line-height: 150%;
+color: #4c4c4c; background-color: #ffffff; font-family: sans-serif; font-size: 14px; line-height: 150%;
+}
+
+@media only screen and (min-width: 600px) {
+ .container { width: auto !important; padding: 0 40px !important;}
}
@media screen and (max-width: 600px) {
@@ -63,4 +67,4 @@
.container { width: auto !important; padding: 0 10px !important;}
}</style>
</body>
-</html>
+</html>
@@ -3,15 +3,65 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, target-densitydpi=device-dpi">
+ <style>
+ img {
+ border: none;
+ -ms-interpolation-mode: bicubic;
+ max-width: 100%; }
+
+ body {
+ background-color: #f6f6f6;
+ font-family: sans-serif;
+ -webkit-font-smoothing: antialiased;
+ font-size: 14px;
+ line-height: 1.4;
+ margin: 0;
+ padding: 0;
+ -ms-text-size-adjust: 100%;
+ -webkit-text-size-adjust: 100%; }
+
+ table {
+ border-collapse: separate;
+ mso-table-lspace: 0pt;
+ mso-table-rspace: 0pt;
+ width: 100%; }
+ table td {
+ font-family: sans-serif;
+ font-size: 14px;
+ vertical-align: top; }
+
+ @media all {
+ .ExternalClass {
+ width: 100%; }
+ .ExternalClass,
+ .ExternalClass p,
+ .ExternalClass span,
+ .ExternalClass font,
+ .ExternalClass td,
+ .ExternalClass div {
+ line-height: 100%; }
+ .apple-link a {
+ color: inherit !important;
+ font-family: inherit !important;
+ font-size: inherit !important;
+ font-weight: inherit !important;
+ line-height: inherit !important;
+ text-decoration: none !important; }
+ .btn-primary table td:hover {
+ background-color: #34495e !important; }
+ .btn-primary a:hover {
+ background-color: #34495e !important;
+ border-color: #34495e !important; } }
+ </style>
</head>
<body id="jsbinannouce" style="width: 100% !important; -webkit-text-size-adjust: none; margin: 0; padding: 0;">
<center>
- <table id="backgroundTable" style="border-spacing: 0; border-collapse: collapse; font-family: proxima-nova, 'helvetica neue', helvetica, arial, geneva, sans-serif; height: 100% !important; width: 100% !important; color: #4c4c4c; font-size: 15px; line-height: 150%; background: #ffffff; margin: 0; padding: 0; border: 0;">
+ <table id="backgroundTable" style="border-spacing: 0; border-collapse: collapse; font-family: sans-serif; height: 100% !important; width: 100% !important; color: #4c4c4c; font-size: 14px; line-height: 150%; background: #ffffff; margin: 0; padding: 0; border: 0;">
<tr style="vertical-align: top; padding: 0;">
<td align="center" valign="top" style="vertical-align: top; padding: 0;">
- <table class="container" id="templateContainer" style="border-spacing: 0; border-collapse: collapse; font-family: proxima-nova, 'helvetica neue', helvetica, arial, geneva, sans-serif; height: 100%; width: 600px; color: #4c4c4c; font-size: 15px; line-height: 150%; background: #ffffff; margin: 0px 0; padding: 0; border: 0;">
+ <table class="container" id="templateContainer" style="border-spacing: 0; border-collapse: collapse; font-family: sans-serif; height: 100%; width: 600px; color: #4c4c4c; font-size: 14px; line-height: 150%; background: #ffffff; margin: 0px 0; padding: 0; border: 0;">
<tr style="vertical-align: top; padding: 0;">
- <td class="container templateContainerPadding" align="center" valign="top" style="vertical-align: top; padding: 0 40px;">
- <table id="templateContent" style="border-spacing: 0; border-collapse: collapse; font-family: proxima-nova, 'helvetica neue', helvetica, arial, geneva, sans-serif; height: 100%; width: 100%; background: #ffffff; margin: 0; padding: 0; border: 0;">
+ <td class="container templateContainerPadding" align="center" valign="top" style="vertical-align: top; padding: 0;">
+ <table id="templateContent" style="border-spacing: 0; border-collapse: collapse; font-family: sans-serif; height: 100%; width: 100%; background: #ffffff; margin: 0; padding: 0; border: 0;">
<tr style="vertical-align: top; padding: 0;">
<td style="vertical-align: top; text-align: left; padding: 0;" align="left" valign="top">
@@ -0,0 +1,16 @@
+{{>email-header}}
+
+<!-- BODY -->
+
+<p style="font-weight: bold; margin: 20px 0;"><strong>New customer created:</strong></p>
+<ul>
+<li style="margin: 0;">username: <a href="https://jsbin.com/user/{{username}}">{{username}}</a> (<a href="{{html_url}}">github</a>)</li>
+<li style="margin: 0;">plan: {{plan.name}} (£{{#divide plan.amount 100 2}}{{/divide}})</li>
+<li style="margin: 0;">repos: {{public_repos}}</li>
+<li style="margin: 0;">gists: {{public_gists}}</li>
+<li style="margin: 0;">followers: {{followers}}</li>
+<li style="margin: 0;">following: {{following}}</li>
+</ul>
+
+<!-- /BODY -->
+{{>email-footer}}
@@ -0,0 +1,13 @@
+New customer created:
+
+- username: [{{username}}](https://jsbin.com/user/{{username}}) ([github]({{html_url}}))
+- plan: {{plan.id}} (£{{#divide plan.amount 100 2}}{{/divide}})
+- repos: {{public_repos}}
+- gists: {{public_gists}}
+- followers: {{followers}}
+- following: {{following}}
+
+---
+
+JS Bin Ltd. Company No. 8998555
+Made in Brighton, UK
@@ -9,6 +9,12 @@ var emailRoot = path.resolve(__dirname, '..', '..', 'emails');
var config = require('../config');
require('../hbs'); // load helpers if they're not there yet
+// register the header + footer partial
+['email-header', 'email-footer'].forEach(function (name) {
+ var template = fs.readFileSync(emailRoot + '/' + name + '.html', 'utf8');
+ hbs.registerPartial(name, template);
+});
+
function send(emailData) {
if (!emailData.from) {
emailData.from = 'support@jsbin.com';
@@ -0,0 +1,42 @@
+'use strict';
+var debug = require('debug')('jsbin:upgrade');
+var request = require('request');
+var emailSender = require('../../email');
+
+module.exports = function (stripe) {
+ return function (req, data, done) {
+ var customerId = data.customer;
+ debug('stripe.customers.retrieve(%s)', customerId);
+
+ done(null, true);
+
+ stripe.customers.retrieve(customerId).then(function (customer) {
+ // check the customer against github and see if
+ // they have any repos, stars follows etc.
+ // and email the profile to myself
+ request({
+ url: 'https://api.github.com/users/' + customer.metadata.username,
+ headers: {
+ 'user-agent': 'jsbin',
+ 'accept': 'application/vnd.github.v3+json',
+ },
+ json: true
+ }, function (error, response, body) {
+ console.log(data);
+ body.username = body.login;
+ body.plan = data.plan;
+ emailSender.send({
+ filename: 'new-customer-report',
+ data: body,
+ to: 'info@jsbin.com',
+ subject: 'new customer report',
+ }).catch(function (e) {
+ console.log('customer report failed');
+ console.log(e.stack);
+ });
+
+ });
+ });
+ }
+}
+
@@ -19,6 +19,7 @@ module.exports = function (config) {
'customer.subscription.deleted': require('./customer.subscription.deleted'),
'invoice.created': require('./invoice.created')(stripe),
'charge.failed': require('./charge.failed')(stripe),
+ 'customer.subscription.created': require('./customer.subscription.created')(stripe),
};
return {
View
@@ -62,6 +62,7 @@
"passport-github": "~0.1.5",
"promise": "~5.0.0",
"replify": "~1.2.0",
+ "request": "^2.74.0",
"rsvp": "~3.0.1",
"semver": "^5.0.3",
"snyk": "^1.12.0",
@@ -87,9 +88,12 @@
"mocha": "~1.21.4",
"mocha-casperjs": "~0.5.0",
"nightwatch": "^0.9.6",
+ "proxyquire": "^1.7.10",
"selenium-standalone": "^5.5.0",
"should": "~1.2.2",
- "sinon": "~1.7.3"
+ "sinon": "~1.7.3",
+ "tap": "^6.3.2",
+ "tap-only": "0.0.5"
},
"optionalDependencies": {
"zmq": "~2.6.0"
@@ -0,0 +1,16 @@
+{
+ "id": "cus_XXXXXXXXXXX",
+ "object": "customer",
+ "account_balance": 0,
+ "created": 1462738589,
+ "currency": "gbp",
+ "default_source": "card_XXXXXXXXXXXXX",
+ "delinquent": false,
+ "description": "Chloe Anderson",
+ "discount": null,
+ "email": "chloe.anderson.56@example.com",
+ "livemode": false,
+ "metadata": {
+ "username": "Rishard1"
+ }
+}
@@ -0,0 +1,48 @@
+{
+ "id": "evt_XXXXXXXXXXXX",
+ "object": "event",
+ "api_version": "2014-06-17",
+ "created": 1471018855,
+ "data": {
+ "object": {
+ "id": "sub_XXXXXXXXX",
+ "object": "subscription",
+ "application_fee_percent": null,
+ "cancel_at_period_end": false,
+ "canceled_at": null,
+ "created": 1471018852,
+ "current_period_end": 1502554852,
+ "current_period_start": 1471018852,
+ "customer": "cus_XXXXXXXXXXXX",
+ "discount": null,
+ "ended_at": null,
+ "livemode": true,
+ "metadata": {},
+ "plan": {
+ "id": "yearly3",
+ "object": "plan",
+ "amount": 9999,
+ "created": 1434381891,
+ "currency": "gbp",
+ "interval": "year",
+ "interval_count": 1,
+ "livemode": true,
+ "metadata": {},
+ "name": "Pro yearly",
+ "statement_descriptor": "JS BIN PRO (yearly)",
+ "trial_period_days": null,
+ "statement_description": "JS BIN PRO (yearly)"
+ },
+ "quantity": 1,
+ "start": 1471018852,
+ "status": "active",
+ "tax_percent": null,
+ "trial_end": null,
+ "trial_start": null
+ }
+ },
+ "livemode": true,
+ "pending_webhooks": 3,
+ "request": "req_XXXXXXXXXX",
+ "type": "customer.subscription.created"
+}
@@ -0,0 +1,22 @@
+var test = require('tap-only');
+global.Promise = require('promise'); // expose
+var root = __dirname + '/../../..';
+var emailSender = require(root + '/lib/email');
+
+test('welcome email', function (t) {
+ var data = {
+ name: 'remy',
+ email: 'remy@jsbin.com'
+ };
+ return emailSender.send({
+ filename: 'welcome',
+ data: { user: {
+ name: data.name,
+ email: data.email,
+ }, },
+ to: data.email,
+ subject: 'Welcome!',
+ }).then(function () {
+ t.ok('email sent');
+ });
+});
@@ -0,0 +1,24 @@
+var test = require('tap-only');
+global.Promise = require('promise'); // expose
+var root = __dirname + '/../../../..';
+var event = require(root + '/test/fixtures/customer.subscription.created.json').data.object;
+var user = require(root + '/test/fixtures/customer.json');
+
+test('customer.subscription.created', function (t) {
+ var handler = require(root + '/lib/stripe/handlers/customer.subscription.created.js');
+ var stripe = {
+ customers: {
+ retrieve: function (id) {
+ return Promise.resolve(user);
+ }
+ }
+ };
+
+ handler(stripe)({}, event, function (error, res) {
+ setTimeout(function () {
+ t.ok(res, 'got response');
+ t.equal(error, null, 'no error');
+ t.end();
+ }, 200);
+ });
+});

0 comments on commit c2a947a

Please sign in to comment.