Przeglądaj źródła

Allow CLSI cache to be cleared from within the editor

James Allen 12 lat temu
rodzic
commit
767b220fab

+ 4 - 3
services/web/app/coffee/Features/Compile/CompileController.coffee

@@ -19,6 +19,9 @@ module.exports = CompileController =
 				res.header('Content-Disposition', "filename=#{project.getSafeProjectName()}.pdf")
 				res.header('Content-Disposition', "filename=#{project.getSafeProjectName()}.pdf")
 			CompileController.proxyToClsi("/project/#{project_id}/output/output.pdf", req, res, next)
 			CompileController.proxyToClsi("/project/#{project_id}/output/output.pdf", req, res, next)
 
 
+	deleteAuxFiles: (req, res, next) ->
+		project_id = req.params.Project_id
+		CompileController.proxyToClsi("/project/#{project_id}", req, res, next)
 
 
 	compileAndDownloadPdf: (req, res, next)->
 	compileAndDownloadPdf: (req, res, next)->
 		project_id = req.params.project_id
 		project_id = req.params.project_id
@@ -29,8 +32,6 @@ module.exports = CompileController =
 			url = "/project/#{project_id}/output/output.pdf"
 			url = "/project/#{project_id}/output/output.pdf"
 			CompileController.proxyToClsi url, req, res, next
 			CompileController.proxyToClsi url, req, res, next
 
 
-
-
 	getFileFromClsi: (req, res, next = (error) ->) ->
 	getFileFromClsi: (req, res, next = (error) ->) ->
 		CompileController.proxyToClsi("/project/#{req.params.Project_id}/output/#{req.params.file}", req, res, next)
 		CompileController.proxyToClsi("/project/#{req.params.Project_id}/output/#{req.params.file}", req, res, next)
 
 
@@ -38,7 +39,7 @@ module.exports = CompileController =
 		logger.log url: url, "proxying to CLSI"
 		logger.log url: url, "proxying to CLSI"
 		url = "#{Settings.apis.clsi.url}#{url}"
 		url = "#{Settings.apis.clsi.url}#{url}"
 		oneMinute = 60 * 1000
 		oneMinute = 60 * 1000
-		proxy = request.get(url: url, timeout: oneMinute)
+		proxy = request(url: url, method: req.method, timeout: oneMinute)
 		proxy.pipe(res)
 		proxy.pipe(res)
 		proxy.on "error", (error) ->
 		proxy.on "error", (error) ->
 			logger.error err: error, url: url, "CLSI proxy error"
 			logger.error err: error, url: url, "CLSI proxy error"

+ 30 - 32
services/web/app/coffee/router.coffee

@@ -6,7 +6,7 @@ ProjectApiController = require("./Features/Project/ProjectApiController")
 InfoController = require('./controllers/InfoController')
 InfoController = require('./controllers/InfoController')
 SpellingController = require('./Features/Spelling/SpellingController')
 SpellingController = require('./Features/Spelling/SpellingController')
 CollaberationManager = require('./managers/CollaberationManager')
 CollaberationManager = require('./managers/CollaberationManager')
-SecutiryManager = require('./managers/SecurityManager')
+SecurityManager = require('./managers/SecurityManager')
 AuthorizationManager = require('./Features/Security/AuthorizationManager')
 AuthorizationManager = require('./Features/Security/AuthorizationManager')
 versioningController =  require("./Features/Versioning/VersioningApiController")
 versioningController =  require("./Features/Versioning/VersioningApiController")
 EditorController = require("./Features/Editor/EditorController")
 EditorController = require("./Features/Editor/EditorController")
@@ -56,7 +56,7 @@ module.exports = class Router
 		app.get  '/login', UserController.loginForm
 		app.get  '/login', UserController.loginForm
 		app.post '/login', AuthenticationController.login
 		app.post '/login', AuthenticationController.login
 		app.get  '/logout', UserController.logout
 		app.get  '/logout', UserController.logout
