diff --git a/website/public/js/services/paymentServices.js b/website/public/js/services/paymentServices.js index a3fc832d24..c5bfeae262 100644 --- a/website/public/js/services/paymentServices.js +++ b/website/public/js/services/paymentServices.js @@ -127,12 +127,12 @@ function($rootScope, User, $http, Content) { var url = '/amazon/createOrderReferenceId' $http.post(url, { billingAgreementId: Payments.amazonPayments.billingAgreementId - }).success(function(data){ + }).success(function(res){ Payments.amazonPayments.loggedIn = true; - Payments.amazonPayments.orderReferenceId = data.orderReferenceId; + Payments.amazonPayments.orderReferenceId = res.data.orderReferenceId; Payments.amazonPayments.initWidgets(); }).error(function(res){ - alert(res.err); + alert(res.message); }); } }, @@ -146,7 +146,7 @@ function($rootScope, User, $http, Content) { var url = '/amazon/verifyAccessToken' $http.post(url, response).error(function(res){ - alert(res.err); + alert(res.message); }); }); }, @@ -232,7 +232,7 @@ function($rootScope, User, $http, Content) { Payments.amazonPayments.reset(); window.location.reload(true); }).error(function(res){ - alert(res.err); + alert(res.message); Payments.amazonPayments.reset(); }); }else if(Payments.amazonPayments.type === 'subscription'){ @@ -246,7 +246,7 @@ function($rootScope, User, $http, Content) { Payments.amazonPayments.reset(); window.location.reload(true); }).error(function(res){ - alert(res.err); + alert(res.message); Payments.amazonPayments.reset(); }); } diff --git a/website/src/controllers/top-level/payments/amazon.js b/website/src/controllers/top-level/payments/amazon.js index 17b8486389..a22618fa23 100644 --- a/website/src/controllers/top-level/payments/amazon.js +++ b/website/src/controllers/top-level/payments/amazon.js @@ -18,13 +18,11 @@ let api = {}; /** * @apiIgnore Payments are considered part of the private API - * @api {post} /amazon/verifyAccessToken verify access token + * @api {post} /amazon/verifyAccessToken Amazon Payments: verify access token * @apiVersion 3.0.0 * @apiName AmazonVerifyAccessToken * @apiGroup Payments * - * @apiParam {string} access_token the access token - * * @apiSuccess {Object} data Empty object **/ api.verifyAccessToken = { @@ -32,56 +30,53 @@ api.verifyAccessToken = { url: '/amazon/verifyAccessToken', middlewares: [authWithHeaders()], async handler (req, res) { - try { - await amzLib.getTokenInfo(req.body.access_token); - res.respond(200, {}); - } catch (error) { - throw new BadRequest(error.body.error_description); - } + let accessToken = req.body.access_token; + + if (!accessToken) throw new BadRequest('Missing req.body.access_token'); + + await amzLib.getTokenInfo(accessToken); + res.respond(200, {}); }, }; /** * @apiIgnore Payments are considered part of the private API - * @api {post} /amazon/createOrderReferenceId create order reference id + * @api {post} /amazon/createOrderReferenceId Amazon Payments: create order reference id * @apiVersion 3.0.0 * @apiName AmazonCreateOrderReferenceId * @apiGroup Payments * - * @apiParam {string} billingAgreementId billing agreement id - * - * @apiSuccess {object} data.orderReferenceId The order reference id. + * @apiSuccess {string} data.orderReferenceId The order reference id. **/ api.createOrderReferenceId = { method: 'POST', url: '/amazon/createOrderReferenceId', middlewares: [authWithHeaders()], async handler (req, res) { - try { - let response = await amzLib.createOrderReferenceId({ - Id: req.body.billingAgreementId, - IdType: 'BillingAgreement', - ConfirmNow: false, - }); - res.respond(200, { - orderReferenceId: response.OrderReferenceDetails.AmazonOrderReferenceId, - }); - } catch (error) { - throw new BadRequest(error); - } + let billingAgreementId = req.body.billingAgreementId; + + if (!billingAgreementId) throw new BadRequest('Missing req.body.billingAgreementId'); + + let response = await amzLib.createOrderReferenceId({ + Id: billingAgreementId, + IdType: 'BillingAgreement', + ConfirmNow: false, + }); + + res.respond(200, { + orderReferenceId: response.OrderReferenceDetails.AmazonOrderReferenceId, + }); }, }; /** * @apiIgnore Payments are considered part of the private API - * @api {post} /amazon/checkout do checkout + * @api {post} /amazon/checkout Amazon Payments: checkout * @apiVersion 3.0.0 * @apiName AmazonCheckout * @apiGroup Payments * - * @apiParam {string} billingAgreementId billing agreement id - * - * @apiSuccess {object} object containing { orderReferenceId } + * @apiSuccess {object} data Empty object **/ api.checkout = { method: 'POST', @@ -93,6 +88,8 @@ api.checkout = { let orderReferenceId = req.body.orderReferenceId; let amount = 5; + if (!orderReferenceId) throw new BadRequest('Missing req.body.orderReferenceId'); + if (gift) { if (gift.type === 'gems') { amount = gift.gems.amount / 4; @@ -101,68 +98,62 @@ api.checkout = { } } - try { - await amzLib.setOrderReferenceDetails({ - AmazonOrderReferenceId: orderReferenceId, - OrderReferenceAttributes: { - OrderTotal: { - CurrencyCode: 'USD', - Amount: amount, - }, - SellerNote: 'HabitRPG Payment', - SellerOrderAttributes: { - SellerOrderId: shared.uuid(), - StoreName: 'HabitRPG', - }, - }, - }); - - await amzLib.confirmOrderReference({ AmazonOrderReferenceId: orderReferenceId }); - - await amzLib.authorize({ - AmazonOrderReferenceId: orderReferenceId, - AuthorizationReferenceId: shared.uuid().substring(0, 32), - AuthorizationAmount: { + await amzLib.setOrderReferenceDetails({ + AmazonOrderReferenceId: orderReferenceId, + OrderReferenceAttributes: { + OrderTotal: { CurrencyCode: 'USD', Amount: amount, }, - SellerAuthorizationNote: 'HabitRPG Payment', - TransactionTimeout: 0, - CaptureNow: true, - }); + SellerNote: 'HabitRPG Payment', + SellerOrderAttributes: { + SellerOrderId: shared.uuid(), + StoreName: 'HabitRPG', + }, + }, + }); - await amzLib.closeOrderReference({ AmazonOrderReferenceId: orderReferenceId }); + await amzLib.confirmOrderReference({ AmazonOrderReferenceId: orderReferenceId }); - // execute payment - let method = 'buyGems'; - let data = { user, paymentMethod: 'Amazon Payments' }; - if (gift) { - if (gift.type === 'subscription') method = 'createSubscription'; - gift.member = await User.findById(gift ? gift.uuid : undefined); - data.gift = gift; - data.paymentMethod = 'Gift'; - } - await payments[method](data); + await amzLib.authorize({ + AmazonOrderReferenceId: orderReferenceId, + AuthorizationReferenceId: shared.uuid().substring(0, 32), + AuthorizationAmount: { + CurrencyCode: 'USD', + Amount: amount, + }, + SellerAuthorizationNote: 'HabitRPG Payment', + TransactionTimeout: 0, + CaptureNow: true, + }); - res.respond(200); - } catch (error) { - throw new BadRequest(error); + await amzLib.closeOrderReference({ AmazonOrderReferenceId: orderReferenceId }); + + // execute payment + let method = 'buyGems'; + let data = { user, paymentMethod: 'Amazon Payments' }; + + if (gift) { + if (gift.type === 'subscription') method = 'createSubscription'; + gift.member = await User.findById(gift ? gift.uuid : undefined); + data.gift = gift; + data.paymentMethod = 'Gift'; } + + await payments[method](data); + + res.respond(200); }, }; /** * @apiIgnore Payments are considered part of the private API - * @api {post} /amazon/subscribe Subscribe + * @api {post} /amazon/subscribe Amazon Payments: subscribe * @apiVersion 3.0.0 * @apiName AmazonSubscribe * @apiGroup Payments * - * @apiParam {string} billingAgreementId billing agreement id - * @apiParam {string} subscription Subscription plan - * @apiParam {string} coupon Coupon - * - * @apiSuccess {object} data.orderReferenceId The order reference id. + * @apiSuccess {object} data Empty object **/ api.subscribe = { method: 'POST', @@ -174,67 +165,62 @@ api.subscribe = { let coupon = req.body.coupon; let user = res.locals.user; - if (!sub) { - throw new BadRequest(res.t('missingSubscriptionCode')); + if (!sub) throw new BadRequest(res.t('missingSubscriptionCode')); + if (!billingAgreementId) throw new BadRequest('Missing req.body.billingAgreementId'); + + if (sub.discount) { // apply discount + if (!coupon) throw new BadRequest(res.t('couponCodeRequired')); + let result = await Coupon.findOne({_id: cc.validate(coupon), event: sub.key}); + if (!result) throw new NotAuthorized(res.t('invalidCoupon')); } - try { - if (sub.discount) { // apply discount - if (!coupon) throw new BadRequest(res.t('couponCodeRequired')); - let result = await Coupon.findOne({_id: cc.validate(coupon), event: sub.key}); - if (!result) throw new BadRequest(res.t('invalidCoupon')); - } - - await amzLib.setBillingAgreementDetails({ - AmazonBillingAgreementId: billingAgreementId, - BillingAgreementAttributes: { - SellerNote: 'HabitRPG Subscription', - SellerBillingAgreementAttributes: { - SellerBillingAgreementId: shared.uuid(), - StoreName: 'HabitRPG', - CustomInformation: 'HabitRPG Subscription', - }, - }, - }); - - await amzLib.confirmBillingAgreement({ - AmazonBillingAgreementId: billingAgreementId, - }); - - await amzLib.authorizeOnBillingAgreement({ - AmazonBillingAgreementId: billingAgreementId, - AuthorizationReferenceId: shared.uuid().substring(0, 32), - AuthorizationAmount: { - CurrencyCode: 'USD', - Amount: sub.price, - }, - SellerAuthorizationNote: 'HabitRPG Subscription Payment', - TransactionTimeout: 0, - CaptureNow: true, - SellerNote: 'HabitRPG Subscription Payment', - SellerOrderAttributes: { - SellerOrderId: shared.uuid(), + await amzLib.setBillingAgreementDetails({ + AmazonBillingAgreementId: billingAgreementId, + BillingAgreementAttributes: { + SellerNote: 'HabitRPG Subscription', + SellerBillingAgreementAttributes: { + SellerBillingAgreementId: shared.uuid(), StoreName: 'HabitRPG', + CustomInformation: 'HabitRPG Subscription', }, - }); + }, + }); - await payments.createSubscription({ - user, - customerId: billingAgreementId, - paymentMethod: 'Amazon Payments', - sub, - }); + await amzLib.confirmBillingAgreement({ + AmazonBillingAgreementId: billingAgreementId, + }); - res.respond(200); - } catch (error) { - throw new BadRequest(error); - } + await amzLib.authorizeOnBillingAgreement({ + AmazonBillingAgreementId: billingAgreementId, + AuthorizationReferenceId: shared.uuid().substring(0, 32), + AuthorizationAmount: { + CurrencyCode: 'USD', + Amount: sub.price, + }, + SellerAuthorizationNote: 'HabitRPG Subscription Payment', + TransactionTimeout: 0, + CaptureNow: true, + SellerNote: 'HabitRPG Subscription Payment', + SellerOrderAttributes: { + SellerOrderId: shared.uuid(), + StoreName: 'HabitRPG', + }, + }); + + await payments.createSubscription({ + user, + customerId: billingAgreementId, + paymentMethod: 'Amazon Payments', + sub, + }); + + res.respond(200); }, }; /** * @apiIgnore Payments are considered part of the private API - * @api {get} /amazon/subscribe/cancel SubscribeCancel + * @api {get} /amazon/subscribe/cancel Amazon Payments: subscribe cancel * @apiVersion 3.0.0 * @apiName AmazonSubscribe * @apiGroup Payments @@ -249,21 +235,20 @@ api.subscribeCancel = { if (!billingAgreementId) throw new NotAuthorized(res.t('missingSubscription')); - try { - await amzLib.closeBillingAgreement({ - AmazonBillingAgreementId: billingAgreementId, - }); + await amzLib.closeBillingAgreement({ + AmazonBillingAgreementId: billingAgreementId, + }); - let data = { - user, - nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: 30 }), - paymentMethod: 'Amazon Payments', - }; - await payments.cancelSubscription(data); + await payments.cancelSubscription({ + user, + nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: 30 }), + paymentMethod: 'Amazon Payments', + }); + if (req.query.noRedirect) { + res.respond(200); + } else { res.redirect('/'); - } catch (error) { - throw new BadRequest(error.message); } }, }; diff --git a/website/src/controllers/top-level/payments/stripe.js b/website/src/controllers/top-level/payments/stripe.js index a319d2d4f9..2ac8c863f7 100644 --- a/website/src/controllers/top-level/payments/stripe.js +++ b/website/src/controllers/top-level/payments/stripe.js @@ -45,6 +45,8 @@ api.checkout = { let coupon; let response; + if (!token) throw new BadRequest('Missing req.body.id'); + if (sub) { if (sub.discount) { if (!req.query.coupon) throw new BadRequest(res.t('couponCodeRequired')); @@ -127,10 +129,12 @@ api.subscribeEdit = { let customerId = user.purchased.plan.customerId; if (!customerId) throw new NotAuthorized(res.t('missingSubscription')); + if (!token) throw new BadRequest('Missing req.body.id'); let subscriptions = await stripe.customers.listSubscriptions(customerId); let subscriptionId = subscriptions.data[0].id; await stripe.customers.updateSubscription(customerId, subscriptionId, { card: token }); + res.respond(200, {}); }, }; diff --git a/website/src/libs/api-v3/amazonPayments.js b/website/src/libs/api-v3/amazonPayments.js index c22b3cfb3b..338a6acd08 100644 --- a/website/src/libs/api-v3/amazonPayments.js +++ b/website/src/libs/api-v3/amazonPayments.js @@ -6,7 +6,9 @@ import { BadRequest, } from './errors'; -const t = common.i18n.t; +// TODO better handling of errors + +const i18n = common.i18n; const IS_PROD = nconf.get('NODE_ENV') === 'production'; let amzPayment = amazonPayments.connect({ @@ -30,7 +32,7 @@ let authorizeOnBillingAgreement = (inputSet) => { return new Promise((resolve, reject) => { amzPayment.offAmazonPayments.authorizeOnBillingAgreement(inputSet, (err, response) => { if (err) return reject(err); - if (response.AuthorizationDetails.AuthorizationStatus.State === 'Declined') return reject(new BadRequest(t('paymentNotSuccessful'))); + if (response.AuthorizationDetails.AuthorizationStatus.State === 'Declined') return reject(new BadRequest(i18n.t('paymentNotSuccessful'))); return resolve(response); }); }); @@ -40,7 +42,7 @@ let authorize = (inputSet) => { return new Promise((resolve, reject) => { amzPayment.offAmazonPayments.authorize(inputSet, (err, response) => { if (err) return reject(err); - if (response.AuthorizationDetails.AuthorizationStatus.State === 'Declined') return reject(new BadRequest(t('paymentNotSuccessful'))); + if (response.AuthorizationDetails.AuthorizationStatus.State === 'Declined') return reject(new BadRequest(i18n.t('paymentNotSuccessful'))); return resolve(response); }); });