diff --git a/Gemfile.lock b/Gemfile.lock index 6253088e..812bdaf2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -50,8 +50,6 @@ GEM bootstrap-will_paginate (0.0.10) will_paginate builder (3.2.2) - byebug (4.0.5) - columnize (= 0.9.0) capistrano (3.3.5) capistrano-stats (~> 1.1.0) i18n @@ -96,7 +94,6 @@ GEM execjs coffee-script-source (1.9.1) colorize (0.7.7) - columnize (0.9.0) concurrent-ruby (0.8.0) ref (~> 1.0, >= 1.0.5) concurrent-ruby (0.8.0-java) @@ -110,6 +107,7 @@ GEM excon (>= 0.38.0) json erubis (2.7.0) + eventmachine (1.0.8) excon (0.45.2) execjs (2.5.2) factory_girl (4.5.0) @@ -119,6 +117,9 @@ GEM railties (>= 3.0.0) faraday (0.9.1) multipart-post (>= 1.2, < 3) + faye-websocket (0.10.0) + eventmachine (>= 0.12.0) + websocket-driver (>= 0.5.1) ffi (1.9.8) ffi (1.9.8-java) forgery (0.6.0) @@ -302,6 +303,9 @@ GEM thread_safe (0.3.5) thread_safe (0.3.5-java) tilt (1.4.1) + tubesock (0.2.5) + rack (>= 1.5.0) + websocket (>= 1.1.0) turbolinks (2.5.3) coffee-rails tzinfo (1.2.2) @@ -315,6 +319,9 @@ GEM railties (>= 4.0) sprockets-rails (>= 2.0, < 4.0) websocket (1.2.1) + websocket-driver (0.6.2) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.2) will_paginate (3.0.7) xpath (2.0.0) nokogiri (~> 1.3) @@ -330,7 +337,6 @@ DEPENDENCIES better_errors binding_of_caller bootstrap-will_paginate - byebug capistrano (~> 3.3.0) capistrano-rails capistrano-rvm @@ -345,6 +351,7 @@ DEPENDENCIES database_cleaner docker-api (~> 1.21.1) factory_girl_rails (~> 4.0) + faye-websocket forgery highline ims-lti @@ -375,6 +382,7 @@ DEPENDENCIES sorcery spring thread_safe + tubesock turbolinks uglifier (>= 1.3.0) web-console (~> 2.0) diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js index 6d505efc..160cf315 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js @@ -11,6 +11,7 @@ $(function() { var FILENAME_URL_PLACEHOLDER = '{filename}'; var SUCCESSFULL_PERCENTAGE = 90; var THEME = 'ace/theme/textmate'; + var REMEMBER_TAB = false; var AUTOSAVE_INTERVAL = 15 * 1000; var editors = []; @@ -59,7 +60,7 @@ $(function() { if (event.type === 'error' || JSON.parse(event.data).code !== 200) { ajaxError(); - showTab(1); + showTab(0); } }; @@ -262,13 +263,11 @@ $(function() { var handleKeyPress = function(event) { if (event.which === ALT_1_KEY_CODE) { - showTab(0); - } else if (event.which === ALT_2_KEY_CODE) { showWorkspaceTab(event); + } else if (event.which === ALT_2_KEY_CODE) { + showTab(1); } else if (event.which === ALT_3_KEY_CODE) { showTab(2); - } else if (event.which === ALT_4_KEY_CODE) { - showTab(3); } else if (event.which === ALT_R_KEY_CODE) { $('#run').trigger('click'); } else if (event.which === ALT_S_KEY_CODE) { @@ -311,7 +310,7 @@ $(function() { }, 0).toFixed(2); $('#score').data('score', score); renderScore(); - showTab(3); + showTab(2); }; var stderrOutput = ''; @@ -364,7 +363,7 @@ $(function() { qa_api.executeCommand('syncOutput', [response]); } showStatus(response[0]); - showTab(2); + showTab(1); }; var hideSpinner = function() { @@ -719,7 +718,7 @@ $(function() { clearOutput(); $('#hint').fadeOut(); $('#flowrHint').fadeOut(); - showTab(2); + showTab(1); } var printOutput = function(output, colorize, index) { @@ -820,7 +819,7 @@ $(function() { stderr: message }, true, 0); sendError(message, response.id); - showTab(2); + showTab(1); }; } }); @@ -943,16 +942,21 @@ $(function() { var showOutput = function(event) { event.preventDefault(); - showTab(2); + showTab(1); $('#output').scrollTo($(this).attr('href')); }; var showRequestedTab = function() { - var regexp = /tab=(\d+)/; - if (regexp.test(window.location.search)) { - var index = regexp.exec(window.location.search)[1] - 1; + if(REMEMBER_TAB){ + var regexp = /tab=(\d+)/; + if (regexp.test(window.location.search)) { + var index = regexp.exec(window.location.search)[1] - 1; + } else { + var index = localStorage.tab; + } } else { - var index = localStorage.tab; + // else start with first tab. + var index = 0; } showTab(index); }; @@ -1008,7 +1012,7 @@ $(function() { var showWorkspaceTab = function(event) { event.preventDefault(); - showTab(1); + showTab(0); }; var stopCode = function(event) { @@ -1156,7 +1160,8 @@ $(function() { if (!msg.data) { return; } - msg.data = msg.data.replace(/(\r\n|\n|\r)/gm, "
"); + //msg.data = msg.data.replace(/(\r\n|\n|\r)/gm, "
"); + msg.data = msg.data.replace(/(\r)/gm, "\n"); var stream = {}; stream[msg.stream] = msg.data; printOutput(stream, true, 0); diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index f2d3390c..7a26627a 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -62,7 +62,7 @@ class ExercisesController < ApplicationController end def exercise_params - params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :team_id, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name) + params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :team_id, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name) end private :exercise_params diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb index b7940ed9..a1a804f1 100644 --- a/app/controllers/submissions_controller.rb +++ b/app/controllers/submissions_controller.rb @@ -138,8 +138,10 @@ class SubmissionsController < ApplicationController if (/^exit/.match(message)) kill_socket(tubesock) else - # Filter out information about user and working directory - if !(/root|workspace/.match(message)) + # Filter out information about run_command, test_command, user or working directory + run_command = @submission.execution_environment.run_command + test_command = @submission.execution_environment.test_command + if !(/root|workspace|#{run_command}|#{test_command}/.match(message)) parse_message(message, 'stdout', tubesock) end end diff --git a/app/views/exercises/_editor.html.slim b/app/views/exercises/_editor.html.slim index 986af92d..cc5dfe7e 100644 --- a/app/views/exercises/_editor.html.slim +++ b/app/views/exercises/_editor.html.slim @@ -1,6 +1,6 @@ #editor.row data-exercise-id=exercise.id data-message-depleted=t('exercises.editor.depleted') data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @exercise.execution_environment.permitted_execution_time) data-errors-url=execution_environment_errors_path(exercise.execution_environment) data-submissions-url=submissions_path data-user-id=@current_user.id - .col-sm-3 = render('editor_file_tree', files: @files) - #frames.col-sm-9 + div class=(@exercise.hide_file_tree ? 'hidden col-sm-3' : 'col-sm-3') = render('editor_file_tree', files: @files) + div id='frames' class=(@exercise.hide_file_tree ? 'col-sm-12' : 'col-sm-9') - @files.each do |file| = render('editor_frame', exercise: exercise, file: file) #autosave-label diff --git a/app/views/exercises/_form.html.slim b/app/views/exercises/_form.html.slim index 32365e4a..1002f78a 100644 --- a/app/views/exercises/_form.html.slim +++ b/app/views/exercises/_form.html.slim @@ -23,6 +23,10 @@ label = f.check_box(:public) = t('activerecord.attributes.exercise.public') + .checkbox + label + = f.check_box(:hide_file_tree) + = t('activerecord.attributes.exercise.hide_file_tree') h2 = t('activerecord.attributes.exercise.files') ul#files.list-unstyled = f.fields_for :files do |files_form| diff --git a/app/views/exercises/implement.html.slim b/app/views/exercises/implement.html.slim index b0a3f0e0..72ac1b2c 100644 --- a/app/views/exercises/implement.html.slim +++ b/app/views/exercises/implement.html.slim @@ -13,39 +13,29 @@ #development-environment ul.nav.nav-justified.nav-tabs role='tablist' li.active - a data-placement='top' data-toggle='tab' data-tooltip=true href='#instructions' role='tab' title=t('shared.tooltips.shortcut', shortcut: 'ALT + 1') - i.fa.fa-question - = t('activerecord.attributes.exercise.instructions') - li - a data-placement='top' data-toggle='tab' data-tooltip=true href='#workspace' role='tab' title=t('shared.tooltips.shortcut', shortcut: 'ALT + 2') + a data-placement='top' data-toggle='tab' data-tooltip=true href='#workspace' role='tab' title=t('shared.tooltips.shortcut', shortcut: 'ALT + 1') i.fa.fa-code = t('.workspace') li - a data-placement='top' data-toggle='tab' data-tooltip=true href='#outputInformation' role='tab' title=t('shared.tooltips.shortcut', shortcut: 'ALT + 3') + a data-placement='top' data-toggle='tab' data-tooltip=true href='#outputInformation' role='tab' title=t('shared.tooltips.shortcut', shortcut: 'ALT + 2') i.fa.fa-terminal = t('.output') li - a data-placement='top' data-toggle='tab' data-tooltip=true href='#progress' role='tab' title=t('shared.tooltips.shortcut', shortcut: 'ALT + 4') + a data-placement='top' data-toggle='tab' data-tooltip=true href='#progress' role='tab' title=t('shared.tooltips.shortcut', shortcut: 'ALT + 3') i.fa.fa-line-chart = t('.progress') hr .tab-content - #instructions.tab-pane.active - p = render_markdown(@exercise.instructions) - br - p.text-center - a#start.btn.btn-lg.btn-success - i.fa.fa-code - = t('.start') - #workspace.tab-pane = render('editor', exercise: @exercise, files: @files, submission: @submission) + #workspace.tab-pane.active = render('editor', exercise: @exercise, files: @files, submission: @submission) #outputInformation.tab-pane data-message-no-output=t('.no_output') #hint .panel.panel-warning .panel-heading = t('.hint') .panel-body .row + / #output-col1.col-sm-12 #output-col1 // todo set to full width if turtle isnt used #prompt.input-group.hidden @@ -62,7 +52,7 @@ #output-col2.col-lg-5.col-md-5 #turtlediv // todo what should the canvas default size be? - canvas#turtlecanvas.hidden style='border-style:solid;border-width:thin' + canvas#turtlecanvas.hidden width=400 height=400 style='border-style:solid;border-width:thin' #progress.tab-pane #results h2 = t('.results') diff --git a/app/views/exercises/show.html.slim b/app/views/exercises/show.html.slim index 6456c3c0..67185046 100644 --- a/app/views/exercises/show.html.slim +++ b/app/views/exercises/show.html.slim @@ -14,6 +14,7 @@ h1 = row(label: 'exercise.team', value: @exercise.team ? link_to(@exercise.team, @exercise.team) : nil) = row(label: 'exercise.maximum_score', value: @exercise.maximum_score) = row(label: 'exercise.public', value: @exercise.public?) += row(label: 'exercise.hide_file_tree', value: @exercise.hide_file_tree?) = row(label: 'exercise.embedding_parameters') do = content_tag(:input, nil, class: 'form-control', readonly: true, value: embedding_parameters(@exercise)) diff --git a/config/docker.yml.erb b/config/docker.yml.erb index cf38ac79..b44497fd 100644 --- a/config/docker.yml.erb +++ b/config/docker.yml.erb @@ -7,7 +7,9 @@ default: &default development: <<: *default host: tcp://192.168.59.104:2376 - workspace_root: <%= File.join('/', 'shared', Rails.env) %> + ws_host: ws://192.168.59.104:2376 + #workspace_root: <%= File.join('/', 'shared', Rails.env) %> + workspace_root: <%= Rails.root.join('tmp', 'files', Rails.env) %> production: <<: *default diff --git a/config/locales/de.yml b/config/locales/de.yml index cb8ef305..9cb546b3 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -28,6 +28,7 @@ de: execution_environment: Ausführungsumgebung execution_environment_id: Ausführungsumgebung files: Dateien + hide_file_tree: Dateibaum verstecken instructions: Anweisungen maximum_score: Erreichbare Punktzahl public: Öffentlich diff --git a/config/locales/en.yml b/config/locales/en.yml index e726557d..d7fd84a9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -28,6 +28,7 @@ en: execution_environment: Execution Environment execution_environment_id: Execution Environment files: Files + hide_file_tree: Hide File Tree instructions: Instructions maximum_score: Maximum Score public: Public diff --git a/db/migrate/20150922125415_add_hide_file_tree_to_exercises.rb b/db/migrate/20150922125415_add_hide_file_tree_to_exercises.rb new file mode 100644 index 00000000..9890c35b --- /dev/null +++ b/db/migrate/20150922125415_add_hide_file_tree_to_exercises.rb @@ -0,0 +1,5 @@ +class AddHideFileTreeToExercises < ActiveRecord::Migration + def change + add_column :exercises, :hide_file_tree, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 7f3be339..d895da3f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150903152727) do +ActiveRecord::Schema.define(version: 20150922125415) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -79,6 +79,7 @@ ActiveRecord::Schema.define(version: 20150903152727) do t.string "user_type" t.string "token" t.integer "team_id" + t.boolean "hide_file_tree" end create_table "external_users", force: true do |t| diff --git a/lib/py_unit_adapter.rb b/lib/py_unit_adapter.rb index 29a47ddf..0e80c593 100644 --- a/lib/py_unit_adapter.rb +++ b/lib/py_unit_adapter.rb @@ -1,5 +1,5 @@ class PyUnitAdapter < TestingFrameworkAdapter - COUNT_REGEXP = /Ran (\d+) tests/ + COUNT_REGEXP = /Ran (\d+) test/ FAILURES_REGEXP = /FAILED \(failures=(\d+)\)/ def self.framework_name diff --git a/webpython/Dockerfile b/webpython/Dockerfile index 76eae9dc..54d6d4ad 100644 --- a/webpython/Dockerfile +++ b/webpython/Dockerfile @@ -2,10 +2,11 @@ FROM ubuntu:14.04 MAINTAINER "Martin v. Löwis" RUN locale-gen en_US.UTF-8 ENV LANG en_US.UTF-8 +ENV PYTHONPATH $PYTHONPATH:/usr/lib/python3.4:/workspace +ENV PATH $PATH:/usr/lib/python3.4 ADD assess.py /usr/lib/python3.4/assess.py ADD webpython.py /usr/lib/python3.4/webpython.py RUN rm /usr/lib/python3.4/turtle.py ADD turtle.py /usr/lib/python3.4/turtle.py RUN adduser --disabled-password --gecos Python python -USER python -WORKDIR /usr/lib/python3.4 +USER python \ No newline at end of file