-		app.get  '/restricted', SecutiryManager.restricted
+		app.get  '/restricted', SecurityManager.restricted
 
 
 		app.get '/resources', HomeController.resources
 		app.get '/resources', HomeController.resources
 		app.get '/comments', HomeController.comments
 		app.get '/comments', HomeController.comments
@@ -99,13 +99,10 @@ module.exports = class Router
 		app.post '/project/new', AuthenticationController.requireLogin(), Project.apiNewProject
 		app.post '/project/new', AuthenticationController.requireLogin(), Project.apiNewProject
 		app.get '/project/new/template', TemplatesMiddlewear.saveTemplateDataInSession, AuthenticationController.requireLogin(), TemplatesController.createProjectFromZipTemplate
 		app.get '/project/new/template', TemplatesMiddlewear.saveTemplateDataInSession, AuthenticationController.requireLogin(), TemplatesController.createProjectFromZipTemplate
 
 
-		app.get  '/Project/:Project_id', SecutiryManager.requestCanAccessProject, Project.loadEditor
-		app.get  '/Project/:Project_id/file/:File_id', SecutiryManager.requestCanAccessProject, FileStoreController.getFile
+		app.get  '/Project/:Project_id', SecurityManager.requestCanAccessProject, Project.loadEditor
+		app.get  '/Project/:Project_id/file/:File_id', SecurityManager.requestCanAccessProject, FileStoreController.getFile
 
 
-		# This is left for legacy reasons and can be removed once all editors have had a chance to refresh:
-		app.get  '/Project/:Project_id/download/pdf', SecutiryManager.requestCanAccessProject, CompileController.downloadPdf
-
-		app.get  '/Project/:Project_id/output/output.pdf', SecutiryManager.requestCanAccessProject, CompileController.downloadPdf
+		app.get  '/Project/:Project_id/output/output.pdf', SecurityManager.requestCanAccessProject, CompileController.downloadPdf
 		app.get  /^\/project\/([^\/]*)\/output\/(.*)$/,
 		app.get  /^\/project\/([^\/]*)\/output\/(.*)$/,
 			((req, res, next) ->
 			((req, res, next) ->
 				params =
 				params =
@@ -113,25 +110,26 @@ module.exports = class Router
 					"file":       req.params[1]
 					"file":       req.params[1]
 				req.params = params
 				req.params = params
 				next()
 				next()
-			), SecutiryManager.requestCanAccessProject, CompileController.getFileFromClsi
+			), SecurityManager.requestCanAccessProject, CompileController.getFileFromClsi
+		app.del "/project/:Project_id/output", SecurityManager.requestCanAccessProject, CompileController.deleteAuxFiles
 
 
-		app.del  '/Project/:Project_id',  SecutiryManager.requestIsOwner, Project.deleteProject
-		app.post  '/Project/:Project_id/clone', SecutiryManager.requestCanAccessProject, Project.cloneProject
+		app.del  '/Project/:Project_id', SecurityManager.requestIsOwner, Project.deleteProject
+		app.post  '/Project/:Project_id/clone', SecurityManager.requestCanAccessProject, Project.cloneProject
 
 
-		app.post '/Project/:Project_id/snapshot', SecutiryManager.requestCanModifyProject, versioningController.takeSnapshot
-		app.get  '/Project/:Project_id/version', SecutiryManager.requestCanAccessProject, versioningController.listVersions
-		app.get  '/Project/:Project_id/version/:Version_id', SecutiryManager.requestCanAccessProject, versioningController.getVersion
-		app.get  '/Project/:Project_id/version', SecutiryManager.requestCanAccessProject, versioningController.listVersions
-		app.get  '/Project/:Project_id/version/:Version_id', SecutiryManager.requestCanAccessProject, versioningController.getVersion
+		app.post '/Project/:Project_id/snapshot', SecurityManager.requestCanModifyProject, versioningController.takeSnapshot
+		app.get  '/Project/:Project_id/version', SecurityManager.requestCanAccessProject, versioningController.listVersions
+		app.get  '/Project/:Project_id/version/:Version_id', SecurityManager.requestCanAccessProject, versioningController.getVersion
+		app.get  '/Project/:Project_id/version', SecurityManager.requestCanAccessProject, versioningController.listVersions
+		app.get  '/Project/:Project_id/version/:Version_id', SecurityManager.requestCanAccessProject, versioningController.getVersion
 
 
-		app.get  "/project/:Project_id/updates", SecutiryManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi
-		app.get  "/project/:Project_id/doc/:doc_id/diff", SecutiryManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi
-		app.post "/project/:Project_id/doc/:doc_id/version/:version_id/restore", SecutiryManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi
+		app.get  "/project/:Project_id/updates", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi
+		app.get  "/project/:Project_id/doc/:doc_id/diff", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi
+		app.post "/project/:Project_id/doc/:doc_id/version/:version_id/restore", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi
 
 
 		app.post '/project/:project_id/leave', AuthenticationController.requireLogin(), CollaboratorsController.removeSelfFromProject
 		app.post '/project/:project_id/leave', AuthenticationController.requireLogin(), CollaboratorsController.removeSelfFromProject
-		app.get  '/project/:Project_id/collaborators', SecutiryManager.requestCanAccessProject(allow_auth_token: true), CollaboratorsController.getCollaborators
+		app.get  '/project/:Project_id/collaborators', SecurityManager.requestCanAccessProject(allow_auth_token: true), CollaboratorsController.getCollaborators
 
 
-		app.get  '/Project/:Project_id/download/zip', SecutiryManager.requestCanAccessProject, ProjectDownloadsController.downloadProject
+		app.get  '/Project/:Project_id/download/zip', SecurityManager.requestCanAccessProject, ProjectDownloadsController.downloadProject
 
 
 
 
 		app.get '/tag', AuthenticationController.requireLogin(), TagsController.getAllTags
 		app.get '/tag', AuthenticationController.requireLogin(), TagsController.getAllTags
@@ -164,21 +162,21 @@ module.exports = class Router
 				req.params = params
 				req.params = params
 				next()
 				next()
 			),
 			),
-			SecutiryManager.requestCanAccessProject, versioningController.getVersionFile
+			SecurityManager.requestCanAccessProject, versioningController.getVersionFile
 
 
 		app.post "/spelling/check", AuthenticationController.requireLogin(), SpellingController.proxyRequestToSpellingApi
 		app.post "/spelling/check", AuthenticationController.requireLogin(), SpellingController.proxyRequestToSpellingApi
 		app.post "/spelling/learn", AuthenticationController.requireLogin(), SpellingController.proxyRequestToSpellingApi
 		app.post "/spelling/learn", AuthenticationController.requireLogin(), SpellingController.proxyRequestToSpellingApi
 
 
 		#Admin Stuff
 		#Admin Stuff
