Merge pull request #1176 from sharelatex/ja-manage-v1-subs

Manage v1 subscriptions from v2

GitOrigin-RevId: 1fd63b3630f781e8b4cc3dc1413966540e8d0076
This commit is contained in:
James Allen 2018-11-30 11:29:40 +01:00 committed by sharelatex
parent e8b7ab1f8a
commit ee800f7448
11 changed files with 151 additions and 15 deletions

View file

@ -12,6 +12,7 @@ UserGetter = require "../User/UserGetter"
FeaturesUpdater = require './FeaturesUpdater'
planFeatures = require './planFeatures'
GroupPlansData = require './GroupPlansData'
V1SubscriptionManager = require "./V1SubscriptionManager"
module.exports = SubscriptionController =
@ -97,7 +98,8 @@ module.exports = SubscriptionController =
managedGroupSubscriptions,
confirmedMemberInstitutions,
managedInstitutions,
v1Subscriptions
v1Subscriptions,
v1SubscriptionStatus
} = results
logger.log {
user,
@ -106,7 +108,8 @@ module.exports = SubscriptionController =
managedGroupSubscriptions,
confirmedMemberInstitutions,
managedInstitutions,
v1Subscriptions
v1Subscriptions,
v1SubscriptionStatus
}, "showing subscription dashboard"
plans = SubscriptionViewModelBuilder.buildViewModel()
data = {
@ -118,7 +121,8 @@ module.exports = SubscriptionController =
managedGroupSubscriptions,
confirmedMemberInstitutions,
managedInstitutions,
v1Subscriptions
v1Subscriptions,
v1SubscriptionStatus
}
res.render "subscriptions/dashboard", data
@ -158,6 +162,15 @@ module.exports = SubscriptionController =
return next(err)
res.redirect "/user/subscription"
cancelV1Subscription: (req, res, next) ->
user_id = AuthenticationController.getLoggedInUserId(req)
logger.log {user_id}, "canceling v1 subscription"
V1SubscriptionManager.cancelV1Subscription user_id, (err)->
if err?
logger.err err:err, user_id:user_id, "something went wrong canceling v1 subscription"
return next(err)
res.redirect "/user/subscription"
updateSubscription: (req, res, next)->
_origin = req?.query?.origin || null
user = AuthenticationController.getSessionUser(req)

View file

@ -40,6 +40,8 @@ module.exports =
webRouter.post '/user/subscription/cancel', AuthenticationController.requireLogin(), SubscriptionController.cancelSubscription
webRouter.post '/user/subscription/reactivate', AuthenticationController.requireLogin(), SubscriptionController.reactivateSubscription
webRouter.post '/user/subscription/v1/cancel', AuthenticationController.requireLogin(), SubscriptionController.cancelV1Subscription
webRouter.put '/user/subscription/extend', AuthenticationController.requireLogin(), SubscriptionController.extendTrial
webRouter.get "/user/subscription/upgrade-annual", AuthenticationController.requireLogin(), SubscriptionController.renderUpgradeToAnnualPlanPage

View file

@ -51,6 +51,10 @@ module.exports =
return cb(error) if error?
# Only return one argument to async.auto, otherwise it returns an array
cb(null, subscriptions)
v1SubscriptionStatus: (cb) ->
V1SubscriptionManager.getSubscriptionStatusFromV1 user._id, (error, status, v1Id) ->
return cb(error) if error?
cb(null, status)
}, (err, results) ->
return callback(err) if err?
{
@ -60,6 +64,7 @@ module.exports =
confirmedMemberInstitutions,
managedInstitutions,
v1Subscriptions,
v1SubscriptionStatus,
recurlySubscription,
plan
} = results
@ -68,6 +73,7 @@ module.exports =
confirmedMemberInstitutions ?= []
managedInstitutions ?= []
v1Subscriptions ?= {}
v1SubscriptionStatus ?= {}
if personalSubscription?.toObject?
@ -97,7 +103,8 @@ module.exports =
memberGroupSubscriptions,
confirmedMemberInstitutions,
managedInstitutions,
v1Subscriptions
v1Subscriptions,
v1SubscriptionStatus
}
buildViewModel : ->

View file

@ -39,6 +39,18 @@ module.exports = V1SubscriptionManager =
url: (v1Id) -> "/api/v1/sharelatex/users/#{v1Id}/subscriptions"
}, callback
getSubscriptionStatusFromV1: (userId, callback=(err, status) ->) ->
V1SubscriptionManager._v1Request userId, {
method: 'GET',
url: (v1Id) -> "/api/v1/sharelatex/users/#{v1Id}/subscription_status"
}, callback
cancelV1Subscription: (userId, callback=(err)->) ->
V1SubscriptionManager._v1Request userId, {
method: 'DELETE',
url: (v1Id) -> "/api/v1/sharelatex/users/#{v1Id}/subscription"
}, callback
v1IdForUser: (userId, callback=(err, v1Id) ->) ->
UserGetter.getUser userId, {'overleaf.id': 1}, (err, user) ->
return callback(err) if err?
@ -76,7 +88,7 @@ module.exports = V1SubscriptionManager =
pass: settings.apis.v1.pass
sendImmediately: true
json: true,
timeout: 5 * 1000
timeout: 15 * 1000
}, (error, response, body) ->
if error?
# Specially handle no connection err, so warning can be shown

View file

@ -16,6 +16,7 @@ hashedFiles = {}
Path = require 'path'
Features = require "./Features"
Modules = require "./Modules"
moment = require 'moment'
jsPath =
if Settings.useMinifiedJs
@ -126,6 +127,7 @@ module.exports = (app, webRouter, privateApiRouter, publicApiRouter)->
res.locals.fullJsPath = Url.resolve(staticFilesBase, jsPath)
res.locals.lib = PackageVersions.lib
res.locals.moment = moment
res.locals.buildJsPath = (jsFile, opts = {})->
path = Path.join(jsPath, jsFile)

View file

@ -35,6 +35,9 @@ block content
-if (settings.overleaf && v1Subscriptions)
include ./dashboard/_v1_subscriptions
-if (v1SubscriptionStatus)
include ./dashboard/_v1_subscription_status
-if (!hasAnySubscription)
p You're on the #{settings.appName} Free plan.
|

View file

@ -0,0 +1,60 @@
- if (v1SubscriptionStatus['team'])
p
| You have a legacy group licence from Overleaf v1.
- if (v1SubscriptionStatus['team']['will_end_at'])
p
| Your current group licence ends on
|
strong= moment(v1SubscriptionStatus['team']['will_end_at']).format('Do MMM YY')
|
| and will
|
- if (v1SubscriptionStatus['team']['will_renew'])
| be automatically renewed.
- else
| not be automatically renewed.
- if (v1SubscriptionStatus['can_cancel_team'])
p
form(method="POST", action="/user/subscription/v1/cancel")
input(type="hidden", name="_csrf", value=csrfToken)
button().btn.btn-danger Stop automatic renewal
- else
p
| Please
|
a(href="/contact") contact support
|
| to make changes to your plan
hr
- if (v1SubscriptionStatus['product'])
p
| You have a legacy Overleaf v1
|
strong= v1SubscriptionStatus['product']['display_name']
|
| plan.
p
| Your plan ends on
|
strong= moment(v1SubscriptionStatus['product']['will_end_at']).format('Do MMM YY')
|
| and will
|
- if (v1SubscriptionStatus['product']['will_renew'])
| be automatically renewed.
- else
| not be automatically renewed.
- if (v1SubscriptionStatus['can_cancel'])
p
form(method="POST", action="/user/subscription/v1/cancel")
input(type="hidden", name="_csrf", value=csrfToken)
button().btn.btn-danger Stop automatic renewal
- else
p
| Please
|
a(href="/contact") contact support
|
| to make changes to your plan
hr

View file

@ -1,11 +1,3 @@
- if (v1Subscriptions.has_subscription)
-hasAnySubscription = true
p
| You are subscribed to Overleaf through Overleaf v1
p
a.btn.btn-primary(href='/sign_in_to_v1?return_to=/users/edit%23status') Manage v1 Subscription
hr
- if (v1Subscriptions.teams && v1Subscriptions.teams.length > 0)
-hasAnySubscription = true
for team in v1Subscriptions.teams

View file

@ -234,7 +234,8 @@ describe 'Subscriptions', ->
before (done) ->
v1Id = MockV1Api.nextV1Id()
MockV1Api.setUser v1Id, {
subscription: {}
subscription: {},
subscription_status: {}
}
MockV1Api.setAffiliations [{
email: 'confirmed-affiliation-email@stanford.example.edu'
@ -281,6 +282,10 @@ describe 'Subscriptions', ->
name: 'Test team'
}]
}
subscription_status: @subscription_status = {
product: { 'mock': 'product' }
team: null
}
}
@user.setV1Id v1Id, (error) =>
return done(error) if error?
@ -295,4 +300,29 @@ describe 'Subscriptions', ->
expect(@data.memberGroupSubscriptions).to.deep.equal []
it 'should return a v1Subscriptions', ->
expect(@data.v1Subscriptions).to.deep.equal @subscription
expect(@data.v1Subscriptions).to.deep.equal @subscription
it 'should return a v1SubscriptionStatus', ->
expect(@data.v1SubscriptionStatus).to.deep.equal @subscription_status
describe.only 'canceling', ->
before (done) ->
@user = new User()
MockV1Api.setUser v1Id = MockV1Api.nextV1Id(), @v1_user = {}
async.series [
(cb) => @user.login(cb)
(cb) => @user.setV1Id(v1Id, cb)
], (error) =>
@user.request {
method: 'POST',
url: '/user/subscription/v1/cancel'
}, (error, @response) =>
return done(error) if error?
done()
it 'should tell v1 to cancel the subscription', ->
expect(@v1_user.canceled).to.equal true
it 'should redirect to the subscription dashboard', ->
expect(@response.statusCode).to.equal 302
expect(@response.headers.location).to.equal '/user/subscription'

View file

@ -53,6 +53,20 @@ module.exports = MockV1Api =
else
res.sendStatus 404
app.get "/api/v1/sharelatex/users/:v1_user_id/subscription_status", (req, res, next) =>
user = @users[req.params.v1_user_id]
if user?.subscription_status?
res.json user.subscription_status
else
res.sendStatus 404
app.delete "/api/v1/sharelatex/users/:v1_user_id/subscription", (req, res, next) =>
user = @users[req.params.v1_user_id]
if user?
user.canceled = true
res.sendStatus 200
else
res.sendStatus 404
app.post "/api/v1/sharelatex/users/:v1_user_id/sync", (req, res, next) =>
@syncUserFeatures(req.params.v1_user_id)

View file

@ -79,6 +79,7 @@ describe "SubscriptionController", ->
"./RecurlyWrapper": @RecurlyWrapper = {}
"./FeaturesUpdater": @FeaturesUpdater = {}
"./GroupPlansData": @GroupPlansData = {}
"./V1SubscriptionManager": @V1SubscriptionManager = {}
@res = new MockResponse()