merge master

This commit is contained in:
Karol
2019-12-03 17:55:58 +01:00
26 changed files with 3405 additions and 1620 deletions

30
.snyk Normal file
View File

@ -0,0 +1,30 @@
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
version: v1.13.5
ignore: {}
# patches apply the minimum changes required to fix a vulnerability
patch:
SNYK-JS-LODASH-450202:
- '@rails/webpacker > node-sass > gaze > globule > lodash':
patched: '2019-07-04T06:33:26.979Z'
- webpack-merge > lodash:
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > optimize-css-assets-webpack-plugin > last-call-webpack-plugin > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > @babel/preset-env > @babel/plugin-transform-block-scoping > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > node-sass > sass-graph > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > @babel/preset-env > @babel/plugin-proposal-unicode-property-regex > @babel/helper-regex > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > @babel/core > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > @babel/preset-env > @babel/plugin-transform-modules-commonjs > @babel/helper-module-transforms > @babel/types > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > @babel/preset-env > @babel/plugin-transform-modules-commonjs > @babel/helper-module-transforms > @babel/helper-split-export-declaration > @babel/types > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > @babel/preset-env > @babel/plugin-proposal-async-generator-functions > @babel/helper-remap-async-to-generator > @babel/helper-wrap-function > @babel/traverse > @babel/generator > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > @babel/preset-env > @babel/plugin-transform-exponentiation-operator > @babel/helper-builder-binary-assignment-operator-visitor > @babel/helper-explode-assignable-expression > @babel/traverse > @babel/helper-function-name > @babel/types > lodash':
patched: '2019-07-04T06:33:26.979Z'
- '@rails/webpacker > @babel/preset-env > @babel/plugin-transform-async-to-generator > @babel/helper-remap-async-to-generator > @babel/helper-wrap-function > @babel/traverse > @babel/helper-function-name > @babel/template > @babel/types > lodash':
patched: '2019-07-04T06:33:26.979Z'

View File

@ -2,10 +2,11 @@ sudo: required
services:
- docker
- xvfb
language: ruby
rvm:
- 2.6.2
- 2.6.3
cache:
bundler: true
yarn: true
@ -15,13 +16,13 @@ env:
- secure: "DkOGGPCrRgV08KGgav3Bl+keZQqb11TINQRVQS2aeMaYR5GW7Rt9zEcZzhUE0JdKVVOvm4Cclft7BO4OyMd6Cq9XnZkOOHY+Yn8Qv923761SKrRgkGUkO8eeVKMawAA8lS53XGrMZWCP2xaLsLQYq8xzinnE3GqstoZJaHLnqVs="
addons:
postgresql: "9.6"
firefox: "62.0.3"
postgresql: "10"
firefox: "latest-esr"
before_install:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- echo 'DOCKER_OPTS="-H tcp://127.0.0.1:2376 -H unix:///var/run/docker.sock --iptables=false"' | sudo tee /etc/default/docker > /dev/null
- sudo sed -i '/ExecStart=\/usr\/bin\/dockerd -H fd:\/\//c\ExecStart=\/usr\/bin\/dockerd' /lib/systemd/system/docker.service
- sudo systemctl daemon-reload
- "echo '{\"hosts\": [\"tcp://127.0.0.1:2376\", \"unix:///var/run/docker.sock\"], \"iptables\": false}' | sudo tee /etc/docker/daemon.json > /dev/null"
- sudo service docker restart
- sleep 5
- docker pull openhpi/co_execenv_python

View File

@ -64,6 +64,7 @@ end
group :test do
gem 'rails-controller-testing'
gem 'autotest' # required by autotest-rails
gem 'autotest-rails'
gem 'capybara'
gem 'selenium-webdriver'

View File

@ -21,7 +21,7 @@ GIT
GEM
remote: https://rubygems.org/
specs:
ZenTest (4.11.2)
ZenTest (4.12.0)
actioncable (5.2.3)
actionpack (= 5.2.3)
nio4r (~> 2.0)
@ -63,37 +63,39 @@ GEM
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
airbrussh (1.3.1)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
airbrussh (1.4.0)
sshkit (>= 1.6.1, != 1.7.0)
amq-protocol (2.3.0)
arel (9.0.0)
ast (2.4.0)
autotest (5.0.0)
minitest-autotest (~> 1.0)
autotest-rails (4.2.1)
ZenTest (~> 4.5)
bcrypt (3.1.12)
bcrypt (3.1.13)
better_errors (2.5.1)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
bindex (0.7.0)
bindex (0.8.1)
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
bootsnap (1.4.4)
bootsnap (1.4.5)
msgpack (~> 1.0)
bootstrap-will_paginate (1.0.0)
will_paginate
builder (3.2.3)
bunny (2.14.2)
bunny (2.14.3)
amq-protocol (~> 2.3, >= 2.3.0)
byebug (11.0.1)
capistrano (3.11.0)
capistrano (3.11.2)
airbrussh (>= 1.0.0)
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
capistrano-bundler (1.5.0)
capistrano-bundler (1.6.0)
capistrano (~> 3.1)
capistrano-rails (1.4.0)
capistrano (~> 3.1)
@ -103,81 +105,86 @@ GEM
sshkit (~> 1.2)
capistrano-upload-config (0.8.2)
capistrano (>= 3.0)
capistrano3-puma (3.1.1)
capistrano3-puma (4.0.0)
capistrano (~> 3.7)
capistrano-bundler
puma (~> 3.4)
capybara (3.20.2)
puma (~> 4.0)
capybara (3.29.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (~> 1.2)
regexp_parser (~> 1.5)
xpath (~> 3.2)
carrierwave (1.3.1)
activemodel (>= 4.0.0)
activesupport (>= 4.0.0)
mime-types (>= 1.16)
childprocess (1.0.1)
rake (< 13.0)
carrierwave (2.0.2)
activemodel (>= 5.0.0)
activesupport (>= 5.0.0)
addressable (~> 2.6)
image_processing (~> 1.1)
mimemagic (>= 0.3.0)
mini_mime (>= 0.1.3)
childprocess (3.0.0)
chronic (0.10.2)
coderay (1.1.2)
concurrent-ruby (1.1.5)
crass (1.0.4)
crass (1.0.5)
database_cleaner (1.7.0)
debug_inspector (0.0.3)
diff-lcs (1.3)
docile (1.3.1)
docile (1.3.2)
docker-api (1.34.2)
excon (>= 0.47.0)
multi_json
domain_name (0.5.20180417)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
erubi (1.8.0)
erubi (1.9.0)
eventmachine (1.0.9.1)
excon (0.64.0)
excon (0.69.1)
execjs (2.7.0)
factory_bot (5.0.2)
factory_bot (5.1.1)
activesupport (>= 4.2.0)
factory_bot_rails (5.0.2)
factory_bot (~> 5.0.2)
factory_bot_rails (5.1.1)
factory_bot (~> 5.1.0)
railties (>= 4.2.0)
faraday (0.15.4)
faraday (0.17.1)
multipart-post (>= 1.2, < 3)
faye-websocket (0.10.7)
faye-websocket (0.10.9)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
ffi (1.10.0)
ffi (1.11.3)
forgery (0.7.0)
globalid (0.4.2)
activesupport (>= 4.2.0)
headless (2.3.1)
highline (2.0.2)
highline (2.0.3)
http-accept (1.7.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
i18n (1.6.0)
i18n (1.7.0)
concurrent-ruby (~> 1.0)
i18n-js (3.2.2)
i18n-js (3.5.0)
i18n (>= 0.6.6)
image_processing (1.9.3)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.13, < 3)
ims-lti (1.2.2)
builder
oauth (>= 0.4.5, < 0.6)
jaro_winkler (1.5.2)
jaro_winkler (1.5.4)
jbuilder (2.9.1)
activesupport (>= 4.2.0)
jquery-rails (4.3.3)
jquery-rails (4.3.5)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (2.2.0)
jwt (2.1.0)
jwt (2.2.1)
kramdown (2.1.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
loofah (2.2.3)
listen (3.2.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.4.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
@ -185,43 +192,52 @@ GEM
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.9.2)
mime-types (3.2.2)
mime-types (3.3)
mime-types-data (~> 3.2015)
mime-types-data (3.2019.0331)
mime-types-data (3.2019.1009)
mimemagic (0.3.3)
mini_mime (1.0.1)
mini_magick (4.9.5)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.11.3)
mnemosyne-ruby (1.6.2)
minitest (5.13.0)
minitest-autotest (1.1.1)
minitest-server (~> 1.0)
path_expander (~> 1.0)
minitest-server (1.0.5)
minitest (~> 5.0)
mnemosyne-ruby (1.8.0)
activesupport (>= 4)
bunny
msgpack (1.2.10)
multi_json (1.13.1)
msgpack (1.3.1)
multi_json (1.14.1)
multi_xml (0.6.0)
multipart-post (2.1.0)
multipart-post (2.1.1)
net-scp (2.0.0)
net-ssh (>= 2.6.5, < 6.0.0)
net-ssh (5.2.0)
netrc (0.11.0)
newrelic_rpm (6.3.0.355)
nio4r (2.3.1)
nokogiri (1.10.3)
newrelic_rpm (6.7.0.359)
nio4r (2.5.2)
nokogiri (1.10.5)
mini_portile2 (~> 2.4.0)
nyan-cat-formatter (0.12.0)
rspec (>= 2.99, >= 2.14.2, < 4)
oauth (0.5.4)
oauth2 (1.4.1)
faraday (>= 0.8, < 0.16.0)
oauth2 (1.4.2)
faraday (>= 0.8, < 2.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
pagedown-bootstrap-rails (2.1.4)
railties (> 3.1)
parallel (1.17.0)
parser (2.6.3.0)
parallel (1.19.1)
parser (2.6.5.0)
ast (~> 2.4.0)
path_expander (1.1.0)
pg (1.1.4)
polyamorous (2.3.0)
activerecord (>= 5.0)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
@ -230,12 +246,13 @@ GEM
pry (~> 0.10)
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (3.0.3)
puma (3.12.1)
pundit (2.0.1)
public_suffix (4.0.1)
puma (4.3.0)
nio4r (~> 2.0)
pundit (2.1.0)
activesupport (>= 3.0.0)
rack (2.0.7)
rack-mini-profiler (1.0.2)
rack-mini-profiler (1.1.3)
rack (>= 1.2.0)
rack-proxy (0.6.5)
rack
@ -261,12 +278,12 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
rails-i18n (5.1.3)
i18n (>= 0.7, < 2)
railties (>= 5.0, < 6)
rails-timeago (2.17.1)
rails-timeago (2.18.0)
actionpack (>= 3.1)
activesupport (>= 3.1)
railties (5.2.3)
@ -276,73 +293,75 @@ GEM
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (12.3.2)
ransack (2.1.1)
rake (13.0.1)
ransack (2.3.0)
actionpack (>= 5.0)
activerecord (>= 5.0)
activesupport (>= 5.0)
i18n
polyamorous (= 2.3.0)
rb-fsevent (0.10.3)
rb-inotify (0.10.0)
ffi (~> 1.0)
regexp_parser (1.5.0)
rest-client (2.0.2)
regexp_parser (1.6.0)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec (3.9.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
rspec-mocks (~> 3.9.0)
rspec-autotest (1.0.2)
rspec-core (>= 2.99.0.beta1, < 4.0.0)
rspec-core (3.8.0)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.3)
rspec-core (3.9.0)
rspec-support (~> 3.9.0)
rspec-expectations (3.9.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.0)
rspec-support (~> 3.9.0)
rspec-mocks (3.9.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-rails (3.8.2)
rspec-support (~> 3.9.0)
rspec-rails (3.9.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.0)
rubocop (0.69.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
rspec-mocks (~> 3.9.0)
rspec-support (~> 3.9.0)
rspec-support (3.9.0)
rubocop (0.77.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.6)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
rubocop-rspec (1.33.0)
rubocop (>= 0.60.0)
ruby-progressbar (1.10.0)
ruby_dep (1.5.0)
rubocop-rspec (1.37.0)
rubocop (>= 0.68.1)
ruby-progressbar (1.10.1)
ruby-vips (2.0.16)
ffi (~> 1.9)
rubytree (1.0.0)
json (~> 2.1)
structured_warnings (~> 0.3)
rubyzip (1.2.2)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.0.7)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
selenium-webdriver (3.142.3)
childprocess (>= 0.5, < 2.0)
rubyzip (~> 1.2, >= 1.2.2)
simplecov (0.16.1)
rubyzip (2.0.0)
sass-rails (6.0.0)
sassc-rails (~> 2.1, >= 2.1.1)
sassc (2.2.1)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
selenium-webdriver (3.142.6)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
simplecov (0.17.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
@ -354,33 +373,32 @@ GEM
actionpack (>= 3.1)
railties (>= 3.1)
slim (>= 3.0, < 5.0)
sorcery (0.13.0)
sorcery (0.14.0)
bcrypt (~> 3.1)
oauth (~> 0.4, >= 0.4.4)
oauth2 (~> 1.0, >= 0.8.0)
spring (2.0.2)
activesupport (>= 4.2)
sprockets (3.7.2)
spring (2.1.0)
sprockets (4.0.0)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sshkit (1.18.2)
sshkit (1.20.0)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
structured_warnings (0.3.0)
temple (0.8.1)
structured_warnings (0.4.0)
temple (0.8.2)
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.9)
turbolinks (5.2.0)
tilt (2.0.10)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (4.1.20)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unf (0.1.4)
unf_ext
@ -391,17 +409,17 @@ GEM
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
webpacker (4.0.2)
webpacker (4.2.0)
activesupport (>= 4.2)
rack-proxy (>= 0.6.1)
railties (>= 4.2)
websocket (1.2.8)
websocket-driver (0.7.0)
websocket-driver (0.7.1)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
whenever (0.11.0)
websocket-extensions (0.1.4)
whenever (1.0.0)
chronic (>= 0.6.3)
will_paginate (3.1.7)
will_paginate (3.2.1)
xpath (3.2.0)
nokogiri (~> 1.8)
@ -409,6 +427,7 @@ PLATFORMS
ruby
DEPENDENCIES
autotest
autotest-rails
bcrypt
better_errors

View File

@ -25,6 +25,7 @@ In order to execute code submissions using Docker, source code files are written
- create *config/sendmail.yml*
- create *config/smtp.yml*
- use boot2docker or vagrant if there is no native support for docker on your OS
- if you want to use the app without docker (and hence without code execution) comment the validation `validate :working_docker_image?` in `models/execution_environments.rb` otherwise the seed will fail (because of missing docker connection)
- create seed data by executing `rake db:seed`
- if you already created a configuration for your local installation and want to use vagrant, too, be sure to log into the vagrant instance via ssh and add your database user manually to the database. Afterwards, create, migrate and seed.

View File

@ -0,0 +1,3 @@
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css

View File

@ -252,7 +252,11 @@ configureEditors: function () {
this.editors.push(editor);
this.editor_for_file.set($(element).parent().data('filename'), editor);
var session = editor.getSession();
session.setMode($(element).data('mode'));
var mode = $(element).data('mode')
session.setMode(mode);
if (mode === 'ace/mode/python') {
editor.setTheme('ace/theme/tomorrow')
}
session.setTabSize($(element).data('indent-size'));
session.setUseSoftTabs(true);
session.setUseWrapMode(true);

View File

@ -7,7 +7,7 @@ class ExercisesController < ApplicationController
before_action :handle_file_uploads, only: [:create, :update]
before_action :set_execution_environments, only: [:create, :edit, :new, :update]
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:clone, :implement, :working_times, :intervention, :search, :run, :statistics, :submit, :reload, :feedback, :study_group_dashboard, :export_external_check, :export_external_confirm]
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:clone, :implement, :working_times, :intervention, :search, :run, :statistics, :submit, :reload, :feedback, :requests_for_comments, :study_group_dashboard, :export_external_check, :export_external_confirm]
before_action :set_external_user_and_authorize, only: [:statistics]
before_action :set_file_types, only: [:create, :edit, :new, :update]
before_action :set_course_token, only: [:implement]
@ -104,6 +104,21 @@ class ExercisesController < ApplicationController
def feedback
authorize!
@feedbacks = @exercise.user_exercise_feedbacks.paginate(page: params[:page])
@submissions = @feedbacks.map do |feedback|
feedback.exercise.final_submission(feedback.user)
end
end
def requests_for_comments
authorize!
@search = RequestForComment
.with_last_activity
.where(exercise: @exercise)
.ransack(params[:q])
@request_for_comments = @search.result
.order('last_comment DESC')
.paginate(page: params[:page])
render 'request_for_comments/index'
end
def export_external_check
@ -377,6 +392,7 @@ class ExercisesController < ApplicationController
def statistics
if(@external_user)
authorize(@external_user, :statistics?)
@submissions = Submission.where("user_id = ? AND exercise_id = ?", @external_user.id, @exercise.id).order("created_at")
interventions = UserExerciseIntervention.where("user_id = ? AND exercise_id = ?", @external_user.id, @exercise.id)
@all_events = (@submissions + interventions).sort_by { |a| a.created_at }

View File

@ -20,8 +20,8 @@ class SessionsController < ApplicationController
def create_through_lti
store_lti_session_data(consumer: @consumer, parameters: params)
store_nonce(params[:oauth_nonce])
if params[:redirect_target]
redirect_to(params[:redirect_target])
if params[:custom_redirect_target]
redirect_to(params[:custom_redirect_target])
else
redirect_to(implement_exercise_path(@exercise),
notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id , @consumer.id) ? 'with' : 'without'}_outcome",

View File

@ -494,12 +494,17 @@ class Exercise < ApplicationRecord
def maximum_score(user = nil)
if user
# FIXME: where(user: user) will not work here!
submissions.where(user: user).where("cause IN ('submit','assess')").where("score IS NOT NULL").order("score DESC").first.score || 0 rescue 0
else
files.teacher_defined_tests.sum(:weight)
end
end
def final_submission(user)
submissions.final.where(user_id: user.id, user_type: user.class.name).order(created_at: :desc).first
end
def has_user_solved(user)
maximum_score(user).to_i == maximum_score.to_i
end

View File

@ -3,11 +3,11 @@ class ExercisePolicy < AdminOrAuthorPolicy
admin?
end
[:show?, :study_group_dashboard?].each do |action|
[:show?, :study_group_dashboard?, :feedback?, :requests_for_comments?, :statistics?].each do |action|
define_method(action) { admin? || teacher? }
end
[:clone?, :destroy?, :edit?, :statistics?, :update?, :feedback?, :export_external_check?, :export_external_confirm?].each do |action|
[:clone?, :destroy?, :edit?, :update?, :export_external_check?, :export_external_confirm?].each do |action|
define_method(action) { admin? || author? }
end

View File

@ -4,12 +4,17 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise))
.header = t('activerecord.attributes.exercise.description')
.value = render_markdown(@exercise.description)
.header = t('activerecord.models.user_exercise_feedback.other')
span.header.col-sm-3.pl-0 = "#{t('activerecord.attributes.exercise.maximum_score')}"
span.col-sm-9 = @exercise.maximum_score
.header.mt-3 = t('activerecord.models.user_exercise_feedback.other')
- if @feedbacks.nil? or @feedbacks.size == 0
.no-feedback = t('user_exercise_feedback.no_feedback')
ul.list-unstyled
- @feedbacks.each do |feedback|
- comment_presets = UserExerciseFeedbacksController.new.comment_presets
- time_presets = UserExerciseFeedbacksController.new.time_presets
- @feedbacks.each_with_index do |feedback, index|
li.card.mt-2
.card-header role="tab" id="heading"
div.clearfix.feedback-header
@ -20,8 +25,11 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise))
.card-collapse role="tabpanel"
.card-body.feedback
.text = feedback.feedback_text
.difficulty = "#{t('user_exercise_feedback.difficulty')} #{feedback.difficulty}" if feedback.difficulty
.worktime = "#{t('user_exercise_feedback.working_time')} #{feedback.user_estimated_worktime}" if feedback.user_estimated_worktime
.difficulty = "#{t('user_exercise_feedback.difficulty')} #{comment_presets[feedback.difficulty].join(' - ')}" if feedback.difficulty
.worktime = "#{t('user_exercise_feedback.working_time')} #{time_presets[feedback.user_estimated_worktime].join(' - ')}" if feedback.user_estimated_worktime
.card-footer
span.points = "#{t('exercises.statistics.score')}: #{@submissions[index].score}"
span.working_time.pull-right = "#{t('exercises.statistics.worktime')}: #{@exercise.average_working_time_for(feedback.user.id) or 0}"
= render('shared/pagination', collection: @feedbacks)

