From 3660f1a85c1447de118f334a145d0d7698b93981 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 30 Jan 2014 10:51:32 -0700 Subject: [PATCH 1/6] feat(premium): backport server code for premium subs (it's just ccard handling & uer model stuff) --- src/controllers/user.js | 67 +++++++++++++++++++++++++----- src/models/user.js | 7 ++++ src/routes/apiv2.coffee | 5 +++ views/shared/modals/new-stuff.jade | 2 +- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/controllers/user.js b/src/controllers/user.js index 5174d6f955..063aa5cceb 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -166,6 +166,9 @@ acceptablePUTPaths = _.reduce(require('./../models/user').schema.paths, function if (found) m[leaf]=true; return m; }, {}) +_.each('stats.gp'.split(' '), function(removePath){ + delete acceptablePUTPaths[removePath]; +}) /** * Update user @@ -257,6 +260,8 @@ api.addTenGems = function(req, res) { }) } +// TODO delete plan + /* Setup Stripe response when posting payment */ @@ -264,20 +269,39 @@ api.buyGems = function(req, res) { var api_key = nconf.get('STRIPE_API_KEY'); var stripe = require("stripe")(api_key); var token = req.body.id; - // console.dir {token:token, req:req}, 'stripe' + var user = res.locals.user; async.waterfall([ function(cb){ - stripe.charges.create({ - amount: "500", // $5 - currency: "usd", - card: token - }, cb); + if (req.query.plan) { + stripe.customers.create({ + email: req.body.email, + metadata: {uuid: res.locals.user._id}, + card: token, + plan: req.query.plan, + }, cb); + } else { + stripe.charges.create({ + amount: "500", // $5 + currency: "usd", + card: token + }, cb); + } }, function(response, cb) { - res.locals.user.balance += 5; - res.locals.user.purchased.ads = true; - res.locals.user.save(cb); + //user.purchased.ads = true; + if (req.query.plan) { + user.purchased.plan = { + planId:'basic_earned', + customerId: response.id, + dateCreated: new Date, + dateUpdated: new Date, + gemsBought: 0 + }; + } else { + user.balance += 5; + } + user.save(cb); } ], function(err, saved){ if (err) return res.send(500, err.toString()); // don't json this, let toString() handle errors @@ -285,6 +309,29 @@ api.buyGems = function(req, res) { }); }; +api.cancelSubscription = function(req, res) { + var api_key = nconf.get('STRIPE_API_KEY'); + var stripe = require("stripe")(api_key); + var user = res.locals.user; + if (!user.purchased.plan.customerId) + return res.json(401, {err: "User does not have a plan subscription"}); + + async.waterfall([ + function(cb) { + stripe.customers.del(user.purchased.plan.customerId, cb); + }, + function(response, cb) { + user.purchased.plan = {}; + user.markModified('purchased.plan'); + user.save(cb); + } + ], function(err, saved){ + if (err) return res.send(500, err.toString()); // don't json this, let toString() handle errors + res.send(200, saved); + }); + +} + api.buyGemsPaypalIPN = function(req, res, next) { res.send(200); ipn.verify(req.body, function callback(err, msg) { @@ -298,7 +345,7 @@ api.buyGemsPaypalIPN = function(req, res, next) { if (_.isEmpty(user)) err = "user not found with uuid " + uuid + " when completing paypal transaction"; if (err) return nex(err); user.balance += 5; - user.purchased.ads = true; + //user.purchased.ads = true; user.save(); console.log('PayPal transaction completed and user updated'); }); diff --git a/src/models/user.js b/src/models/user.js index ef8a8b3e18..391810fb54 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -78,6 +78,13 @@ var UserSchema = new Schema({ skin: {type: Schema.Types.Mixed, 'default': {}}, // eg, {skeleton: true, pumpkin: true, eb052b: true} hair: {type: Schema.Types.Mixed, 'default': {}}, shirt: {type: Schema.Types.Mixed, 'default': {}}, + plan: { + planId: String, + customerId: String, + dateCreated: Date, + dateUpdated: Date, + gemsBought: {type: Number, 'default': 0} + } }, flags: { diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 2d8bc073ab..513fb7e312 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -304,6 +304,11 @@ module.exports = (swagger, v2) -> middleware: auth.auth action:user.buyGems + "/user/cancel-subscription": + spec: method: 'POST', description: "Do not use this route" + middleware: auth.auth + action:user.cancelSubscription + "/user/buy-gems/paypal-ipn": spec: method: 'POST' diff --git a/views/shared/modals/new-stuff.jade b/views/shared/modals/new-stuff.jade index 096590cbce..9eb471415b 100644 --- a/views/shared/modals/new-stuff.jade +++ b/views/shared/modals/new-stuff.jade @@ -42,7 +42,7 @@ div(modal='modals.newStuff') tr td h5 Spread The Word Challenge Update - p We have 2k+ submissions, holy cow! Great job everyone! Now, we need to go through these manually, so it will take a few days to a couple weeks to process. The challenge will stay open until we're done choosing our winners, but be sure to edit the To-Do with your submission URL before 1/31, as that's the cut-off date for processing. We'll send a Tweet out when the winner has been selected, so follow @habitrpg and stay tuned. + p We have 1k+ submissions, holy cow! Great job everyone! Now, we need to go through these manually, so it will take a few days to a couple weeks to process. The challenge will stay open until we're done choosing our winners, but be sure to edit the To-Do with your submission URL before 1/31, as that's the cut-off date for processing. We'll send a Tweet out when the winner has been selected, so follow @habitrpg and stay tuned. From 5b0639287999b366d19cfde158d320f26b4d501e Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 30 Jan 2014 10:55:28 -0700 Subject: [PATCH 2/6] chore(newrelic): add newrelic --- .gitignore | 1 + .nodemonignore | 1 + newrelic.js | 25 +++++++++++++++++++++++++ package.json | 3 ++- src/server.js | 2 ++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 newrelic.js diff --git a/.gitignore b/.gitignore index a7d8e7d2e6..ef989eaea0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ npm-debug.log lib public/bower_components build +newrelic_agent.log src/*/*.map src/*/*/*.map diff --git a/.nodemonignore b/.nodemonignore index 216c52f8b0..f4e0b53926 100644 --- a/.nodemonignore +++ b/.nodemonignore @@ -6,3 +6,4 @@ Gruntfile.js CHANGELOG.md .idea* .git* +newrelic_agent.log diff --git a/newrelic.js b/newrelic.js new file mode 100644 index 0000000000..48127ad3bc --- /dev/null +++ b/newrelic.js @@ -0,0 +1,25 @@ +/** + * New Relic agent configuration. + * + * See lib/config.defaults.js in the agent distribution for a more complete + * description of configuration variables and their potential values. + */ +var nconf = require('nconf') +exports.config = { + /** + * Array of application names. + */ + app_name : ['HabitRPG'], + /** + * Your New Relic license key. + */ + license_key : nconf.get('NEWRELIC'), + logging : { + /** + * Level at which to log. 'trace' is most useful to New Relic when diagnosing + * issues with the agent, 'info' and higher will impose the least overhead on + * production applications. + */ + level : 'trace' + } +}; diff --git a/package.json b/package.json index 2ecac913bc..9e3e9a52d4 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "domain-middleware": "~0.1.0", "swagger-node-express": "git://github.com/lefnire/swagger-node-express#habitrpg", "passport": "~0.1.18", - "passport-facebook": "~1.0.2" + "passport-facebook": "~1.0.2", + "newrelic": "~1.3.0" }, "private": true, "subdomain": "habitrpg", diff --git a/src/server.js b/src/server.js index a5013dcc44..5ad08abe4b 100644 --- a/src/server.js +++ b/src/server.js @@ -17,6 +17,8 @@ var server; // ------------ Setup configurations ------------ utils.setupConfig(); +if (nconf.get('NODE_ENV') === 'production') + require('newrelic'); // ------------ MongoDB Configuration ------------ mongoose = require('mongoose'); From 2d4d103ca6104d7d60ac355f42269db2b5a7db74 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 30 Jan 2014 10:56:40 -0700 Subject: [PATCH 3/6] chore(bower): strange temporary fix. Can't remember where I picked this up, but I was having issues deploying to prod with bower referencing a private repo (using github oauth key, see private#premium) --- .bowerrc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.bowerrc b/.bowerrc index 9c9ea40600..20772d5d24 100644 --- a/.bowerrc +++ b/.bowerrc @@ -1,3 +1,8 @@ { - "directory": "public/bower_components" + "directory": "public/bower_components", + "storage": { + "packages": ".bower-cache", + "registry": ".bower-registry" + }, + "tmp": ".bower-tmp" } \ No newline at end of file From 85e2ce5c4a10068ab2d2879968d08c8e52ee1769 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 30 Jan 2014 11:04:17 -0700 Subject: [PATCH 4/6] chore(logging): don't log in production --- src/server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server.js b/src/server.js index 5ad08abe4b..0dec3210ac 100644 --- a/src/server.js +++ b/src/server.js @@ -76,7 +76,8 @@ passport.use(new FacebookStrategy({ // ------------ Server Configuration ------------ app.set("port", nconf.get('PORT')); -if (!process.env.SUPPRESS) app.use(express.logger("dev")); +if (nconf.get('NODE_ENV') !== 'production') + app.use(express.logger("dev")); app.use(express.compress()); app.set("views", __dirname + "/../views"); app.set("view engine", "jade"); From 416feca42e6c9d2dd42a66701bbf2a0ab0374a3e Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 30 Jan 2014 11:52:58 -0700 Subject: [PATCH 5/6] chore(newrelic): use license key in accordance with https://docs.newrelic.com/docs/nodejs/nodejs-agent-on-heroku --- config.json.example | 3 ++- newrelic.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config.json.example b/config.json.example index 5cf560aae6..634d22c7a7 100644 --- a/config.json.example +++ b/config.json.example @@ -13,5 +13,6 @@ "SMTP_SERVICE":"Gmail", "STRIPE_API_KEY":"aaaabbbbccccddddeeeeffff00001111", "STRIPE_PUB_KEY":"22223333444455556666777788889999", - "PAYPAL_MERCHANT":"paypal-merchant@gmail.com" + "PAYPAL_MERCHANT":"paypal-merchant@gmail.com", + "NEW_RELIC_LICENSE_KEY":"NEW_RELIC_LICENSE_KEY" } diff --git a/newrelic.js b/newrelic.js index 48127ad3bc..7763ba2269 100644 --- a/newrelic.js +++ b/newrelic.js @@ -13,7 +13,7 @@ exports.config = { /** * Your New Relic license key. */ - license_key : nconf.get('NEWRELIC'), + license_key : nconf.get('NEW_RELIC_LICENSE_KEY'), logging : { /** * Level at which to log. 'trace' is most useful to New Relic when diagnosing From 6f2f3dd71e5b0419ceec326d2209df03c4831094 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 30 Jan 2014 13:43:30 -0700 Subject: [PATCH 6/6] chore(newrelic): some newrelic code location experiments --- newrelic.js | 2 +- src/server.js | 9 ++------- src/utils.js | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/newrelic.js b/newrelic.js index 7763ba2269..682f608e42 100644 --- a/newrelic.js +++ b/newrelic.js @@ -20,6 +20,6 @@ exports.config = { * issues with the agent, 'info' and higher will impose the least overhead on * production applications. */ - level : 'trace' + level : 'warning' } }; diff --git a/src/server.js b/src/server.js index 0dec3210ac..fb76862fad 100644 --- a/src/server.js +++ b/src/server.js @@ -1,5 +1,6 @@ -// Only do the minimal amount of work before forking just in case of a dyno restart var nconf = require('nconf'); +var utils = require('./utils'); +utils.setupConfig(); require('coffee-script') // remove this once we've fully converted over var express = require("express"); @@ -8,18 +9,12 @@ var path = require("path"); var domainMiddleware = require('domain-middleware'); var swagger = require("swagger-node-express"); -var utils = require('./utils'); var middleware = require('./middleware'); var TWO_WEEKS = 1000 * 60 * 60 * 24 * 14; var app = express(); var server; -// ------------ Setup configurations ------------ -utils.setupConfig(); -if (nconf.get('NODE_ENV') === 'production') - require('newrelic'); - // ------------ MongoDB Configuration ------------ mongoose = require('mongoose'); require('./models/user'); //load up the user schema - TODO is this necessary? diff --git a/src/utils.js b/src/utils.js index 791ba3c57c..e903b3b91c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -56,6 +56,7 @@ module.exports.setupConfig = function(){ if (nconf.get('NODE_ENV') === "development") { Error.stackTraceLimit = Infinity; } + if (nconf.get('NODE_ENV') === 'production') require('newrelic'); };