Merge remote-tracking branch 'origin/master' into statistics
This commit is contained in:
1
Gemfile
1
Gemfile
@ -35,6 +35,7 @@ gem 'uglifier', '>= 1.3.0'
|
|||||||
gem 'will_paginate', '~> 3.0'
|
gem 'will_paginate', '~> 3.0'
|
||||||
gem 'tubesock'
|
gem 'tubesock'
|
||||||
gem 'faye-websocket'
|
gem 'faye-websocket'
|
||||||
|
gem 'nokogiri'
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'better_errors', platform: :ruby
|
gem 'better_errors', platform: :ruby
|
||||||
|
248
Gemfile.lock
248
Gemfile.lock
@ -2,41 +2,40 @@ GEM
|
|||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
ZenTest (4.11.0)
|
ZenTest (4.11.0)
|
||||||
actionmailer (4.1.14)
|
actionmailer (4.1.14.1)
|
||||||
actionpack (= 4.1.14)
|
actionpack (= 4.1.14.1)
|
||||||
actionview (= 4.1.14)
|
actionview (= 4.1.14.1)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
actionpack (4.1.14)
|
actionpack (4.1.14.1)
|
||||||
actionview (= 4.1.14)
|
actionview (= 4.1.14.1)
|
||||||
activesupport (= 4.1.14)
|
activesupport (= 4.1.14.1)
|
||||||
rack (~> 1.5.2)
|
rack (~> 1.5.2)
|
||||||
rack-test (~> 0.6.2)
|
rack-test (~> 0.6.2)
|
||||||
actionview (4.1.14)
|
actionview (4.1.14.1)
|
||||||
activesupport (= 4.1.14)
|
activesupport (= 4.1.14.1)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubis (~> 2.7.0)
|
erubis (~> 2.7.0)
|
||||||
activemodel (4.1.14)
|
activemodel (4.1.14.1)
|
||||||
activesupport (= 4.1.14)
|
activesupport (= 4.1.14.1)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
activerecord (4.1.14)
|
activerecord (4.1.14.1)
|
||||||
activemodel (= 4.1.14)
|
activemodel (= 4.1.14.1)
|
||||||
activesupport (= 4.1.14)
|
activesupport (= 4.1.14.1)
|
||||||
arel (~> 5.0.0)
|
arel (~> 5.0.0)
|
||||||
activerecord-jdbc-adapter (1.3.15)
|
activerecord-jdbc-adapter (1.3.19)
|
||||||
activerecord (>= 2.2)
|
activerecord (>= 2.2)
|
||||||
activerecord-jdbcpostgresql-adapter (1.3.15)
|
activerecord-jdbcpostgresql-adapter (1.3.19)
|
||||||
activerecord-jdbc-adapter (~> 1.3.15)
|
activerecord-jdbc-adapter (~> 1.3.19)
|
||||||
jdbc-postgres (>= 9.1)
|
jdbc-postgres (>= 9.1)
|
||||||
activesupport (4.1.14)
|
activesupport (4.1.14.1)
|
||||||
i18n (~> 0.6, >= 0.6.9)
|
i18n (~> 0.6, >= 0.6.9)
|
||||||
json (~> 1.7, >= 1.7.7)
|
json (~> 1.7, >= 1.7.7)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
|
addressable (2.4.0)
|
||||||
arel (5.0.1.20140414130214)
|
arel (5.0.1.20140414130214)
|
||||||
ast (2.0.0)
|
ast (2.2.0)
|
||||||
astrolabe (1.3.0)
|
|
||||||
parser (>= 2.2.0.pre.3, < 3.0)
|
|
||||||
autotest-rails (4.2.1)
|
autotest-rails (4.2.1)
|
||||||
ZenTest (~> 4.5)
|
ZenTest (~> 4.5)
|
||||||
bcrypt (3.1.10)
|
bcrypt (3.1.10)
|
||||||
@ -50,7 +49,7 @@ GEM
|
|||||||
bootstrap-will_paginate (0.0.10)
|
bootstrap-will_paginate (0.0.10)
|
||||||
will_paginate
|
will_paginate
|
||||||
builder (3.2.2)
|
builder (3.2.2)
|
||||||
byebug (6.0.2)
|
byebug (8.2.2)
|
||||||
capistrano (3.3.5)
|
capistrano (3.3.5)
|
||||||
capistrano-stats (~> 1.1.0)
|
capistrano-stats (~> 1.1.0)
|
||||||
i18n
|
i18n
|
||||||
@ -59,19 +58,20 @@ GEM
|
|||||||
capistrano-bundler (1.1.4)
|
capistrano-bundler (1.1.4)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
sshkit (~> 1.2)
|
sshkit (~> 1.2)
|
||||||
capistrano-rails (1.1.2)
|
capistrano-rails (1.1.6)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
capistrano-bundler (~> 1.1)
|
capistrano-bundler (~> 1.1)
|
||||||
capistrano-rvm (0.1.2)
|
capistrano-rvm (0.1.2)
|
||||||
capistrano (~> 3.0)
|
capistrano (~> 3.0)
|
||||||
sshkit (~> 1.2)
|
sshkit (~> 1.2)
|
||||||
capistrano-stats (1.1.1)
|
capistrano-stats (1.1.1)
|
||||||
capistrano-upload-config (0.6.0)
|
capistrano-upload-config (0.7.0)
|
||||||
capistrano (>= 3.0)
|
capistrano (>= 3.0)
|
||||||
capistrano3-puma (0.9.0)
|
capistrano3-puma (1.2.1)
|
||||||
capistrano (~> 3.0)
|
capistrano (~> 3.0)
|
||||||
puma (>= 2.6)
|
puma (>= 2.6)
|
||||||
capybara (2.4.4)
|
capybara (2.6.2)
|
||||||
|
addressable
|
||||||
mime-types (>= 1.16)
|
mime-types (>= 1.16)
|
||||||
nokogiri (>= 1.3.3)
|
nokogiri (>= 1.3.3)
|
||||||
rack (>= 1.0.0)
|
rack (>= 1.0.0)
|
||||||
@ -82,9 +82,9 @@ GEM
|
|||||||
activesupport (>= 3.2.0)
|
activesupport (>= 3.2.0)
|
||||||
json (>= 1.7)
|
json (>= 1.7)
|
||||||
mime-types (>= 1.16)
|
mime-types (>= 1.16)
|
||||||
childprocess (0.5.6)
|
childprocess (0.5.9)
|
||||||
ffi (~> 1.0, >= 1.0.11)
|
ffi (~> 1.0, >= 1.0.11)
|
||||||
codeclimate-test-reporter (0.4.7)
|
codeclimate-test-reporter (0.4.8)
|
||||||
simplecov (>= 0.7.1, < 1.0.0)
|
simplecov (>= 0.7.1, < 1.0.0)
|
||||||
coderay (1.1.0)
|
coderay (1.1.0)
|
||||||
coffee-rails (4.0.1)
|
coffee-rails (4.0.1)
|
||||||
@ -93,13 +93,12 @@ GEM
|
|||||||
coffee-script (2.4.1)
|
coffee-script (2.4.1)
|
||||||
coffee-script-source
|
coffee-script-source
|
||||||
execjs
|
execjs
|
||||||
coffee-script-source (1.9.1)
|
coffee-script-source (1.10.0)
|
||||||
colorize (0.7.7)
|
|
||||||
concurrent-ruby (1.0.0)
|
concurrent-ruby (1.0.0)
|
||||||
concurrent-ruby (1.0.0-java)
|
concurrent-ruby (1.0.0-java)
|
||||||
concurrent-ruby-ext (1.0.0)
|
concurrent-ruby-ext (1.0.0)
|
||||||
concurrent-ruby (~> 1.0.0)
|
concurrent-ruby (~> 1.0.0)
|
||||||
database_cleaner (1.4.1)
|
database_cleaner (1.5.1)
|
||||||
debug_inspector (0.0.2)
|
debug_inspector (0.0.2)
|
||||||
diff-lcs (1.2.5)
|
diff-lcs (1.2.5)
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
@ -107,34 +106,34 @@ GEM
|
|||||||
excon (>= 0.38.0)
|
excon (>= 0.38.0)
|
||||||
json
|
json
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
eventmachine (1.0.8)
|
eventmachine (1.0.9.1)
|
||||||
eventmachine (1.0.8-java)
|
eventmachine (1.0.9.1-java)
|
||||||
excon (0.45.4)
|
excon (0.45.4)
|
||||||
execjs (2.5.2)
|
execjs (2.6.0)
|
||||||
factory_girl (4.5.0)
|
factory_girl (4.5.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
factory_girl_rails (4.5.0)
|
factory_girl_rails (4.6.0)
|
||||||
factory_girl (~> 4.5.0)
|
factory_girl (~> 4.5.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
faraday (0.9.1)
|
faraday (0.9.2)
|
||||||
multipart-post (>= 1.2, < 3)
|
multipart-post (>= 1.2, < 3)
|
||||||
faye-websocket (0.10.0)
|
faye-websocket (0.10.2)
|
||||||
eventmachine (>= 0.12.0)
|
eventmachine (>= 0.12.0)
|
||||||
websocket-driver (>= 0.5.1)
|
websocket-driver (>= 0.5.1)
|
||||||
ffi (1.9.8)
|
ffi (1.9.10)
|
||||||
ffi (1.9.8-java)
|
ffi (1.9.10-java)
|
||||||
forgery (0.6.0)
|
forgery (0.6.0)
|
||||||
highline (1.7.1)
|
highline (1.7.8)
|
||||||
hike (1.2.3)
|
hike (1.2.3)
|
||||||
i18n (0.7.0)
|
i18n (0.7.0)
|
||||||
ims-lti (1.1.8)
|
ims-lti (1.1.10)
|
||||||
builder
|
builder
|
||||||
oauth (~> 0.4.5)
|
oauth (~> 0.4.5)
|
||||||
jbuilder (2.2.13)
|
jbuilder (2.4.1)
|
||||||
activesupport (>= 3.0.0, < 5)
|
activesupport (>= 3.0.0, < 5.1)
|
||||||
multi_json (~> 1.2)
|
multi_json (~> 1.2)
|
||||||
jdbc-postgres (9.4.1200)
|
jdbc-postgres (9.4.1206)
|
||||||
jquery-rails (3.1.2)
|
jquery-rails (3.1.4)
|
||||||
railties (>= 3.0, < 5.0)
|
railties (>= 3.0, < 5.0)
|
||||||
thor (>= 0.14, < 2.0)
|
thor (>= 0.14, < 2.0)
|
||||||
jquery-turbolinks (2.1.0)
|
jquery-turbolinks (2.1.0)
|
||||||
@ -142,115 +141,117 @@ GEM
|
|||||||
turbolinks
|
turbolinks
|
||||||
json (1.8.3)
|
json (1.8.3)
|
||||||
json (1.8.3-java)
|
json (1.8.3-java)
|
||||||
jwt (1.4.1)
|
jwt (1.5.1)
|
||||||
kramdown (1.6.0)
|
kramdown (1.9.0)
|
||||||
mail (2.6.3)
|
mail (2.6.3)
|
||||||
mime-types (>= 1.16, < 3)
|
mime-types (>= 1.16, < 3)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (2.99)
|
mime-types (2.99)
|
||||||
mini_portile (0.6.2)
|
mini_portile2 (2.0.0)
|
||||||
minitest (5.8.3)
|
minitest (5.8.4)
|
||||||
multi_json (1.11.2)
|
multi_json (1.11.2)
|
||||||
multi_xml (0.5.5)
|
multi_xml (0.5.5)
|
||||||
multipart-post (2.0.0)
|
multipart-post (2.0.0)
|
||||||
net-scp (1.2.1)
|
net-scp (1.2.1)
|
||||||
net-ssh (>= 2.6.5)
|
net-ssh (>= 2.6.5)
|
||||||
net-ssh (2.9.2)
|
net-ssh (3.0.2)
|
||||||
newrelic_rpm (3.11.2.286)
|
newrelic_rpm (3.14.3.313)
|
||||||
nokogiri (1.6.6.2)
|
nokogiri (1.6.7.2)
|
||||||
mini_portile (~> 0.6.0)
|
mini_portile2 (~> 2.0.0.rc2)
|
||||||
nokogiri (1.6.6.2-java)
|
nokogiri (1.6.7.2-java)
|
||||||
nyan-cat-formatter (0.11)
|
nyan-cat-formatter (0.11)
|
||||||
rspec (>= 2.99, >= 2.14.2, < 4)
|
rspec (>= 2.99, >= 2.14.2, < 4)
|
||||||
oauth (0.4.7)
|
oauth (0.4.7)
|
||||||
oauth2 (1.0.0)
|
oauth2 (1.1.0)
|
||||||
faraday (>= 0.8, < 0.10)
|
faraday (>= 0.8, < 0.10)
|
||||||
jwt (~> 1.0)
|
jwt (~> 1.0, < 1.5.2)
|
||||||
multi_json (~> 1.3)
|
multi_json (~> 1.3)
|
||||||
multi_xml (~> 0.5)
|
multi_xml (~> 0.5)
|
||||||
rack (~> 1.2)
|
rack (>= 1.2, < 3)
|
||||||
parser (2.2.0.3)
|
parser (2.3.0.6)
|
||||||
ast (>= 1.1, < 3.0)
|
ast (~> 2.2)
|
||||||
pg (0.18.1)
|
pg (0.18.4)
|
||||||
polyamorous (1.2.0)
|
polyamorous (1.3.0)
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
powerpack (0.1.0)
|
powerpack (0.1.1)
|
||||||
pry (0.10.1)
|
pry (0.10.3)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8.1)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
slop (~> 3.4)
|
||||||
pry (0.10.1-java)
|
pry (0.10.3-java)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8.1)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
slop (~> 3.4)
|
||||||
spoon (~> 0.0)
|
spoon (~> 0.0)
|
||||||
puma (2.15.3)
|
puma (2.15.3)
|
||||||
puma (2.15.3-java)
|
puma (2.15.3-java)
|
||||||
pundit (0.3.0)
|
pundit (1.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
rack (1.5.5)
|
rack (1.5.5)
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rails (4.1.14)
|
rails (4.1.14.1)
|
||||||
actionmailer (= 4.1.14)
|
actionmailer (= 4.1.14.1)
|
||||||
actionpack (= 4.1.14)
|
actionpack (= 4.1.14.1)
|
||||||
actionview (= 4.1.14)
|
actionview (= 4.1.14.1)
|
||||||
activemodel (= 4.1.14)
|
activemodel (= 4.1.14.1)
|
||||||
activerecord (= 4.1.14)
|
activerecord (= 4.1.14.1)
|
||||||
activesupport (= 4.1.14)
|
activesupport (= 4.1.14.1)
|
||||||
bundler (>= 1.3.0, < 2.0)
|
bundler (>= 1.3.0, < 2.0)
|
||||||
railties (= 4.1.14)
|
railties (= 4.1.14.1)
|
||||||
sprockets-rails (~> 2.0)
|
sprockets-rails (~> 2.0)
|
||||||
rails-i18n (4.0.4)
|
rails-i18n (4.0.8)
|
||||||
i18n (~> 0.6)
|
i18n (~> 0.7)
|
||||||
railties (~> 4.0)
|
railties (~> 4.0)
|
||||||
railties (4.1.14)
|
railties (4.1.14.1)
|
||||||
actionpack (= 4.1.14)
|
actionpack (= 4.1.14.1)
|
||||||
activesupport (= 4.1.14)
|
activesupport (= 4.1.14.1)
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rainbow (2.0.0)
|
rainbow (2.1.0)
|
||||||
rake (10.4.2)
|
rake (10.5.0)
|
||||||
ransack (1.6.6)
|
ransack (1.7.0)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
i18n
|
i18n
|
||||||
polyamorous (~> 1.2)
|
polyamorous (~> 1.2)
|
||||||
rdoc (4.2.0)
|
rdoc (4.2.2)
|
||||||
rspec (3.1.0)
|
json (~> 1.4)
|
||||||
rspec-core (~> 3.1.0)
|
rspec (3.4.0)
|
||||||
rspec-expectations (~> 3.1.0)
|
rspec-core (~> 3.4.0)
|
||||||
rspec-mocks (~> 3.1.0)
|
rspec-expectations (~> 3.4.0)
|
||||||
|
rspec-mocks (~> 3.4.0)
|
||||||
rspec-autotest (1.0.0)
|
rspec-autotest (1.0.0)
|
||||||
rspec-core (>= 2.99.0.beta1, < 4.0.0)
|
rspec-core (>= 2.99.0.beta1, < 4.0.0)
|
||||||
rspec-core (3.1.7)
|
rspec-core (3.4.2)
|
||||||
rspec-support (~> 3.1.0)
|
rspec-support (~> 3.4.0)
|
||||||
rspec-expectations (3.1.2)
|
rspec-expectations (3.4.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.1.0)
|
rspec-support (~> 3.4.0)
|
||||||
rspec-mocks (3.1.3)
|
rspec-mocks (3.4.1)
|
||||||
rspec-support (~> 3.1.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-rails (3.1.0)
|
rspec-support (~> 3.4.0)
|
||||||
actionpack (>= 3.0)
|
rspec-rails (3.4.2)
|
||||||
activesupport (>= 3.0)
|
actionpack (>= 3.0, < 4.3)
|
||||||
railties (>= 3.0)
|
activesupport (>= 3.0, < 4.3)
|
||||||
rspec-core (~> 3.1.0)
|
railties (>= 3.0, < 4.3)
|
||||||
rspec-expectations (~> 3.1.0)
|
rspec-core (~> 3.4.0)
|
||||||
rspec-mocks (~> 3.1.0)
|
rspec-expectations (~> 3.4.0)
|
||||||
rspec-support (~> 3.1.0)
|
rspec-mocks (~> 3.4.0)
|
||||||
rspec-support (3.1.2)
|
rspec-support (~> 3.4.0)
|
||||||
rubocop (0.30.0)
|
rspec-support (3.4.1)
|
||||||
astrolabe (~> 1.3)
|
rubocop (0.37.2)
|
||||||
parser (>= 2.2.0.1, < 3.0)
|
parser (>= 2.3.0.4, < 3.0)
|
||||||
powerpack (~> 0.1)
|
powerpack (~> 0.1)
|
||||||
rainbow (>= 1.99.1, < 3.0)
|
rainbow (>= 1.99.1, < 3.0)
|
||||||
ruby-progressbar (~> 1.4)
|
ruby-progressbar (~> 1.7)
|
||||||
rubocop-rspec (1.2.2)
|
unicode-display_width (~> 0.3)
|
||||||
|
rubocop-rspec (1.4.0)
|
||||||
ruby-progressbar (1.7.5)
|
ruby-progressbar (1.7.5)
|
||||||
rubytree (0.9.4)
|
rubytree (0.9.7)
|
||||||
json (~> 1.8)
|
json (~> 1.8)
|
||||||
structured_warnings (~> 0.1)
|
structured_warnings (~> 0.2)
|
||||||
rubyzip (1.1.7)
|
rubyzip (1.1.7)
|
||||||
sass (3.2.19)
|
sass (3.2.19)
|
||||||
sass-rails (4.0.5)
|
sass-rails (4.0.5)
|
||||||
@ -261,17 +262,17 @@ GEM
|
|||||||
sdoc (0.4.1)
|
sdoc (0.4.1)
|
||||||
json (~> 1.7, >= 1.7.7)
|
json (~> 1.7, >= 1.7.7)
|
||||||
rdoc (~> 4.0)
|
rdoc (~> 4.0)
|
||||||
selenium-webdriver (2.45.0)
|
selenium-webdriver (2.52.0)
|
||||||
childprocess (~> 0.5)
|
childprocess (~> 0.5)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
rubyzip (~> 1.0)
|
rubyzip (~> 1.0)
|
||||||
websocket (~> 1.0)
|
websocket (~> 1.0)
|
||||||
simplecov (0.9.2)
|
simplecov (0.11.2)
|
||||||
docile (~> 1.1.0)
|
docile (~> 1.1.0)
|
||||||
multi_json (~> 1.0)
|
json (~> 1.8)
|
||||||
simplecov-html (~> 0.9.0)
|
simplecov-html (~> 0.10.0)
|
||||||
simplecov-html (0.9.0)
|
simplecov-html (0.10.0)
|
||||||
slim (3.0.3)
|
slim (3.0.6)
|
||||||
temple (~> 0.7.3)
|
temple (~> 0.7.3)
|
||||||
tilt (>= 1.3.3, < 2.1)
|
tilt (>= 1.3.3, < 2.1)
|
||||||
slop (3.6.0)
|
slop (3.6.0)
|
||||||
@ -281,7 +282,7 @@ GEM
|
|||||||
oauth2 (>= 0.8.0)
|
oauth2 (>= 0.8.0)
|
||||||
spoon (0.0.4)
|
spoon (0.0.4)
|
||||||
ffi
|
ffi
|
||||||
spring (1.3.4)
|
spring (1.6.3)
|
||||||
sprockets (2.12.4)
|
sprockets (2.12.4)
|
||||||
hike (~> 1.2)
|
hike (~> 1.2)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
@ -291,12 +292,11 @@ GEM
|
|||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
sprockets (>= 2.8, < 4.0)
|
sprockets (>= 2.8, < 4.0)
|
||||||
sshkit (1.7.1)
|
sshkit (1.8.1)
|
||||||
colorize (>= 0.7.0)
|
|
||||||
net-scp (>= 1.1.2)
|
net-scp (>= 1.1.2)
|
||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
structured_warnings (0.2.0)
|
structured_warnings (0.2.0)
|
||||||
temple (0.7.5)
|
temple (0.7.6)
|
||||||
thor (0.19.1)
|
thor (0.19.1)
|
||||||
thread_safe (0.3.5)
|
thread_safe (0.3.5)
|
||||||
thread_safe (0.3.5-java)
|
thread_safe (0.3.5-java)
|
||||||
@ -308,21 +308,22 @@ GEM
|
|||||||
coffee-rails
|
coffee-rails
|
||||||
tzinfo (1.2.2)
|
tzinfo (1.2.2)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
uglifier (2.7.1)
|
uglifier (2.7.2)
|
||||||
execjs (>= 0.3.0)
|
execjs (>= 0.3.0)
|
||||||
json (>= 1.8.0)
|
json (>= 1.8.0)
|
||||||
web-console (2.1.2)
|
unicode-display_width (0.3.1)
|
||||||
|
web-console (2.3.0)
|
||||||
activemodel (>= 4.0)
|
activemodel (>= 4.0)
|
||||||
binding_of_caller (>= 0.7.2)
|
binding_of_caller (>= 0.7.2)
|
||||||
railties (>= 4.0)
|
railties (>= 4.0)
|
||||||
sprockets-rails (>= 2.0, < 4.0)
|
sprockets-rails (>= 2.0, < 4.0)
|
||||||
websocket (1.2.1)
|
websocket (1.2.2)
|
||||||
websocket-driver (0.6.2)
|
websocket-driver (0.6.3)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-driver (0.6.2-java)
|
websocket-driver (0.6.3-java)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.2)
|
websocket-extensions (0.1.2)
|
||||||
will_paginate (3.0.7)
|
will_paginate (3.1.0)
|
||||||
xpath (2.0.0)
|
xpath (2.0.0)
|
||||||
nokogiri (~> 1.3)
|
nokogiri (~> 1.3)
|
||||||
|
|
||||||
@ -361,6 +362,7 @@ DEPENDENCIES
|
|||||||
jquery-turbolinks
|
jquery-turbolinks
|
||||||
kramdown
|
kramdown
|
||||||
newrelic_rpm
|
newrelic_rpm
|
||||||
|
nokogiri
|
||||||
nyan-cat-formatter
|
nyan-cat-formatter
|
||||||
pg
|
pg
|
||||||
pry
|
pry
|
||||||
|
@ -30,7 +30,7 @@ $(function() {
|
|||||||
numMessages = 0,
|
numMessages = 0,
|
||||||
turtlecanvas = $('#turtlecanvas'),
|
turtlecanvas = $('#turtlecanvas'),
|
||||||
prompt = $('#prompt'),
|
prompt = $('#prompt'),
|
||||||
commands = ['input', 'write', 'turtle', 'turtlebatch', 'exit', 'timeout', 'status'],
|
commands = ['input', 'write', 'turtle', 'turtlebatch', 'render', 'exit', 'timeout', 'status'],
|
||||||
streams = ['stdin', 'stdout', 'stderr'];
|
streams = ['stdin', 'stdout', 'stderr'];
|
||||||
|
|
||||||
var ENTER_KEY_CODE = 13;
|
var ENTER_KEY_CODE = 13;
|
||||||
@ -245,6 +245,18 @@ $(function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var findOrCreateRenderElement = function(index) {
|
||||||
|
if ($('#render-' + index).isPresent()) {
|
||||||
|
return $('#render-' + index);
|
||||||
|
} else {
|
||||||
|
var element = $('<div>').attr('id', 'render-' + index);
|
||||||
|
$('#render').append(element);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var getPanelClass = function(result) {
|
var getPanelClass = function(result) {
|
||||||
if (result.stderr && !result.score) {
|
if (result.stderr && !result.score) {
|
||||||
return 'panel-danger';
|
return 'panel-danger';
|
||||||
@ -1172,6 +1184,9 @@ $(function() {
|
|||||||
showCanvas();
|
showCanvas();
|
||||||
handleTurtlebatchCommand(msg);
|
handleTurtlebatchCommand(msg);
|
||||||
break;
|
break;
|
||||||
|
case 'render':
|
||||||
|
renderWebsocketOutput(msg);
|
||||||
|
break;
|
||||||
case 'exit':
|
case 'exit':
|
||||||
killWebsocketAndContainer();
|
killWebsocketAndContainer();
|
||||||
break;
|
break;
|
||||||
@ -1185,6 +1200,11 @@ $(function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var renderWebsocketOutput = function(msg){
|
||||||
|
var element = findOrCreateRenderElement(0);
|
||||||
|
element.append(msg.data);
|
||||||
|
};
|
||||||
|
|
||||||
var printWebsocketOutput = function(msg) {
|
var printWebsocketOutput = function(msg) {
|
||||||
if (!msg.data) {
|
if (!msg.data) {
|
||||||
return;
|
return;
|
||||||
|
3
app/assets/stylesheets/code_harbor_links.css.scss
Normal file
3
app/assets/stylesheets/code_harbor_links.css.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// Place all the styles related to the CodeHarborLinks controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
69
app/assets/stylesheets/scaffolds.css.scss
Normal file
69
app/assets/stylesheets/scaffolds.css.scss
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
body {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #333;
|
||||||
|
font-family: verdana, arial, helvetica, sans-serif;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, ol, ul, td {
|
||||||
|
font-family: verdana, arial, helvetica, sans-serif;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background-color: #eee;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #000;
|
||||||
|
&:visited {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
&.field, &.actions {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#notice {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field_with_errors {
|
||||||
|
padding: 2px;
|
||||||
|
background-color: red;
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error_explanation {
|
||||||
|
width: 450px;
|
||||||
|
border: 2px solid red;
|
||||||
|
padding: 7px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
h2 {
|
||||||
|
text-align: left;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px 5px 5px 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: -7px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
background-color: #c00;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
ul li {
|
||||||
|
font-size: 12px;
|
||||||
|
list-style: square;
|
||||||
|
}
|
||||||
|
}
|
68
app/controllers/code_harbor_links_controller.rb
Normal file
68
app/controllers/code_harbor_links_controller.rb
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
class CodeHarborLinksController < ApplicationController
|
||||||
|
include CommonBehavior
|
||||||
|
before_action :set_code_harbor_link, only: [:show, :edit, :update, :destroy]
|
||||||
|
|
||||||
|
def authorize!
|
||||||
|
authorize(@code_harbor_link || @code_harbor_links)
|
||||||
|
end
|
||||||
|
private :authorize!
|
||||||
|
|
||||||
|
# GET /code_harbor_links
|
||||||
|
# GET /code_harbor_links.json
|
||||||
|
def index
|
||||||
|
@code_harbor_links = CodeHarborLink.where(user_id: current_user.id).paginate(page: params[:page])
|
||||||
|
authorize!
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /code_harbor_links/1
|
||||||
|
# GET /code_harbor_links/1.json
|
||||||
|
def show
|
||||||
|
authorize!
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /code_harbor_links/new
|
||||||
|
def new
|
||||||
|
@code_harbor_link = CodeHarborLink.new
|
||||||
|
authorize!
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /code_harbor_links/1/edit
|
||||||
|
def edit
|
||||||
|
authorize!
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /code_harbor_links
|
||||||
|
# POST /code_harbor_links.json
|
||||||
|
def create
|
||||||
|
@code_harbor_link = CodeHarborLink.new(code_harbor_link_params)
|
||||||
|
@code_harbor_link.user = current_user
|
||||||
|
authorize!
|
||||||
|
create_and_respond(object: @code_harbor_link)
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH/PUT /code_harbor_links/1
|
||||||
|
# PATCH/PUT /code_harbor_links/1.json
|
||||||
|
def update
|
||||||
|
update_and_respond(object: @code_harbor_link, params: code_harbor_link_params)
|
||||||
|
authorize!
|
||||||
|
end
|
||||||
|
|
||||||
|
# DELETE /code_harbor_links/1
|
||||||
|
# DELETE /code_harbor_links/1.json
|
||||||
|
def destroy
|
||||||
|
destroy_and_respond(object: @code_harbor_link)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
|
def set_code_harbor_link
|
||||||
|
@code_harbor_link = CodeHarborLink.find(params[:id])
|
||||||
|
@code_harbor_link.user = current_user
|
||||||
|
authorize!
|
||||||
|
end
|
||||||
|
|
||||||
|
# Never trust parameters from the scary internet, only allow the white list through.
|
||||||
|
def code_harbor_link_params
|
||||||
|
params.require(:code_harbor_link).permit(:oauth2token)
|
||||||
|
end
|
||||||
|
end
|
@ -11,6 +11,10 @@ class ExercisesController < ApplicationController
|
|||||||
before_action :set_file_types, only: [:create, :edit, :new, :update]
|
before_action :set_file_types, only: [:create, :edit, :new, :update]
|
||||||
before_action :set_teams, only: [:create, :edit, :new, :update]
|
before_action :set_teams, only: [:create, :edit, :new, :update]
|
||||||
|
|
||||||
|
skip_before_filter :verify_authenticity_token, only: [:import_proforma_xml]
|
||||||
|
skip_after_action :verify_authorized, only: [:import_proforma_xml]
|
||||||
|
skip_after_action :verify_policy_scoped, only: [:import_proforma_xml]
|
||||||
|
|
||||||
def authorize!
|
def authorize!
|
||||||
authorize(@exercise || @exercises)
|
authorize(@exercise || @exercises)
|
||||||
end
|
end
|
||||||
@ -62,6 +66,58 @@ class ExercisesController < ApplicationController
|
|||||||
def edit
|
def edit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def import_proforma_xml
|
||||||
|
begin
|
||||||
|
user = user_for_oauth2_request()
|
||||||
|
exercise = Exercise.new
|
||||||
|
request_body = request.body.read
|
||||||
|
exercise.from_proforma_xml(request_body)
|
||||||
|
exercise.user = user
|
||||||
|
saved = exercise.save
|
||||||
|
if saved
|
||||||
|
render :text => 'SUCCESS', :status => 200
|
||||||
|
else
|
||||||
|
logger.info(exercise.errors.full_messages)
|
||||||
|
render :text => 'Invalid exercise', :status => 400
|
||||||
|
end
|
||||||
|
rescue => error
|
||||||
|
if error.class == Hash
|
||||||
|
render :text => error.message, :status => error.status
|
||||||
|
else
|
||||||
|
raise error
|
||||||
|
render :text => '', :status => 500
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_for_oauth2_request
|
||||||
|
authorizationHeader = request.headers['Authorization']
|
||||||
|
if authorizationHeader == nil
|
||||||
|
raise ({status: 401, message: 'No Authorization header'})
|
||||||
|
end
|
||||||
|
|
||||||
|
oauth2Token = authorizationHeader.split(' ')[1]
|
||||||
|
if oauth2Token == nil || oauth2Token.size == 0
|
||||||
|
raise ({status: 401, message: 'No token in Authorization header'})
|
||||||
|
end
|
||||||
|
|
||||||
|
user = user_by_code_harbor_token(oauth2Token)
|
||||||
|
if user == nil
|
||||||
|
raise ({status: 401, message: 'Unknown OAuth2 token'})
|
||||||
|
end
|
||||||
|
|
||||||
|
return user
|
||||||
|
end
|
||||||
|
private :user_for_oauth2_request
|
||||||
|
|
||||||
|
def user_by_code_harbor_token(oauth2Token)
|
||||||
|
link = CodeHarborLink.where(:oauth2token => oauth2Token)[0]
|
||||||
|
if link != nil
|
||||||
|
return link.user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
private :user_by_code_harbor_token
|
||||||
|
|
||||||
def exercise_params
|
def exercise_params
|
||||||
params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :team_id, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name)
|
params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :team_id, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name)
|
||||||
end
|
end
|
||||||
|
@ -111,6 +111,7 @@ class SubmissionsController < ApplicationController
|
|||||||
|
|
||||||
if result[:status] == :container_running
|
if result[:status] == :container_running
|
||||||
socket = result[:socket]
|
socket = result[:socket]
|
||||||
|
command = result[:command]
|
||||||
|
|
||||||
socket.on :message do |event|
|
socket.on :message do |event|
|
||||||
Rails.logger.info( Time.now.getutc.to_s + ": Docker sending: " + event.data)
|
Rails.logger.info( Time.now.getutc.to_s + ": Docker sending: " + event.data)
|
||||||
@ -139,6 +140,11 @@ class SubmissionsController < ApplicationController
|
|||||||
Rails.logger.debug('Rescued parsing error, sent the received client data to docker:' + data)
|
Rails.logger.debug('Rescued parsing error, sent the received client data to docker:' + data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Send command after all listeners are attached.
|
||||||
|
# Newline required to flush
|
||||||
|
socket.send command + "\n"
|
||||||
|
Rails.logger.info('Sent command: ' + command.to_s)
|
||||||
else
|
else
|
||||||
kill_socket(tubesock)
|
kill_socket(tubesock)
|
||||||
end
|
end
|
||||||
@ -176,7 +182,24 @@ class SubmissionsController < ApplicationController
|
|||||||
for part in message.split("\n")
|
for part in message.split("\n")
|
||||||
self.parse_message(part,output_stream,socket,false)
|
self.parse_message(part,output_stream,socket,false)
|
||||||
end
|
end
|
||||||
|
elsif(message.include? "<img")
|
||||||
|
#Rails.logger.info('img foung')
|
||||||
|
@buffering = true
|
||||||
|
@buffer = ""
|
||||||
|
@buffer += message
|
||||||
|
#Rails.logger.info('Starting to buffer')
|
||||||
|
elsif(@buffering && (message.include? "/>"))
|
||||||
|
@buffer += message
|
||||||
|
parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>@buffer}
|
||||||
|
socket.send_data JSON.dump(parsed)
|
||||||
|
#socket.send_data @buffer
|
||||||
|
@buffering = false
|
||||||
|
#Rails.logger.info('Sent complete buffer')
|
||||||
|
elsif(@buffering)
|
||||||
|
@buffer += message
|
||||||
|
#Rails.logger.info('Appending to buffer')
|
||||||
else
|
else
|
||||||
|
#Rails.logger.info('else')
|
||||||
parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>message}
|
parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>message}
|
||||||
socket.send_data JSON.dump(parsed)
|
socket.send_data JSON.dump(parsed)
|
||||||
Rails.logger.info('parse_message sent: ' + JSON.dump(parsed))
|
Rails.logger.info('parse_message sent: ' + JSON.dump(parsed))
|
||||||
|
2
app/helpers/code_harbor_links_helper.rb
Normal file
2
app/helpers/code_harbor_links_helper.rb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
module CodeHarborLinksHelper
|
||||||
|
end
|
13
app/models/code_harbor_link.rb
Normal file
13
app/models/code_harbor_link.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
class CodeHarborLink < ActiveRecord::Base
|
||||||
|
validates :oauth2token, presence: true
|
||||||
|
validates :user_id, presence: true
|
||||||
|
|
||||||
|
belongs_to :internal_user, foreign_key: :user_id
|
||||||
|
alias_method :user, :internal_user
|
||||||
|
alias_method :user=, :internal_user=
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
oauth2token
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -1,3 +1,4 @@
|
|||||||
|
require 'nokogiri'
|
||||||
require File.expand_path('../../../lib/active_model/validations/boolean_presence_validator', __FILE__)
|
require File.expand_path('../../../lib/active_model/validations/boolean_presence_validator', __FILE__)
|
||||||
|
|
||||||
class Exercise < ActiveRecord::Base
|
class Exercise < ActiveRecord::Base
|
||||||
@ -29,7 +30,11 @@ class Exercise < ActiveRecord::Base
|
|||||||
|
|
||||||
|
|
||||||
def average_percentage
|
def average_percentage
|
||||||
(average_score / maximum_score * 100).round if average_score and maximum_score != 0.0 else 0
|
if average_score and maximum_score != 0.0
|
||||||
|
(average_score / maximum_score * 100).round
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def average_score
|
def average_score
|
||||||
@ -105,6 +110,54 @@ class Exercise < ActiveRecord::Base
|
|||||||
exercise
|
exercise
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def determine_file_role_from_proforma_file(task_node, file_node)
|
||||||
|
file_id = file_node.xpath('@id')
|
||||||
|
file_class = file_node.xpath('@class').first.value
|
||||||
|
comment = file_node.xpath('@comment').first.value
|
||||||
|
is_referenced_by_test = task_node.xpath("p:tests/p:test/p:filerefs/p:fileref[@id=#{file_id}]")
|
||||||
|
is_referenced_by_model_solution = task_node.xpath("p:model-solutions/p:model-solution/p:filerefs/p:fileref[@id=#{file_id}]")
|
||||||
|
if is_referenced_by_test && (file_class == 'internal')
|
||||||
|
return 'teacher_defined_test'
|
||||||
|
elsif is_referenced_by_model_solution && (file_class == 'internal')
|
||||||
|
return 'reference_implementation'
|
||||||
|
elsif (file_class == 'template') && (comment == 'main')
|
||||||
|
return 'main_file'
|
||||||
|
elsif (file_class == 'internal') && (comment == 'main')
|
||||||
|
end
|
||||||
|
return 'regular_file'
|
||||||
|
end
|
||||||
|
|
||||||
|
def from_proforma_xml(xml_string)
|
||||||
|
# how to extract the proforma functionality into a different module in rails?
|
||||||
|
xml = Nokogiri::XML(xml_string)
|
||||||
|
xml.collect_namespaces
|
||||||
|
task_node = xml.xpath('/root/p:task')
|
||||||
|
description = task_node.xpath('p:description/text()')[0].content
|
||||||
|
self.attributes = {
|
||||||
|
title: task_node.xpath('p:meta-data/p:title/text()')[0].content,
|
||||||
|
description: description,
|
||||||
|
instructions: description
|
||||||
|
}
|
||||||
|
task_node.xpath('p:files/p:file').all? { |file|
|
||||||
|
file_name_split = file.xpath('@filename').first.value.split('.')
|
||||||
|
file_class = file.xpath('@class').first.value
|
||||||
|
role = determine_file_role_from_proforma_file(task_node, file)
|
||||||
|
feedback_message_nodes = task_node.xpath("p:tests/p:test/p:test-configuration/c:feedback-message/text()")
|
||||||
|
files.build({
|
||||||
|
name: file_name_split.first,
|
||||||
|
content: file.xpath('text()').first.content,
|
||||||
|
read_only: false,
|
||||||
|
hidden: file_class == 'internal',
|
||||||
|
role: role,
|
||||||
|
feedback_message: (role == 'teacher_defined_test') ? feedback_message_nodes.first.content : nil,
|
||||||
|
file_type: FileType.where(
|
||||||
|
file_extension: ".#{file_name_split.second}"
|
||||||
|
).take
|
||||||
|
})
|
||||||
|
}
|
||||||
|
self.execution_environment_id = 1
|
||||||
|
end
|
||||||
|
|
||||||
def generate_token
|
def generate_token
|
||||||
self.token ||= SecureRandom.hex(4)
|
self.token ||= SecureRandom.hex(4)
|
||||||
end
|
end
|
||||||
@ -129,4 +182,5 @@ class Exercise < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
private :valid_main_file?
|
private :valid_main_file?
|
||||||
|
|
||||||
end
|
end
|
||||||
|
3
app/policies/code_harbor_link_policy.rb
Normal file
3
app/policies/code_harbor_link_policy.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
class CodeHarborLinkPolicy < AdminOnlyPolicy
|
||||||
|
|
||||||
|
end
|
@ -8,7 +8,7 @@
|
|||||||
- if current_user.admin?
|
- if current_user.admin?
|
||||||
li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path)
|
li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path)
|
||||||
li.divider
|
li.divider
|
||||||
- models = [ExecutionEnvironment, Exercise, Consumer, ExternalUser, FileType, InternalUser, Submission, Team].sort_by { |model| model.model_name.human(count: 2) }
|
- models = [ExecutionEnvironment, Exercise, Consumer, CodeHarborLink, ExternalUser, FileType, InternalUser, Submission, Team].sort_by { |model| model.model_name.human(count: 2) }
|
||||||
- models.each do |model|
|
- models.each do |model|
|
||||||
- if policy(model).index?
|
- if policy(model).index?
|
||||||
li = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path"))
|
li = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path"))
|
||||||
|
6
app/views/code_harbor_links/_form.html.slim
Normal file
6
app/views/code_harbor_links/_form.html.slim
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
= form_for(@code_harbor_link) do |f|
|
||||||
|
= render('shared/form_errors', object: @code_harbor_link)
|
||||||
|
.form-group
|
||||||
|
= f.label(:oauth2token)
|
||||||
|
= f.text_field(:oauth2token, class: 'form-control', required: true)
|
||||||
|
.actions = render('shared/submit_button', f: f, object: @code_harbor_link)
|
3
app/views/code_harbor_links/edit.html.slim
Normal file
3
app/views/code_harbor_links/edit.html.slim
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
h1 = @code_harbor_link
|
||||||
|
|
||||||
|
= render('form')
|
18
app/views/code_harbor_links/index.html.slim
Normal file
18
app/views/code_harbor_links/index.html.slim
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
h1 = CodeHarborLink.model_name.human(count: 2)
|
||||||
|
|
||||||
|
.table-responsive
|
||||||
|
table.table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th = t('activerecord.attributes.code_harbor_link.oauth2token')
|
||||||
|
th colspan=3 = t('shared.actions')
|
||||||
|
tbody
|
||||||
|
- @code_harbor_links.each do |code_harbor_link|
|
||||||
|
tr
|
||||||
|
td = code_harbor_link.oauth2token
|
||||||
|
td = link_to(t('shared.show'), code_harbor_link)
|
||||||
|
td = link_to(t('shared.edit'), edit_code_harbor_link_path(code_harbor_link))
|
||||||
|
td = link_to(t('shared.destroy'), code_harbor_link, data: {confirm: t('shared.confirm_destroy')}, method: :delete)
|
||||||
|
|
||||||
|
= render('shared/pagination', collection: @code_harbor_links)
|
||||||
|
p = render('shared/new_button', model: CodeHarborLink)
|
3
app/views/code_harbor_links/new.html.slim
Normal file
3
app/views/code_harbor_links/new.html.slim
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
h1 = t('shared.new_model', model: CodeHarborLink.model_name.human)
|
||||||
|
|
||||||
|
= render('form')
|
7
app/views/code_harbor_links/show.html.slim
Normal file
7
app/views/code_harbor_links/show.html.slim
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
h1
|
||||||
|
= @code_harbor_link
|
||||||
|
= render('shared/edit_button', object: @code_harbor_link) if policy(@code_harbor_link).edit?
|
||||||
|
|
||||||
|
- %w[oauth2token].each do |attribute|
|
||||||
|
= row(label: "code_harbor_link.#{attribute}") do
|
||||||
|
= content_tag(:input, nil, class: 'form-control', readonly: true, value: @code_harbor_link.send(attribute))
|
@ -1,6 +1,8 @@
|
|||||||
de:
|
de:
|
||||||
activerecord:
|
activerecord:
|
||||||
attributes:
|
attributes:
|
||||||
|
code_harbor_link:
|
||||||
|
oauth2token: OAuth2 Token
|
||||||
consumer:
|
consumer:
|
||||||
name: Name
|
name: Name
|
||||||
oauth_key: OAuth Key
|
oauth_key: OAuth Key
|
||||||
@ -90,6 +92,9 @@ de:
|
|||||||
internal_user_ids: Mitglieder
|
internal_user_ids: Mitglieder
|
||||||
name: Name
|
name: Name
|
||||||
models:
|
models:
|
||||||
|
code_harbor_link:
|
||||||
|
one: CodeHarbor-Link
|
||||||
|
other: CodeHarbor-Links
|
||||||
consumer:
|
consumer:
|
||||||
one: Konsument
|
one: Konsument
|
||||||
other: Konsumenten
|
other: Konsumenten
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
en:
|
en:
|
||||||
activerecord:
|
activerecord:
|
||||||
attributes:
|
attributes:
|
||||||
|
code_harbor_link:
|
||||||
|
oauth2token: OAuth2 Token
|
||||||
consumer:
|
consumer:
|
||||||
name: Name
|
name: Name
|
||||||
oauth_key: OAuth Key
|
oauth_key: OAuth Key
|
||||||
@ -90,6 +92,9 @@ en:
|
|||||||
internal_user_ids: Members
|
internal_user_ids: Members
|
||||||
name: Name
|
name: Name
|
||||||
models:
|
models:
|
||||||
|
code_harbor_link:
|
||||||
|
one: CodeHarbor Link
|
||||||
|
other: CodeHarbor Links
|
||||||
consumer:
|
consumer:
|
||||||
one: Consumer
|
one: Consumer
|
||||||
other: Consumers
|
other: Consumers
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
FILENAME_REGEXP = /[\w\.]+/ unless Kernel.const_defined?(:FILENAME_REGEXP)
|
FILENAME_REGEXP = /[\w\.]+/ unless Kernel.const_defined?(:FILENAME_REGEXP)
|
||||||
|
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
|
resources :code_harbor_links
|
||||||
resources :request_for_comments
|
resources :request_for_comments
|
||||||
get '/my_request_for_comments', as: 'my_request_for_comments', to: 'request_for_comments#get_my_comment_requests'
|
get '/my_request_for_comments', as: 'my_request_for_comments', to: 'request_for_comments#get_my_comment_requests'
|
||||||
resources :comments, except: [:destroy] do
|
resources :comments, except: [:destroy] do
|
||||||
@ -40,6 +41,8 @@ Rails.application.routes.draw do
|
|||||||
resources :hints
|
resources :hints
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post '/import_proforma_xml' => 'exercises#import_proforma_xml'
|
||||||
|
|
||||||
resources :exercises do
|
resources :exercises do
|
||||||
collection do
|
collection do
|
||||||
match '', to: 'exercises#batch_update', via: [:patch, :put]
|
match '', to: 'exercises#batch_update', via: [:patch, :put]
|
||||||
|
9
db/migrate/20160204094409_create_code_harbor_links.rb
Normal file
9
db/migrate/20160204094409_create_code_harbor_links.rb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class CreateCodeHarborLinks < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :code_harbor_links do |t|
|
||||||
|
t.string :oauth2token
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
class AddUserToCodeHarborLink < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_reference :code_harbor_links, :user, index: true, foreign_key: true
|
||||||
|
end
|
||||||
|
end
|
11
db/schema.rb
11
db/schema.rb
@ -11,11 +11,20 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20150922125415) do
|
ActiveRecord::Schema.define(version: 20160204111716) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
||||||
|
create_table "code_harbor_links", force: true do |t|
|
||||||
|
t.string "oauth2token"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.integer "user_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
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: true do |t|
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.integer "file_id"
|
t.integer "file_id"
|
||||||
|
@ -21,14 +21,14 @@ class DockerClient
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.clean_container_workspace(container)
|
def self.clean_container_workspace(container)
|
||||||
container.exec(['bash', '-c', 'rm -rf ' + CONTAINER_WORKSPACE_PATH + '/*'])
|
# remove files when using transferral via Docker API archive_in (transmit)
|
||||||
=begin
|
#container.exec(['bash', '-c', 'rm -rf ' + CONTAINER_WORKSPACE_PATH + '/*'])
|
||||||
|
|
||||||
local_workspace_path = local_workspace_path(container)
|
local_workspace_path = local_workspace_path(container)
|
||||||
if local_workspace_path && Pathname.new(local_workspace_path).exist?
|
if local_workspace_path && Pathname.new(local_workspace_path).exist?
|
||||||
Pathname.new(local_workspace_path).children.each{ |p| p.rmtree}
|
Pathname.new(local_workspace_path).children.each{ |p| p.rmtree}
|
||||||
#FileUtils.rmdir(Pathname.new(local_workspace_path))
|
#FileUtils.rmdir(Pathname.new(local_workspace_path))
|
||||||
end
|
end
|
||||||
=end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def command_substitutions(filename)
|
def command_substitutions(filename)
|
||||||
@ -96,9 +96,10 @@ class DockerClient
|
|||||||
#Rails.logger.info "docker_client: self.create_container with creation options:"
|
#Rails.logger.info "docker_client: self.create_container with creation options:"
|
||||||
#Rails.logger.info(container_creation_options(execution_environment))
|
#Rails.logger.info(container_creation_options(execution_environment))
|
||||||
container = Docker::Container.create(container_creation_options(execution_environment))
|
container = Docker::Container.create(container_creation_options(execution_environment))
|
||||||
|
# container.start sometimes creates the passed local_workspace_path on disk (depending on the setup).
|
||||||
|
# this is however not guaranteed and caused issues on the server already. Therefore create the necessary folders manually!
|
||||||
local_workspace_path = generate_local_workspace_path
|
local_workspace_path = generate_local_workspace_path
|
||||||
# container.start always creates the passed local_workspace_path on disk. Seems like we have to live with that, therefore we can also just create the empty folder ourselves.
|
FileUtils.mkdir(local_workspace_path)
|
||||||
# FileUtils.mkdir(local_workspace_path)
|
|
||||||
container.start(container_start_options(execution_environment, local_workspace_path))
|
container.start(container_start_options(execution_environment, local_workspace_path))
|
||||||
container.start_time = Time.now
|
container.start_time = Time.now
|
||||||
container.status = :created
|
container.status = :created
|
||||||
@ -217,7 +218,7 @@ class DockerClient
|
|||||||
end
|
end
|
||||||
|
|
||||||
#called when the user clicks the "Run" button
|
#called when the user clicks the "Run" button
|
||||||
def execute_websocket_command(command, before_execution_block, output_consuming_block)
|
def open_websocket_connection(command, before_execution_block, output_consuming_block)
|
||||||
@container = DockerContainerPool.get_container(@execution_environment)
|
@container = DockerContainerPool.get_container(@execution_environment)
|
||||||
if @container
|
if @container
|
||||||
@container.status = :executing
|
@container.status = :executing
|
||||||
@ -230,10 +231,7 @@ class DockerClient
|
|||||||
end
|
end
|
||||||
# TODO: catch exception if socket could not be created
|
# TODO: catch exception if socket could not be created
|
||||||
@socket ||= create_socket(@container)
|
@socket ||= create_socket(@container)
|
||||||
# Newline required to flush
|
{status: :container_running, socket: @socket, container: @container, command: command}
|
||||||
@socket.send command + "\n"
|
|
||||||
Rails.logger.info('Sent command: ' + command.to_s)
|
|
||||||
{status: :container_running, socket: @socket, container: @container}
|
|
||||||
else
|
else
|
||||||
{status: :container_depleted}
|
{status: :container_depleted}
|
||||||
end
|
end
|
||||||
@ -295,8 +293,9 @@ class DockerClient
|
|||||||
Run commands by attaching a websocket to Docker.
|
Run commands by attaching a websocket to Docker.
|
||||||
"""
|
"""
|
||||||
command = submission.execution_environment.run_command % command_substitutions(filename)
|
command = submission.execution_environment.run_command % command_substitutions(filename)
|
||||||
create_workspace_files = proc { create_workspace_files_transmit(container, submission) }
|
create_workspace_files = proc { create_workspace_files(container, submission) }
|
||||||
execute_websocket_command(command, create_workspace_files, block)
|
open_websocket_connection(command, create_workspace_files, block)
|
||||||
|
# actual run command is run in the submissions controller, after all listeners are attached.
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute_test_command(submission, filename, &block)
|
def execute_test_command(submission, filename, &block)
|
||||||
@ -304,7 +303,7 @@ class DockerClient
|
|||||||
Stick to existing Docker API with exec command.
|
Stick to existing Docker API with exec command.
|
||||||
"""
|
"""
|
||||||
command = submission.execution_environment.test_command % command_substitutions(filename)
|
command = submission.execution_environment.test_command % command_substitutions(filename)
|
||||||
create_workspace_files = proc { create_workspace_files_transmit(container, submission) }
|
create_workspace_files = proc { create_workspace_files(container, submission) }
|
||||||
execute_command(command, create_workspace_files, block)
|
execute_command(command, create_workspace_files, block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -41,16 +41,17 @@ class DockerContainerPool
|
|||||||
@all_containers[execution_environment.id]+=[container]
|
@all_containers[execution_environment.id]+=[container]
|
||||||
if(!@containers[execution_environment.id].include?(container))
|
if(!@containers[execution_environment.id].include?(container))
|
||||||
@containers[execution_environment.id]+=[container]
|
@containers[execution_environment.id]+=[container]
|
||||||
Rails.logger.debug('Added container ' + container.to_s + ' to all_pool for execution environment ' + execution_environment.to_s + '. Containers in all_pool: ' + @all_containers[execution_environment.id].size.to_s)
|
#Rails.logger.debug('Added container ' + container.to_s + ' to all_pool for execution environment ' + execution_environment.to_s + '. Containers in all_pool: ' + @all_containers[execution_environment.id].size.to_s)
|
||||||
else
|
else
|
||||||
Rails.logger.info('failed trying to add existing container ' + container.to_s + ' to execution_environment ' + execution_environment.to_s)
|
Rails.logger.info('failed trying to add existing container ' + container.to_s + ' to execution_environment ' + execution_environment.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.create_container(execution_environment)
|
def self.create_container(execution_environment)
|
||||||
|
Rails.logger.info('trying to create container for execution environment: ' + execution_environment.to_s)
|
||||||
container = DockerClient.create_container(execution_environment)
|
container = DockerClient.create_container(execution_environment)
|
||||||
container.status = 'available'
|
container.status = 'available'
|
||||||
Rails.logger.debug('created container ' + container.to_s + ' for execution environment ' + execution_environment.to_s)
|
#Rails.logger.debug('created container ' + container.to_s + ' for execution environment ' + execution_environment.to_s)
|
||||||
container
|
container
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -120,11 +121,11 @@ class DockerContainerPool
|
|||||||
if refill_count > 0
|
if refill_count > 0
|
||||||
Rails.logger.info('Adding ' + refill_count.to_s + ' containers for execution_environment ' + execution_environment.name )
|
Rails.logger.info('Adding ' + refill_count.to_s + ' containers for execution_environment ' + execution_environment.name )
|
||||||
c = refill_count.times.map { create_container(execution_environment) }
|
c = refill_count.times.map { create_container(execution_environment) }
|
||||||
Rails.logger.info('Created containers: ' + c.to_s )
|
#Rails.logger.info('Created containers: ' + c.to_s )
|
||||||
@containers[execution_environment.id] += c
|
@containers[execution_environment.id] += c
|
||||||
@all_containers[execution_environment.id] += c
|
@all_containers[execution_environment.id] += c
|
||||||
Rails.logger.debug('@containers for ' + execution_environment.name.to_s + ' (' + @containers.object_id.to_s + ') has the following content: '+ @containers[execution_environment.id].to_s)
|
#Rails.logger.debug('@containers for ' + execution_environment.name.to_s + ' (' + @containers.object_id.to_s + ') has the following content: '+ @containers[execution_environment.id].to_s)
|
||||||
Rails.logger.debug('@all_containers for ' + execution_environment.name.to_s + ' (' + @all_containers.object_id.to_s + ') has the following content: ' + @all_containers[execution_environment.id].to_s)
|
#Rails.logger.debug('@all_containers for ' + execution_environment.name.to_s + ' (' + @all_containers.object_id.to_s + ') has the following content: ' + @all_containers[execution_environment.id].to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ class Xikolo::Client
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.url
|
def self.url
|
||||||
|
#todo: JanR: set an environment variable here, fallback value: http://open.hpi.de/api/
|
||||||
'http://localhost:2000/api/'
|
'http://localhost:2000/api/'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user