@ -6,6 +6,7 @@ services:
|
|||||||
addons:
|
addons:
|
||||||
code_climate:
|
code_climate:
|
||||||
repo_token: 53a2c2608c848714e96f6a1fc0365dcfdfec051f7827d50cea965ea625f49734
|
repo_token: 53a2c2608c848714e96f6a1fc0365dcfdfec051f7827d50cea965ea625f49734
|
||||||
|
postgresql: "9.5"
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export DISPLAY=:99.0
|
- export DISPLAY=:99.0
|
||||||
|
2
Gemfile
2
Gemfile
@ -21,7 +21,7 @@ gem 'pg', platform: :ruby
|
|||||||
gem 'pry-byebug'
|
gem 'pry-byebug'
|
||||||
gem 'puma', '~> 2.15.3'
|
gem 'puma', '~> 2.15.3'
|
||||||
gem 'pundit'
|
gem 'pundit'
|
||||||
gem 'rails', '~> 4.1.13'
|
gem 'rails', '4.2.5'
|
||||||
gem 'rails-i18n', '~> 4.0.0'
|
gem 'rails-i18n', '~> 4.0.0'
|
||||||
gem 'ransack'
|
gem 'ransack'
|
||||||
gem 'rubytree'
|
gem 'rubytree'
|
||||||
|
131
Gemfile.lock
131
Gemfile.lock
@ -2,40 +2,49 @@ GEM
|
|||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
ZenTest (4.11.0)
|
ZenTest (4.11.0)
|
||||||
actionmailer (4.1.14.1)
|
actionmailer (4.2.5)
|
||||||
actionpack (= 4.1.14.1)
|
actionpack (= 4.2.5)
|
||||||
actionview (= 4.1.14.1)
|
actionview (= 4.2.5)
|
||||||
|
activejob (= 4.2.5)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
actionpack (4.1.14.1)
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||||
actionview (= 4.1.14.1)
|
actionpack (4.2.5)
|
||||||
activesupport (= 4.1.14.1)
|
actionview (= 4.2.5)
|
||||||
rack (~> 1.5.2)
|
activesupport (= 4.2.5)
|
||||||
|
rack (~> 1.6)
|
||||||
rack-test (~> 0.6.2)
|
rack-test (~> 0.6.2)
|
||||||
actionview (4.1.14.1)
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||||
activesupport (= 4.1.14.1)
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||||
|
actionview (4.2.5)
|
||||||
|
activesupport (= 4.2.5)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubis (~> 2.7.0)
|
erubis (~> 2.7.0)
|
||||||
activemodel (4.1.14.1)
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||||
activesupport (= 4.1.14.1)
|
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)
|
builder (~> 3.1)
|
||||||
activerecord (4.1.14.1)
|
activerecord (4.2.5)
|
||||||
activemodel (= 4.1.14.1)
|
activemodel (= 4.2.5)
|
||||||
activesupport (= 4.1.14.1)
|
activesupport (= 4.2.5)
|
||||||
arel (~> 5.0.0)
|
arel (~> 6.0)
|
||||||
activerecord-jdbc-adapter (1.3.19)
|
activerecord-jdbc-adapter (1.3.19)
|
||||||
activerecord (>= 2.2)
|
activerecord (>= 2.2)
|
||||||
activerecord-jdbcpostgresql-adapter (1.3.19)
|
activerecord-jdbcpostgresql-adapter (1.3.19)
|
||||||
activerecord-jdbc-adapter (~> 1.3.19)
|
activerecord-jdbc-adapter (~> 1.3.19)
|
||||||
jdbc-postgres (>= 9.1)
|
jdbc-postgres (>= 9.1)
|
||||||
activesupport (4.1.14.1)
|
activesupport (4.2.5)
|
||||||
i18n (~> 0.6, >= 0.6.9)
|
i18n (~> 0.7)
|
||||||
json (~> 1.7, >= 1.7.7)
|
json (~> 1.7, >= 1.7.7)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.3, >= 0.3.4)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
addressable (2.4.0)
|
addressable (2.4.0)
|
||||||
arel (5.0.1.20140414130214)
|
arel (6.0.4)
|
||||||
ast (2.2.0)
|
ast (2.3.0)
|
||||||
autotest-rails (4.2.1)
|
autotest-rails (4.2.1)
|
||||||
ZenTest (~> 4.5)
|
ZenTest (~> 4.5)
|
||||||
bcrypt (3.1.10)
|
bcrypt (3.1.10)
|
||||||
@ -129,6 +138,8 @@ GEM
|
|||||||
ffi (1.9.10)
|
ffi (1.9.10)
|
||||||
ffi (1.9.10-java)
|
ffi (1.9.10-java)
|
||||||
forgery (0.6.0)
|
forgery (0.6.0)
|
||||||
|
globalid (0.3.7)
|
||||||
|
activesupport (>= 4.1.0)
|
||||||
highline (1.7.8)
|
highline (1.7.8)
|
||||||
hike (1.2.3)
|
hike (1.2.3)
|
||||||
http-cookie (1.0.2)
|
http-cookie (1.0.2)
|
||||||
@ -151,13 +162,15 @@ GEM
|
|||||||
json (1.8.3-java)
|
json (1.8.3-java)
|
||||||
jwt (1.5.1)
|
jwt (1.5.1)
|
||||||
kramdown (1.9.0)
|
kramdown (1.9.0)
|
||||||
mail (2.6.3)
|
loofah (2.0.3)
|
||||||
mime-types (>= 1.16, < 3)
|
nokogiri (>= 1.5.9)
|
||||||
|
mail (2.6.4)
|
||||||
|
mime-types (>= 1.16, < 4)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (2.99)
|
mime-types (2.99.3)
|
||||||
mini_portile2 (2.0.0)
|
mini_portile2 (2.1.0)
|
||||||
minitest (5.9.0)
|
minitest (5.10.1)
|
||||||
multi_json (1.11.2)
|
multi_json (1.12.1)
|
||||||
multi_xml (0.5.5)
|
multi_xml (0.5.5)
|
||||||
multipart-post (2.0.0)
|
multipart-post (2.0.0)
|
||||||
net-scp (1.2.1)
|
net-scp (1.2.1)
|
||||||
@ -165,9 +178,9 @@ GEM
|
|||||||
net-ssh (3.0.2)
|
net-ssh (3.0.2)
|
||||||
netrc (0.10.3)
|
netrc (0.10.3)
|
||||||
newrelic_rpm (3.14.3.313)
|
newrelic_rpm (3.14.3.313)
|
||||||
nokogiri (1.6.7.2)
|
nokogiri (1.7.0.1)
|
||||||
mini_portile2 (~> 2.0.0.rc2)
|
mini_portile2 (~> 2.1.0)
|
||||||
nokogiri (1.6.7.2-java)
|
nokogiri (1.7.0.1-java)
|
||||||
nyan-cat-formatter (0.11)
|
nyan-cat-formatter (0.11)
|
||||||
rspec (>= 2.99, >= 2.14.2, < 4)
|
rspec (>= 2.99, >= 2.14.2, < 4)
|
||||||
oauth (0.4.7)
|
oauth (0.4.7)
|
||||||
@ -179,7 +192,7 @@ GEM
|
|||||||
rack (>= 1.2, < 3)
|
rack (>= 1.2, < 3)
|
||||||
pagedown-rails (1.1.4)
|
pagedown-rails (1.1.4)
|
||||||
railties (> 3.1)
|
railties (> 3.1)
|
||||||
parser (2.3.0.6)
|
parser (2.3.3.1)
|
||||||
ast (~> 2.2)
|
ast (~> 2.2)
|
||||||
pg (0.18.4)
|
pg (0.18.4)
|
||||||
polyamorous (1.3.0)
|
polyamorous (1.3.0)
|
||||||
@ -201,31 +214,40 @@ GEM
|
|||||||
puma (2.15.3-java)
|
puma (2.15.3-java)
|
||||||
pundit (1.1.0)
|
pundit (1.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
rack (1.5.5)
|
rack (1.6.5)
|
||||||
rack-mini-profiler (0.10.1)
|
rack-mini-profiler (0.10.1)
|
||||||
rack (>= 1.2.0)
|
rack (>= 1.2.0)
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rails (4.1.14.1)
|
rails (4.2.5)
|
||||||
actionmailer (= 4.1.14.1)
|
actionmailer (= 4.2.5)
|
||||||
actionpack (= 4.1.14.1)
|
actionpack (= 4.2.5)
|
||||||
actionview (= 4.1.14.1)
|
actionview (= 4.2.5)
|
||||||
activemodel (= 4.1.14.1)
|
activejob (= 4.2.5)
|
||||||
activerecord (= 4.1.14.1)
|
activemodel (= 4.2.5)
|
||||||
activesupport (= 4.1.14.1)
|
activerecord (= 4.2.5)
|
||||||
|
activesupport (= 4.2.5)
|
||||||
bundler (>= 1.3.0, < 2.0)
|
bundler (>= 1.3.0, < 2.0)
|
||||||
railties (= 4.1.14.1)
|
railties (= 4.2.5)
|
||||||
sprockets-rails (~> 2.0)
|
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)
|
rails-i18n (4.0.8)
|
||||||
i18n (~> 0.7)
|
i18n (~> 0.7)
|
||||||
railties (~> 4.0)
|
railties (~> 4.0)
|
||||||
railties (4.1.14.1)
|
railties (4.2.5)
|
||||||
actionpack (= 4.1.14.1)
|
actionpack (= 4.2.5)
|
||||||
activesupport (= 4.1.14.1)
|
activesupport (= 4.2.5)
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rainbow (2.1.0)
|
rainbow (2.2.1)
|
||||||
rake (10.5.0)
|
rake (12.0.0)
|
||||||
ransack (1.7.0)
|
ransack (1.7.0)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
@ -244,7 +266,7 @@ GEM
|
|||||||
rspec-mocks (~> 3.4.0)
|
rspec-mocks (~> 3.4.0)
|
||||||
rspec-autotest (1.0.0)
|
rspec-autotest (1.0.0)
|
||||||
rspec-core (>= 2.99.0.beta1, < 4.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-support (~> 3.4.0)
|
||||||
rspec-expectations (3.4.0)
|
rspec-expectations (3.4.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
@ -261,14 +283,15 @@ GEM
|
|||||||
rspec-mocks (~> 3.4.0)
|
rspec-mocks (~> 3.4.0)
|
||||||
rspec-support (~> 3.4.0)
|
rspec-support (~> 3.4.0)
|
||||||
rspec-support (3.4.1)
|
rspec-support (3.4.1)
|
||||||
rubocop (0.37.2)
|
rubocop (0.46.0)
|
||||||
parser (>= 2.3.0.4, < 3.0)
|
parser (>= 2.3.1.1, < 3.0)
|
||||||
powerpack (~> 0.1)
|
powerpack (~> 0.1)
|
||||||
rainbow (>= 1.99.1, < 3.0)
|
rainbow (>= 1.99.1, < 3.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (~> 0.3)
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||||
rubocop-rspec (1.4.0)
|
rubocop-rspec (1.9.0)
|
||||||
ruby-progressbar (1.7.5)
|
rubocop (>= 0.42.0)
|
||||||
|
ruby-progressbar (1.8.1)
|
||||||
rubytree (0.9.7)
|
rubytree (0.9.7)
|
||||||
json (~> 1.8)
|
json (~> 1.8)
|
||||||
structured_warnings (~> 0.2)
|
structured_warnings (~> 0.2)
|
||||||
@ -317,7 +340,7 @@ GEM
|
|||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
structured_warnings (0.2.0)
|
structured_warnings (0.2.0)
|
||||||
temple (0.7.6)
|
temple (0.7.6)
|
||||||
thor (0.19.1)
|
thor (0.19.4)
|
||||||
thread_safe (0.3.5)
|
thread_safe (0.3.5)
|
||||||
thread_safe (0.3.5-java)
|
thread_safe (0.3.5-java)
|
||||||
tilt (1.4.1)
|
tilt (1.4.1)
|
||||||
@ -335,7 +358,7 @@ GEM
|
|||||||
unf_ext
|
unf_ext
|
||||||
unf (0.1.4-java)
|
unf (0.1.4-java)
|
||||||
unf_ext (0.0.7.1)
|
unf_ext (0.0.7.1)
|
||||||
unicode-display_width (0.3.1)
|
unicode-display_width (1.1.2)
|
||||||
web-console (2.3.0)
|
web-console (2.3.0)
|
||||||
activemodel (>= 4.0)
|
activemodel (>= 4.0)
|
||||||
binding_of_caller (>= 0.7.2)
|
binding_of_caller (>= 0.7.2)
|
||||||
@ -396,7 +419,7 @@ DEPENDENCIES
|
|||||||
puma (~> 2.15.3)
|
puma (~> 2.15.3)
|
||||||
pundit
|
pundit
|
||||||
rack-mini-profiler
|
rack-mini-profiler
|
||||||
rails (~> 4.1.13)
|
rails (= 4.2.5)
|
||||||
rails-i18n (~> 4.0.0)
|
rails-i18n (~> 4.0.0)
|
||||||
rake
|
rake
|
||||||
ransack
|
ransack
|
||||||
|
@ -2,8 +2,11 @@ CodeOceanEditorWebsocket = {
|
|||||||
websocket: null,
|
websocket: null,
|
||||||
|
|
||||||
createSocketUrl: function(url) {
|
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 : "" %>';
|
var sockURL = new URL(window.location);
|
||||||
return '<%= DockerClient.config['ws_client_protocol'] %>' + window.location.hostname + ':' + rel_url_root + window.location.port + url;
|
sockURL.pathname = url;
|
||||||
|
sockURL.protocol = '<%= DockerClient.config['ws_client_protocol'] %>';
|
||||||
|
|
||||||
|
return sockURL.toString();
|
||||||
},
|
},
|
||||||
|
|
||||||
initializeSocket: function(url) {
|
initializeSocket: function(url) {
|
||||||
|
@ -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 = {
|
CodeOceanEditorRequestForComments = {
|
||||||
requestComments: function () {
|
requestComments: function () {
|
||||||
var user_id = $('#editor').data('user-id');
|
var user_id = $('#editor').data('user-id');
|
||||||
|
@ -10,7 +10,6 @@ class ApplicationController < ActionController::Base
|
|||||||
rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized
|
rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized
|
||||||
|
|
||||||
def current_user
|
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
|
@current_user ||= ExternalUser.find_by(id: session[:external_user_id]) || login_from_session || login_from_other_sources
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ require 'oauth/request_proxy/rack_request'
|
|||||||
|
|
||||||
module Lti
|
module Lti
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
include LtiHelper
|
||||||
|
|
||||||
MAXIMUM_SCORE = 1
|
MAXIMUM_SCORE = 1
|
||||||
MAXIMUM_SESSION_AGE = 60.minutes
|
MAXIMUM_SESSION_AGE = 60.minutes
|
||||||
@ -14,10 +15,18 @@ module Lti
|
|||||||
end
|
end
|
||||||
private :build_tool_provider
|
private :build_tool_provider
|
||||||
|
|
||||||
def clear_lti_session_data
|
# 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(:consumer_id)
|
||||||
session.delete(:external_user_id)
|
session.delete(:external_user_id)
|
||||||
session.delete(:lti_parameters)
|
else
|
||||||
|
LtiParameter.destroy_all(consumers_id: consumer_id,
|
||||||
|
external_users_id: user_id,
|
||||||
|
exercises_id: exercise_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
private :clear_lti_session_data
|
private :clear_lti_session_data
|
||||||
|
|
||||||
@ -43,11 +52,6 @@ module Lti
|
|||||||
end
|
end
|
||||||
private :external_user_name
|
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 = {})
|
def refuse_lti_launch(options = {})
|
||||||
return_to_consumer(lti_errorlog: options[:message], lti_errormsg: t('sessions.oauth.failure'))
|
return_to_consumer(lti_errorlog: options[:message], lti_errormsg: t('sessions.oauth.failure'))
|
||||||
end
|
end
|
||||||
@ -94,10 +98,19 @@ module Lti
|
|||||||
end
|
end
|
||||||
private :return_to_consumer
|
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 })
|
::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)
|
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?
|
if provider.nil?
|
||||||
{status: 'error'}
|
{status: 'error'}
|
||||||
elsif provider.outcome_service?
|
elsif provider.outcome_service?
|
||||||
@ -116,9 +129,19 @@ module Lti
|
|||||||
private :set_current_user
|
private :set_current_user
|
||||||
|
|
||||||
def store_lti_session_data(options = {})
|
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[:consumer_id] = options[:consumer].id
|
||||||
session[:external_user_id] = @current_user.id
|
session[:external_user_id] = current_user.id
|
||||||
session[:lti_parameters] = options[:parameters].slice(*SESSION_PARAMETERS)
|
|
||||||
end
|
end
|
||||||
private :store_lti_session_data
|
private :store_lti_session_data
|
||||||
|
|
||||||
|
@ -157,7 +157,14 @@ class ExercisesController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def redirect_to_lti_return_path
|
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|
|
respond_to do |format|
|
||||||
format.html { redirect_to(path) }
|
format.html { redirect_to(path) }
|
||||||
format.json { render(json: {redirect: path}) }
|
format.json { render(json: {redirect: path}) }
|
||||||
@ -221,7 +228,8 @@ class ExercisesController < ApplicationController
|
|||||||
def submit
|
def submit
|
||||||
@submission = Submission.create(submission_params)
|
@submission = Submission.create(submission_params)
|
||||||
score_submission(@submission)
|
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
|
transmit_lti_score
|
||||||
else
|
else
|
||||||
redirect_after_submit
|
redirect_after_submit
|
||||||
@ -230,7 +238,8 @@ class ExercisesController < ApplicationController
|
|||||||
|
|
||||||
def transmit_lti_score
|
def transmit_lti_score
|
||||||
::NewRelic::Agent.add_custom_parameters({ submission: @submission.id, normalized_score: @submission.normalized_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'
|
if response[:status] == 'success'
|
||||||
redirect_after_submit
|
redirect_after_submit
|
||||||
else
|
else
|
||||||
|
@ -21,7 +21,9 @@ class SessionsController < ApplicationController
|
|||||||
set_current_user
|
set_current_user
|
||||||
store_lti_session_data(consumer: @consumer, parameters: params)
|
store_lti_session_data(consumer: @consumer, parameters: params)
|
||||||
store_nonce(params[:oauth_nonce])
|
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
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@ -34,9 +36,8 @@ class SessionsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def destroy_through_lti
|
def destroy_through_lti
|
||||||
@consumer = Consumer.find_by(id: params[:consumer_id])
|
|
||||||
@submission = Submission.find(params[:submission_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
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
module ExerciseHelper
|
module ExerciseHelper
|
||||||
|
include LtiHelper
|
||||||
|
|
||||||
def embedding_parameters(exercise)
|
def embedding_parameters(exercise)
|
||||||
"locale=#{I18n.locale}&token=#{exercise.token}"
|
"locale=#{I18n.locale}&token=#{exercise.token}"
|
||||||
end
|
end
|
||||||
|
10
app/helpers/lti_helper.rb
Normal file
10
app/helpers/lti_helper.rb
Normal file
@ -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
|
9
app/models/lti_parameter.rb
Normal file
9
app/models/lti_parameter.rb
Normal file
@ -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
|
@ -28,17 +28,6 @@ class Submission < ActiveRecord::Base
|
|||||||
ancestors.merge(descendants).values
|
ancestors.merge(descendants).values
|
||||||
end
|
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
|
def main_file
|
||||||
collect_files.detect(&:main_file?)
|
collect_files.detect(&:main_file?)
|
||||||
end
|
end
|
||||||
@ -56,12 +45,6 @@ class Submission < ActiveRecord::Base
|
|||||||
(normalized_score * 100).round
|
(normalized_score * 100).round
|
||||||
end
|
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
|
def siblings
|
||||||
user.submissions.where(exercise_id: exercise_id)
|
user.submissions.where(exercise_id: exercise_id)
|
||||||
end
|
end
|
||||||
|
@ -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 : '')
|
- external_user_external_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_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="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'
|
div id='frames' class='editor-col'
|
||||||
#editor-buttons.btn-group.enforce-bottom-margin
|
#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', 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', 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'))
|
= 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'))
|
||||||
|
@ -27,7 +27,7 @@ div id='output_sidebar_uncollapsed' class='hidden col-sm-12 enforce-bottom-margi
|
|||||||
.progress-bar role='progressbar'
|
.progress-bar role='progressbar'
|
||||||
|
|
||||||
br
|
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'))
|
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
|
- 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'))
|
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'))
|
||||||
|
@ -3,6 +3,7 @@ h1 = t('.headline')
|
|||||||
p
|
p
|
||||||
== t(".success_#{params[:outcome] ? 'with' : 'without'}_outcome", consumer: @consumer)
|
== t(".success_#{params[:outcome] ? 'with' : 'without'}_outcome", consumer: @consumer)
|
||||||
==< t(".finished_#{@consumer ? 'with' : 'without'}_consumer", consumer: @consumer, url: params[:url])
|
==< t(".finished_#{@consumer ? 'with' : 'without'}_consumer", consumer: @consumer, url: params[:url])
|
||||||
|
==< t(".do_not_use_backbutton", consumer: @consumer)
|
||||||
|
|
||||||
h2 = t('shared.statistics')
|
h2 = t('shared.statistics')
|
||||||
|
|
||||||
|
@ -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}')
|
||||||
|
29
bin/setup
Executable file
29
bin/setup
Executable file
@ -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
|
@ -1,13 +1,6 @@
|
|||||||
require File.expand_path('../boot', __FILE__)
|
require File.expand_path('../boot', __FILE__)
|
||||||
|
|
||||||
# Pick the frameworks you want:
|
require 'rails/all'
|
||||||
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 the gems listed in Gemfile, including any gems
|
# Require the gems listed in Gemfile, including any gems
|
||||||
# you've limited to :test, :development, or :production.
|
# 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.
|
# 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.
|
# 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.
|
# 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.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||||
# config.i18n.default_locale = :de
|
# config.i18n.default_locale = :de
|
||||||
config.i18n.available_locales = [:de, :en]
|
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.autoload_paths << Rails.root.join('lib')
|
||||||
config.eager_load_paths << Rails.root.join('lib')
|
config.eager_load_paths << Rails.root.join('lib')
|
||||||
config.assets.precompile += %w( markdown-buttons.png )
|
config.assets.precompile += %w( markdown-buttons.png )
|
||||||
|
|
||||||
|
config.active_record.schema_format = :sql
|
||||||
|
|
||||||
case (RUBY_ENGINE)
|
case (RUBY_ENGINE)
|
||||||
when 'ruby'
|
when 'ruby'
|
||||||
# ...
|
# ...
|
||||||
@ -43,5 +41,3 @@ module CodeOcean
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Rails.application.config.assets.precompile += %w( markdown-buttons.png )
|
|
@ -1,4 +1,3 @@
|
|||||||
# Set up gems listed in the Gemfile.
|
|
||||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
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.
|
||||||
|
@ -2,6 +2,7 @@ Rails.application.configure do
|
|||||||
# Settings specified here will take precedence over those in config/application.rb.
|
# 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
|
# In the development environment your application's code is reloaded on
|
||||||
# every request. This slows down response time but is perfect for development
|
# 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.
|
# since you don't have to restart the web server when you make code changes.
|
||||||
@ -14,7 +15,7 @@ Rails.application.configure do
|
|||||||
config.consider_all_requests_local = true
|
config.consider_all_requests_local = true
|
||||||
config.action_controller.perform_caching = false
|
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.
|
# Don't care if the mailer can't send.
|
||||||
config.action_mailer.raise_delivery_errors = false
|
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.
|
# Raise an error on page load if there are pending migrations.
|
||||||
config.active_record.migration_error = :page_load
|
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.
|
# Adds additional error checking when serving assets at runtime.
|
||||||
# Checks for improperly declared sprockets dependencies.
|
# Checks for improperly declared sprockets dependencies.
|
||||||
# Raises helpful error messages.
|
# Raises helpful error messages.
|
||||||
config.assets.raise_runtime_errors = true
|
config.assets.raise_runtime_errors = true
|
||||||
|
|
||||||
# Raise errors for missing translations.
|
# Raises error for missing translations
|
||||||
config.action_view.raise_on_missing_translations = true
|
config.action_view.raise_on_missing_translations = true
|
||||||
|
|
||||||
BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP']
|
BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP']
|
||||||
|
@ -16,11 +16,13 @@ Rails.application.configure do
|
|||||||
|
|
||||||
# Enable Rack::Cache to put a simple HTTP cache in front of your application
|
# Enable Rack::Cache to put a simple HTTP cache in front of your application
|
||||||
# Add `rack-cache` to your Gemfile before enabling this.
|
# 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
|
# config.action_dispatch.rack_cache = true
|
||||||
|
|
||||||
# Disable Rails's static asset server (Apache or nginx will already do this).
|
# Disable serving static files from the `/public` folder by default since
|
||||||
config.serve_static_assets = false
|
# Apache or NGINX already handles this.
|
||||||
|
config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
|
||||||
|
|
||||||
# Compress JavaScripts and CSS.
|
# Compress JavaScripts and CSS.
|
||||||
config.assets.js_compressor = :uglifier
|
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.
|
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
||||||
config.assets.compile = false
|
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
|
config.assets.digest = true
|
||||||
|
|
||||||
# Version of your assets, change this if you want to expire all your assets.
|
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
|
||||||
config.assets.version = '1.0'
|
|
||||||
|
|
||||||
# Specifies the header that your server uses for sending files.
|
# 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-Sendfile' # for Apache
|
||||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
|
# 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.
|
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
||||||
# config.force_ssl = true
|
# 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
|
config.log_level = :error
|
||||||
|
|
||||||
# Prepend all log lines with the following tags.
|
# Prepend all log lines with the following tags.
|
||||||
@ -55,11 +58,7 @@ Rails.application.configure do
|
|||||||
# config.cache_store = :mem_cache_store
|
# config.cache_store = :mem_cache_store
|
||||||
|
|
||||||
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
||||||
# config.action_controller.asset_host = "http://assets.example.com"
|
# 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 )
|
|
||||||
|
|
||||||
# Ignore bad email addresses and do not raise email delivery errors.
|
# 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.
|
# 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.
|
# Send deprecation notices to registered listeners.
|
||||||
config.active_support.deprecation = :notify
|
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.
|
# Use default logging formatter so that PID and timestamp are not suppressed.
|
||||||
config.log_formatter = ::Logger::Formatter.new
|
config.log_formatter = ::Logger::Formatter.new
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ Rails.application.configure do
|
|||||||
# config.action_dispatch.rack_cache = true
|
# config.action_dispatch.rack_cache = true
|
||||||
|
|
||||||
# Disable Rails's static asset server (Apache or nginx will already do this).
|
# 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.
|
# Compress JavaScripts and CSS.
|
||||||
# config.assets.js_compressor = :uglifier
|
# config.assets.js_compressor = :uglifier
|
||||||
|
@ -12,8 +12,8 @@ Rails.application.configure do
|
|||||||
# preloads Rails for running tests, you may have to set it to true.
|
# preloads Rails for running tests, you may have to set it to true.
|
||||||
config.eager_load = false
|
config.eager_load = false
|
||||||
|
|
||||||
# Configure static asset server for tests with Cache-Control for performance.
|
# Configure static file server for tests with Cache-Control for performance.
|
||||||
config.serve_static_assets = true
|
config.serve_static_files = true
|
||||||
config.static_cache_control = 'public, max-age=3600'
|
config.static_cache_control = 'public, max-age=3600'
|
||||||
|
|
||||||
# Show full error reports and disable caching.
|
# Show full error reports and disable caching.
|
||||||
@ -31,6 +31,9 @@ Rails.application.configure do
|
|||||||
# ActionMailer::Base.deliveries array.
|
# ActionMailer::Base.deliveries array.
|
||||||
config.action_mailer.delivery_method = :test
|
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.
|
# Print deprecation notices to the stderr.
|
||||||
config.active_support.deprecation = :stderr
|
config.active_support.deprecation = :stderr
|
||||||
|
|
||||||
|
12
config/initializers/assets.rb
Normal file
12
config/initializers/assets.rb
Normal file
@ -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 )
|
@ -1,3 +1,3 @@
|
|||||||
# Be sure to restart your server when you modify this file.
|
# 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'
|
||||||
|
@ -217,10 +217,10 @@ de:
|
|||||||
submit: Code zur Bewertung abgeben
|
submit: Code zur Bewertung abgeben
|
||||||
test: Testen
|
test: Testen
|
||||||
timeout: 'Ausführung gestoppt. Ihr Code hat die erlaubte Ausführungszeit von %{permitted_execution_time} Sekunden überschritten.'
|
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:
|
tooltips:
|
||||||
save: Ihr Code wird automatisch gespeichert, wann immer Sie eine Datei herunterladen, ausführen oder testen. Explizites Speichern ist also selten notwendig.
|
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."
|
request_for_comments_sent: "Kommentaranfrage gesendet."
|
||||||
editor_file_tree:
|
editor_file_tree:
|
||||||
file_root: Dateien
|
file_root: Dateien
|
||||||
@ -386,6 +386,7 @@ de:
|
|||||||
score: Ihre Punktzahl
|
score: Ihre Punktzahl
|
||||||
success_with_outcome: 'Ihr Code wurde erfolgreich bewertet. Ihre Bewertung wurde an %{consumer} übermittelt.'
|
success_with_outcome: 'Ihr Code wurde erfolgreich bewertet. Ihre Bewertung wurde an %{consumer} übermittelt.'
|
||||||
success_without_outcome: Ihr Code wurde erfolgreich bewertet.
|
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:
|
new:
|
||||||
forgot_password: Passwort vergessen?
|
forgot_password: Passwort vergessen?
|
||||||
headline: Anmelden
|
headline: Anmelden
|
||||||
|
@ -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:
|
en:
|
||||||
activerecord:
|
activerecord:
|
||||||
attributes:
|
attributes:
|
||||||
@ -217,10 +238,10 @@ en:
|
|||||||
submit: Submit Code For Assessment
|
submit: Submit Code For Assessment
|
||||||
test: Test
|
test: Test
|
||||||
timeout: 'Execution stopped. Your code exceeded the permitted execution time of %{permitted_execution_time} seconds.'
|
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:
|
tooltips:
|
||||||
save: Your code is automatically saved whenever you download, run, or test it. Therefore, explicitly saving is rarely necessary.
|
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."
|
request_for_comments_sent: "Request for comments sent."
|
||||||
editor_file_tree:
|
editor_file_tree:
|
||||||
file_root: Files
|
file_root: Files
|
||||||
@ -386,6 +407,7 @@ en:
|
|||||||
score: Your Score
|
score: Your Score
|
||||||
success_with_outcome: 'Your code has been successfully assessed. Your grade has been transmitted to %{consumer}.'
|
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.
|
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:
|
new:
|
||||||
forgot_password: Forgot password?
|
forgot_password: Forgot password?
|
||||||
headline: Sign In
|
headline: Sign In
|
||||||
@ -466,3 +488,4 @@ en:
|
|||||||
previous_label: '← Previous Page'
|
previous_label: '← Previous Page'
|
||||||
file_template:
|
file_template:
|
||||||
no_template_label: "Empty File"
|
no_template_label: "Empty File"
|
||||||
|
|
||||||
|
11
db/migrate/20170112151637_create_lti_parameters.rb
Normal file
11
db/migrate/20170112151637_create_lti_parameters.rb
Normal file
@ -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
|
133
db/schema.rb
133
db/schema.rb
@ -11,13 +11,13 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# 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
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
||||||
create_table "code_harbor_links", force: true do |t|
|
create_table "code_harbor_links", force: :cascade do |t|
|
||||||
t.string "oauth2token"
|
t.string "oauth2token", limit: 255
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.integer "user_id"
|
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
|
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 "user_id"
|
||||||
t.integer "file_id"
|
t.integer "file_id"
|
||||||
t.string "user_type"
|
t.string "user_type", limit: 255
|
||||||
t.integer "row"
|
t.integer "row"
|
||||||
t.integer "column"
|
t.integer "column"
|
||||||
t.text "text"
|
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", ["file_id"], name: "index_comments_on_file_id", using: :btree
|
||||||
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
|
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
|
||||||
|
|
||||||
create_table "consumers", force: true do |t|
|
create_table "consumers", force: :cascade do |t|
|
||||||
t.string "name"
|
t.string "name", limit: 255
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "oauth_key"
|
t.string "oauth_key", limit: 255
|
||||||
t.string "oauth_secret"
|
t.string "oauth_secret", limit: 255
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "errors", force: true do |t|
|
create_table "errors", force: :cascade do |t|
|
||||||
t.integer "execution_environment_id"
|
t.integer "execution_environment_id"
|
||||||
t.text "message"
|
t.text "message"
|
||||||
t.datetime "created_at"
|
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
|
add_index "errors", ["submission_id"], name: "index_errors_on_submission_id", using: :btree
|
||||||
|
|
||||||
create_table "execution_environments", force: true do |t|
|
create_table "execution_environments", force: :cascade do |t|
|
||||||
t.string "docker_image"
|
t.string "docker_image", limit: 255
|
||||||
t.string "name"
|
t.string "name", limit: 255
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "run_command"
|
t.string "run_command", limit: 255
|
||||||
t.string "test_command"
|
t.string "test_command", limit: 255
|
||||||
t.string "testing_framework"
|
t.string "testing_framework", limit: 255
|
||||||
t.text "help"
|
t.text "help"
|
||||||
t.string "exposed_ports"
|
t.string "exposed_ports", limit: 255
|
||||||
t.integer "permitted_execution_time"
|
t.integer "permitted_execution_time"
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.string "user_type"
|
t.string "user_type", limit: 255
|
||||||
t.integer "pool_size"
|
t.integer "pool_size"
|
||||||
t.integer "file_type_id"
|
t.integer "file_type_id"
|
||||||
t.integer "memory_limit"
|
t.integer "memory_limit"
|
||||||
t.boolean "network_enabled"
|
t.boolean "network_enabled"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "exercises", force: true do |t|
|
create_table "exercises", force: :cascade do |t|
|
||||||
t.text "description"
|
t.text "description"
|
||||||
t.integer "execution_environment_id"
|
t.integer "execution_environment_id"
|
||||||
t.string "title"
|
t.string "title", limit: 255
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.text "instructions"
|
t.text "instructions"
|
||||||
t.boolean "public"
|
t.boolean "public"
|
||||||
t.string "user_type"
|
t.string "user_type", limit: 255
|
||||||
t.string "token"
|
t.string "token", limit: 255
|
||||||
t.boolean "hide_file_tree"
|
t.boolean "hide_file_tree"
|
||||||
t.boolean "allow_file_creation"
|
t.boolean "allow_file_creation"
|
||||||
t.boolean "allow_auto_completion", default: false
|
t.boolean "allow_auto_completion", default: false
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "external_users", force: true do |t|
|
create_table "external_users", force: :cascade do |t|
|
||||||
t.integer "consumer_id"
|
t.integer "consumer_id"
|
||||||
t.string "email"
|
t.string "email", limit: 255
|
||||||
t.string "external_id"
|
t.string "external_id", limit: 255
|
||||||
t.string "name"
|
t.string "name", limit: 255
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "file_templates", force: true do |t|
|
create_table "file_templates", force: :cascade do |t|
|
||||||
t.string "name"
|
t.string "name", limit: 255
|
||||||
t.text "content"
|
t.text "content"
|
||||||
t.integer "file_type_id"
|
t.integer "file_type_id"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "file_types", force: true do |t|
|
create_table "file_types", force: :cascade do |t|
|
||||||
t.string "editor_mode"
|
t.string "editor_mode", limit: 255
|
||||||
t.string "file_extension"
|
t.string "file_extension", limit: 255
|
||||||
t.integer "indent_size"
|
t.integer "indent_size"
|
||||||
t.string "name"
|
t.string "name", limit: 255
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.boolean "executable"
|
t.boolean "executable"
|
||||||
t.boolean "renderable"
|
t.boolean "renderable"
|
||||||
t.string "user_type"
|
t.string "user_type", limit: 255
|
||||||
t.boolean "binary"
|
t.boolean "binary"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "files", force: true do |t|
|
create_table "files", force: :cascade do |t|
|
||||||
t.text "content"
|
t.text "content"
|
||||||
t.integer "context_id"
|
t.integer "context_id"
|
||||||
t.string "context_type"
|
t.string "context_type", limit: 255
|
||||||
t.integer "file_id"
|
t.integer "file_id"
|
||||||
t.integer "file_type_id"
|
t.integer "file_type_id"
|
||||||
t.boolean "hidden"
|
t.boolean "hidden"
|
||||||
t.string "name"
|
t.string "name", limit: 255
|
||||||
t.boolean "read_only"
|
t.boolean "read_only"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "native_file"
|
t.string "native_file", limit: 255
|
||||||
t.string "role"
|
t.string "role", limit: 255
|
||||||
t.string "hashed_content"
|
t.string "hashed_content", limit: 255
|
||||||
t.string "feedback_message"
|
t.string "feedback_message", limit: 255
|
||||||
t.float "weight"
|
t.float "weight"
|
||||||
t.string "path"
|
t.string "path", limit: 255
|
||||||
t.integer "file_template_id"
|
t.integer "file_template_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "files", ["context_id", "context_type"], name: "index_files_on_context_id_and_context_type", using: :btree
|
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.integer "execution_environment_id"
|
||||||
t.string "locale"
|
t.string "locale", limit: 255
|
||||||
t.text "message"
|
t.text "message"
|
||||||
t.string "name"
|
t.string "name", limit: 255
|
||||||
t.string "regular_expression"
|
t.string "regular_expression", limit: 255
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "internal_users", force: true do |t|
|
create_table "internal_users", force: :cascade do |t|
|
||||||
t.integer "consumer_id"
|
t.integer "consumer_id"
|
||||||
t.string "email"
|
t.string "email", limit: 255
|
||||||
t.string "name"
|
t.string "name", limit: 255
|
||||||
t.string "role"
|
t.string "role", limit: 255
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "crypted_password"
|
t.string "crypted_password", limit: 255
|
||||||
t.string "salt"
|
t.string "salt", limit: 255
|
||||||
t.integer "failed_logins_count", default: 0
|
t.integer "failed_logins_count", default: 0
|
||||||
t.datetime "lock_expires_at"
|
t.datetime "lock_expires_at"
|
||||||
t.string "unlock_token"
|
t.string "unlock_token", limit: 255
|
||||||
t.string "remember_me_token"
|
t.string "remember_me_token", limit: 255
|
||||||
t.datetime "remember_me_token_expires_at"
|
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_token_expires_at"
|
||||||
t.datetime "reset_password_email_sent_at"
|
t.datetime "reset_password_email_sent_at"
|
||||||
t.string "activation_state"
|
t.string "activation_state", limit: 255
|
||||||
t.string "activation_token"
|
t.string "activation_token", limit: 255
|
||||||
t.datetime "activation_token_expires_at"
|
t.datetime "activation_token_expires_at"
|
||||||
end
|
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", ["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
|
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|
|
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"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "request_for_comments", force: :cascade do |t|
|
||||||
t.integer "user_id", null: false
|
t.integer "user_id", null: false
|
||||||
t.integer "exercise_id", null: false
|
t.integer "exercise_id", null: false
|
||||||
t.integer "file_id", null: false
|
t.integer "file_id", null: false
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "user_type"
|
t.string "user_type", limit: 255
|
||||||
t.text "question"
|
t.text "question"
|
||||||
t.boolean "solved"
|
t.boolean "solved"
|
||||||
t.integer "submission_id"
|
t.integer "submission_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "submissions", force: true do |t|
|
create_table "submissions", force: :cascade do |t|
|
||||||
t.integer "exercise_id"
|
t.integer "exercise_id"
|
||||||
t.float "score"
|
t.float "score"
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "cause"
|
t.string "cause", limit: 255
|
||||||
t.string "user_type"
|
t.string "user_type", limit: 255
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "testruns", force: true do |t|
|
create_table "testruns", force: :cascade do |t|
|
||||||
t.boolean "passed"
|
t.boolean "passed"
|
||||||
t.text "output"
|
t.text "output"
|
||||||
t.integer "file_id"
|
t.integer "file_id"
|
||||||
|
1122
db/structure.sql
Normal file
1122
db/structure.sql
Normal file
File diff suppressed because it is too large
Load Diff
69
debian_installer/setup_debian_1_install_postgres.sh
Normal file
69
debian_installer/setup_debian_1_install_postgres.sh
Normal file
@ -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 <<EOF
|
||||||
|
#CodeOcean: drop access control
|
||||||
|
local all all trust
|
||||||
|
host all all 127.0.0.1/32 trust
|
||||||
|
host all all ::1/128 trust
|
||||||
|
EOF'
|
||||||
|
echo "Done"
|
||||||
|
echo "Restart Postgres..."
|
||||||
|
echo sudo service postgresql restart
|
||||||
|
echo "Done"
|
||||||
|
else
|
||||||
|
echo "Postgres access control already dropped"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Postgres installation failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create development database
|
||||||
|
# TODO: extract databasename to variable
|
||||||
|
if ! (sudo -u postgres psql -l | grep -q codeocean-development)
|
||||||
|
then
|
||||||
|
echo "Create database codeocean-development..."
|
||||||
|
sudo -u postgres createdb codeocean-development || true
|
||||||
|
sudo -u postgres psql -d codeocean-development -U postgres -c "CREATE USER root;"
|
||||||
|
sudo -u postgres psql -d codeocean-development -U postgres -c 'GRANT ALL PRIVILEGES ON DATABASE "codeocean-development" to root';
|
||||||
|
sudo -u postgres psql -d codeocean-development -U postgres -c "CREATE USER debian;"
|
||||||
|
sudo -u postgres psql -d codeocean-development -U postgres -c 'GRANT ALL PRIVILEGES ON DATABASE "codeocean-development" to debian';
|
||||||
|
sudo -u postgres psql -d codeocean-development -U postgres -c "CREATE USER codeocean;"
|
||||||
|
sudo -u postgres psql -d codeocean-development -U postgres -c 'GRANT ALL PRIVILEGES ON DATABASE "codeocean-development" to codeocean';
|
||||||
|
sudo -u postgres psql -d codeocean-development -U postgres -c 'ALTER DATABASE "codeocean-development" OWNER TO codeocean';
|
||||||
|
sudo -u postgres psql -d codeocean-development -U postgres -c 'ALTER USER "codeocean" CREATEDB';
|
||||||
|
echo "Done"
|
||||||
|
else
|
||||||
|
echo "Database codeocean-development already exists"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# TODO: create test database
|
||||||
|
|
||||||
|
|
||||||
|
|
86
debian_installer/setup_debian_2_install_docker.sh
Normal file
86
debian_installer/setup_debian_2_install_docker.sh
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#install docker
|
||||||
|
if [ ! -f /etc/apt/sources.list.d/backports.list ]
|
||||||
|
then
|
||||||
|
#get sources for dependencies
|
||||||
|
echo "Get apt-get sources for some docker dependencies..."
|
||||||
|
cd /etc/apt/sources.list.d
|
||||||
|
sudo touch backports.list
|
||||||
|
sudo sh -c 'echo "deb http://http.debian.net/debian jessie-backports main" > 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 <<EOF
|
||||||
|
# code_ocean: enable TCP
|
||||||
|
[Service]
|
||||||
|
ExecStart=
|
||||||
|
ExecStart=/usr/bin/dockerd -H fd:// -D -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock"
|
||||||
|
EOF'
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo service docker restart
|
||||||
|
|
||||||
|
# enable to run docker without sudo
|
||||||
|
sudo gpasswd -a ${USER} docker
|
||||||
|
newgrp docker
|
||||||
|
sudo service docker restart
|
||||||
|
echo "Done"
|
||||||
|
else
|
||||||
|
echo "Docker already installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! (docker images | grep -q co_execenv_python)
|
||||||
|
then
|
||||||
|
echo "Pull Docker images..."
|
||||||
|
# get docker images
|
||||||
|
docker pull openhpi/co_execenv_python
|
||||||
|
docker pull openhpi/co_execenv_java
|
||||||
|
docker pull openhpi/co_execenv_java_antlr
|
||||||
|
echo "Done"
|
||||||
|
else
|
||||||
|
echo "Docker images already pulled"
|
||||||
|
fi
|
@ -0,0 +1,67 @@
|
|||||||
|
if [ ! -f /etc/apt/sources.list.d/nonfree.list ]
|
||||||
|
then
|
||||||
|
echo "Get additional sources for apt-get"
|
||||||
|
cd /etc/apt/sources.list.d
|
||||||
|
sudo touch nonfree.list
|
||||||
|
sudo sh -c 'echo "deb http://http.debian.net/debian jessie main non-free contrib" > 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"
|
10
debian_installer/setup_debian_4_install_guest_additions.sh
Normal file
10
debian_installer/setup_debian_4_install_guest_additions.sh
Normal file
@ -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."
|
||||||
|
|
7
debian_installer/setup_debian_5_mount_shared_folder.sh
Normal file
7
debian_installer/setup_debian_5_mount_shared_folder.sh
Normal file
@ -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"
|
28
debian_installer/setup_debian_6_setup_codeocean.sh
Normal file
28
debian_installer/setup_debian_6_setup_codeocean.sh
Normal file
@ -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
|
8
debian_installer/setup_debian_7_create_tables.sh
Normal file
8
debian_installer/setup_debian_7_create_tables.sh
Normal file
@ -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
|
165
debian_installer/setup_debian_vm.sh
Normal file
165
debian_installer/setup_debian_vm.sh
Normal file
@ -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"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -325,7 +325,7 @@ class DockerClient
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.image_tags
|
def self.image_tags
|
||||||
Docker::Image.all.map { |image| image.info['RepoTags'] }.flatten.reject { |tag| tag.present? && tag.include?('<none>') }
|
Docker::Image.all.map { |image| image.info['RepoTags'] }.flatten.reject { |tag| tag.nil? || tag.include?('<none>') }
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(options = {})
|
def initialize(options = {})
|
||||||
|
@ -19,7 +19,6 @@ describe Lti do
|
|||||||
it 'clears the session' do
|
it 'clears the session' do
|
||||||
expect(controller.session).to receive(:delete).with(:consumer_id)
|
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(:external_user_id)
|
||||||
expect(controller.session).to receive(:delete).with(:lti_parameters)
|
|
||||||
controller.send(:clear_lti_session_data)
|
controller.send(:clear_lti_session_data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -106,24 +105,25 @@ describe Lti do
|
|||||||
describe '#send_score' do
|
describe '#send_score' do
|
||||||
let(:consumer) { FactoryGirl.create(:consumer) }
|
let(:consumer) { FactoryGirl.create(:consumer) }
|
||||||
let(:score) { 0.5 }
|
let(:score) { 0.5 }
|
||||||
|
let(:submission) { FactoryGirl.create(:submission) }
|
||||||
|
let!(:lti_parameter) { FactoryGirl.create(:lti_parameter)}
|
||||||
|
|
||||||
context 'with an invalid score' do
|
context 'with an invalid score' do
|
||||||
it 'raises an exception' 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
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with an valid score' do
|
context 'with an valid score' do
|
||||||
context 'with a tool provider' do
|
context 'with a tool consumer' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
controller.session[:consumer_id] = consumer.id
|
controller.session[:consumer_id] = consumer.id
|
||||||
controller.session[:lti_parameters] = {}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when grading is not supported' do
|
context 'when grading is not supported' do
|
||||||
it 'returns a corresponding status' do
|
it 'returns a corresponding status' do
|
||||||
expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(false)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -140,11 +140,11 @@ describe Lti do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'sends the score' do
|
it 'sends the score' do
|
||||||
controller.send(:send_score, score)
|
controller.send(:send_score, submission.exercise_id, score, submission.user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns code, message, and status' do
|
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[:code]).to eq(response.response_code)
|
||||||
expect(result[:message]).to eq(response.body)
|
expect(result[:message]).to eq(response.body)
|
||||||
expect(result[:status]).to eq(response.code_major)
|
expect(result[:status]).to eq(response.code_major)
|
||||||
@ -152,10 +152,9 @@ describe Lti do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without a tool provider' do
|
context 'without a tool consumer' do
|
||||||
it 'returns a corresponding status' do
|
it 'returns a corresponding status' do
|
||||||
expect(controller).to receive(:build_tool_provider).and_return(nil)
|
expect(controller.send(:send_score, submission.exercise_id, score, submission.user_id)[:status]).to eq('error')
|
||||||
expect(controller.send(:send_score, score)[:status]).to eq('error')
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -163,17 +162,18 @@ describe Lti do
|
|||||||
|
|
||||||
describe '#store_lti_session_data' do
|
describe '#store_lti_session_data' do
|
||||||
let(:parameters) { {} }
|
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
|
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(:consumer_id, anything)
|
||||||
expect(controller.session).to receive(:[]=).with(:external_user_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
|
end
|
||||||
|
|
||||||
it 'stores only selected tuples' do
|
it 'it creates an LtiParameter Object' do
|
||||||
expect(parameters).to receive(:slice).with(*Lti::SESSION_PARAMETERS)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -230,11 +230,14 @@ describe ExercisesController do
|
|||||||
describe 'POST #submit' do
|
describe 'POST #submit' do
|
||||||
let(:output) { {} }
|
let(:output) { {} }
|
||||||
let(:request) { post :submit, format: :json, id: exercise.id, submission: {cause: 'submit', exercise_id: exercise.id} }
|
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
|
before(:each) do
|
||||||
allow_any_instance_of(Submission).to receive(:normalized_score).and_return(1)
|
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(:collect_test_results).and_return([{score: 1, weight: 1}])
|
||||||
expect(controller).to receive(:score_submission).and_call_original
|
expect(controller).to receive(:score_submission).and_call_original
|
||||||
|
controller.session[:consumer_id] = external_user.consumer_id
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when LTI outcomes are supported' do
|
context 'when LTI outcomes are supported' do
|
||||||
|
@ -93,6 +93,7 @@ describe SessionsController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'stores LTI parameters in the session' do
|
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)
|
expect(controller).to receive(:store_lti_session_data)
|
||||||
request
|
request
|
||||||
end
|
end
|
||||||
@ -159,6 +160,7 @@ describe SessionsController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'clears the session' do
|
it 'clears the session' do
|
||||||
|
#Todo replace session with lti_parameter /should be done already
|
||||||
expect(controller).to receive(:clear_lti_session_data)
|
expect(controller).to receive(:clear_lti_session_data)
|
||||||
delete :destroy
|
delete :destroy
|
||||||
end
|
end
|
||||||
@ -174,13 +176,16 @@ describe SessionsController do
|
|||||||
let(:submission) { FactoryGirl.create(:submission, exercise: FactoryGirl.create(:dummy)) }
|
let(:submission) { FactoryGirl.create(:submission, exercise: FactoryGirl.create(:dummy)) }
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
|
#Todo replace session with lti_parameter
|
||||||
session[:consumer_id] = consumer.id
|
session[:consumer_id] = consumer.id
|
||||||
session[:lti_parameters] = {}
|
#Todo create LtiParameter Object
|
||||||
|
# session[:lti_parameters] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:each) { request.call }
|
before(:each) { request.call }
|
||||||
|
|
||||||
it 'clears the session' do
|
it 'clears the session' do
|
||||||
|
#Todo replace session with lti_parameter /should be done already
|
||||||
expect(controller).to receive(:clear_lti_session_data)
|
expect(controller).to receive(:clear_lti_session_data)
|
||||||
request.call
|
request.call
|
||||||
end
|
end
|
||||||
|
@ -32,7 +32,7 @@ FactoryGirl.define do
|
|||||||
factory :java, class: ExecutionEnvironment do
|
factory :java, class: ExecutionEnvironment do
|
||||||
created_by_teacher
|
created_by_teacher
|
||||||
default_memory_limit
|
default_memory_limit
|
||||||
docker_image 'hklement/ubuntu-java:latest'
|
docker_image 'openhpi/co_execenv_java:latest'
|
||||||
association :file_type, factory: :dot_java
|
association :file_type, factory: :dot_java
|
||||||
help
|
help
|
||||||
name 'Java 8'
|
name 'Java 8'
|
||||||
@ -78,7 +78,7 @@ FactoryGirl.define do
|
|||||||
factory :python, class: ExecutionEnvironment do
|
factory :python, class: ExecutionEnvironment do
|
||||||
created_by_teacher
|
created_by_teacher
|
||||||
default_memory_limit
|
default_memory_limit
|
||||||
docker_image 'hklement/ubuntu-python:latest'
|
docker_image 'openhpi/co_execenv_python:latest'
|
||||||
association :file_type, factory: :dot_py
|
association :file_type, factory: :dot_py
|
||||||
help
|
help
|
||||||
name 'Python 3.4'
|
name 'Python 3.4'
|
||||||
|
20
spec/factories/lti_parameter.rb
Normal file
20
spec/factories/lti_parameter.rb
Normal file
@ -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
|
@ -2,7 +2,7 @@ FactoryGirl.define do
|
|||||||
factory :submission do
|
factory :submission do
|
||||||
cause 'save'
|
cause 'save'
|
||||||
created_by_external_user
|
created_by_external_user
|
||||||
association :exercise, factory: :fibonacci
|
association :exercise, factory: :math
|
||||||
|
|
||||||
after(:create) do |submission|
|
after(:create) do |submission|
|
||||||
submission.exercise.files.editable.visible.each do |file|
|
submission.exercise.files.editable.visible.each do |file|
|
||||||
|
@ -3,8 +3,8 @@ require 'seeds_helper'
|
|||||||
|
|
||||||
describe DockerClient, docker: true do
|
describe DockerClient, docker: true do
|
||||||
let(:command) { 'whoami' }
|
let(:command) { 'whoami' }
|
||||||
let(:docker_client) { described_class.new(execution_environment: FactoryGirl.build(:ruby), user: FactoryGirl.build(:admin)) }
|
let(:docker_client) { described_class.new(execution_environment: FactoryGirl.build(:java), user: FactoryGirl.build(:admin)) }
|
||||||
let(:execution_environment) { FactoryGirl.build(:ruby) }
|
let(:execution_environment) { FactoryGirl.build(:java) }
|
||||||
let(:image) { double }
|
let(:image) { double }
|
||||||
let(:submission) { FactoryGirl.create(:submission) }
|
let(:submission) { FactoryGirl.create(:submission) }
|
||||||
let(:workspace_path) { '/tmp' }
|
let(:workspace_path) { '/tmp' }
|
||||||
|
Reference in New Issue
Block a user