View File

@ -44,6 +44,7 @@ h1 = Exercise.model_name.human(count: 2)
ul.dropdown-menu.float-right role="menu"
li = link_to(t('shared.show'), exercise, 'data-turbolinks' => "false", class: 'dropdown-item') if policy(exercise).show?
li = link_to(t('activerecord.models.user_exercise_feedback.other'), feedback_exercise_path(exercise), class: 'dropdown-item') if policy(exercise).feedback?
li = link_to(t('activerecord.models.request_for_comment.other'), requests_for_comments_exercise_path(exercise), class: 'dropdown-item') if policy(exercise).requests_for_comments?
li = link_to(t('shared.destroy'), exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(exercise).destroy?
li = link_to(t('.clone'), clone_exercise_path(exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(exercise).clone?
li = link_to(t('exercises.export_codeharbor.label'), '', class: 'dropdown-item export-start', data: {'exercise-id' => exercise.id}) if policy(exercise).export_external_confirm?

View File

@ -38,18 +38,19 @@ h1 = @exercise
hr
div#chart_2
hr
.table-responsive
table.table.table-striped.sortable
thead
tr
- ['.user', '.score', '.runs', '.worktime'].each do |title|
th.header = t(title)
tbody
- @exercise.send(symbol).distinct().each do |user|
- if user_statistics[user.id] then us = user_statistics[user.id] else us = {"maximum_score" => nil, "runs" => nil}
- label = "#{user.displayname}"
- if current_user.admin?
.table-responsive
table.table.table-striped.sortable
thead
tr
td = link_to_if symbol==:external_users && policy(user).statistics?, label, {controller: "exercises", action: "statistics", external_user_id: user.id, id: @exercise.id}
td = us['maximum_score'] or 0
td = us['runs']
td = @exercise.average_working_time_for(user.id) or 0
- ['.user', '.score', '.runs', '.worktime'].each do |title|
th.header = t(title)
tbody
- @exercise.send(symbol).distinct().each do |user|
- if user_statistics[user.id] then us = user_statistics[user.id] else us = {"maximum_score" => nil, "runs" => nil}
- label = "#{user.displayname}"
tr
td = link_to_if symbol==:external_users && policy(user).statistics?, label, {controller: "exercises", action: "statistics", external_user_id: user.id, id: @exercise.id}
td = us['maximum_score'] or 0
td = us['runs']
td = @exercise.average_working_time_for(user.id) or 0

View File

@ -353,6 +353,7 @@ de:
implement: Implementieren
test_files: Test-Dateien
feedback: Feedback
requests_for_comments: Kommentaranfragen
study_group_dashboard: Live Dashboard
statistics:
average_score: Durchschnittliche Punktzahl

View File

@ -398,6 +398,7 @@ en:
implement: Implement
test_files: Test Files
feedback: Feedback
requests_for_comments: Requests for Comments
study_group_dashboard: Live Dashboard
show:
is_unpublished: Exercise is unpublished

View File

@ -82,6 +82,7 @@ Rails.application.routes.draw do
post :search
get :statistics
get :feedback
get :requests_for_comments
get :reload
post :submit
get 'study_group_dashboard/:study_group_id', to: 'exercises#study_group_dashboard'

View File

@ -18,7 +18,7 @@ end
# delete all present records
Rails.application.eager_load!
(ApplicationRecord.descendants - [ActiveRecord::SchemaMigration]).each(&:delete_all)
(ApplicationRecord.descendants - [ActiveRecord::SchemaMigration, User]).each(&:delete_all)
# delete file uploads
FileUtils.rm_rf(Rails.root.join('public', 'uploads'))

View File

@ -13,6 +13,7 @@
"jstree": "^3.3.8",
"opensans-webkit": "^1.0.1",
"popper.js": "^1.15.0",
"snyk": "^1.189.0",
"underscore": "^1.9.1",
"vis": "^4.21.0",
"webpack-merge": "^4.1.4"
@ -22,6 +23,9 @@
},
"scripts": {
"webpack": "./bin/webpack",
"webpack-dev-server": "./bin/webpack-dev-server"
}
"webpack-dev-server": "./bin/webpack-dev-server",
"snyk-protect": "snyk protect",
"prepublish": "npm run snyk-protect"
},
"snyk": true
}

