mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-28 10:06:08 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
40ed4e1056
6 changed files with 43 additions and 19 deletions
|
@ -51,7 +51,7 @@ module.exports = ModuleLoader = class ModuleLoader extends CocoClass
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
|
|
||||||
loadLanguage: (langCode) ->
|
loadLanguage: (langCode='en-US') ->
|
||||||
loading = @load("locale/#{langCode}")
|
loading = @load("locale/#{langCode}")
|
||||||
firstBit = langCode[...2]
|
firstBit = langCode[...2]
|
||||||
return loading if firstBit is langCode
|
return loading if firstBit is langCode
|
||||||
|
|
|
@ -19,21 +19,37 @@ module.exports = class Tracker
|
||||||
traits[userTrait] ?= me.get(userTrait)
|
traits[userTrait] ?= me.get(userTrait)
|
||||||
analytics.identify me.id, traits
|
analytics.identify me.id, traits
|
||||||
|
|
||||||
trackPageView: (name=null, includeIntegrations=null) ->
|
trackPageView: (virtualName=null, includeIntegrations=null) ->
|
||||||
|
# console.log 'trackPageView', virtualName, includeIntegrations
|
||||||
# Google Analytics does not support event-based funnels, so we have to use virtual pageviews instead
|
# Google Analytics does not support event-based funnels, so we have to use virtual pageviews instead
|
||||||
# https://support.google.com/analytics/answer/1032720?hl=en
|
# https://support.google.com/analytics/answer/1032720?hl=en
|
||||||
# https://segment.com/docs/libraries/analytics.js/#page
|
name = virtualName ? Backbone.history.getFragment()
|
||||||
unless name?
|
|
||||||
name = Backbone.history.getFragment()
|
properties = {}
|
||||||
console.log "Would track analytics pageview: /#{name}" if debugAnalytics
|
if virtualName?
|
||||||
return unless @isProduction and analytics? and not me.isAdmin()
|
# Override title and path properties for virtual page view
|
||||||
if includeIntegrations
|
# https://segment.com/docs/libraries/analytics.js/#page
|
||||||
|
properties =
|
||||||
|
title: name
|
||||||
|
path: "/#{name}"
|
||||||
|
|
||||||
|
options = {}
|
||||||
|
if includeIntegrations?
|
||||||
options = integrations: {'All': false}
|
options = integrations: {'All': false}
|
||||||
for integration in includeIntegrations
|
for integration in includeIntegrations
|
||||||
options.integrations[integration] = true
|
options.integrations[integration] = true
|
||||||
analytics.page "/#{name}", {}, options
|
|
||||||
else
|
console.log "Would track analytics pageview: '/#{name}'", properties, options if debugAnalytics
|
||||||
|
return unless @isProduction and analytics? and not me.isAdmin()
|
||||||
|
|
||||||
|
# Ok to pass empty properties, but maybe not options
|
||||||
|
# TODO: What happens when we pass empty options?
|
||||||
|
if _.isEmpty options
|
||||||
|
# console.log "trackPageView without options '/#{name}'", properties, options
|
||||||
analytics.page "/#{name}"
|
analytics.page "/#{name}"
|
||||||
|
else
|
||||||
|
# console.log "trackPageView with options '/#{name}'", properties, options
|
||||||
|
analytics.page "/#{name}", properties, options
|
||||||
|
|
||||||
trackEvent: (action, properties, includeIntegrations=null) =>
|
trackEvent: (action, properties, includeIntegrations=null) =>
|
||||||
# 'action' is a string
|
# 'action' is a string
|
||||||
|
|
|
@ -271,7 +271,13 @@ _.extend UserSchema.properties,
|
||||||
earned: c.RewardSchema 'earned by achievements'
|
earned: c.RewardSchema 'earned by achievements'
|
||||||
purchased: c.RewardSchema 'purchased with gems or money'
|
purchased: c.RewardSchema 'purchased with gems or money'
|
||||||
spent: {type: 'number'}
|
spent: {type: 'number'}
|
||||||
stripeCustomerID: { type: 'string' }
|
stripeCustomerID: { type: 'string' } # TODO: Migrate away from this property
|
||||||
|
|
||||||
|
stripe: c.object {}, {
|
||||||
|
customerID: { type: 'string' }
|
||||||
|
subscription: { enum: ['basic'] }
|
||||||
|
token: { type: 'string' }
|
||||||
|
}
|
||||||
|
|
||||||
c.extendBasicProperties UserSchema, 'user'
|
c.extendBasicProperties UserSchema, 'user'
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ PaymentHandler = class PaymentHandler extends Handler
|
||||||
@logPaymentError(req, 'Missing stripe productID')
|
@logPaymentError(req, 'Missing stripe productID')
|
||||||
return @sendBadInputError(res, 'Need productID if paying with Stripe.')
|
return @sendBadInputError(res, 'Need productID if paying with Stripe.')
|
||||||
|
|
||||||
if stripeTimestamp and (not stripeToken) and (not user.get('stripeCustomerID'))
|
if stripeTimestamp and (not stripeToken) and (not req.user.get('stripe')?.customerID)
|
||||||
@logPaymentError(req, 'Missing stripe token')
|
@logPaymentError(req, 'Missing stripe token')
|
||||||
return @sendBadInputError(res, 'Need stripe.token if new customer.')
|
return @sendBadInputError(res, 'Need stripe.token if new customer.')
|
||||||
|
|
||||||
|
@ -160,12 +160,14 @@ PaymentHandler = class PaymentHandler extends Handler
|
||||||
handleStripePaymentPost: (req, res, timestamp, productID, token) ->
|
handleStripePaymentPost: (req, res, timestamp, productID, token) ->
|
||||||
|
|
||||||
# First, make sure we save the payment info as a Customer object, if we haven't already.
|
# First, make sure we save the payment info as a Customer object, if we haven't already.
|
||||||
if not req.user.get('stripeCustomerID')
|
if not req.user.get('stripe')?.customerID
|
||||||
stripe.customers.create({
|
stripe.customers.create({
|
||||||
card: token
|
card: token
|
||||||
description: req.user._id + ''
|
description: req.user._id + ''
|
||||||
}).then(((customer) =>
|
}).then(((customer) =>
|
||||||
req.user.set('stripeCustomerID', customer.id)
|
stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
|
||||||
|
stripeInfo.customerID = customer.id
|
||||||
|
req.user.set('stripe', stripeInfo)
|
||||||
req.user.save((err) =>
|
req.user.save((err) =>
|
||||||
if err
|
if err
|
||||||
@logPaymentError(req, 'Stripe customer id save db error. '+err)
|
@logPaymentError(req, 'Stripe customer id save db error. '+err)
|
||||||
|
@ -193,7 +195,7 @@ PaymentHandler = class PaymentHandler extends Handler
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
((callback) ->
|
((callback) ->
|
||||||
stripe.charges.list({customer: req.user.get('stripeCustomerID')}, (err, recentCharges) =>
|
stripe.charges.list({customer: req.user.get('stripe')?.customerID}, (err, recentCharges) =>
|
||||||
return callback(err) if err
|
return callback(err) if err
|
||||||
charge = _.find recentCharges.data, (c) -> c.metadata.timestamp is timestamp
|
charge = _.find recentCharges.data, (c) -> c.metadata.timestamp is timestamp
|
||||||
callback(null, charge)
|
callback(null, charge)
|
||||||
|
@ -232,7 +234,7 @@ PaymentHandler = class PaymentHandler extends Handler
|
||||||
stripe.charges.create({
|
stripe.charges.create({
|
||||||
amount: product.amount
|
amount: product.amount
|
||||||
currency: 'usd'
|
currency: 'usd'
|
||||||
customer: req.user.get('stripeCustomerID')
|
customer: req.user.get('stripe')?.customerID
|
||||||
metadata: {
|
metadata: {
|
||||||
productID: product.id
|
productID: product.id
|
||||||
userID: req.user._id + ''
|
userID: req.user._id + ''
|
||||||
|
@ -262,7 +264,7 @@ PaymentHandler = class PaymentHandler extends Handler
|
||||||
payment.set 'amount', product.amount
|
payment.set 'amount', product.amount
|
||||||
payment.set 'gems', product.gems
|
payment.set 'gems', product.gems
|
||||||
payment.set 'stripe', {
|
payment.set 'stripe', {
|
||||||
customerID: req.user.get('stripeCustomerID')
|
customerID: req.user.get('stripe')?.customerID
|
||||||
timestamp: parseInt(req.body.stripe.timestamp)
|
timestamp: parseInt(req.body.stripe.timestamp)
|
||||||
chargeID: charge.id
|
chargeID: charge.id
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ UserSchema.statics.hashPassword = (password) ->
|
||||||
UserSchema.statics.privateProperties = [
|
UserSchema.statics.privateProperties = [
|
||||||
'permissions', 'email', 'mailChimp', 'firstName', 'lastName', 'gender', 'facebookID',
|
'permissions', 'email', 'mailChimp', 'firstName', 'lastName', 'gender', 'facebookID',
|
||||||
'gplusID', 'music', 'volume', 'aceConfig', 'employerAt', 'signedEmployerAgreement',
|
'gplusID', 'music', 'volume', 'aceConfig', 'employerAt', 'signedEmployerAgreement',
|
||||||
'emailSubscriptions', 'emails', 'activity', 'stripeCustomerID'
|
'emailSubscriptions', 'emails', 'activity', 'stripe', 'stripeCustomerID'
|
||||||
]
|
]
|
||||||
UserSchema.statics.jsonSchema = jsonschema
|
UserSchema.statics.jsonSchema = jsonschema
|
||||||
UserSchema.statics.editableProperties = [
|
UserSchema.statics.editableProperties = [
|
||||||
|
|
|
@ -109,7 +109,7 @@ describe '/db/payment', ->
|
||||||
expect(body.purchaser).toBe(joeID)
|
expect(body.purchaser).toBe(joeID)
|
||||||
User.findById(joe.get('_id'), (err, user) ->
|
User.findById(joe.get('_id'), (err, user) ->
|
||||||
expect(user.get('purchased').gems).toBe(5000)
|
expect(user.get('purchased').gems).toBe(5000)
|
||||||
expect(user.get('stripeCustomerID')).toBe(body.stripe.customerID)
|
expect(user.get('stripe').customerID).toBe(body.stripe.customerID)
|
||||||
done()
|
done()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue