Merge branch 'master' of github.com:sharelatex/web-sharelatex

This commit is contained in:
James Allen 2015-10-16 12:31:21 +01:00
commit bafd3a1cb4
11 changed files with 112 additions and 134 deletions

View file

@ -11,7 +11,8 @@ module.exports = (grunt) ->
grunt.loadNpmTasks 'grunt-bunyan'
grunt.loadNpmTasks 'grunt-sed'
grunt.loadNpmTasks 'grunt-git-rev-parse'
grunt.loadNpmTasks 'grunt-file-append'
config =
execute:
app:
@ -129,6 +130,14 @@ module.exports = (grunt) ->
options:
prop: 'commit'
file_append:
default_options: files: [ {
append: '\n//ide.js is complete - used for automated testing'
input: 'public/minjs/ide.js'
output: 'public/minjs/ide.js'
}]
sed:
version:
path: "app/views/sentry.jade"
@ -272,7 +281,7 @@ module.exports = (grunt) ->
grunt.registerTask 'compile:server', 'Compile the server side coffee script', ['clean:app', 'coffee:app', 'coffee:app_dir', 'compile:modules:server']
grunt.registerTask 'compile:client', 'Compile the client side coffee script', ['coffee:client', 'coffee:sharejs', 'wrap_sharejs', "compile:modules:client", 'compile:modules:inject_clientside_includes']
grunt.registerTask 'compile:css', 'Compile the less files to css', ['less']
grunt.registerTask 'compile:minify', 'Concat and minify the client side js', ['requirejs']
grunt.registerTask 'compile:minify', 'Concat and minify the client side js', ['requirejs', "file_append"]
grunt.registerTask 'compile:unit_tests', 'Compile the unit tests', ['clean:unit_tests', 'coffee:unit_tests']
grunt.registerTask 'compile:smoke_tests', 'Compile the smoke tests', ['coffee:smoke_tests']
grunt.registerTask 'compile:tests', 'Compile all the tests', ['compile:smoke_tests', 'compile:unit_tests']

View file

@ -32,46 +32,35 @@ module.exports = ReferalAllocator =
assignBonus: (user_id, callback = (error) ->) ->
SubscriptionLocator.getUsersSubscription user_id, (error, subscription) ->
return callback(error) if error?
logger.log
subscription: subscription,
user_id: user_id,
"checking user doesn't have a subsciption before assigning bonus"
if !subscription? or !subscription.planCode?
query = _id: user_id
User.findOne query, (error, user) ->
return callback(error) if error
return callback(new Error("user not found")) if !user?
logger.log
user_id: user_id,
refered_user_count: user.refered_user_count,
"assigning bonus"
if user.refered_user_count? and user.refered_user_count > 0
newFeatures = ReferalAllocator._calculateBonuses(user)
User.update query, { $set: features: newFeatures }, callback
else
callback()
query = _id: user_id
User.findOne query, (error, user) ->
return callback(error) if error
return callback(new Error("user not found")) if !user?
logger.log user_id: user_id, refered_user_count: user.refered_user_count, "assigning bonus"
if user.refered_user_count? and user.refered_user_count > 0
newFeatures = ReferalAllocator._calculateFeatures(user)
if _.isEqual newFeatures, user.features
return callback()
User.update query, { $set: features: newFeatures }, callback
else
callback()
_calculateBonuses : (user)->
bonusLevel = ReferalAllocator._getBonusLevel(user)
newFeatures = {}
_calculateFeatures : (user)->
bonusLevel = ReferalAllocator._getBonusLevel(user)
currentFeatures = _.clone(user.features) #need to clone because we exend with underscore later
betterBonusFeatures = {}
_.each Settings.bonus_features["#{bonusLevel}"], (bonusLevel, key)->
currentLevel = user?.features?[key]
if _.isBoolean(currentLevel) and currentLevel == false
newFeatures[key] = bonusLevel
betterBonusFeatures[key] = bonusLevel
if _.isNumber(currentLevel)
if _.isNumber(currentLevel)
if currentLevel == -1
return
bonusIsGreaterThanCurrent = currentLevel < bonusLevel
if bonusIsGreaterThanCurrent or bonusLevel == -1
newFeatures[key] = bonusLevel
betterBonusFeatures[key] = bonusLevel
newFeatures = _.extend(currentFeatures, betterBonusFeatures)
return newFeatures

View file

