@ -6,6 +6,7 @@ services:
|
||||
addons:
|
||||
code_climate:
|
||||
repo_token: 53a2c2608c848714e96f6a1fc0365dcfdfec051f7827d50cea965ea625f49734
|
||||
postgresql: "9.5"
|
||||
|
||||
before_install:
|
||||
- export DISPLAY=:99.0
|
||||
|
2
Gemfile
2
Gemfile
@ -21,7 +21,7 @@ gem 'pg', platform: :ruby
|
||||
gem 'pry-byebug'
|
||||
gem 'puma', '~> 2.15.3'
|
||||
gem 'pundit'
|
||||
gem 'rails', '~> 4.1.13'
|
||||
gem 'rails', '4.2.5'
|
||||
gem 'rails-i18n', '~> 4.0.0'
|
||||
gem 'ransack'
|
||||
gem 'rubytree'
|
||||
|
131
Gemfile.lock
131
Gemfile.lock
@ -2,40 +2,49 @@ GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
ZenTest (4.11.0)
|
||||
actionmailer (4.1.14.1)
|
||||
actionpack (= 4.1.14.1)
|
||||
actionview (= 4.1.14.1)
|
||||
actionmailer (4.2.5)
|
||||
actionpack (= 4.2.5)
|
||||
actionview (= 4.2.5)
|
||||
activejob (= 4.2.5)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
actionpack (4.1.14.1)
|
||||
actionview (= 4.1.14.1)
|
||||
activesupport (= 4.1.14.1)
|
||||
rack (~> 1.5.2)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
actionpack (4.2.5)
|
||||
actionview (= 4.2.5)
|
||||
activesupport (= 4.2.5)
|
||||
rack (~> 1.6)
|
||||
rack-test (~> 0.6.2)
|
||||
actionview (4.1.14.1)
|
||||
activesupport (= 4.1.14.1)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (4.2.5)
|
||||
activesupport (= 4.2.5)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
activemodel (4.1.14.1)
|
||||
activesupport (= 4.1.14.1)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
activejob (4.2.5)
|
||||
activesupport (= 4.2.5)
|
||||
globalid (>= 0.3.0)
|
||||
activemodel (4.2.5)
|
||||
activesupport (= 4.2.5)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.1.14.1)
|
||||
activemodel (= 4.1.14.1)
|
||||
activesupport (= 4.1.14.1)
|
||||
arel (~> 5.0.0)
|
||||
activerecord (4.2.5)
|
||||
activemodel (= 4.2.5)
|
||||
activesupport (= 4.2.5)
|
||||
arel (~> 6.0)
|
||||
activerecord-jdbc-adapter (1.3.19)
|
||||
activerecord (>= 2.2)
|
||||
activerecord-jdbcpostgresql-adapter (1.3.19)
|
||||
activerecord-jdbc-adapter (~> 1.3.19)
|
||||
jdbc-postgres (>= 9.1)
|
||||
activesupport (4.1.14.1)
|
||||
i18n (~> 0.6, >= 0.6.9)
|
||||
activesupport (4.2.5)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.4.0)
|
||||
arel (5.0.1.20140414130214)
|
||||
ast (2.2.0)
|
||||
arel (6.0.4)
|
||||
ast (2.3.0)
|
||||
autotest-rails (4.2.1)
|
||||
ZenTest (~> 4.5)
|
||||
bcrypt (3.1.10)
|
||||
@ -129,6 +138,8 @@ GEM
|
||||
ffi (1.9.10)
|
||||
ffi (1.9.10-java)
|
||||
forgery (0.6.0)
|
||||
globalid (0.3.7)
|
||||
activesupport (>= 4.1.0)
|
||||
highline (1.7.8)
|
||||
hike (1.2.3)
|
||||
http-cookie (1.0.2)
|
||||
@ -151,13 +162,15 @@ GEM
|
||||
json (1.8.3-java)
|
||||
jwt (1.5.1)
|
||||
kramdown (1.9.0)
|
||||
mail (2.6.3)
|
||||
mime-types (>= 1.16, < 3)
|
||||
loofah (2.0.3)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.6.4)
|
||||
mime-types (>= 1.16, < 4)
|
||||
method_source (0.8.2)
|
||||
mime-types (2.99)
|
||||
mini_portile2 (2.0.0)
|
||||
minitest (5.9.0)
|
||||
multi_json (1.11.2)
|
||||
mime-types (2.99.3)
|
||||
mini_portile2 (2.1.0)
|
||||
minitest (5.10.1)
|
||||
multi_json (1.12.1)
|
||||
multi_xml (0.5.5)
|
||||
multipart-post (2.0.0)
|
||||
net-scp (1.2.1)
|
||||
@ -165,9 +178,9 @@ GEM
|
||||
net-ssh (3.0.2)
|
||||
netrc (0.10.3)
|
||||
newrelic_rpm (3.14.3.313)
|
||||
nokogiri (1.6.7.2)
|
||||
mini_portile2 (~> 2.0.0.rc2)
|
||||
nokogiri (1.6.7.2-java)
|
||||
nokogiri (1.7.0.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
nokogiri (1.7.0.1-java)
|
||||
nyan-cat-formatter (0.11)
|
||||
rspec (>= 2.99, >= 2.14.2, < 4)
|
||||
oauth (0.4.7)
|
||||
@ -179,7 +192,7 @@ GEM
|
||||
rack (>= 1.2, < 3)
|
||||
pagedown-rails (1.1.4)
|
||||
railties (> 3.1)
|
||||
parser (2.3.0.6)
|
||||
parser (2.3.3.1)
|
||||
ast (~> 2.2)
|
||||
pg (0.18.4)
|
||||
polyamorous (1.3.0)
|
||||
@ -201,31 +214,40 @@ GEM
|
||||
puma (2.15.3-java)
|
||||
pundit (1.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
rack (1.5.5)
|
||||
rack (1.6.5)
|
||||
rack-mini-profiler (0.10.1)
|
||||
rack (>= 1.2.0)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (4.1.14.1)
|
||||
actionmailer (= 4.1.14.1)
|
||||
actionpack (= 4.1.14.1)
|
||||
actionview (= 4.1.14.1)
|
||||
activemodel (= 4.1.14.1)
|
||||
activerecord (= 4.1.14.1)
|
||||
activesupport (= 4.1.14.1)
|
||||
rails (4.2.5)
|
||||
actionmailer (= 4.2.5)
|
||||
actionpack (= 4.2.5)
|
||||
actionview (= 4.2.5)
|
||||
activejob (= 4.2.5)
|
||||
activemodel (= 4.2.5)
|
||||
activerecord (= 4.2.5)
|
||||
activesupport (= 4.2.5)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 4.1.14.1)
|
||||
sprockets-rails (~> 2.0)
|
||||
railties (= 4.2.5)
|
||||
sprockets-rails
|
||||
rails-deprecated_sanitizer (1.0.3)
|
||||
activesupport (>= 4.2.0.alpha)
|
||||
rails-dom-testing (1.0.8)
|
||||
activesupport (>= 4.2.0.beta, < 5.0)
|
||||
nokogiri (~> 1.6)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
rails-i18n (4.0.8)
|
||||
i18n (~> 0.7)
|
||||
railties (~> 4.0)
|
||||
railties (4.1.14.1)
|
||||
actionpack (= 4.1.14.1)
|
||||
activesupport (= 4.1.14.1)
|
||||
railties (4.2.5)
|
||||
actionpack (= 4.2.5)
|
||||
activesupport (= 4.2.5)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.1.0)
|
||||
rake (10.5.0)
|
||||
rainbow (2.2.1)
|
||||
rake (12.0.0)
|
||||
ransack (1.7.0)
|
||||
actionpack (>= 3.0)
|
||||
activerecord (>= 3.0)
|
||||
@ -244,7 +266,7 @@ GEM
|
||||
rspec-mocks (~> 3.4.0)
|
||||
rspec-autotest (1.0.0)
|
||||
rspec-core (>= 2.99.0.beta1, < 4.0.0)
|
||||
rspec-core (3.4.2)
|
||||
rspec-core (3.4.4)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-expectations (3.4.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
@ -261,14 +283,15 @@ GEM
|
||||
rspec-mocks (~> 3.4.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-support (3.4.1)
|
||||
rubocop (0.37.2)
|
||||
parser (>= 2.3.0.4, < 3.0)
|
||||
rubocop (0.46.0)
|
||||
parser (>= 2.3.1.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 0.3)
|
||||
rubocop-rspec (1.4.0)
|
||||
ruby-progressbar (1.7.5)
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
rubocop-rspec (1.9.0)
|
||||
rubocop (>= 0.42.0)
|
||||
ruby-progressbar (1.8.1)
|
||||
rubytree (0.9.7)
|
||||
json (~> 1.8)
|
||||
structured_warnings (~> 0.2)
|
||||
@ -317,7 +340,7 @@ GEM
|
||||
net-ssh (>= 2.8.0)
|
||||
structured_warnings (0.2.0)
|
||||
temple (0.7.6)
|
||||
thor (0.19.1)
|
||||
thor (0.19.4)
|
||||
thread_safe (0.3.5)
|
||||
thread_safe (0.3.5-java)
|
||||
tilt (1.4.1)
|
||||
@ -335,7 +358,7 @@ GEM
|
||||
unf_ext
|
||||
unf (0.1.4-java)
|
||||
unf_ext (0.0.7.1)
|
||||
unicode-display_width (0.3.1)
|
||||
unicode-display_width (1.1.2)
|
||||
web-console (2.3.0)
|
||||
activemodel (>= 4.0)
|
||||
binding_of_caller (>= 0.7.2)
|
||||
@ -396,7 +419,7 @@ DEPENDENCIES
|
||||
puma (~> 2.15.3)
|
||||
pundit
|
||||
rack-mini-profiler
|
||||
rails (~> 4.1.13)
|
||||
rails (= 4.2.5)
|
||||
rails-i18n (~> 4.0.0)
|
||||
rake
|
||||
ransack
|
||||
|
@ -2,8 +2,11 @@ CodeOceanEditorWebsocket = {
|
||||
websocket: null,
|
||||
|
||||
createSocketUrl: function(url) {
|
||||
var rel_url_root = '<%= (defined? config.relative_url_root) && config.relative_url_root != nil && config.relative_url_root != "" ? config.relative_url_root : "" %>';
|
||||
return '<%= DockerClient.config['ws_client_protocol'] %>' + window.location.hostname + ':' + rel_url_root + window.location.port + url;
|
||||
var sockURL = new URL(window.location);
|
||||
sockURL.pathname = url;
|
||||
sockURL.protocol = '<%= DockerClient.config['ws_client_protocol'] %>';
|
||||
|
||||
return sockURL.toString();
|
||||
},
|
||||
|
||||
initializeSocket: function(url) {
|
||||
|
@ -59,6 +59,8 @@ CodeOceanEditorCodePilot = {
|
||||
}
|
||||
};
|
||||
|
||||
//Request for comments does currently not work on staging platform (no relative root_url used here).
|
||||
//To fix this rely on ruby routes
|
||||
CodeOceanEditorRequestForComments = {
|
||||
requestComments: function () {
|
||||
var user_id = $('#editor').data('user-id');
|
||||
|
@ -10,7 +10,6 @@ class ApplicationController < ActionController::Base
|
||||
rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized
|
||||
|
||||
def current_user
|
||||
::NewRelic::Agent.add_custom_parameters({ external_user_id: session[:external_user_id], session_user_id: session[:user_id] })
|
||||
@current_user ||= ExternalUser.find_by(id: session[:external_user_id]) || login_from_session || login_from_other_sources
|
||||
end
|
||||
|
||||
|
@ -2,6 +2,7 @@ require 'oauth/request_proxy/rack_request'
|
||||
|
||||
module Lti
|
||||
extend ActiveSupport::Concern
|
||||
include LtiHelper
|
||||
|
||||
MAXIMUM_SCORE = 1
|
||||
MAXIMUM_SESSION_AGE = 60.minutes
|
||||
@ -14,10 +15,18 @@ module Lti
|
||||
end
|
||||
private :build_tool_provider
|
||||
|
||||
def clear_lti_session_data
|
||||
# exercise_id.nil? ==> the user has logged out. All session data is to be destroyed
|
||||
# exercise_id.exists? ==> the user has submitted the results of an exercise to the consumer.
|
||||
# Only the lti_parameters are deleted.
|
||||
def clear_lti_session_data(exercise_id = nil, user_id = nil, consumer_id = nil)
|
||||
if (exercise_id.nil?)
|
||||
session.delete(:consumer_id)
|
||||
session.delete(:external_user_id)
|
||||
session.delete(:lti_parameters)
|
||||
else
|
||||
LtiParameter.destroy_all(consumers_id: consumer_id,
|
||||
external_users_id: user_id,
|
||||
exercises_id: exercise_id)
|
||||
end
|
||||
end
|
||||
private :clear_lti_session_data
|
||||
|
||||
@ -43,11 +52,6 @@ module Lti
|
||||
end
|
||||
private :external_user_name
|
||||
|
||||
def lti_outcome_service?
|
||||
session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url')
|
||||
end
|
||||
private :lti_outcome_service?
|
||||
|
||||
def refuse_lti_launch(options = {})
|
||||
return_to_consumer(lti_errorlog: options[:message], lti_errormsg: t('sessions.oauth.failure'))
|
||||
end
|
||||
@ -94,10 +98,19 @@ module Lti
|
||||
end
|
||||
private :return_to_consumer
|
||||
|
||||
def send_score(score)
|
||||
def send_score(exercise_id, score, user_id)
|
||||
::NewRelic::Agent.add_custom_parameters({ score: score, session: session })
|
||||
fail(Error, "Score #{score} must be between 0 and #{MAXIMUM_SCORE}!") unless (0..MAXIMUM_SCORE).include?(score)
|
||||
provider = build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters])
|
||||
|
||||
if session[:consumer_id]
|
||||
lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id],
|
||||
external_users_id: user_id,
|
||||
exercises_id: exercise_id).first
|
||||
|
||||
consumer = Consumer.find_by(id: session[:consumer_id])
|
||||
provider = build_tool_provider(consumer: consumer, parameters: lti_parameter.lti_parameters)
|
||||
end
|
||||
|
||||
if provider.nil?
|
||||
{status: 'error'}
|
||||
elsif provider.outcome_service?
|
||||
@ -116,9 +129,19 @@ module Lti
|
||||
private :set_current_user
|
||||
|
||||
def store_lti_session_data(options = {})
|
||||
exercise = Exercise.where(token: options[:parameters][:custom_token]).first
|
||||
exercise_id = exercise.id unless exercise.nil?
|
||||
|
||||
current_user = ExternalUser.find_or_create_by(consumer_id: options[:consumer].id, external_id: options[:parameters][:user_id].to_s)
|
||||
lti_parameters = LtiParameter.find_or_create_by(consumers_id: options[:consumer].id,
|
||||
external_users_id: current_user.id,
|
||||
exercises_id: exercise_id)
|
||||
|
||||
lti_parameters.lti_parameters = options[:parameters].slice(*SESSION_PARAMETERS).to_json
|
||||
lti_parameters.save!
|
||||
|
||||
session[:consumer_id] = options[:consumer].id
|
||||
session[:external_user_id] = @current_user.id
|
||||
session[:lti_parameters] = options[:parameters].slice(*SESSION_PARAMETERS)
|
||||
session[:external_user_id] = current_user.id
|
||||
end
|
||||
private :store_lti_session_data
|
||||
|
||||
|
@ -157,7 +157,14 @@ class ExercisesController < ApplicationController
|
||||
end
|
||||
|
||||
def redirect_to_lti_return_path
|
||||
path = lti_return_path(consumer_id: session[:consumer_id], submission_id: @submission.id, url: consumer_return_url(build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters])))
|
||||
lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id],
|
||||
external_users_id: @submission.user_id,
|
||||
exercises_id: @submission.exercise_id).first
|
||||
|
||||
path = lti_return_path(consumer_id: session[:consumer_id],
|
||||
submission_id: @submission.id,
|
||||
url: consumer_return_url(build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]),
|
||||
parameters: lti_parameter.lti_parameters)))
|
||||
respond_to do |format|
|
||||
format.html { redirect_to(path) }
|
||||
format.json { render(json: {redirect: path}) }
|
||||
@ -221,7 +228,8 @@ class ExercisesController < ApplicationController
|
||||
def submit
|
||||
@submission = Submission.create(submission_params)
|
||||
score_submission(@submission)
|
||||
if lti_outcome_service?
|
||||
current_user = ExternalUser.find(@submission.user_id)
|
||||
if !current_user.nil? && lti_outcome_service?(@submission.exercise_id, current_user.id, current_user.consumer_id)
|
||||
transmit_lti_score
|
||||
else
|
||||
redirect_after_submit
|
||||
@ -230,7 +238,8 @@ class ExercisesController < ApplicationController
|
||||
|
||||
def transmit_lti_score
|
||||
::NewRelic::Agent.add_custom_parameters({ submission: @submission.id, normalized_score: @submission.normalized_score })
|
||||
response = send_score(@submission.normalized_score)
|
||||
response = send_score(@submission.exercise_id, @submission.normalized_score, @submission.user_id)
|
||||
|
||||
if response[:status] == 'success'
|
||||
redirect_after_submit
|
||||
else
|
||||
|
@ -21,7 +21,9 @@ class SessionsController < ApplicationController
|
||||
set_current_user
|
||||
store_lti_session_data(consumer: @consumer, parameters: params)
|
||||
store_nonce(params[:oauth_nonce])
|
||||
redirect_to(implement_exercise_path(@exercise), notice: t("sessions.create_through_lti.session_#{lti_outcome_service? ? 'with' : 'without'}_outcome", consumer: @consumer))
|
||||
redirect_to(implement_exercise_path(@exercise),
|
||||
notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id , @consumer.id) ? 'with' : 'without'}_outcome",
|
||||
consumer: @consumer))
|
||||
end
|
||||
|
||||
def destroy
|
||||
@ -34,9 +36,8 @@ class SessionsController < ApplicationController
|
||||
end
|
||||
|
||||
def destroy_through_lti
|
||||
@consumer = Consumer.find_by(id: params[:consumer_id])
|
||||
@submission = Submission.find(params[:submission_id])
|
||||
clear_lti_session_data
|
||||
clear_lti_session_data(@submission.exercise_id, @submission.user_id, params[:consumer_id])
|
||||
end
|
||||
|
||||
def new
|
||||
|
@ -1,4 +1,6 @@
|
||||
module ExerciseHelper
|
||||
include LtiHelper
|
||||
|
||||
def embedding_parameters(exercise)
|
||||
"locale=#{I18n.locale}&token=#{exercise.token}"
|
||||
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
|
||||
end
|
||||
|
||||
[:download_file, :render, :run, :test].each do |action|
|
||||
filename = FILENAME_URL_PLACEHOLDER.gsub(/\W/, '')
|
||||
define_method("#{action}_url") do
|
||||
Rails.application.routes.url_helpers.send(:"#{action}_submission_path", self, filename).sub(filename, FILENAME_URL_PLACEHOLDER)
|
||||
end
|
||||
end
|
||||
|
||||
def download_url
|
||||
Rails.application.routes.url_helpers.send(:download_submission_path, self)
|
||||
end
|
||||
|
||||
def main_file
|
||||
collect_files.detect(&:main_file?)
|
||||
end
|
||||
@ -56,12 +45,6 @@ class Submission < ActiveRecord::Base
|
||||
(normalized_score * 100).round
|
||||
end
|
||||
|
||||
[:score, :stop].each do |action|
|
||||
define_method("#{action}_url") do
|
||||
Rails.application.routes.url_helpers.send(:"#{action}_submission_path", self)
|
||||
end
|
||||
end
|
||||
|
||||
def siblings
|
||||
user.submissions.where(exercise_id: exercise_id)
|
||||
end
|
||||
|
@ -1,11 +1,11 @@
|
||||
- external_user_id = @current_user.respond_to?(:external_id) ? @current_user.external_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '')
|
||||
#editor.row data-exercise-id=exercise.id data-message-depleted=t('exercises.editor.depleted') data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @exercise.execution_environment.permitted_execution_time) data-errors-url=execution_environment_errors_path(exercise.execution_environment) data-submissions-url=submissions_path data-user-id=@current_user.id data-user-external-id=external_user_id
|
||||
- external_user_external_id = @current_user.respond_to?(:external_id) ? @current_user.external_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '')
|
||||
- external_user_id = @current_user.respond_to?(:external_id) ? @current_user.id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '')
|
||||
- consumer_id = @current_user.respond_to?(:external_id) ? @current_user.consumer_id : '' #'tests' #(@current_user.uuid.present? ? @current_user.uuid : '')
|
||||
#editor.row data-exercise-id=exercise.id data-message-depleted=t('exercises.editor.depleted') data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @exercise.execution_environment.permitted_execution_time) data-errors-url=execution_environment_errors_path(exercise.execution_environment) data-submissions-url=submissions_path data-user-id=@current_user.id data-user-external-id=external_user_external_id
|
||||
div id="sidebar" class=(@exercise.hide_file_tree ? 'sidebar-col-collapsed' : 'sidebar-col') = render('editor_file_tree', exercise: @exercise, files: @files)
|
||||
div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output')
|
||||
div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id )
|
||||
div id='frames' class='editor-col'
|
||||
#editor-buttons.btn-group.enforce-bottom-margin
|
||||
// = render('editor_button', data: {:'data-message-success' => t('submissions.create.success'), :'data-placement' => 'top', :'data-tooltip' => true}, icon: 'fa fa-save', id: 'save', label: t('exercises.editor.save'), title: t('.tooltips.save'))
|
||||
// .btn-group
|
||||
= render('editor_button', disabled: true, icon: 'fa fa-ban', id: 'dummy', label: t('exercises.editor.dummy'))
|
||||
= render('editor_button', icon: 'fa fa-desktop', id: 'render', label: t('exercises.editor.render'))
|
||||
= render('editor_button', data: {:'data-message-failure' => t('exercises.editor.run_failure'), :'data-message-network' => t('exercises.editor.network'), :'data-message-success' => t('exercises.editor.run_success'), :'data-placement' => 'top', :'data-tooltip' => true}, icon: 'fa fa-play', id: 'run', label: t('exercises.editor.run'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + r'))
|
||||
|
@ -27,7 +27,7 @@ div id='output_sidebar_uncollapsed' class='hidden col-sm-12 enforce-bottom-margi
|
||||
.progress-bar role='progressbar'
|
||||
|
||||
br
|
||||
- if session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url')
|
||||
- if lti_outcome_service?(@exercise.id, external_user_id, consumer_id)
|
||||
p.text-center = render('editor_button', classes: 'btn-lg btn-success', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa fa-send', id: 'submit', label: t('exercises.editor.submit'))
|
||||
- else
|
||||
p.text-center = render('editor_button', classes: 'btn-lg btn-warning-outline', data: {:'data-placement' => 'bottom', :'data-tooltip' => true}, icon: 'fa fa-clock-o', id: 'submit_outdated', label: t('exercises.editor.exercise_deadline_passed'), title: t('exercises.editor.tooltips.exercise_deadline_passed'))
|
||||
|
@ -3,6 +3,7 @@ h1 = t('.headline')
|
||||
p
|
||||
== t(".success_#{params[:outcome] ? 'with' : 'without'}_outcome", consumer: @consumer)
|
||||
==< t(".finished_#{@consumer ? 'with' : 'without'}_consumer", consumer: @consumer, url: params[:url])
|
||||
==< t(".do_not_use_backbutton", consumer: @consumer)
|
||||
|
||||
h2 = t('shared.statistics')
|
||||
|
||||
|
@ -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__)
|
||||
|
||||
# Pick the frameworks you want:
|
||||
require "active_model/railtie"
|
||||
require "active_record/railtie"
|
||||
require "action_controller/railtie"
|
||||
require "action_mailer/railtie"
|
||||
require "action_view/railtie"
|
||||
require "sprockets/railtie"
|
||||
# require "rails/test_unit/railtie"
|
||||
require 'rails/all'
|
||||
|
||||
# Require the gems listed in Gemfile, including any gems
|
||||
# you've limited to :test, :development, or :production.
|
||||
@ -21,17 +14,22 @@ module CodeOcean
|
||||
|
||||
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
||||
config.time_zone = 'Berlin'
|
||||
config.time_zone = 'UTC'
|
||||
|
||||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||
# config.i18n.default_locale = :de
|
||||
config.i18n.available_locales = [:de, :en]
|
||||
|
||||
# Do not swallow errors in after_commit/after_rollback callbacks.
|
||||
config.active_record.raise_in_transactional_callbacks = true
|
||||
|
||||
config.autoload_paths << Rails.root.join('lib')
|
||||
config.eager_load_paths << Rails.root.join('lib')
|
||||
config.assets.precompile += %w( markdown-buttons.png )
|
||||
|
||||
config.active_record.schema_format = :sql
|
||||
|
||||
case (RUBY_ENGINE)
|
||||
when 'ruby'
|
||||
# ...
|
||||
@ -43,5 +41,3 @@ module CodeOcean
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Rails.application.config.assets.precompile += %w( markdown-buttons.png )
|
@ -1,4 +1,3 @@
|
||||
# Set up gems listed in the Gemfile.
|
||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
||||
|
||||
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
||||
require 'bundler/setup' # Set up gems listed in the Gemfile.
|
||||
|
@ -2,6 +2,7 @@ Rails.application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
||||
config.web_console.whitelisted_ips = '192.168.0.0/16'
|
||||
|
||||
# In the development environment your application's code is reloaded on
|
||||
# every request. This slows down response time but is perfect for development
|
||||
# since you don't have to restart the web server when you make code changes.
|
||||
@ -14,7 +15,7 @@ Rails.application.configure do
|
||||
config.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
config.action_mailer.perform_deliveries = true
|
||||
config.action_mailer.perform_deliveries = false
|
||||
|
||||
# Don't care if the mailer can't send.
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
@ -25,12 +26,21 @@ Rails.application.configure do
|
||||
# Raise an error on page load if there are pending migrations.
|
||||
config.active_record.migration_error = :page_load
|
||||
|
||||
# Debug mode disables concatenation and preprocessing of assets.
|
||||
# This option may cause significant delays in view rendering with a large
|
||||
# number of complex assets.
|
||||
config.assets.debug = true
|
||||
|
||||
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
||||
# yet still be able to expire them through the digest params.
|
||||
config.assets.digest = true
|
||||
|
||||
# Adds additional error checking when serving assets at runtime.
|
||||
# Checks for improperly declared sprockets dependencies.
|
||||
# Raises helpful error messages.
|
||||
config.assets.raise_runtime_errors = true
|
||||
|
||||
# Raise errors for missing translations.
|
||||
# Raises error for missing translations
|
||||
config.action_view.raise_on_missing_translations = true
|
||||
|
||||
BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP']
|
||||
|
@ -16,11 +16,13 @@ Rails.application.configure do
|
||||
|
||||
# Enable Rack::Cache to put a simple HTTP cache in front of your application
|
||||
# Add `rack-cache` to your Gemfile before enabling this.
|
||||
# For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
|
||||
# For large-scale production use, consider using a caching reverse proxy like
|
||||
# NGINX, varnish or squid.
|
||||
# config.action_dispatch.rack_cache = true
|
||||
|
||||
# Disable Rails's static asset server (Apache or nginx will already do this).
|
||||
config.serve_static_assets = false
|
||||
# Disable serving static files from the `/public` folder by default since
|
||||
# Apache or NGINX already handles this.
|
||||
config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
|
||||
|
||||
# Compress JavaScripts and CSS.
|
||||
config.assets.js_compressor = :uglifier
|
||||
@ -29,20 +31,21 @@ Rails.application.configure do
|
||||
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
||||
config.assets.compile = false
|
||||
|
||||
# Generate digests for assets URLs.
|
||||
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
||||
# yet still be able to expire them through the digest params.
|
||||
config.assets.digest = true
|
||||
|
||||
# Version of your assets, change this if you want to expire all your assets.
|
||||
config.assets.version = '1.0'
|
||||
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
|
||||
|
||||
# Specifies the header that your server uses for sending files.
|
||||
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
|
||||
|
||||
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
||||
# config.force_ssl = true
|
||||
|
||||
# Set to :debug to see everything in the log.
|
||||
# Use the lowest log level to ensure availability of diagnostic information
|
||||
# when problems arise.
|
||||
config.log_level = :error
|
||||
|
||||
# Prepend all log lines with the following tags.
|
||||
@ -55,11 +58,7 @@ Rails.application.configure do
|
||||
# config.cache_store = :mem_cache_store
|
||||
|
||||
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
||||
# config.action_controller.asset_host = "http://assets.example.com"
|
||||
|
||||
# Precompile additional assets.
|
||||
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
|
||||
# config.assets.precompile += %w( search.js )
|
||||
# config.action_controller.asset_host = 'http://assets.example.com'
|
||||
|
||||
# Ignore bad email addresses and do not raise email delivery errors.
|
||||
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
|
||||
@ -72,9 +71,6 @@ Rails.application.configure do
|
||||
# Send deprecation notices to registered listeners.
|
||||
config.active_support.deprecation = :notify
|
||||
|
||||
# Disable automatic flushing of the log to improve performance.
|
||||
# config.autoflush_log = false
|
||||
|
||||
# Use default logging formatter so that PID and timestamp are not suppressed.
|
||||
config.log_formatter = ::Logger::Formatter.new
|
||||
|
||||
|
@ -37,7 +37,7 @@ Rails.application.configure do
|
||||
# config.action_dispatch.rack_cache = true
|
||||
|
||||
# Disable Rails's static asset server (Apache or nginx will already do this).
|
||||
config.serve_static_assets = false
|
||||
config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
|
||||
|
||||
# Compress JavaScripts and CSS.
|
||||
# config.assets.js_compressor = :uglifier
|
||||
|
@ -12,8 +12,8 @@ Rails.application.configure do
|
||||
# preloads Rails for running tests, you may have to set it to true.
|
||||
config.eager_load = false
|
||||
|
||||
# Configure static asset server for tests with Cache-Control for performance.
|
||||
config.serve_static_assets = true
|
||||
# Configure static file server for tests with Cache-Control for performance.
|
||||
config.serve_static_files = true
|
||||
config.static_cache_control = 'public, max-age=3600'
|
||||
|
||||
# Show full error reports and disable caching.
|
||||
@ -31,6 +31,9 @@ Rails.application.configure do
|
||||
# ActionMailer::Base.deliveries array.
|
||||
config.action_mailer.delivery_method = :test
|
||||
|
||||
# Randomize the order test cases are executed.
|
||||
config.active_support.test_order = :random
|
||||
|
||||
# Print deprecation notices to the stderr.
|
||||
config.active_support.deprecation = :stderr
|
||||
|
||||
|
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.
|
||||
|
||||
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
|
||||
test: Testen
|
||||
timeout: 'Ausführung gestoppt. Ihr Code hat die erlaubte Ausführungszeit von %{permitted_execution_time} Sekunden überschritten.'
|
||||
exercise_deadline_passed: 'Die Abgabefrist für diese Aufgabe ist bereits abgelaufen.'
|
||||
exercise_deadline_passed: 'Das Ergebnis kann nicht übertragen werden.'
|
||||
tooltips:
|
||||
save: Ihr Code wird automatisch gespeichert, wann immer Sie eine Datei herunterladen, ausführen oder testen. Explizites Speichern ist also selten notwendig.
|
||||
exercise_deadline_passed: 'Die hier erzielten Punkte können nur bis zum Ablauf der Abgabefrist an die E-Learning-Plattform übertragen werden.'
|
||||
exercise_deadline_passed: 'Entweder ist die Abgabefrist bereits abgelaufen oder Sie haben die Aufgabe nicht direkt über die E-Learning Plattform gestartet. (Möglicherweise haben Sie den Zurück Button Ihres Browsers benutzt nachdem Sie Ihre Aufgabe abgegeben haben?)'
|
||||
request_for_comments_sent: "Kommentaranfrage gesendet."
|
||||
editor_file_tree:
|
||||
file_root: Dateien
|
||||
@ -386,6 +386,7 @@ de:
|
||||
score: Ihre Punktzahl
|
||||
success_with_outcome: 'Ihr Code wurde erfolgreich bewertet. Ihre Bewertung wurde an %{consumer} übermittelt.'
|
||||
success_without_outcome: Ihr Code wurde erfolgreich bewertet.
|
||||
do_not_use_backbutton: Benutzen Sie nicht den "Zurück" Button des Browsers, um zu CodeOcean zurück zu kehren. Übungen müssen immer aus dem %{consumer} Kontext gestartet werden.
|
||||
new:
|
||||
forgot_password: Passwort vergessen?
|
||||
headline: Anmelden
|
||||
|
@ -1,3 +1,24 @@
|
||||
# Files in the config/locales directory are used for internationalization
|
||||
# and are automatically loaded by Rails. If you want to use locales other
|
||||
# than English, add the necessary files in this directory.
|
||||
#
|
||||
# To use the locales, use `I18n.t`:
|
||||
#
|
||||
# I18n.t 'hello'
|
||||
#
|
||||
# In views, this is aliased to just `t`:
|
||||
#
|
||||
# <%= t('hello') %>
|
||||
#
|
||||
# To use a different locale, set it with `I18n.locale`:
|
||||
#
|
||||
# I18n.locale = :es
|
||||
#
|
||||
# This would use the information in config/locales/es.yml.
|
||||
#
|
||||
# To learn more, please read the Rails Internationalization guide
|
||||
# available at http://guides.rubyonrails.org/i18n.html.
|
||||
|
||||
en:
|
||||
activerecord:
|
||||
attributes:
|
||||
@ -217,10 +238,10 @@ en:
|
||||
submit: Submit Code For Assessment
|
||||
test: Test
|
||||
timeout: 'Execution stopped. Your code exceeded the permitted execution time of %{permitted_execution_time} seconds.'
|
||||
exercise_deadline_passed: 'The deadline for this exercise has already passed'
|
||||
exercise_deadline_passed: 'The score cannot be submitted.'
|
||||
tooltips:
|
||||
save: Your code is automatically saved whenever you download, run, or test it. Therefore, explicitly saving is rarely necessary.
|
||||
exercise_deadline_passed: 'The results for this exercise can only be submitted to the e-learning platform before the deadline has passed.'
|
||||
exercise_deadline_passed: 'Either the deadline has already passed or you did not directly access this page from the e-learning platform. (Did you use the Back button of your browser after submitting the score?)'
|
||||
request_for_comments_sent: "Request for comments sent."
|
||||
editor_file_tree:
|
||||
file_root: Files
|
||||
@ -386,6 +407,7 @@ en:
|
||||
score: Your Score
|
||||
success_with_outcome: 'Your code has been successfully assessed. Your grade has been transmitted to %{consumer}.'
|
||||
success_without_outcome: Your code has been successfully assessed.
|
||||
do_not_use_backbutton: Never use the browser's "Back" button to get back to CodeOcean. Always start an exercise from within %{consumer}.
|
||||
new:
|
||||
forgot_password: Forgot password?
|
||||
headline: Sign In
|
||||
@ -466,3 +488,4 @@ en:
|
||||
previous_label: '← Previous Page'
|
||||
file_template:
|
||||
no_template_label: "Empty File"
|
||||
|
||||
|
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.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160907123009) do
|
||||
ActiveRecord::Schema.define(version: 20161214144837) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
create_table "code_harbor_links", force: true do |t|
|
||||
t.string "oauth2token"
|
||||
create_table "code_harbor_links", force: :cascade do |t|
|
||||
t.string "oauth2token", limit: 255
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "user_id"
|
||||
@ -25,10 +25,10 @@ ActiveRecord::Schema.define(version: 20160907123009) do
|
||||
|
||||
add_index "code_harbor_links", ["user_id"], name: "index_code_harbor_links_on_user_id", using: :btree
|
||||
|
||||
create_table "comments", force: true do |t|
|
||||
create_table "comments", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "file_id"
|
||||
t.string "user_type"
|
||||
t.string "user_type", limit: 255
|
||||
t.integer "row"
|
||||
t.integer "column"
|
||||
t.text "text"
|
||||
@ -39,15 +39,15 @@ ActiveRecord::Schema.define(version: 20160907123009) do
|
||||
add_index "comments", ["file_id"], name: "index_comments_on_file_id", using: :btree
|
||||
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
|
||||
|
||||
create_table "consumers", force: true do |t|
|
||||
t.string "name"
|
||||
create_table "consumers", force: :cascade do |t|
|
||||
t.string "name", limit: 255
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "oauth_key"
|
||||
t.string "oauth_secret"
|
||||
t.string "oauth_key", limit: 255
|
||||
t.string "oauth_secret", limit: 255
|
||||
end
|
||||
|
||||
create_table "errors", force: true do |t|
|
||||
create_table "errors", force: :cascade do |t|
|
||||
t.integer "execution_environment_id"
|
||||
t.text "message"
|
||||
t.datetime "created_at"
|
||||
@ -57,123 +57,123 @@ ActiveRecord::Schema.define(version: 20160907123009) do
|
||||
|
||||
add_index "errors", ["submission_id"], name: "index_errors_on_submission_id", using: :btree
|
||||
|
||||
create_table "execution_environments", force: true do |t|
|
||||
t.string "docker_image"
|
||||
t.string "name"
|
||||
create_table "execution_environments", force: :cascade do |t|
|
||||
t.string "docker_image", limit: 255
|
||||
t.string "name", limit: 255
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "run_command"
|
||||
t.string "test_command"
|
||||
t.string "testing_framework"
|
||||
t.string "run_command", limit: 255
|
||||
t.string "test_command", limit: 255
|
||||
t.string "testing_framework", limit: 255
|
||||
t.text "help"
|
||||
t.string "exposed_ports"
|
||||
t.string "exposed_ports", limit: 255
|
||||
t.integer "permitted_execution_time"
|
||||
t.integer "user_id"
|
||||
t.string "user_type"
|
||||
t.string "user_type", limit: 255
|
||||
t.integer "pool_size"
|
||||
t.integer "file_type_id"
|
||||
t.integer "memory_limit"
|
||||
t.boolean "network_enabled"
|
||||
end
|
||||
|
||||
create_table "exercises", force: true do |t|
|
||||
create_table "exercises", force: :cascade do |t|
|
||||
t.text "description"
|
||||
t.integer "execution_environment_id"
|
||||
t.string "title"
|
||||
t.string "title", limit: 255
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "user_id"
|
||||
t.text "instructions"
|
||||
t.boolean "public"
|
||||
t.string "user_type"
|
||||
t.string "token"
|
||||
t.string "user_type", limit: 255
|
||||
t.string "token", limit: 255
|
||||
t.boolean "hide_file_tree"
|
||||
t.boolean "allow_file_creation"
|
||||
t.boolean "allow_auto_completion", default: false
|
||||
end
|
||||
|
||||
create_table "external_users", force: true do |t|
|
||||
create_table "external_users", force: :cascade do |t|
|
||||
t.integer "consumer_id"
|
||||
t.string "email"
|
||||
t.string "external_id"
|
||||
t.string "name"
|
||||
t.string "email", limit: 255
|
||||
t.string "external_id", limit: 255
|
||||
t.string "name", limit: 255
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "file_templates", force: true do |t|
|
||||
t.string "name"
|
||||
create_table "file_templates", force: :cascade do |t|
|
||||
t.string "name", limit: 255
|
||||
t.text "content"
|
||||
t.integer "file_type_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "file_types", force: true do |t|
|
||||
t.string "editor_mode"
|
||||
t.string "file_extension"
|
||||
create_table "file_types", force: :cascade do |t|
|
||||
t.string "editor_mode", limit: 255
|
||||
t.string "file_extension", limit: 255
|
||||
t.integer "indent_size"
|
||||
t.string "name"
|
||||
t.string "name", limit: 255
|
||||
t.integer "user_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "executable"
|
||||
t.boolean "renderable"
|
||||
t.string "user_type"
|
||||
t.string "user_type", limit: 255
|
||||
t.boolean "binary"
|
||||
end
|
||||
|
||||
create_table "files", force: true do |t|
|
||||
create_table "files", force: :cascade do |t|
|
||||
t.text "content"
|
||||
t.integer "context_id"
|
||||
t.string "context_type"
|
||||
t.string "context_type", limit: 255
|
||||
t.integer "file_id"
|
||||
t.integer "file_type_id"
|
||||
t.boolean "hidden"
|
||||
t.string "name"
|
||||
t.string "name", limit: 255
|
||||
t.boolean "read_only"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "native_file"
|
||||
t.string "role"
|
||||
t.string "hashed_content"
|
||||
t.string "feedback_message"
|
||||
t.string "native_file", limit: 255
|
||||
t.string "role", limit: 255
|
||||
t.string "hashed_content", limit: 255
|
||||
t.string "feedback_message", limit: 255
|
||||
t.float "weight"
|
||||
t.string "path"
|
||||
t.string "path", limit: 255
|
||||
t.integer "file_template_id"
|
||||
end
|
||||
|
||||
add_index "files", ["context_id", "context_type"], name: "index_files_on_context_id_and_context_type", using: :btree
|
||||
|
||||
create_table "hints", force: true do |t|
|
||||
create_table "hints", force: :cascade do |t|
|
||||
t.integer "execution_environment_id"
|
||||
t.string "locale"
|
||||
t.string "locale", limit: 255
|
||||
t.text "message"
|
||||
t.string "name"
|
||||
t.string "regular_expression"
|
||||
t.string "name", limit: 255
|
||||
t.string "regular_expression", limit: 255
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "internal_users", force: true do |t|
|
||||
create_table "internal_users", force: :cascade do |t|
|
||||
t.integer "consumer_id"
|
||||
t.string "email"
|
||||
t.string "name"
|
||||
t.string "role"
|
||||
t.string "email", limit: 255
|
||||
t.string "name", limit: 255
|
||||
t.string "role", limit: 255
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "crypted_password"
|
||||
t.string "salt"
|
||||
t.string "crypted_password", limit: 255
|
||||
t.string "salt", limit: 255
|
||||
t.integer "failed_logins_count", default: 0
|
||||
t.datetime "lock_expires_at"
|
||||
t.string "unlock_token"
|
||||
t.string "remember_me_token"
|
||||
t.string "unlock_token", limit: 255
|
||||
t.string "remember_me_token", limit: 255
|
||||
t.datetime "remember_me_token_expires_at"
|
||||
t.string "reset_password_token"
|
||||
t.string "reset_password_token", limit: 255
|
||||
t.datetime "reset_password_token_expires_at"
|
||||
t.datetime "reset_password_email_sent_at"
|
||||
t.string "activation_state"
|
||||
t.string "activation_token"
|
||||
t.string "activation_state", limit: 255
|
||||
t.string "activation_token", limit: 255
|
||||
t.datetime "activation_token_expires_at"
|
||||
end
|
||||
|
||||
@ -182,29 +182,38 @@ ActiveRecord::Schema.define(version: 20160907123009) do
|
||||
add_index "internal_users", ["remember_me_token"], name: "index_internal_users_on_remember_me_token", using: :btree
|
||||
add_index "internal_users", ["reset_password_token"], name: "index_internal_users_on_reset_password_token", using: :btree
|
||||
|
||||
create_table "request_for_comments", force: true do |t|
|
||||
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 "exercise_id", null: false
|
||||
t.integer "file_id", null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "user_type"
|
||||
t.string "user_type", limit: 255
|
||||
t.text "question"
|
||||
t.boolean "solved"
|
||||
t.integer "submission_id"
|
||||
end
|
||||
|
||||
create_table "submissions", force: true do |t|
|
||||
create_table "submissions", force: :cascade do |t|
|
||||
t.integer "exercise_id"
|
||||
t.float "score"
|
||||
t.integer "user_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "cause"
|
||||
t.string "user_type"
|
||||
t.string "cause", limit: 255
|
||||
t.string "user_type", limit: 255
|
||||
end
|
||||
|
||||
create_table "testruns", force: true do |t|
|
||||
create_table "testruns", force: :cascade do |t|
|
||||
t.boolean "passed"
|
||||
t.text "output"
|
||||
t.integer "file_id"
|
||||
|
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
|
||||
|
||||
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
|
||||
|
||||
def initialize(options = {})
|
||||
|
@ -19,7 +19,6 @@ describe Lti do
|
||||
it 'clears the session' do
|
||||
expect(controller.session).to receive(:delete).with(:consumer_id)
|
||||
expect(controller.session).to receive(:delete).with(:external_user_id)
|
||||
expect(controller.session).to receive(:delete).with(:lti_parameters)
|
||||
controller.send(:clear_lti_session_data)
|
||||
end
|
||||
end
|
||||
@ -106,24 +105,25 @@ describe Lti do
|
||||
describe '#send_score' do
|
||||
let(:consumer) { FactoryGirl.create(:consumer) }
|
||||
let(:score) { 0.5 }
|
||||
let(:submission) { FactoryGirl.create(:submission) }
|
||||
let!(:lti_parameter) { FactoryGirl.create(:lti_parameter)}
|
||||
|
||||
context 'with an invalid score' do
|
||||
it 'raises an exception' do
|
||||
expect { controller.send(:send_score, Lti::MAXIMUM_SCORE * 2) }.to raise_error(Lti::Error)
|
||||
expect { controller.send(:send_score, submission.exercise_id, Lti::MAXIMUM_SCORE * 2, submission.user_id) }.to raise_error(Lti::Error)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an valid score' do
|
||||
context 'with a tool provider' do
|
||||
context 'with a tool consumer' do
|
||||
before(:each) do
|
||||
controller.session[:consumer_id] = consumer.id
|
||||
controller.session[:lti_parameters] = {}
|
||||
end
|
||||
|
||||
context 'when grading is not supported' do
|
||||
it 'returns a corresponding status' do
|
||||
expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(false)
|
||||
expect(controller.send(:send_score, score)[:status]).to eq('unsupported')
|
||||
expect(controller.send(:send_score, submission.exercise_id, score, submission.user_id)[:status]).to eq('unsupported')
|
||||
end
|
||||
end
|
||||
|
||||
@ -140,11 +140,11 @@ describe Lti do
|
||||
end
|
||||
|
||||
it 'sends the score' do
|
||||
controller.send(:send_score, score)
|
||||
controller.send(:send_score, submission.exercise_id, score, submission.user_id)
|
||||
end
|
||||
|
||||
it 'returns code, message, and status' do
|
||||
result = controller.send(:send_score, score)
|
||||
result = controller.send(:send_score, submission.exercise_id, score, submission.user_id)
|
||||
expect(result[:code]).to eq(response.response_code)
|
||||
expect(result[:message]).to eq(response.body)
|
||||
expect(result[:status]).to eq(response.code_major)
|
||||
@ -152,10 +152,9 @@ describe Lti do
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a tool provider' do
|
||||
context 'without a tool consumer' do
|
||||
it 'returns a corresponding status' do
|
||||
expect(controller).to receive(:build_tool_provider).and_return(nil)
|
||||
expect(controller.send(:send_score, score)[:status]).to eq('error')
|
||||
expect(controller.send(:send_score, submission.exercise_id, score, submission.user_id)[:status]).to eq('error')
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -163,17 +162,18 @@ describe Lti do
|
||||
|
||||
describe '#store_lti_session_data' do
|
||||
let(:parameters) { {} }
|
||||
before(:each) { controller.instance_variable_set(:@current_user, FactoryGirl.create(:external_user)) }
|
||||
after(:each) { controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) }
|
||||
|
||||
it 'stores data in the session' do
|
||||
controller.instance_variable_set(:@current_user, FactoryGirl.create(:external_user))
|
||||
expect(controller.session).to receive(:[]=).with(:consumer_id, anything)
|
||||
expect(controller.session).to receive(:[]=).with(:external_user_id, anything)
|
||||
expect(controller.session).to receive(:[]=).with(:lti_parameters, kind_of(Hash))
|
||||
controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters)
|
||||
end
|
||||
|
||||
it 'stores only selected tuples' do
|
||||
expect(parameters).to receive(:slice).with(*Lti::SESSION_PARAMETERS)
|
||||
it 'it creates an LtiParameter Object' do
|
||||
before_count = LtiParameter.count
|
||||
controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters)
|
||||
expect(LtiParameter.count).to eq(before_count + 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -230,11 +230,14 @@ describe ExercisesController do
|
||||
describe 'POST #submit' do
|
||||
let(:output) { {} }
|
||||
let(:request) { post :submit, format: :json, id: exercise.id, submission: {cause: 'submit', exercise_id: exercise.id} }
|
||||
let!(:external_user) { FactoryGirl.create(:external_user) }
|
||||
let!(:lti_parameter) { FactoryGirl.create(:lti_parameter, external_user: external_user, exercise: exercise) }
|
||||
|
||||
before(:each) do
|
||||
allow_any_instance_of(Submission).to receive(:normalized_score).and_return(1)
|
||||
expect(controller).to receive(:collect_test_results).and_return([{score: 1, weight: 1}])
|
||||
expect(controller).to receive(:score_submission).and_call_original
|
||||
controller.session[:consumer_id] = external_user.consumer_id
|
||||
end
|
||||
|
||||
context 'when LTI outcomes are supported' do
|
||||
|
@ -93,6 +93,7 @@ describe SessionsController do
|
||||
end
|
||||
|
||||
it 'stores LTI parameters in the session' do
|
||||
#Todo replace session with lti_parameter /should be done already
|
||||
expect(controller).to receive(:store_lti_session_data)
|
||||
request
|
||||
end
|
||||
@ -159,6 +160,7 @@ describe SessionsController do
|
||||
end
|
||||
|
||||
it 'clears the session' do
|
||||
#Todo replace session with lti_parameter /should be done already
|
||||
expect(controller).to receive(:clear_lti_session_data)
|
||||
delete :destroy
|
||||
end
|
||||
@ -174,13 +176,16 @@ describe SessionsController do
|
||||
let(:submission) { FactoryGirl.create(:submission, exercise: FactoryGirl.create(:dummy)) }
|
||||
|
||||
before(:each) do
|
||||
#Todo replace session with lti_parameter
|
||||
session[:consumer_id] = consumer.id
|
||||
session[:lti_parameters] = {}
|
||||
#Todo create LtiParameter Object
|
||||
# session[:lti_parameters] = {}
|
||||
end
|
||||
|
||||
before(:each) { request.call }
|
||||
|
||||
it 'clears the session' do
|
||||
#Todo replace session with lti_parameter /should be done already
|
||||
expect(controller).to receive(:clear_lti_session_data)
|
||||
request.call
|
||||
end
|
||||
|
@ -32,7 +32,7 @@ FactoryGirl.define do
|
||||
factory :java, class: ExecutionEnvironment do
|
||||
created_by_teacher
|
||||
default_memory_limit
|
||||
docker_image 'hklement/ubuntu-java:latest'
|
||||
docker_image 'openhpi/co_execenv_java:latest'
|
||||
association :file_type, factory: :dot_java
|
||||
help
|
||||
name 'Java 8'
|
||||
@ -78,7 +78,7 @@ FactoryGirl.define do
|
||||
factory :python, class: ExecutionEnvironment do
|
||||
created_by_teacher
|
||||
default_memory_limit
|
||||
docker_image 'hklement/ubuntu-python:latest'
|
||||
docker_image 'openhpi/co_execenv_python:latest'
|
||||
association :file_type, factory: :dot_py
|
||||
help
|
||||
name 'Python 3.4'
|
||||
|
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
|
||||
cause 'save'
|
||||
created_by_external_user
|
||||
association :exercise, factory: :fibonacci
|
||||
association :exercise, factory: :math
|
||||
|
||||
after(:create) do |submission|
|
||||
submission.exercise.files.editable.visible.each do |file|
|
||||
|
@ -3,8 +3,8 @@ require 'seeds_helper'
|
||||
|
||||
describe DockerClient, docker: true do
|
||||
let(:command) { 'whoami' }
|
||||
let(:docker_client) { described_class.new(execution_environment: FactoryGirl.build(:ruby), user: FactoryGirl.build(:admin)) }
|
||||
let(:execution_environment) { FactoryGirl.build(:ruby) }
|
||||
let(:docker_client) { described_class.new(execution_environment: FactoryGirl.build(:java), user: FactoryGirl.build(:admin)) }
|
||||
let(:execution_environment) { FactoryGirl.build(:java) }
|
||||
let(:image) { double }
|
||||
let(:submission) { FactoryGirl.create(:submission) }
|
||||
let(:workspace_path) { '/tmp' }
|
||||
|
Reference in New Issue
Block a user