-		app.get  '/admin', SecutiryManager.requestIsAdmin, AdminController.index
-		app.post '/admin/closeEditor', SecutiryManager.requestIsAdmin, AdminController.closeEditor
-		app.post '/admin/dissconectAllUsers', SecutiryManager.requestIsAdmin, AdminController.dissconectAllUsers
-		app.post '/admin/writeAllDocsToMongo', SecutiryManager.requestIsAdmin, AdminController.writeAllToMongo
-		app.post '/admin/addquote', SecutiryManager.requestIsAdmin, AdminController.addQuote
-		app.post '/admin/syncUserToSubscription', SecutiryManager.requestIsAdmin, AdminController.syncUserToSubscription
-		app.post '/admin/flushProjectToTpds', SecutiryManager.requestIsAdmin, AdminController.flushProjectToTpds
-		app.post '/admin/pollUsersWithDropbox', SecutiryManager.requestIsAdmin, AdminController.pollUsersWithDropbox
-		app.post '/admin/updateProjectCompiler', SecutiryManager.requestIsAdmin, AdminController.updateProjectCompiler
+		app.get  '/admin', SecurityManager.requestIsAdmin, AdminController.index
+		app.post '/admin/closeEditor', SecurityManager.requestIsAdmin, AdminController.closeEditor
+		app.post '/admin/dissconectAllUsers', SecurityManager.requestIsAdmin, AdminController.dissconectAllUsers
+		app.post '/admin/writeAllDocsToMongo', SecurityManager.requestIsAdmin, AdminController.writeAllToMongo
+		app.post '/admin/addquote', SecurityManager.requestIsAdmin, AdminController.addQuote
+		app.post '/admin/syncUserToSubscription', SecurityManager.requestIsAdmin, AdminController.syncUserToSubscription
+		app.post '/admin/flushProjectToTpds', SecurityManager.requestIsAdmin, AdminController.flushProjectToTpds
+		app.post '/admin/pollUsersWithDropbox', SecurityManager.requestIsAdmin, AdminController.pollUsersWithDropbox
+		app.post '/admin/updateProjectCompiler', SecurityManager.requestIsAdmin, AdminController.updateProjectCompiler
 
 
 		app.get '/perfTest', (req,res)->
 		app.get '/perfTest', (req,res)->
 			res.send("hello")
 			res.send("hello")
@@ -190,7 +188,7 @@ module.exports = class Router
 
 
 		app.get '/health_check', HealthCheckController.check
 		app.get '/health_check', HealthCheckController.check
 
 
-		app.get "/status/compiler/:Project_id", SecutiryManager.requestCanAccessProject, (req, res) ->
+		app.get "/status/compiler/:Project_id", SecurityManager.requestCanAccessProject, (req, res) ->
 			sendRes = _.once (statusCode, message)->
 			sendRes = _.once (statusCode, message)->
 				res.writeHead statusCode
 				res.writeHead statusCode
 				res.end message
 				res.end message

+ 5 - 1
services/web/app/views/templates.jade

@@ -182,7 +182,11 @@
 					button#downloadPdf.btn Download
 					button#downloadPdf.btn Download
 					button#downloadLinksButton.btn.dropdown-toggle(data-toggle="dropdown")
 					button#downloadLinksButton.btn.dropdown-toggle(data-toggle="dropdown")
 						span.caret
 						span.caret
-					ul.dropdown-menu#downloadLinks
+					ul.dropdown-menu
+						#downloadLinks
+						li.divider
+						li.delete-cached-files
+							a(href="#") Clear cached files
 				.btn-group.pull-right(data-toggle="buttons-radio")
 				.btn-group.pull-right(data-toggle="buttons-radio")
 					button(type="button", title="Flat view")#flatViewButton.btn
 					button(type="button", title="Flat view")#flatViewButton.btn
 						i.icon-flatview
 						i.icon-flatview

+ 1 - 0
services/web/public/coffee/pdf/CompiledView.coffee