@ -6,6 +6,7 @@ html(itemscope, itemtype='http://schema.org/Product')
script(type="text/javascript").
// Stop superfish from loading
window.similarproducts = true
style [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {display: none !important; display: none; }
-if (typeof(gaExperiments) != "undefined")
|!{gaExperiments}

View file

@ -13,7 +13,9 @@ block content
h3 #{translate("loading")}...
.progress
.progress-bar(style="width: 20%", ng-style="{'width': state.load_progress + '%'}")
p.text-center.text-danger(ng-if="state.error").ng-cloak {{ state.error }}
p.text-center.text-danger(ng-if="state.error").ng-cloak
span(ng-bind-html="state.error")
.global-alerts(ng-cloak)
.alert.alert-danger.small(ng-if="connection.forced_disconnect")
@ -28,8 +30,11 @@ block content
.alert.alert-warning.small(ng-if="connection.reconnecting")
strong #{translate("reconnecting")}...
.alert.alert-warning.small(ng-if="connection.inactive_disconnect")
strong #{translate("editor_disconected_click_to_reconnect")}
.div(ng-controller="SavingNotificationController")
.alert.alert-warning.small( ng-repeat="(doc_id, state) in docSavingStatus" ng-if="state.unsavedSeconds > 8") #{translate("saving_notification_with_seconds", {docname:"{{ state.doc.name }}", seconds:"{{ state.unsavedSeconds }}"})}
.alert.alert-warning.small(ng-repeat="(doc_id, state) in docSavingStatus" ng-if="state.unsavedSeconds > 8") #{translate("saving_notification_with_seconds", {docname:"{{ state.doc.name }}", seconds:"{{ state.unsavedSeconds }}"})}
include ./editor/left-menu

View file

@ -100,7 +100,7 @@ div.full-size.pdf(ng-controller="PdfController")
p
a.btn.btn-info(
href
ng-click="hello('compile-timeout')"
ng-click="startFreeTrial('compile-timeout')"
) #{translate("start_free_trial")}
.pdf-errors(ng-show="pdf.projectTooLarge")

View file

@ -284,7 +284,7 @@ module.exports =
title: "ShareLaTeX Community Edition"
left_footer: [{
text: "Powered by <a href='https://www.sharelatex.com'>ShareLaTeX</a> © 2014"
text: "Powered by <a href='https://www.sharelatex.com'>ShareLaTeX</a> © 2015"
}]
right_footer: [{

View file

@ -48,29 +48,30 @@
"session.socket.io": "0.1.4",
"settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git#v1.0.0",
"socket.io": "0.9.16",
"translations-sharelatex": "git+https://github.com/sharelatex/translations-sharelatex.git#v0.2.0",
"translations-sharelatex": "git+https://github.com/sharelatex/translations-sharelatex.git#master",
"underscore": "1.6.0",
"underscore.string": "^3.0.2",
"v8-profiler": "^5.2.3",
"xml2js": "0.2.0"
},
"devDependencies": {
"bunyan": "0.22.1",
"chai": "",
"chai-spies": "",
"sandboxed-module": "0.2.0",
"timekeeper": "",
"sinon": "",
"grunt-available-tasks": "0.4.1",
"grunt-bunyan": "0.5.0",
"grunt-concurrent": "0.4.3",
"grunt-contrib-clean": "0.5.0",
"grunt-contrib-coffee": "0.10.0",
"grunt-contrib-less": "0.9.0",
"grunt-mocha-test": "0.9.0",
"grunt-available-tasks": "0.4.1",
"grunt-contrib-requirejs": "0.4.1",
"grunt-execute": "0.1.5",
"grunt-file-append": "0.0.6",
"grunt-git-rev-parse": "^0.1.4",
"grunt-mocha-test": "0.9.0",
"grunt-sed": "^0.1.1",
"bunyan": "0.22.1",
"grunt-bunyan": "0.5.0"
"sandboxed-module": "0.2.0",
"sinon": "",
"timekeeper": ""
}
}

View file

@ -1,5 +1,12 @@
define [], () ->
ONEHOUR = 1000 * 60 * 60
class ConnectionManager
disconnectAfterMs: ONEHOUR * 24
lastUserAction : new Date()
constructor: (@ide, @$scope) ->
if !io?
console.error "Socket.io javascript not loaded. Please check that the real-time service is running and accessible."
@ -8,18 +15,29 @@ define [], () ->
$scope.$apply () =>
@$scope.state.error = "Could not connect to websocket server :("
return
@connected = false
setInterval(() =>
@disconnectIfInactive()
, ONEHOUR)
@userIsLeavingPage = false
window.addEventListener 'beforeunload', =>
@userIsLeavingPage = true
@connected = false
@userIsInactive = false
@$scope.connection =
reconnecting: false
# If we need to force everyone to reload the editor
forced_disconnect: false
inactive_disconnect: false
@$scope.tryReconnectNow = () =>
@tryReconnect()
@$scope.$on 'cursor:editor:update', () =>
@lastUserAction = new Date()
if !@connected
@tryReconnect()
@ -29,6 +47,7 @@ define [], () ->
@ide.socket = io.connect null,
reconnect: false
'connect timeout': 30 * 1000
"force new connection": true
@ide.socket.on "connect", () =>
@ -37,6 +56,7 @@ define [], () ->
@$scope.$apply () =>
@$scope.connection.reconnecting = false
@$scope.connection.inactive_disconnect = false
if @$scope.state.loading
@$scope.state.load_progress = 70
@ -44,6 +64,13 @@ define [], () ->
@joinProject()
, 100)
@ide.socket.on "connect_failed", () =>
@connected = false
$scope.$apply () =>
@$scope.state.error = "Unable to connect, please view the <u><a href='http://sharelatex.tenderapp.com/help/kb/latex-editor/editor-connection-problems'>connection problems guide</a></u> to fix the issue."
@ide.socket.on 'disconnect', () =>
@connected = false
@ide.pushEvent("disconnected")
@ -55,7 +82,7 @@ define [], () ->
ga('send', 'event', 'editor-interaction', 'disconnect')
, 2000)
if !$scope.connection.forced_disconnect
if !$scope.connection.forced_disconnect and !@userIsInactive
@startAutoReconnectCountdown()
@ide.socket.on 'forceDisconnect', (message) =>
@ -102,6 +129,9 @@ define [], () ->
else
countdown = 3 + Math.floor(Math.random() * 7)
if @userIsLeavingPage #user will have pressed refresh or back etc
return
@$scope.$apply () =>
@$scope.connection.reconnecting = false
@$scope.connection.reconnection_countdown = countdown
@ -133,3 +163,10 @@ define [], () ->
@ide.socket.socket.reconnect()
setTimeout (=> @startAutoReconnectCountdown() if !@connected), 2000
disconnectIfInactive: ()->
@userIsInactive = (new Date() - @lastUserAction) > @disconnectAfterMs
if @userIsInactive and @connected
@disconnect()
@$scope.$apply () =>
@$scope.connection.inactive_disconnect = true

