diff --git a/.travis.yml b/.travis.yml index 1a5b99f1..08e44380 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ services: addons: code_climate: repo_token: 53a2c2608c848714e96f6a1fc0365dcfdfec051f7827d50cea965ea625f49734 + postgresql: "9.5" before_install: - export DISPLAY=:99.0 diff --git a/Gemfile b/Gemfile index 65cb5fe8..afd0aeff 100644 --- a/Gemfile +++ b/Gemfile @@ -21,7 +21,7 @@ gem 'pg', platform: :ruby gem 'pry-byebug' gem 'puma', '~> 2.15.3' gem 'pundit' -gem 'rails', '~> 4.1.13' +gem 'rails', '4.2.5' gem 'rails-i18n', '~> 4.0.0' gem 'ransack' gem 'rubytree' diff --git a/Gemfile.lock b/Gemfile.lock index bd8caf11..166109fe 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,40 +2,49 @@ GEM remote: https://rubygems.org/ specs: ZenTest (4.11.0) - actionmailer (4.1.14.1) - actionpack (= 4.1.14.1) - actionview (= 4.1.14.1) + actionmailer (4.2.5) + actionpack (= 4.2.5) + actionview (= 4.2.5) + activejob (= 4.2.5) mail (~> 2.5, >= 2.5.4) - actionpack (4.1.14.1) - actionview (= 4.1.14.1) - activesupport (= 4.1.14.1) - rack (~> 1.5.2) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.5) + actionview (= 4.2.5) + activesupport (= 4.2.5) + rack (~> 1.6) rack-test (~> 0.6.2) - actionview (4.1.14.1) - activesupport (= 4.1.14.1) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (4.2.5) + activesupport (= 4.2.5) builder (~> 3.1) erubis (~> 2.7.0) - activemodel (4.1.14.1) - activesupport (= 4.1.14.1) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + activejob (4.2.5) + activesupport (= 4.2.5) + globalid (>= 0.3.0) + activemodel (4.2.5) + activesupport (= 4.2.5) builder (~> 3.1) - activerecord (4.1.14.1) - activemodel (= 4.1.14.1) - activesupport (= 4.1.14.1) - arel (~> 5.0.0) + activerecord (4.2.5) + activemodel (= 4.2.5) + activesupport (= 4.2.5) + arel (~> 6.0) activerecord-jdbc-adapter (1.3.19) activerecord (>= 2.2) activerecord-jdbcpostgresql-adapter (1.3.19) activerecord-jdbc-adapter (~> 1.3.19) jdbc-postgres (>= 9.1) - activesupport (4.1.14.1) - i18n (~> 0.6, >= 0.6.9) + activesupport (4.2.5) + i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) - thread_safe (~> 0.1) + thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) addressable (2.4.0) - arel (5.0.1.20140414130214) - ast (2.2.0) + arel (6.0.4) + ast (2.3.0) autotest-rails (4.2.1) ZenTest (~> 4.5) bcrypt (3.1.10) @@ -129,6 +138,8 @@ GEM ffi (1.9.10) ffi (1.9.10-java) forgery (0.6.0) + globalid (0.3.7) + activesupport (>= 4.1.0) highline (1.7.8) hike (1.2.3) http-cookie (1.0.2) @@ -151,13 +162,15 @@ GEM json (1.8.3-java) jwt (1.5.1) kramdown (1.9.0) - mail (2.6.3) - mime-types (>= 1.16, < 3) + loofah (2.0.3) + nokogiri (>= 1.5.9) + mail (2.6.4) + mime-types (>= 1.16, < 4) method_source (0.8.2) - mime-types (2.99) - mini_portile2 (2.0.0) - minitest (5.9.0) - multi_json (1.11.2) + mime-types (2.99.3) + mini_portile2 (2.1.0) + minitest (5.10.1) + multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) net-scp (1.2.1) @@ -165,9 +178,9 @@ GEM net-ssh (3.0.2) netrc (0.10.3) newrelic_rpm (3.14.3.313) - nokogiri (1.6.7.2) - mini_portile2 (~> 2.0.0.rc2) - nokogiri (1.6.7.2-java) + nokogiri (1.7.0.1) + mini_portile2 (~> 2.1.0) + nokogiri (1.7.0.1-java) nyan-cat-formatter (0.11) rspec (>= 2.99, >= 2.14.2, < 4) oauth (0.4.7) @@ -179,7 +192,7 @@ GEM rack (>= 1.2, < 3) pagedown-rails (1.1.4) railties (> 3.1) - parser (2.3.0.6) + parser (2.3.3.1) ast (~> 2.2) pg (0.18.4) polyamorous (1.3.0) @@ -201,31 +214,40 @@ GEM puma (2.15.3-java) pundit (1.1.0) activesupport (>= 3.0.0) - rack (1.5.5) + rack (1.6.5) rack-mini-profiler (0.10.1) rack (>= 1.2.0) rack-test (0.6.3) rack (>= 1.0) - rails (4.1.14.1) - actionmailer (= 4.1.14.1) - actionpack (= 4.1.14.1) - actionview (= 4.1.14.1) - activemodel (= 4.1.14.1) - activerecord (= 4.1.14.1) - activesupport (= 4.1.14.1) + rails (4.2.5) + actionmailer (= 4.2.5) + actionpack (= 4.2.5) + actionview (= 4.2.5) + activejob (= 4.2.5) + activemodel (= 4.2.5) + activerecord (= 4.2.5) + activesupport (= 4.2.5) bundler (>= 1.3.0, < 2.0) - railties (= 4.1.14.1) - sprockets-rails (~> 2.0) + railties (= 4.2.5) + sprockets-rails + rails-deprecated_sanitizer (1.0.3) + activesupport (>= 4.2.0.alpha) + rails-dom-testing (1.0.8) + activesupport (>= 4.2.0.beta, < 5.0) + nokogiri (~> 1.6) + rails-deprecated_sanitizer (>= 1.0.1) + rails-html-sanitizer (1.0.3) + loofah (~> 2.0) rails-i18n (4.0.8) i18n (~> 0.7) railties (~> 4.0) - railties (4.1.14.1) - actionpack (= 4.1.14.1) - activesupport (= 4.1.14.1) + railties (4.2.5) + actionpack (= 4.2.5) + activesupport (= 4.2.5) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.1.0) - rake (10.5.0) + rainbow (2.2.1) + rake (12.0.0) ransack (1.7.0) actionpack (>= 3.0) activerecord (>= 3.0) @@ -244,7 +266,7 @@ GEM rspec-mocks (~> 3.4.0) rspec-autotest (1.0.0) rspec-core (>= 2.99.0.beta1, < 4.0.0) - rspec-core (3.4.2) + rspec-core (3.4.4) rspec-support (~> 3.4.0) rspec-expectations (3.4.0) diff-lcs (>= 1.2.0, < 2.0) @@ -261,14 +283,15 @@ GEM rspec-mocks (~> 3.4.0) rspec-support (~> 3.4.0) rspec-support (3.4.1) - rubocop (0.37.2) - parser (>= 2.3.0.4, < 3.0) + rubocop (0.46.0) + parser (>= 2.3.1.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) - unicode-display_width (~> 0.3) - rubocop-rspec (1.4.0) - ruby-progressbar (1.7.5) + unicode-display_width (~> 1.0, >= 1.0.1) + rubocop-rspec (1.9.0) + rubocop (>= 0.42.0) + ruby-progressbar (1.8.1) rubytree (0.9.7) json (~> 1.8) structured_warnings (~> 0.2) @@ -317,7 +340,7 @@ GEM net-ssh (>= 2.8.0) structured_warnings (0.2.0) temple (0.7.6) - thor (0.19.1) + thor (0.19.4) thread_safe (0.3.5) thread_safe (0.3.5-java) tilt (1.4.1) @@ -335,7 +358,7 @@ GEM unf_ext unf (0.1.4-java) unf_ext (0.0.7.1) - unicode-display_width (0.3.1) + unicode-display_width (1.1.2) web-console (2.3.0) activemodel (>= 4.0) binding_of_caller (>= 0.7.2) @@ -396,7 +419,7 @@ DEPENDENCIES puma (~> 2.15.3) pundit rack-mini-profiler - rails (~> 4.1.13) + rails (= 4.2.5) rails-i18n (~> 4.0.0) rake ransack diff --git a/app/assets/javascripts/editor/execution.js.erb b/app/assets/javascripts/editor/execution.js.erb index 3cc9b262..668ca81a 100644 --- a/app/assets/javascripts/editor/execution.js.erb +++ b/app/assets/javascripts/editor/execution.js.erb @@ -2,8 +2,11 @@ CodeOceanEditorWebsocket = { websocket: null, createSocketUrl: function(url) { - var rel_url_root = '<%= (defined? config.relative_url_root) && config.relative_url_root != nil && config.relative_url_root != "" ? config.relative_url_root : "" %>'; - return '<%= DockerClient.config['ws_client_protocol'] %>' + window.location.hostname + ':' + rel_url_root + window.location.port + url; + var sockURL = new URL(window.location); + sockURL.pathname = url; + sockURL.protocol = '<%= DockerClient.config['ws_client_protocol'] %>'; + + return sockURL.toString(); }, initializeSocket: function(url) { diff --git a/app/assets/javascripts/editor/participantsupport.js.erb b/app/assets/javascripts/editor/participantsupport.js.erb index 5ea4cc9e..91e9f0d1 100644 --- a/app/assets/javascripts/editor/participantsupport.js.erb +++ b/app/assets/javascripts/editor/participantsupport.js.erb @@ -59,6 +59,8 @@ CodeOceanEditorCodePilot = { } }; +//Request for comments does currently not work on staging platform (no relative root_url used here). +//To fix this rely on ruby routes CodeOceanEditorRequestForComments = { requestComments: function () { var user_id = $('#editor').data('user-id'); diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b1a4323f..617bab02 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -10,7 +10,6 @@ class ApplicationController < ActionController::Base rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized def current_user - ::NewRelic::Agent.add_custom_parameters({ external_user_id: session[:external_user_id], session_user_id: session[:user_id] }) @current_user ||= ExternalUser.find_by(id: session[:external_user_id]) || login_from_session || login_from_other_sources end diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 5287d94c..7c168ec6 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -2,6 +2,7 @@ require 'oauth/request_proxy/rack_request' module Lti extend ActiveSupport::Concern + include LtiHelper MAXIMUM_SCORE = 1 MAXIMUM_SESSION_AGE = 60.minutes @@ -14,10 +15,18 @@ module Lti end private :build_tool_provider - def clear_lti_session_data - session.delete(:consumer_id) - session.delete(:external_user_id) - session.delete(:lti_parameters) + # exercise_id.nil? ==> the user has logged out. All session data is to be destroyed + # exercise_id.exists? ==> the user has submitted the results of an exercise to the consumer. + # Only the lti_parameters are deleted. + def clear_lti_session_data(exercise_id = nil, user_id = nil, consumer_id = nil) + if (exercise_id.nil?) + session.delete(:consumer_id) + session.delete(:external_user_id) + else + LtiParameter.destroy_all(consumers_id: consumer_id, + external_users_id: user_id, + exercises_id: exercise_id) + end end private :clear_lti_session_data @@ -43,11 +52,6 @@ module Lti end private :external_user_name - def lti_outcome_service? - session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') - end - private :lti_outcome_service? - def refuse_lti_launch(options = {}) return_to_consumer(lti_errorlog: options[:message], lti_errormsg: t('sessions.oauth.failure')) end @@ -94,10 +98,19 @@ module Lti end private :return_to_consumer - def send_score(score) + def send_score(exercise_id, score, user_id) ::NewRelic::Agent.add_custom_parameters({ score: score, session: session }) fail(Error, "Score #{score} must be between 0 and #{MAXIMUM_SCORE}!") unless (0..MAXIMUM_SCORE).include?(score) - provider = build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters]) + + if session[:consumer_id] + lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], + external_users_id: user_id, + exercises_id: exercise_id).first + + consumer = Consumer.find_by(id: session[:consumer_id]) + provider = build_tool_provider(consumer: consumer, parameters: lti_parameter.lti_parameters) + end + if provider.nil? {status: 'error'} elsif provider.outcome_service? @@ -116,9 +129,19 @@ module Lti private :set_current_user def store_lti_session_data(options = {}) + exercise = Exercise.where(token: options[:parameters][:custom_token]).first + exercise_id = exercise.id unless exercise.nil? + + current_user = ExternalUser.find_or_create_by(consumer_id: options[:consumer].id, external_id: options[:parameters][:user_id].to_s) + lti_parameters = LtiParameter.find_or_create_by(consumers_id: options[:consumer].id, + external_users_id: current_user.id, + exercises_id: exercise_id) + + lti_parameters.lti_parameters = options[:parameters].slice(*SESSION_PARAMETERS).to_json + lti_parameters.save! + session[:consumer_id] = options[:consumer].id - session[:external_user_id] = @current_user.id - session[:lti_parameters] = options[:parameters].slice(*SESSION_PARAMETERS) + session[:external_user_id] = current_user.id end private :store_lti_session_data diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index c6847a54..79314208 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -157,7 +157,14 @@ class ExercisesController < ApplicationController end def redirect_to_lti_return_path - path = lti_return_path(consumer_id: session[:consumer_id], submission_id: @submission.id, url: consumer_return_url(build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters]))) + lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], + external_users_id: @submission.user_id, + exercises_id: @submission.exercise_id).first + + path = lti_return_path(consumer_id: session[:consumer_id], + submission_id: @submission.id, + url: consumer_return_url(build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), + parameters: lti_parameter.lti_parameters))) respond_to do |format| format.html { redirect_to(path) } format.json { render(json: {redirect: path}) } @@ -221,7 +228,8 @@ class ExercisesController < ApplicationController def submit @submission = Submission.create(submission_params) score_submission(@submission) - if lti_outcome_service? + current_user = ExternalUser.find(@submission.user_id) + if !current_user.nil? && lti_outcome_service?(@submission.exercise_id, current_user.id, current_user.consumer_id) transmit_lti_score else redirect_after_submit @@ -230,7 +238,8 @@ class ExercisesController < ApplicationController def transmit_lti_score ::NewRelic::Agent.add_custom_parameters({ submission: @submission.id, normalized_score: @submission.normalized_score }) - response = send_score(@submission.normalized_score) + response = send_score(@submission.exercise_id, @submission.normalized_score, @submission.user_id) + if response[:status] == 'success' redirect_after_submit else diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index ce1418bb..e6bdac8c 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -21,7 +21,9 @@ class SessionsController < ApplicationController set_current_user store_lti_session_data(consumer: @consumer, parameters: params) store_nonce(params[:oauth_nonce]) - redirect_to(implement_exercise_path(@exercise), notice: t("sessions.create_through_lti.session_#{lti_outcome_service? ? 'with' : 'without'}_outcome", consumer: @consumer)) + redirect_to(implement_exercise_path(@exercise), + notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id , @consumer.id) ? 'with' : 'without'}_outcome", + consumer: @consumer)) end def destroy @@ -34,9 +36,8 @@ class SessionsController < ApplicationController end def destroy_through_lti - @consumer = Consumer.find_by(id: params[:consumer_id]) @submission = Submission.find(params[:submission_id]) - clear_lti_session_data + clear_lti_session_data(@submission.exercise_id, @submission.user_id, params[:consumer_id]) end def new diff --git a/app/helpers/exercise_helper.rb b/app/helpers/exercise_helper.rb index 7dcbb6f4..190a18f3 100644 --- a/app/helpers/exercise_helper.rb +++ b/app/helpers/exercise_helper.rb @@ -1,4 +1,6 @@ module ExerciseHelper + include LtiHelper + def embedding_parameters(exercise) "locale=#{I18n.locale}&token=#{exercise.token}" end diff --git a/app/helpers/lti_helper.rb b/app/helpers/lti_helper.rb new file mode 100644 index 00000000..f46974cd --- /dev/null +++ b/app/helpers/lti_helper.rb @@ -0,0 +1,10 @@ +module LtiHelper + def lti_outcome_service?(exercise_id, external_user_id, consumer_id) + return false if external_user_id == '' || consumer_id == '' + + lti_parameters = LtiParameter.where(consumers_id: consumer_id, + external_users_id: external_user_id, + exercises_id: exercise_id).lis_outcome_service_url? + !lti_parameters.nil? && lti_parameters.size > 0 + end +end \ No newline at end of file diff --git a/app/models/lti_parameter.rb b/app/models/lti_parameter.rb new file mode 100644 index 00000000..3351a6c9 --- /dev/null +++ b/app/models/lti_parameter.rb @@ -0,0 +1,9 @@ +class LtiParameter < ActiveRecord::Base + belongs_to :consumer, foreign_key: "consumers_id" + belongs_to :exercise, foreign_key: "exercises_id" + belongs_to :external_user, foreign_key: "external_users_id" + + scope :lis_outcome_service_url?, -> { + where("lti_parameters.lti_parameters ? 'lis_outcome_service_url'") + } +end \ No newline at end of file diff --git a/app/models/submission.rb b/app/models/submission.rb index 5a95587f..1abbbb84 100644 --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -28,17 +28,6 @@ class Submission < ActiveRecord::Base ancestors.merge(descendants).values end - [:download_file, :render, :run, :test].each do |action| - filename = FILENAME_URL_PLACEHOLDER.gsub(/\W/, '') - define_method("#{action}_url") do - Rails.application.routes.url_helpers.send(:"#{action}_submission_path", self, filename).sub(filename, FILENAME_URL_PLACEHOLDER) - end - end - - def download_url - Rails.application.routes.url_helpers.send(:download_submission_path, self) - end - def main_file collect_files.detect(&:main_file?) end @@ -56,12 +45,6 @@ class Submission < ActiveRecord::Base (normalized_score * 100).round end - [:score, :stop].each do |action| - define_method("#{action}_url") do - Rails.application.routes.url_helpers.send(:"#{action}_submission_path", self) - end - end - def siblings user.submissions.where(exercise_id: exercise_id) end diff --git a/app/views/exercises/_editor.html.slim b/app/views/exercises/_editor.html.slim index 6b14d3c8..56986673 100644 --- a/app/views/exercises/_editor.html.slim +++ b/app/views/exercises/_editor.html.slim @@ -1,11 +1,11 @@ -- external_user_id = @current_user.respond_to?(:external_id) ? @current_user.external_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') -#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 data-user-external-id=external_user_id +- external_user_external_id = @current_user.respond_to?(:external_id) ? @current_user.external_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') +- external_user_id = @current_user.respond_to?(:external_id) ? @current_user.id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') +- consumer_id = @current_user.respond_to?(:external_id) ? @current_user.consumer_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '') +#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 data-user-external-id=external_user_external_id div id="sidebar" class=(@exercise.hide_file_tree ? 'sidebar-col-collapsed' : 'sidebar-col') = render('editor_file_tree', exercise: @exercise, files: @files) - div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output') + div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id ) div id='frames' class='editor-col' #editor-buttons.btn-group.enforce-bottom-margin - // = render('editor_button', data: {:'data-message-success' => t('submissions.create.success'), :'data-placement' => 'top', :'data-tooltip' => true}, icon: 'fa fa-save', id: 'save', label: t('exercises.editor.save'), title: t('.tooltips.save')) - // .btn-group = render('editor_button', disabled: true, icon: 'fa fa-ban', id: 'dummy', label: t('exercises.editor.dummy')) = render('editor_button', icon: 'fa fa-desktop', id: 'render', label: t('exercises.editor.render')) = render('editor_button', data: {:'data-message-failure' => t('exercises.editor.run_failure'), :'data-message-network' => t('exercises.editor.network'), :'data-message-success' => t('exercises.editor.run_success'), :'data-placement' => 'top', :'data-tooltip' => true}, icon: 'fa fa-play', id: 'run', label: t('exercises.editor.run'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + r')) diff --git a/app/views/exercises/_editor_output.html.slim b/app/views/exercises/_editor_output.html.slim index ab09adac..4b255d5a 100644 --- a/app/views/exercises/_editor_output.html.slim +++ b/app/views/exercises/_editor_output.html.slim @@ -27,7 +27,7 @@ div id='output_sidebar_uncollapsed' class='hidden col-sm-12 enforce-bottom-margi .progress-bar role='progressbar' br - - if session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') + - if lti_outcome_service?(@exercise.id, external_user_id, consumer_id) p.text-center = render('editor_button', classes: 'btn-lg btn-success', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa fa-send', id: 'submit', label: t('exercises.editor.submit')) - else p.text-center = render('editor_button', classes: 'btn-lg btn-warning-outline', data: {:'data-placement' => 'bottom', :'data-tooltip' => true}, icon: 'fa fa-clock-o', id: 'submit_outdated', label: t('exercises.editor.exercise_deadline_passed'), title: t('exercises.editor.tooltips.exercise_deadline_passed')) diff --git a/app/views/sessions/destroy_through_lti.html.slim b/app/views/sessions/destroy_through_lti.html.slim index 8f1e89a8..3e55e0fc 100644 --- a/app/views/sessions/destroy_through_lti.html.slim +++ b/app/views/sessions/destroy_through_lti.html.slim @@ -3,6 +3,7 @@ h1 = t('.headline') p == t(".success_#{params[:outcome] ? 'with' : 'without'}_outcome", consumer: @consumer) ==< t(".finished_#{@consumer ? 'with' : 'without'}_consumer", consumer: @consumer, url: params[:url]) + ==< t(".do_not_use_backbutton", consumer: @consumer) h2 = t('shared.statistics') diff --git a/app/views/submissions/show.json.jbuilder b/app/views/submissions/show.json.jbuilder index 3b860684..07e199f4 100644 --- a/app/views/submissions/show.json.jbuilder +++ b/app/views/submissions/show.json.jbuilder @@ -1 +1,8 @@ -json.extract! @submission, :download_url, :download_file_url, :id, :score_url, :render_url, :run_url, :stop_url, :test_url, :files +json.extract! @submission, :id, :files +json.download_url download_submission_path(@submission) +json.score_url score_submission_path(@submission) +json.stop_url stop_submission_path(@submission) +json.download_file_url download_file_submission_path(@submission, 'a.').gsub(/a\.$/, '{filename}') +json.render_url render_submission_path(@submission, 'a.').gsub(/a\.$/, '{filename}') +json.run_url run_submission_path(@submission, 'a.').gsub(/a\.$/, '{filename}') +json.test_url test_submission_path(@submission, 'a.').gsub(/a\.$/, '{filename}') diff --git a/bin/rails b/bin/rails index 728cd85a..5191e692 100755 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,4 @@ #!/usr/bin/env ruby -APP_PATH = File.expand_path('../../config/application', __FILE__) +APP_PATH = File.expand_path('../../config/application', __FILE__) require_relative '../config/boot' require 'rails/commands' diff --git a/bin/setup b/bin/setup new file mode 100755 index 00000000..acdb2c13 --- /dev/null +++ b/bin/setup @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +require 'pathname' + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +Dir.chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file: + + puts "== Installing dependencies ==" + system "gem install bundler --conservative" + system "bundle check || bundle install" + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # system "cp config/database.yml.sample config/database.yml" + # end + + puts "\n== Preparing database ==" + system "bin/rake db:setup" + + puts "\n== Removing old logs and tempfiles ==" + system "rm -f log/*" + system "rm -rf tmp/cache" + + puts "\n== Restarting application server ==" + system "touch tmp/restart.txt" +end diff --git a/config/application.rb b/config/application.rb index 10a8537d..a9e3518b 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,13 +1,6 @@ require File.expand_path('../boot', __FILE__) -# Pick the frameworks you want: -require "active_model/railtie" -require "active_record/railtie" -require "action_controller/railtie" -require "action_mailer/railtie" -require "action_view/railtie" -require "sprockets/railtie" -# require "rails/test_unit/railtie" +require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. @@ -21,17 +14,22 @@ module CodeOcean # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. - config.time_zone = 'Berlin' + config.time_zone = 'UTC' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de config.i18n.available_locales = [:de, :en] + # Do not swallow errors in after_commit/after_rollback callbacks. + config.active_record.raise_in_transactional_callbacks = true + config.autoload_paths << Rails.root.join('lib') config.eager_load_paths << Rails.root.join('lib') config.assets.precompile += %w( markdown-buttons.png ) + config.active_record.schema_format = :sql + case (RUBY_ENGINE) when 'ruby' # ... @@ -43,5 +41,3 @@ module CodeOcean end end end - -Rails.application.config.assets.precompile += %w( markdown-buttons.png ) \ No newline at end of file diff --git a/config/boot.rb b/config/boot.rb index 5e5f0c1f..6b750f00 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,4 +1,3 @@ -# Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/config/environments/development.rb b/config/environments/development.rb index 10cc7bc8..5960bb24 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,7 +1,8 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - config.web_console.whitelisted_ips = '192.168.0.0/16' + config.web_console.whitelisted_ips = '192.168.0.0/16' + # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. @@ -13,8 +14,8 @@ Rails.application.configure do # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false - - config.action_mailer.perform_deliveries = true + + config.action_mailer.perform_deliveries = false # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false @@ -25,12 +26,21 @@ Rails.application.configure do # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true + + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = true + # Adds additional error checking when serving assets at runtime. # Checks for improperly declared sprockets dependencies. # Raises helpful error messages. config.assets.raise_runtime_errors = true - # Raise errors for missing translations. + # Raises error for missing translations config.action_view.raise_on_missing_translations = true BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP'] diff --git a/config/environments/production.rb b/config/environments/production.rb index 3c3fe0c5..23c4e5b4 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -16,11 +16,13 @@ Rails.application.configure do # Enable Rack::Cache to put a simple HTTP cache in front of your application # Add `rack-cache` to your Gemfile before enabling this. - # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. + # For large-scale production use, consider using a caching reverse proxy like + # NGINX, varnish or squid. # config.action_dispatch.rack_cache = true - # Disable Rails's static asset server (Apache or nginx will already do this). - config.serve_static_assets = false + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier @@ -29,20 +31,21 @@ Rails.application.configure do # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Generate digests for assets URLs. + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. config.assets.digest = true - # Version of your assets, change this if you want to expire all your assets. - config.assets.version = '1.0' + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # Set to :debug to see everything in the log. + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. config.log_level = :error # Prepend all log lines with the following tags. @@ -55,11 +58,7 @@ Rails.application.configure do # config.cache_store = :mem_cache_store # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.action_controller.asset_host = "http://assets.example.com" - - # Precompile additional assets. - # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. - # config.assets.precompile += %w( search.js ) + # config.action_controller.asset_host = 'http://assets.example.com' # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. @@ -72,9 +71,6 @@ Rails.application.configure do # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify - # Disable automatic flushing of the log to improve performance. - # config.autoflush_log = false - # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new diff --git a/config/environments/staging.rb b/config/environments/staging.rb index ca1a98bb..7caf841e 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -37,7 +37,7 @@ Rails.application.configure do # config.action_dispatch.rack_cache = true # Disable Rails's static asset server (Apache or nginx will already do this). - config.serve_static_assets = false + config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. # config.assets.js_compressor = :uglifier diff --git a/config/environments/test.rb b/config/environments/test.rb index 053f5b66..1c19f08b 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -12,8 +12,8 @@ Rails.application.configure do # preloads Rails for running tests, you may have to set it to true. config.eager_load = false - # Configure static asset server for tests with Cache-Control for performance. - config.serve_static_assets = true + # Configure static file server for tests with Cache-Control for performance. + config.serve_static_files = true config.static_cache_control = 'public, max-age=3600' # Show full error reports and disable caching. @@ -31,6 +31,9 @@ Rails.application.configure do # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test + # Randomize the order test cases are executed. + config.active_support.test_order = :random + # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 00000000..d74f7733 --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,12 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path +# Rails.application.config.assets.paths << Emoji.images_path + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. +# Rails.application.config.assets.precompile += %w( search.js ) +Rails.application.config.assets.precompile += %w( markdown-buttons.png ) \ No newline at end of file diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 1e5f1e1d..bdaed01f 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,3 +1,3 @@ # Be sure to restart your server when you modify this file. -Rails.application.config.session_store :cookie_store, key: '_hands-on-programming_session' +Rails.application.config.session_store :cookie_store, key: '_code_ocean_session' diff --git a/config/locales/de.yml b/config/locales/de.yml index 0695eda6..de6fe41a 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -217,10 +217,10 @@ de: submit: Code zur Bewertung abgeben test: Testen timeout: 'Ausführung gestoppt. Ihr Code hat die erlaubte Ausführungszeit von %{permitted_execution_time} Sekunden überschritten.' - exercise_deadline_passed: 'Die Abgabefrist für diese Aufgabe ist bereits abgelaufen.' + exercise_deadline_passed: 'Das Ergebnis kann nicht übertragen werden.' tooltips: save: Ihr Code wird automatisch gespeichert, wann immer Sie eine Datei herunterladen, ausführen oder testen. Explizites Speichern ist also selten notwendig. - exercise_deadline_passed: 'Die hier erzielten Punkte können nur bis zum Ablauf der Abgabefrist an die E-Learning-Plattform übertragen werden.' + exercise_deadline_passed: 'Entweder ist die Abgabefrist bereits abgelaufen oder Sie haben die Aufgabe nicht direkt über die E-Learning Plattform gestartet. (Möglicherweise haben Sie den Zurück Button Ihres Browsers benutzt nachdem Sie Ihre Aufgabe abgegeben haben?)' request_for_comments_sent: "Kommentaranfrage gesendet." editor_file_tree: file_root: Dateien @@ -386,6 +386,7 @@ de: score: Ihre Punktzahl success_with_outcome: 'Ihr Code wurde erfolgreich bewertet. Ihre Bewertung wurde an %{consumer} übermittelt.' success_without_outcome: Ihr Code wurde erfolgreich bewertet. + do_not_use_backbutton: Benutzen Sie nicht den "Zurück" Button des Browsers, um zu CodeOcean zurück zu kehren. Übungen müssen immer aus dem %{consumer} Kontext gestartet werden. new: forgot_password: Passwort vergessen? headline: Anmelden diff --git a/config/locales/en.yml b/config/locales/en.yml index 6d30f612..304d7d0f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,3 +1,24 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# To learn more, please read the Rails Internationalization guide +# available at http://guides.rubyonrails.org/i18n.html. + en: activerecord: attributes: @@ -217,10 +238,10 @@ en: submit: Submit Code For Assessment test: Test timeout: 'Execution stopped. Your code exceeded the permitted execution time of %{permitted_execution_time} seconds.' - exercise_deadline_passed: 'The deadline for this exercise has already passed' + exercise_deadline_passed: 'The score cannot be submitted.' tooltips: save: Your code is automatically saved whenever you download, run, or test it. Therefore, explicitly saving is rarely necessary. - exercise_deadline_passed: 'The results for this exercise can only be submitted to the e-learning platform before the deadline has passed.' + exercise_deadline_passed: 'Either the deadline has already passed or you did not directly access this page from the e-learning platform. (Did you use the Back button of your browser after submitting the score?)' request_for_comments_sent: "Request for comments sent." editor_file_tree: file_root: Files @@ -386,6 +407,7 @@ en: score: Your Score success_with_outcome: 'Your code has been successfully assessed. Your grade has been transmitted to %{consumer}.' success_without_outcome: Your code has been successfully assessed. + do_not_use_backbutton: Never use the browser's "Back" button to get back to CodeOcean. Always start an exercise from within %{consumer}. new: forgot_password: Forgot password? headline: Sign In @@ -466,3 +488,4 @@ en: previous_label: '← Previous Page' file_template: no_template_label: "Empty File" + diff --git a/db/migrate/20170112151637_create_lti_parameters.rb b/db/migrate/20170112151637_create_lti_parameters.rb new file mode 100644 index 00000000..c7613edf --- /dev/null +++ b/db/migrate/20170112151637_create_lti_parameters.rb @@ -0,0 +1,11 @@ +class CreateLtiParameters < ActiveRecord::Migration + def change + create_table :lti_parameters do |t| + t.belongs_to :external_users + t.belongs_to :consumers + t.belongs_to :exercises + t.jsonb :lti_parameters, null: false, default: '{}' + t.timestamps + end + end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index 330f99d6..6f5accb0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,13 +11,13 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160907123009) do +ActiveRecord::Schema.define(version: 20161214144837) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" - create_table "code_harbor_links", force: true do |t| - t.string "oauth2token" + create_table "code_harbor_links", force: :cascade do |t| + t.string "oauth2token", limit: 255 t.datetime "created_at" t.datetime "updated_at" t.integer "user_id" @@ -25,10 +25,10 @@ ActiveRecord::Schema.define(version: 20160907123009) do add_index "code_harbor_links", ["user_id"], name: "index_code_harbor_links_on_user_id", using: :btree - create_table "comments", force: true do |t| + create_table "comments", force: :cascade do |t| t.integer "user_id" t.integer "file_id" - t.string "user_type" + t.string "user_type", limit: 255 t.integer "row" t.integer "column" t.text "text" @@ -39,15 +39,15 @@ ActiveRecord::Schema.define(version: 20160907123009) do add_index "comments", ["file_id"], name: "index_comments_on_file_id", using: :btree add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree - create_table "consumers", force: true do |t| - t.string "name" + create_table "consumers", force: :cascade do |t| + t.string "name", limit: 255 t.datetime "created_at" t.datetime "updated_at" - t.string "oauth_key" - t.string "oauth_secret" + t.string "oauth_key", limit: 255 + t.string "oauth_secret", limit: 255 end - create_table "errors", force: true do |t| + create_table "errors", force: :cascade do |t| t.integer "execution_environment_id" t.text "message" t.datetime "created_at" @@ -57,123 +57,123 @@ ActiveRecord::Schema.define(version: 20160907123009) do add_index "errors", ["submission_id"], name: "index_errors_on_submission_id", using: :btree - create_table "execution_environments", force: true do |t| - t.string "docker_image" - t.string "name" + create_table "execution_environments", force: :cascade do |t| + t.string "docker_image", limit: 255 + t.string "name", limit: 255 t.datetime "created_at" t.datetime "updated_at" - t.string "run_command" - t.string "test_command" - t.string "testing_framework" + t.string "run_command", limit: 255 + t.string "test_command", limit: 255 + t.string "testing_framework", limit: 255 t.text "help" - t.string "exposed_ports" + t.string "exposed_ports", limit: 255 t.integer "permitted_execution_time" t.integer "user_id" - t.string "user_type" + t.string "user_type", limit: 255 t.integer "pool_size" t.integer "file_type_id" t.integer "memory_limit" t.boolean "network_enabled" end - create_table "exercises", force: true do |t| + create_table "exercises", force: :cascade do |t| t.text "description" t.integer "execution_environment_id" - t.string "title" + t.string "title", limit: 255 t.datetime "created_at" t.datetime "updated_at" t.integer "user_id" t.text "instructions" t.boolean "public" - t.string "user_type" - t.string "token" + t.string "user_type", limit: 255 + t.string "token", limit: 255 t.boolean "hide_file_tree" t.boolean "allow_file_creation" - t.boolean "allow_auto_completion", default: false + t.boolean "allow_auto_completion", default: false end - create_table "external_users", force: true do |t| + create_table "external_users", force: :cascade do |t| t.integer "consumer_id" - t.string "email" - t.string "external_id" - t.string "name" + t.string "email", limit: 255 + t.string "external_id", limit: 255 + t.string "name", limit: 255 t.datetime "created_at" t.datetime "updated_at" end - create_table "file_templates", force: true do |t| - t.string "name" + create_table "file_templates", force: :cascade do |t| + t.string "name", limit: 255 t.text "content" t.integer "file_type_id" t.datetime "created_at" t.datetime "updated_at" end - create_table "file_types", force: true do |t| - t.string "editor_mode" - t.string "file_extension" + create_table "file_types", force: :cascade do |t| + t.string "editor_mode", limit: 255 + t.string "file_extension", limit: 255 t.integer "indent_size" - t.string "name" + t.string "name", limit: 255 t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" t.boolean "executable" t.boolean "renderable" - t.string "user_type" + t.string "user_type", limit: 255 t.boolean "binary" end - create_table "files", force: true do |t| + create_table "files", force: :cascade do |t| t.text "content" t.integer "context_id" - t.string "context_type" + t.string "context_type", limit: 255 t.integer "file_id" t.integer "file_type_id" t.boolean "hidden" - t.string "name" + t.string "name", limit: 255 t.boolean "read_only" t.datetime "created_at" t.datetime "updated_at" - t.string "native_file" - t.string "role" - t.string "hashed_content" - t.string "feedback_message" + t.string "native_file", limit: 255 + t.string "role", limit: 255 + t.string "hashed_content", limit: 255 + t.string "feedback_message", limit: 255 t.float "weight" - t.string "path" + t.string "path", limit: 255 t.integer "file_template_id" end add_index "files", ["context_id", "context_type"], name: "index_files_on_context_id_and_context_type", using: :btree - create_table "hints", force: true do |t| + create_table "hints", force: :cascade do |t| t.integer "execution_environment_id" - t.string "locale" + t.string "locale", limit: 255 t.text "message" - t.string "name" - t.string "regular_expression" + t.string "name", limit: 255 + t.string "regular_expression", limit: 255 t.datetime "created_at" t.datetime "updated_at" end - create_table "internal_users", force: true do |t| + create_table "internal_users", force: :cascade do |t| t.integer "consumer_id" - t.string "email" - t.string "name" - t.string "role" + t.string "email", limit: 255 + t.string "name", limit: 255 + t.string "role", limit: 255 t.datetime "created_at" t.datetime "updated_at" - t.string "crypted_password" - t.string "salt" - t.integer "failed_logins_count", default: 0 + t.string "crypted_password", limit: 255 + t.string "salt", limit: 255 + t.integer "failed_logins_count", default: 0 t.datetime "lock_expires_at" - t.string "unlock_token" - t.string "remember_me_token" + t.string "unlock_token", limit: 255 + t.string "remember_me_token", limit: 255 t.datetime "remember_me_token_expires_at" - t.string "reset_password_token" + t.string "reset_password_token", limit: 255 t.datetime "reset_password_token_expires_at" t.datetime "reset_password_email_sent_at" - t.string "activation_state" - t.string "activation_token" + t.string "activation_state", limit: 255 + t.string "activation_token", limit: 255 t.datetime "activation_token_expires_at" end @@ -182,29 +182,38 @@ ActiveRecord::Schema.define(version: 20160907123009) do add_index "internal_users", ["remember_me_token"], name: "index_internal_users_on_remember_me_token", using: :btree add_index "internal_users", ["reset_password_token"], name: "index_internal_users_on_reset_password_token", using: :btree - create_table "request_for_comments", force: true do |t| - t.integer "user_id", null: false - t.integer "exercise_id", null: false - t.integer "file_id", null: false + create_table "lti_parameters", force: :cascade do |t| + t.string "external_user_id" + t.integer "consumers_id" + t.integer "exercises_id" + t.jsonb "lti_parameters", default: {}, null: false t.datetime "created_at" t.datetime "updated_at" - t.string "user_type" + end + + create_table "request_for_comments", force: :cascade do |t| + t.integer "user_id", null: false + t.integer "exercise_id", null: false + t.integer "file_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.string "user_type", limit: 255 t.text "question" t.boolean "solved" t.integer "submission_id" end - create_table "submissions", force: true do |t| + create_table "submissions", force: :cascade do |t| t.integer "exercise_id" t.float "score" t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" - t.string "cause" - t.string "user_type" + t.string "cause", limit: 255 + t.string "user_type", limit: 255 end - create_table "testruns", force: true do |t| + create_table "testruns", force: :cascade do |t| t.boolean "passed" t.text "output" t.integer "file_id" diff --git a/db/structure.sql b/db/structure.sql new file mode 100644 index 00000000..4b290bdc --- /dev/null +++ b/db/structure.sql @@ -0,0 +1,1122 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 9.5.5 +-- Dumped by pg_dump version 9.5.5 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: code_harbor_links; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE code_harbor_links ( + id integer NOT NULL, + oauth2token character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + user_id integer +); + + +-- +-- Name: code_harbor_links_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE code_harbor_links_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: code_harbor_links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE code_harbor_links_id_seq OWNED BY code_harbor_links.id; + + +-- +-- Name: comments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE comments ( + id integer NOT NULL, + user_id integer, + file_id integer, + user_type character varying(255), + "row" integer, + "column" integer, + text text, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE comments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE comments_id_seq OWNED BY comments.id; + + +-- +-- Name: consumers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE consumers ( + id integer NOT NULL, + name character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + oauth_key character varying(255), + oauth_secret character varying(255) +); + + +-- +-- Name: consumers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE consumers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: consumers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE consumers_id_seq OWNED BY consumers.id; + + +-- +-- Name: errors; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE errors ( + id integer NOT NULL, + execution_environment_id integer, + message text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + submission_id integer +); + + +-- +-- Name: errors_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE errors_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: errors_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE errors_id_seq OWNED BY errors.id; + + +-- +-- Name: execution_environments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE execution_environments ( + id integer NOT NULL, + docker_image character varying(255), + name character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + run_command character varying(255), + test_command character varying(255), + testing_framework character varying(255), + help text, + exposed_ports character varying(255), + permitted_execution_time integer, + user_id integer, + user_type character varying(255), + pool_size integer, + file_type_id integer, + memory_limit integer, + network_enabled boolean +); + + +-- +-- Name: execution_environments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE execution_environments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: execution_environments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE execution_environments_id_seq OWNED BY execution_environments.id; + + +-- +-- Name: exercises; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE exercises ( + id integer NOT NULL, + description text, + execution_environment_id integer, + title character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + user_id integer, + instructions text, + public boolean, + user_type character varying(255), + token character varying(255), + hide_file_tree boolean, + allow_file_creation boolean, + allow_auto_completion boolean DEFAULT false +); + + +-- +-- Name: exercises_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE exercises_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: exercises_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE exercises_id_seq OWNED BY exercises.id; + + +-- +-- Name: external_users; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE external_users ( + id integer NOT NULL, + consumer_id integer, + email character varying(255), + external_id character varying(255), + name character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: external_users_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE external_users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: external_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE external_users_id_seq OWNED BY external_users.id; + + +-- +-- Name: file_templates; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE file_templates ( + id integer NOT NULL, + name character varying(255), + content text, + file_type_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: file_templates_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE file_templates_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: file_templates_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE file_templates_id_seq OWNED BY file_templates.id; + + +-- +-- Name: file_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE file_types ( + id integer NOT NULL, + editor_mode character varying(255), + file_extension character varying(255), + indent_size integer, + name character varying(255), + user_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + executable boolean, + renderable boolean, + user_type character varying(255), + "binary" boolean +); + + +-- +-- Name: file_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE file_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: file_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE file_types_id_seq OWNED BY file_types.id; + + +-- +-- Name: files; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE files ( + id integer NOT NULL, + content text, + context_id integer, + context_type character varying(255), + file_id integer, + file_type_id integer, + hidden boolean, + name character varying(255), + read_only boolean, + created_at timestamp without time zone, + updated_at timestamp without time zone, + native_file character varying(255), + role character varying(255), + hashed_content character varying(255), + feedback_message character varying(255), + weight double precision, + path character varying(255), + file_template_id integer +); + + +-- +-- Name: files_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE files_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: files_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE files_id_seq OWNED BY files.id; + + +-- +-- Name: hints; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE hints ( + id integer NOT NULL, + execution_environment_id integer, + locale character varying(255), + message text, + name character varying(255), + regular_expression character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: hints_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE hints_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: hints_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE hints_id_seq OWNED BY hints.id; + + +-- +-- Name: internal_users; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE internal_users ( + id integer NOT NULL, + consumer_id integer, + email character varying(255), + name character varying(255), + role character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + crypted_password character varying(255), + salt character varying(255), + failed_logins_count integer DEFAULT 0, + lock_expires_at timestamp without time zone, + unlock_token character varying(255), + remember_me_token character varying(255), + remember_me_token_expires_at timestamp without time zone, + reset_password_token character varying(255), + reset_password_token_expires_at timestamp without time zone, + reset_password_email_sent_at timestamp without time zone, + activation_state character varying(255), + activation_token character varying(255), + activation_token_expires_at timestamp without time zone +); + + +-- +-- Name: internal_users_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE internal_users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: internal_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE internal_users_id_seq OWNED BY internal_users.id; + + +-- +-- Name: lti_parameters; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE lti_parameters ( + id integer NOT NULL, + external_users_id integer, + consumers_id integer, + exercises_id integer, + lti_parameters jsonb DEFAULT '{}'::jsonb NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: lti_parameters_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE lti_parameters_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: lti_parameters_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE lti_parameters_id_seq OWNED BY lti_parameters.id; + + +-- +-- Name: request_for_comments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE request_for_comments ( + id integer NOT NULL, + user_id integer NOT NULL, + exercise_id integer NOT NULL, + file_id integer NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, + user_type character varying(255), + question text, + solved boolean, + submission_id integer +); + + +-- +-- Name: request_for_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE request_for_comments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: request_for_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE request_for_comments_id_seq OWNED BY request_for_comments.id; + + +-- +-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE schema_migrations ( + version character varying(255) NOT NULL +); + + +-- +-- Name: submissions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE submissions ( + id integer NOT NULL, + exercise_id integer, + score double precision, + user_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + cause character varying(255), + user_type character varying(255) +); + + +-- +-- Name: submissions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE submissions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: submissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE submissions_id_seq OWNED BY submissions.id; + + +-- +-- Name: testruns; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE testruns ( + id integer NOT NULL, + passed boolean, + output text, + file_id integer, + submission_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: testruns_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE testruns_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: testruns_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE testruns_id_seq OWNED BY testruns.id; + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY code_harbor_links ALTER COLUMN id SET DEFAULT nextval('code_harbor_links_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY comments ALTER COLUMN id SET DEFAULT nextval('comments_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY consumers ALTER COLUMN id SET DEFAULT nextval('consumers_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY errors ALTER COLUMN id SET DEFAULT nextval('errors_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY execution_environments ALTER COLUMN id SET DEFAULT nextval('execution_environments_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY exercises ALTER COLUMN id SET DEFAULT nextval('exercises_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY external_users ALTER COLUMN id SET DEFAULT nextval('external_users_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY file_templates ALTER COLUMN id SET DEFAULT nextval('file_templates_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY file_types ALTER COLUMN id SET DEFAULT nextval('file_types_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY files ALTER COLUMN id SET DEFAULT nextval('files_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY hints ALTER COLUMN id SET DEFAULT nextval('hints_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY internal_users ALTER COLUMN id SET DEFAULT nextval('internal_users_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY lti_parameters ALTER COLUMN id SET DEFAULT nextval('lti_parameters_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY request_for_comments ALTER COLUMN id SET DEFAULT nextval('request_for_comments_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY submissions ALTER COLUMN id SET DEFAULT nextval('submissions_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY testruns ALTER COLUMN id SET DEFAULT nextval('testruns_id_seq'::regclass); + + +-- +-- Name: code_harbor_links_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY code_harbor_links + ADD CONSTRAINT code_harbor_links_pkey PRIMARY KEY (id); + + +-- +-- Name: comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY comments + ADD CONSTRAINT comments_pkey PRIMARY KEY (id); + + +-- +-- Name: consumers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY consumers + ADD CONSTRAINT consumers_pkey PRIMARY KEY (id); + + +-- +-- Name: errors_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY errors + ADD CONSTRAINT errors_pkey PRIMARY KEY (id); + + +-- +-- Name: execution_environments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY execution_environments + ADD CONSTRAINT execution_environments_pkey PRIMARY KEY (id); + + +-- +-- Name: exercises_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY exercises + ADD CONSTRAINT exercises_pkey PRIMARY KEY (id); + + +-- +-- Name: external_users_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY external_users + ADD CONSTRAINT external_users_pkey PRIMARY KEY (id); + + +-- +-- Name: file_templates_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY file_templates + ADD CONSTRAINT file_templates_pkey PRIMARY KEY (id); + + +-- +-- Name: file_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY file_types + ADD CONSTRAINT file_types_pkey PRIMARY KEY (id); + + +-- +-- Name: files_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY files + ADD CONSTRAINT files_pkey PRIMARY KEY (id); + + +-- +-- Name: hints_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY hints + ADD CONSTRAINT hints_pkey PRIMARY KEY (id); + + +-- +-- Name: internal_users_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY internal_users + ADD CONSTRAINT internal_users_pkey PRIMARY KEY (id); + + +-- +-- Name: lti_parameters_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY lti_parameters + ADD CONSTRAINT lti_parameters_pkey PRIMARY KEY (id); + + +-- +-- Name: request_for_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY request_for_comments + ADD CONSTRAINT request_for_comments_pkey PRIMARY KEY (id); + + +-- +-- Name: submissions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY submissions + ADD CONSTRAINT submissions_pkey PRIMARY KEY (id); + + +-- +-- Name: testruns_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY testruns + ADD CONSTRAINT testruns_pkey PRIMARY KEY (id); + + +-- +-- Name: index_code_harbor_links_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_code_harbor_links_on_user_id ON code_harbor_links USING btree (user_id); + + +-- +-- Name: index_comments_on_file_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_comments_on_file_id ON comments USING btree (file_id); + + +-- +-- Name: index_comments_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_comments_on_user_id ON comments USING btree (user_id); + + +-- +-- Name: index_errors_on_submission_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_errors_on_submission_id ON errors USING btree (submission_id); + + +-- +-- Name: index_files_on_context_id_and_context_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_files_on_context_id_and_context_type ON files USING btree (context_id, context_type); + + +-- +-- Name: index_internal_users_on_activation_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_internal_users_on_activation_token ON internal_users USING btree (activation_token); + + +-- +-- Name: index_internal_users_on_email; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_internal_users_on_email ON internal_users USING btree (email); + + +-- +-- Name: index_internal_users_on_remember_me_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_internal_users_on_remember_me_token ON internal_users USING btree (remember_me_token); + + +-- +-- Name: index_internal_users_on_reset_password_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_internal_users_on_reset_password_token ON internal_users USING btree (reset_password_token); + + +-- +-- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX unique_schema_migrations ON schema_migrations USING btree (version); + + +-- +-- PostgreSQL database dump complete +-- + +SET search_path TO "$user", public; + +INSERT INTO schema_migrations (version) VALUES ('20140625134118'); + +INSERT INTO schema_migrations (version) VALUES ('20140626143132'); + +INSERT INTO schema_migrations (version) VALUES ('20140626144036'); + +INSERT INTO schema_migrations (version) VALUES ('20140630093736'); + +INSERT INTO schema_migrations (version) VALUES ('20140630111215'); + +INSERT INTO schema_migrations (version) VALUES ('20140701120126'); + +INSERT INTO schema_migrations (version) VALUES ('20140701122345'); + +INSERT INTO schema_migrations (version) VALUES ('20140702100130'); + +INSERT INTO schema_migrations (version) VALUES ('20140703070749'); + +INSERT INTO schema_migrations (version) VALUES ('20140716153147'); + +INSERT INTO schema_migrations (version) VALUES ('20140717074902'); + +INSERT INTO schema_migrations (version) VALUES ('20140722125431'); + +INSERT INTO schema_migrations (version) VALUES ('20140723135530'); + +INSERT INTO schema_migrations (version) VALUES ('20140723135747'); + +INSERT INTO schema_migrations (version) VALUES ('20140724155359'); + +INSERT INTO schema_migrations (version) VALUES ('20140730114343'); + +INSERT INTO schema_migrations (version) VALUES ('20140730115010'); + +INSERT INTO schema_migrations (version) VALUES ('20140805161431'); + +INSERT INTO schema_migrations (version) VALUES ('20140812102114'); + +INSERT INTO schema_migrations (version) VALUES ('20140812144733'); + +INSERT INTO schema_migrations (version) VALUES ('20140812150607'); + +INSERT INTO schema_migrations (version) VALUES ('20140812150925'); + +INSERT INTO schema_migrations (version) VALUES ('20140813091722'); + +INSERT INTO schema_migrations (version) VALUES ('20140820170039'); + +INSERT INTO schema_migrations (version) VALUES ('20140821064318'); + +INSERT INTO schema_migrations (version) VALUES ('20140823172643'); + +INSERT INTO schema_migrations (version) VALUES ('20140823173923'); + +INSERT INTO schema_migrations (version) VALUES ('20140825121336'); + +INSERT INTO schema_migrations (version) VALUES ('20140825125801'); + +INSERT INTO schema_migrations (version) VALUES ('20140825154202'); + +INSERT INTO schema_migrations (version) VALUES ('20140825161350'); + +INSERT INTO schema_migrations (version) VALUES ('20140825161358'); + +INSERT INTO schema_migrations (version) VALUES ('20140825161406'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073318'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073319'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073320'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073321'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073322'); + +INSERT INTO schema_migrations (version) VALUES ('20140827065359'); + +INSERT INTO schema_migrations (version) VALUES ('20140827083957'); + +INSERT INTO schema_migrations (version) VALUES ('20140829141913'); + +INSERT INTO schema_migrations (version) VALUES ('20140903093436'); + +INSERT INTO schema_migrations (version) VALUES ('20140903165113'); + +INSERT INTO schema_migrations (version) VALUES ('20140904082810'); + +INSERT INTO schema_migrations (version) VALUES ('20140909115430'); + +INSERT INTO schema_migrations (version) VALUES ('20140915095420'); + +INSERT INTO schema_migrations (version) VALUES ('20140915122846'); + +INSERT INTO schema_migrations (version) VALUES ('20140918063522'); + +INSERT INTO schema_migrations (version) VALUES ('20140922161120'); + +INSERT INTO schema_migrations (version) VALUES ('20140922161226'); + +INSERT INTO schema_migrations (version) VALUES ('20141003072729'); + +INSERT INTO schema_migrations (version) VALUES ('20141004114747'); + +INSERT INTO schema_migrations (version) VALUES ('20141009110434'); + +INSERT INTO schema_migrations (version) VALUES ('20141011145303'); + +INSERT INTO schema_migrations (version) VALUES ('20141017110211'); + +INSERT INTO schema_migrations (version) VALUES ('20141031161603'); + +INSERT INTO schema_migrations (version) VALUES ('20141119131607'); + +INSERT INTO schema_migrations (version) VALUES ('20150128083123'); + +INSERT INTO schema_migrations (version) VALUES ('20150128084834'); + +INSERT INTO schema_migrations (version) VALUES ('20150128093003'); + +INSERT INTO schema_migrations (version) VALUES ('20150204080832'); + +INSERT INTO schema_migrations (version) VALUES ('20150310150712'); + +INSERT INTO schema_migrations (version) VALUES ('20150317083739'); + +INSERT INTO schema_migrations (version) VALUES ('20150317115338'); + +INSERT INTO schema_migrations (version) VALUES ('20150327141740'); + +INSERT INTO schema_migrations (version) VALUES ('20150408155923'); + +INSERT INTO schema_migrations (version) VALUES ('20150421074734'); + +INSERT INTO schema_migrations (version) VALUES ('20150818141554'); + +INSERT INTO schema_migrations (version) VALUES ('20150818142251'); + +INSERT INTO schema_migrations (version) VALUES ('20150903152727'); + +INSERT INTO schema_migrations (version) VALUES ('20150922125415'); + +INSERT INTO schema_migrations (version) VALUES ('20160204094409'); + +INSERT INTO schema_migrations (version) VALUES ('20160204111716'); + +INSERT INTO schema_migrations (version) VALUES ('20160302133540'); + +INSERT INTO schema_migrations (version) VALUES ('20160426114951'); + +INSERT INTO schema_migrations (version) VALUES ('20160510145341'); + +INSERT INTO schema_migrations (version) VALUES ('20160512131539'); + +INSERT INTO schema_migrations (version) VALUES ('20160609185708'); + +INSERT INTO schema_migrations (version) VALUES ('20160610111602'); + +INSERT INTO schema_migrations (version) VALUES ('20160624130951'); + +INSERT INTO schema_migrations (version) VALUES ('20160630154310'); + +INSERT INTO schema_migrations (version) VALUES ('20160701092140'); + +INSERT INTO schema_migrations (version) VALUES ('20160704143402'); + +INSERT INTO schema_migrations (version) VALUES ('20160907123009'); + +INSERT INTO schema_migrations (version) VALUES ('20170112151637'); + diff --git a/debian_installer/setup_debian_1_install_postgres.sh b/debian_installer/setup_debian_1_install_postgres.sh new file mode 100644 index 00000000..515362f1 --- /dev/null +++ b/debian_installer/setup_debian_1_install_postgres.sh @@ -0,0 +1,69 @@ +# update apt-get +echo "Update apt-get..." +sudo apt-get update +# upgrade all packages +echo "Upgrade packages..." +sudo apt-get upgrade + +#install postgres +if [ ! -f /etc/apt/sources.list.d/pgdg.list ] +then + echo "Add Postgres sources..." + cd /etc/apt/sources.list.d + sudo touch pgdg.list + sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main" > pgdg.list' + sudo wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + sudo apt-get update + echo "Done" +else + echo "Postgres sources already added" +fi + +sudo apt-get -y --force-yes install postgresql-9.5 + +# drop postgres access control +if [ -f /etc/postgresql/9.5/main/pg_hba.conf ] +then + if ! sudo -u postgres grep -q CodeOcean /etc/postgresql/9.5/main/pg_hba.conf + then + echo "Drop Postgres access control..." + sudo -u postgres sh -c 'cat >/etc/postgresql/9.5/main/pg_hba.conf < backports.list' + sudo apt-get update + echo "Done" + + #just in case there is some old stuff + echo "Remove legacy stuff...Just in case..." + sudo apt-get purge "lxc-docker*" + sudo apt-get purge "docker.io*" + sudo apt-get update + + #install docker dependencies + echo "Install dependencies..." + sudo apt-get install -y --force-yes apt-transport-https ca-certificates gnupg2 + echo "Done" +else + echo "Docker dependencies already added." +fi + +if [ ! -f /etc/apt/sources.list.d/docker.list ] +then + # get docker sources + echo "Add apt-get sources for Docker..." + sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D + cd /etc/apt/sources.list.d + sudo touch docker.list + sudo sh -c 'echo "deb https://apt.dockerproject.org/repo debian-jessie main" > docker.list' + sudo apt-cache policy docker-engine + sudo apt-get update + echo "Done" +else + echo "Docker apt-get sources already added." +fi + +if [ ! -f /etc/systemd/system/docker.service.d/docker.conf ] + then + echo "Install Docker Engine..." + sudo apt-get install -y --force-yes docker-engine + echo "Done" + echo "Start Docker..." + sudo service docker start + echo "Done" + echo "Run Hello World..." + sudo docker run hello-world + echo "Done" + + #set some docker options + echo "Configure Docker..." + sudo mkdir /etc/systemd/system/docker.service.d + cd /etc/systemd/system/docker.service.d + sudo touch docker.conf + sudo sh -c 'cat >>/etc/systemd/system/docker.service.d/docker.conf < nonfree.list' + sudo sh -c 'echo "deb-src http://http.debian.net/debian jessie main non-free contrib" >> nonfree.list' + sudo sh -c 'echo "deb http://http.debian.net/debian jessie-updates main contrib non-free" >> nonfree.list' + sudo sh -c 'echo "deb-src http://http.debian.net/debian jessie-updates main contrib non-free" >> nonfree.list' + sudo apt-get update +else + # install utilities + echo "Additional apt-get sources already added" +fi + +# install utilities +echo "Install some utils..." +sudo apt-get install -y --force-yes screen +sudo apt-get install -y --force-yes htop +echo "Done" + +# install dependencies +echo "Install some libraries..." +sudo apt-get install -y --force-yes git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev +sudo apt-get install -y --force-yes libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev +sudo apt-get install -y --force-yes python-software-properties libffi-dev +sudo apt-get install -y --force-yes libgdbm-dev libncurses5-dev automake libtool bison libffi-dev +sudo apt-get install -y --force-yes libpq-dev +echo "Done" + +# get the clock in sync +echo "Install clock synchronization..." +sudo apt-get install -y --force-yes ntp ntpdate +echo "Done" + +echo "Install NodeJS..." +# install nodejs +sudo apt-get install -y --force-yes nodejs +echo "Done" + +if ! (ruby -v | grep -q 2.3.3) +then + # install rvm + echo "Install RVM..." + gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 + \curl -sSL https://get.rvm.io | bash -s stable --ruby + source /home/debian/.rvm/scripts/rvm + echo "Done" + # install ruby + echo "Install Ruby 2.3.3..." + rvm install 2.3.3 + rvm use 2.3.3 --default + ruby -v + exec bash + echo "Done" +else + echo "RVM and Ruby are already installed" +fi + +# install guest additions - required for sharing a folder +echo "Install prerequisites for guest additions..." +sudo apt-get install -y --force-yes dkms build-essential linux-headers-amd64 +echo "Done" + +echo "Please follow the instructions:" +echo "Insert Guest Additions CD image. VM: Devices=>Insert Guest Additions CD image" +echo "Install Guest Additions" \ No newline at end of file diff --git a/debian_installer/setup_debian_4_install_guest_additions.sh b/debian_installer/setup_debian_4_install_guest_additions.sh new file mode 100644 index 00000000..68f7e552 --- /dev/null +++ b/debian_installer/setup_debian_4_install_guest_additions.sh @@ -0,0 +1,10 @@ +# Mount Guest Additions and run the installer +echo "Mount Guest Additions and run the installer..." +sudo mount /dev/sr0 /media/cdrom +cd /media/cdrom +sudo sh ./VBoxLinuxAdditions.run +echo "Done" +echo "Please follow the instructions:" +echo "Create Shared Folder. VM: Devices=>VM: Devices=>Shared Folders=>Shared Folders Settings" +echo "Name: codeocean, Path: path to your local codeocaen repository on the host machine." + diff --git a/debian_installer/setup_debian_5_mount_shared_folder.sh b/debian_installer/setup_debian_5_mount_shared_folder.sh new file mode 100644 index 00000000..db1f8234 --- /dev/null +++ b/debian_installer/setup_debian_5_mount_shared_folder.sh @@ -0,0 +1,7 @@ +echo "Mount Shared Folder..." +mkdir /home/debian/codeocean_host +sudo mount -t vboxsf -o rw,uid=1000,gid=1000 codeocean /home/debian/codeocean_host + +# Enable automount during startup +sudo sh -c 'echo "sudo mount -t vboxsf -o rw,uid=1000,gid=1000 codeocean /home/debian/codeocean_host" >> /home/debian/.bashrc ' +echo "Done" \ No newline at end of file diff --git a/debian_installer/setup_debian_6_setup_codeocean.sh b/debian_installer/setup_debian_6_setup_codeocean.sh new file mode 100644 index 00000000..6151fb3a --- /dev/null +++ b/debian_installer/setup_debian_6_setup_codeocean.sh @@ -0,0 +1,28 @@ +############# codeocean install ########################### +cd /home/debian/codeocean_host + +#install rails and bundler +echo "Install Rails..." +gem install rails +echo "Done" +echo "Install Bundler..." +gem install bundler +echo "Done" + +# install required gems +bundle install + +# copy config files +for f in action_mailer.yml database.yml secrets.yml sendmail.yml smtp.yml code_ocean.yml +do + if [ ! -f config/$f ] + then + cp config/$f.example config/$f + fi +done + +# Manual Task: +# if necessary adjust db config +echo "Check if settings in database.yml correspond with your database setup." + +cat /home/debian/codeocean_host/config/database.yml \ No newline at end of file diff --git a/debian_installer/setup_debian_7_create_tables.sh b/debian_installer/setup_debian_7_create_tables.sh new file mode 100644 index 00000000..ed7f5990 --- /dev/null +++ b/debian_installer/setup_debian_7_create_tables.sh @@ -0,0 +1,8 @@ +# create, migrate, and seed database tables +cd /home/debian/codeocean_host +export RAILS_ENV=development + +echo "load, seed, migrate" +rake db:schema:load +rake db:seed +rake db:migrate \ No newline at end of file diff --git a/debian_installer/setup_debian_vm.sh b/debian_installer/setup_debian_vm.sh new file mode 100644 index 00000000..8759157d --- /dev/null +++ b/debian_installer/setup_debian_vm.sh @@ -0,0 +1,165 @@ +# Prerequisites: +# 1 Download Debian iso image. http://cdimage.debian.org/debian-cd/8.6.0/amd64/iso-cd/debian-8.6.0-amd64-netinst.iso +# 2 Create Debian VM in VirtualBox: +# - without GUI +# - without webserver (we do not want an apache2 but an nginx server) +# - with ssh () +# 2 Create 2 users +# - debian/debian +# - root/root + +# Manual preparation: +# Login as root +su + +# install sudo +apt-get install -y sudo + +# add user debian to sudoers and enable this user to sudo without password (do not do this on a production machine) +# or change the line after finishing the installation +cd /etc/sudoers.d +touch debian +echo "debian ALL=(ALL) NOPASSWD:ALL" >> debian +# echo "debian ALL=(ALL:ALL) ALL" >> debian # production systems +# return to no-root user again +exit + +# Running the following directly on the VM command line is inconvenient +# Therefore enable login via ssh from Host + +# The best way to login to a guest Linux VirtualBox VM is port forwarding. +# By default, you should have one interface already which is using NAT. +# Then go to the Network settings and click the Port Forwarding button. Add a new Rule: + +# Protocol TCP Host port 3022, guest port 22, name ssh, other left blank. +# That's all! Please be sure you don't forget to install an SSH server: + +# To SSH into the guest VM, write: +# ssh -p 3022 user@127.0.0.1 +# http://stackoverflow.com/questions/5906441/how-to-ssh-to-a-virtualbox-guest-externally-through-a-host +#======================================================================================================= + +# Install postgres +# run script: +debian_installer/setup_debian_1_install_postgres.sh + +# Install docker +# run script: +debian_installer/setup_debian_2_install_docker.sh + +# Install dependencies, utils, rvm, ruby, node +# run script: +debian_installer/setup_debian_3_install_depencies_and_utils.sh + +##################################local installation on VirtualBox only################## +# Before running the next script, the Guest Additions CD image needs to be inserted via VBox GUI +# Devices=>Insert Guest Additions CD image" +# When that is done run the next script +debian_installer/setup_debian_4_install_guest_additions.sh + +# Before running the next script, a Shared Folder has to be created via VBox GUI +# Devices=>Shared Folders=>Shared Folders Settings +# Folder Name: codeocean, Folder Path: path to your local codeocean repository on the host machine. +# Automount, Make Permanent +# When that is done run the next script +debian_installer/setup_debian_5_mount_shared_folder.sh +##################################local installation on VirtualBox only################## + +# Install rails and bundler +# run script: +debian_installer/setup_debian_6_setup_codeocean.sh + +# Create, seed, and migrate database tables +# run script: +debian_installer/setup_debian_7_create_tables.sh + +# Add Port Forwarding for Rails server: + +# Protocol TCP Host port 3030, guest port 3000, name CodeOcean, other left blank. +# That's all! +# Start Puma server on VM (since we upgraded to rails 4.2.5, it is necessary to specify the address here as well. Otherwise, we can't connect from the host machine) +# rails s -b 0.0.0.0 -p 8080 + +# To connect to Ruby app use +#http://127.0.0.1:3030 + + +#The following is required so that CodeOcean can connect back to openHPI local + +# Setup a second networking interface +# 1. Host-only vboxnet0 (ip-address: 192.168.59.104) +# 2. NAT with all the portforwarding stuff as described above + +# Edit /etc/network/interfaces in Guest machine: +# 1. check for available interfaces: +# ls /sys/class/net ===> docker0 eth0 eth1 lo + +# 2. edit network configuration: +# sudoedit /etc/network/interfaces +# and add the following lines: + +# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + +source /etc/network/interfaces.d/* + +# The loopback network interface +auto lo +iface lo inet loopback + +# The primary network interface +# allow-hotplug eth0 +# iface eth0 inet dhcp + +#Host-only interface +auto eth0 +iface eth0 inet static + address 192.168.59.104 + netmask 255.255.255.0 + network 192.168.59.0 + broadcast 192.168.59.255 + +#NAT interface +auto eth1 +iface eth1 inet dhcp + +# See also: +# http://askubuntu.com/questions/293816/in-virtualbox-how-do-i-set-up-host-only-virtual-machines-that-can-access-the-in + +# !!!!!Attention!!!!!!!! +# Start openHPI Local as: +# http://{host.ip}:3000/ +# e.g. http://192.168.178.33:3000/ +# set LTI Provider in course as: +# http://192.168.59.104:3030/lti/launch + +# Access VBox with static IP and port-forwarding +# SSH: +# ssh -p 3022 debian@192.168.59.104 +# CodeOcean: +# http://192.168.59.104:3030 + +#TODO production: +# require passwd for sudo again. +# cd /etc/sudoers.d +# echo "debian ALL=(ALL:ALL) ALL" > debian + +#TODO production: Install nginx +# install nginx +# echo "Install NGINX..." +# sudo apt-get install -y --force-yes nginx +# echo "Done" + + + + + + + + + + + + + + diff --git a/lib/docker_client.rb b/lib/docker_client.rb index a8bdf915..28e2a3fb 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -325,7 +325,7 @@ class DockerClient end def self.image_tags - Docker::Image.all.map { |image| image.info['RepoTags'] }.flatten.reject { |tag| tag.present? && tag.include?('') } + Docker::Image.all.map { |image| image.info['RepoTags'] }.flatten.reject { |tag| tag.nil? || tag.include?('') } end def initialize(options = {}) diff --git a/spec/concerns/lti_spec.rb b/spec/concerns/lti_spec.rb index c4ff350a..95181d3b 100644 --- a/spec/concerns/lti_spec.rb +++ b/spec/concerns/lti_spec.rb @@ -19,7 +19,6 @@ describe Lti do it 'clears the session' do expect(controller.session).to receive(:delete).with(:consumer_id) expect(controller.session).to receive(:delete).with(:external_user_id) - expect(controller.session).to receive(:delete).with(:lti_parameters) controller.send(:clear_lti_session_data) end end @@ -106,24 +105,25 @@ describe Lti do describe '#send_score' do let(:consumer) { FactoryGirl.create(:consumer) } let(:score) { 0.5 } + let(:submission) { FactoryGirl.create(:submission) } + let!(:lti_parameter) { FactoryGirl.create(:lti_parameter)} context 'with an invalid score' do it 'raises an exception' do - expect { controller.send(:send_score, Lti::MAXIMUM_SCORE * 2) }.to raise_error(Lti::Error) + expect { controller.send(:send_score, submission.exercise_id, Lti::MAXIMUM_SCORE * 2, submission.user_id) }.to raise_error(Lti::Error) end end context 'with an valid score' do - context 'with a tool provider' do + context 'with a tool consumer' do before(:each) do controller.session[:consumer_id] = consumer.id - controller.session[:lti_parameters] = {} end context 'when grading is not supported' do it 'returns a corresponding status' do expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(false) - expect(controller.send(:send_score, score)[:status]).to eq('unsupported') + expect(controller.send(:send_score, submission.exercise_id, score, submission.user_id)[:status]).to eq('unsupported') end end @@ -140,11 +140,11 @@ describe Lti do end it 'sends the score' do - controller.send(:send_score, score) + controller.send(:send_score, submission.exercise_id, score, submission.user_id) end it 'returns code, message, and status' do - result = controller.send(:send_score, score) + result = controller.send(:send_score, submission.exercise_id, score, submission.user_id) expect(result[:code]).to eq(response.response_code) expect(result[:message]).to eq(response.body) expect(result[:status]).to eq(response.code_major) @@ -152,10 +152,9 @@ describe Lti do end end - context 'without a tool provider' do + context 'without a tool consumer' do it 'returns a corresponding status' do - expect(controller).to receive(:build_tool_provider).and_return(nil) - expect(controller.send(:send_score, score)[:status]).to eq('error') + expect(controller.send(:send_score, submission.exercise_id, score, submission.user_id)[:status]).to eq('error') end end end @@ -163,17 +162,18 @@ describe Lti do describe '#store_lti_session_data' do let(:parameters) { {} } - before(:each) { controller.instance_variable_set(:@current_user, FactoryGirl.create(:external_user)) } - after(:each) { controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) } it 'stores data in the session' do + controller.instance_variable_set(:@current_user, FactoryGirl.create(:external_user)) expect(controller.session).to receive(:[]=).with(:consumer_id, anything) expect(controller.session).to receive(:[]=).with(:external_user_id, anything) - expect(controller.session).to receive(:[]=).with(:lti_parameters, kind_of(Hash)) + controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) end - it 'stores only selected tuples' do - expect(parameters).to receive(:slice).with(*Lti::SESSION_PARAMETERS) + it 'it creates an LtiParameter Object' do + before_count = LtiParameter.count + controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) + expect(LtiParameter.count).to eq(before_count + 1) end end diff --git a/spec/controllers/exercises_controller_spec.rb b/spec/controllers/exercises_controller_spec.rb index 5323096d..43dada43 100644 --- a/spec/controllers/exercises_controller_spec.rb +++ b/spec/controllers/exercises_controller_spec.rb @@ -230,11 +230,14 @@ describe ExercisesController do describe 'POST #submit' do let(:output) { {} } let(:request) { post :submit, format: :json, id: exercise.id, submission: {cause: 'submit', exercise_id: exercise.id} } + let!(:external_user) { FactoryGirl.create(:external_user) } + let!(:lti_parameter) { FactoryGirl.create(:lti_parameter, external_user: external_user, exercise: exercise) } before(:each) do allow_any_instance_of(Submission).to receive(:normalized_score).and_return(1) expect(controller).to receive(:collect_test_results).and_return([{score: 1, weight: 1}]) expect(controller).to receive(:score_submission).and_call_original + controller.session[:consumer_id] = external_user.consumer_id end context 'when LTI outcomes are supported' do diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index aa76dcca..ffa957ea 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -93,6 +93,7 @@ describe SessionsController do end it 'stores LTI parameters in the session' do + #Todo replace session with lti_parameter /should be done already expect(controller).to receive(:store_lti_session_data) request end @@ -159,6 +160,7 @@ describe SessionsController do end it 'clears the session' do + #Todo replace session with lti_parameter /should be done already expect(controller).to receive(:clear_lti_session_data) delete :destroy end @@ -174,13 +176,16 @@ describe SessionsController do let(:submission) { FactoryGirl.create(:submission, exercise: FactoryGirl.create(:dummy)) } before(:each) do + #Todo replace session with lti_parameter session[:consumer_id] = consumer.id - session[:lti_parameters] = {} + #Todo create LtiParameter Object + # session[:lti_parameters] = {} end before(:each) { request.call } it 'clears the session' do + #Todo replace session with lti_parameter /should be done already expect(controller).to receive(:clear_lti_session_data) request.call end diff --git a/spec/factories/execution_environment.rb b/spec/factories/execution_environment.rb index a58e879a..051d9de6 100644 --- a/spec/factories/execution_environment.rb +++ b/spec/factories/execution_environment.rb @@ -32,7 +32,7 @@ FactoryGirl.define do factory :java, class: ExecutionEnvironment do created_by_teacher default_memory_limit - docker_image 'hklement/ubuntu-java:latest' + docker_image 'openhpi/co_execenv_java:latest' association :file_type, factory: :dot_java help name 'Java 8' @@ -78,7 +78,7 @@ FactoryGirl.define do factory :python, class: ExecutionEnvironment do created_by_teacher default_memory_limit - docker_image 'hklement/ubuntu-python:latest' + docker_image 'openhpi/co_execenv_python:latest' association :file_type, factory: :dot_py help name 'Python 3.4' diff --git a/spec/factories/lti_parameter.rb b/spec/factories/lti_parameter.rb new file mode 100644 index 00000000..9cd0f367 --- /dev/null +++ b/spec/factories/lti_parameter.rb @@ -0,0 +1,20 @@ +FactoryGirl.define do + + LTI_PARAMETERS = { + lis_result_sourcedid: "c2db0c7c-4411-4b27-a52b-ddfc3dc32065", + lis_outcome_service_url: "http://172.16.54.235:3000/courses/0132156a-9afb-434d-83cc-704780104105/sections/21c6c6f4-1fb6-43b4-af3c-04fdc098879e/items/999b1fe6-d4b6-47b7-a577-ea2b4b1041ec/tool_grading", + launch_presentation_return_url: "http://172.16.54.235:3000/courses/0132156a-9afb-434d-83cc-704780104105/sections/21c6c6f4-1fb6-43b4-af3c-04fdc098879e/items/999b1fe6-d4b6-47b7-a577-ea2b4b1041ec/tool_return" + } + + factory :lti_parameter do + association :consumer + association :exercise, factory: :math + association :external_user + + lti_parameters LTI_PARAMETERS + + trait :without_outcome_service_url do + lti_parameters LTI_PARAMETERS.except(:lis_outcome_service_url) + end + end +end \ No newline at end of file diff --git a/spec/factories/submission.rb b/spec/factories/submission.rb index b3ef8a0e..cd4e34e1 100644 --- a/spec/factories/submission.rb +++ b/spec/factories/submission.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :submission do cause 'save' created_by_external_user - association :exercise, factory: :fibonacci + association :exercise, factory: :math after(:create) do |submission| submission.exercise.files.editable.visible.each do |file| diff --git a/spec/lib/docker_client_spec.rb b/spec/lib/docker_client_spec.rb index e9343f9a..feb457f6 100644 --- a/spec/lib/docker_client_spec.rb +++ b/spec/lib/docker_client_spec.rb @@ -3,8 +3,8 @@ require 'seeds_helper' describe DockerClient, docker: true do let(:command) { 'whoami' } - let(:docker_client) { described_class.new(execution_environment: FactoryGirl.build(:ruby), user: FactoryGirl.build(:admin)) } - let(:execution_environment) { FactoryGirl.build(:ruby) } + let(:docker_client) { described_class.new(execution_environment: FactoryGirl.build(:java), user: FactoryGirl.build(:admin)) } + let(:execution_environment) { FactoryGirl.build(:java) } let(:image) { double } let(:submission) { FactoryGirl.create(:submission) } let(:workspace_path) { '/tmp' }