View File

@ -5,9 +5,9 @@
######## VERSION INFORMATION ########
postgres_version=10
ruby_version=2.6.2
ruby_version=2.6.3
rails_version=5.2.3
geckodriver_version=0.24.0
geckodriver_version=0.26.0
########## INSTALL SCRIPT ###########

18
spec/db/seeds_spec.rb Normal file
View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'seeds' do
subject(:seed) { Rake::Task['db:seed'].invoke }
before do
CodeOcean::Application.load_tasks
allow(Rails).to receive(:env) { 'development'.inquiry }
end
describe 'execute db:seed' do
it 'collects the test results' do
expect { seed }.not_to raise_error(StandardError)
end
end
end

View File

@ -1,6 +1,7 @@
require 'rails_helper'
describe 'Authentication' do
before { skip 'feature specs fail randomly as of Nov 2019 on Travis' }
let(:user) { FactoryBot.create(:admin) }
let(:password) { FactoryBot.attributes_for(:admin)[:password] }

View File

@ -1,6 +1,7 @@
require 'rails_helper'
describe 'Authorization' do
before { skip 'feature specs fail randomly as of Nov 2019 on Travis' }
context 'as an admin' do
let(:user) { FactoryBot.create(:admin) }
before(:each) { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) }

View File

@ -1,6 +1,7 @@
require 'rails_helper'
describe 'Editor', js: true do
before { skip 'feature specs fail randomly as of Nov 2019 on Travis' }
let(:exercise) { FactoryBot.create(:audio_video, description: Forgery(:lorem_ipsum).sentence) }
let(:user) { FactoryBot.create(:teacher) }

View File

@ -14,7 +14,7 @@ let(:exercise) { FactoryBot.build(:dummy) }
end
end
[:create?, :index?, :new?].each do |action|
[:create?, :index?, :new?, :statistics?, :feedback?, :requests_for_comments?].each do |action|
permissions(action) do
it 'grants access to admins' do
expect(subject).to permit(FactoryBot.build(:admin), exercise)
@ -30,7 +30,7 @@ let(:exercise) { FactoryBot.build(:dummy) }
end
end
[:clone?, :destroy?, :edit?, :statistics?, :update?].each do |action|
[:clone?, :destroy?, :edit?, :update?].each do |action|
permissions(action) do
it 'grants access to admins' do
expect(subject).to permit(FactoryBot.build(:admin), exercise)

4593
yarn.lock

File diff suppressed because it is too large Load Diff