From 1bd70591a0f38c5ca51ae652aef0b7833a5c35ed Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sat, 29 Nov 2014 10:44:58 -0800 Subject: [PATCH] Added new mongodb versions to be allowed. Added error logging for every which reason a user may be unable to pay. Added more info for users when they hit unknown errors. --- app/templates/play/modal/buy-gems-modal.jade | 5 +- app/views/play/modal/BuyGemsModal.coffee | 2 + bin/coco-mongodb | 2 +- server/payments/payment_handler.coffee | 60 ++++++++++++++++---- 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/app/templates/play/modal/buy-gems-modal.jade b/app/templates/play/modal/buy-gems-modal.jade index 6884890eb..78255af54 100644 --- a/app/templates/play/modal/buy-gems-modal.jade +++ b/app/templates/play/modal/buy-gems-modal.jade @@ -25,6 +25,7 @@ if state === 'unknown_error' #error-alert.alert.alert-danger.alert-dismissible - span(data-i18n="loading_error.unknown") button.close(type="button" data-dismiss="alert") - span(aria-hidden="true") × \ No newline at end of file + span(aria-hidden="true") × + p(data-i18n="loading_error.unknown") + p= stateMessage diff --git a/app/views/play/modal/BuyGemsModal.coffee b/app/views/play/modal/BuyGemsModal.coffee index 73fbe1cfb..38f298a20 100644 --- a/app/views/play/modal/BuyGemsModal.coffee +++ b/app/views/play/modal/BuyGemsModal.coffee @@ -35,6 +35,7 @@ module.exports = class BuyGemsModal extends ModalView c = super() c.products = @products c.state = @state + c.stateMessage = @stateMessage return c onIPadProducts: (e) -> @@ -89,6 +90,7 @@ module.exports = class BuyGemsModal extends ModalView _.delay f, 2000 else @state = 'unknown_error' + @stateMessage = "#{jqxhr.status}: #{jqxhr.responseText}" @render() ) diff --git a/bin/coco-mongodb b/bin/coco-mongodb index eeb3d7aa8..18cd4cda3 100755 --- a/bin/coco-mongodb +++ b/bin/coco-mongodb @@ -71,7 +71,7 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): current_directory = os.path.dirname(os.path.realpath(sys.argv[0])) -allowedMongoVersions = ["v2.6.0","v2.6.4"] +allowedMongoVersions = ["v2.6.0","v2.6.1","v2.6.4","v2.6.5"] if which("mongod") and any(i in subprocess.check_output("mongod --version",shell=True) for i in allowedMongoVersions): mongo_executable = "mongod" else: diff --git a/server/payments/payment_handler.coffee b/server/payments/payment_handler.coffee index ccd2e206f..fcf423445 100644 --- a/server/payments/payment_handler.coffee +++ b/server/payments/payment_handler.coffee @@ -36,6 +36,17 @@ PaymentHandler = class PaymentHandler extends Handler editableProperties: [] postEditableProperties: ['purchased'] jsonSchema: require '../../app/schemas/models/payment.schema' + + get: (req, res) -> + return res.send([]) unless req.user + q = Payment.find({recipient:req.user._id}) + q.exec((err, payments) -> + return @sendDatabaseError(res, err) if err + res.send(payments) + ) + + logPaymentError: (req, msg) -> + console.warn "Payment Error: #{req.user.get('slug')} (#{req.user._id}): '#{msg}'" makeNewInstance: (req) -> payment = super(req) @@ -53,16 +64,20 @@ PaymentHandler = class PaymentHandler extends Handler productID = req.body.productID if not (appleReceipt or (stripeTimestamp and productID)) + @logPaymentError(req, "Missing data. Apple? #{!!appleReceipt}. Stripe timestamp? #{!!stripeTimestamp}. Product id? #{!!productID}.") return @sendBadInputError(res, 'Need either apple.rawReceipt or stripe.timestamp and productID') if stripeTimestamp and not productID + @logPaymentError(req, 'Missing stripe productID') return @sendBadInputError(res, 'Need productID if paying with Stripe.') if stripeTimestamp and (not stripeToken) and (not user.get('stripeCustomerID')) + @logPaymentError(req, 'Missing stripe token') return @sendBadInputError(res, 'Need stripe.token if new customer.') if appleReceipt if not appleTransactionID + @logPaymentError(req, 'Missing apple transaction id') return @sendBadInputError(res, 'Apple purchase? Need to specify which transaction.') @handleApplePaymentPost(req, res, appleReceipt, appleTransactionID, appleLocalPrice) @@ -80,11 +95,14 @@ PaymentHandler = class PaymentHandler extends Handler verifyReq = request.post({url: config.apple.verifyURL, json: formFields}, (err, verifyRes, body) => if err or not body?.receipt?.in_app or (not body?.bundle_id is 'com.codecombat.CodeCombat') console.warn 'apple receipt error?', err, body + @logPaymentError(req, 'Unable to verify apple receipt') @sendBadInputError(res, 'Unable to verify Apple receipt.') return transaction = _.find body.receipt.in_app, { transaction_id: transactionID } - return @sendBadInputError(res, 'Invalid transactionID.') unless transaction + unless transaction + @logPaymentError(req, 'Missing transaction given id.') + return @sendBadInputError(res, 'Invalid transactionID.') #- Check existence transactionID = transaction.transaction_id @@ -93,10 +111,13 @@ PaymentHandler = class PaymentHandler extends Handler if payment unless payment.get('recipient').equals(req.user._id) + @logPaymentError(req, 'Cross user apple payment.') return @sendForbiddenError(res) @recalculateGemsFor(req.user, (err) => - return @sendDatabaseError(res, err) if err + if err + @logPaymentError(req, 'Apple recalc db error.'+err) + return @sendDatabaseError(res, err) @sendSuccess(res, @formatEntity(req, payment)) ) return @@ -114,11 +135,18 @@ PaymentHandler = class PaymentHandler extends Handler } validation = @validateDocumentInput(payment.toObject()) - return @sendBadInputError(res, validation.errors) if validation.valid is false + if validation.valid is false + @logPaymentError(req, 'Invalid apple payment object.') + return @sendBadInputError(res, validation.errors) + payment.save((err) => - return @sendDatabaseError(res, err) if err + if err + @logPaymentError(req, 'Apple payment save error.'+err) + return @sendDatabaseError(res, err) @incrementGemsFor(req.user, product.gems, (err) => - return @sendDatabaseError(res, err) if err + if err + @logPaymentError(req, 'Apple incr db error.'+err) + return @sendDatabaseError(res, err) @sendPaymentHipChatMessage user: req.user, payment: payment @sendCreated(res, @formatEntity(req, payment)) ) @@ -139,11 +167,14 @@ PaymentHandler = class PaymentHandler extends Handler }).then(((customer) => req.user.set('stripeCustomerID', customer.id) req.user.save((err) => - return @sendDatabaseError(res, err) if err + if err + @logPaymentError(req, 'Stripe customer id save db error. '+err) + return @sendDatabaseError(res, err) @beginStripePayment(req, res, timestamp, productID) ) ), (err) => + @logPaymentError(req, 'Stripe customer creation error. '+err) return @sendDatabaseError(res, err) ) @@ -171,7 +202,9 @@ PaymentHandler = class PaymentHandler extends Handler ], ((err, results) => - return @sendDatabaseError(res, err) if err + if err + @logPaymentError(req, 'Stripe async load db error. '+err) + return @sendDatabaseError(res, err) [payment, charge] = results if not (payment or charge) @@ -185,7 +218,9 @@ PaymentHandler = class PaymentHandler extends Handler else # Charged Stripe and recorded it. Recalculate gems to make sure credited the purchase. @recalculateGemsFor(req.user, (err) => - return @sendDatabaseError(res, err) if err + if err + @logPaymentError(req, 'Stripe recalc db error. '+err) + return @sendDatabaseError(res, err) @sendPaymentHipChatMessage user: req.user, payment: payment @sendSuccess(res, @formatEntity(req, payment)) ) @@ -214,6 +249,7 @@ PaymentHandler = class PaymentHandler extends Handler if err.type in ['StripeCardError', 'StripeInvalidRequestError'] @sendError(res, 402, err.message) else + @logPaymentError(req, 'Stripe charge error. '+err) @sendDatabaseError(res, 'Error charging card, please retry.')) ) @@ -232,13 +268,17 @@ PaymentHandler = class PaymentHandler extends Handler } validation = @validateDocumentInput(payment.toObject()) - return @sendBadInputError(res, validation.errors) if validation.valid is false + if validation.valid is false + @logPaymentError(req, 'Invalid stripe payment object.') + return @sendBadInputError(res, validation.errors) payment.save((err) => # Credit gems return @sendDatabaseError(res, err) if err @incrementGemsFor(req.user, product.gems, (err) => - return @sendDatabaseError(res, err) if err + if err + @logPaymentError(req, 'Stripe incr db error. '+err) + return @sendDatabaseError(res, err) @sendCreated(res, @formatEntity(req, payment)) ) )