Merge branch 'master' into ho-jade-speedup

This commit is contained in:
Henry Oswald 2016-08-23 15:35:04 +01:00
commit f8799334ec
12 changed files with 167 additions and 36 deletions

View file

@ -29,13 +29,15 @@ module.exports = RecurlyWrapper =
RecurlyWrapper.apiRequest({
url: "accounts/#{user._id}"
method: "GET"
expect404: true
}, (error, response, responseBody) ->
if error
if response.statusCode == 404 # actually not an error in this case, just no existing account
cache.userExists = false
return next(null, cache)
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while checking account"
return next(error)
if response.statusCode == 404 # actually not an error in this case, just no existing account
logger.log {user_id: user._id, recurly_token_id}, "user does not currently exist in recurly, proceed"
cache.userExists = false
return next(null, cache)
logger.log {user_id: user._id, recurly_token_id}, "user appears to exist in recurly"
RecurlyWrapper._parseAccountXml responseBody, (err, account) ->
if err
@ -236,10 +238,14 @@ module.exports = RecurlyWrapper =
"Authorization" : "Basic " + new Buffer(Settings.apis.recurly.apiKey).toString("base64")
"Accept" : "application/xml"
"Content-Type" : "application/xml; charset=utf-8"
expect404 = options.expect404
delete options.expect404
request options, (error, response, body) ->
unless error? or response.statusCode == 200 or response.statusCode == 201 or response.statusCode == 204
unless error? or response.statusCode == 200 or response.statusCode == 201 or response.statusCode == 204 or (response.statusCode == 404 and expect404)
logger.err err:error, body:body, options:options, statusCode:response?.statusCode, "error returned from recurly"
error = "Recurly API returned with status code: #{response.statusCode}"
if response.statusCode == 404 and expect404
logger.log {url: options.url, method: options.method}, "got 404 response from recurly, expected as valid response"
callback(error, response, body)
sign : (parameters, callback) ->

View file

@ -22,6 +22,7 @@ module.exports = SubscriptionController =
viewName = "#{viewName}_#{req.query.v}"
logger.log viewName:viewName, "showing plans page"
GeoIpLookup.getCurrencyCode req.query?.ip || req.ip, (err, recomendedCurrency)->
return next(err) if err?
res.render viewName,
title: "plans_and_pricing"
plans: plans
@ -71,6 +72,7 @@ module.exports = SubscriptionController =
AuthenticationController.getLoggedInUser req, (error, user) =>
return next(error) if error?
LimitationsManager.userHasSubscriptionOrIsGroupMember user, (err, hasSubOrIsGroupMember, subscription)->
return next(err) if err?
groupLicenceInviteUrl = SubscriptionDomainHandler.getDomainLicencePage(user)
if subscription?.customAccount
logger.log user: user, "redirecting to custom account page"
@ -95,11 +97,13 @@ module.exports = SubscriptionController =
groupSubscriptions: groupSubscriptions
subscriptionTabActive: true
user:user
saved_billing_details: req.query.saved_billing_details?
userCustomSubscriptionPage: (req, res, next)->
AuthenticationController.getLoggedInUser req, (error, user) ->
return next(error) if error?
LimitationsManager.userHasSubscriptionOrIsGroupMember user, (err, hasSubOrIsGroupMember, subscription)->
return next(err) if err?
if !subscription?
err = new Error("subscription null for custom account, user:#{user?._id}")
logger.warn err:err, "subscription is null for custom accounts page"
@ -113,6 +117,7 @@ module.exports = SubscriptionController =
AuthenticationController.getLoggedInUser req, (error, user) ->
return next(error) if error?
LimitationsManager.userHasSubscription user, (err, hasSubscription)->
return next(err) if err?
if !hasSubscription
res.redirect "/user/subscription"
else
@ -126,10 +131,13 @@ module.exports = SubscriptionController =
currency: "USD"
subdomain: Settings.apis.recurly.subdomain
signature : signature
successURL : "#{Settings.siteUrl}/user/subscription/update"
successURL : "#{Settings.siteUrl}/user/subscription/billing-details/update"
user :
id : user._id
updateBillingDetails: (req, res, next) ->
res.redirect "/user/subscription?saved_billing_details=true"
createSubscription: (req, res, next)->
AuthenticationController.getLoggedInUser req, (error, user) ->
return callback(error) if error?
@ -142,54 +150,67 @@ module.exports = SubscriptionController =
return res.sendStatus 500
res.sendStatus 201
successful_subscription: (req, res)->
successful_subscription: (req, res, next)->
AuthenticationController.getLoggedInUser req, (error, user) =>
return next(error) if error?
SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel user, (error, subscription) ->
return next(error) if error?
res.render "subscriptions/successful_subscription",
title: "thank_you"
subscription:subscription
cancelSubscription: (req, res, next) ->
AuthenticationController.getLoggedInUser req, (error, user) ->
logger.log user_id:user._id, "canceling subscription"
return next(error) if error?
logger.log user_id:user._id, "canceling subscription"
SubscriptionHandler.cancelSubscription user, (err)->
if err?
logger.err err:err, user_id:user._id, "something went wrong canceling subscription"
return next(err)
res.redirect "/user/subscription"
updateSubscription: (req, res)->
updateSubscription: (req, res, next)->
_origin = req?.query?.origin || null
AuthenticationController.getLoggedInUser req, (error, user) ->
return next(error) if error?
planCode = req.body.plan_code
if !planCode?
err = new Error('plan_code is not defined')
logger.err {user_id: user._id, err, planCode, origin: _origin, body: req.body}, "[Subscription] error in updateSubscription form"
return next(err)
logger.log planCode: planCode, user_id:user._id, "updating subscription"
SubscriptionHandler.updateSubscription user, planCode, null, (err)->
if err?
logger.err err:err, user_id:user._id, "something went wrong updating subscription"
return next(err)
res.redirect "/user/subscription"
reactivateSubscription: (req, res)->
reactivateSubscription: (req, res, next)->
AuthenticationController.getLoggedInUser req, (error, user) ->
logger.log user_id:user._id, "reactivating subscription"
return next(error) if error?
logger.log user_id:user._id, "reactivating subscription"
SubscriptionHandler.reactivateSubscription user, (err)->
if err?
logger.err err:err, user_id:user._id, "something went wrong reactivating subscription"
return next(err)
res.redirect "/user/subscription"
recurlyCallback: (req, res)->
recurlyCallback: (req, res, next)->
logger.log data: req.body, "received recurly callback"
# we only care if a subscription has exipired
if req.body? and req.body["expired_subscription_notification"]?
recurlySubscription = req.body["expired_subscription_notification"].subscription
SubscriptionHandler.recurlyCallback recurlySubscription, ->
SubscriptionHandler.recurlyCallback recurlySubscription, (err)->
return next(err) if err?
res.sendStatus 200
else
res.sendStatus 200
renderUpgradeToAnnualPlanPage: (req, res)->
renderUpgradeToAnnualPlanPage: (req, res, next)->
AuthenticationController.getLoggedInUser req, (error, user) ->
return next(error) if error?
LimitationsManager.userHasSubscription user, (err, hasSubscription, subscription)->
return next(err) if err?
planCode = subscription?.planCode.toLowerCase()
if planCode?.indexOf("annual") != -1
planName = "annual"
@ -204,8 +225,9 @@ module.exports = SubscriptionController =
title: "Upgrade to annual"
planName: planName
processUpgradeToAnnualPlan: (req, res)->
processUpgradeToAnnualPlan: (req, res, next)->
AuthenticationController.getLoggedInUser req, (error, user) ->
return next(error) if error?
{planName} = req.body
coupon_code = Settings.coupon_codes.upgradeToAnnualPromo[planName]
annualPlanName = "#{planName}-annual"
@ -213,13 +235,14 @@ module.exports = SubscriptionController =
SubscriptionHandler.updateSubscription user, annualPlanName, coupon_code, (err)->
if err?
logger.err err:err, user_id:user._id, "error updating subscription"
res.sendStatus 500
else
return next(err)
res.sendStatus 200
extendTrial: (req, res)->
extendTrial: (req, res, next)->
AuthenticationController.getLoggedInUser req, (error, user) ->
return next(error) if error?
LimitationsManager.userHasSubscription user, (err, hasSubscription, subscription)->
return next(err) if err?
SubscriptionHandler.extendTrial subscription, 14, (err)->
if err?
res.send 500

View file

@ -16,6 +16,7 @@ module.exports =
webRouter.get '/user/subscription/new', AuthenticationController.requireLogin(), SubscriptionController.paymentPage
webRouter.get '/user/subscription/billing-details/edit', AuthenticationController.requireLogin(), SubscriptionController.editBillingDetailsPage
webRouter.post '/user/subscription/billing-details/update', AuthenticationController.requireLogin(), SubscriptionController.updateBillingDetails
webRouter.get '/user/subscription/thank-you', AuthenticationController.requireLogin(), SubscriptionController.successful_subscription

View file

@ -41,11 +41,12 @@ aside.chat(
}"
)
.arrow(ng-style="{'border-color': 'hsl({{ hue(message.user) }}, 70%, 70%)'}")
.message-content
p(
mathjax,
ng-repeat="content in message.contents track by $index"
)
span(ng-bind-html="content | linky:'_blank' | wrapLongWords")
span(ng-bind-html="content | linky:'_blank'")
.new-message
textarea(

View file

@ -40,6 +40,11 @@ block content
.container(ng-controller="UserSubscriptionController")
.row
.col-md-8.col-md-offset-2
if saved_billing_details
.alert.alert-success
i.fa.fa-check
|  
| #{translate("your_billing_details_were_saved")}
.card(ng-if="view == 'overview'")
.page-header
h1 #{translate("your_subscription")}

View file

@ -19,7 +19,7 @@ block content
Recurly.config(!{recurlyConfig})
Recurly.buildBillingInfoUpdateForm({
target : "#billingDetailsForm",
successURL : "#{successURL}?_csrf=#{csrfToken}",
successURL : "#{successURL}?_csrf=#{csrfToken}&origin=editBillingDetails",
signature : "!{signature}",
accountCode : "#{user.id}"
});

View file

@ -11,6 +11,8 @@ define [
_getRule = (logMessage) ->
return rule for rule in ruleset when rule.regexToMatch.test logMessage
seenErrorTypes = {} # keep track of types of errors seen
for entry in parsedLogEntries.all
ruleDetails = _getRule entry.message
@ -21,8 +23,20 @@ define [
entry.ruleId = 'hint_' + ruleDetails.regexToMatch.toString().replace(/\s/g, '_').slice(1, -1)
if ruleDetails.newMessage?
entry.message = entry.message.replace ruleDetails.regexToMatch, ruleDetails.newMessage
# suppress any entries that are known to cascade from previous error types
if ruleDetails.cascadesFrom?
for type in ruleDetails.cascadesFrom
entry.suppressed = true if seenErrorTypes[type]
# record the types of errors seen
if ruleDetails.types?
for type in ruleDetails.types
seenErrorTypes[type] = true
entry.humanReadableHint = ruleDetails.humanReadableHint if ruleDetails.humanReadableHint?
entry.extraInfoURL = ruleDetails.extraInfoURL if ruleDetails.extraInfoURL?
# filter out the suppressed errors (from the array entries in parsedLogEntries)
for key, errors of parsedLogEntries when typeof errors is 'object' and errors.length > 0
parsedLogEntries[key] = (err for err in errors when not err.suppressed)
return parsedLogEntries

View file

@ -90,6 +90,7 @@ define -> [
"""
,
ruleId: "hint_mismatched_environment"
types: ['environment']
regexToMatch: /Error: `([^']{2,})' expected, found `([^']{2,})'.*/
newMessage: "Error: environment does not match \\begin{$1} ... \\end{$2}"
humanReadableHint: """
@ -97,10 +98,85 @@ define -> [
"""
,
ruleId: "hint_mismatched_brackets"
types: ['environment']
regexToMatch: /Error: `([^a-zA-Z0-9])' expected, found `([^a-zA-Z0-9])'.*/
newMessage: "Error: brackets do not match, found '$2' instead of '$1'"
humanReadableHint: """
You have used an open bracket without a corresponding close bracket.
"""
,
regexToMatch: /LaTeX Error: Can be used only in preamble/
extraInfoURL: "https://www.sharelatex.com/learn/Errors/LaTeX_Error:_Can_be_used_only_in_preamble"
humanReadableHint: """
You have used a command in the main body of your document which should be used in the preamble. Make sure that \\documentclass[\u2026]{\u2026} and all \\usepackage{\u2026} commands are written before \\begin{document}.
"""
,
regexToMatch: /Missing \\right inserted/
extraInfoURL: "https://www.sharelatex.com/learn/Errors/Missing_%5Cright_insertede"
humanReadableHint: """
You have started an expression with a \\left command, but have not included a corresponding \\right command. Make sure that your \\left and \\right commands balance everywhere, or else try using \\Biggl and \\Biggr commands instead as shown <a target=\"_blank\" href=\"https://www.sharelatex.com/learn/Errors/Missing_%5Cright_inserted\">here</a>.
"""
,
regexToMatch: /Double superscript/
extraInfoURL: "https://www.sharelatex.com/learn/Errors/Double_superscript"
humanReadableHint: """
You have written a double superscript incorrectly as a^b^c, or else you have written a prime with a superscript. Remember to include { and } when using multiple superscripts. Try a^{b^c} instead.
"""
,
regexToMatch: /Double subscript/
extraInfoURL: "https://www.sharelatex.com/learn/Errors/Double_subscript"
humanReadableHint: """
You have written a double subscript incorrectly as a_b_c. Remember to include { and } when using multiple subscripts. Try a_{b_c} instead.
"""
,
regexToMatch: /No \\author given/
extraInfoURL: "https://www.sharelatex.com/learn/Errors/No_%5Cauthor_given"
humanReadableHint: """
You have used the \\maketitle command, but have not specified any \\author. To fix this, include an author in your preamble using the \\author{\u2026} command.
"""
,
regexToMatch: /LaTeX Error: Environment .+ undefined/
extraInfoURL: "https://www.sharelatex.com/learn/Errors%2FLaTeX%20Error%3A%20Environment%20XXX%20undefined"
humanReadableHint: """
You have created an environment (using \\begin{\u2026} and \\end{\u2026} commands) which is not recognized. Make sure you have included the required package for that environment in your preamble, and that the environment is spelled correctly.
"""
,
regexToMatch: /LaTeX Error: Something's wrong--perhaps a missing \\item/
extraInfoURL: "https://www.sharelatex.com/learn/Errors/LaTeX_Error:_Something%27s_wrong--perhaps_a_missing_%5Citem"
humanReadableHint: """
There are no entries found in a list you have created. Make sure you label list entries using the \\item command, and that you have not used a list inside a table.
"""
,
regexToMatch: /Misplaced \\noalign/
extraInfoURL: "https://www.sharelatex.com/learn/Errors/Misplaced_%5Cnoalign"
humanReadableHint: """
You have used a \\hline command in the wrong place, probably outside a table. If the \\hline command is written inside a table, try including \\\ before it.
"""
,
ruleId: "hint_mismatched_environment2"
types: ['environment']
cascadesFrom: ['environment']
regexToMatch: /Error: `\\end\{([^\}]+)\}' expected but found `\\end\{([^\}]+)\}'.*/
newMessage: "Error: environments do not match: \\begin{$1} ... \\end{$2}"
humanReadableHint: """
You have used \\begin{} without a corresponding \\end{}.
"""
,
ruleId: "hint_mismatched_environment3"
types: ['environment']
cascadesFrom: ['environment']
regexToMatch: /Warning: No matching \\end found for `\\begin\{([^\}]+)\}'.*/
newMessage: "Warning: No matching \\end found for \\begin{$1}"
humanReadableHint: """
You have used \\begin{} without a corresponding \\end{}.
"""
,
ruleId: "hint_mismatched_environment4"
types: ['environment']
cascadesFrom: ['environment']
regexToMatch: /Error: Found `\\end\{([^\}]+)\}' without corresponding \\begin.*/
newMessage: "Error: found \\end{$1} without a corresponding \\begin{$1}"
humanReadableHint: """
You have used \\begin{} without a corresponding \\end{}.
"""
]

View file

@ -62,8 +62,7 @@ define [
$scope.inflight = true
$http.post(SUBSCRIPTION_URL, body)
$http.post("#{SUBSCRIPTION_URL}?origin=confirmChangePlan", body)
.success ->
location.reload()
.error ->
@ -124,7 +123,7 @@ define [
plan_code: 'student'
_csrf : window.csrfToken
$scope.inflight = true
$http.post(SUBSCRIPTION_URL, body)
$http.post("#{SUBSCRIPTION_URL}?origin=downgradeToStudent", body)
.success ->
location.reload()
.error ->

View file

@ -47,6 +47,7 @@
}
.message-wrapper {
margin-left: 50px + @line-height-computed/2;
.name {
font-size: 12px;
color: @gray-light;
@ -54,12 +55,17 @@
min-height: 16px;
}
.message {
padding: @line-height-computed / 2;
border-left: 3px solid transparent;
position: relative;
font-size: 14px;
box-shadow: -1px 2px 3px #ddd;
border-raduis: @border-radius-base;
position: relative;
.message-content {
padding: @line-height-computed / 2;
overflow-x: auto;
}
.arrow {
right: 100%;
top: @line-height-computed / 4;

View file

@ -728,7 +728,7 @@ describe "RecurlyWrapper", ->
describe 'when the account does not exist', ->
beforeEach ->
@apiRequest.callsArgWith(1, new Error('not found'), {statusCode: 404}, '')
@apiRequest.callsArgWith(1, null, {statusCode: 404}, '')
it 'should not produce an error', (done) ->
@call (err, result) =>

View file

@ -109,7 +109,7 @@ describe "SubscriptionController sanboxed", ->
it "should set the correct variables for the template", ->
should.exist @res.renderedVariables.signature
@res.renderedVariables.successURL.should.equal "#{@settings.siteUrl}/user/subscription/update"
@res.renderedVariables.successURL.should.equal "#{@settings.siteUrl}/user/subscription/billing-details/update"
@res.renderedVariables.user.id.should.equal @user._id
describe "with a user without subscription", ->