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
bf38fb7459
44 changed files with 30 additions and 1700 deletions
|
@ -1,81 +0,0 @@
|
||||||
request = require('request')
|
|
||||||
settings = require('settings-sharelatex')
|
|
||||||
logger = require('logger-sharelatex')
|
|
||||||
Project = require('../../models/Project').Project
|
|
||||||
projectEntityHandler = require '../Project/ProjectEntityHandler'
|
|
||||||
_ = require('underscore')
|
|
||||||
async = require('async')
|
|
||||||
|
|
||||||
module.exports =
|
|
||||||
|
|
||||||
getUserRegistrationStatus: (user_id, callback)->
|
|
||||||
logger.log user_id:user_id, "getting dropbox registration status from tpds"
|
|
||||||
opts =
|
|
||||||
url : "#{settings.apis.thirdPartyDataStore.url}/user/#{user_id}/dropbox/status"
|
|
||||||
timeout: 5000
|
|
||||||
request.get opts, (err, response, body)->
|
|
||||||
safelyGetResponse err, response, body, (err, body)->
|
|
||||||
if err?
|
|
||||||
logger.err err:err, response:response, "getUserRegistrationStatus problem"
|
|
||||||
return callback err
|
|
||||||
logger.log status:body, "getting dropbox registration status for user #{user_id}"
|
|
||||||
callback err, body
|
|
||||||
|
|
||||||
getDropboxRegisterUrl: (user_id, callback)->
|
|
||||||
opts =
|
|
||||||
url: "#{settings.apis.thirdPartyDataStore.url}/user/#{user_id}/dropbox/register"
|
|
||||||
timeout: 5000
|
|
||||||
request.get opts, (err, response, body)->
|
|
||||||
safelyGetResponse err, response, body, (err, body)->
|
|
||||||
if err?
|
|
||||||
logger.err err:err, response:response, "getUserRegistrationStatus problem"
|
|
||||||
return callback err
|
|
||||||
url = "#{body.authorize_url}&oauth_callback=#{settings.siteUrl}/dropbox/completeRegistration"
|
|
||||||
logger.log user_id:user_id, url:url, "starting dropbox register"
|
|
||||||
callback err, url
|
|
||||||
|
|
||||||
completeRegistration: (user_id, callback)->
|
|
||||||
opts =
|
|
||||||
url: "#{settings.apis.thirdPartyDataStore.url}/user/#{user_id}/dropbox/getaccesstoken"
|
|
||||||
timeout: 5000
|
|
||||||
request.get opts, (err, response, body)=>
|
|
||||||
safelyGetResponse err, response, body, (err, body)=>
|
|
||||||
if err?
|
|
||||||
logger.err err:err, response:response, "getUserRegistrationStatus problem"
|
|
||||||
return callback err
|
|
||||||
success = body.success
|
|
||||||
logger.log user_id:user_id, success:body.success, "completing dropbox register"
|
|
||||||
if success
|
|
||||||
@flushUsersProjectToDropbox user_id
|
|
||||||
callback err, body.success
|
|
||||||
|
|
||||||
|
|
||||||
unlinkAccount: (user_id, callback)->
|
|
||||||
opts =
|
|
||||||
url: "#{settings.apis.thirdPartyDataStore.url}/user/#{user_id}/dropbox"
|
|
||||||
timeout: 5000
|
|
||||||
request.del opts, (err, response, body)=>
|
|
||||||
callback(err)
|
|
||||||
|
|
||||||
flushUsersProjectToDropbox: (user_id, callback)->
|
|
||||||
Project.findAllUsersProjects user_id, '_id', (err, projects = [], collabertions = [], readOnlyProjects = [])->
|
|
||||||
projectList = []
|
|
||||||
projectList = projectList.concat(projects)
|
|
||||||
projectList = projectList.concat(collabertions)
|
|
||||||
projectList = projectList.concat(readOnlyProjects)
|
|
||||||
projectIds = _.pluck(projectList, "_id")
|
|
||||||
logger.log projectIds:projectIds, user_id:user_id, "flushing all a users projects to tpds"
|
|
||||||
jobs = projectIds.map (project_id)->
|
|
||||||
return (cb)->
|
|
||||||
projectEntityHandler.flushProjectToThirdPartyDataStore project_id, cb
|
|
||||||
async.series jobs, callback
|
|
||||||
|
|
||||||
safelyGetResponse = (err, res, body, callback)->
|
|
||||||
statusCode = if res? then res.statusCode else 500
|
|
||||||
if err? or statusCode != 200
|
|
||||||
e = new Error("something went wrong getting response from dropbox, #{err}, #{statusCode}")
|
|
||||||
logger.err err:err
|
|
||||||
callback(e, [])
|
|
||||||
else
|
|
||||||
body = JSON.parse body
|
|
||||||
callback(null, body)
|
|
|
@ -1,12 +0,0 @@
|
||||||
DropboxHandler = require "./DropboxHandler"
|
|
||||||
ProjectGetter = require "../Project/ProjectGetter"
|
|
||||||
|
|
||||||
module.exports = DropboxProjectController =
|
|
||||||
getStatus: (req, res, next) ->
|
|
||||||
project_id = req.params.Project_id
|
|
||||||
ProjectGetter.getProject project_id, {owner_ref: 1}, (error, project) ->
|
|
||||||
return next(error) if error?
|
|
||||||
DropboxHandler.getUserRegistrationStatus project.owner_ref, (error, status) ->
|
|
||||||
return next(error) if error?
|
|
||||||
res.json status
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
DropboxUserController = require './DropboxUserController'
|
|
||||||
DropboxWebhookController = require './DropboxWebhookController'
|
|
||||||
DropboxProjectController = require "./DropboxProjectController"
|
|
||||||
SecurityManager = require "../../managers/SecurityManager"
|
|
||||||
|
|
||||||
module.exports =
|
|
||||||
apply: (app) ->
|
|
||||||
app.get '/dropbox/beginAuth', DropboxUserController.redirectUserToDropboxAuth
|
|
||||||
app.get '/dropbox/completeRegistration', DropboxUserController.completeDropboxRegistration
|
|
||||||
app.get '/dropbox/unlink', DropboxUserController.unlinkDropbox
|
|
||||||
|
|
||||||
app.get '/dropbox/webhook', DropboxWebhookController.verify
|
|
||||||
app.post '/dropbox/webhook', DropboxWebhookController.webhook
|
|
||||||
app.ignoreCsrf('post', '/dropbox/webhook')
|
|
||||||
|
|
||||||
app.get '/project/:Project_id/dropbox/status', SecurityManager.requestIsOwner, DropboxProjectController.getStatus
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
dropboxHandler = require('./DropboxHandler')
|
|
||||||
logger = require('logger-sharelatex')
|
|
||||||
|
|
||||||
|
|
||||||
module.exports =
|
|
||||||
|
|
||||||
redirectUserToDropboxAuth: (req, res, next)->
|
|
||||||
user_id = req.session.user._id
|
|
||||||
dropboxHandler.getDropboxRegisterUrl user_id, (err, url)->
|
|
||||||
return next(err) if err?
|
|
||||||
logger.log url:url, "redirecting user for dropbox auth"
|
|
||||||
res.redirect url
|
|
||||||
|
|
||||||
completeDropboxRegistration: (req, res, next)->
|
|
||||||
user_id = req.session.user._id
|
|
||||||
dropboxHandler.completeRegistration user_id, (err, success)->
|
|
||||||
return next(err) if err?
|
|
||||||
res.redirect('/user/settings#dropboxSettings')
|
|
||||||
|
|
||||||
unlinkDropbox: (req, res, next)->
|
|
||||||
user_id = req.session.user._id
|
|
||||||
dropboxHandler.unlinkAccount user_id, (err, success)->
|
|
||||||
return next(err) if err?
|
|
||||||
res.redirect('/user/settings#dropboxSettings')
|
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
logger = require("logger-sharelatex")
|
|
||||||
DropboxWebhookHandler = require("./DropboxWebhookHandler")
|
|
||||||
|
|
||||||
module.exports = DropboxWebhookController =
|
|
||||||
verify: (req, res, next = (error) ->) ->
|
|
||||||
res.send(req.query.challenge)
|
|
||||||
req.session.destroy()
|
|
||||||
|
|
||||||
webhook: (req, res, next = (error) ->) ->
|
|
||||||
dropbox_uids = req.body?.delta?.users
|
|
||||||
logger.log dropbox_uids: dropbox_uids, "received webhook request from Dropbox"
|
|
||||||
if !dropbox_uids?
|
|
||||||
return res.send(400) # Bad Request
|
|
||||||
|
|
||||||
# Do this in the background so as not to keep Dropbox waiting
|
|
||||||
DropboxWebhookHandler.pollDropboxUids dropbox_uids, (error) ->
|
|
||||||
if error?
|
|
||||||
logger.error err: error, dropbox_uids: dropbox_uids, "error in webhook"
|
|
||||||
|
|
||||||
res.send(200)
|
|
||||||
req.session.destroy()
|
|
|
@ -1,48 +0,0 @@
|
||||||
logger = require("logger-sharelatex")
|
|
||||||
settings = require("settings-sharelatex")
|
|
||||||
async = require "async"
|
|
||||||
User = require("../../models/User").User
|
|
||||||
TpdsUpdateSender = require "../ThirdPartyDataStore/TpdsUpdateSender"
|
|
||||||
|
|
||||||
redis = require("redis-sharelatex")
|
|
||||||
rclient = redis.createClient(settings.redis.web)
|
|
||||||
|
|
||||||
module.exports = DropboxWebhookHandler =
|
|
||||||
pollDropboxUids: (dropbox_uids, callback = (error) ->) ->
|
|
||||||
jobs = []
|
|
||||||
for uid in dropbox_uids
|
|
||||||
do (uid) ->
|
|
||||||
jobs.push (callback) ->
|
|
||||||
DropboxWebhookHandler.pollDropboxUid uid, callback
|
|
||||||
async.series jobs, callback
|
|
||||||
|
|
||||||
pollDropboxUid: (dropbox_uid, callback = (error) ->) ->
|
|
||||||
DropboxWebhookHandler._delayAndBatchPoll dropbox_uid, (error, shouldPoll) ->
|
|
||||||
return callback(error) if error?
|
|
||||||
return callback() if !shouldPoll
|
|
||||||
User.find {
|
|
||||||
"dropbox.access_token.uid": dropbox_uid.toString()
|
|
||||||
"features.dropbox": true
|
|
||||||
}, (error, users = []) ->
|
|
||||||
return callback(error) if error?
|
|
||||||
user = users[0]
|
|
||||||
if !user?
|
|
||||||
logger.log dropbox_uid: dropbox_uid, "no sharelatex user found"
|
|
||||||
return callback()
|
|
||||||
TpdsUpdateSender.pollDropboxForUser user._id, callback
|
|
||||||
|
|
||||||
POLL_DELAY_IN_MS: 5000 # 5 seconds
|
|
||||||
_delayAndBatchPoll: (dropbox_uid, callback = (error, shouldPoll) ->) ->
|
|
||||||
rclient.set(
|
|
||||||
"dropbox-poll-lock:#{dropbox_uid}", "LOCK",
|
|
||||||
"PX", DropboxWebhookHandler.POLL_DELAY_IN_MS,
|
|
||||||
"NX",
|
|
||||||
(error, gotLock) ->
|
|
||||||
return callback(error) if error?
|
|
||||||
if gotLock
|
|
||||||
setTimeout () ->
|
|
||||||
callback(null, true)
|
|
||||||
, DropboxWebhookHandler.POLL_DELAY_IN_MS
|
|
||||||
else
|
|
||||||
callback(null, false)
|
|
||||||
)
|
|
|
@ -151,9 +151,6 @@ module.exports = EditorController =
|
||||||
return {_id:doc._id, path:path.substring(1)}
|
return {_id:doc._id, path:path.substring(1)}
|
||||||
callback(null, docList)
|
callback(null, docList)
|
||||||
|
|
||||||
forceResyncOfDropbox: (project_id, callback)->
|
|
||||||
ProjectEntityHandler.flushProjectToThirdPartyDataStore project_id, callback
|
|
||||||
|
|
||||||
notifyUsersProjectHasBeenDeletedOrRenamed: (project_id, callback)->
|
notifyUsersProjectHasBeenDeletedOrRenamed: (project_id, callback)->
|
||||||
EditorRealTimeController.emitToRoom(project_id, 'projectRenamedOrDeletedByExternalSource')
|
EditorRealTimeController.emitToRoom(project_id, 'projectRenamedOrDeletedByExternalSource')
|
||||||
callback()
|
callback()
|
||||||
|
|
|
@ -6,7 +6,7 @@ logger = require('logger-sharelatex')
|
||||||
SubscriptionUpdater = require("./SubscriptionUpdater")
|
SubscriptionUpdater = require("./SubscriptionUpdater")
|
||||||
LimitationsManager = require('./LimitationsManager')
|
LimitationsManager = require('./LimitationsManager')
|
||||||
EmailHandler = require("../Email/EmailHandler")
|
EmailHandler = require("../Email/EmailHandler")
|
||||||
DropboxHandler = require("../Dropbox/DropboxHandler")
|
Events = require "../../infrastructure/Events"
|
||||||
|
|
||||||
module.exports =
|
module.exports =
|
||||||
|
|
||||||
|
@ -52,8 +52,8 @@ module.exports =
|
||||||
ONE_HOUR_IN_MS = 1000 * 60 * 60
|
ONE_HOUR_IN_MS = 1000 * 60 * 60
|
||||||
setTimeout (-> EmailHandler.sendEmail "canceledSubscription", emailOpts
|
setTimeout (-> EmailHandler.sendEmail "canceledSubscription", emailOpts
|
||||||
), ONE_HOUR_IN_MS
|
), ONE_HOUR_IN_MS
|
||||||
DropboxHandler.unlinkAccount user._id, ->
|
Events.emit "cancelSubscription", user._id
|
||||||
callback()
|
callback()
|
||||||
else
|
else
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
path = require('path')
|
|
||||||
ProjectUploadManager = require('../Uploads/ProjectUploadManager')
|
|
||||||
ProjectOptionsHandler = require("../Project/ProjectOptionsHandler")
|
|
||||||
ProjectDetailsHandler = require('../Project/ProjectDetailsHandler')
|
|
||||||
ProjectGetter = require('../Project/ProjectGetter')
|
|
||||||
EditorController = require('../Editor/EditorController')
|
|
||||||
TemplatesPublisher = require("./TemplatesPublisher")
|
|
||||||
settings = require('settings-sharelatex')
|
|
||||||
fs = require('fs')
|
|
||||||
request = require('request')
|
|
||||||
uuid = require('node-uuid')
|
|
||||||
logger = require('logger-sharelatex')
|
|
||||||
async = require("async")
|
|
||||||
|
|
||||||
|
|
||||||
module.exports =
|
|
||||||
|
|
||||||
createProjectFromZipTemplate: (req, res)->
|
|
||||||
logger.log body:req.session.templateData, "creating project from zip"
|
|
||||||
if !req.session.templateData?
|
|
||||||
return res.redirect "/project"
|
|
||||||
|
|
||||||
dumpPath = "#{settings.path.dumpFolder}/#{uuid.v4()}"
|
|
||||||
writeStream = fs.createWriteStream(dumpPath)
|
|
||||||
zipUrl = req.session.templateData.zipUrl
|
|
||||||
if zipUrl.slice(0,12).indexOf("templates") == -1
|
|
||||||
zipUrl = "#{settings.apis.web.url}#{zipUrl}"
|
|
||||||
else
|
|
||||||
zipUrl = "#{settings.apis.templates.url}#{zipUrl}"
|
|
||||||
zipReq = request(zipUrl)
|
|
||||||
zipReq.on "error", (error) ->
|
|
||||||
logger.error err: error, "error getting zip from template API"
|
|
||||||
zipReq.pipe(writeStream)
|
|
||||||
writeStream.on 'close', ->
|
|
||||||
ProjectUploadManager.createProjectFromZipArchive req.session.user._id, req.session.templateData.templateName, dumpPath, (err, project)->
|
|
||||||
if err?
|
|
||||||
logger.err err:err, zipUrl:zipUrl, "problem building project from zip"
|
|
||||||
return res.send 500
|
|
||||||
setCompiler project._id, req.session.templateData.compiler, ->
|
|
||||||
fs.unlink dumpPath, ->
|
|
||||||
delete req.session.templateData
|
|
||||||
res.redirect "/project/#{project._id}"
|
|
||||||
|
|
||||||
publishProject: (req, res, next) ->
|
|
||||||
project_id = req.params.Project_id
|
|
||||||
ProjectGetter.getProject project_id, {owner_ref: 1}, (error, project) ->
|
|
||||||
return callback(error) if error?
|
|
||||||
user_id = project.owner_ref.toString()
|
|
||||||
logger.log user_id:user_id, project_id:project_id, "receiving request to publish project as template"
|
|
||||||
TemplatesPublisher.publish user_id, project_id, (error) ->
|
|
||||||
return next(error) if error?
|
|
||||||
res.send 204
|
|
||||||
|
|
||||||
unpublishProject: (req, res, next) ->
|
|
||||||
project_id = req.params.Project_id
|
|
||||||
ProjectGetter.getProject project_id, {owner_ref: 1}, (error, project) ->
|
|
||||||
return callback(error) if error?
|
|
||||||
user_id = project.owner_ref.toString()
|
|
||||||
logger.log user_id:user_id, project_id:project_id, "receiving request to unpublish project"
|
|
||||||
TemplatesPublisher.unpublish user_id, project_id, (error) ->
|
|
||||||
return next(error) if error?
|
|
||||||
res.send 204
|
|
||||||
|
|
||||||
updateProjectDescription: (req, res, next) ->
|
|
||||||
project_id = req.params.Project_id
|
|
||||||
{description} = req.body
|
|
||||||
EditorController.updateProjectDescription project_id, description, (error) ->
|
|
||||||
return next(error) if error?
|
|
||||||
res.send 204
|
|
||||||
|
|
||||||
getTemplateDetails: (req, res, next)->
|
|
||||||
project_id = req.params.Project_id
|
|
||||||
ProjectGetter.getProject project_id, {owner_ref: 1}, (error, project) ->
|
|
||||||
return next(error) if error?
|
|
||||||
user_id = project.owner_ref.toString()
|
|
||||||
async.parallel {
|
|
||||||
details: (cb)->
|
|
||||||
TemplatesPublisher.getTemplateDetails user_id, project_id, cb
|
|
||||||
description: (cb)->
|
|
||||||
ProjectDetailsHandler.getProjectDescription project_id, cb
|
|
||||||
}, (err, results)->
|
|
||||||
if err?
|
|
||||||
logger.err err:err, user_id:user_id, project_id:project_id, "something went wrong getting template details"
|
|
||||||
return next(err)
|
|
||||||
details = results.details
|
|
||||||
details.description = results.description
|
|
||||||
res.json details
|
|
||||||
|
|
||||||
setCompiler = (project_id, compiler, callback)->
|
|
||||||
if compiler?
|
|
||||||
ProjectOptionsHandler.setCompiler project_id, compiler, callback
|
|
||||||
else
|
|
||||||
callback()
|
|
|
@ -1,25 +0,0 @@
|
||||||
settings = require("settings-sharelatex")
|
|
||||||
logger = require("logger-sharelatex")
|
|
||||||
|
|
||||||
|
|
||||||
module.exports =
|
|
||||||
saveTemplateDataInSession: (req, res, next)->
|
|
||||||
if req.query.templateName
|
|
||||||
req.session.templateData = req.query
|
|
||||||
next()
|
|
||||||
|
|
||||||
id_or_tag_parse: (req, res, next)->
|
|
||||||
tag_or_template_id = req.params.tag_or_template_id
|
|
||||||
if _isObjectId(tag_or_template_id)
|
|
||||||
req.params.template_id = tag_or_template_id
|
|
||||||
else
|
|
||||||
req.params.tag_name = tag_or_template_id
|
|
||||||
next()
|
|
||||||
|
|
||||||
_isObjectId: _isObjectId = (tag_or_id)->
|
|
||||||
checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$")
|
|
||||||
checkForHexRegExp.test(tag_or_id)
|
|
||||||
|
|
||||||
insert_templates_user_id: (req, res, next)->
|
|
||||||
req.params.user_id = settings.templates.user_id
|
|
||||||
next()
|
|
|
@ -1,36 +0,0 @@
|
||||||
request = require("request")
|
|
||||||
settings = require("settings-sharelatex")
|
|
||||||
logger = require("logger-sharelatex")
|
|
||||||
|
|
||||||
module.exports =
|
|
||||||
|
|
||||||
publish : (user_id, project_id, callback)->
|
|
||||||
url = buildUrl(user_id, project_id)
|
|
||||||
request.post url, (err)->
|
|
||||||
if err?
|
|
||||||
logger.err err:err, "something went wrong publishing project as template"
|
|
||||||
callback err
|
|
||||||
|
|
||||||
unpublish: (user_id, project_id, callback)->
|
|
||||||
url = buildUrl(user_id, project_id)
|
|
||||||
request.del url, (err)->
|
|
||||||
callback()
|
|
||||||
|
|
||||||
|
|
||||||
getTemplateDetails: (user_id, project_id, callback)->
|
|
||||||
url = buildUrl(user_id, project_id)+"/details"
|
|
||||||
request.get url, (err, res, body)->
|
|
||||||
if err?
|
|
||||||
logger.err err:err, user_id:user_id, project_id:project_id, body:body, "error getting template details"
|
|
||||||
return callback err
|
|
||||||
try
|
|
||||||
json = JSON.parse body
|
|
||||||
catch err
|
|
||||||
logger.err err:err, user_id:user_id, project_id:project_id, body:body, "error parsing project json details"
|
|
||||||
return callback err
|
|
||||||
logger.log json:json, user_id:user_id, project_id:project_id, "got template details"
|
|
||||||
callback(err, json)
|
|
||||||
|
|
||||||
|
|
||||||
buildUrl = (user_id, project_id)->
|
|
||||||
url = "#{settings.apis.templates.url}/templates/user/#{user_id}/project/#{project_id}"
|
|
|
@ -1,30 +0,0 @@
|
||||||
SecurityManager = require("../../managers/SecurityManager")
|
|
||||||
AuthenticationController = require("../Authentication/AuthenticationController")
|
|
||||||
TemplatesWebController = require("./TemplatesWebController")
|
|
||||||
TemplatesController = require("./TemplatesController")
|
|
||||||
TemplatesMiddlewear = require('./TemplatesMiddlewear')
|
|
||||||
middleWear = require("./TemplatesMiddlewear")
|
|
||||||
|
|
||||||
module.exports =
|
|
||||||
apply: (app)->
|
|
||||||
|
|
||||||
app.get "/templates", middleWear.insert_templates_user_id, TemplatesWebController.renderTemplatesIndexPage
|
|
||||||
app.get "/templates/user/:user_id", TemplatesWebController.renderTemplatesIndexPage
|
|
||||||
|
|
||||||
app.get "/templates/:tag_or_template_id", middleWear.id_or_tag_parse, middleWear.insert_templates_user_id, TemplatesWebController.tagOrCanonicalPage
|
|
||||||
app.get "/templates/user/:user_id/:tag_or_template_id", middleWear.id_or_tag_parse, TemplatesWebController.tagOrCanonicalPage
|
|
||||||
|
|
||||||
app.get "/templates/:tag_name/:template_name", middleWear.insert_templates_user_id, TemplatesWebController.renerTemplateInTag
|
|
||||||
app.get "/templates/user/:user_id/:tag_name/:template_name", TemplatesWebController.renerTemplateInTag
|
|
||||||
|
|
||||||
app.get "/templates/:template_id/v/:version/:file_type", TemplatesWebController.proxyToTemplatesApi
|
|
||||||
|
|
||||||
app.post "/project/:Project_id/template/publish", SecurityManager.requestIsOwner, TemplatesController.publishProject
|
|
||||||
app.post "/project/:Project_id/template/unpublish", SecurityManager.requestIsOwner, TemplatesController.unpublishProject
|
|
||||||
app.post "/project/:Project_id/template/description", SecurityManager.requestCanModifyProject, TemplatesController.updateProjectDescription
|
|
||||||
|
|
||||||
# Make sure the /project/new/template route comes before the /project/:project_id/template route
|
|
||||||
# This is a get request so that it can be linked to.
|
|
||||||
app.get '/project/new/template', TemplatesMiddlewear.saveTemplateDataInSession, AuthenticationController.requireLogin(), TemplatesController.createProjectFromZipTemplate
|
|
||||||
|
|
||||||
app.get "/project/:Project_id/template", SecurityManager.requestCanAccessProject, TemplatesController.getTemplateDetails
|
|
|
@ -1,102 +0,0 @@
|
||||||
request = require("request")
|
|
||||||
settings = require("settings-sharelatex")
|
|
||||||
logger = require("logger-sharelatex")
|
|
||||||
ErrorController = require("../Errors/ErrorController")
|
|
||||||
|
|
||||||
module.exports = TemplatesWebController =
|
|
||||||
|
|
||||||
renderTemplatesIndexPage: (req, res)->
|
|
||||||
logger.log "rendering index page of templates"
|
|
||||||
TemplatesWebController._getDataFromTemplatesApi "/user/#{req.params.user_id}", (err, data)->
|
|
||||||
if err? or !data?
|
|
||||||
logger.err err:err, "something went wrong in renderTemplatesIndexPage"
|
|
||||||
return res.send 500
|
|
||||||
data.title = "latex_templates"
|
|
||||||
res.render "templates/index", data
|
|
||||||
|
|
||||||
renerTemplateInTag: (req, res)->
|
|
||||||
{user_id, tag_name, template_name} = req.params
|
|
||||||
logger.log user_id:user_id, tag_name:tag_name, template_name:template_name, "rendering latex template page"
|
|
||||||
TemplatesWebController._getDataFromTemplatesApi "/user/#{user_id}/tag/#{tag_name}/template/#{template_name}", (err, data)->
|
|
||||||
if err? and err == 404
|
|
||||||
return ErrorController.notFound req, res
|
|
||||||
if err? or !data?
|
|
||||||
logger.err err:err, user_id:user_id, tag_name:tag_name, template_name:template_name, "something went wrong in renerTemplateInTag"
|
|
||||||
return res.send 500
|
|
||||||
data.title = data?.template?.name
|
|
||||||
res.render "templates/template", data
|
|
||||||
|
|
||||||
tagOrCanonicalPage: (req, res)->
|
|
||||||
if req.params.template_id?
|
|
||||||
TemplatesWebController._renderCanonicalPage(req, res)
|
|
||||||
else if req.params.tag_name?.toLowerCase() == "all"
|
|
||||||
TemplatesWebController._renderAllTemplatesPage(req, res)
|
|
||||||
else if req.params.tag_name?
|
|
||||||
TemplatesWebController._renderTagPage(req, res)
|
|
||||||
else
|
|
||||||
logger.log params:req.params, "problem rendering tagOrCanonicalPage"
|
|
||||||
res.send 500
|
|
||||||
|
|
||||||
proxyToTemplatesApi: (req, res)->
|
|
||||||
url = req.url
|
|
||||||
|
|
||||||
name = req.query.name or "Template"
|
|
||||||
if req.query.inline?
|
|
||||||
disposition = "inline"
|
|
||||||
else
|
|
||||||
disposition = "attachment"
|
|
||||||
res.header({"content-disposition": "#{disposition}; filename=\"#{name.replace("\"", "-")}.#{req.params.file_type}\""})
|
|
||||||
|
|
||||||
logger.log url:url, template_name: name, disposition: disposition, "proxying request to templates api"
|
|
||||||
|
|
||||||
getReq = request.get("#{settings.apis.templates.url}#{url}")
|
|
||||||
getReq.pipe(res)
|
|
||||||
getReq.on "error", (error) ->
|
|
||||||
logger.error err: error, "templates proxy API error"
|
|
||||||
res.send 500
|
|
||||||
|
|
||||||
_renderCanonicalPage: (req, res)->
|
|
||||||
{user_id, template_id} = req.params
|
|
||||||
logger.log user_id:user_id, template_id:template_id, "rendering template page"
|
|
||||||
TemplatesWebController._getDataFromTemplatesApi "/user/#{user_id}/template/#{template_id}", (err, data)->
|
|
||||||
if err? and err == 404
|
|
||||||
return ErrorController.notFound req, res
|
|
||||||
if err?
|
|
||||||
logger.err err:err, user_id:user_id, template_id:template_id, "something went wrong in _renderCanonicalPage"
|
|
||||||
return res.send 500
|
|
||||||
data.title = data?.template?.name
|
|
||||||
data.tag = null
|
|
||||||
res.render "templates/template", data
|
|
||||||
|
|
||||||
_renderAllTemplatesPage: (req, res)->
|
|
||||||
{user_id} = req.params
|
|
||||||
logger.log user_id:user_id, "rendering all templates page"
|
|
||||||
TemplatesWebController._getDataFromTemplatesApi "/user/#{user_id}/all", (err, data)->
|
|
||||||
if err? and err == 404
|
|
||||||
return ErrorController.notFound req, res
|
|
||||||
if err?
|
|
||||||
logger.err err:err, user_id:user_id, "something went wrong in _renderCanonicalPage"
|
|
||||||
return res.send 500
|
|
||||||
data.title = "all_templates"
|
|
||||||
res.render "templates/tag", data
|
|
||||||
|
|
||||||
_renderTagPage: (req, res)->
|
|
||||||
{user_id, tag_name} = req.params
|
|
||||||
logger.log user_id:user_id, tag_name:tag_name, "rendinging tag page for templates"
|
|
||||||
TemplatesWebController._getDataFromTemplatesApi "/user/#{user_id}/tag/#{tag_name}", (err, data)->
|
|
||||||
if err? and err == 404
|
|
||||||
return ErrorController.notFound req, res
|
|
||||||
if err?
|
|
||||||
logger.err err:err, user_id:user_id, tag_name:tag_name, "something went wrong in _renderCanonicalPage"
|
|
||||||
return res.send 500
|
|
||||||
data.title = data?.tag?.name
|
|
||||||
res.render "templates/tag", data
|
|
||||||
|
|
||||||
_getDataFromTemplatesApi: (path, callback)->
|
|
||||||
opts =
|
|
||||||
url: "#{settings.apis.templates.url}#{path}"
|
|
||||||
json:true
|
|
||||||
request.get opts, (err, response, data)->
|
|
||||||
if response.statusCode == 404
|
|
||||||
return callback 404
|
|
||||||
callback err, data
|
|
|
@ -1,5 +1,4 @@
|
||||||
UserLocator = require("./UserLocator")
|
UserLocator = require("./UserLocator")
|
||||||
dropboxHandler = require('../Dropbox/DropboxHandler')
|
|
||||||
logger = require("logger-sharelatex")
|
logger = require("logger-sharelatex")
|
||||||
Settings = require("settings-sharelatex")
|
Settings = require("settings-sharelatex")
|
||||||
fs = require('fs')
|
fs = require('fs')
|
||||||
|
@ -27,14 +26,12 @@ module.exports =
|
||||||
title: 'login',
|
title: 'login',
|
||||||
redir: req.query.redir
|
redir: req.query.redir
|
||||||
|
|
||||||
settingsPage : (req, res)->
|
settingsPage : (req, res, next)->
|
||||||
logger.log user: req.session.user, "loading settings page"
|
logger.log user: req.session.user, "loading settings page"
|
||||||
UserLocator.findById req.session.user._id, (err, user)->
|
UserLocator.findById req.session.user._id, (err, user)->
|
||||||
dropboxHandler.getUserRegistrationStatus user._id, (err, status)->
|
return next(err) if err?
|
||||||
userIsRegisteredWithDropbox = !err? and status.registered
|
res.render 'user/settings',
|
||||||
res.render 'user/settings',
|
title:'account_settings'
|
||||||
title:'account_settings'
|
user: user,
|
||||||
userIsRegisteredWithDropbox: userIsRegisteredWithDropbox
|
languages: Settings.languages,
|
||||||
user: user,
|
accountSettingsTabActive: true
|
||||||
languages: Settings.languages,
|
|
||||||
accountSettingsTabActive: true
|
|
||||||
|
|
2
services/web/app/coffee/infrastructure/Events.coffee
Normal file
2
services/web/app/coffee/infrastructure/Events.coffee
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
events = require "events"
|
||||||
|
module.exports = new events.EventEmitter()
|
|
@ -157,5 +157,6 @@ module.exports = (app)->
|
||||||
if Settings.reloadModuleViewsOnEachRequest
|
if Settings.reloadModuleViewsOnEachRequest
|
||||||
Modules.loadViewIncludes()
|
Modules.loadViewIncludes()
|
||||||
res.locals.moduleIncludes = Modules.moduleIncludes
|
res.locals.moduleIncludes = Modules.moduleIncludes
|
||||||
|
res.locals.moduleIncludesAvailable = Modules.moduleIncludesAvailable
|
||||||
next()
|
next()
|
||||||
|
|
||||||
|
|
|
@ -33,4 +33,7 @@ module.exports = Modules =
|
||||||
html += compiler(locals)
|
html += compiler(locals)
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
moduleIncludesAvailable: (view) ->
|
||||||
|
return (Modules.viewIncludes[view] or []).length > 0
|
||||||
|
|
||||||
Modules.loadModules()
|
Modules.loadModules()
|
|
@ -14,7 +14,6 @@ UploadsRouter = require './Features/Uploads/UploadsRouter'
|
||||||
metrics = require('./infrastructure/Metrics')
|
metrics = require('./infrastructure/Metrics')
|
||||||
ReferalController = require('./Features/Referal/ReferalController')
|
ReferalController = require('./Features/Referal/ReferalController')
|
||||||
ReferalMiddleware = require('./Features/Referal/ReferalMiddleware')
|
ReferalMiddleware = require('./Features/Referal/ReferalMiddleware')
|
||||||
TemplatesRouter = require('./Features/Templates/TemplatesRouter')
|
|
||||||
AuthenticationController = require('./Features/Authentication/AuthenticationController')
|
AuthenticationController = require('./Features/Authentication/AuthenticationController')
|
||||||
TagsController = require("./Features/Tags/TagsController")
|
TagsController = require("./Features/Tags/TagsController")
|
||||||
CollaboratorsRouter = require('./Features/Collaborators/CollaboratorsRouter')
|
CollaboratorsRouter = require('./Features/Collaborators/CollaboratorsRouter')
|
||||||
|
@ -33,8 +32,6 @@ StaticPagesRouter = require("./Features/StaticPages/StaticPagesRouter")
|
||||||
ChatController = require("./Features/Chat/ChatController")
|
ChatController = require("./Features/Chat/ChatController")
|
||||||
BlogController = require("./Features/Blog/BlogController")
|
BlogController = require("./Features/Blog/BlogController")
|
||||||
WikiController = require("./Features/Wiki/WikiController")
|
WikiController = require("./Features/Wiki/WikiController")
|
||||||
DropboxRouter = require "./Features/Dropbox/DropboxRouter"
|
|
||||||
dropboxHandler = require "./Features/Dropbox/DropboxHandler"
|
|
||||||
Modules = require "./infrastructure/Modules"
|
Modules = require "./infrastructure/Modules"
|
||||||
RateLimiterMiddlewear = require('./Features/Security/RateLimiterMiddlewear')
|
RateLimiterMiddlewear = require('./Features/Security/RateLimiterMiddlewear')
|
||||||
|
|
||||||
|
@ -65,8 +62,6 @@ module.exports = class Router
|
||||||
UploadsRouter.apply(app)
|
UploadsRouter.apply(app)
|
||||||
PasswordResetRouter.apply(app)
|
PasswordResetRouter.apply(app)
|
||||||
StaticPagesRouter.apply(app)
|
StaticPagesRouter.apply(app)
|
||||||
TemplatesRouter.apply(app)
|
|
||||||
DropboxRouter.apply(app)
|
|
||||||
|
|
||||||
Modules.applyRouter(app)
|
Modules.applyRouter(app)
|
||||||
|
|
||||||
|
@ -190,16 +185,6 @@ module.exports = class Router
|
||||||
), 10000
|
), 10000
|
||||||
req.session.destroy()
|
req.session.destroy()
|
||||||
|
|
||||||
app.get '/test', (req, res) ->
|
|
||||||
res.render "tests",
|
|
||||||
privilegeLevel: "owner"
|
|
||||||
project:
|
|
||||||
name: "test"
|
|
||||||
date: Date.now()
|
|
||||||
layout: false
|
|
||||||
userCanSeeDropbox: true
|
|
||||||
languages: []
|
|
||||||
|
|
||||||
app.get "/ip", (req, res, next) ->
|
app.get "/ip", (req, res, next) ->
|
||||||
res.send({
|
res.send({
|
||||||
ip: req.ip
|
ip: req.ip
|
||||||
|
|
|
@ -56,7 +56,6 @@ block content
|
||||||
include ./editor/binary-file
|
include ./editor/binary-file
|
||||||
include ./editor/track-changes
|
include ./editor/track-changes
|
||||||
include ./editor/publish-template
|
include ./editor/publish-template
|
||||||
include ./editor/dropbox
|
|
||||||
|
|
||||||
.ui-layout-east
|
.ui-layout-east
|
||||||
include ./editor/chat
|
include ./editor/chat
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
script(type="text/ng-template", id="dropboxModalTemplate")
|
|
||||||
.modal-header
|
|
||||||
button.close(
|
|
||||||
type="button"
|
|
||||||
data-dismiss="modal"
|
|
||||||
ng-click="cancel()"
|
|
||||||
) ×
|
|
||||||
h3 #{translate("dropbox_sync")}
|
|
||||||
.modal-body.modal-body-share
|
|
||||||
|
|
||||||
div(ng-show="dbState.gotLinkStatus")
|
|
||||||
div(ng-hide="dbState.userIsLinkedToDropbox || !dbState.hasDropboxFeature")
|
|
||||||
|
|
||||||
span(ng-hide="dbState.startedLinkProcess") #{translate("account_not_linked_to_dropbox")}
|
|
||||||
|
|
|
||||||
a(ng-click="linkToDropbox()").btn.btn-info #{translate("update_dropbox_settings")}
|
|
||||||
|
|
||||||
p.small.text-center(ng-show="dbState.startedLinkProcess")
|
|
||||||
| #{translate("refresh_page_after_starting_free_trial")}
|
|
||||||
|
|
||||||
|
|
||||||
div(ng-show="dbState.hasDropboxFeature && dbState.userIsLinkedToDropbox")
|
|
||||||
p.small
|
|
||||||
| #{translate("this_project_will_appear_in_your_dropbox_folder_at")}
|
|
||||||
strong Dropbox/sharelatex/{{ project.name }}
|
|
||||||
div.text-center(ng-hide="dbState.hasDropboxFeature")
|
|
||||||
p #{translate("need_to_upgrade_for_dropbox")}
|
|
||||||
p(ng-controller="FreeTrialModalController")
|
|
||||||
a.btn(ng-click="startFreeTrial('dropbox')", ng-class="buttonClass") #{translate("start_free_trial")}
|
|
||||||
p.small(ng-show="startedFreeTrial")
|
|
||||||
| #{translate("refresh_page_after_starting_free_trial")}
|
|
||||||
|
|
||||||
div(ng-hide="dbState.gotLinkStatus")
|
|
||||||
i.fa.fa-refresh.fa-spin
|
|
||||||
span.small #{translate("checking_dropbox_status")}
|
|
||||||
|
|
||||||
.modal-footer()
|
|
||||||
button.btn.btn-default(
|
|
||||||
ng-click="cancel()",
|
|
||||||
)
|
|
||||||
span #{translate("dismiss")}
|
|
|
@ -41,21 +41,12 @@ aside#left-menu.full-size(
|
||||||
)
|
)
|
||||||
i.fa.fa-fw.fa-copy
|
i.fa.fa-fw.fa-copy
|
||||||
| #{translate("copy_project")}
|
| #{translate("copy_project")}
|
||||||
li(ng-controller="TemplatesController", ng-show="permissions.admin")
|
!{moduleIncludes("editorLeftMenu:actions", locals)}
|
||||||
a(ng-click="openPublishTemplateModal()")
|
|
||||||
i.fa.fa-external-link.fa-fw
|
|
||||||
| #{translate("publish_as_template")}
|
|
||||||
|
|
||||||
div(ng-show="!anonymous")
|
if (moduleIncludesAvailable("editorLeftMenu:sync"))
|
||||||
h4() #{translate("sync")}
|
div(ng-show="!anonymous")
|
||||||
span(ng-controller="DropboxController")
|
h4() #{translate("sync")}
|
||||||
ul.list-unstyled.nav()
|
!{moduleIncludes("editorLeftMenu:sync", locals)}
|
||||||
li
|
|
||||||
a(ng-click="openDropboxModal()")
|
|
||||||
i.fa.fa-dropbox.fa-fw
|
|
||||||
| Dropbox
|
|
||||||
|
|
||||||
!{moduleIncludes("editorLeftMenu", locals)}
|
|
||||||
|
|
||||||
h4(ng-show="!anonymous") #{translate("settings")}
|
h4(ng-show="!anonymous") #{translate("settings")}
|
||||||
form.settings(ng-controller="SettingsController", ng-show="!anonymous")
|
form.settings(ng-controller="SettingsController", ng-show="!anonymous")
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
extends ../layout
|
|
||||||
|
|
||||||
block vars
|
|
||||||
- var meta = "Over 400 LaTeX templates for journal articles, theses, CV and resumes, posters, presentations, and much more"
|
|
||||||
|
|
||||||
block content
|
|
||||||
.content.content-alt
|
|
||||||
.container
|
|
||||||
.row.template-page-header(ng-controller="SearchController")
|
|
||||||
|
|
||||||
.col-md-2
|
|
||||||
h2
|
|
||||||
a(href="/templates") #{translate("templates")}
|
|
||||||
.col-md-8
|
|
||||||
form.project-search.form-horizontal(role="form")
|
|
||||||
.form-group.has-feedback.has-feedback-left.col-md-12
|
|
||||||
input.form-control.col-md-12(type='text', ng-model='searchQueryText', ng-keyup='search()', placeholder="Search template library....")
|
|
||||||
i.fa.fa-search.form-control-feedback-left
|
|
||||||
i.fa.fa-times.form-control-feedback(
|
|
||||||
ng-click="clearSearchText()",
|
|
||||||
style="cursor: pointer;",
|
|
||||||
ng-show="searchQueryText.length > 0"
|
|
||||||
)
|
|
||||||
.col-md-2(ng-controller="MissingTemplateController")
|
|
||||||
a.btn.btn-primary(ng-click="showMissingTemplateModal()") #{translate("missing_template_question")}
|
|
||||||
.col-md-8(ng-cloak)
|
|
||||||
ul.list-unstyled
|
|
||||||
li(ng-repeat='hit in hits')
|
|
||||||
.thumbnail.searchResult
|
|
||||||
.row
|
|
||||||
a(ng-href='{{hit.url}}')
|
|
||||||
.col-md-3
|
|
||||||
img(ng-src='{{hit.image_url}}')
|
|
||||||
.col-md-7
|
|
||||||
h1(ng-bind-html='hit.name')
|
|
||||||
p(ng-bind-html='hit.description')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.row
|
|
||||||
-each tag in tags
|
|
||||||
-if(tag.totalNumberOfTemplates > 0)
|
|
||||||
.template-section-header.col-md-12
|
|
||||||
h2
|
|
||||||
a(href=tag.tagPagePath) #{tag.name}
|
|
||||||
.row
|
|
||||||
-each template in tag.exampleTemplates
|
|
||||||
.col-md-3.template-thumbnail
|
|
||||||
a(href=template.templatePagePath ? template.templatePagePath : template.canonicalUrl).thumbnail
|
|
||||||
img(src=template.thumbnailUrl)
|
|
||||||
div.caption
|
|
||||||
h3.txt-middle #{template.name}
|
|
||||||
|
|
||||||
-if(tag.totalNumberOfTemplates > 4)
|
|
||||||
.row
|
|
||||||
.col-md-12.text-center
|
|
||||||
a(href=tag.tagPagePath) View all #{tag.totalNumberOfTemplates} #{tag.name} templates »
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
script(type="text/ng-template", id="missingTemplateModal")
|
|
||||||
.modal-header
|
|
||||||
button.close(
|
|
||||||
type="button"
|
|
||||||
data-dismiss="modal"
|
|
||||||
ng-click="cancel()"
|
|
||||||
) ×
|
|
||||||
h3 #{translate("missing_template_question")}
|
|
||||||
.modal-body #{translate("tell_us_about_the_template")}
|
|
||||||
.modal-footer
|
|
||||||
button.btn.btn-default(
|
|
||||||
ng-click="cancel()",
|
|
||||||
)
|
|
||||||
span #{translate("dismiss")}
|
|
||||||
a.btn.btn-primary(href='mailto:team@sharelatex.com?Subject=template') #{translate("email_us")}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
extends ../layout
|
|
||||||
|
|
||||||
mixin template(template)
|
|
||||||
.template-thumbnail
|
|
||||||
a(href=template.templatePagePath ? template.templatePagePath : template.canonicalUrl).thumbnail
|
|
||||||
img(src=template.thumbnailUrl)
|
|
||||||
div.caption
|
|
||||||
h3 #{template.name}
|
|
||||||
|
|
||||||
block content
|
|
||||||
.content.content-alt
|
|
||||||
.container
|
|
||||||
.row
|
|
||||||
.page-header
|
|
||||||
h2
|
|
||||||
a(href="/templates") #{translate("templates")}
|
|
||||||
| ›
|
|
||||||
a(href=tag.tagPagePath) #{tag.name}
|
|
||||||
- for (var row = 0; row <= Math.floor(templates.length / 4); row++)
|
|
||||||
.row
|
|
||||||
- for (var column = 0; column < 4; column++)
|
|
||||||
- if (templates[row*4 + column])
|
|
||||||
.col-md-3
|
|
||||||
+template(templates[row*4 + column])
|
|
||||||
//- -each template in templates
|
|
||||||
//- a(href=template.templatePagePath || template.canonicalUrl)
|
|
||||||
//- .col-md-3.template-thumbnail
|
|
||||||
//- a(href=template.templatePagePath ? template.templatePagePath : template.canonicalUrl).thumbnail
|
|
||||||
//- img(src=template.thumbnailUrl)
|
|
||||||
//- div.caption
|
|
||||||
//- h3 #{template.name}
|
|
|
@ -1,69 +0,0 @@
|
||||||
extends ../layout
|
|
||||||
|
|
||||||
block vars
|
|
||||||
- var meta = template.description
|
|
||||||
- title = title + " - LaTeX Template"
|
|
||||||
|
|
||||||
block content
|
|
||||||
.content.content-alt
|
|
||||||
.container
|
|
||||||
.row
|
|
||||||
.page-header
|
|
||||||
h2
|
|
||||||
a(href="/templates") #{translate("templates")}
|
|
||||||
| ›
|
|
||||||
- if(tag)
|
|
||||||
a(href=tag.tagPagePath) #{tag.name}
|
|
||||||
| ›
|
|
||||||
| #{template.name}
|
|
||||||
.row
|
|
||||||
.col-md-6
|
|
||||||
.entry
|
|
||||||
.row
|
|
||||||
.col-md-12.template-large-pdf-preview
|
|
||||||
a(href="#{template.pdfUrl}?inline=true&name=#{template.name}")
|
|
||||||
img(src="#{template.previewUrl}")
|
|
||||||
|
|
||||||
.col-md-6
|
|
||||||
.template-details-section
|
|
||||||
h3 #{translate("about")}
|
|
||||||
div !{template.description}
|
|
||||||
div(ng-controller="openInSlController", ng-cloak).download-buttons
|
|
||||||
a.btn.btn-primary.btn-large(href=template.open_in_sharelatex_url, ng-click='open()', ng-disabled="isDisabled", rel='nofollow') {{openInSlText}}
|
|
||||||
|
|
|
||||||
|
|
||||||
a.btn.btn-default(
|
|
||||||
href="#{template.zipUrl}?name=#{template.name}",
|
|
||||||
rel='nofollow',
|
|
||||||
ng-click='downloadZip()',
|
|
||||||
tooltip-placement="bottom",
|
|
||||||
tooltip="#{translate('download_zip_file')}"
|
|
||||||
)
|
|
||||||
i.fa.fa-cloud-download
|
|
||||||
.template-details-section.social_buttons
|
|
||||||
.addthis_toolbox.addthis_default_style.addthis_32x32_style
|
|
||||||
a.addthis_button_facebook
|
|
||||||
a.addthis_button_twitter
|
|
||||||
a.addthis_button_google_plusone_share
|
|
||||||
a.addthis_button_compact
|
|
||||||
script(type='text/javascript', src='//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-517c16586439faa7')
|
|
||||||
|
|
||||||
h3 #{translate("comment")}
|
|
||||||
#disqus_thread
|
|
||||||
script(type='text/javascript').
|
|
||||||
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
|
|
||||||
var disqus_shortname = 'sharelatextemplates'; // required: replace example with your forum shortname
|
|
||||||
/* * * DON'T EDIT BELOW THIS LINE * * */
|
|
||||||
(function() {
|
|
||||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
|
||||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
|
||||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
|
||||||
})();
|
|
||||||
noscript
|
|
||||||
| Please enable JavaScript to view the
|
|
||||||
a(href='http://disqus.com/?ref_noscript') comments powered by Disqus.
|
|
||||||
a.dsq-brlink(href='http://disqus.com')
|
|
||||||
| comments powered by
|
|
||||||
span.logo-disqus Disqus
|
|
||||||
|
|
||||||
|
|
|
@ -96,27 +96,6 @@ block content
|
||||||
ng-disabled="changePasswordForm.$invalid"
|
ng-disabled="changePasswordForm.$invalid"
|
||||||
) #{translate("change")}
|
) #{translate("change")}
|
||||||
|
|
||||||
hr
|
|
||||||
|
|
||||||
h3 #{translate("dropbox_integration")}
|
|
||||||
span.small
|
|
||||||
a(href='/help/kb/dropbox-2') (#{translate("learn_more")})
|
|
||||||
- if(!user.features.dropbox)
|
|
||||||
p.small #{translate("dropbox_sync_description")}
|
|
||||||
.alert.alert-info
|
|
||||||
p #{translate("dropbox_is_premium")}
|
|
||||||
p
|
|
||||||
a.btn.btn-info(href='/user/subscription/plans') #{translate("upgrade")}
|
|
||||||
- else if(userIsRegisteredWithDropbox)
|
|
||||||
.alert.alert-success
|
|
||||||
| #{translate("account_is_linked")}.
|
|
||||||
|
|
|
||||||
a(href='/dropbox/unlink') #{translate("unlink_dropbox")}
|
|
||||||
- else
|
|
||||||
p.small #{translate("dropbox_sync_description")}
|
|
||||||
p
|
|
||||||
a.btn.btn-info(href='/dropbox/beginAuth') #{translate("link_to_dropbox")}
|
|
||||||
|
|
||||||
| !{moduleIncludes("userSettings", locals)}
|
| !{moduleIncludes("userSettings", locals)}
|
||||||
|
|
||||||
hr
|
hr
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "web-sharelatex",
|
"name": "web-sharelatex",
|
||||||
"version": "0.1.0",
|
"version": "0.1.2",
|
||||||
"description": "The HTTP front end for ShareLaTeX",
|
"description": "The HTTP front end for ShareLaTeX",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -12,8 +12,6 @@ define [
|
||||||
"ide/share/index"
|
"ide/share/index"
|
||||||
"ide/chat/index"
|
"ide/chat/index"
|
||||||
"ide/clone/index"
|
"ide/clone/index"
|
||||||
"ide/templates/index"
|
|
||||||
"ide/dropbox/index"
|
|
||||||
"ide/hotkeys/index"
|
"ide/hotkeys/index"
|
||||||
"ide/directives/layout"
|
"ide/directives/layout"
|
||||||
"ide/services/ide"
|
"ide/services/ide"
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
define [
|
|
||||||
"base"
|
|
||||||
"ide/permissions/PermissionsManager"
|
|
||||||
], (App, PermissionsManager) ->
|
|
||||||
|
|
||||||
POLLING_INTERVAL = 15
|
|
||||||
ONE_MIN_MILI = 1000 * 60
|
|
||||||
|
|
||||||
cachedState =
|
|
||||||
gotLinkStatus: false
|
|
||||||
startedLinkProcess: false
|
|
||||||
userIsLinkedToDropbox: false
|
|
||||||
hasDropboxFeature: false
|
|
||||||
|
|
||||||
|
|
||||||
App.controller "DropboxController", ($scope, $modal, ide) ->
|
|
||||||
$scope.openDropboxModal = () ->
|
|
||||||
|
|
||||||
$modal.open {
|
|
||||||
templateUrl: "dropboxModalTemplate"
|
|
||||||
controller: "DropboxModalController"
|
|
||||||
scope:$scope
|
|
||||||
}
|
|
||||||
|
|
||||||
App.controller "DropboxModalController", ($scope, $modalInstance, ide, $timeout, $http) ->
|
|
||||||
user_id = ide.$scope.user.id
|
|
||||||
|
|
||||||
$scope.dbState = cachedState
|
|
||||||
$scope.dbState.hasDropboxFeature = $scope.project.features.dropbox
|
|
||||||
|
|
||||||
$http.get("/project/#{ide.project_id}/dropbox/status")
|
|
||||||
.success (status) ->
|
|
||||||
$scope.dbState.gotLinkStatus = true
|
|
||||||
if status.registered
|
|
||||||
$scope.dbState.userIsLinkedToDropbox = true
|
|
||||||
cachedState = $scope.dbState
|
|
||||||
|
|
||||||
$scope.linkToDropbox = ->
|
|
||||||
window.open("/user/settings#dropboxSettings")
|
|
||||||
$scope.startedLinkProcess = true
|
|
||||||
|
|
||||||
$scope.cancel = () ->
|
|
||||||
$modalInstance.dismiss()
|
|
|
@ -1,4 +0,0 @@
|
||||||
define [
|
|
||||||
"ide/dropbox/controllers/DropboxController"
|
|
||||||
], () ->
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ define [
|
||||||
|
|
||||||
timedOut = false
|
timedOut = false
|
||||||
timer = $timeout () =>
|
timer = $timeout () =>
|
||||||
Raven?.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms')
|
Raven?.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms (1% sample)') if Math.random() < 0.01
|
||||||
# console.log 'page load timed out', pagenum
|
# console.log 'page load timed out', pagenum
|
||||||
timedOut = true
|
timedOut = true
|
||||||
clearTimeout(spinTimer)
|
clearTimeout(spinTimer)
|
||||||
|
@ -246,7 +246,7 @@ define [
|
||||||
timedOut = false
|
timedOut = false
|
||||||
|
|
||||||
timer = $timeout () =>
|
timer = $timeout () =>
|
||||||
Raven?.captureMessage?('pdfng page render timed out after ' + @PAGE_RENDER_TIMEOUT + 'ms')
|
Raven?.captureMessage?('pdfng page render timed out after ' + @PAGE_RENDER_TIMEOUT + 'ms (1% sample)') if Math.random() < 0.01
|
||||||
# console.log 'page render timed out', pagenum
|
# console.log 'page render timed out', pagenum
|
||||||
timedOut = true
|
timedOut = true
|
||||||
result.cancel()
|
result.cancel()
|
||||||
|
|
|
@ -38,7 +38,7 @@ define [
|
||||||
loadedCallback: () ->
|
loadedCallback: () ->
|
||||||
$scope.$emit 'loaded'
|
$scope.$emit 'loaded'
|
||||||
errorCallback: (error) ->
|
errorCallback: (error) ->
|
||||||
Raven?.captureMessage?('pdfng error ' + error)
|
Raven?.captureMessage?('pdfng error ' + error + ' (1% sample)') if Math.random() < 0.01
|
||||||
$scope.$emit 'pdf:error', error
|
$scope.$emit 'pdf:error', error
|
||||||
pageSizeChangeCallback: (pageNum, deltaH) ->
|
pageSizeChangeCallback: (pageNum, deltaH) ->
|
||||||
$scope.$broadcast 'pdf:page:size-change', pageNum, deltaH
|
$scope.$broadcast 'pdf:page:size-change', pageNum, deltaH
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
define [
|
|
||||||
"base"
|
|
||||||
"ide/permissions/PermissionsManager"
|
|
||||||
], (App, PermissionsManager) ->
|
|
||||||
|
|
||||||
App.controller "TemplatesController", ($scope, $modal, ide) ->
|
|
||||||
$scope.openPublishTemplateModal = () ->
|
|
||||||
resetState = ->
|
|
||||||
$scope.problemTalkingToTemplateApi = false
|
|
||||||
|
|
||||||
resetState()
|
|
||||||
|
|
||||||
modal = $modal.open {
|
|
||||||
templateUrl: "publishProjectAsTemplateModalTemplate"
|
|
||||||
controller: "PublishProjectAsTemplateModalController"
|
|
||||||
scope:$scope
|
|
||||||
}
|
|
||||||
modal.result.then(resetState, resetState)
|
|
||||||
|
|
||||||
App.controller "PublishProjectAsTemplateModalController", ($scope, $modalInstance, ide, $http) ->
|
|
||||||
user_id = ide.$scope.user.id
|
|
||||||
$scope.templateDetails = {exists:false}
|
|
||||||
|
|
||||||
$scope.state =
|
|
||||||
publishInflight: false
|
|
||||||
unpublishInflight: false
|
|
||||||
|
|
||||||
problemTalkingToTemplateApi = ->
|
|
||||||
$scope.problemTalkingToTemplateApi = true
|
|
||||||
|
|
||||||
refreshPublishedStatus = ->
|
|
||||||
$http.get("/project/#{ide.project_id}/template")
|
|
||||||
.success (data) ->
|
|
||||||
$scope.templateDetails = data
|
|
||||||
$scope.templateDetails.publishedDate = moment(data.publishedDate).format("Do MMM YYYY, h:mm a")
|
|
||||||
$scope.templateDetails.description = data.description
|
|
||||||
.error () ->
|
|
||||||
problemTalkingToTemplateApi()
|
|
||||||
|
|
||||||
refreshPublishedStatus()
|
|
||||||
$scope.$watch $scope.problemTalkingToTemplateApi, (value) ->
|
|
||||||
if value?
|
|
||||||
refreshPublishedStatus()
|
|
||||||
|
|
||||||
updateProjectDescription = ->
|
|
||||||
$http.post("/project/#{ide.project_id}/template/description", {
|
|
||||||
description: $scope.templateDetails.description
|
|
||||||
_csrf: window.csrfToken
|
|
||||||
})
|
|
||||||
|
|
||||||
# Save the description on modal close
|
|
||||||
$modalInstance.result.finally () -> updateProjectDescription()
|
|
||||||
|
|
||||||
$scope.publishTemplate = ->
|
|
||||||
$scope.state.publishInflight = true
|
|
||||||
updateProjectDescription()
|
|
||||||
.error () ->
|
|
||||||
problemTalkingToTemplateApi()
|
|
||||||
.success () ->
|
|
||||||
$http
|
|
||||||
.post("/project/#{ide.project_id}/template/publish", {
|
|
||||||
_csrf: window.csrfToken
|
|
||||||
})
|
|
||||||
.error () ->
|
|
||||||
problemTalkingToTemplateApi()
|
|
||||||
.success () ->
|
|
||||||
refreshPublishedStatus()
|
|
||||||
$scope.state.publishInflight = false
|
|
||||||
|
|
||||||
|
|
||||||
$scope.unpublishTemplate = ->
|
|
||||||
$scope.state.unpublishInflight = true
|
|
||||||
$http
|
|
||||||
.post("/project/#{ide.project_id}/template/unpublish", {
|
|
||||||
_csrf: window.csrfToken
|
|
||||||
})
|
|
||||||
.success () ->
|
|
||||||
refreshPublishedStatus()
|
|
||||||
$scope.state.unpublishInflight = false
|
|
||||||
.error () ->
|
|
||||||
problemTalkingToTemplateApi()
|
|
||||||
|
|
||||||
$scope.cancel = () ->
|
|
||||||
$modalInstance.dismiss()
|
|
|
@ -1,4 +0,0 @@
|
||||||
define [
|
|
||||||
"ide/templates/controllers/TemplatesController"
|
|
||||||
], () ->
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
padding: @line-height-computed / 2;
|
padding: @line-height-computed / 2;
|
||||||
background-color: @gray-lightest;
|
background-color: @gray-lightest;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
overflow: auto;
|
||||||
img {
|
img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 90%;
|
max-height: 90%;
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
SandboxedModule = require('sandboxed-module')
|
|
||||||
assert = require('assert')
|
|
||||||
require('chai').should()
|
|
||||||
sinon = require('sinon')
|
|
||||||
modulePath = require('path').join __dirname, '../../../../app/js/Features/Dropbox/DropboxHandler.js'
|
|
||||||
|
|
||||||
thirdPartyDataStoreApiUrl = "http://third-party-json-store.herokuapp.com"
|
|
||||||
siteUrl = "www.sharelatex.com"
|
|
||||||
|
|
||||||
describe 'third party data store', ->
|
|
||||||
user_id = "123nd3ijdks"
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
@stubGet = sinon.stub()
|
|
||||||
@stubDel = sinon.stub()
|
|
||||||
@projectEntityHandler = flushProjectToThirdPartyDataStore:sinon.stub().callsArgWith(1)
|
|
||||||
@projectModel = findAllUsersProjects : sinon.stub()
|
|
||||||
@handler = SandboxedModule.require modulePath, requires:
|
|
||||||
"settings-sharelatex": {siteUrl:siteUrl, apis: {thirdPartyDataStore: {url: thirdPartyDataStoreApiUrl}}}
|
|
||||||
"../../models/Project":{Project:@projectModel}
|
|
||||||
'../Project/ProjectEntityHandler':@projectEntityHandler
|
|
||||||
"request":
|
|
||||||
get:@stubGet
|
|
||||||
del: @stubDel
|
|
||||||
'logger-sharelatex':
|
|
||||||
log:->
|
|
||||||
err:->
|
|
||||||
|
|
||||||
|
|
||||||
it 'should be able to get userStatus', (done)->
|
|
||||||
body = JSON.stringify({registered:true})
|
|
||||||
opts =
|
|
||||||
url: "#{thirdPartyDataStoreApiUrl}/user/#{user_id}/dropbox/status"
|
|
||||||
timeout: 5000
|
|
||||||
@stubGet.withArgs(opts).callsArgWith(1, null, {statusCode:200}, body)
|
|
||||||
@handler.getUserRegistrationStatus user_id, (err, status)->
|
|
||||||
status.registered.should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
it 'should be able to get auth url with callback url on it', (done)->
|
|
||||||
url = "http://www.dropbox.com"
|
|
||||||
body = JSON.stringify({authorize_url:url})
|
|
||||||
opts =
|
|
||||||
url: "#{thirdPartyDataStoreApiUrl}/user/#{user_id}/dropbox/register"
|
|
||||||
timeout: 5000
|
|
||||||
@stubGet.withArgs(opts).callsArgWith(1, null, {statusCode:200}, body)
|
|
||||||
@handler.getDropboxRegisterUrl user_id, (err, returnedUrl)->
|
|
||||||
returnedUrl.should.equal "#{url}&oauth_callback=#{siteUrl}/dropbox/completeRegistration"
|
|
||||||
done()
|
|
||||||
|
|
||||||
it 'should be able to complete registration and get getAccessToken from dropbox', (done)->
|
|
||||||
body = JSON.stringify({success:true})
|
|
||||||
opts =
|
|
||||||
url: "#{thirdPartyDataStoreApiUrl}/user/#{user_id}/dropbox/getaccesstoken"
|
|
||||||
timeout: 5000
|
|
||||||
@stubGet.withArgs(opts).callsArgWith(1, null, {statusCode:200}, body)
|
|
||||||
@handler.flushUsersProjectToDropbox = sinon.stub()
|
|
||||||
@handler.completeRegistration user_id, (err, successful)=>
|
|
||||||
@handler.flushUsersProjectToDropbox.called.should.equal true
|
|
||||||
successful.should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
it 'should tell the tpds to unlink the account', (done)->
|
|
||||||
opts =
|
|
||||||
url: "#{thirdPartyDataStoreApiUrl}/user/#{user_id}/dropbox"
|
|
||||||
timeout: 5000
|
|
||||||
@stubDel.callsArgWith(1, null, {statusCode:200})
|
|
||||||
@handler.unlinkAccount user_id, (err)=>
|
|
||||||
@stubDel.calledWith(opts).should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
it 'should tell the project entity handler to flush project to tpds', (done)->
|
|
||||||
user_id = "123u9oijllkj"
|
|
||||||
projectList = [{_id:"123lk"}, {_id:"12ji3ojio"}, {_id:"2jiojdoi"}]
|
|
||||||
collabProjectList = [{_id:"213ds"}]
|
|
||||||
@projectModel.findAllUsersProjects.callsArgWith(2, null, projectList, collabProjectList)
|
|
||||||
@handler.flushUsersProjectToDropbox user_id, =>
|
|
||||||
@projectEntityHandler.flushProjectToThirdPartyDataStore.calledWith(projectList[0]._id).should.equal true
|
|
||||||
@projectEntityHandler.flushProjectToThirdPartyDataStore.calledWith(projectList[1]._id).should.equal true
|
|
||||||
@projectEntityHandler.flushProjectToThirdPartyDataStore.calledWith(projectList[2]._id).should.equal true
|
|
||||||
@projectEntityHandler.flushProjectToThirdPartyDataStore.calledWith(collabProjectList[0]._id).should.equal true
|
|
||||||
done()
|
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
SandboxedModule = require('sandboxed-module')
|
|
||||||
assert = require('assert')
|
|
||||||
require('chai').should()
|
|
||||||
sinon = require('sinon')
|
|
||||||
modulePath = require('path').join __dirname, '../../../../app/js/Features/Dropbox/DropboxProjectController.js'
|
|
||||||
|
|
||||||
describe 'DropboxProjectController', ->
|
|
||||||
beforeEach ->
|
|
||||||
@DropboxProjectController = SandboxedModule.require modulePath, requires:
|
|
||||||
'./DropboxHandler': @DropboxHandler = {}
|
|
||||||
'../Project/ProjectGetter': @ProjectGetter = {}
|
|
||||||
'logger-sharelatex':
|
|
||||||
log:->
|
|
||||||
err:->
|
|
||||||
|
|
||||||
@project_id = "project-id-123"
|
|
||||||
@user_id = "user-id-123"
|
|
||||||
@req = {}
|
|
||||||
@res =
|
|
||||||
json: sinon.stub()
|
|
||||||
|
|
||||||
describe "getStatus", ->
|
|
||||||
beforeEach ->
|
|
||||||
@req.params =
|
|
||||||
Project_id: @project_id
|
|
||||||
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, { owner_ref: @user_id })
|
|
||||||
@DropboxHandler.getUserRegistrationStatus = sinon.stub().callsArgWith(1, null, @status = {"mock": "status"})
|
|
||||||
@DropboxProjectController.getStatus @req, @res
|
|
||||||
|
|
||||||
it "should look up the project owner", ->
|
|
||||||
@ProjectGetter.getProject
|
|
||||||
.calledWith(@project_id, {owner_ref: 1})
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should get the owner's Dropbox status", ->
|
|
||||||
@DropboxHandler.getUserRegistrationStatus
|
|
||||||
.calledWith(@user_id)
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should send the status to the client", ->
|
|
||||||
@res.json.calledWith(@status).should.equal true
|
|
|
@ -1,70 +0,0 @@
|
||||||
SandboxedModule = require('sandboxed-module')
|
|
||||||
assert = require('assert')
|
|
||||||
require('chai').should()
|
|
||||||
sinon = require('sinon')
|
|
||||||
modulePath = require('path').join __dirname, '../../../../app/js/Features/Dropbox/DropboxUserController.js'
|
|
||||||
|
|
||||||
|
|
||||||
describe 'DropboxUserController', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
@DropboxHandler =
|
|
||||||
getDropboxRegisterUrl: sinon.stub()
|
|
||||||
completeRegistration: sinon.stub()
|
|
||||||
unlinkAccount: sinon.stub()
|
|
||||||
|
|
||||||
@controller = SandboxedModule.require modulePath, requires:
|
|
||||||
'./DropboxHandler': @DropboxHandler
|
|
||||||
'logger-sharelatex':
|
|
||||||
log:->
|
|
||||||
err:->
|
|
||||||
|
|
||||||
@user_id = "23j21lk3j1312j321jkljkl"
|
|
||||||
@req =
|
|
||||||
session:
|
|
||||||
user:
|
|
||||||
_id: @user_id
|
|
||||||
@res = {}
|
|
||||||
|
|
||||||
describe "redirectUserToDropboxAuth", ->
|
|
||||||
beforeEach ->
|
|
||||||
@dropboxUrl = "www.dropbox.com"
|
|
||||||
@DropboxHandler.getDropboxRegisterUrl.callsArgWith(1, null, @dropboxUrl)
|
|
||||||
|
|
||||||
it "should call getDropboxRegisterUrl with the user id", (done)->
|
|
||||||
|
|
||||||
@res.redirect = (redirectUrl)=>
|
|
||||||
redirectUrl.should.equal @dropboxUrl
|
|
||||||
@DropboxHandler.getDropboxRegisterUrl.calledWith(@user_id).should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
@controller.redirectUserToDropboxAuth @req, @res
|
|
||||||
|
|
||||||
describe "completeDropboxRegistration", ->
|
|
||||||
beforeEach ->
|
|
||||||
@DropboxHandler.completeRegistration.callsArgWith(1)
|
|
||||||
|
|
||||||
it "should call getDropboxRegisterUrl with the user id", (done)->
|
|
||||||
|
|
||||||
@res.redirect = (redirectUrl)=>
|
|
||||||
redirectUrl.should.equal "/user/settings#dropboxSettings"
|
|
||||||
@DropboxHandler.completeRegistration.calledWith(@user_id).should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
@controller.completeDropboxRegistration @req, @res
|
|
||||||
|
|
||||||
|
|
||||||
describe "unlinkDropbox", ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
@DropboxHandler.unlinkAccount.callsArgWith(1)
|
|
||||||
|
|
||||||
it "should call getDropboxRegisterUrl with the user id", (done)->
|
|
||||||
|
|
||||||
@res.redirect = (redirectUrl)=>
|
|
||||||
redirectUrl.should.equal "/user/settings#dropboxSettings"
|
|
||||||
@DropboxHandler.unlinkAccount.calledWith(@user_id).should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
@controller.unlinkDropbox @req, @res
|
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
SandboxedModule = require('sandboxed-module')
|
|
||||||
assert = require('assert')
|
|
||||||
require('chai').should()
|
|
||||||
sinon = require('sinon')
|
|
||||||
modulePath = require('path').join __dirname, '../../../../app/js/Features/Dropbox/DropboxWebhookController.js'
|
|
||||||
|
|
||||||
describe 'DropboxWebhookController', ->
|
|
||||||
beforeEach ->
|
|
||||||
@req =
|
|
||||||
session:
|
|
||||||
destroy: ->
|
|
||||||
|
|
||||||
@DropboxWebhookController = SandboxedModule.require modulePath, requires:
|
|
||||||
"./DropboxWebhookHandler": @DropboxWebhookHandler = {}
|
|
||||||
'logger-sharelatex':
|
|
||||||
log:->
|
|
||||||
err:->
|
|
||||||
|
|
||||||
describe "verify", ->
|
|
||||||
beforeEach ->
|
|
||||||
@res =
|
|
||||||
send: sinon.stub()
|
|
||||||
@req.query =
|
|
||||||
challenge: @challenge = "foo"
|
|
||||||
@DropboxWebhookController.verify(@req, @res)
|
|
||||||
|
|
||||||
it "should echo the challenge parameter back", ->
|
|
||||||
@res.send.calledWith(@challenge).should.equal true
|
|
||||||
|
|
||||||
describe "webhook", ->
|
|
||||||
beforeEach ->
|
|
||||||
@req.body =
|
|
||||||
delta:
|
|
||||||
users: @dropbox_uids = [
|
|
||||||
"123456",
|
|
||||||
"789123"
|
|
||||||
]
|
|
||||||
@res.send = sinon.stub()
|
|
||||||
@DropboxWebhookHandler.pollDropboxUids = sinon.stub().callsArg(1)
|
|
||||||
@DropboxWebhookController.webhook(@req, @res)
|
|
||||||
|
|
||||||
it "should poll the Dropbox uids", ->
|
|
||||||
@DropboxWebhookHandler.pollDropboxUids
|
|
||||||
.calledWith(@dropbox_uids)
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should return success", ->
|
|
||||||
@res.send
|
|
||||||
.calledWith(200)
|
|
||||||
.should.equal true
|
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
SandboxedModule = require('sandboxed-module')
|
|
||||||
assert = require('assert')
|
|
||||||
require('chai').should()
|
|
||||||
expect = require("chai").expect
|
|
||||||
sinon = require('sinon')
|
|
||||||
modulePath = require('path').join __dirname, '../../../../app/js/Features/Dropbox/DropboxWebhookHandler.js'
|
|
||||||
|
|
||||||
describe 'DropboxWebhookHandler', ->
|
|
||||||
beforeEach ->
|
|
||||||
@DropboxWebhookHandler = SandboxedModule.require modulePath, requires:
|
|
||||||
"../../models/User": User: @User = {}
|
|
||||||
"../ThirdPartyDataStore/TpdsUpdateSender": @TpdsUpdateSender = {}
|
|
||||||
"redis-sharelatex":
|
|
||||||
createClient: () => @rclient =
|
|
||||||
auth: sinon.stub()
|
|
||||||
'settings-sharelatex': redis: web: {}
|
|
||||||
'logger-sharelatex':
|
|
||||||
log:->
|
|
||||||
err:->
|
|
||||||
@callback = sinon.stub()
|
|
||||||
|
|
||||||
describe "pollDropboxUids", ->
|
|
||||||
beforeEach (done) ->
|
|
||||||
@dropbox_uids = [
|
|
||||||
"123456",
|
|
||||||
"789123"
|
|
||||||
]
|
|
||||||
@DropboxWebhookHandler.pollDropboxUid = sinon.stub().callsArg(1)
|
|
||||||
@DropboxWebhookHandler.pollDropboxUids @dropbox_uids, done
|
|
||||||
|
|
||||||
it "should call pollDropboxUid for each uid", ->
|
|
||||||
for uid in @dropbox_uids
|
|
||||||
@DropboxWebhookHandler.pollDropboxUid
|
|
||||||
.calledWith(uid)
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
describe "pollDropboxUid", ->
|
|
||||||
beforeEach ->
|
|
||||||
@dropbox_uid = "dropbox-123456"
|
|
||||||
@user_id = "sharelatex-user-id"
|
|
||||||
@User.find = sinon.stub().callsArgWith(1, null, [ _id: @user_id ])
|
|
||||||
@TpdsUpdateSender.pollDropboxForUser = sinon.stub().callsArg(1)
|
|
||||||
|
|
||||||
describe "when there is already a poll in progress", () ->
|
|
||||||
beforeEach ->
|
|
||||||
@DropboxWebhookHandler._delayAndBatchPoll = sinon.stub().callsArgWith(1, null, false)
|
|
||||||
@DropboxWebhookHandler.pollDropboxUid @dropbox_uid, @callback
|
|
||||||
|
|
||||||
it "should not go ahead with the poll", ->
|
|
||||||
@TpdsUpdateSender.pollDropboxForUser.called.should.equal false
|
|
||||||
|
|
||||||
describe "when we are the one to do the delayed poll", () ->
|
|
||||||
beforeEach ->
|
|
||||||
@DropboxWebhookHandler._delayAndBatchPoll = sinon.stub().callsArgWith(1, null, true)
|
|
||||||
@DropboxWebhookHandler.pollDropboxUid @dropbox_uid, @callback
|
|
||||||
|
|
||||||
it "should look up the user", ->
|
|
||||||
@User.find
|
|
||||||
.calledWith({ "dropbox.access_token.uid": @dropbox_uid, "features.dropbox": true })
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should poll the user's Dropbox", ->
|
|
||||||
@TpdsUpdateSender.pollDropboxForUser
|
|
||||||
.calledWith(@user_id)
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should call the callback", ->
|
|
||||||
@callback.called.should.equal true
|
|
||||||
|
|
||||||
describe "_delayAndBatchPoll", () ->
|
|
||||||
beforeEach ->
|
|
||||||
@dropbox_uid = "dropbox-uid-123"
|
|
||||||
@DropboxWebhookHandler.POLL_DELAY_IN_MS = 100
|
|
||||||
|
|
||||||
describe "when no one else is polling yet", ->
|
|
||||||
beforeEach (done) ->
|
|
||||||
@rclient.set = sinon.stub().callsArgWith(5, null, "OK")
|
|
||||||
@start = Date.now()
|
|
||||||
@DropboxWebhookHandler._delayAndBatchPoll @dropbox_uid, (error, @shouldPoll) =>
|
|
||||||
@end = Date.now()
|
|
||||||
done()
|
|
||||||
|
|
||||||
it "should set the lock", ->
|
|
||||||
@rclient.set
|
|
||||||
.calledWith("dropbox-poll-lock:#{@dropbox_uid}", "LOCK", "PX", @DropboxWebhookHandler.POLL_DELAY_IN_MS, "NX")
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should return the callback after the delay with shouldPoll=true", ->
|
|
||||||
@shouldPoll.should.equal true
|
|
||||||
expect(@end - @start).to.be.at.least(@DropboxWebhookHandler.POLL_DELAY_IN_MS)
|
|
||||||
|
|
||||||
describe "when someone else is already polling", ->
|
|
||||||
beforeEach ->
|
|
||||||
@rclient.set = sinon.stub().callsArgWith(5, null, null)
|
|
||||||
@DropboxWebhookHandler._delayAndBatchPoll @dropbox_uid, @callback
|
|
||||||
|
|
||||||
it "should return the callback immediately with shouldPoll=false", ->
|
|
||||||
@callback.calledWith(null, false).should.equal true
|
|
||||||
|
|
|
@ -512,13 +512,6 @@ describe "EditorController", ->
|
||||||
returnedDocs[1].path.should.equal "doc2.tex"
|
returnedDocs[1].path.should.equal "doc2.tex"
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe "forceResyncOfDropbox", ->
|
|
||||||
it 'should tell the project entity handler to flush to tpds', (done)->
|
|
||||||
@ProjectEntityHandler.flushProjectToThirdPartyDataStore = sinon.stub().callsArgWith(1)
|
|
||||||
@EditorController.forceResyncOfDropbox @project_id, (err)=>
|
|
||||||
@ProjectEntityHandler.flushProjectToThirdPartyDataStore.calledWith(@project_id).should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
describe "notifyUsersProjectHasBeenDeletedOrRenamed", ->
|
describe "notifyUsersProjectHasBeenDeletedOrRenamed", ->
|
||||||
it 'should emmit a message to all users in a project', (done)->
|
it 'should emmit a message to all users in a project', (done)->
|
||||||
@EditorRealTimeController.emitToRoom = sinon.stub()
|
@EditorRealTimeController.emitToRoom = sinon.stub()
|
||||||
|
|
|
@ -66,6 +66,7 @@ describe "Subscription Handler sanboxed", ->
|
||||||
'./LimitationsManager':@LimitationsManager
|
'./LimitationsManager':@LimitationsManager
|
||||||
"../Email/EmailHandler":@EmailHandler
|
"../Email/EmailHandler":@EmailHandler
|
||||||
"../Dropbox/DropboxHandler":@DropboxHandler
|
"../Dropbox/DropboxHandler":@DropboxHandler
|
||||||
|
"../../infrastructure/Events": @Events = {emit: sinon.stub()}
|
||||||
|
|
||||||
@SubscriptionHandler.syncSubscriptionToUser = sinon.stub().callsArgWith(2)
|
@SubscriptionHandler.syncSubscriptionToUser = sinon.stub().callsArgWith(2)
|
||||||
|
|
||||||
|
@ -160,10 +161,8 @@ describe "Subscription Handler sanboxed", ->
|
||||||
@RecurlyWrapper.cancelSubscription.called.should.equal true
|
@RecurlyWrapper.cancelSubscription.called.should.equal true
|
||||||
@RecurlyWrapper.cancelSubscription.calledWith(@subscription.recurlySubscription_id).should.equal true
|
@RecurlyWrapper.cancelSubscription.calledWith(@subscription.recurlySubscription_id).should.equal true
|
||||||
|
|
||||||
|
it "should trigger the cancel subscription event", ->
|
||||||
it "should unlink dropbox", ->
|
@Events.emit.calledWith("cancelSubscription", @user._id).should.equal true
|
||||||
@DropboxHandler.unlinkAccount.called.should.equal true
|
|
||||||
@DropboxHandler.unlinkAccount.calledWith(@user._id).should.equal true
|
|
||||||
|
|
||||||
describe "reactiveRecurlySubscription", ->
|
describe "reactiveRecurlySubscription", ->
|
||||||
describe "with a user without a subscription", ->
|
describe "with a user without a subscription", ->
|
||||||
|
|
|
@ -1,209 +0,0 @@
|
||||||
should = require('chai').should()
|
|
||||||
SandboxedModule = require('sandboxed-module')
|
|
||||||
assert = require('assert')
|
|
||||||
path = require('path')
|
|
||||||
sinon = require('sinon')
|
|
||||||
modulePath = path.join __dirname, '../../../../app/js/Features/Templates/TemplatesController'
|
|
||||||
|
|
||||||
|
|
||||||
describe 'TemplatesController', ->
|
|
||||||
|
|
||||||
project_id = "213432"
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
@request = sinon.stub()
|
|
||||||
@request.returns {
|
|
||||||
pipe:->
|
|
||||||
on:->
|
|
||||||
}
|
|
||||||
@fs = {
|
|
||||||
unlink : sinon.stub()
|
|
||||||
createWriteStream : sinon.stub().returns(on:(_, cb)->cb())
|
|
||||||
}
|
|
||||||
@ProjectUploadManager = {createProjectFromZipArchive : sinon.stub().callsArgWith(3, null, {_id:project_id})}
|
|
||||||
@dumpFolder = "dump/path"
|
|
||||||
@ProjectOptionsHandler = {setCompiler:sinon.stub().callsArgWith(2)}
|
|
||||||
@uuid = "1234"
|
|
||||||
@TemplatesPublisher =
|
|
||||||
publish: sinon.stub()
|
|
||||||
unpublish:sinon.stub()
|
|
||||||
getTemplateDetails: sinon.stub()
|
|
||||||
@ProjectDetailsHandler =
|
|
||||||
getProjectDescription:sinon.stub()
|
|
||||||
@controller = SandboxedModule.require modulePath, requires:
|
|
||||||
'../Uploads/ProjectUploadManager':@ProjectUploadManager
|
|
||||||
'../Project/ProjectOptionsHandler':@ProjectOptionsHandler
|
|
||||||
'../Project/ProjectDetailsHandler':@ProjectDetailsHandler
|
|
||||||
'../Project/ProjectGetter':@ProjectGetter = {}
|
|
||||||
'../Editor/EditorController': @EditorController = {}
|
|
||||||
'./TemplatesPublisher':@TemplatesPublisher
|
|
||||||
"logger-sharelatex":
|
|
||||||
log:->
|
|
||||||
err:->
|
|
||||||
"settings-sharelatex":
|
|
||||||
path:
|
|
||||||
dumpFolder:@dumpFolder
|
|
||||||
siteUrl: "http://localhost:3000"
|
|
||||||
apis:
|
|
||||||
templates:
|
|
||||||
url: @templateApiUrl="http://templates.sharelatex.env"
|
|
||||||
web:
|
|
||||||
url: @webApiUrl="http://web-api.sharelatex.env"
|
|
||||||
"node-uuid":v4:=>@uuid
|
|
||||||
"request": @request
|
|
||||||
"fs":@fs
|
|
||||||
@zipUrl = "%2Ftemplates%2F52fb86a81ae1e566597a25f6%2Fv%2F4%2Fzip&templateName=Moderncv%20Banking&compiler=pdflatex"
|
|
||||||
@templateName = "project name here"
|
|
||||||
@user_id = "1234"
|
|
||||||
@req =
|
|
||||||
session:
|
|
||||||
user: _id:@user_id
|
|
||||||
templateData:
|
|
||||||
zipUrl: @zipUrl
|
|
||||||
templateName: @templateName
|
|
||||||
@redirect = {}
|
|
||||||
|
|
||||||
describe 'reciving a request to create project from templates.sharelatex.com', ->
|
|
||||||
|
|
||||||
it 'should take the zip url and write it to disk', (done)->
|
|
||||||
redirect = =>
|
|
||||||
@ProjectUploadManager.createProjectFromZipArchive.calledWith(@user_id, @templateName, "#{@dumpFolder}/#{@uuid}").should.equal true
|
|
||||||
@request.calledWith("#{@templateApiUrl}#{@zipUrl}").should.equal true
|
|
||||||
@fs.unlink.calledWith("#{@dumpFolder}/#{@uuid}").should.equal true
|
|
||||||
done()
|
|
||||||
res = redirect:redirect
|
|
||||||
@controller.createProjectFromZipTemplate @req, res
|
|
||||||
|
|
||||||
|
|
||||||
it "should go to the web api if the url does not contain templates", (done)->
|
|
||||||
@req.session.templateData.zipUrl = @zipUrl = "/project/52fd24abf080d80a22000fbd/download/zip&templateName=Example_Project&compiler=xelatex"
|
|
||||||
redirect = =>
|
|
||||||
@request.calledWith("#{@webApiUrl}#{@zipUrl}").should.equal true
|
|
||||||
done()
|
|
||||||
res = redirect:redirect
|
|
||||||
@controller.createProjectFromZipTemplate @req, res
|
|
||||||
|
|
||||||
it "should go to the web api if the url has template futher down the string", (done)->
|
|
||||||
@req.session.templateData.zipUrl = @zipUrl = "/project/52fd24abf080d80a22000fbd/download/zip&templateName=templates&compiler=xelatex"
|
|
||||||
redirect = =>
|
|
||||||
@request.calledWith("#{@webApiUrl}#{@zipUrl}").should.equal true
|
|
||||||
done()
|
|
||||||
res = redirect:redirect
|
|
||||||
@controller.createProjectFromZipTemplate @req, res
|
|
||||||
|
|
||||||
describe 'publishProject', ->
|
|
||||||
beforeEach ->
|
|
||||||
@user_id = "user-id-123"
|
|
||||||
@project_id = "project-id-123"
|
|
||||||
@res =
|
|
||||||
send: sinon.stub()
|
|
||||||
@req.params =
|
|
||||||
Project_id: @project_id
|
|
||||||
|
|
||||||
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, {owner_ref: @user_id})
|
|
||||||
@TemplatesPublisher.publish = sinon.stub().callsArgWith(2)
|
|
||||||
@controller.publishProject @req, @res
|
|
||||||
|
|
||||||
it "should look up the project owner", ->
|
|
||||||
@ProjectGetter.getProject
|
|
||||||
.calledWith(@project_id, { owner_ref: 1 })
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should publish the template", ->
|
|
||||||
@TemplatesPublisher.publish
|
|
||||||
.calledWith(@user_id, @project_id)
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should return a success status", ->
|
|
||||||
@res.send.calledWith(204).should.equal true
|
|
||||||
|
|
||||||
describe 'unpublishProject', ->
|
|
||||||
beforeEach ->
|
|
||||||
@user_id = "user-id-123"
|
|
||||||
@project_id = "project-id-123"
|
|
||||||
@res =
|
|
||||||
send: sinon.stub()
|
|
||||||
@req.params =
|
|
||||||
Project_id: @project_id
|
|
||||||
|
|
||||||
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, {owner_ref: @user_id})
|
|
||||||
@TemplatesPublisher.unpublish = sinon.stub().callsArgWith(2)
|
|
||||||
@controller.unpublishProject @req, @res
|
|
||||||
|
|
||||||
it "should look up the project owner", ->
|
|
||||||
@ProjectGetter.getProject
|
|
||||||
.calledWith(@project_id, { owner_ref: 1 })
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should publish the template", ->
|
|
||||||
@TemplatesPublisher.unpublish
|
|
||||||
.calledWith(@user_id, @project_id)
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should return a success status", ->
|
|
||||||
@res.send.calledWith(204).should.equal true
|
|
||||||
|
|
||||||
describe 'settings the compiler from the query string', ->
|
|
||||||
it 'should use the said compiler', (done)->
|
|
||||||
@req.session.templateData.compiler = "xelatex"
|
|
||||||
redirect = =>
|
|
||||||
@ProjectOptionsHandler.setCompiler.calledWith(project_id, "xelatex").should.equal true
|
|
||||||
done()
|
|
||||||
res = redirect:redirect
|
|
||||||
@controller.createProjectFromZipTemplate @req, res
|
|
||||||
|
|
||||||
it 'should not call the options handler if there is not set compiler', (done)->
|
|
||||||
redirect = =>
|
|
||||||
@ProjectOptionsHandler.setCompiler.called.should.equal false
|
|
||||||
done()
|
|
||||||
res = redirect:redirect
|
|
||||||
@controller.createProjectFromZipTemplate @req, res
|
|
||||||
|
|
||||||
describe "updateProjectDescription", ->
|
|
||||||
beforeEach ->
|
|
||||||
@EditorController.updateProjectDescription = sinon.stub().callsArg(2)
|
|
||||||
@res =
|
|
||||||
send: sinon.stub()
|
|
||||||
@req.params =
|
|
||||||
Project_id: @project_id = "project-id-123"
|
|
||||||
@req.body =
|
|
||||||
description: @description = "test description"
|
|
||||||
|
|
||||||
@controller.updateProjectDescription @req, @res
|
|
||||||
|
|
||||||
it "should update the project description", ->
|
|
||||||
@EditorController.updateProjectDescription
|
|
||||||
.calledWith(@project_id, @description)
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should return a success code", ->
|
|
||||||
@res.send.calledWith(204).should.equal true
|
|
||||||
|
|
||||||
describe 'getTemplateDetails', ->
|
|
||||||
beforeEach ->
|
|
||||||
@user_id = "user-id-123"
|
|
||||||
@project_id = "project-id-123"
|
|
||||||
@res =
|
|
||||||
json: sinon.stub()
|
|
||||||
@req.params =
|
|
||||||
Project_id: @project_id
|
|
||||||
|
|
||||||
@ProjectGetter.getProject = sinon.stub().callsArgWith(2, null, {owner_ref: @user_id})
|
|
||||||
@TemplatesPublisher.getTemplateDetails.callsArgWith(2, null, @details = {exists: true})
|
|
||||||
@ProjectDetailsHandler.getProjectDescription.callsArgWith(1, null, @description = "test description")
|
|
||||||
|
|
||||||
@controller.getTemplateDetails @req, @res
|
|
||||||
|
|
||||||
it "should get the template details for the user_id and project_id", ->
|
|
||||||
@TemplatesPublisher.getTemplateDetails
|
|
||||||
.calledWith(@user_id, @project_id)
|
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should return the details and description", ->
|
|
||||||
@res.json
|
|
||||||
.calledWith({
|
|
||||||
exists: @details.exists
|
|
||||||
description: @description
|
|
||||||
})
|
|
||||||
.should.equal true
|
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
should = require('chai').should()
|
|
||||||
SandboxedModule = require('sandboxed-module')
|
|
||||||
assert = require('assert')
|
|
||||||
path = require('path')
|
|
||||||
sinon = require('sinon')
|
|
||||||
modulePath = path.join __dirname, '../../../../app/js/Features/Templates/TemplatesPublisher'
|
|
||||||
expect = require("chai").expect
|
|
||||||
|
|
||||||
describe 'Templates publish', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
@request =
|
|
||||||
post: sinon.stub().callsArgWith(1)
|
|
||||||
del: sinon.stub().callsArgWith(1)
|
|
||||||
get: sinon.stub()
|
|
||||||
@settings =
|
|
||||||
apis:
|
|
||||||
templates:
|
|
||||||
url: "http://templates.sharelatex.env"
|
|
||||||
@TemplatesPublisher = SandboxedModule.require modulePath, requires:
|
|
||||||
"request": @request
|
|
||||||
"settings-sharelatex":@settings
|
|
||||||
"logger-sharelatex":
|
|
||||||
log:->
|
|
||||||
err:->
|
|
||||||
|
|
||||||
@project_id = "12312132"
|
|
||||||
@user_id = "132jlkjdsaoij"
|
|
||||||
|
|
||||||
describe "publish", ->
|
|
||||||
|
|
||||||
it 'should post the project to the templates api', (done)->
|
|
||||||
@TemplatesPublisher.publish @user_id, @project_id, =>
|
|
||||||
uri = "#{@settings.apis.templates.url}/templates/user/#{@user_id}/project/#{@project_id}"
|
|
||||||
@request.post.calledWith(uri).should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
|
|
||||||
describe "unpublish", ->
|
|
||||||
|
|
||||||
it "should make a DELETE request to templates api", (done)->
|
|
||||||
@TemplatesPublisher.unpublish @user_id, @project_id, =>
|
|
||||||
uri = "#{@settings.apis.templates.url}/templates/user/#{@user_id}/project/#{@project_id}"
|
|
||||||
@request.del.calledWith(uri).should.equal true
|
|
||||||
done()
|
|
||||||
|
|
||||||
|
|
||||||
describe "getTemplateDetails", ->
|
|
||||||
it "should make a get request to templates api", (done)->
|
|
||||||
body =
|
|
||||||
exists:true
|
|
||||||
@request.get.callsArgWith(1, null, null, JSON.stringify(body))
|
|
||||||
@TemplatesPublisher.getTemplateDetails @user_id, @project_id, (err, details)=>
|
|
||||||
uri = "#{@settings.apis.templates.url}/templates/user/#{@user_id}/project/#{@project_id}/details"
|
|
||||||
@request.get.calledWith(uri).should.equal true
|
|
||||||
assert.deepEqual details, body
|
|
||||||
done()
|
|
||||||
|
|
||||||
|
|
||||||
it "should catch an error thrown from trying to parse bad json", (done)->
|
|
||||||
@request.get.callsArgWith(1, null, null, "<not json>")
|
|
||||||
@TemplatesPublisher.getTemplateDetails @user_id, @project_id, (err, details)=>
|
|
||||||
expect(err).to.exist
|
|
||||||
done()
|
|
|
@ -1,150 +0,0 @@
|
||||||
should = require('chai').should()
|
|
||||||
SandboxedModule = require('sandboxed-module')
|
|
||||||
assert = require('assert')
|
|
||||||
path = require('path')
|
|
||||||
sinon = require('sinon')
|
|
||||||
modulePath = path.join __dirname, "../../../../app/js/Features/Templates/TemplatesWebController"
|
|
||||||
expect = require("chai").expect
|
|
||||||
|
|
||||||
describe "TemplatesWebController", ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
|
|
||||||
@settings =
|
|
||||||
apis:
|
|
||||||
templates_api:
|
|
||||||
url:"templates.sharelatex.env"
|
|
||||||
@TemplatesWebController = SandboxedModule.require modulePath, requires:
|
|
||||||
"settings-sharelatex":@settings
|
|
||||||
"logger-sharelatex":
|
|
||||||
log:->
|
|
||||||
err:->
|
|
||||||
@stubbedApiData =
|
|
||||||
template:{_id:"12312321", name:"bob"}
|
|
||||||
tag: {name:"tag name"}
|
|
||||||
|
|
||||||
@TemplatesWebController._getDataFromTemplatesApi = sinon.stub().callsArgWith(1, null, @stubbedApiData)
|
|
||||||
|
|
||||||
@user_id = "12332lk3jlkj"
|
|
||||||
@tag_name = "tag-name-here"
|
|
||||||
@template_name = "template-name-here"
|
|
||||||
@template_id = "template_id_here"
|
|
||||||
@req =
|
|
||||||
params:
|
|
||||||
user_id: @user_id
|
|
||||||
@res = {}
|
|
||||||
|
|
||||||
describe "renderTemplatesIndexPage", ->
|
|
||||||
|
|
||||||
it "should get the data from the templates api", (done)->
|
|
||||||
@res.render = (viewName, data)=>
|
|
||||||
@TemplatesWebController._getDataFromTemplatesApi.calledWith("/user/#{@user_id}").should.equal true
|
|
||||||
data.should.equal @stubbedApiData
|
|
||||||
done()
|
|
||||||
@TemplatesWebController.renderTemplatesIndexPage @req, @res
|
|
||||||
|
|
||||||
|
|
||||||
describe "renerTemplateInTag", ->
|
|
||||||
|
|
||||||
it "should get the data from the templates api", (done)->
|
|
||||||
@res.render = (viewName, data)=>
|
|
||||||
@TemplatesWebController._getDataFromTemplatesApi.calledWith("/user/#{@user_id}/tag/#{@tag_name}/template/#{@template_name}").should.equal true
|
|
||||||
data.should.equal @stubbedApiData
|
|
||||||
done()
|
|
||||||
|
|
||||||
@req.params =
|
|
||||||
user_id:@user_id
|
|
||||||
template_name:@template_name
|
|
||||||
tag_name:@tag_name
|
|
||||||
|
|
||||||
@TemplatesWebController.renerTemplateInTag @req, @res
|
|
||||||
|
|
||||||
|
|
||||||
describe "tagOrCanonicalPage", ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
@TemplatesWebController._renderCanonicalPage = sinon.stub()
|
|
||||||
@TemplatesWebController._renderAllTemplatesPage = sinon.stub()
|
|
||||||
@TemplatesWebController._renderTagPage = sinon.stub()
|
|
||||||
|
|
||||||
it "should call _renderCanonicalPage if there is a template id", ()->
|
|
||||||
|
|
||||||
@req.params =
|
|
||||||
template_id:@template_id
|
|
||||||
|
|
||||||
@TemplatesWebController.tagOrCanonicalPage @req, @res
|
|
||||||
|
|
||||||
@TemplatesWebController._renderCanonicalPage.called.should.equal true
|
|
||||||
@TemplatesWebController._renderAllTemplatesPage.called.should.equal false
|
|
||||||
@TemplatesWebController._renderTagPage.called.should.equal false
|
|
||||||
|
|
||||||
it "should call _renderAllTemplatesPage the tag name is all", ()->
|
|
||||||
|
|
||||||
@req.params =
|
|
||||||
tag_name:"all"
|
|
||||||
|
|
||||||
@TemplatesWebController.tagOrCanonicalPage @req, @res
|
|
||||||
|
|
||||||
@TemplatesWebController._renderCanonicalPage.called.should.equal false
|
|
||||||
@TemplatesWebController._renderAllTemplatesPage.called.should.equal true
|
|
||||||
@TemplatesWebController._renderTagPage.called.should.equal false
|
|
||||||
|
|
||||||
|
|
||||||
it "should call _renderTagPage the tag name is set", ()->
|
|
||||||
|
|
||||||
@req.params =
|
|
||||||
tag_name:"some-tag"
|
|
||||||
|
|
||||||
@TemplatesWebController.tagOrCanonicalPage @req, @res
|
|
||||||
|
|
||||||
@TemplatesWebController._renderCanonicalPage.called.should.equal false
|
|
||||||
@TemplatesWebController._renderAllTemplatesPage.called.should.equal false
|
|
||||||
@TemplatesWebController._renderTagPage.called.should.equal true
|
|
||||||
|
|
||||||
describe "_renderCanonicalPage", ->
|
|
||||||
|
|
||||||
it "should get the data from the templates api", (done)->
|
|
||||||
@res.render = (viewName, data)=>
|
|
||||||
@TemplatesWebController._getDataFromTemplatesApi.calledWith("/user/#{@user_id}/template/#{@template_id}").should.equal true
|
|
||||||
data.tag = null
|
|
||||||
data.should.equal @stubbedApiData
|
|
||||||
done()
|
|
||||||
|
|
||||||
@req.params =
|
|
||||||
user_id:@user_id
|
|
||||||
template_id:@template_id
|
|
||||||
|
|
||||||
@TemplatesWebController._renderCanonicalPage @req, @res
|
|
||||||
|
|
||||||
|
|
||||||
describe "_renderAllTemplatesPage", ->
|
|
||||||
|
|
||||||
it "should get the data from the templates api", (done)->
|
|
||||||
@res.render = (viewName, data)=>
|
|
||||||
@TemplatesWebController._getDataFromTemplatesApi.calledWith("/user/#{@user_id}/all").should.equal true
|
|
||||||
data.should.equal @stubbedApiData
|
|
||||||
done()
|
|
||||||
|
|
||||||
@req.params =
|
|
||||||
user_id:@user_id
|
|
||||||
|
|
||||||
@TemplatesWebController._renderAllTemplatesPage @req, @res
|
|
||||||
|
|
||||||
|
|
||||||
describe "_renderTagPage", ->
|
|
||||||
|
|
||||||
it "should get the data from the templates api", (done)->
|
|
||||||
@res.render = (viewName, data)=>
|
|
||||||
@TemplatesWebController._getDataFromTemplatesApi.calledWith("/user/#{@user_id}/tag/#{@tag_name}").should.equal true
|
|
||||||
data.should.equal @stubbedApiData
|
|
||||||
done()
|
|
||||||
|
|
||||||
@req.params =
|
|
||||||
user_id:@user_id
|
|
||||||
tag_name:@tag_name
|
|
||||||
|
|
||||||
@TemplatesWebController._renderTagPage @req, @res
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue