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({
|
RecurlyWrapper.apiRequest({
|
||||||
url: "accounts/#{user._id}"
|
url: "accounts/#{user._id}"
|
||||||
method: "GET"
|
method: "GET"
|
||||||
|
expect404: true
|
||||||
}, (error, response, responseBody) ->
|
}, (error, response, responseBody) ->
|
||||||
if error
|
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"
|
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while checking account"
|
||||||
return next(error)
|
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"
|
logger.log {user_id: user._id, recurly_token_id}, "user appears to exist in recurly"
|
||||||
RecurlyWrapper._parseAccountXml responseBody, (err, account) ->
|
RecurlyWrapper._parseAccountXml responseBody, (err, account) ->
|
||||||
if err
|
if err
|
||||||
|
@ -236,10 +238,14 @@ module.exports = RecurlyWrapper =
|
||||||
"Authorization" : "Basic " + new Buffer(Settings.apis.recurly.apiKey).toString("base64")
|
"Authorization" : "Basic " + new Buffer(Settings.apis.recurly.apiKey).toString("base64")
|
||||||
"Accept" : "application/xml"
|
"Accept" : "application/xml"
|
||||||
"Content-Type" : "application/xml; charset=utf-8"
|
"Content-Type" : "application/xml; charset=utf-8"
|
||||||
|
expect404 = options.expect404
|
||||||
|
delete options.expect404
|
||||||
request options, (error, response, body) ->
|
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"
|
logger.err err:error, body:body, options:options, statusCode:response?.statusCode, "error returned from recurly"
|
||||||
error = "Recurly API returned with status code: #{response.statusCode}"
|
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)
|
callback(error, response, body)
|
||||||
|
|
||||||
sign : (parameters, callback) ->
|
sign : (parameters, callback) ->
|
||||||
|
|
|
@ -22,6 +22,7 @@ module.exports = SubscriptionController =
|
||||||
viewName = "#{viewName}_#{req.query.v}"
|
viewName = "#{viewName}_#{req.query.v}"
|
||||||
logger.log viewName:viewName, "showing plans page"
|
logger.log viewName:viewName, "showing plans page"
|
||||||
GeoIpLookup.getCurrencyCode req.query?.ip || req.ip, (err, recomendedCurrency)->
|
GeoIpLookup.getCurrencyCode req.query?.ip || req.ip, (err, recomendedCurrency)->
|
||||||
|
return next(err) if err?
|
||||||
res.render viewName,
|
res.render viewName,
|
||||||
title: "plans_and_pricing"
|
title: "plans_and_pricing"
|
||||||
plans: plans
|
plans: plans
|
||||||
|
@ -71,6 +72,7 @@ module.exports = SubscriptionController =
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) =>
|
AuthenticationController.getLoggedInUser req, (error, user) =>
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
LimitationsManager.userHasSubscriptionOrIsGroupMember user, (err, hasSubOrIsGroupMember, subscription)->
|
LimitationsManager.userHasSubscriptionOrIsGroupMember user, (err, hasSubOrIsGroupMember, subscription)->
|
||||||
|
return next(err) if err?
|
||||||
groupLicenceInviteUrl = SubscriptionDomainHandler.getDomainLicencePage(user)
|
groupLicenceInviteUrl = SubscriptionDomainHandler.getDomainLicencePage(user)
|
||||||
if subscription?.customAccount
|
if subscription?.customAccount
|
||||||
logger.log user: user, "redirecting to custom account page"
|
logger.log user: user, "redirecting to custom account page"
|
||||||
|
@ -95,11 +97,13 @@ module.exports = SubscriptionController =
|
||||||
groupSubscriptions: groupSubscriptions
|
groupSubscriptions: groupSubscriptions
|
||||||
subscriptionTabActive: true
|
subscriptionTabActive: true
|
||||||
user:user
|
user:user
|
||||||
|
saved_billing_details: req.query.saved_billing_details?
|
||||||
|
|
||||||
userCustomSubscriptionPage: (req, res, next)->
|
userCustomSubscriptionPage: (req, res, next)->
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
|
return next(error) if error?
|
||||||
LimitationsManager.userHasSubscriptionOrIsGroupMember user, (err, hasSubOrIsGroupMember, subscription)->
|
LimitationsManager.userHasSubscriptionOrIsGroupMember user, (err, hasSubOrIsGroupMember, subscription)->
|
||||||
|
return next(err) if err?
|
||||||
if !subscription?
|
if !subscription?
|
||||||
err = new Error("subscription null for custom account, user:#{user?._id}")
|
err = new Error("subscription null for custom account, user:#{user?._id}")
|
||||||
logger.warn err:err, "subscription is null for custom accounts page"
|
logger.warn err:err, "subscription is null for custom accounts page"
|
||||||
|
@ -113,6 +117,7 @@ module.exports = SubscriptionController =
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
LimitationsManager.userHasSubscription user, (err, hasSubscription)->
|
LimitationsManager.userHasSubscription user, (err, hasSubscription)->
|
||||||
|
return next(err) if err?
|
||||||
if !hasSubscription
|
if !hasSubscription
|
||||||
res.redirect "/user/subscription"
|
res.redirect "/user/subscription"
|
||||||
else
|
else
|
||||||
|
@ -126,10 +131,13 @@ module.exports = SubscriptionController =
|
||||||
currency: "USD"
|
currency: "USD"
|
||||||
subdomain: Settings.apis.recurly.subdomain
|
subdomain: Settings.apis.recurly.subdomain
|
||||||
signature : signature
|
signature : signature
|
||||||
successURL : "#{Settings.siteUrl}/user/subscription/update"
|
successURL : "#{Settings.siteUrl}/user/subscription/billing-details/update"
|
||||||
user :
|
user :
|
||||||
id : user._id
|
id : user._id
|
||||||
|
|
||||||
|
updateBillingDetails: (req, res, next) ->
|
||||||
|
res.redirect "/user/subscription?saved_billing_details=true"
|
||||||
|
|
||||||
createSubscription: (req, res, next)->
|
createSubscription: (req, res, next)->
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
|
@ -142,54 +150,67 @@ module.exports = SubscriptionController =
|
||||||
return res.sendStatus 500
|
return res.sendStatus 500
|
||||||
res.sendStatus 201
|
res.sendStatus 201
|
||||||
|
|
||||||
successful_subscription: (req, res)->
|
successful_subscription: (req, res, next)->
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) =>
|
AuthenticationController.getLoggedInUser req, (error, user) =>
|
||||||
|
return next(error) if error?
|
||||||
SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel user, (error, subscription) ->
|
SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel user, (error, subscription) ->
|
||||||
|
return next(error) if error?
|
||||||
res.render "subscriptions/successful_subscription",
|
res.render "subscriptions/successful_subscription",
|
||||||
title: "thank_you"
|
title: "thank_you"
|
||||||
subscription:subscription
|
subscription:subscription
|
||||||
|
|
||||||
cancelSubscription: (req, res, next) ->
|
cancelSubscription: (req, res, next) ->
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
logger.log user_id:user._id, "canceling subscription"
|
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
|
logger.log user_id:user._id, "canceling subscription"
|
||||||
SubscriptionHandler.cancelSubscription user, (err)->
|
SubscriptionHandler.cancelSubscription user, (err)->
|
||||||
if err?
|
if err?
|
||||||
logger.err err:err, user_id:user._id, "something went wrong canceling subscription"
|
logger.err err:err, user_id:user._id, "something went wrong canceling subscription"
|
||||||
|
return next(err)
|
||||||
res.redirect "/user/subscription"
|
res.redirect "/user/subscription"
|
||||||
|
|
||||||
updateSubscription: (req, res)->
|
updateSubscription: (req, res, next)->
|
||||||
|
_origin = req?.query?.origin || null
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
planCode = req.body.plan_code
|
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"
|
logger.log planCode: planCode, user_id:user._id, "updating subscription"
|
||||||
SubscriptionHandler.updateSubscription user, planCode, null, (err)->
|
SubscriptionHandler.updateSubscription user, planCode, null, (err)->
|
||||||
if err?
|
if err?
|
||||||
logger.err err:err, user_id:user._id, "something went wrong updating subscription"
|
logger.err err:err, user_id:user._id, "something went wrong updating subscription"
|
||||||
|
return next(err)
|
||||||
res.redirect "/user/subscription"
|
res.redirect "/user/subscription"
|
||||||
|
|
||||||
reactivateSubscription: (req, res)->
|
reactivateSubscription: (req, res, next)->
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
logger.log user_id:user._id, "reactivating subscription"
|
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
|
logger.log user_id:user._id, "reactivating subscription"
|
||||||
SubscriptionHandler.reactivateSubscription user, (err)->
|
SubscriptionHandler.reactivateSubscription user, (err)->
|
||||||
if err?
|
if err?
|
||||||
logger.err err:err, user_id:user._id, "something went wrong reactivating subscription"
|
logger.err err:err, user_id:user._id, "something went wrong reactivating subscription"
|
||||||
|
return next(err)
|
||||||
res.redirect "/user/subscription"
|
res.redirect "/user/subscription"
|
||||||
|
|
||||||
recurlyCallback: (req, res)->
|
recurlyCallback: (req, res, next)->
|
||||||
logger.log data: req.body, "received recurly callback"
|
logger.log data: req.body, "received recurly callback"
|
||||||
# we only care if a subscription has exipired
|
# we only care if a subscription has exipired
|
||||||
if req.body? and req.body["expired_subscription_notification"]?
|
if req.body? and req.body["expired_subscription_notification"]?
|
||||||
recurlySubscription = req.body["expired_subscription_notification"].subscription
|
recurlySubscription = req.body["expired_subscription_notification"].subscription
|
||||||
SubscriptionHandler.recurlyCallback recurlySubscription, ->
|
SubscriptionHandler.recurlyCallback recurlySubscription, (err)->
|
||||||
|
return next(err) if err?
|
||||||
res.sendStatus 200
|
res.sendStatus 200
|
||||||
else
|
else
|
||||||
res.sendStatus 200
|
res.sendStatus 200
|
||||||
|
|
||||||
renderUpgradeToAnnualPlanPage: (req, res)->
|
renderUpgradeToAnnualPlanPage: (req, res, next)->
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
|
return next(error) if error?
|
||||||
LimitationsManager.userHasSubscription user, (err, hasSubscription, subscription)->
|
LimitationsManager.userHasSubscription user, (err, hasSubscription, subscription)->
|
||||||
|
return next(err) if err?
|
||||||
planCode = subscription?.planCode.toLowerCase()
|
planCode = subscription?.planCode.toLowerCase()
|
||||||
if planCode?.indexOf("annual") != -1
|
if planCode?.indexOf("annual") != -1
|
||||||
planName = "annual"
|
planName = "annual"
|
||||||
|
@ -204,8 +225,9 @@ module.exports = SubscriptionController =
|
||||||
title: "Upgrade to annual"
|
title: "Upgrade to annual"
|
||||||
planName: planName
|
planName: planName
|
||||||
|
|
||||||
processUpgradeToAnnualPlan: (req, res)->
|
processUpgradeToAnnualPlan: (req, res, next)->
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
|
return next(error) if error?
|
||||||
{planName} = req.body
|
{planName} = req.body
|
||||||
coupon_code = Settings.coupon_codes.upgradeToAnnualPromo[planName]
|
coupon_code = Settings.coupon_codes.upgradeToAnnualPromo[planName]
|
||||||
annualPlanName = "#{planName}-annual"
|
annualPlanName = "#{planName}-annual"
|
||||||
|
@ -213,13 +235,14 @@ module.exports = SubscriptionController =
|
||||||
SubscriptionHandler.updateSubscription user, annualPlanName, coupon_code, (err)->
|
SubscriptionHandler.updateSubscription user, annualPlanName, coupon_code, (err)->
|
||||||
if err?
|
if err?
|
||||||
logger.err err:err, user_id:user._id, "error updating subscription"
|
logger.err err:err, user_id:user._id, "error updating subscription"
|
||||||
res.sendStatus 500
|
return next(err)
|
||||||
else
|
res.sendStatus 200
|
||||||
res.sendStatus 200
|
|
||||||
|
|
||||||
extendTrial: (req, res)->
|
extendTrial: (req, res, next)->
|
||||||
AuthenticationController.getLoggedInUser req, (error, user) ->
|
AuthenticationController.getLoggedInUser req, (error, user) ->
|
||||||
|
return next(error) if error?
|
||||||
LimitationsManager.userHasSubscription user, (err, hasSubscription, subscription)->
|
LimitationsManager.userHasSubscription user, (err, hasSubscription, subscription)->
|
||||||
|
return next(err) if err?
|
||||||
SubscriptionHandler.extendTrial subscription, 14, (err)->
|
SubscriptionHandler.extendTrial subscription, 14, (err)->
|
||||||
if err?
|
if err?
|
||||||
res.send 500
|
res.send 500
|
||||||
|
|
|
@ -16,6 +16,7 @@ module.exports =
|
||||||
|
|
||||||
webRouter.get '/user/subscription/new', AuthenticationController.requireLogin(), SubscriptionController.paymentPage
|
webRouter.get '/user/subscription/new', AuthenticationController.requireLogin(), SubscriptionController.paymentPage
|
||||||
webRouter.get '/user/subscription/billing-details/edit', AuthenticationController.requireLogin(), SubscriptionController.editBillingDetailsPage
|
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
|
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%)'}")
|
.arrow(ng-style="{'border-color': 'hsl({{ hue(message.user) }}, 70%, 70%)'}")
|
||||||
p(
|
.message-content
|
||||||
mathjax,
|
p(
|
||||||
ng-repeat="content in message.contents track by $index"
|
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
|
.new-message
|
||||||
textarea(
|
textarea(
|
||||||
|
|
|
@ -40,6 +40,11 @@ block content
|
||||||
.container(ng-controller="UserSubscriptionController")
|
.container(ng-controller="UserSubscriptionController")
|
||||||
.row
|
.row
|
||||||
.col-md-8.col-md-offset-2
|
.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'")
|
.card(ng-if="view == 'overview'")
|
||||||
.page-header
|
.page-header
|
||||||
h1 #{translate("your_subscription")}
|
h1 #{translate("your_subscription")}
|
||||||
|
|
|
@ -19,7 +19,7 @@ block content
|
||||||
Recurly.config(!{recurlyConfig})
|
Recurly.config(!{recurlyConfig})
|
||||||
Recurly.buildBillingInfoUpdateForm({
|
Recurly.buildBillingInfoUpdateForm({
|
||||||
target : "#billingDetailsForm",
|
target : "#billingDetailsForm",
|
||||||
successURL : "#{successURL}?_csrf=#{csrfToken}",
|
successURL : "#{successURL}?_csrf=#{csrfToken}&origin=editBillingDetails",
|
||||||
signature : "!{signature}",
|
signature : "!{signature}",
|
||||||
accountCode : "#{user.id}"
|
accountCode : "#{user.id}"
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,8 @@ define [
|
||||||
_getRule = (logMessage) ->
|
_getRule = (logMessage) ->
|
||||||
return rule for rule in ruleset when rule.regexToMatch.test 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
|
for entry in parsedLogEntries.all
|
||||||
ruleDetails = _getRule entry.message
|
ruleDetails = _getRule entry.message
|
||||||
|
|
||||||
|
@ -21,8 +23,20 @@ define [
|
||||||
entry.ruleId = 'hint_' + ruleDetails.regexToMatch.toString().replace(/\s/g, '_').slice(1, -1)
|
entry.ruleId = 'hint_' + ruleDetails.regexToMatch.toString().replace(/\s/g, '_').slice(1, -1)
|
||||||
if ruleDetails.newMessage?
|
if ruleDetails.newMessage?
|
||||||
entry.message = entry.message.replace ruleDetails.regexToMatch, 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.humanReadableHint = ruleDetails.humanReadableHint if ruleDetails.humanReadableHint?
|
||||||
entry.extraInfoURL = ruleDetails.extraInfoURL if ruleDetails.extraInfoURL?
|
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
|
return parsedLogEntries
|
||||||
|
|
|
@ -90,6 +90,7 @@ define -> [
|
||||||
"""
|
"""
|
||||||
,
|
,
|
||||||
ruleId: "hint_mismatched_environment"
|
ruleId: "hint_mismatched_environment"
|
||||||
|
types: ['environment']
|
||||||
regexToMatch: /Error: `([^']{2,})' expected, found `([^']{2,})'.*/
|
regexToMatch: /Error: `([^']{2,})' expected, found `([^']{2,})'.*/
|
||||||
newMessage: "Error: environment does not match \\begin{$1} ... \\end{$2}"
|
newMessage: "Error: environment does not match \\begin{$1} ... \\end{$2}"
|
||||||
humanReadableHint: """
|
humanReadableHint: """
|
||||||
|
@ -97,10 +98,85 @@ define -> [
|
||||||
"""
|
"""
|
||||||
,
|
,
|
||||||
ruleId: "hint_mismatched_brackets"
|
ruleId: "hint_mismatched_brackets"
|
||||||
|
types: ['environment']
|
||||||
regexToMatch: /Error: `([^a-zA-Z0-9])' expected, found `([^a-zA-Z0-9])'.*/
|
regexToMatch: /Error: `([^a-zA-Z0-9])' expected, found `([^a-zA-Z0-9])'.*/
|
||||||
newMessage: "Error: brackets do not match, found '$2' instead of '$1'"
|
newMessage: "Error: brackets do not match, found '$2' instead of '$1'"
|
||||||
humanReadableHint: """
|
humanReadableHint: """
|
||||||
You have used an open bracket without a corresponding close bracket.
|
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
|
$scope.inflight = true
|
||||||
|
|
||||||
|
$http.post("#{SUBSCRIPTION_URL}?origin=confirmChangePlan", body)
|
||||||
$http.post(SUBSCRIPTION_URL, body)
|
|
||||||
.success ->
|
.success ->
|
||||||
location.reload()
|
location.reload()
|
||||||
.error ->
|
.error ->
|
||||||
|
@ -124,7 +123,7 @@ define [
|
||||||
plan_code: 'student'
|
plan_code: 'student'
|
||||||
_csrf : window.csrfToken
|
_csrf : window.csrfToken
|
||||||
$scope.inflight = true
|
$scope.inflight = true
|
||||||
$http.post(SUBSCRIPTION_URL, body)
|
$http.post("#{SUBSCRIPTION_URL}?origin=downgradeToStudent", body)
|
||||||
.success ->
|
.success ->
|
||||||
location.reload()
|
location.reload()
|
||||||
.error ->
|
.error ->
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
}
|
}
|
||||||
.message-wrapper {
|
.message-wrapper {
|
||||||
margin-left: 50px + @line-height-computed/2;
|
margin-left: 50px + @line-height-computed/2;
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: @gray-light;
|
color: @gray-light;
|
||||||
|
@ -54,12 +55,17 @@
|
||||||
min-height: 16px;
|
min-height: 16px;
|
||||||
}
|
}
|
||||||
.message {
|
.message {
|
||||||
padding: @line-height-computed / 2;
|
|
||||||
border-left: 3px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
position: relative;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
box-shadow: -1px 2px 3px #ddd;
|
box-shadow: -1px 2px 3px #ddd;
|
||||||
border-raduis: @border-radius-base;
|
border-raduis: @border-radius-base;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.message-content {
|
||||||
|
padding: @line-height-computed / 2;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.arrow {
|
.arrow {
|
||||||
right: 100%;
|
right: 100%;
|
||||||
top: @line-height-computed / 4;
|
top: @line-height-computed / 4;
|
||||||
|
|
|
@ -728,7 +728,7 @@ describe "RecurlyWrapper", ->
|
||||||
describe 'when the account does not exist', ->
|
describe 'when the account does not exist', ->
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@apiRequest.callsArgWith(1, new Error('not found'), {statusCode: 404}, '')
|
@apiRequest.callsArgWith(1, null, {statusCode: 404}, '')
|
||||||
|
|
||||||
it 'should not produce an error', (done) ->
|
it 'should not produce an error', (done) ->
|
||||||
@call (err, result) =>
|
@call (err, result) =>
|
||||||
|
|
|
@ -109,7 +109,7 @@ describe "SubscriptionController sanboxed", ->
|
||||||
|
|
||||||
it "should set the correct variables for the template", ->
|
it "should set the correct variables for the template", ->
|
||||||
should.exist @res.renderedVariables.signature
|
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
|
@res.renderedVariables.user.id.should.equal @user._id
|
||||||
|
|
||||||
describe "with a user without subscription", ->
|
describe "with a user without subscription", ->
|
||||||
|
|
Loading…
Reference in a new issue