diff --git a/services/web/app/coffee/Features/Compile/ClsiManager.coffee b/services/web/app/coffee/Features/Compile/ClsiManager.coffee index f874573d6f..f04c568bd6 100755 --- a/services/web/app/coffee/Features/Compile/ClsiManager.coffee +++ b/services/web/app/coffee/Features/Compile/ClsiManager.coffee @@ -11,11 +11,11 @@ ClsiCookieManager = require("./ClsiCookieManager") module.exports = ClsiManager = - sendRequest: (project_id, options = {}, callback = (error, success) ->) -> + sendRequest: (project_id, user_id, options = {}, callback = (error, success) ->) -> ClsiManager._buildRequest project_id, options, (error, req) -> return callback(error) if error? logger.log project_id: project_id, "sending compile to CLSI" - ClsiManager._postToClsi project_id, req, options.compileGroup, (error, response) -> + ClsiManager._postToClsi project_id, user_id, req, options.compileGroup, (error, response) -> if error? logger.err err:error, project_id:project_id, "error sending request to clsi" return callback(error) @@ -27,14 +27,13 @@ module.exports = ClsiManager = outputFiles = ClsiManager._parseOutputFiles(project_id, response?.compile?.outputFiles) callback(null, response?.compile?.status, outputFiles, clsiServerId) - deleteAuxFiles: (project_id, options, callback = (error) ->) -> - compilerUrl = @_getCompilerUrl(options?.compileGroup) + deleteAuxFiles: (project_id, user_id, options, callback = (error) ->) -> + compilerUrl = @_getCompilerUrl(options?.compileGroup, project_id, user_id) opts = - url:"#{compilerUrl}/project/#{project_id}" + url:compilerUrl method:"DELETE" ClsiManager._makeRequest project_id, opts, callback - _makeRequest: (project_id, opts, callback)-> ClsiCookieManager.getCookieJar project_id, (err, jar)-> if err? @@ -51,14 +50,17 @@ module.exports = ClsiManager = return callback err, response, body + _getCompilerUrl: (compileGroup, project_id, user_id, action) -> + host = Settings.apis.clsi.url + path = "/project/#{project_id}" + path += "/user/#{user_id}" if user_id? + path += "/#{action}" if action? + return "#{host}#{path}" - _getCompilerUrl: (compileGroup) -> - return Settings.apis.clsi.url - - _postToClsi: (project_id, req, compileGroup, callback = (error, response) ->) -> - compilerUrl = Settings.apis.clsi.url - opts = - url: "#{compilerUrl}/project/#{project_id}/compile" + _postToClsi: (project_id, user_id, req, compileGroup, callback = (error, response) ->) -> + compileUrl = @_getCompilerUrl(compileGroup, project_id, user_id, "compile") + opts = + url: compileUrl json: req method: "POST" ClsiManager._makeRequest project_id, opts, (error, response, body) -> @@ -133,15 +135,15 @@ module.exports = ClsiManager = resources: resources } - wordCount: (project_id, file, options, callback = (error, response) ->) -> + wordCount: (project_id, user_id, file, options, callback = (error, response) ->) -> ClsiManager._buildRequest project_id, options, (error, req) -> - compilerUrl = ClsiManager._getCompilerUrl(options?.compileGroup) filename = file || req?.compile?.rootResourcePath - wordcount_url = "#{compilerUrl}/project/#{project_id}/wordcount?file=#{encodeURIComponent(filename)}" - if req.compile.options.imageName? - wordcount_url += "&image=#{encodeURIComponent(req.compile.options.imageName)}" + wordcount_url = ClsiManager._getCompilerUrl(options?.compileGroup, project_id, user_id, "wordcount") opts = url: wordcount_url + qs: + file: filename + image: req.compile.options.imageName method: "GET" ClsiManager._makeRequest project_id, opts, (error, response, body) -> return callback(error) if error? diff --git a/services/web/app/coffee/Features/Compile/CompileController.coffee b/services/web/app/coffee/Features/Compile/CompileController.coffee index b50c6ffd1a..830af98115 100755 --- a/services/web/app/coffee/Features/Compile/CompileController.coffee +++ b/services/web/app/coffee/Features/Compile/CompileController.coffee @@ -29,7 +29,9 @@ module.exports = CompileController = options.compiler = req.body.compiler if req.body?.draft options.draft = req.body.draft - logger.log {options, project_id}, "got compile request" + if req.query?.isolated is "true" + options.isolated = true + logger.log {options:options, project_id:project_id, user_id:user_id}, "got compile request" CompileManager.compile project_id, user_id, options, (error, status, outputFiles, clsiServerId, limits) -> return next(error) if error? res.contentType("application/json") @@ -40,6 +42,13 @@ module.exports = CompileController = clsiServerId:clsiServerId } + _compileAsUser: (req, callback) -> + isolated = req.query?.isolated is "true" + if isolated + AuthenticationController.getLoggedInUserId req, callback + else + callback() + downloadPdf: (req, res, next = (error) ->)-> Metrics.inc "pdf-downloads" project_id = req.params.Project_id @@ -76,28 +85,40 @@ module.exports = CompileController = deleteAuxFiles: (req, res, next) -> project_id = req.params.Project_id - CompileManager.deleteAuxFiles project_id, (error) -> + CompileController._compileAsUser req, (error, user_id) -> return next(error) if error? - res.sendStatus(200) + CompileManager.deleteAuxFiles project_id, user_id, (error) -> + return next(error) if error? + res.sendStatus(200) compileAndDownloadPdf: (req, res, next)-> project_id = req.params.project_id - CompileManager.compile project_id, null, {}, (err)-> - if err? - logger.err err:err, project_id:project_id, "something went wrong compile and downloading pdf" - res.sendStatus 500 - url = "/project/#{project_id}/output/output.pdf" - CompileController.proxyToClsi project_id, url, req, res, next + CompileController._compileAsUser req, (error, user_id) -> + return next(error) if error? + CompileManager.compile project_id, user_id, {}, (err)-> + if err? + logger.err err:err, project_id:project_id, "something went wrong compile and downloading pdf" + res.sendStatus 500 + url = "/project/#{project_id}/output/output.pdf" + CompileController.proxyToClsi project_id, user_id, url, req, res, next getFileFromClsi: (req, res, next = (error) ->) -> project_id = req.params.Project_id build = req.params.build - if build? + user = req.params.user + if user? and build? + url = "/project/#{project_id}/user/#{user}/build/#{build}/output/#{req.params.file}" + else if build? url = "/project/#{project_id}/build/#{build}/output/#{req.params.file}" else url = "/project/#{project_id}/output/#{req.params.file}" CompileController.proxyToClsi(project_id, url, req, res, next) + _getUrl: (project_id, user_id, action) -> + path = "/project/#{project_id}" + path += "/user/#{user_id}" if user_id? + return "#{path}/#{action}" + proxySyncPdf: (req, res, next = (error) ->) -> project_id = req.params.Project_id {page, h, v} = req.query @@ -107,8 +128,12 @@ module.exports = CompileController = return next(new Error("invalid h parameter")) if not v?.match(/^\d+\.\d+$/) return next(new Error("invalid v parameter")) - destination = {url: "/project/#{project_id}/sync/pdf", qs: {page, h, v}} - CompileController.proxyToClsi(project_id, destination, req, res, next) + url = CompileController._getUrl(project_id, user_id, "sync/pdf") + destination = {url: url, qs: {page, h, v}} + # whether this request is going to a per-user container + CompileController._compileAsUser req, (error, user_id) -> + return next(error) if error? + CompileController.proxyToClsi(project_id, destination, req, res, next) proxySyncCode: (req, res, next = (error) ->) -> project_id = req.params.Project_id @@ -119,8 +144,11 @@ module.exports = CompileController = return next(new Error("invalid line parameter")) if not column?.match(/^\d+$/) return next(new Error("invalid column parameter")) - destination = {url:"/project/#{project_id}/sync/code", qs: {file, line, column}} - CompileController.proxyToClsi(project_id, destination, req, res, next) + url = CompileController._getUrl(project_id, user_id, "sync/code") + destination = {url:url, qs: {file, line, column}} + CompileController._compileAsUser req, (error, user_id) -> + return next(error) if error? + CompileController.proxyToClsi(project_id, destination, req, res, next) proxyToClsi: (project_id, url, req, res, next = (error) ->) -> if req.query?.compileGroup @@ -168,7 +196,9 @@ module.exports = CompileController = wordCount: (req, res, next) -> project_id = req.params.Project_id file = req.query.file || false - CompileManager.wordCount project_id, file, (error, body) -> + CompileController._compileAsUser req, (error, user_id) -> return next(error) if error? - res.contentType("application/json") - res.send body + CompileManager.wordCount project_id, user_id, file, (error, body) -> + return next(error) if error? + res.contentType("application/json") + res.send body diff --git a/services/web/app/coffee/Features/Compile/CompileManager.coffee b/services/web/app/coffee/Features/Compile/CompileManager.coffee index 0d8d480b7b..b552b1a7c7 100755 --- a/services/web/app/coffee/Features/Compile/CompileManager.coffee +++ b/services/web/app/coffee/Features/Compile/CompileManager.coffee @@ -37,15 +37,16 @@ module.exports = CompileManager = return callback(error) if error? for key, value of limits options[key] = value - ClsiManager.sendRequest project_id, options, (error, status, outputFiles, clsiServerId) -> + user_id = undefined if not options.isolated + ClsiManager.sendRequest project_id, user_id, options, (error, status, outputFiles, clsiServerId) -> return callback(error) if error? logger.log files: outputFiles, "output files" callback(null, status, outputFiles, clsiServerId, limits) - deleteAuxFiles: (project_id, callback = (error) ->) -> + deleteAuxFiles: (project_id, user_id, callback = (error) ->) -> CompileManager.getProjectCompileLimits project_id, (error, limits) -> return callback(error) if error? - ClsiManager.deleteAuxFiles project_id, limits, callback + ClsiManager.deleteAuxFiles project_id, user_id, limits, callback getProjectCompileLimits: (project_id, callback = (error, limits) ->) -> Project.findById project_id, {owner_ref: 1}, (error, project) -> @@ -92,7 +93,7 @@ module.exports = CompileManager = else ProjectRootDocManager.setRootDocAutomatically project_id, callback - wordCount: (project_id, file, callback = (error) ->) -> + wordCount: (project_id, user_id, file, callback = (error) ->) -> CompileManager.getProjectCompileLimits project_id, (error, limits) -> return callback(error) if error? - ClsiManager.wordCount project_id, file, limits, callback + ClsiManager.wordCount project_id, user_id, file, limits, callback diff --git a/services/web/app/coffee/router.coffee b/services/web/app/coffee/router.coffee index 80c52c5a24..b281b019ff 100644 --- a/services/web/app/coffee/router.coffee +++ b/services/web/app/coffee/router.coffee @@ -124,6 +124,19 @@ module.exports = class Router next() ), AuthorizationMiddlewear.ensureUserCanReadProject, CompileController.getFileFromClsi + # direct url access to output files for a specific user and build (query string not required) + webRouter.get /^\/project\/([^\/]*)\/user\/([0-9a-f]+)\/build\/([0-9a-f-]+)\/output\/(.*)$/, + ((req, res, next) -> + params = + "Project_id": req.params[0] + "user": req.params[1] + "build": req.params[2] + "file": req.params[3] + req.params = params + next() + ), AuthorizationMiddlewear.ensureUserCanReadProject, CompileController.getFileFromClsi + + webRouter.delete "/project/:Project_id/output", AuthorizationMiddlewear.ensureUserCanReadProject, CompileController.deleteAuxFiles webRouter.get "/project/:Project_id/sync/code", AuthorizationMiddlewear.ensureUserCanReadProject, CompileController.proxySyncCode webRouter.get "/project/:Project_id/sync/pdf", AuthorizationMiddlewear.ensureUserCanReadProject, CompileController.proxySyncPdf