mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge branch 'master' into ho-jade-speedup
This commit is contained in:
commit
f8799334ec
12 changed files with 167 additions and 36 deletions
|
@ -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) ->
|
||||
|
|
|
@ -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
|
||||
res.sendStatus 200
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -41,11 +41,12 @@ aside.chat(
|
|||
}"
|
||||
)
|
||||
.arrow(ng-style="{'border-color': 'hsl({{ hue(message.user) }}, 70%, 70%)'}")
|
||||
p(
|
||||
mathjax,
|
||||
ng-repeat="content in message.contents track by $index"
|
||||
)
|
||||
span(ng-bind-html="content | linky:'_blank' | wrapLongWords")
|
||||
.message-content
|
||||
p(
|
||||
mathjax,
|
||||
ng-repeat="content in message.contents track by $index"
|
||||
)
|
||||
span(ng-bind-html="content | linky:'_blank'")
|
||||
|
||||
.new-message
|
||||
textarea(
|
||||
|
|
|
@ -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")}
|
||||
|
|
|
@ -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}"
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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{}.
|
||||
"""
|
||||
]
|
||||
|
|
|
@ -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 ->
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) =>
|
||||
|
|
|
@ -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", ->
|
||||
|
|
Loading…
Reference in a new issue