View file

@ -196,6 +196,11 @@ define [
else
$scope.switchToSideBySideLayout()
$scope.startFreeTrial = (source) ->
ga?('send', 'event', 'subscription-funnel', 'compile-timeout', source)
window.open("/user/subscription/new?planCode=student_free_trial_7_days")
$scope.startedFreeTrial = true
App.factory "synctex", ["ide", "$http", "$q", (ide, $http, $q) ->
synctex =
syncToPdf: (cursorPosition) ->

View file

@ -1,7 +1,3 @@
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
.system-message {
padding: (@line-height-computed / 4) (@line-height-computed / 2);
background-color: @state-warning-bg;

View file

@ -4,7 +4,7 @@ require('chai').should()
sinon = require('sinon')
modulePath = require('path').join __dirname, '../../../../app/js/Features/Referal/ReferalAllocator.js'
describe 'Referal allocator', ->
describe 'Referalallocator', ->
beforeEach ->
@ReferalAllocator = SandboxedModule.require modulePath, requires:
@ -75,7 +75,6 @@ describe 'Referal allocator', ->
@callback.called.should.equal true
describe "assignBonus", ->
describe "when user does not have a subscription", ->
beforeEach ->
@refered_user_count = 3
@Settings.bonus_features =
@ -88,16 +87,10 @@ describe 'Referal allocator', ->
features:{collaborators:1, dropbox:false, versioning:false}
}
@User.findOne = sinon.stub().callsArgWith 1, null,stubbedUser
@User.findOne = sinon.stub().callsArgWith 1, null, stubbedUser
@User.update = sinon.stub().callsArgWith 2, null
@SubscriptionLocator.getUsersSubscription = sinon.stub().callsArgWith 1, null, null
@ReferalAllocator.assignBonus @user_id, @callback
it "should get the users subscription", ->
@SubscriptionLocator.getUsersSubscription
.calledWith(@user_id)
.should.equal true
it "should get the users number of refered user", ->
@User.findOne
.calledWith(_id: @user_id)
@ -116,52 +109,26 @@ describe 'Referal allocator', ->
it "should call the callback", ->
@callback.called.should.equal true
describe "when user does not have a recurlySubscription_id", ->
describe "when there is nothing to assign", ->
beforeEach ->
@refered_user_count = 4
@ReferalAllocator._calculateBonuses = sinon.stub().returns({})
@stubbedUser =
refered_user_count:4
features:{collaborators:3, versioning:true, dropbox:false}
@Settings.bonus_features =
"2":
collaborators: 2
dropbox: false
versioning: false
"5":
collaborators: 5
dropbox: true
versioning: false
"3":
collaborators: 3
dropbox: false
versioning: false
stubbedUser = { refered_user_count: @refered_user_count, features:{collaborators:1, dropbox:false, versioning:false} }
@User.findOne = sinon.stub().callsArgWith 1, null, stubbedUser
"4":
collaborators:3
versioning:true
dropbox:false
@User.findOne = sinon.stub().callsArgWith 1, null, @stubbedUser
@User.update = sinon.stub().callsArgWith 2, null
@SubscriptionLocator.getUsersSubscription = sinon.stub().callsArgWith 1, null, {}
@ReferalAllocator.assignBonus @user_id, @callback
it "should get the users subscription", ->
@SubscriptionLocator.getUsersSubscription
.calledWith(@user_id)
.should.equal true
it "should get the users number of refered user", ->
@User.findOne
.calledWith(_id: @user_id)
.should.equal true
it "should update the user to bonus features with the closest level", ->
@User.update
.calledWith({
_id: @user_id
}, {
$set:
features:
@Settings.bonus_features["3"]
})
.should.equal true
it "should call the callback", ->
@callback.called.should.equal true
it "should not call update if there are no bonuses to apply", (done)->
@ReferalAllocator.assignBonus @user_id, (err)=>
@User.update.called.should.equal false
done()
describe "when the user has better features already", ->
@ -181,7 +148,6 @@ describe 'Referal allocator', ->
@User.findOne = sinon.stub().callsArgWith 1, null, @stubbedUser
@User.update = sinon.stub().callsArgWith 2, null
@SubscriptionLocator.getUsersSubscription = sinon.stub().callsArgWith 1, null,null
it "should not set in in mongo when the feature is better", (done)->
@ReferalAllocator.assignBonus @user_id, =>
@ -191,7 +157,7 @@ describe 'Referal allocator', ->
it "should not overright if the user has -1 users", (done)->
@stubbedUser.features.collaborators = -1
@ReferalAllocator.assignBonus @user_id, =>
@User.update.calledWith({_id: @user_id }, {$set: features:{dropbox:true, versioning:false} }).should.equal true
@User.update.calledWith({_id: @user_id }, {$set: features:{dropbox:true, versioning:false, collaborators:-1} }).should.equal true
done()
describe "when the user is not at a bonus level", ->
@ -204,14 +170,8 @@ describe 'Referal allocator', ->
versioning: false
@User.findOne = sinon.stub().callsArgWith 1, null, { refered_user_count: @refered_user_count }
@User.update = sinon.stub().callsArgWith 2, null
@SubscriptionLocator.getUsersSubscription = sinon.stub().callsArgWith 1, null, {}
@ReferalAllocator.assignBonus @user_id, @callback
it "should get the users subscription", ->
@SubscriptionLocator.getUsersSubscription
.calledWith(@user_id)
.should.equal true
it "should get the users number of refered user", ->
@User.findOne
.calledWith(_id: @user_id)
@ -223,29 +183,4 @@ describe 'Referal allocator', ->
it "should call the callback", ->
@callback.called.should.equal true
describe "when user has a subscription", ->
beforeEach ->
@refered_user_count = 3
@Settings.bonus_features =
"3":
collaborators: 3
dropbox: false
versioning: false
@User.findOne = sinon.stub().callsArgWith 1, null, { refered_user_count: @refered_user_count }
@User.update = sinon.stub().callsArgWith 2, null
@SubscriptionLocator.getUsersSubscription = sinon.stub().callsArgWith 1, null, { planCode: "collaborator" }
@ReferalAllocator.assignBonus @user_id, @callback
it "should get the users subscription", ->
@SubscriptionLocator.getUsersSubscription
.calledWith(@user_id)
.should.equal true
it "should not get the users number of refered user", ->
@User.findOne.called.should.equal false
it "should not update the user to bonus features", ->
@User.update.called.should.equal false
it "should call the callback", ->
@callback.called.should.equal true