@@ -51,6 +51,7 @@ define [
 			"click #splitViewButton": ->
 			"click #splitViewButton": ->
 				$.localStorage("layout.pdf", "split")
 				$.localStorage("layout.pdf", "split")
 				@options.manager.switchToSplitView()
 				@options.manager.switchToSplitView()
+			"click .delete-cached-files > a": -> @options.manager.deleteCachedFiles()
 
 
 		initialize: (@options) ->
 		initialize: (@options) ->
 			@ide = @options.ide
 			@ide = @options.ide

+ 23 - 0
services/web/public/coffee/pdf/PdfManager.coffee

@@ -187,3 +187,26 @@ define [
 
 
 		downloadPdf: () ->
 		downloadPdf: () ->
 			@ide.mainAreaManager.setIframeSrc "/project/#{@ide.project_id}/output/output.pdf?popupDownload=true"
 			@ide.mainAreaManager.setIframeSrc "/project/#{@ide.project_id}/output/output.pdf?popupDownload=true"
+
+		deleteCachedFiles: () ->
+			modal = new Modal
+				title: "Clear cache?"
+				message: "This will clear all hidden LaTeX files like .aux, .bbl, etc, from our compile server. You generally don't need to do this unless you're having trouble with references. Your project files will not be deleted or changed."
+				buttons: [{
+					text: "Cancel"
+				}, {
+					text: "Clear from cache",
+					class: "btn-primary",
+					close: false
+					callback: ($button) =>
+						$button.text("Clearing...")
+						$button.prop("disabled", true)
+						$.ajax({
+							url: "/project/#{@ide.project_id}/output"
+							type: "DELETE"
+							headers:
+								"X-CSRF-Token": window.csrfToken
+							complete: () -> modal.remove()
+						})
+
+				}]

+ 23 - 4
services/web/test/UnitTests/coffee/Compile/CompileControllerTests.coffee

@@ -16,7 +16,7 @@ describe "CompileController", ->
 				apis:
 				apis:
 					clsi:
 					clsi:
 						url: "clsi.example.com"
 						url: "clsi.example.com"
-			"request": @request = {}
+			"request": @request = sinon.stub()
 			"../../models/Project": Project: @Project = {}
 			"../../models/Project": Project: @Project = {}
 			"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
 			"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
 			"../../infrastructure/Metrics": @Metrics =  { inc: sinon.stub() }
 			"../../infrastructure/Metrics": @Metrics =  { inc: sinon.stub() }
@@ -68,15 +68,23 @@ describe "CompileController", ->
 
 
 	describe "proxyToClsi", ->
 	describe "proxyToClsi", ->
 		beforeEach ->
 		beforeEach ->
-			@request.get = sinon.stub().returns(@proxy = {
+			@request.returns(@proxy = {
 				pipe: sinon.stub()
 				pipe: sinon.stub()
 				on: sinon.stub()
 				on: sinon.stub()
 			})
 			})
+			@upstream =
+				statusCode: 204
+				headers: { "mock": "header" }
+			@req.method = "mock-method"
 			@CompileController.proxyToClsi(@url = "/test", @req, @res, @next)
 			@CompileController.proxyToClsi(@url = "/test", @req, @res, @next)
 
 
 		it "should open a request to the CLSI", ->
 		it "should open a request to the CLSI", ->
-			@request.get
-				.calledWith(url: "#{@settings.apis.clsi.url}#{@url}", timeout: 60 * 1000)
+			@request
+				.calledWith(
+					method: @req.method
+					url: "#{@settings.apis.clsi.url}#{@url}",
+					timeout: 60 * 1000
+				)
 				.should.equal true
 				.should.equal true
 
 
 		it "should pass the request on to the client", ->
 		it "should pass the request on to the client", ->
@@ -87,6 +95,17 @@ describe "CompileController", ->
 		it "should bind an error handle to the request proxy", ->
 		it "should bind an error handle to the request proxy", ->
 			@proxy.on.calledWith("error").should.equal true
 			@proxy.on.calledWith("error").should.equal true
 
 
+	describe "deleteAuxFiles", ->
+		beforeEach ->
+			@CompileController.proxyToClsi = sinon.stub()
+			@req.params =
+				Project_id: @project_id
+			@CompileController.deleteAuxFiles @req, @res, @next
+
+		it "should proxy to the CLSI", ->
+			@CompileController.proxyToClsi
+				.calledWith("/project/#{@project_id}", @req, @res, @next)
+				.should.equal true
 
 
 	describe "compileAndDownloadPdf", ->
 	describe "compileAndDownloadPdf", ->
 		beforeEach ->
 		beforeEach ->