mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge branch 'master' of https://github.com/sharelatex/web-sharelatex
This commit is contained in:
commit
895af7c07a
11 changed files with 283 additions and 2 deletions
|
@ -0,0 +1,29 @@
|
|||
BetaProgramHandler = require './BetaProgramHandler'
|
||||
UserLocator = require "../User/UserLocator"
|
||||
Settings = require "settings-sharelatex"
|
||||
logger = require 'logger-sharelatex'
|
||||
|
||||
|
||||
module.exports = BetaProgramController =
|
||||
|
||||
optIn: (req, res, next) ->
|
||||
user_id = req?.session?.user?._id
|
||||
logger.log {user_id}, "user opting in to beta program"
|
||||
if !user_id
|
||||
return next(new Error("no user id in session"))
|
||||
BetaProgramHandler.optIn user_id, (err) ->
|
||||
if err
|
||||
return next(err)
|
||||
return res.redirect "/beta/opt-in"
|
||||
|
||||
optInPage: (req, res, next)->
|
||||
user_id = req.session?.user?._id
|
||||
logger.log {user_id}, "showing beta opt-in page for user"
|
||||
UserLocator.findById user_id, (err, user)->
|
||||
if err
|
||||
logger.err {err, user_id}, "error fetching user"
|
||||
return next(err)
|
||||
res.render 'beta_program/opt_in',
|
||||
title:'sharelatex_beta_program'
|
||||
user: user,
|
||||
languages: Settings.languages,
|
|
@ -0,0 +1,18 @@
|
|||
User = require("../../models/User").User
|
||||
logger = require 'logger-sharelatex'
|
||||
metrics = require("../../infrastructure/Metrics")
|
||||
|
||||
module.exports = BetaProgramHandler =
|
||||
|
||||
optIn: (user_id, callback=(err)->) ->
|
||||
User.findById user_id, (err, user) ->
|
||||
if err
|
||||
logger.err {err, user_id}, "problem adding user to beta"
|
||||
return callback(err)
|
||||
metrics.inc "beta-program.opt-in"
|
||||
user.betaProgram = true
|
||||
user.save (err) ->
|
||||
if err
|
||||
logger.err {err, user_id}, "problem adding user to beta"
|
||||
return callback(err)
|
||||
return callback(null)
|
|
@ -38,6 +38,7 @@ InactiveProjectController = require("./Features/InactiveData/InactiveProjectCont
|
|||
ContactRouter = require("./Features/Contacts/ContactRouter")
|
||||
ReferencesController = require('./Features/References/ReferencesController')
|
||||
AuthorizationMiddlewear = require('./Features/Authorization/AuthorizationMiddlewear')
|
||||
BetaProgramController = require('./Features/BetaProgram/BetaProgramController')
|
||||
|
||||
logger = require("logger-sharelatex")
|
||||
_ = require("underscore")
|
||||
|
@ -197,6 +198,9 @@ module.exports = class Router
|
|||
webRouter.post "/project/:Project_id/references/index", AuthorizationMiddlewear.ensureUserCanReadProject, ReferencesController.index
|
||||
webRouter.post "/project/:Project_id/references/indexAll", AuthorizationMiddlewear.ensureUserCanReadProject, ReferencesController.indexAll
|
||||
|
||||
webRouter.get "/beta/opt-in", AuthenticationController.requireLogin(), BetaProgramController.optInPage
|
||||
webRouter.post "/beta/opt-in", AuthenticationController.requireLogin(), BetaProgramController.optIn
|
||||
|
||||
#Admin Stuff
|
||||
webRouter.get '/admin', AuthorizationMiddlewear.ensureUserIsSiteAdmin, AdminController.index
|
||||
webRouter.get '/admin/user', AuthorizationMiddlewear.ensureUserIsSiteAdmin, (req, res)-> res.redirect("/admin/register") #this gets removed by admin-panel addon
|
||||
|
|
40
services/web/app/views/beta_program/opt_in.jade
Normal file
40
services/web/app/views/beta_program/opt_in.jade
Normal file
|
@ -0,0 +1,40 @@
|
|||
extends ../layout
|
||||
|
||||
block content
|
||||
.content.content-alt
|
||||
.container.beta-opt-in-wrapper
|
||||
.row
|
||||
.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
|
||||
.card
|
||||
.page-header.text-centered
|
||||
h1
|
||||
| #{translate("sharelatex_beta_program")}
|
||||
.beta-opt-in
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-12
|
||||
p.text-centered #{translate("beta_program_benefits")}
|
||||
p.text-centered
|
||||
| #{translate("beta_program_badge_description")}
|
||||
span.beta-feature-badge
|
||||
p.text-centered
|
||||
| #{translate("beta_program_current_beta_features_description")}
|
||||
ul.list-unstyled.text-center
|
||||
li
|
||||
i.fa.fa-fw.fa-book
|
||||
| #{translate("mendeley_integration")}
|
||||
.row.text-centered
|
||||
.col-md-12
|
||||
if user.betaProgram
|
||||
p #{translate("beta_program_already_participating")}
|
||||
.form-group
|
||||
a(href="/project").btn.btn-info #{translate("back_to_your_projects")}
|
||||
else
|
||||
form(method="post", action="/beta/opt-in", novalidate)
|
||||
.form-group
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
button.btn.btn-primary(
|
||||
type="submit"
|
||||
)
|
||||
span #{translate("beta_program_opt_in_action")}
|
||||
|
|
@ -15,7 +15,7 @@ aside#left-menu.full-size(
|
|||
| #{translate("source")}
|
||||
li
|
||||
a(
|
||||
ng-href="{{pdf.url}}"
|
||||
ng-href="{{pdf.downloadUrl || pdf.url}}"
|
||||
target="_blank"
|
||||
ng-if="pdf.url"
|
||||
)
|
||||
|
|
|
@ -46,7 +46,7 @@ div.full-size.pdf(ng-controller="PdfController")
|
|||
) {{ pdf.logEntries.errors.length + pdf.logEntries.warnings.length }}
|
||||
|
||||
a(
|
||||
ng-href="{{pdf.url}}"
|
||||
ng-href="{{pdf.downloadUrl || pdf.url}}"
|
||||
target="_blank"
|
||||
ng-if="pdf.url"
|
||||
tooltip="#{translate('download_pdf')}"
|
||||
|
|
|
@ -104,6 +104,7 @@ define [
|
|||
qs_args = ("#{k}=#{v}" for k, v of qs)
|
||||
$scope.pdf.qs = if qs_args.length then "?" + qs_args.join("&") else ""
|
||||
$scope.pdf.url += $scope.pdf.qs
|
||||
$scope.pdf.downloadUrl = "/Project/#{$scope.project_id}/output/output.pdf" + $scope.pdf.qs
|
||||
|
||||
fetchLogs(fileByPath['output.log'], fileByPath['output.blg'])
|
||||
|
||||
|
|
21
services/web/public/stylesheets/app/beta-program.less
Normal file
21
services/web/public/stylesheets/app/beta-program.less
Normal file
|
@ -0,0 +1,21 @@
|
|||
.beta-opt-in-wrapper {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.beta-opt-in {
|
||||
.form-group {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.beta-feature-badge {
|
||||
&:extend(.label);
|
||||
&:extend(.label-warning);
|
||||
vertical-align: 11%;
|
||||
padding-bottom: 4px;
|
||||
padding-top: 2px;
|
||||
margin-left: 12px;
|
||||
&:before {
|
||||
content: "β";
|
||||
}
|
||||
}
|
|
@ -58,6 +58,7 @@
|
|||
// ShareLaTeX app classes
|
||||
@import "app/base.less";
|
||||
@import "app/account-settings.less";
|
||||
@import "app/beta-program.less";
|
||||
@import "app/about-page.less";
|
||||
@import "app/project-list.less";
|
||||
@import "app/editor.less";
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
should = require('chai').should()
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
assert = require('assert')
|
||||
path = require('path')
|
||||
sinon = require('sinon')
|
||||
modulePath = path.join __dirname, "../../../../app/js/Features/BetaProgram/BetaProgramController"
|
||||
expect = require("chai").expect
|
||||
|
||||
describe "BetaProgramController", ->
|
||||
|
||||
beforeEach ->
|
||||
@user =
|
||||
_id: @user_id = "a_simple_id"
|
||||
email: "user@example.com"
|
||||
features: {}
|
||||
betaProgram: false
|
||||
@req =
|
||||
query: {}
|
||||
session:
|
||||
user: @user
|
||||
@BetaProgramController = SandboxedModule.require modulePath, requires:
|
||||
"./BetaProgramHandler": @BetaProgramHandler = {
|
||||
optIn: sinon.stub()
|
||||
},
|
||||
"../User/UserLocator": @UserLocator = {
|
||||
findById: sinon.stub()
|
||||
},
|
||||
"settings-sharelatex": @settings = {
|
||||
languages: {}
|
||||
}
|
||||
"logger-sharelatex": @logger = {
|
||||
log: sinon.stub()
|
||||
err: sinon.stub()
|
||||
error: sinon.stub()
|
||||
}
|
||||
@res =
|
||||
send: sinon.stub()
|
||||
redirect: sinon.stub()
|
||||
render: sinon.stub()
|
||||
@next = sinon.stub()
|
||||
|
||||
describe "optIn", ->
|
||||
|
||||
beforeEach ->
|
||||
@BetaProgramHandler.optIn.callsArgWith(1, null)
|
||||
|
||||
it "should redirect to '/beta/opt-in'", () ->
|
||||
@BetaProgramController.optIn @req, @res, @next
|
||||
@res.redirect.callCount.should.equal 1
|
||||
@res.redirect.firstCall.args[0].should.equal "/beta/opt-in"
|
||||
|
||||
it "should not call next with an error", () ->
|
||||
@BetaProgramController.optIn @req, @res, @next
|
||||
@next.callCount.should.equal 0
|
||||
|
||||
it "should not call next with an error", () ->
|
||||
@BetaProgramController.optIn @req, @res, @next
|
||||
@next.callCount.should.equal 0
|
||||
|
||||
it "should call BetaProgramHandler.optIn", () ->
|
||||
@BetaProgramController.optIn @req, @res, @next
|
||||
@BetaProgramHandler.optIn.callCount.should.equal 1
|
||||
|
||||
describe "when BetaProgramHandler.opIn produces an error", ->
|
||||
|
||||
beforeEach ->
|
||||
@BetaProgramHandler.optIn.callsArgWith(1, new Error('woops'))
|
||||
|
||||
it "should not redirect to '/'", () ->
|
||||
@BetaProgramController.optIn @req, @res, @next
|
||||
@res.redirect.callCount.should.equal 0
|
||||
|
||||
it "should produce an error", () ->
|
||||
@BetaProgramController.optIn @req, @res, @next
|
||||
@next.callCount.should.equal 1
|
||||
@next.firstCall.args[0].should.be.instanceof Error
|
||||
|
||||
describe "optInPage", ->
|
||||
|
||||
beforeEach ->
|
||||
@UserLocator.findById.callsArgWith(1, null, @user)
|
||||
|
||||
it "should render the opt-in page", () ->
|
||||
@BetaProgramController.optInPage @req, @res, @next
|
||||
@res.render.callCount.should.equal 1
|
||||
args = @res.render.firstCall.args
|
||||
args[0].should.equal 'beta_program/opt_in'
|
||||
|
||||
|
||||
describe "when UserLocator.findById produces an error", ->
|
||||
|
||||
beforeEach ->
|
||||
@UserLocator.findById.callsArgWith(1, new Error('woops'))
|
||||
|
||||
it "should not render the opt-in page", () ->
|
||||
@BetaProgramController.optInPage @req, @res, @next
|
||||
@res.render.callCount.should.equal 0
|
||||
|
||||
it "should produce an error", () ->
|
||||
@BetaProgramController.optInPage @req, @res, @next
|
||||
@next.callCount.should.equal 1
|
||||
@next.firstCall.args[0].should.be.instanceof Error
|
|
@ -0,0 +1,65 @@
|
|||
should = require('chai').should()
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
assert = require('assert')
|
||||
path = require('path')
|
||||
modulePath = path.join __dirname, '../../../../app/js/Features/BetaProgram/BetaProgramHandler'
|
||||
sinon = require("sinon")
|
||||
expect = require("chai").expect
|
||||
|
||||
|
||||
describe 'BetaProgramHandler', ->
|
||||
|
||||
beforeEach ->
|
||||
@user_id = "some_id"
|
||||
@user =
|
||||
_id: @user_id
|
||||
email: 'user@example.com'
|
||||
features: {}
|
||||
betaProgram: false
|
||||
save: sinon.stub().callsArgWith(0, null)
|
||||
@handler = SandboxedModule.require modulePath, requires:
|
||||
"../../models/User": {
|
||||
User:
|
||||
findById: sinon.stub().callsArgWith(1, null, @user)
|
||||
},
|
||||
"logger-sharelatex": @logger = {
|
||||
log: sinon.stub()
|
||||
err: sinon.stub()
|
||||
},
|
||||
"../../infrastructure/Metrics": @logger = {
|
||||
inc: sinon.stub()
|
||||
}
|
||||
|
||||
|
||||
describe "optIn", ->
|
||||
|
||||
beforeEach ->
|
||||
@call = (callback) =>
|
||||
@handler.optIn @user_id, callback
|
||||
|
||||
it "should set betaProgram = true on user object", (done) ->
|
||||
@call (err) =>
|
||||
@user.betaProgram.should.equal true
|
||||
done()
|
||||
|
||||
it "should call user.save", (done) ->
|
||||
@call (err) =>
|
||||
@user.save.callCount.should.equal 1
|
||||
done()
|
||||
|
||||
it "should not produce an error", (done) ->
|
||||
@call (err) =>
|
||||
expect(err).to.equal null
|
||||
expect(err).to.not.be.instanceof Error
|
||||
done()
|
||||
|
||||
describe "when user.save produces an error", ->
|
||||
|
||||
beforeEach ->
|
||||
@user.save.callsArgWith(0, new Error('woops'))
|
||||
|
||||
it "should produce an error", (done) ->
|
||||
@call (err) =>
|
||||
expect(err).to.not.equal null
|
||||
expect(err).to.be.instanceof Error
|
||||
done()
|
Loading…
Reference in a new issue