diff --git a/.travis.yml b/.travis.yml index 0dca2ec6..40c85850 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ language: ruby rvm: - 2.1.5 - 2.2.1 -script: bundle exec rspec --tag ~docker +script: bundle exec rspec diff --git a/app/assets/javascripts/editor.js.erb b/app/assets/javascripts/editor.js.erb index 2d73bbf0..a46667ae 100644 --- a/app/assets/javascripts/editor.js.erb +++ b/app/assets/javascripts/editor.js.erb @@ -14,21 +14,18 @@ $(function() { var REMEMBER_TAB = false; var AUTOSAVE_INTERVAL = 15 * 1000; var REQUEST_FOR_COMMENTS_DELAY = 3 * 60 * 1000; - var NONE = 0; - var WEBSOCKET = 1; - var SERVER_SEND_EVENT = 2; var editors = []; var editor_for_file = new Map(); var regex_for_language = new Map(); var tracepositions_regex; + var resetTurtle = true; var active_file = undefined; var active_frame = undefined; var running = false; var qa_api = undefined; var output_mode_is_streaming = true; - var runmode = NONE; var websocket, turtlescreen, @@ -63,18 +60,6 @@ $(function() { $('#output pre').remove(); }; - var closeEventSource = function(event) { - event.target.close(); - hideSpinner(); - running = false; - toggleButtonStates(); - - if (event.type === 'error' || JSON.parse(event.data).code !== 200) { - ajaxError(); - showTab(0); - } - }; - var collectFiles = function() { var editable_editors = _.filter(editors, function(editor) { return !editor.getReadOnly(); @@ -188,44 +173,8 @@ $(function() { }); }; - var evaluateCode = function(url, streamed, callback) { - (streamed ? evaluateCodeWithStreamedResponse : evaluateCodeWithoutStreamedResponse)(url, callback); - }; - - var evaluateCodeWithStreamedResponse = function(url, onmessageFunction) { - initWebsocketConnection(url, onmessageFunction); - - // TODO only init turtle when required - initTurtle(); - - // TODO reimplement via websocket messsages - /*var event_source = new EventSource(url); - event_source.addEventListener('hint', renderHint); - event_source.addEventListener('info', storeContainerInformation); - - if ($('#flowrHint').isPresent()) { - event_source.addEventListener('output', handleStderrOutputForFlowr); - event_source.addEventListener('close', handleStderrOutputForFlowr); - } - - if (qa_api) { - event_source.addEventListener('close', handleStreamedResponseForCodePilot); - }*/ - }; - - var handleStreamedResponseForCodePilot = function(event) { - qa_api.executeCommand('syncOutput', [chunkBuffer]); - chunkBuffer = [{streamedResponse: true}]; - } - - var evaluateCodeWithoutStreamedResponse = function(url, callback) { - var jqxhr = ajax({ - method: 'GET', - url: url - }); - jqxhr.always(hideSpinner); - jqxhr.done(callback); - jqxhr.fail(ajaxError); + var evaluateCode = function(url, callback) { + initWebsocketConnection(url, callback); }; var fileActionsAvailable = function() { @@ -521,10 +470,6 @@ $(function() { }, REQUEST_FOR_COMMENTS_DELAY); }; - var isActiveFileBinary = function() { - return 'binary' in active_frame.data(); - }; - var isActiveFileExecutable = function() { return 'executable' in active_frame.data(); }; @@ -574,21 +519,6 @@ $(function() { panel.find('.row .col-sm-9').eq(4).find('a').attr('href', '#output-' + index); }; - var chunkBuffer = [{streamedResponse: true}]; - - var printChunk = function(event) { - var output = JSON.parse(event.data); - if (output) { - printOutput(output, true, 0); - // send test response to QA - // we are expecting an array of outputs: - if (qa_api) { - chunkBuffer.push(output); - } - } else { - resetOutputTab(); - } - }; var resetOutputTab = function() { clearOutput(); @@ -769,14 +699,13 @@ $(function() { var runCode = function(event) { event.preventDefault(); if ($('#run').is(':visible')) { - runmode = WEBSOCKET; createSubmission(this, null, function(response) { $('#stop').data('url', response.stop_url); running = true; showSpinner($('#run')); toggleButtonStates(); var url = response.run_url.replace(FILENAME_URL_PLACEHOLDER, active_file.filename); - evaluateCode(url, true, function(evt) { parseCanvasMessage(evt.data, true); }); + evaluateCode(url, function(evt) { parseCanvasMessage(evt.data, true); }); }); } }; @@ -807,11 +736,10 @@ $(function() { var scoreCode = function(event) { event.preventDefault(); - runmode = SERVER_SEND_EVENT; createSubmission(this, null, function(response) { showSpinner($('#assess')); var url = response.score_url; - evaluateCode(url, true, handleScoringResponse); + evaluateCode(url, handleScoringResponse); }); }; @@ -917,31 +845,11 @@ $(function() { var stopCode = function(event) { event.preventDefault(); - if ($('#stop').is(':visible')) { - if(runmode == WEBSOCKET){ - killWebsocketAndContainer(); - } else if (runmode == SERVER_SEND_EVENT) { - stopCodeServerSendEvent(event); - } - runmode = NONE; + if (isActiveFileStoppable()) { + killWebsocketAndContainer(); } }; - var stopCodeServerSendEvent = function(event){ - var jqxhr = ajax({ - data: { - container_id: $('#stop').data('container').id - }, - url: $('#stop').data('url') - }); - jqxhr.always(function() { - hideSpinner(); - running = false; - toggleButtonStates(); - }); - jqxhr.fail(ajaxError); - }; - var killWebsocketAndContainer = function() { if (websocket.readyState != WebSocket.OPEN) { return; @@ -949,28 +857,17 @@ $(function() { websocket.send(JSON.stringify({cmd: 'exit'})); websocket.flush(); websocket.close(); + + if(turtlescreen != null){ + resetTurtle = true; + } + hideSpinner(); running = false; toggleButtonStates(); hidePrompt(); } - // todo set this from websocket command, required to e.g. stop container - var storeContainerInformation = function(event) { - var container_information = JSON.parse(event.data); - $('#stop').data('container', container_information); - - if (_.size(container_information.port_bindings) > 0) { - $.flash.info({ - icon: ['fa', 'fa-exchange'], - text: _.map(container_information.port_bindings, function(key, value) { - var url = window.location.protocol + '//' + window.location.hostname + ':' + key; - return $('#run').data('message-network').replace('%{port}', value).replace(/%{address}/g, url); - }).join('\n') - }); - } - }; - var storeTab = function(event) { localStorage.tab = $(event.target).parent().index(); }; @@ -990,7 +887,7 @@ $(function() { createSubmission(this, null, function(response) { showSpinner($('#test')); var url = response.test_url.replace(FILENAME_URL_PLACEHOLDER, active_file.filename); - evaluateCode(url, true, handleTestResponse); + evaluateCode(url, handleTestResponse); }); } }; @@ -1027,10 +924,11 @@ $(function() { // clear canvas // turtlecanvas.getContext("2d").clearRect(0, 0, turtlecanvas.width, turtlecanvas.height); + if(resetTurtle) { turtlescreen = new Turtle(websocket, turtlecanvas); - if ($('#run').isPresent()) { - $('#run').bind('click', hideCanvas); - } + showCanvas(); + resetTurtle = false; + } }; var initPrompt = function() { @@ -1058,10 +956,12 @@ $(function() { printWebsocketOutput(msg); break; case 'turtle': + initTurtle(); showCanvas(); handleTurtleCommand(msg); break; case 'turtlebatch': + initTurtle(); showCanvas(); handleTurtlebatchCommand(msg); break; diff --git a/app/views/exercises/implement.html.slim b/app/views/exercises/implement.html.slim index 0c5e109b..1feab189 100644 --- a/app/views/exercises/implement.html.slim +++ b/app/views/exercises/implement.html.slim @@ -38,7 +38,7 @@ / #output-col1.col-sm-12 #output-col1 // todo set to full width if turtle isnt used - #prompt.input-group.hidden + #prompt.input-group.hidden.col-lg-7.col-md-7.two-column span.input-group-addon data-prompt=t('exercises.editor.input') = t('exercises.editor.input') input#prompt-input.form-control type='text' span.input-group-btn diff --git a/config/application.rb b/config/application.rb index 4b2a543a..68350af1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -30,6 +30,8 @@ module CodeOcean config.autoload_paths << Rails.root.join('lib') config.eager_load_paths << Rails.root.join('lib') + config.assets.precompile += %w( markdown-buttons.png ) + case (RUBY_ENGINE) when 'ruby' # ... diff --git a/config/nginx.conf b/config/nginx.conf deleted file mode 100644 index 32d4f34f..00000000 --- a/config/nginx.conf +++ /dev/null @@ -1,45 +0,0 @@ -upstream puma { - server unix:///var/www/app/shared/tmp/sockets/puma.sock; -} - -server { - listen 80 default deferred; - return 301 https://codeocean.openhpi.de$request_uri; - server_name codeocean.openhpi.de; -} - -server { - client_max_body_size 4G; - error_page 500 502 503 504 /500.html; - keepalive_timeout 10; - listen 443 ssl; - root /var/www/app/current/public; - server_name codeocean.openhpi.de; - try_files $uri @puma; - - ssl_certificate /etc/nginx/ssl/ssl-bundle.crt; - ssl_certificate_key /etc/nginx/ssl/server.key; - ssl_ciphers HIGH:!ADH:!EXPORT56:RC4+RSA:+MEDIUM; - ssl_prefer_server_ciphers on; - ssl_protocols SSLv3 TLSv1; - ssl_session_timeout 5m; - - location / { - access_log /var/www/app/current/log/nginx.access.log; - error_log /var/www/app/current/log/nginx.error.log; - proxy_http_version 1.1; - proxy_pass http://puma; - proxy_read_timeout 900; - proxy_redirect off; - proxy_set_header Connection ''; - proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - location ^~ /assets/ { - add_header Cache-Control public; - expires max; - gzip_static on; - } -}