From 44380c0cc1b29a548aacd0295a82b5a87b59fc6f Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Wed, 14 Dec 2016 15:53:16 +0100 Subject: [PATCH 01/26] added model for lti_parameters --- app/models/lti_parameter.rb | 2 ++ db/migrate/20161214144832_create_lti_parameters.rb | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 app/models/lti_parameter.rb create mode 100644 db/migrate/20161214144832_create_lti_parameters.rb diff --git a/app/models/lti_parameter.rb b/app/models/lti_parameter.rb new file mode 100644 index 00000000..667570be --- /dev/null +++ b/app/models/lti_parameter.rb @@ -0,0 +1,2 @@ +class LtiParameter < ActiveRecord::Base +end diff --git a/db/migrate/20161214144832_create_lti_parameters.rb b/db/migrate/20161214144832_create_lti_parameters.rb new file mode 100644 index 00000000..1541c368 --- /dev/null +++ b/db/migrate/20161214144832_create_lti_parameters.rb @@ -0,0 +1,12 @@ +class CreateLtiParameters < ActiveRecord::Migration + def change + create_table :lti_parameters do |t| + t.string :external_user_id + t.string :consumer_id + t.string :exercise_id + t.text :lti_return_url + + t.timestamps + end + end +end From 2b55e0081cc51f43808a7900ac7e274491fce178 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Fri, 16 Dec 2016 15:28:40 +0100 Subject: [PATCH 02/26] change LtiParameters Table --- ...130605_remove_lti_return_url_from_lti_parameter.rb | 5 +++++ ...61216131239_add_lti_parameters_to_lti_parameter.rb | 5 +++++ db/schema.rb | 11 ++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20161216130605_remove_lti_return_url_from_lti_parameter.rb create mode 100644 db/migrate/20161216131239_add_lti_parameters_to_lti_parameter.rb diff --git a/db/migrate/20161216130605_remove_lti_return_url_from_lti_parameter.rb b/db/migrate/20161216130605_remove_lti_return_url_from_lti_parameter.rb new file mode 100644 index 00000000..96efc4cc --- /dev/null +++ b/db/migrate/20161216130605_remove_lti_return_url_from_lti_parameter.rb @@ -0,0 +1,5 @@ +class RemoveLtiReturnUrlFromLtiParameter < ActiveRecord::Migration + def change + remove_column :lti_parameters, :lti_return_url, :text + end +end diff --git a/db/migrate/20161216131239_add_lti_parameters_to_lti_parameter.rb b/db/migrate/20161216131239_add_lti_parameters_to_lti_parameter.rb new file mode 100644 index 00000000..73a4c4c0 --- /dev/null +++ b/db/migrate/20161216131239_add_lti_parameters_to_lti_parameter.rb @@ -0,0 +1,5 @@ +class AddLtiParametersToLtiParameter < ActiveRecord::Migration + def change + add_column :lti_parameters, :lti_parameters, :json + end +end diff --git a/db/schema.rb b/db/schema.rb index 330f99d6..a61a1160 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160907123009) do +ActiveRecord::Schema.define(version: 20161216131239) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -182,6 +182,15 @@ 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 "lti_parameters", force: true do |t| + t.string "external_user_id" + t.string "consumer_id" + t.string "exercise_id" + t.datetime "created_at" + t.datetime "updated_at" + t.json "lti_parameters" + end + create_table "request_for_comments", force: true do |t| t.integer "user_id", null: false t.integer "exercise_id", null: false From f4c01879bffa1387e9478a5654e04d3efeaad95c Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Tue, 27 Dec 2016 00:13:41 +0100 Subject: [PATCH 03/26] preparations to replace session with lti_parameters object --- app/controllers/application_controller.rb | 1 + app/controllers/concerns/lti.rb | 14 +++++++++++--- app/controllers/exercises_controller.rb | 1 + app/views/exercises/_editor_output.html.slim | 1 + ....rb => 20161214144837_create_lti_parameters.rb} | 6 +++--- ...605_remove_lti_return_url_from_lti_parameter.rb | 5 ----- ...16131239_add_lti_parameters_to_lti_parameter.rb | 5 ----- db/schema.rb | 9 --------- spec/concerns/lti_spec.rb | 1 + spec/controllers/application_controller_spec.rb | 1 + spec/controllers/sessions_controller_spec.rb | 2 ++ spec/factories/execution_environment.rb | 4 ++-- 12 files changed, 23 insertions(+), 27 deletions(-) rename db/migrate/{20161214144832_create_lti_parameters.rb => 20161214144837_create_lti_parameters.rb} (64%) delete mode 100644 db/migrate/20161216130605_remove_lti_return_url_from_lti_parameter.rb delete mode 100644 db/migrate/20161216131239_add_lti_parameters_to_lti_parameter.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b1a4323f..0c302db5 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -10,6 +10,7 @@ class ApplicationController < ActionController::Base rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized def current_user + #Todo replace session with lti_parameter ::NewRelic::Agent.add_custom_parameters({ external_user_id: session[:external_user_id], session_user_id: session[:user_id] }) @current_user ||= ExternalUser.find_by(id: session[:external_user_id]) || login_from_session || login_from_other_sources end diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 5287d94c..92fc490f 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -44,6 +44,7 @@ module Lti private :external_user_name def lti_outcome_service? + #Todo replace session with lti_parameter session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') end private :lti_outcome_service? @@ -97,6 +98,7 @@ module Lti def send_score(score) ::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) + #Todo replace session with lti_parameter provider = build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters]) if provider.nil? {status: 'error'} @@ -116,9 +118,15 @@ module Lti private :set_current_user def store_lti_session_data(options = {}) - session[:consumer_id] = options[:consumer].id - session[:external_user_id] = @current_user.id - session[:lti_parameters] = options[:parameters].slice(*SESSION_PARAMETERS) + exercise = Exercise.where(token: options[:parameters][:custom_token]).first + exercise_id = exercise.id unless exercise.nil? + + lti_parameters = LtiParameter.find_or_create_by(consumers_id: options[:consumer].id, + external_user_id: options[:parameters][:user_id].to_s, + exercises_id: exercise_id) + + lti_parameters.lti_parameters = options[:parameters].slice(*SESSION_PARAMETERS).to_json + lti_parameters.save! end private :store_lti_session_data diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index 31e970f3..9668e430 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -157,6 +157,7 @@ class ExercisesController < ApplicationController end def redirect_to_lti_return_path + #Todo replace session with lti_parameter 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]))) respond_to do |format| format.html { redirect_to(path) } diff --git a/app/views/exercises/_editor_output.html.slim b/app/views/exercises/_editor_output.html.slim index ab09adac..645d1a1d 100644 --- a/app/views/exercises/_editor_output.html.slim +++ b/app/views/exercises/_editor_output.html.slim @@ -27,6 +27,7 @@ div id='output_sidebar_uncollapsed' class='hidden col-sm-12 enforce-bottom-margi .progress-bar role='progressbar' br + / #Todo replace session with lti_parameter - if session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') 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 diff --git a/db/migrate/20161214144832_create_lti_parameters.rb b/db/migrate/20161214144837_create_lti_parameters.rb similarity index 64% rename from db/migrate/20161214144832_create_lti_parameters.rb rename to db/migrate/20161214144837_create_lti_parameters.rb index 1541c368..890484f4 100644 --- a/db/migrate/20161214144832_create_lti_parameters.rb +++ b/db/migrate/20161214144837_create_lti_parameters.rb @@ -2,9 +2,9 @@ class CreateLtiParameters < ActiveRecord::Migration def change create_table :lti_parameters do |t| t.string :external_user_id - t.string :consumer_id - t.string :exercise_id - t.text :lti_return_url + t.belongs_to :consumers + t.belongs_to :exercises + t.column :lti_parameters, :jsonb t.timestamps end diff --git a/db/migrate/20161216130605_remove_lti_return_url_from_lti_parameter.rb b/db/migrate/20161216130605_remove_lti_return_url_from_lti_parameter.rb deleted file mode 100644 index 96efc4cc..00000000 --- a/db/migrate/20161216130605_remove_lti_return_url_from_lti_parameter.rb +++ /dev/null @@ -1,5 +0,0 @@ -class RemoveLtiReturnUrlFromLtiParameter < ActiveRecord::Migration - def change - remove_column :lti_parameters, :lti_return_url, :text - end -end diff --git a/db/migrate/20161216131239_add_lti_parameters_to_lti_parameter.rb b/db/migrate/20161216131239_add_lti_parameters_to_lti_parameter.rb deleted file mode 100644 index 73a4c4c0..00000000 --- a/db/migrate/20161216131239_add_lti_parameters_to_lti_parameter.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddLtiParametersToLtiParameter < ActiveRecord::Migration - def change - add_column :lti_parameters, :lti_parameters, :json - end -end diff --git a/db/schema.rb b/db/schema.rb index a61a1160..b7bef30a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -182,15 +182,6 @@ ActiveRecord::Schema.define(version: 20161216131239) 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 "lti_parameters", force: true do |t| - t.string "external_user_id" - t.string "consumer_id" - t.string "exercise_id" - t.datetime "created_at" - t.datetime "updated_at" - t.json "lti_parameters" - end - create_table "request_for_comments", force: true do |t| t.integer "user_id", null: false t.integer "exercise_id", null: false diff --git a/spec/concerns/lti_spec.rb b/spec/concerns/lti_spec.rb index c4ff350a..a1448661 100644 --- a/spec/concerns/lti_spec.rb +++ b/spec/concerns/lti_spec.rb @@ -116,6 +116,7 @@ describe Lti do context 'with an valid score' do context 'with a tool provider' do before(:each) do + #Todo replace session with lti_parameter controller.session[:consumer_id] = consumer.id controller.session[:lti_parameters] = {} end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 0ad4b20d..9062008f 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -4,6 +4,7 @@ describe ApplicationController do describe '#current_user' do context 'with an external user' do let(:external_user) { FactoryGirl.create(:external_user) } + #Todo replace session with lti_parameter before(:each) { session[:external_user_id] = external_user.id } it 'returns the external user' do diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index aa76dcca..f56bd708 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -78,6 +78,7 @@ describe SessionsController do it 'assigns the current user' do request expect(assigns(:current_user)).to be_an(ExternalUser) + #Todo replace session with lti_parameter expect(session[:external_user_id]).to eq(user.id) end @@ -174,6 +175,7 @@ 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] = {} end diff --git a/spec/factories/execution_environment.rb b/spec/factories/execution_environment.rb index a58e879a..051d9de6 100644 --- a/spec/factories/execution_environment.rb +++ b/spec/factories/execution_environment.rb @@ -32,7 +32,7 @@ FactoryGirl.define do factory :java, class: ExecutionEnvironment do created_by_teacher default_memory_limit - docker_image 'hklement/ubuntu-java:latest' + docker_image 'openhpi/co_execenv_java:latest' association :file_type, factory: :dot_java help name 'Java 8' @@ -78,7 +78,7 @@ FactoryGirl.define do factory :python, class: ExecutionEnvironment do created_by_teacher default_memory_limit - docker_image 'hklement/ubuntu-python:latest' + docker_image 'openhpi/co_execenv_python:latest' association :file_type, factory: :dot_py help name 'Python 3.4' From 730d76843b28a72ff453c6a0d5b6e8e6b30bc6a7 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Tue, 27 Dec 2016 00:15:04 +0100 Subject: [PATCH 04/26] Added some installer scripts for manual setup of local VBox environment running Debian Jessie --- .../setup_debian_1_install_postgres.sh | 63 ++++++++++ .../setup_debian_2_install_docker.sh | 86 ++++++++++++++ ...up_debian_3_install_depencies_and_utils.sh | 67 +++++++++++ .../setup_debian_4_install_guest_additions.sh | 10 ++ .../setup_debian_5_mount_shared_folder.sh | 7 ++ .../setup_debian_6_setup_codeocean.sh | 28 +++++ .../setup_debian_7_create_tables.sh | 8 ++ debian_installer/setup_debian_vm.sh | 110 ++++++++++++++++++ 8 files changed, 379 insertions(+) create mode 100644 debian_installer/setup_debian_1_install_postgres.sh create mode 100644 debian_installer/setup_debian_2_install_docker.sh create mode 100644 debian_installer/setup_debian_3_install_depencies_and_utils.sh create mode 100644 debian_installer/setup_debian_4_install_guest_additions.sh create mode 100644 debian_installer/setup_debian_5_mount_shared_folder.sh create mode 100644 debian_installer/setup_debian_6_setup_codeocean.sh create mode 100644 debian_installer/setup_debian_7_create_tables.sh create mode 100644 debian_installer/setup_debian_vm.sh diff --git a/debian_installer/setup_debian_1_install_postgres.sh b/debian_installer/setup_debian_1_install_postgres.sh new file mode 100644 index 00000000..f94c7ee0 --- /dev/null +++ b/debian_installer/setup_debian_1_install_postgres.sh @@ -0,0 +1,63 @@ +# update apt-get +echo "Update apt-get..." +sudo apt-get update +# upgrade all packages +echo "Upgrade packages..." +sudo apt-get upgrade + +#install postgres +if [ ! -f /etc/apt/sources.list.d/pgdg.list ] +then + echo "Add Postgres sources..." + cd /etc/apt/sources.list.d + sudo touch pgdg.list + sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main" > pgdg.list' + sudo wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + sudo apt-get update + echo "Done" +else + echo "Postgres sources already added" +fi + +sudo apt-get -y --force-yes install postgresql-9.5 + +# drop postgres access control +if [ -f /etc/postgresql/9.5/main/pg_hba.conf ] +then + if ! sudo -u postgres grep -q CodeOcean /etc/postgresql/9.5/main/pg_hba.conf + then + echo "Drop Postgres access control..." + sudo -u postgres sh -c 'cat >/etc/postgresql/9.5/main/pg_hba.conf < backports.list' + sudo apt-get update + echo "Done" + + #just in case there is some old stuff + echo "Remove legacy stuff...Just in case..." + sudo apt-get purge "lxc-docker*" + sudo apt-get purge "docker.io*" + sudo apt-get update + + #install docker dependencies + echo "Install dependencies..." + sudo apt-get install -y --force-yes apt-transport-https ca-certificates gnupg2 + echo "Done" +else + echo "Docker dependencies already added." +fi + +if [ ! -f /etc/apt/sources.list.d/docker.list ] +then + # get docker sources + echo "Add apt-get sources for Docker..." + sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D + cd /etc/apt/sources.list.d + sudo touch docker.list + sudo sh -c 'echo "deb https://apt.dockerproject.org/repo debian-jessie main" > docker.list' + sudo apt-cache policy docker-engine + sudo apt-get update + echo "Done" +else + echo "Docker apt-get sources already added." +fi + +if [ ! -f /etc/systemd/system/docker.service.d/docker.conf ] + then + echo "Install Docker Engine..." + sudo apt-get install -y --force-yes docker-engine + echo "Done" + echo "Start Docker..." + sudo service docker start + echo "Done" + echo "Run Hello World..." + sudo docker run hello-world + echo "Done" + + #set some docker options + echo "Configure Docker..." + sudo mkdir /etc/systemd/system/docker.service.d + cd /etc/systemd/system/docker.service.d + sudo touch docker.conf + sudo sh -c 'cat >>/etc/systemd/system/docker.service.d/docker.conf < nonfree.list' + sudo sh -c 'echo "deb-src http://http.debian.net/debian jessie main non-free contrib" >> nonfree.list' + sudo sh -c 'echo "deb http://http.debian.net/debian jessie-updates main contrib non-free" >> nonfree.list' + sudo sh -c 'echo "deb-src http://http.debian.net/debian jessie-updates main contrib non-free" >> nonfree.list' + sudo apt-get update +else + # install utilities + echo "Additional apt-get sources already added" +fi + +# install utilities +echo "Install some utils..." +sudo apt-get install -y --force-yes screen +sudo apt-get install -y --force-yes htop +echo "Done" + +# install dependencies +echo "Install some libraries..." +sudo apt-get install -y --force-yes git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev +sudo apt-get install -y --force-yes libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev +sudo apt-get install -y --force-yes python-software-properties libffi-dev +sudo apt-get install -y --force-yes libgdbm-dev libncurses5-dev automake libtool bison libffi-dev +sudo apt-get install -y --force-yes libpq-dev +echo "Done" + +# get the clock in sync +echo "Install clock synchronization..." +sudo apt-get install -y --force-yes ntp ntpdate +echo "Done" + +echo "Install NodeJS..." +# install nodejs +sudo apt-get install -y --force-yes nodejs +echo "Done" + +if ! (ruby -v | grep -q 2.3.3) +then + # install rvm + echo "Install RVM..." + gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 + \curl -sSL https://get.rvm.io | bash -s stable --ruby + source /home/debian/.rvm/scripts/rvm + echo "Done" + # install ruby + echo "Install Ruby 2.3.3..." + rvm install 2.3.3 + rvm use 2.3.3 --default + ruby -v + exec bash + echo "Done" +else + echo "RVM and Ruby are already installed" +fi + +# install guest additions - required for sharing a folder +echo "Install prerequisites for guest additions..." +sudo apt-get install -y --force-yes dkms build-essential linux-headers-amd64 +echo "Done" + +echo "Please follow the instructions:" +echo "Insert Guest Additions CD image. VM: Devices=>Insert Guest Additions CD image" +echo "Install Guest Additions" \ No newline at end of file diff --git a/debian_installer/setup_debian_4_install_guest_additions.sh b/debian_installer/setup_debian_4_install_guest_additions.sh new file mode 100644 index 00000000..68f7e552 --- /dev/null +++ b/debian_installer/setup_debian_4_install_guest_additions.sh @@ -0,0 +1,10 @@ +# Mount Guest Additions and run the installer +echo "Mount Guest Additions and run the installer..." +sudo mount /dev/sr0 /media/cdrom +cd /media/cdrom +sudo sh ./VBoxLinuxAdditions.run +echo "Done" +echo "Please follow the instructions:" +echo "Create Shared Folder. VM: Devices=>VM: Devices=>Shared Folders=>Shared Folders Settings" +echo "Name: codeocean, Path: path to your local codeocaen repository on the host machine." + diff --git a/debian_installer/setup_debian_5_mount_shared_folder.sh b/debian_installer/setup_debian_5_mount_shared_folder.sh new file mode 100644 index 00000000..db1f8234 --- /dev/null +++ b/debian_installer/setup_debian_5_mount_shared_folder.sh @@ -0,0 +1,7 @@ +echo "Mount Shared Folder..." +mkdir /home/debian/codeocean_host +sudo mount -t vboxsf -o rw,uid=1000,gid=1000 codeocean /home/debian/codeocean_host + +# Enable automount during startup +sudo sh -c 'echo "sudo mount -t vboxsf -o rw,uid=1000,gid=1000 codeocean /home/debian/codeocean_host" >> /home/debian/.bashrc ' +echo "Done" \ No newline at end of file diff --git a/debian_installer/setup_debian_6_setup_codeocean.sh b/debian_installer/setup_debian_6_setup_codeocean.sh new file mode 100644 index 00000000..6151fb3a --- /dev/null +++ b/debian_installer/setup_debian_6_setup_codeocean.sh @@ -0,0 +1,28 @@ +############# codeocean install ########################### +cd /home/debian/codeocean_host + +#install rails and bundler +echo "Install Rails..." +gem install rails +echo "Done" +echo "Install Bundler..." +gem install bundler +echo "Done" + +# install required gems +bundle install + +# copy config files +for f in action_mailer.yml database.yml secrets.yml sendmail.yml smtp.yml code_ocean.yml +do + if [ ! -f config/$f ] + then + cp config/$f.example config/$f + fi +done + +# Manual Task: +# if necessary adjust db config +echo "Check if settings in database.yml correspond with your database setup." + +cat /home/debian/codeocean_host/config/database.yml \ No newline at end of file diff --git a/debian_installer/setup_debian_7_create_tables.sh b/debian_installer/setup_debian_7_create_tables.sh new file mode 100644 index 00000000..ed7f5990 --- /dev/null +++ b/debian_installer/setup_debian_7_create_tables.sh @@ -0,0 +1,8 @@ +# create, migrate, and seed database tables +cd /home/debian/codeocean_host +export RAILS_ENV=development + +echo "load, seed, migrate" +rake db:schema:load +rake db:seed +rake db:migrate \ No newline at end of file diff --git a/debian_installer/setup_debian_vm.sh b/debian_installer/setup_debian_vm.sh new file mode 100644 index 00000000..1fdb628a --- /dev/null +++ b/debian_installer/setup_debian_vm.sh @@ -0,0 +1,110 @@ +# 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 +# rails s -p 3000 + +# To connect to Ruby app use +#http://127.0.0.1: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" + + + + + + + + + + + + + + From 6f1d8b2d3889137fc706536c53d4a335e4bd1884 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Tue, 27 Dec 2016 07:48:59 +0100 Subject: [PATCH 05/26] Marked more locations that might require to be changed when we switch from session to LtiParameters Object --- app/controllers/application_controller.rb | 1 - app/controllers/concerns/lti.rb | 1 + spec/concerns/lti_spec.rb | 3 +++ spec/controllers/sessions_controller_spec.rb | 3 +++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0c302db5..0aa26303 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -11,7 +11,6 @@ class ApplicationController < ActionController::Base def current_user #Todo replace session with lti_parameter - ::NewRelic::Agent.add_custom_parameters({ external_user_id: session[:external_user_id], session_user_id: session[:user_id] }) @current_user ||= ExternalUser.find_by(id: session[:external_user_id]) || login_from_session || login_from_other_sources end diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 92fc490f..b5e53e1a 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -15,6 +15,7 @@ module Lti private :build_tool_provider def clear_lti_session_data + #Todo replace session with lti_parameter session.delete(:consumer_id) session.delete(:external_user_id) session.delete(:lti_parameters) diff --git a/spec/concerns/lti_spec.rb b/spec/concerns/lti_spec.rb index a1448661..ab047306 100644 --- a/spec/concerns/lti_spec.rb +++ b/spec/concerns/lti_spec.rb @@ -17,6 +17,7 @@ describe Lti do describe '#clear_lti_session_data' do it 'clears the session' do + #Todo replace session with lti_parameter 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) @@ -163,11 +164,13 @@ describe Lti do end describe '#store_lti_session_data' do + #Todo replace session with lti_parameter 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 + #Todo replace session with lti_parameter 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)) diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index f56bd708..06fc68dc 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -94,6 +94,7 @@ describe SessionsController do end it 'stores LTI parameters in the session' do + #Todo replace session with lti_parameter expect(controller).to receive(:store_lti_session_data) request end @@ -160,6 +161,7 @@ describe SessionsController do end it 'clears the session' do + #Todo replace session with lti_parameter expect(controller).to receive(:clear_lti_session_data) delete :destroy end @@ -183,6 +185,7 @@ describe SessionsController do before(:each) { request.call } it 'clears the session' do + #Todo replace session with lti_parameter expect(controller).to receive(:clear_lti_session_data) request.call end From 325ea25849f9b9462b9cd1c5fd4a14c07e52d31f Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Fri, 30 Dec 2016 09:45:39 +0100 Subject: [PATCH 06/26] Replaced session[:lti_parameters] with proper LtiParameter object. Removed all tests that would be failing TODO: decision if all LtiParameter objects for a certain user/consumer will be deleted when the user/consumer is deleted from the session, or only the LtiParameter object for the current exercise of the user/consumer. TODO: replace removed tests with proper tests --- app/controllers/application_controller.rb | 1 - app/controllers/concerns/lti.rb | 35 ++++++++++++------- app/controllers/exercises_controller.rb | 19 +++++++--- app/controllers/sessions_controller.rb | 7 ++-- app/helpers/exercise_helper.rb | 2 ++ app/helpers/lti_helper.rb | 10 ++++++ app/models/lti_parameter.rb | 5 ++- app/views/exercises/_editor_output.html.slim | 5 +-- .../setup_debian_1_install_postgres.sh | 10 ++++-- spec/concerns/lti_spec.rb | 12 ++++--- .../application_controller_spec.rb | 1 - spec/controllers/sessions_controller_spec.rb | 10 +++--- 12 files changed, 83 insertions(+), 34 deletions(-) create mode 100644 app/helpers/lti_helper.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0aa26303..617bab02 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -10,7 +10,6 @@ class ApplicationController < ActionController::Base rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized def current_user - #Todo replace session with lti_parameter @current_user ||= ExternalUser.find_by(id: session[:external_user_id]) || login_from_session || login_from_other_sources end diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index b5e53e1a..cf489b7f 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -2,6 +2,7 @@ require 'oauth/request_proxy/rack_request' module Lti extend ActiveSupport::Concern + include LtiHelper MAXIMUM_SCORE = 1 MAXIMUM_SESSION_AGE = 60.minutes @@ -14,11 +15,17 @@ module Lti end private :build_tool_provider - def clear_lti_session_data - #Todo replace session with lti_parameter + def clear_lti_session_data(exercise_id = nil) + #Todo replace session with lti_parameter /done + #TODO decide if we need to remove all LtiParameters for user/consumer + if (exercise_id.nil?) + LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: session[:external_user_id]) + else #TODO: probably it does not make sense to keep the LtiParameters if the session is deleted + LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: session[:external_user_id], exercises_id: exercise_id) + end session.delete(:consumer_id) session.delete(:external_user_id) - session.delete(:lti_parameters) + #session.delete(:lti_parameters) end private :clear_lti_session_data @@ -44,12 +51,6 @@ module Lti end private :external_user_name - def lti_outcome_service? - #Todo replace session with lti_parameter - 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 @@ -96,11 +97,18 @@ module Lti end private :return_to_consumer - def send_score(score) + def send_score(exercise_id, score) ::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) - #Todo replace session with lti_parameter - provider = build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters]) + #Todo replace session with lti_parameter /done + lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], + external_user_id: session[:external_user_id], + exercises_id: exercise_id).first + lti_parameters = JSON.parse(lti_parameter.lti_parameters) + + consumer = Consumer.find_by(id: session[:consumer_id]) + provider = build_tool_provider(consumer: consumer, parameters: lti_parameters) + # provider = build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters]) if provider.nil? {status: 'error'} elsif provider.outcome_service? @@ -128,6 +136,9 @@ module Lti 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.external_id end private :store_lti_session_data diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index e1ada974..34bc376f 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -157,8 +157,18 @@ class ExercisesController < ApplicationController end def redirect_to_lti_return_path - #Todo replace session with lti_parameter - 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]))) + #Todo replace session with lti_parameter /done + lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], + external_user_id: session[:external_user_id], + exercises_id: @submission.exercise_id).first + + lti_parameters = JSON.parse(lti_parameter.lti_parameters) + + 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_parameters))) + # parameters: session[:lti_parameters]))) respond_to do |format| format.html { redirect_to(path) } format.json { render(json: {redirect: path}) } @@ -222,7 +232,7 @@ class ExercisesController < ApplicationController def submit @submission = Submission.create(submission_params) score_submission(@submission) - if lti_outcome_service? + if lti_outcome_service?(@submission.exercise_id) transmit_lti_score else redirect_after_submit @@ -231,7 +241,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) + if response[:status] == 'success' redirect_after_submit else diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index ce1418bb..9a9a7029 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -21,7 +21,9 @@ class SessionsController < ApplicationController set_current_user store_lti_session_data(consumer: @consumer, parameters: params) store_nonce(params[:oauth_nonce]) - redirect_to(implement_exercise_path(@exercise), notice: t("sessions.create_through_lti.session_#{lti_outcome_service? ? 'with' : 'without'}_outcome", consumer: @consumer)) + redirect_to(implement_exercise_path(@exercise), + notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id) ? 'with' : 'without'}_outcome", + consumer: @consumer)) end def destroy @@ -36,7 +38,8 @@ class SessionsController < ApplicationController def destroy_through_lti @consumer = Consumer.find_by(id: params[:consumer_id]) @submission = Submission.find(params[:submission_id]) - clear_lti_session_data + #TODO decide if we need to remove all LtiParameters for user/consumer + clear_lti_session_data(@submission.exercise_id) end def new diff --git a/app/helpers/exercise_helper.rb b/app/helpers/exercise_helper.rb index 7dcbb6f4..190a18f3 100644 --- a/app/helpers/exercise_helper.rb +++ b/app/helpers/exercise_helper.rb @@ -1,4 +1,6 @@ module ExerciseHelper + include LtiHelper + def embedding_parameters(exercise) "locale=#{I18n.locale}&token=#{exercise.token}" end diff --git a/app/helpers/lti_helper.rb b/app/helpers/lti_helper.rb new file mode 100644 index 00000000..4edf8445 --- /dev/null +++ b/app/helpers/lti_helper.rb @@ -0,0 +1,10 @@ +module LtiHelper + def lti_outcome_service?(exercise_id) + #Todo replace session with lti_parameter /done + lti_parameters = LtiParameter.where(consumers_id: session[:consumer_id], + external_user_id: session[:external_user_id], + exercises_id: exercise_id).lis_outcome_service_url? + !lti_parameters.nil? && lti_parameters.size > 0 + # session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') + end +end \ No newline at end of file diff --git a/app/models/lti_parameter.rb b/app/models/lti_parameter.rb index 667570be..a6b1917b 100644 --- a/app/models/lti_parameter.rb +++ b/app/models/lti_parameter.rb @@ -1,2 +1,5 @@ class LtiParameter < ActiveRecord::Base -end + scope :lis_outcome_service_url?, -> { + where("lti_parameters.lti_parameters ? 'lis_outcome_service_url'") + } +end \ No newline at end of file diff --git a/app/views/exercises/_editor_output.html.slim b/app/views/exercises/_editor_output.html.slim index 645d1a1d..cc3b6b98 100644 --- a/app/views/exercises/_editor_output.html.slim +++ b/app/views/exercises/_editor_output.html.slim @@ -27,8 +27,9 @@ div id='output_sidebar_uncollapsed' class='hidden col-sm-12 enforce-bottom-margi .progress-bar role='progressbar' br - / #Todo replace session with lti_parameter - - if session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') + / #Todo replace session with lti_parameter /done + /- if session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') + - if lti_outcome_service?(@exercise.id) p.text-center = render('editor_button', classes: 'btn-lg btn-success', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa fa-send', id: 'submit', label: t('exercises.editor.submit')) - else p.text-center = render('editor_button', classes: 'btn-lg btn-warning-outline', data: {:'data-placement' => 'bottom', :'data-tooltip' => true}, icon: 'fa fa-clock-o', id: 'submit_outdated', label: t('exercises.editor.exercise_deadline_passed'), title: t('exercises.editor.tooltips.exercise_deadline_passed')) diff --git a/debian_installer/setup_debian_1_install_postgres.sh b/debian_installer/setup_debian_1_install_postgres.sh index f94c7ee0..515362f1 100644 --- a/debian_installer/setup_debian_1_install_postgres.sh +++ b/debian_installer/setup_debian_1_install_postgres.sh @@ -44,7 +44,7 @@ else echo "Postgres installation failed" fi -# create database +# create development database # TODO: extract databasename to variable if ! (sudo -u postgres psql -l | grep -q codeocean-development) then @@ -57,7 +57,13 @@ then 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 \ No newline at end of file +fi + +# TODO: create test database + + + diff --git a/spec/concerns/lti_spec.rb b/spec/concerns/lti_spec.rb index ab047306..87c11d02 100644 --- a/spec/concerns/lti_spec.rb +++ b/spec/concerns/lti_spec.rb @@ -20,7 +20,8 @@ describe Lti do #Todo replace session with lti_parameter 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) + # expect(controller.session).to receive(:delete).with(:lti_parameters) + #Todo check that there are no more LtiParameters for this user/consumer/(exercise?) controller.send(:clear_lti_session_data) end end @@ -119,7 +120,8 @@ describe Lti do before(:each) do #Todo replace session with lti_parameter controller.session[:consumer_id] = consumer.id - controller.session[:lti_parameters] = {} + # controller.session[:lti_parameters] = {} + #Todo create empty LtiParameter instead end context 'when grading is not supported' do @@ -167,13 +169,15 @@ describe Lti do #Todo replace session with lti_parameter 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) } + #Todo do this with lti_parameter object + # after(:each) { controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) } it 'stores data in the session' do #Todo replace session with lti_parameter 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)) + # expect(controller.session).to receive(:[]=).with(:lti_parameters, kind_of(Hash)) + #Todo it creates an LtiParameter Object end it 'stores only selected tuples' do diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 9062008f..0ad4b20d 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -4,7 +4,6 @@ describe ApplicationController do describe '#current_user' do context 'with an external user' do let(:external_user) { FactoryGirl.create(:external_user) } - #Todo replace session with lti_parameter before(:each) { session[:external_user_id] = external_user.id } it 'returns the external user' do diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 06fc68dc..ffa957ea 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -78,7 +78,6 @@ describe SessionsController do it 'assigns the current user' do request expect(assigns(:current_user)).to be_an(ExternalUser) - #Todo replace session with lti_parameter expect(session[:external_user_id]).to eq(user.id) end @@ -94,7 +93,7 @@ describe SessionsController do end it 'stores LTI parameters in the session' do - #Todo replace session with lti_parameter + #Todo replace session with lti_parameter /should be done already expect(controller).to receive(:store_lti_session_data) request end @@ -161,7 +160,7 @@ describe SessionsController do end it 'clears the session' do - #Todo replace session with lti_parameter + #Todo replace session with lti_parameter /should be done already expect(controller).to receive(:clear_lti_session_data) delete :destroy end @@ -179,13 +178,14 @@ describe SessionsController do 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 + #Todo replace session with lti_parameter /should be done already expect(controller).to receive(:clear_lti_session_data) request.call end From 930f417a9f6bd3b0e8640ba9ce6f1e895ff68303 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Fri, 30 Dec 2016 09:48:21 +0100 Subject: [PATCH 07/26] Added setup instructions for adding a host-only network adapter. This is required so that codeocean on the VM can connect back to openHPI on the host machine. --- debian_installer/setup_debian_vm.sh | 57 ++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/debian_installer/setup_debian_vm.sh b/debian_installer/setup_debian_vm.sh index 1fdb628a..a06c7484 100644 --- a/debian_installer/setup_debian_vm.sh +++ b/debian_installer/setup_debian_vm.sh @@ -78,12 +78,67 @@ debian_installer/setup_debian_7_create_tables.sh # Protocol TCP Host port 3030, guest port 3000, name CodeOcean, other left blank. # That's all! # Start Puma server on VM -# rails s -p 3000 +# rails s -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 From ca28e0aa87bb799f8dfb9f31406c01d1aa0d0ee0 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Sat, 31 Dec 2016 00:05:23 +0100 Subject: [PATCH 08/26] updated rails from 4.1.13 to 4.2.5. This is required for rails to make use of new features in postgres 9.5 @Ralf TODO: migration /Users/groucho/Documents/HPI/workspace/Xikolo-CodeOcean/codeocean/db/migrate/20160204111716_add_user_to_code_harbor_link.rb is broken. A reference is made to table users which does not exist. Workaround: run rake db:schema:load before running db:migrate. Still this should be fixed. --- Gemfile | 2 +- Gemfile.lock | 135 +- app/controllers/concerns/lti.rb | 4 +- app/controllers/exercises_controller.rb | 4 +- bin/rails | 2 +- bin/setup | 29 + config/application.rb | 18 +- config/boot.rb | 3 +- config/environments/development.rb | 18 +- config/environments/production.rb | 30 +- config/environments/test.rb | 7 +- config/initializers/assets.rb | 12 + config/initializers/session_store.rb | 2 +- config/locales/en.yml | 22 + config/routes.rb | 14 +- .../20161214144837_create_lti_parameters.rb | 4 +- db/schema.rb | 143 +- db/structure.sql | 1227 +++++++++++++++++ debian_installer/setup_debian_vm.sh | 4 +- 19 files changed, 1503 insertions(+), 177 deletions(-) create mode 100755 bin/setup create mode 100644 config/initializers/assets.rb create mode 100644 db/structure.sql diff --git a/Gemfile b/Gemfile index 65cb5fe8..afd0aeff 100644 --- a/Gemfile +++ b/Gemfile @@ -21,7 +21,7 @@ gem 'pg', platform: :ruby gem 'pry-byebug' gem 'puma', '~> 2.15.3' gem 'pundit' -gem 'rails', '~> 4.1.13' +gem 'rails', '4.2.5' gem 'rails-i18n', '~> 4.0.0' gem 'ransack' gem 'rubytree' diff --git a/Gemfile.lock b/Gemfile.lock index 3493d81f..d00e819c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,40 +2,49 @@ GEM remote: https://rubygems.org/ specs: ZenTest (4.11.0) - actionmailer (4.1.14.1) - actionpack (= 4.1.14.1) - actionview (= 4.1.14.1) + actionmailer (4.2.5) + actionpack (= 4.2.5) + actionview (= 4.2.5) + activejob (= 4.2.5) mail (~> 2.5, >= 2.5.4) - actionpack (4.1.14.1) - actionview (= 4.1.14.1) - activesupport (= 4.1.14.1) - rack (~> 1.5.2) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.5) + actionview (= 4.2.5) + activesupport (= 4.2.5) + rack (~> 1.6) rack-test (~> 0.6.2) - actionview (4.1.14.1) - activesupport (= 4.1.14.1) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (4.2.5) + activesupport (= 4.2.5) builder (~> 3.1) erubis (~> 2.7.0) - activemodel (4.1.14.1) - activesupport (= 4.1.14.1) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + activejob (4.2.5) + activesupport (= 4.2.5) + globalid (>= 0.3.0) + activemodel (4.2.5) + activesupport (= 4.2.5) builder (~> 3.1) - activerecord (4.1.14.1) - activemodel (= 4.1.14.1) - activesupport (= 4.1.14.1) - arel (~> 5.0.0) + activerecord (4.2.5) + activemodel (= 4.2.5) + activesupport (= 4.2.5) + arel (~> 6.0) activerecord-jdbc-adapter (1.3.19) activerecord (>= 2.2) activerecord-jdbcpostgresql-adapter (1.3.19) activerecord-jdbc-adapter (~> 1.3.19) jdbc-postgres (>= 9.1) - activesupport (4.1.14.1) - i18n (~> 0.6, >= 0.6.9) + activesupport (4.2.5) + i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) - thread_safe (~> 0.1) + thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) addressable (2.4.0) - arel (5.0.1.20140414130214) - ast (2.2.0) + arel (6.0.4) + ast (2.3.0) autotest-rails (4.2.1) ZenTest (~> 4.5) bcrypt (3.1.10) @@ -97,6 +106,7 @@ GEM execjs coffee-script-source (1.10.0) concurrent-ruby (1.0.2) + concurrent-ruby (1.0.2-java) concurrent-ruby-ext (1.0.2) concurrent-ruby (~> 1.0.2) d3-rails (3.5.11) @@ -128,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) @@ -150,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) @@ -164,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) + mini_portile2 (~> 2.1.0) + nokogiri (1.7.0-java) nyan-cat-formatter (0.11) rspec (>= 2.99, >= 2.14.2, < 4) oauth (0.4.7) @@ -178,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) @@ -200,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) @@ -243,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) @@ -260,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) @@ -316,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) @@ -334,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) @@ -395,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 @@ -419,3 +443,6 @@ DEPENDENCIES uglifier (>= 1.3.0) web-console (~> 2.0) will_paginate (~> 3.0) + +BUNDLED WITH + 1.13.6 diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index cf489b7f..61559728 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -104,10 +104,8 @@ module Lti lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], external_user_id: session[:external_user_id], exercises_id: exercise_id).first - lti_parameters = JSON.parse(lti_parameter.lti_parameters) - consumer = Consumer.find_by(id: session[:consumer_id]) - provider = build_tool_provider(consumer: consumer, parameters: lti_parameters) + provider = build_tool_provider(consumer: consumer, parameters: lti_parameter.lti_parameters) # provider = build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters]) if provider.nil? {status: 'error'} diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index 34bc376f..c92e8084 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -162,12 +162,10 @@ class ExercisesController < ApplicationController external_user_id: session[:external_user_id], exercises_id: @submission.exercise_id).first - lti_parameters = JSON.parse(lti_parameter.lti_parameters) - 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_parameters))) + parameters: lti_parameter.lti_parameters))) # parameters: session[:lti_parameters]))) respond_to do |format| format.html { redirect_to(path) } diff --git a/bin/rails b/bin/rails index 728cd85a..5191e692 100755 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,4 @@ #!/usr/bin/env ruby -APP_PATH = File.expand_path('../../config/application', __FILE__) +APP_PATH = File.expand_path('../../config/application', __FILE__) require_relative '../config/boot' require 'rails/commands' diff --git a/bin/setup b/bin/setup new file mode 100755 index 00000000..acdb2c13 --- /dev/null +++ b/bin/setup @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +require 'pathname' + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +Dir.chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file: + + puts "== Installing dependencies ==" + system "gem install bundler --conservative" + system "bundle check || bundle install" + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # system "cp config/database.yml.sample config/database.yml" + # end + + puts "\n== Preparing database ==" + system "bin/rake db:setup" + + puts "\n== Removing old logs and tempfiles ==" + system "rm -f log/*" + system "rm -rf tmp/cache" + + puts "\n== Restarting application server ==" + system "touch tmp/restart.txt" +end diff --git a/config/application.rb b/config/application.rb index 10a8537d..a9e3518b 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,13 +1,6 @@ require File.expand_path('../boot', __FILE__) -# Pick the frameworks you want: -require "active_model/railtie" -require "active_record/railtie" -require "action_controller/railtie" -require "action_mailer/railtie" -require "action_view/railtie" -require "sprockets/railtie" -# require "rails/test_unit/railtie" +require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. @@ -21,17 +14,22 @@ module CodeOcean # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. - config.time_zone = 'Berlin' + config.time_zone = 'UTC' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de config.i18n.available_locales = [:de, :en] + # Do not swallow errors in after_commit/after_rollback callbacks. + config.active_record.raise_in_transactional_callbacks = true + config.autoload_paths << Rails.root.join('lib') config.eager_load_paths << Rails.root.join('lib') config.assets.precompile += %w( markdown-buttons.png ) + config.active_record.schema_format = :sql + case (RUBY_ENGINE) when 'ruby' # ... @@ -43,5 +41,3 @@ module CodeOcean end end end - -Rails.application.config.assets.precompile += %w( markdown-buttons.png ) \ No newline at end of file diff --git a/config/boot.rb b/config/boot.rb index 5e5f0c1f..6b750f00 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,4 +1,3 @@ -# Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/config/environments/development.rb b/config/environments/development.rb index 10cc7bc8..5960bb24 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,7 +1,8 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - config.web_console.whitelisted_ips = '192.168.0.0/16' + config.web_console.whitelisted_ips = '192.168.0.0/16' + # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. @@ -13,8 +14,8 @@ Rails.application.configure do # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false - - config.action_mailer.perform_deliveries = true + + config.action_mailer.perform_deliveries = false # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false @@ -25,12 +26,21 @@ Rails.application.configure do # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true + + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = true + # Adds additional error checking when serving assets at runtime. # Checks for improperly declared sprockets dependencies. # Raises helpful error messages. config.assets.raise_runtime_errors = true - # Raise errors for missing translations. + # Raises error for missing translations config.action_view.raise_on_missing_translations = true BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP'] diff --git a/config/environments/production.rb b/config/environments/production.rb index 3c3fe0c5..23c4e5b4 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -16,11 +16,13 @@ Rails.application.configure do # Enable Rack::Cache to put a simple HTTP cache in front of your application # Add `rack-cache` to your Gemfile before enabling this. - # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. + # For large-scale production use, consider using a caching reverse proxy like + # NGINX, varnish or squid. # config.action_dispatch.rack_cache = true - # Disable Rails's static asset server (Apache or nginx will already do this). - config.serve_static_assets = false + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier @@ -29,20 +31,21 @@ Rails.application.configure do # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Generate digests for assets URLs. + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. config.assets.digest = true - # Version of your assets, change this if you want to expire all your assets. - config.assets.version = '1.0' + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # Set to :debug to see everything in the log. + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. config.log_level = :error # Prepend all log lines with the following tags. @@ -55,11 +58,7 @@ Rails.application.configure do # config.cache_store = :mem_cache_store # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.action_controller.asset_host = "http://assets.example.com" - - # Precompile additional assets. - # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. - # config.assets.precompile += %w( search.js ) + # config.action_controller.asset_host = 'http://assets.example.com' # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. @@ -72,9 +71,6 @@ Rails.application.configure do # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify - # Disable automatic flushing of the log to improve performance. - # config.autoflush_log = false - # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new diff --git a/config/environments/test.rb b/config/environments/test.rb index 053f5b66..1c19f08b 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -12,8 +12,8 @@ Rails.application.configure do # preloads Rails for running tests, you may have to set it to true. config.eager_load = false - # Configure static asset server for tests with Cache-Control for performance. - config.serve_static_assets = true + # Configure static file server for tests with Cache-Control for performance. + config.serve_static_files = true config.static_cache_control = 'public, max-age=3600' # Show full error reports and disable caching. @@ -31,6 +31,9 @@ Rails.application.configure do # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test + # Randomize the order test cases are executed. + config.active_support.test_order = :random + # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 00000000..d74f7733 --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,12 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path +# Rails.application.config.assets.paths << Emoji.images_path + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. +# Rails.application.config.assets.precompile += %w( search.js ) +Rails.application.config.assets.precompile += %w( markdown-buttons.png ) \ No newline at end of file diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 1e5f1e1d..bdaed01f 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,3 +1,3 @@ # Be sure to restart your server when you modify this file. -Rails.application.config.session_store :cookie_store, key: '_hands-on-programming_session' +Rails.application.config.session_store :cookie_store, key: '_code_ocean_session' diff --git a/config/locales/en.yml b/config/locales/en.yml index 6d30f612..34ebd266 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,3 +1,24 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# To learn more, please read the Rails Internationalization guide +# available at http://guides.rubyonrails.org/i18n.html. + en: activerecord: attributes: @@ -466,3 +487,4 @@ en: previous_label: '← Previous Page' file_template: no_template_label: "Empty File" + diff --git a/config/routes.rb b/config/routes.rb index 0683a6f1..b4606f74 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,7 +3,7 @@ FILENAME_REGEXP = /[\w\.]+/ unless Kernel.const_defined?(:FILENAME_REGEXP) Rails.application.routes.draw do resources :file_templates do collection do - get 'by_file_type/:file_type_id', as: :by_file_type, to: :by_file_type + get 'by_file_type/:file_type_id', as: :by_file_type, action: :by_file_type end end resources :code_harbor_links @@ -42,7 +42,7 @@ Rails.application.routes.draw do resources :execution_environments do member do get :shell - post 'shell', as: :execute_command, to: :execute_command + post 'shell', as: :execute_command, action: :execute_command get :statistics end @@ -94,14 +94,14 @@ Rails.application.routes.draw do resources :submissions, only: [:create, :index, :show] do member do - get 'download', as: :download, to: :download - get 'download/:filename', as: :download_file, constraints: {filename: FILENAME_REGEXP}, to: :download_file - get 'render/:filename', as: :render, constraints: {filename: FILENAME_REGEXP}, to: :render_file - get 'run/:filename', as: :run, constraints: {filename: FILENAME_REGEXP}, to: :run + get 'download', as: :download, action: :download + get 'download/:filename', as: :download_file, constraints: {filename: FILENAME_REGEXP}, action: :download_file + get 'render/:filename', as: :render, constraints: {filename: FILENAME_REGEXP}, action: :render_file + get 'run/:filename', as: :run, constraints: {filename: FILENAME_REGEXP}, action: :run get :score get :statistics post :stop - get 'test/:filename', as: :test, constraints: {filename: FILENAME_REGEXP}, to: :test + get 'test/:filename', as: :test, constraints: {filename: FILENAME_REGEXP}, action: :test end end diff --git a/db/migrate/20161214144837_create_lti_parameters.rb b/db/migrate/20161214144837_create_lti_parameters.rb index 890484f4..053149a6 100644 --- a/db/migrate/20161214144837_create_lti_parameters.rb +++ b/db/migrate/20161214144837_create_lti_parameters.rb @@ -4,9 +4,9 @@ class CreateLtiParameters < ActiveRecord::Migration t.string :external_user_id t.belongs_to :consumers t.belongs_to :exercises - t.column :lti_parameters, :jsonb + t.jsonb :lti_parameters, null: false, default: '{}' t.timestamps end end -end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index b7bef30a..6f5accb0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,13 +11,13 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20161216131239) 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: 20161216131239) 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: 20161216131239) 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: 20161216131239) do add_index "errors", ["submission_id"], name: "index_errors_on_submission_id", using: :btree - create_table "execution_environments", force: true do |t| - t.string "docker_image" - t.string "name" + create_table "execution_environments", force: :cascade do |t| + t.string "docker_image", limit: 255 + t.string "name", limit: 255 t.datetime "created_at" t.datetime "updated_at" - t.string "run_command" - t.string "test_command" - t.string "testing_framework" + t.string "run_command", limit: 255 + t.string "test_command", limit: 255 + t.string "testing_framework", limit: 255 t.text "help" - t.string "exposed_ports" + t.string "exposed_ports", limit: 255 t.integer "permitted_execution_time" t.integer "user_id" - t.string "user_type" + t.string "user_type", limit: 255 t.integer "pool_size" t.integer "file_type_id" t.integer "memory_limit" t.boolean "network_enabled" end - create_table "exercises", force: true do |t| + create_table "exercises", force: :cascade do |t| t.text "description" t.integer "execution_environment_id" - t.string "title" + t.string "title", limit: 255 t.datetime "created_at" t.datetime "updated_at" t.integer "user_id" t.text "instructions" t.boolean "public" - t.string "user_type" - t.string "token" + t.string "user_type", limit: 255 + t.string "token", limit: 255 t.boolean "hide_file_tree" t.boolean "allow_file_creation" - t.boolean "allow_auto_completion", default: false + t.boolean "allow_auto_completion", default: false end - create_table "external_users", force: true do |t| + create_table "external_users", force: :cascade do |t| t.integer "consumer_id" - t.string "email" - t.string "external_id" - t.string "name" + t.string "email", limit: 255 + t.string "external_id", limit: 255 + t.string "name", limit: 255 t.datetime "created_at" t.datetime "updated_at" end - create_table "file_templates", force: true do |t| - t.string "name" + create_table "file_templates", force: :cascade do |t| + t.string "name", limit: 255 t.text "content" t.integer "file_type_id" t.datetime "created_at" t.datetime "updated_at" end - create_table "file_types", force: true do |t| - t.string "editor_mode" - t.string "file_extension" + create_table "file_types", force: :cascade do |t| + t.string "editor_mode", limit: 255 + t.string "file_extension", limit: 255 t.integer "indent_size" - t.string "name" + t.string "name", limit: 255 t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" t.boolean "executable" t.boolean "renderable" - t.string "user_type" + t.string "user_type", limit: 255 t.boolean "binary" end - create_table "files", force: true do |t| + create_table "files", force: :cascade do |t| t.text "content" t.integer "context_id" - t.string "context_type" + t.string "context_type", limit: 255 t.integer "file_id" t.integer "file_type_id" t.boolean "hidden" - t.string "name" + t.string "name", limit: 255 t.boolean "read_only" t.datetime "created_at" t.datetime "updated_at" - t.string "native_file" - t.string "role" - t.string "hashed_content" - t.string "feedback_message" + t.string "native_file", limit: 255 + t.string "role", limit: 255 + t.string "hashed_content", limit: 255 + t.string "feedback_message", limit: 255 t.float "weight" - t.string "path" + t.string "path", limit: 255 t.integer "file_template_id" end add_index "files", ["context_id", "context_type"], name: "index_files_on_context_id_and_context_type", using: :btree - create_table "hints", force: true do |t| + create_table "hints", force: :cascade do |t| t.integer "execution_environment_id" - t.string "locale" + t.string "locale", limit: 255 t.text "message" - t.string "name" - t.string "regular_expression" + t.string "name", limit: 255 + t.string "regular_expression", limit: 255 t.datetime "created_at" t.datetime "updated_at" end - create_table "internal_users", force: true do |t| + create_table "internal_users", force: :cascade do |t| t.integer "consumer_id" - t.string "email" - t.string "name" - t.string "role" + t.string "email", limit: 255 + t.string "name", limit: 255 + t.string "role", limit: 255 t.datetime "created_at" t.datetime "updated_at" - t.string "crypted_password" - t.string "salt" - t.integer "failed_logins_count", default: 0 + t.string "crypted_password", limit: 255 + t.string "salt", limit: 255 + t.integer "failed_logins_count", default: 0 t.datetime "lock_expires_at" - t.string "unlock_token" - t.string "remember_me_token" + t.string "unlock_token", limit: 255 + t.string "remember_me_token", limit: 255 t.datetime "remember_me_token_expires_at" - t.string "reset_password_token" + t.string "reset_password_token", limit: 255 t.datetime "reset_password_token_expires_at" t.datetime "reset_password_email_sent_at" - t.string "activation_state" - t.string "activation_token" + t.string "activation_state", limit: 255 + t.string "activation_token", limit: 255 t.datetime "activation_token_expires_at" end @@ -182,29 +182,38 @@ ActiveRecord::Schema.define(version: 20161216131239) do add_index "internal_users", ["remember_me_token"], name: "index_internal_users_on_remember_me_token", using: :btree add_index "internal_users", ["reset_password_token"], name: "index_internal_users_on_reset_password_token", using: :btree - create_table "request_for_comments", force: true do |t| - t.integer "user_id", null: false - t.integer "exercise_id", null: false - t.integer "file_id", null: false + create_table "lti_parameters", force: :cascade do |t| + t.string "external_user_id" + t.integer "consumers_id" + t.integer "exercises_id" + t.jsonb "lti_parameters", default: {}, null: false t.datetime "created_at" t.datetime "updated_at" - t.string "user_type" + end + + create_table "request_for_comments", force: :cascade do |t| + t.integer "user_id", null: false + t.integer "exercise_id", null: false + t.integer "file_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.string "user_type", limit: 255 t.text "question" t.boolean "solved" t.integer "submission_id" end - create_table "submissions", force: true do |t| + create_table "submissions", force: :cascade do |t| t.integer "exercise_id" t.float "score" t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" - t.string "cause" - t.string "user_type" + t.string "cause", limit: 255 + t.string "user_type", limit: 255 end - create_table "testruns", force: true do |t| + create_table "testruns", force: :cascade do |t| t.boolean "passed" t.text "output" t.integer "file_id" diff --git a/db/structure.sql b/db/structure.sql new file mode 100644 index 00000000..298a1e32 --- /dev/null +++ b/db/structure.sql @@ -0,0 +1,1227 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 9.5.5 +-- Dumped by pg_dump version 9.5.5 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: code_harbor_links; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE code_harbor_links ( + id integer NOT NULL, + oauth2token character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + user_id integer +); + + +-- +-- Name: code_harbor_links_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE code_harbor_links_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: code_harbor_links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE code_harbor_links_id_seq OWNED BY code_harbor_links.id; + + +-- +-- Name: comments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE comments ( + id integer NOT NULL, + user_id integer, + file_id integer, + user_type character varying(255), + "row" integer, + "column" integer, + text text, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE comments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE comments_id_seq OWNED BY comments.id; + + +-- +-- Name: consumers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE consumers ( + id integer NOT NULL, + name character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + oauth_key character varying(255), + oauth_secret character varying(255) +); + + +-- +-- Name: consumers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE consumers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: consumers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE consumers_id_seq OWNED BY consumers.id; + + +-- +-- Name: errors; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE errors ( + id integer NOT NULL, + execution_environment_id integer, + message text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + submission_id integer +); + + +-- +-- Name: errors_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE errors_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: errors_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE errors_id_seq OWNED BY errors.id; + + +-- +-- Name: execution_environments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE execution_environments ( + id integer NOT NULL, + docker_image character varying(255), + name character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + run_command character varying(255), + test_command character varying(255), + testing_framework character varying(255), + help text, + exposed_ports character varying(255), + permitted_execution_time integer, + user_id integer, + user_type character varying(255), + pool_size integer, + file_type_id integer, + memory_limit integer, + network_enabled boolean +); + + +-- +-- Name: execution_environments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE execution_environments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: execution_environments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE execution_environments_id_seq OWNED BY execution_environments.id; + + +-- +-- Name: exercises; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE exercises ( + id integer NOT NULL, + description text, + execution_environment_id integer, + title character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + user_id integer, + instructions text, + public boolean, + user_type character varying(255), + token character varying(255), + hide_file_tree boolean, + allow_file_creation boolean, + allow_auto_completion boolean DEFAULT false +); + + +-- +-- Name: exercises_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE exercises_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: exercises_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE exercises_id_seq OWNED BY exercises.id; + + +-- +-- Name: external_users; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE external_users ( + id integer NOT NULL, + consumer_id integer, + email character varying(255), + external_id character varying(255), + name character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: external_users_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE external_users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: external_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE external_users_id_seq OWNED BY external_users.id; + + +-- +-- Name: file_templates; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE file_templates ( + id integer NOT NULL, + name character varying(255), + content text, + file_type_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: file_templates_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE file_templates_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: file_templates_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE file_templates_id_seq OWNED BY file_templates.id; + + +-- +-- Name: file_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE file_types ( + id integer NOT NULL, + editor_mode character varying(255), + file_extension character varying(255), + indent_size integer, + name character varying(255), + user_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + executable boolean, + renderable boolean, + user_type character varying(255), + "binary" boolean +); + + +-- +-- Name: file_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE file_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: file_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE file_types_id_seq OWNED BY file_types.id; + + +-- +-- Name: files; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE files ( + id integer NOT NULL, + content text, + context_id integer, + context_type character varying(255), + file_id integer, + file_type_id integer, + hidden boolean, + name character varying(255), + read_only boolean, + created_at timestamp without time zone, + updated_at timestamp without time zone, + native_file character varying(255), + role character varying(255), + hashed_content character varying(255), + feedback_message character varying(255), + weight double precision, + path character varying(255), + file_template_id integer +); + + +-- +-- Name: files_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE files_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: files_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE files_id_seq OWNED BY files.id; + + +-- +-- Name: hints; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE hints ( + id integer NOT NULL, + execution_environment_id integer, + locale character varying(255), + message text, + name character varying(255), + regular_expression character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: hints_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE hints_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: hints_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE hints_id_seq OWNED BY hints.id; + + +-- +-- Name: internal_users; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE internal_users ( + id integer NOT NULL, + consumer_id integer, + email character varying(255), + name character varying(255), + role character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone, + crypted_password character varying(255), + salt character varying(255), + failed_logins_count integer DEFAULT 0, + lock_expires_at timestamp without time zone, + unlock_token character varying(255), + remember_me_token character varying(255), + remember_me_token_expires_at timestamp without time zone, + reset_password_token character varying(255), + reset_password_token_expires_at timestamp without time zone, + reset_password_email_sent_at timestamp without time zone, + activation_state character varying(255), + activation_token character varying(255), + activation_token_expires_at timestamp without time zone +); + + +-- +-- Name: internal_users_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE internal_users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: internal_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE internal_users_id_seq OWNED BY internal_users.id; + + +-- +-- Name: internal_users_teams; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE internal_users_teams ( + id integer NOT NULL, + internal_user_id integer, + team_id integer +); + + +-- +-- Name: internal_users_teams_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE internal_users_teams_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: internal_users_teams_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE internal_users_teams_id_seq OWNED BY internal_users_teams.id; + + +-- +-- Name: lti_parameters; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE lti_parameters ( + id integer NOT NULL, + external_user_id character varying, + consumers_id integer, + exercises_id integer, + lti_parameters jsonb DEFAULT '{}'::jsonb NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: lti_parameters_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE lti_parameters_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: lti_parameters_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE lti_parameters_id_seq OWNED BY lti_parameters.id; + + +-- +-- Name: request_for_comments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE request_for_comments ( + id integer NOT NULL, + user_id integer NOT NULL, + exercise_id integer NOT NULL, + file_id integer NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, + user_type character varying(255), + question text, + solved boolean, + submission_id integer +); + + +-- +-- Name: request_for_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE request_for_comments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: request_for_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE request_for_comments_id_seq OWNED BY request_for_comments.id; + + +-- +-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE schema_migrations ( + version character varying NOT NULL +); + + +-- +-- Name: submissions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE submissions ( + id integer NOT NULL, + exercise_id integer, + score double precision, + user_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + cause character varying(255), + user_type character varying(255) +); + + +-- +-- Name: submissions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE submissions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: submissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE submissions_id_seq OWNED BY submissions.id; + + +-- +-- Name: teams; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE teams ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: teams_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE teams_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: teams_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE teams_id_seq OWNED BY teams.id; + + +-- +-- Name: testruns; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE testruns ( + id integer NOT NULL, + passed boolean, + output text, + file_id integer, + submission_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: testruns_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE testruns_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: testruns_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE testruns_id_seq OWNED BY testruns.id; + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY code_harbor_links ALTER COLUMN id SET DEFAULT nextval('code_harbor_links_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY comments ALTER COLUMN id SET DEFAULT nextval('comments_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY consumers ALTER COLUMN id SET DEFAULT nextval('consumers_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY errors ALTER COLUMN id SET DEFAULT nextval('errors_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY execution_environments ALTER COLUMN id SET DEFAULT nextval('execution_environments_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY exercises ALTER COLUMN id SET DEFAULT nextval('exercises_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY external_users ALTER COLUMN id SET DEFAULT nextval('external_users_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY file_templates ALTER COLUMN id SET DEFAULT nextval('file_templates_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY file_types ALTER COLUMN id SET DEFAULT nextval('file_types_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY files ALTER COLUMN id SET DEFAULT nextval('files_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY hints ALTER COLUMN id SET DEFAULT nextval('hints_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY internal_users ALTER COLUMN id SET DEFAULT nextval('internal_users_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY internal_users_teams ALTER COLUMN id SET DEFAULT nextval('internal_users_teams_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY lti_parameters ALTER COLUMN id SET DEFAULT nextval('lti_parameters_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY request_for_comments ALTER COLUMN id SET DEFAULT nextval('request_for_comments_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY submissions ALTER COLUMN id SET DEFAULT nextval('submissions_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY teams ALTER COLUMN id SET DEFAULT nextval('teams_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY testruns ALTER COLUMN id SET DEFAULT nextval('testruns_id_seq'::regclass); + + +-- +-- Name: code_harbor_links_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY code_harbor_links + ADD CONSTRAINT code_harbor_links_pkey PRIMARY KEY (id); + + +-- +-- Name: comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY comments + ADD CONSTRAINT comments_pkey PRIMARY KEY (id); + + +-- +-- Name: consumers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY consumers + ADD CONSTRAINT consumers_pkey PRIMARY KEY (id); + + +-- +-- Name: errors_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY errors + ADD CONSTRAINT errors_pkey PRIMARY KEY (id); + + +-- +-- Name: execution_environments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY execution_environments + ADD CONSTRAINT execution_environments_pkey PRIMARY KEY (id); + + +-- +-- Name: exercises_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY exercises + ADD CONSTRAINT exercises_pkey PRIMARY KEY (id); + + +-- +-- Name: external_users_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY external_users + ADD CONSTRAINT external_users_pkey PRIMARY KEY (id); + + +-- +-- Name: file_templates_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY file_templates + ADD CONSTRAINT file_templates_pkey PRIMARY KEY (id); + + +-- +-- Name: file_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY file_types + ADD CONSTRAINT file_types_pkey PRIMARY KEY (id); + + +-- +-- Name: files_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY files + ADD CONSTRAINT files_pkey PRIMARY KEY (id); + + +-- +-- Name: hints_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY hints + ADD CONSTRAINT hints_pkey PRIMARY KEY (id); + + +-- +-- Name: internal_users_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY internal_users + ADD CONSTRAINT internal_users_pkey PRIMARY KEY (id); + + +-- +-- Name: internal_users_teams_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY internal_users_teams + ADD CONSTRAINT internal_users_teams_pkey PRIMARY KEY (id); + + +-- +-- Name: lti_parameters_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY lti_parameters + ADD CONSTRAINT lti_parameters_pkey PRIMARY KEY (id); + + +-- +-- Name: request_for_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY request_for_comments + ADD CONSTRAINT request_for_comments_pkey PRIMARY KEY (id); + + +-- +-- Name: submissions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY submissions + ADD CONSTRAINT submissions_pkey PRIMARY KEY (id); + + +-- +-- Name: teams_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY teams + ADD CONSTRAINT teams_pkey PRIMARY KEY (id); + + +-- +-- Name: testruns_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY testruns + ADD CONSTRAINT testruns_pkey PRIMARY KEY (id); + + +-- +-- Name: index_code_harbor_links_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_code_harbor_links_on_user_id ON code_harbor_links USING btree (user_id); + + +-- +-- Name: index_comments_on_file_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_comments_on_file_id ON comments USING btree (file_id); + + +-- +-- Name: index_comments_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_comments_on_user_id ON comments USING btree (user_id); + + +-- +-- Name: index_errors_on_submission_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_errors_on_submission_id ON errors USING btree (submission_id); + + +-- +-- Name: index_files_on_context_id_and_context_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_files_on_context_id_and_context_type ON files USING btree (context_id, context_type); + + +-- +-- Name: index_internal_users_on_activation_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_internal_users_on_activation_token ON internal_users USING btree (activation_token); + + +-- +-- Name: index_internal_users_on_email; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_internal_users_on_email ON internal_users USING btree (email); + + +-- +-- Name: index_internal_users_on_remember_me_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_internal_users_on_remember_me_token ON internal_users USING btree (remember_me_token); + + +-- +-- Name: index_internal_users_on_reset_password_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_internal_users_on_reset_password_token ON internal_users USING btree (reset_password_token); + + +-- +-- Name: index_internal_users_teams_on_internal_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_internal_users_teams_on_internal_user_id ON internal_users_teams USING btree (internal_user_id); + + +-- +-- Name: index_internal_users_teams_on_team_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_internal_users_teams_on_team_id ON internal_users_teams USING btree (team_id); + + +-- +-- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX unique_schema_migrations ON schema_migrations USING btree (version); + + +-- +-- PostgreSQL database dump complete +-- + +SET search_path TO "$user", public; + +INSERT INTO schema_migrations (version) VALUES ('20140625134118'); + +INSERT INTO schema_migrations (version) VALUES ('20140626143132'); + +INSERT INTO schema_migrations (version) VALUES ('20140626144036'); + +INSERT INTO schema_migrations (version) VALUES ('20140630093736'); + +INSERT INTO schema_migrations (version) VALUES ('20140630111215'); + +INSERT INTO schema_migrations (version) VALUES ('20140701120126'); + +INSERT INTO schema_migrations (version) VALUES ('20140701122345'); + +INSERT INTO schema_migrations (version) VALUES ('20140702100130'); + +INSERT INTO schema_migrations (version) VALUES ('20140703070749'); + +INSERT INTO schema_migrations (version) VALUES ('20140716153147'); + +INSERT INTO schema_migrations (version) VALUES ('20140717074902'); + +INSERT INTO schema_migrations (version) VALUES ('20140722125431'); + +INSERT INTO schema_migrations (version) VALUES ('20140723135530'); + +INSERT INTO schema_migrations (version) VALUES ('20140723135747'); + +INSERT INTO schema_migrations (version) VALUES ('20140724155359'); + +INSERT INTO schema_migrations (version) VALUES ('20140730114343'); + +INSERT INTO schema_migrations (version) VALUES ('20140730115010'); + +INSERT INTO schema_migrations (version) VALUES ('20140805161431'); + +INSERT INTO schema_migrations (version) VALUES ('20140812102114'); + +INSERT INTO schema_migrations (version) VALUES ('20140812144733'); + +INSERT INTO schema_migrations (version) VALUES ('20140812150607'); + +INSERT INTO schema_migrations (version) VALUES ('20140812150925'); + +INSERT INTO schema_migrations (version) VALUES ('20140813091722'); + +INSERT INTO schema_migrations (version) VALUES ('20140820170039'); + +INSERT INTO schema_migrations (version) VALUES ('20140821064318'); + +INSERT INTO schema_migrations (version) VALUES ('20140823172643'); + +INSERT INTO schema_migrations (version) VALUES ('20140823173923'); + +INSERT INTO schema_migrations (version) VALUES ('20140825121336'); + +INSERT INTO schema_migrations (version) VALUES ('20140825125801'); + +INSERT INTO schema_migrations (version) VALUES ('20140825154202'); + +INSERT INTO schema_migrations (version) VALUES ('20140825161350'); + +INSERT INTO schema_migrations (version) VALUES ('20140825161358'); + +INSERT INTO schema_migrations (version) VALUES ('20140825161406'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073318'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073319'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073320'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073321'); + +INSERT INTO schema_migrations (version) VALUES ('20140826073322'); + +INSERT INTO schema_migrations (version) VALUES ('20140827065359'); + +INSERT INTO schema_migrations (version) VALUES ('20140827083957'); + +INSERT INTO schema_migrations (version) VALUES ('20140829141913'); + +INSERT INTO schema_migrations (version) VALUES ('20140903093436'); + +INSERT INTO schema_migrations (version) VALUES ('20140903165113'); + +INSERT INTO schema_migrations (version) VALUES ('20140904082810'); + +INSERT INTO schema_migrations (version) VALUES ('20140909115430'); + +INSERT INTO schema_migrations (version) VALUES ('20140915095420'); + +INSERT INTO schema_migrations (version) VALUES ('20140915122846'); + +INSERT INTO schema_migrations (version) VALUES ('20140918063522'); + +INSERT INTO schema_migrations (version) VALUES ('20140922161120'); + +INSERT INTO schema_migrations (version) VALUES ('20140922161226'); + +INSERT INTO schema_migrations (version) VALUES ('20141003072729'); + +INSERT INTO schema_migrations (version) VALUES ('20141004114747'); + +INSERT INTO schema_migrations (version) VALUES ('20141009110434'); + +INSERT INTO schema_migrations (version) VALUES ('20141011145303'); + +INSERT INTO schema_migrations (version) VALUES ('20141017110211'); + +INSERT INTO schema_migrations (version) VALUES ('20141031161603'); + +INSERT INTO schema_migrations (version) VALUES ('20141119131607'); + +INSERT INTO schema_migrations (version) VALUES ('20150128083123'); + +INSERT INTO schema_migrations (version) VALUES ('20150128084834'); + +INSERT INTO schema_migrations (version) VALUES ('20150128093003'); + +INSERT INTO schema_migrations (version) VALUES ('20150204080832'); + +INSERT INTO schema_migrations (version) VALUES ('20150310150712'); + +INSERT INTO schema_migrations (version) VALUES ('20150317083739'); + +INSERT INTO schema_migrations (version) VALUES ('20150317115338'); + +INSERT INTO schema_migrations (version) VALUES ('20150327141740'); + +INSERT INTO schema_migrations (version) VALUES ('20150408155923'); + +INSERT INTO schema_migrations (version) VALUES ('20150421074734'); + +INSERT INTO schema_migrations (version) VALUES ('20150818141554'); + +INSERT INTO schema_migrations (version) VALUES ('20150818142251'); + +INSERT INTO schema_migrations (version) VALUES ('20150903152727'); + +INSERT INTO schema_migrations (version) VALUES ('20150922125415'); + +INSERT INTO schema_migrations (version) VALUES ('20160204094409'); + +INSERT INTO schema_migrations (version) VALUES ('20160204111716'); + +INSERT INTO schema_migrations (version) VALUES ('20160302133540'); + +INSERT INTO schema_migrations (version) VALUES ('20160426114951'); + +INSERT INTO schema_migrations (version) VALUES ('20160510145341'); + +INSERT INTO schema_migrations (version) VALUES ('20160512131539'); + +INSERT INTO schema_migrations (version) VALUES ('20160609185708'); + +INSERT INTO schema_migrations (version) VALUES ('20160610111602'); + +INSERT INTO schema_migrations (version) VALUES ('20160624130951'); + +INSERT INTO schema_migrations (version) VALUES ('20160630154310'); + +INSERT INTO schema_migrations (version) VALUES ('20160701092140'); + +INSERT INTO schema_migrations (version) VALUES ('20160704143402'); + +INSERT INTO schema_migrations (version) VALUES ('20160907123009'); + +INSERT INTO schema_migrations (version) VALUES ('20161214144837'); + diff --git a/debian_installer/setup_debian_vm.sh b/debian_installer/setup_debian_vm.sh index a06c7484..8759157d 100644 --- a/debian_installer/setup_debian_vm.sh +++ b/debian_installer/setup_debian_vm.sh @@ -77,8 +77,8 @@ debian_installer/setup_debian_7_create_tables.sh # Protocol TCP Host port 3030, guest port 3000, name CodeOcean, other left blank. # That's all! -# Start Puma server on VM -# rails s -p 8080 +# 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 From 6f57eb0707ff0740b4562c6e87d3c5c106fef276 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Sat, 31 Dec 2016 00:22:20 +0100 Subject: [PATCH 09/26] tell travis to use postgres 9.5 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1a5b99f1..08e44380 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ services: addons: code_climate: repo_token: 53a2c2608c848714e96f6a1fc0365dcfdfec051f7827d50cea965ea625f49734 + postgresql: "9.5" before_install: - export DISPLAY=:99.0 From f318c628181fbde6f2515fb9413673bba9e33e20 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Sat, 31 Dec 2016 00:51:07 +0100 Subject: [PATCH 10/26] session[:external_user_id] has a somewhat misleading name. As the tests fail however, when the value that fits the name is entered, I switched it back to the old version. --- app/controllers/concerns/lti.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 61559728..f84c8a04 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -136,7 +136,7 @@ module Lti lti_parameters.save! session[:consumer_id] = options[:consumer].id - session[:external_user_id] = @current_user.external_id + session[:external_user_id] = @current_user.id end private :store_lti_session_data From edb813ab149f1628d618b11fb03f29d5b4f964bf Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Sat, 31 Dec 2016 00:58:36 +0100 Subject: [PATCH 11/26] added separate value for the actual external_id of the external user. --- app/controllers/concerns/lti.rb | 11 ++++++++--- app/controllers/exercises_controller.rb | 2 +- app/helpers/lti_helper.rb | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index f84c8a04..702327d1 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -19,9 +19,11 @@ module Lti #Todo replace session with lti_parameter /done #TODO decide if we need to remove all LtiParameters for user/consumer if (exercise_id.nil?) - LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: session[:external_user_id]) + LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: session[:external_user_external_id]) else #TODO: probably it does not make sense to keep the LtiParameters if the session is deleted - LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: session[:external_user_id], exercises_id: exercise_id) + LtiParameter.destroy_all(consumers_id: session[:consumer_id], + external_user_id: session[:external_user_external_id], + exercises_id: exercise_id) end session.delete(:consumer_id) session.delete(:external_user_id) @@ -102,8 +104,10 @@ module Lti fail(Error, "Score #{score} must be between 0 and #{MAXIMUM_SCORE}!") unless (0..MAXIMUM_SCORE).include?(score) #Todo replace session with lti_parameter /done lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], - external_user_id: session[:external_user_id], + external_user_id: session[:external_user_external_id], exercises_id: exercise_id).first + # lti_parameters = JSON.parse(lti_parameter.lti_parameters) + consumer = Consumer.find_by(id: session[:consumer_id]) provider = build_tool_provider(consumer: consumer, parameters: lti_parameter.lti_parameters) # provider = build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters]) @@ -136,6 +140,7 @@ module Lti lti_parameters.save! session[:consumer_id] = options[:consumer].id + session[:external_user_external_id] = @current_user.external_id session[:external_user_id] = @current_user.id end private :store_lti_session_data diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index c92e8084..e9527c48 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -159,7 +159,7 @@ class ExercisesController < ApplicationController def redirect_to_lti_return_path #Todo replace session with lti_parameter /done lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], - external_user_id: session[:external_user_id], + external_user_id: session[:external_user_external_id], exercises_id: @submission.exercise_id).first path = lti_return_path(consumer_id: session[:consumer_id], diff --git a/app/helpers/lti_helper.rb b/app/helpers/lti_helper.rb index 4edf8445..5d1145d9 100644 --- a/app/helpers/lti_helper.rb +++ b/app/helpers/lti_helper.rb @@ -2,7 +2,7 @@ module LtiHelper def lti_outcome_service?(exercise_id) #Todo replace session with lti_parameter /done lti_parameters = LtiParameter.where(consumers_id: session[:consumer_id], - external_user_id: session[:external_user_id], + external_user_id: session[:external_user_external_id], exercises_id: exercise_id).lis_outcome_service_url? !lti_parameters.nil? && lti_parameters.size > 0 # session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') From 41a61a850750d6b4c114e0a6d5fd4750a0c21340 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Sat, 31 Dec 2016 17:21:46 +0100 Subject: [PATCH 12/26] Fixed the destroy session logic. 1. an exercise_id is provided ==> only the LtiParameter object for the current user, consumer, and exercise is deleted. 2. no exercise_id is provided ==> external user and consumer are removed from the session, all LtiParameter objects for this user and consumer are deleted. This enables users to have several tabs with exercises open and submitting the results to the tool consumer. When an exercise has been submitted, the user cannot use the back button to get back to CodeOcean and work on the submitted or any other exercise. For now a warning has been added to the info text to tell users not to do this. (As the LtiParameters have been deleted, the points can no more be submitted to the consumer.) @TODO disable/redirect back button? --- app/controllers/concerns/lti.rb | 11 ++++++----- app/controllers/sessions_controller.rb | 1 - app/views/sessions/destroy_through_lti.html.slim | 1 + config/locales/de.yml | 1 + config/locales/en.yml | 1 + 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 702327d1..0d8a86cc 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -15,19 +15,20 @@ module Lti end private :build_tool_provider + # 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) #Todo replace session with lti_parameter /done - #TODO decide if we need to remove all LtiParameters for user/consumer if (exercise_id.nil?) LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: session[:external_user_external_id]) - else #TODO: probably it does not make sense to keep the LtiParameters if the session is deleted + session.delete(:consumer_id) + session.delete(:external_user_id) + else LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: session[:external_user_external_id], exercises_id: exercise_id) end - session.delete(:consumer_id) - session.delete(:external_user_id) - #session.delete(:lti_parameters) end private :clear_lti_session_data diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 9a9a7029..e99d0ad8 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -38,7 +38,6 @@ class SessionsController < ApplicationController def destroy_through_lti @consumer = Consumer.find_by(id: params[:consumer_id]) @submission = Submission.find(params[:submission_id]) - #TODO decide if we need to remove all LtiParameters for user/consumer clear_lti_session_data(@submission.exercise_id) end diff --git a/app/views/sessions/destroy_through_lti.html.slim b/app/views/sessions/destroy_through_lti.html.slim index 8f1e89a8..3e55e0fc 100644 --- a/app/views/sessions/destroy_through_lti.html.slim +++ b/app/views/sessions/destroy_through_lti.html.slim @@ -3,6 +3,7 @@ h1 = t('.headline') p == t(".success_#{params[:outcome] ? 'with' : 'without'}_outcome", consumer: @consumer) ==< t(".finished_#{@consumer ? 'with' : 'without'}_consumer", consumer: @consumer, url: params[:url]) + ==< t(".do_not_use_backbutton", consumer: @consumer) h2 = t('shared.statistics') diff --git a/config/locales/de.yml b/config/locales/de.yml index 0695eda6..55fea63f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -386,6 +386,7 @@ de: score: Ihre Punktzahl success_with_outcome: 'Ihr Code wurde erfolgreich bewertet. Ihre Bewertung wurde an %{consumer} übermittelt.' success_without_outcome: Ihr Code wurde erfolgreich bewertet. + do_not_use_backbutton: Benutzen Sie nicht den "Zurück" Button des Browsers, um zu CodeOcean zurück zu kehren. Übungen müssen immer aus dem %{consumer} Kontext gestartet werden. new: forgot_password: Passwort vergessen? headline: Anmelden diff --git a/config/locales/en.yml b/config/locales/en.yml index 34ebd266..598faa33 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -407,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 From dd4c789fed841e32ab54d03598c00404481be0ea Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Thu, 12 Jan 2017 15:10:34 +0100 Subject: [PATCH 13/26] replaced session_paramerters with server params for security reasons cleaned up comments --- app/controllers/concerns/lti.rb | 13 +++++-------- app/controllers/exercises_controller.rb | 6 ++---- app/controllers/sessions_controller.rb | 2 +- app/helpers/lti_helper.rb | 10 +++++----- app/views/exercises/_editor.html.slim | 5 ++--- app/views/exercises/_editor_output.html.slim | 4 +--- config/locales/de.yml | 4 ++-- config/locales/en.yml | 4 ++-- 8 files changed, 20 insertions(+), 28 deletions(-) diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 0d8a86cc..33b716ff 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -19,14 +19,13 @@ module Lti # 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) - #Todo replace session with lti_parameter /done if (exercise_id.nil?) - LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: session[:external_user_external_id]) + LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: @current_user.external_id) session.delete(:consumer_id) session.delete(:external_user_id) else LtiParameter.destroy_all(consumers_id: session[:consumer_id], - external_user_id: session[:external_user_external_id], + external_user_id: @current_user.external_id, exercises_id: exercise_id) end end @@ -103,15 +102,14 @@ module Lti def send_score(exercise_id, score) ::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) - #Todo replace session with lti_parameter /done + lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], - external_user_id: session[:external_user_external_id], + external_user_id: @current_user.external_id, exercises_id: exercise_id).first - # lti_parameters = JSON.parse(lti_parameter.lti_parameters) consumer = Consumer.find_by(id: session[:consumer_id]) provider = build_tool_provider(consumer: consumer, parameters: lti_parameter.lti_parameters) - # provider = build_tool_provider(consumer: Consumer.find_by(id: session[:consumer_id]), parameters: session[:lti_parameters]) + if provider.nil? {status: 'error'} elsif provider.outcome_service? @@ -141,7 +139,6 @@ module Lti lti_parameters.save! session[:consumer_id] = options[:consumer].id - session[:external_user_external_id] = @current_user.external_id session[:external_user_id] = @current_user.id end private :store_lti_session_data diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index e9527c48..36a0ecbe 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -157,16 +157,14 @@ class ExercisesController < ApplicationController end def redirect_to_lti_return_path - #Todo replace session with lti_parameter /done lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], - external_user_id: session[:external_user_external_id], + external_user_id: @current_user.external_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))) - # parameters: session[:lti_parameters]))) respond_to do |format| format.html { redirect_to(path) } format.json { render(json: {redirect: path}) } @@ -230,7 +228,7 @@ class ExercisesController < ApplicationController def submit @submission = Submission.create(submission_params) score_submission(@submission) - if lti_outcome_service?(@submission.exercise_id) + if lti_outcome_service?(@submission.exercise_id, @current_user.external_id, @current_user.consumer_id) transmit_lti_score else redirect_after_submit diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index e99d0ad8..47445b68 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -22,7 +22,7 @@ class SessionsController < ApplicationController 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?(@exercise.id) ? 'with' : 'without'}_outcome", + notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.external_id , @consumer.id) ? 'with' : 'without'}_outcome", consumer: @consumer)) end diff --git a/app/helpers/lti_helper.rb b/app/helpers/lti_helper.rb index 5d1145d9..42ccae48 100644 --- a/app/helpers/lti_helper.rb +++ b/app/helpers/lti_helper.rb @@ -1,10 +1,10 @@ module LtiHelper - def lti_outcome_service?(exercise_id) - #Todo replace session with lti_parameter /done - lti_parameters = LtiParameter.where(consumers_id: session[:consumer_id], - external_user_id: session[:external_user_external_id], + 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_user_id: external_user_id, exercises_id: exercise_id).lis_outcome_service_url? !lti_parameters.nil? && lti_parameters.size > 0 - # session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') end end \ No newline at end of file diff --git a/app/views/exercises/_editor.html.slim b/app/views/exercises/_editor.html.slim index 6b14d3c8..aad007ee 100644 --- a/app/views/exercises/_editor.html.slim +++ b/app/views/exercises/_editor.html.slim @@ -1,11 +1,10 @@ - external_user_id = @current_user.respond_to?(:external_id) ? @current_user.external_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_id div id="sidebar" class=(@exercise.hide_file_tree ? 'sidebar-col-collapsed' : 'sidebar-col') = render('editor_file_tree', exercise: @exercise, files: @files) - div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output') + div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id ) div id='frames' class='editor-col' #editor-buttons.btn-group.enforce-bottom-margin - // = render('editor_button', data: {:'data-message-success' => t('submissions.create.success'), :'data-placement' => 'top', :'data-tooltip' => true}, icon: 'fa fa-save', id: 'save', label: t('exercises.editor.save'), title: t('.tooltips.save')) - // .btn-group = render('editor_button', disabled: true, icon: 'fa fa-ban', id: 'dummy', label: t('exercises.editor.dummy')) = render('editor_button', icon: 'fa fa-desktop', id: 'render', label: t('exercises.editor.render')) = render('editor_button', data: {:'data-message-failure' => t('exercises.editor.run_failure'), :'data-message-network' => t('exercises.editor.network'), :'data-message-success' => t('exercises.editor.run_success'), :'data-placement' => 'top', :'data-tooltip' => true}, icon: 'fa fa-play', id: 'run', label: t('exercises.editor.run'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + r')) diff --git a/app/views/exercises/_editor_output.html.slim b/app/views/exercises/_editor_output.html.slim index cc3b6b98..4b255d5a 100644 --- a/app/views/exercises/_editor_output.html.slim +++ b/app/views/exercises/_editor_output.html.slim @@ -27,9 +27,7 @@ div id='output_sidebar_uncollapsed' class='hidden col-sm-12 enforce-bottom-margi .progress-bar role='progressbar' br - / #Todo replace session with lti_parameter /done - /- if session[:lti_parameters].try(:has_key?, 'lis_outcome_service_url') - - if lti_outcome_service?(@exercise.id) + - if lti_outcome_service?(@exercise.id, external_user_id, consumer_id) p.text-center = render('editor_button', classes: 'btn-lg btn-success', data: {:'data-url' => submit_exercise_path(@exercise)}, icon: 'fa fa-send', id: 'submit', label: t('exercises.editor.submit')) - else p.text-center = render('editor_button', classes: 'btn-lg btn-warning-outline', data: {:'data-placement' => 'bottom', :'data-tooltip' => true}, icon: 'fa fa-clock-o', id: 'submit_outdated', label: t('exercises.editor.exercise_deadline_passed'), title: t('exercises.editor.tooltips.exercise_deadline_passed')) diff --git a/config/locales/de.yml b/config/locales/de.yml index 55fea63f..de6fe41a 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -217,10 +217,10 @@ de: submit: Code zur Bewertung abgeben test: Testen timeout: 'Ausführung gestoppt. Ihr Code hat die erlaubte Ausführungszeit von %{permitted_execution_time} Sekunden überschritten.' - exercise_deadline_passed: 'Die Abgabefrist für diese Aufgabe ist bereits abgelaufen.' + exercise_deadline_passed: 'Das Ergebnis kann nicht übertragen werden.' tooltips: save: Ihr Code wird automatisch gespeichert, wann immer Sie eine Datei herunterladen, ausführen oder testen. Explizites Speichern ist also selten notwendig. - exercise_deadline_passed: 'Die hier erzielten Punkte können nur bis zum Ablauf der Abgabefrist an die E-Learning-Plattform übertragen werden.' + exercise_deadline_passed: 'Entweder ist die Abgabefrist bereits abgelaufen oder Sie haben die Aufgabe nicht direkt über die E-Learning Plattform gestartet. (Möglicherweise haben Sie den Zurück Button Ihres Browsers benutzt nachdem Sie Ihre Aufgabe abgegeben haben?)' request_for_comments_sent: "Kommentaranfrage gesendet." editor_file_tree: file_root: Dateien diff --git a/config/locales/en.yml b/config/locales/en.yml index 598faa33..304d7d0f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -238,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 From e4daa7ece303db39b0ebe38fc8454df85aba7726 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Thu, 12 Jan 2017 16:03:30 +0100 Subject: [PATCH 14/26] only destroy LTI_parameter when exercise is submitted --- app/controllers/concerns/lti.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 33b716ff..073eb319 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -19,12 +19,12 @@ module Lti # 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) + @current_user = ExternalUser.find(@submission.user_id) if (exercise_id.nil?) - LtiParameter.destroy_all(consumers_id: session[:consumer_id], external_user_id: @current_user.external_id) session.delete(:consumer_id) session.delete(:external_user_id) else - LtiParameter.destroy_all(consumers_id: session[:consumer_id], + LtiParameter.destroy_all(consumers_id: @consumer.id, external_user_id: @current_user.external_id, exercises_id: exercise_id) end @@ -123,6 +123,7 @@ module Lti def set_current_user @current_user = ExternalUser.find_or_create_by(consumer_id: @consumer.id, external_id: @provider.user_id) + #TODO is this really necessary, and does it work at all? @current_user.update(email: external_user_email(@provider), name: external_user_name(@provider)) end private :set_current_user From 5fe12bfa783ac6d119790e706449273449ba907d Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Thu, 12 Jan 2017 18:12:36 +0100 Subject: [PATCH 15/26] fixing tests p1 --- app/controllers/concerns/lti.rb | 14 +-- app/controllers/exercises_controller.rb | 6 +- app/controllers/sessions_controller.rb | 5 +- app/helpers/lti_helper.rb | 2 +- app/views/exercises/_editor.html.slim | 5 +- ...> 20170112151637_create_lti_parameters.rb} | 3 +- db/structure.sql | 111 +----------------- spec/concerns/lti_spec.rb | 12 +- spec/factories/lti_parameter.rb | 12 ++ spec/factories/submission.rb | 2 +- spec/lib/docker_client_spec.rb | 4 +- 11 files changed, 41 insertions(+), 135 deletions(-) rename db/migrate/{20161214144837_create_lti_parameters.rb => 20170112151637_create_lti_parameters.rb} (88%) create mode 100644 spec/factories/lti_parameter.rb diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 073eb319..434a106f 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -18,14 +18,13 @@ module Lti # 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) - @current_user = ExternalUser.find(@submission.user_id) + def clear_lti_session_data(exercise_id = nil, user_id = nil, consumer_id = nil) if (exercise_id.nil?) session.delete(:consumer_id) session.delete(:external_user_id) else - LtiParameter.destroy_all(consumers_id: @consumer.id, - external_user_id: @current_user.external_id, + LtiParameter.destroy_all(consumers_id: consumer_id, + external_users_id: user_id, exercises_id: exercise_id) end end @@ -99,12 +98,12 @@ module Lti end private :return_to_consumer - def send_score(exercise_id, 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) lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], - external_user_id: @current_user.external_id, + external_users_id: user_id, exercises_id: exercise_id).first consumer = Consumer.find_by(id: session[:consumer_id]) @@ -123,7 +122,6 @@ module Lti def set_current_user @current_user = ExternalUser.find_or_create_by(consumer_id: @consumer.id, external_id: @provider.user_id) - #TODO is this really necessary, and does it work at all? @current_user.update(email: external_user_email(@provider), name: external_user_name(@provider)) end private :set_current_user @@ -133,7 +131,7 @@ module Lti exercise_id = exercise.id unless exercise.nil? lti_parameters = LtiParameter.find_or_create_by(consumers_id: options[:consumer].id, - external_user_id: options[:parameters][:user_id].to_s, + external_users_id: @current_user.id, #options[:parameters][:user_id].to_s, exercises_id: exercise_id) lti_parameters.lti_parameters = options[:parameters].slice(*SESSION_PARAMETERS).to_json diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index 36a0ecbe..4e27d013 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -158,7 +158,7 @@ class ExercisesController < ApplicationController def redirect_to_lti_return_path lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], - external_user_id: @current_user.external_id, + external_users_id: @current_user.id, exercises_id: @submission.exercise_id).first path = lti_return_path(consumer_id: session[:consumer_id], @@ -228,7 +228,7 @@ class ExercisesController < ApplicationController def submit @submission = Submission.create(submission_params) score_submission(@submission) - if lti_outcome_service?(@submission.exercise_id, @current_user.external_id, @current_user.consumer_id) + if lti_outcome_service?(@submission.exercise_id, @current_user.id, @current_user.consumer_id) transmit_lti_score else redirect_after_submit @@ -237,7 +237,7 @@ class ExercisesController < ApplicationController def transmit_lti_score ::NewRelic::Agent.add_custom_parameters({ submission: @submission.id, normalized_score: @submission.normalized_score }) - response = send_score(@submission.exercise_id, @submission.normalized_score) + response = send_score(@submission.exercise_id, @submission.normalized_score, @submission.user_id) if response[:status] == 'success' redirect_after_submit diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 47445b68..e6bdac8c 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -22,7 +22,7 @@ class SessionsController < ApplicationController 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?(@exercise.id, @current_user.external_id , @consumer.id) ? 'with' : 'without'}_outcome", + notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id , @consumer.id) ? 'with' : 'without'}_outcome", consumer: @consumer)) end @@ -36,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(@submission.exercise_id) + clear_lti_session_data(@submission.exercise_id, @submission.user_id, params[:consumer_id]) end def new diff --git a/app/helpers/lti_helper.rb b/app/helpers/lti_helper.rb index 42ccae48..f46974cd 100644 --- a/app/helpers/lti_helper.rb +++ b/app/helpers/lti_helper.rb @@ -3,7 +3,7 @@ module LtiHelper return false if external_user_id == '' || consumer_id == '' lti_parameters = LtiParameter.where(consumers_id: consumer_id, - external_user_id: external_user_id, + external_users_id: external_user_id, exercises_id: exercise_id).lis_outcome_service_url? !lti_parameters.nil? && lti_parameters.size > 0 end diff --git a/app/views/exercises/_editor.html.slim b/app/views/exercises/_editor.html.slim index aad007ee..56986673 100644 --- a/app/views/exercises/_editor.html.slim +++ b/app/views/exercises/_editor.html.slim @@ -1,6 +1,7 @@ -- 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 : '') +- 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_id +#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', external_user_id: external_user_id, consumer_id: consumer_id ) div id='frames' class='editor-col' diff --git a/db/migrate/20161214144837_create_lti_parameters.rb b/db/migrate/20170112151637_create_lti_parameters.rb similarity index 88% rename from db/migrate/20161214144837_create_lti_parameters.rb rename to db/migrate/20170112151637_create_lti_parameters.rb index 053149a6..c7613edf 100644 --- a/db/migrate/20161214144837_create_lti_parameters.rb +++ b/db/migrate/20170112151637_create_lti_parameters.rb @@ -1,11 +1,10 @@ class CreateLtiParameters < ActiveRecord::Migration def change create_table :lti_parameters do |t| - t.string :external_user_id + t.belongs_to :external_users t.belongs_to :consumers t.belongs_to :exercises t.jsonb :lti_parameters, null: false, default: '{}' - t.timestamps end end diff --git a/db/structure.sql b/db/structure.sql index 298a1e32..4b290bdc 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -485,43 +485,13 @@ CREATE SEQUENCE internal_users_id_seq ALTER SEQUENCE internal_users_id_seq OWNED BY internal_users.id; --- --- Name: internal_users_teams; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE internal_users_teams ( - id integer NOT NULL, - internal_user_id integer, - team_id integer -); - - --- --- Name: internal_users_teams_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE internal_users_teams_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: internal_users_teams_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE internal_users_teams_id_seq OWNED BY internal_users_teams.id; - - -- -- Name: lti_parameters; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE lti_parameters ( id integer NOT NULL, - external_user_id character varying, + external_users_id integer, consumers_id integer, exercises_id integer, lti_parameters jsonb DEFAULT '{}'::jsonb NOT NULL, @@ -591,7 +561,7 @@ ALTER SEQUENCE request_for_comments_id_seq OWNED BY request_for_comments.id; -- CREATE TABLE schema_migrations ( - version character varying NOT NULL + version character varying(255) NOT NULL ); @@ -630,37 +600,6 @@ CREATE SEQUENCE submissions_id_seq ALTER SEQUENCE submissions_id_seq OWNED BY submissions.id; --- --- Name: teams; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE teams ( - id integer NOT NULL, - name character varying, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: teams_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE teams_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: teams_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE teams_id_seq OWNED BY teams.id; - - -- -- Name: testruns; Type: TABLE; Schema: public; Owner: - -- @@ -779,13 +718,6 @@ ALTER TABLE ONLY hints ALTER COLUMN id SET DEFAULT nextval('hints_id_seq'::regcl ALTER TABLE ONLY internal_users ALTER COLUMN id SET DEFAULT nextval('internal_users_id_seq'::regclass); --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY internal_users_teams ALTER COLUMN id SET DEFAULT nextval('internal_users_teams_id_seq'::regclass); - - -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -807,13 +739,6 @@ ALTER TABLE ONLY request_for_comments ALTER COLUMN id SET DEFAULT nextval('reque ALTER TABLE ONLY submissions ALTER COLUMN id SET DEFAULT nextval('submissions_id_seq'::regclass); --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY teams ALTER COLUMN id SET DEFAULT nextval('teams_id_seq'::regclass); - - -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -917,14 +842,6 @@ ALTER TABLE ONLY internal_users ADD CONSTRAINT internal_users_pkey PRIMARY KEY (id); --- --- Name: internal_users_teams_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY internal_users_teams - ADD CONSTRAINT internal_users_teams_pkey PRIMARY KEY (id); - - -- -- Name: lti_parameters_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -949,14 +866,6 @@ ALTER TABLE ONLY submissions ADD CONSTRAINT submissions_pkey PRIMARY KEY (id); --- --- Name: teams_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY teams - ADD CONSTRAINT teams_pkey PRIMARY KEY (id); - - -- -- Name: testruns_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -1028,20 +937,6 @@ CREATE INDEX index_internal_users_on_remember_me_token ON internal_users USING b CREATE INDEX index_internal_users_on_reset_password_token ON internal_users USING btree (reset_password_token); --- --- Name: index_internal_users_teams_on_internal_user_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_internal_users_teams_on_internal_user_id ON internal_users_teams USING btree (internal_user_id); - - --- --- Name: index_internal_users_teams_on_team_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_internal_users_teams_on_team_id ON internal_users_teams USING btree (team_id); - - -- -- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: - -- @@ -1223,5 +1118,5 @@ INSERT INTO schema_migrations (version) VALUES ('20160704143402'); INSERT INTO schema_migrations (version) VALUES ('20160907123009'); -INSERT INTO schema_migrations (version) VALUES ('20161214144837'); +INSERT INTO schema_migrations (version) VALUES ('20170112151637'); diff --git a/spec/concerns/lti_spec.rb b/spec/concerns/lti_spec.rb index 87c11d02..27708866 100644 --- a/spec/concerns/lti_spec.rb +++ b/spec/concerns/lti_spec.rb @@ -17,11 +17,8 @@ describe Lti do describe '#clear_lti_session_data' do it 'clears the session' do - #Todo replace session with lti_parameter 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) - #Todo check that there are no more LtiParameters for this user/consumer/(exercise?) controller.send(:clear_lti_session_data) end end @@ -108,10 +105,13 @@ describe Lti do describe '#send_score' do let(:consumer) { FactoryGirl.create(:consumer) } let(:score) { 0.5 } + #let(:exercise) { FactoryGirl.create(:math) } + 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, Lti::MAXIMUM_SCORE * 2, submission.exercise_id, submission.user_id) }.to raise_error(Lti::Error) end end @@ -168,9 +168,10 @@ describe Lti do describe '#store_lti_session_data' do #Todo replace session with lti_parameter let(:parameters) { {} } + before_count = LtiParameter.count before(:each) { controller.instance_variable_set(:@current_user, FactoryGirl.create(:external_user)) } #Todo do this with lti_parameter object - # after(:each) { controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) } + after(:each) { controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) } it 'stores data in the session' do #Todo replace session with lti_parameter @@ -178,6 +179,7 @@ describe Lti do expect(controller.session).to receive(:[]=).with(:external_user_id, anything) # expect(controller.session).to receive(:[]=).with(:lti_parameters, kind_of(Hash)) #Todo it creates an LtiParameter Object + expect(LtiParameter.count).to eq(before_count + 1) end it 'stores only selected tuples' do diff --git a/spec/factories/lti_parameter.rb b/spec/factories/lti_parameter.rb new file mode 100644 index 00000000..d80e85e4 --- /dev/null +++ b/spec/factories/lti_parameter.rb @@ -0,0 +1,12 @@ +FactoryGirl.define do + factory :lti_parameter do + association :consumers_id, factory: :consumer + association :exercises_id, factory: :math + association :external_users_id, factory: :external_user + + + trait :lti_parameters do + JSON.parse('{"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"}') + end + end +end \ No newline at end of file diff --git a/spec/factories/submission.rb b/spec/factories/submission.rb index b3ef8a0e..cd4e34e1 100644 --- a/spec/factories/submission.rb +++ b/spec/factories/submission.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :submission do cause 'save' created_by_external_user - association :exercise, factory: :fibonacci + association :exercise, factory: :math after(:create) do |submission| submission.exercise.files.editable.visible.each do |file| diff --git a/spec/lib/docker_client_spec.rb b/spec/lib/docker_client_spec.rb index e9343f9a..feb457f6 100644 --- a/spec/lib/docker_client_spec.rb +++ b/spec/lib/docker_client_spec.rb @@ -3,8 +3,8 @@ require 'seeds_helper' describe DockerClient, docker: true do let(:command) { 'whoami' } - let(:docker_client) { described_class.new(execution_environment: FactoryGirl.build(:ruby), user: FactoryGirl.build(:admin)) } - let(:execution_environment) { FactoryGirl.build(:ruby) } + let(:docker_client) { described_class.new(execution_environment: FactoryGirl.build(:java), user: FactoryGirl.build(:admin)) } + let(:execution_environment) { FactoryGirl.build(:java) } let(:image) { double } let(:submission) { FactoryGirl.create(:submission) } let(:workspace_path) { '/tmp' } From 4af24d43178fc8c2f9c3c6c65b2f2de41c8297ce Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Fri, 13 Jan 2017 00:37:07 +0100 Subject: [PATCH 16/26] fixing tests p2 lti_spec tests all passed --- app/controllers/concerns/lti.rb | 17 +++++++++------- spec/concerns/lti_spec.rb | 36 ++++++++++++--------------------- spec/factories/lti_parameter.rb | 25 ++++++++++++++++------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 434a106f..7c168ec6 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -102,12 +102,14 @@ module Lti ::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) - lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], - external_users_id: user_id, - exercises_id: exercise_id).first + 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) + 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'} @@ -130,15 +132,16 @@ module Lti 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, #options[:parameters][:user_id].to_s, + 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[:external_user_id] = current_user.id end private :store_lti_session_data diff --git a/spec/concerns/lti_spec.rb b/spec/concerns/lti_spec.rb index 27708866..95181d3b 100644 --- a/spec/concerns/lti_spec.rb +++ b/spec/concerns/lti_spec.rb @@ -105,29 +105,25 @@ describe Lti do describe '#send_score' do let(:consumer) { FactoryGirl.create(:consumer) } let(:score) { 0.5 } - #let(:exercise) { FactoryGirl.create(:math) } 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, submission.exercise_id, submission.user_id) }.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 - #Todo replace session with lti_parameter controller.session[:consumer_id] = consumer.id - # controller.session[:lti_parameters] = {} - #Todo create empty LtiParameter instead 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 @@ -144,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) @@ -156,34 +152,28 @@ 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 end describe '#store_lti_session_data' do - #Todo replace session with lti_parameter let(:parameters) { {} } - before_count = LtiParameter.count - before(:each) { controller.instance_variable_set(:@current_user, FactoryGirl.create(:external_user)) } - #Todo do this with lti_parameter object - after(:each) { controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) } it 'stores data in the session' do - #Todo replace session with lti_parameter + 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)) - #Todo it creates an LtiParameter Object - expect(LtiParameter.count).to eq(before_count + 1) + controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) end - it 'stores only selected tuples' do - expect(parameters).to receive(:slice).with(*Lti::SESSION_PARAMETERS) + it 'it creates an LtiParameter Object' do + before_count = LtiParameter.count + controller.send(:store_lti_session_data, consumer: FactoryGirl.build(:consumer), parameters: parameters) + expect(LtiParameter.count).to eq(before_count + 1) end end diff --git a/spec/factories/lti_parameter.rb b/spec/factories/lti_parameter.rb index d80e85e4..ef91f30d 100644 --- a/spec/factories/lti_parameter.rb +++ b/spec/factories/lti_parameter.rb @@ -1,12 +1,23 @@ FactoryGirl.define do + #TODO do this proper factory :lti_parameter do - association :consumers_id, factory: :consumer - association :exercises_id, factory: :math - association :external_users_id, factory: :external_user + consumers_id 1 + exercises_id 1 + external_users_id 1 - - trait :lti_parameters do - JSON.parse('{"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"}') - end + lti_parameters JSON.parse('{"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"}') end + + # factory :lti_parameter do + # association :consumers_id, factory: :consumer + # association :exercises_id, factory: :math + # association :external_users_id, factory: :external_user + # + # + # trait :lti_parameters do + # JSON.parse('{"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"}') + # end + # end end \ No newline at end of file From 6bf73757ae624d10f5d48e3c017e0a8a8c764852 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Fri, 13 Jan 2017 09:56:36 +0100 Subject: [PATCH 17/26] fixing tests p3 --- app/controllers/exercises_controller.rb | 7 +++++-- spec/controllers/exercises_controller_spec.rb | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index 4e27d013..6eb74602 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -158,9 +158,11 @@ class ExercisesController < ApplicationController def redirect_to_lti_return_path lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id], - external_users_id: @current_user.id, + external_users_id: @submission.user_id, exercises_id: @submission.exercise_id).first + # binding.pry + 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]), @@ -228,7 +230,8 @@ class ExercisesController < ApplicationController def submit @submission = Submission.create(submission_params) score_submission(@submission) - if lti_outcome_service?(@submission.exercise_id, @current_user.id, @current_user.consumer_id) + 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 diff --git a/spec/controllers/exercises_controller_spec.rb b/spec/controllers/exercises_controller_spec.rb index 5323096d..278f9967 100644 --- a/spec/controllers/exercises_controller_spec.rb +++ b/spec/controllers/exercises_controller_spec.rb @@ -230,11 +230,14 @@ describe ExercisesController do describe 'POST #submit' do let(:output) { {} } let(:request) { post :submit, format: :json, id: exercise.id, submission: {cause: 'submit', exercise_id: exercise.id} } + let!(:external_user) { FactoryGirl.create(:external_user) } + let!(:lti_parameter) { FactoryGirl.create(:lti_parameter) } 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 From e634caf408d04d9b76e7e6422e06fbb0ed6644a4 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Fri, 13 Jan 2017 11:11:15 +0100 Subject: [PATCH 18/26] fixing tests final nice-up --- app/models/lti_parameter.rb | 4 ++++ spec/factories/lti_parameter.rb | 33 +++++++++++++++------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/app/models/lti_parameter.rb b/app/models/lti_parameter.rb index a6b1917b..3351a6c9 100644 --- a/app/models/lti_parameter.rb +++ b/app/models/lti_parameter.rb @@ -1,4 +1,8 @@ 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'") } diff --git a/spec/factories/lti_parameter.rb b/spec/factories/lti_parameter.rb index ef91f30d..9cd0f367 100644 --- a/spec/factories/lti_parameter.rb +++ b/spec/factories/lti_parameter.rb @@ -1,23 +1,20 @@ FactoryGirl.define do - #TODO do this proper + + 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 - consumers_id 1 - exercises_id 1 - external_users_id 1 + association :consumer + association :exercise, factory: :math + association :external_user - lti_parameters JSON.parse('{"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"}') + lti_parameters LTI_PARAMETERS + + trait :without_outcome_service_url do + lti_parameters LTI_PARAMETERS.except(:lis_outcome_service_url) + end end - - # factory :lti_parameter do - # association :consumers_id, factory: :consumer - # association :exercises_id, factory: :math - # association :external_users_id, factory: :external_user - # - # - # trait :lti_parameters do - # JSON.parse('{"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"}') - # end - # end end \ No newline at end of file From 3a07e7d5f6e198a9a0a554f4bb2465d001ad11ce Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Fri, 13 Jan 2017 13:46:36 +0100 Subject: [PATCH 19/26] Updated nokogiri --- Gemfile.lock | 4 ++-- app/controllers/exercises_controller.rb | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1b191914..166109fe 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -178,9 +178,9 @@ GEM net-ssh (3.0.2) netrc (0.10.3) newrelic_rpm (3.14.3.313) - nokogiri (1.7.0) + nokogiri (1.7.0.1) mini_portile2 (~> 2.1.0) - nokogiri (1.7.0-java) + nokogiri (1.7.0.1-java) nyan-cat-formatter (0.11) rspec (>= 2.99, >= 2.14.2, < 4) oauth (0.4.7) diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index 6eb74602..79314208 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -161,8 +161,6 @@ class ExercisesController < ApplicationController external_users_id: @submission.user_id, exercises_id: @submission.exercise_id).first - # binding.pry - 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]), From d8fa661c90bc79315a0acb2049bd4e9b82b4aa10 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Wed, 18 Jan 2017 10:52:24 +0100 Subject: [PATCH 20/26] changed back "action" to "to" in routes --- config/routes.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index b4606f74..0683a6f1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,7 +3,7 @@ FILENAME_REGEXP = /[\w\.]+/ unless Kernel.const_defined?(:FILENAME_REGEXP) Rails.application.routes.draw do resources :file_templates do collection do - get 'by_file_type/:file_type_id', as: :by_file_type, action: :by_file_type + get 'by_file_type/:file_type_id', as: :by_file_type, to: :by_file_type end end resources :code_harbor_links @@ -42,7 +42,7 @@ Rails.application.routes.draw do resources :execution_environments do member do get :shell - post 'shell', as: :execute_command, action: :execute_command + post 'shell', as: :execute_command, to: :execute_command get :statistics end @@ -94,14 +94,14 @@ Rails.application.routes.draw do resources :submissions, only: [:create, :index, :show] do member do - get 'download', as: :download, action: :download - get 'download/:filename', as: :download_file, constraints: {filename: FILENAME_REGEXP}, action: :download_file - get 'render/:filename', as: :render, constraints: {filename: FILENAME_REGEXP}, action: :render_file - get 'run/:filename', as: :run, constraints: {filename: FILENAME_REGEXP}, action: :run + get 'download', as: :download, to: :download + get 'download/:filename', as: :download_file, constraints: {filename: FILENAME_REGEXP}, to: :download_file + get 'render/:filename', as: :render, constraints: {filename: FILENAME_REGEXP}, to: :render_file + get 'run/:filename', as: :run, constraints: {filename: FILENAME_REGEXP}, to: :run get :score get :statistics post :stop - get 'test/:filename', as: :test, constraints: {filename: FILENAME_REGEXP}, action: :test + get 'test/:filename', as: :test, constraints: {filename: FILENAME_REGEXP}, to: :test end end From 4674c057a4877868c48cdb512bdfbd622e879df8 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Wed, 18 Jan 2017 11:10:34 +0100 Subject: [PATCH 21/26] Fixed rejection of untagged images --- lib/docker_client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/docker_client.rb b/lib/docker_client.rb index a8bdf915..28e2a3fb 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -325,7 +325,7 @@ class DockerClient end def self.image_tags - Docker::Image.all.map { |image| image.info['RepoTags'] }.flatten.reject { |tag| tag.present? && tag.include?('') } + Docker::Image.all.map { |image| image.info['RepoTags'] }.flatten.reject { |tag| tag.nil? || tag.include?('') } end def initialize(options = {}) From 721c11bf28236de90bbcdd04560119a3cade4099 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Wed, 18 Jan 2017 11:28:27 +0100 Subject: [PATCH 22/26] fixed staging.rb according to rails update --- config/environments/staging.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/staging.rb b/config/environments/staging.rb index ca1a98bb..7caf841e 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -37,7 +37,7 @@ Rails.application.configure do # config.action_dispatch.rack_cache = true # Disable Rails's static asset server (Apache or nginx will already do this). - config.serve_static_assets = false + config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. # config.assets.js_compressor = :uglifier From 59f2ff436e1ecde1a05434e2ccbc27b28149df93 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Wed, 18 Jan 2017 13:35:18 +0100 Subject: [PATCH 23/26] removed url helper from model --- app/models/submission.rb | 17 ----------------- app/views/submissions/show.json.jbuilder | 9 ++++++++- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/app/models/submission.rb b/app/models/submission.rb index 5a95587f..1abbbb84 100644 --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -28,17 +28,6 @@ class Submission < ActiveRecord::Base ancestors.merge(descendants).values end - [:download_file, :render, :run, :test].each do |action| - filename = FILENAME_URL_PLACEHOLDER.gsub(/\W/, '') - define_method("#{action}_url") do - Rails.application.routes.url_helpers.send(:"#{action}_submission_path", self, filename).sub(filename, FILENAME_URL_PLACEHOLDER) - end - end - - def download_url - Rails.application.routes.url_helpers.send(:download_submission_path, self) - end - def main_file collect_files.detect(&:main_file?) end @@ -56,12 +45,6 @@ class Submission < ActiveRecord::Base (normalized_score * 100).round end - [:score, :stop].each do |action| - define_method("#{action}_url") do - Rails.application.routes.url_helpers.send(:"#{action}_submission_path", self) - end - end - def siblings user.submissions.where(exercise_id: exercise_id) end diff --git a/app/views/submissions/show.json.jbuilder b/app/views/submissions/show.json.jbuilder index 3b860684..07e199f4 100644 --- a/app/views/submissions/show.json.jbuilder +++ b/app/views/submissions/show.json.jbuilder @@ -1 +1,8 @@ -json.extract! @submission, :download_url, :download_file_url, :id, :score_url, :render_url, :run_url, :stop_url, :test_url, :files +json.extract! @submission, :id, :files +json.download_url download_submission_path(@submission) +json.score_url score_submission_path(@submission) +json.stop_url stop_submission_path(@submission) +json.download_file_url download_file_submission_path(@submission, 'a.').gsub(/a\.$/, '{filename}') +json.render_url render_submission_path(@submission, 'a.').gsub(/a\.$/, '{filename}') +json.run_url run_submission_path(@submission, 'a.').gsub(/a\.$/, '{filename}') +json.test_url test_submission_path(@submission, 'a.').gsub(/a\.$/, '{filename}') From de79508efb6ceab34f41139d1969e5095d1fea25 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Wed, 18 Jan 2017 13:45:30 +0100 Subject: [PATCH 24/26] repLACED STRING WITH URL --- app/assets/javascripts/editor/execution.js.erb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/editor/execution.js.erb b/app/assets/javascripts/editor/execution.js.erb index 3cc9b262..2f19d69f 100644 --- a/app/assets/javascripts/editor/execution.js.erb +++ b/app/assets/javascripts/editor/execution.js.erb @@ -2,8 +2,11 @@ CodeOceanEditorWebsocket = { websocket: null, createSocketUrl: function(url) { - var rel_url_root = '<%= (defined? config.relative_url_root) && config.relative_url_root != nil && config.relative_url_root != "" ? config.relative_url_root : "" %>'; - return '<%= DockerClient.config['ws_client_protocol'] %>' + window.location.hostname + ':' + rel_url_root + window.location.port + url; + var sockURL = new URL(window.location); + sockURL.path = url; + sockURL.protocol = '<%= DockerClient.config['ws_client_protocol'] %>'; + + return sockURL.toString(); }, initializeSocket: function(url) { From 95f90def8a1ba130bde89cff4fcf6ef284e0c4fd Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Wed, 18 Jan 2017 13:51:46 +0100 Subject: [PATCH 25/26] fix previous --- app/assets/javascripts/editor/execution.js.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/editor/execution.js.erb b/app/assets/javascripts/editor/execution.js.erb index 2f19d69f..668ca81a 100644 --- a/app/assets/javascripts/editor/execution.js.erb +++ b/app/assets/javascripts/editor/execution.js.erb @@ -3,7 +3,7 @@ CodeOceanEditorWebsocket = { createSocketUrl: function(url) { var sockURL = new URL(window.location); - sockURL.path = url; + sockURL.pathname = url; sockURL.protocol = '<%= DockerClient.config['ws_client_protocol'] %>'; return sockURL.toString(); From 4badd82d58ba979d0348c4c61ca17a6639b49ff3 Mon Sep 17 00:00:00 2001 From: Tom Staubitz Date: Thu, 19 Jan 2017 14:34:49 +0100 Subject: [PATCH 26/26] fixed broken test --- app/assets/javascripts/editor/participantsupport.js.erb | 2 ++ spec/controllers/exercises_controller_spec.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/editor/participantsupport.js.erb b/app/assets/javascripts/editor/participantsupport.js.erb index 5ea4cc9e..91e9f0d1 100644 --- a/app/assets/javascripts/editor/participantsupport.js.erb +++ b/app/assets/javascripts/editor/participantsupport.js.erb @@ -59,6 +59,8 @@ CodeOceanEditorCodePilot = { } }; +//Request for comments does currently not work on staging platform (no relative root_url used here). +//To fix this rely on ruby routes CodeOceanEditorRequestForComments = { requestComments: function () { var user_id = $('#editor').data('user-id'); diff --git a/spec/controllers/exercises_controller_spec.rb b/spec/controllers/exercises_controller_spec.rb index 278f9967..43dada43 100644 --- a/spec/controllers/exercises_controller_spec.rb +++ b/spec/controllers/exercises_controller_spec.rb @@ -231,7 +231,7 @@ describe ExercisesController 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) } + 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)