Merge branch 'master' into production

This commit is contained in:
Scott Erickson 2014-12-02 13:30:33 -08:00
commit 40ed4e1056
6 changed files with 43 additions and 19 deletions

View file

@ -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

View file

@ -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
name = virtualName ? Backbone.history.getFragment()
properties = {}
if virtualName?
# Override title and path properties for virtual page view
# https://segment.com/docs/libraries/analytics.js/#page # https://segment.com/docs/libraries/analytics.js/#page
unless name? properties =
name = Backbone.history.getFragment() title: name
console.log "Would track analytics pageview: /#{name}" if debugAnalytics path: "/#{name}"
return unless @isProduction and analytics? and not me.isAdmin()
if includeIntegrations 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

View file

@ -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'

View file

@ -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
} }

View file

@ -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 = [

View file

@ -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()
) )
) )