Description:
merge
Commit status:
[Not Reviewed]
References:
merge java
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r628:3df78cd5515f - - 25 files changed: 527 inserted, 135 deleted

@@ -0,0 +1,24
1 + class TestcasesController < ApplicationController
2 + before_action :set_testcase, only: [:download_input,:download_sol]
3 + before_action :testcase_authorization
4 +
5 + def download_input
6 + send_data @testcase.input, type: 'text/plain', filename: "#{@testcase.problem.name}.#{@testcase.num}.in"
7 + end
8 +
9 + def download_sol
10 + send_data @testcase.sol, type: 'text/plain', filename: "#{@testcase.problem.name}.#{@testcase.num}.sol"
11 + end
12 +
13 +
14 + private
15 + # Use callbacks to share common setup or constraints between actions.
16 + def set_testcase
17 + @testcase = Testcase.find(params[:id])
18 + end
19 +
20 + # Only allow a trusted parameter "white list" through.
21 + def testcase_params
22 + params[:testcase]
23 + end
24 + end
@@ -0,0 +1,2
1 + module TestcasesHelper
2 + end
@@ -0,0 +1,25
1 + %h1 Test cases
2 + %h2= @problem.long_name
3 +
4 + /navbar
5 + %ul.nav.nav-pills{role: :tablist}
6 + - @problem.testcases.each.with_index do |tc,id|
7 + %li{role: :presentation, class: ('active' if id == 0)}
8 + %a{href:"#tc#{tc.id}", role: 'tab', data: {toggle: 'tab'}}= tc.num
9 +
10 + /actual data
11 + .tab-content
12 + - @problem.testcases.each.with_index do |tc,id|
13 + .tab-pane{id: "tc#{tc.id}",class: ('active' if id == 0)}
14 + .row
15 + .col-md-6
16 + %h3 Input
17 + = link_to "Download",download_input_problem_testcase_path(@problem,tc),class: 'btn btn-info btn-sm'
18 + .col-md-6
19 + %h3 Output
20 + = link_to "Download",download_sol_problem_testcase_path(@problem,tc),class: 'btn btn-info btn-sm'
21 + .row
22 + .col-md-6
23 + %textarea{ rows: 25,readonly: true,style: "width:100%;resize=none;overflow-y: scroll;"}= tc.input
24 + .col-md-6
25 + %textarea{ rows: 25,readonly: true,style: "width:100%;resize=none;overflow-y: scroll;"}= tc.sol
@@ -0,0 +1,41
1 + # Original from http://snippets.dzone.com/posts/show/4468 by MichaelBoutros
2 + #
3 + # Optimized version which uses to_yaml for content creation and checks
4 + # that models are ActiveRecord::Base models before trying to fetch
5 + # them from database.
6 + namespace :db do
7 + namespace :fixtures do
8 + desc 'Dumps all models into fixtures.'
9 + task :dump => :environment do
10 + puts "rails root = #{Rails.root}"
11 + models = Dir.glob(Rails.root.to_s + '/app/models/**.rb').map do |s|
12 + Pathname.new(s).basename.to_s.gsub(/\.rb$/,'').camelize
13 + end
14 +
15 + puts "Found models: " + models.join(', ')
16 +
17 + models.each do |m|
18 + model = m.constantize
19 + next unless model.ancestors.include?(ActiveRecord::Base)
20 +
21 + puts "Dumping model: " + m
22 + entries = model.all.order(id: :asc)
23 +
24 + increment = 1
25 +
26 + model_file = Rails.root.to_s + '/test/fixtures2/' + m.underscore.pluralize + '.yml'
27 + File.open(model_file, 'w') do |f|
28 + entries.each do |a|
29 + attrs = a.attributes
30 + attrs.delete_if{|k,v| v.blank?}
31 +
32 + output = {m + '_' + increment.to_s => attrs}
33 + f << output.to_yaml.gsub(/^--- \n/,'') + "\n"
34 +
35 + increment += 1
36 + end
37 + end
38 + end
39 + end
40 + end
41 + end
@@ -0,0 +1,7
1 + require 'test_helper'
2 +
3 + class TestcasesControllerTest < ActionController::TestCase
4 + setup do
5 + @testcase = testcases(:one)
6 + end
7 + end
@@ -0,0 +1,144
1 + GraderConfiguration_1:
2 + key: system.single_user_mode
3 + value_type: boolean
4 + value: 'false'
5 + description: Only admins can log in to the system when running under single user mode.
6 +
7 + GraderConfiguration_2:
8 + key: ui.front.title
9 + value_type: string
10 + value: Grader
11 +
12 + GraderConfiguration_3:
13 + key: ui.front.welcome_message
14 + value_type: string
15 + value: Welcome!
16 +
17 + GraderConfiguration_4:
18 + key: ui.show_score
19 + value_type: boolean
20 + value: 'true'
21 +
22 + GraderConfiguration_5:
23 + key: contest.time_limit
24 + value_type: string
25 + value: unlimited
26 + description: Time limit in format hh:mm, or "unlimited" for contests with no time
27 + limits. This config is CACHED. Restart the server before the change can take
28 + effect.
29 +
30 + GraderConfiguration_6:
31 + key: system.mode
32 + value_type: string
33 + value: standard
34 + description: Current modes are "standard", "contest", "indv-contest", and "analysis".
35 +
36 +
37 + GraderConfiguration_7:
38 + key: contest.name
39 + value_type: string
40 + value: Grader
41 + description: This name will be shown on the user header bar.
42 +
43 +
44 + GraderConfiguration_8:
45 + key: contest.multisites
46 + value_type: boolean
47 + value: 'false'
48 + description: If the server is in contest mode and this option is true, on the log
49 + in of the admin a menu for site selections is shown.
50 +
51 +
52 + GraderConfiguration_9:
53 + key: right.user_hall_of_fame
54 + value_type: boolean
55 + value: 'false'
56 + description: If true, any user can access hall of fame page.
57 +
58 +
59 + GraderConfiguration_10:
60 + key: right.multiple_ip_login
61 + value_type: boolean
62 + value: 'true'
63 + description: When change from true to false, a user can login from the first IP
64 + they logged into afterward.
65 +
66 +
67 + GraderConfiguration_11:
68 + key: right.user_view_submission
69 + value_type: boolean
70 + value: 'false'
71 + description: If true, any user can view submissions of every one.
72 +
73 +
74 + GraderConfiguration_12:
75 + key: right.bypass_agreement
76 + value_type: boolean
77 + value: 'true'
78 + description: When false, a user must accept usage agreement before login
79 +
80 +
81 + GraderConfiguration_13:
82 + key: right.heartbeat_response
83 + value_type: string
84 + value: OK
85 + description: Heart beat response text
86 +
87 +
88 + GraderConfiguration_14:
89 + key: right.view_testcase
90 + value_type: boolean
91 + value: 'false'
92 + description: When true, any user can view/download test data
93 +
94 +
95 + GraderConfiguration_15:
96 + key: system.online_registration.smtp
97 + value_type: string
98 + value: smtp.somehost.com
99 +
100 +
101 + GraderConfiguration_16:
102 + key: system.online_registration.from
103 + value_type: string
104 + value: your.email@address
105 +
106 +
107 + GraderConfiguration_17:
108 + key: system.admin_email
109 + value_type: string
110 + value: admin@admin.email
111 +
112 +
113 + GraderConfiguration_18:
114 + key: system.user_setting_enabled
115 + value_type: boolean
116 + value: 'true'
117 + description: If this option is true, users can change their settings
118 +
119 +
120 + GraderConfiguration_19:
121 + key: contest.test_request.early_timeout
122 + value_type: boolean
123 + value: 'false'
124 +
125 +
126 + GraderConfiguration_20:
127 + key: system.multicontests
128 + value_type: boolean
129 + value: 'false'
130 +
131 +
132 + GraderConfiguration_21:
133 + key: contest.confirm_indv_contest_start
134 + value_type: boolean
135 + value: 'false'
136 +
137 +
138 + GraderConfiguration_22:
139 + key: contest.default_contest_name
140 + value_type: string
141 + value: none
142 + description: New user will be assigned to this contest automatically, if it exists. Set
143 + to 'none' if there is no default contest.
144 +
@@ -1,78 +1,88
1 1 source 'https://rubygems.org'
2 2
3 + #rails
3 4 gem 'rails', '~>4.2.0'
4 5 gem 'activerecord-session_store'
5 6
6 - gem 'select2-rails'
7 7
8 8 # Bundle edge Rails instead:
9 9 # gem 'rails', :git => 'git://github.com/rails/rails.git'
10 10
11 + #---------------- database ---------------------
12 + #the database
11 13 gem 'mysql2'
14 + #for testing
12 15 gem 'sqlite3'
16 + #for dumping database into yaml
17 + gem 'yaml_db'
13 18
14 19 # Gems used only for assets and not required
15 20 # in production environments by default.
16 21 gem 'sass-rails'
17 22 gem 'coffee-rails'
18 23
19 24 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
20 25 # gem 'therubyracer', :platforms => :ruby
21 26
22 27 gem 'uglifier'
23 28
24 -
29 + gem 'haml'
30 + gem 'haml-rails'
25 31 # gem 'prototype-rails'
26 32
27 33 # To use ActiveModel has_secure_password
28 34 # gem 'bcrypt-ruby', '~> 3.0.0'
29 35
30 36 # To use Jbuilder templates for JSON
31 37 # gem 'jbuilder'
32 38
33 39 # Use unicorn as the app server
34 40 # gem 'unicorn'
35 41
36 42 # Deploy with Capistrano
37 43 # gem 'capistrano'
38 44
39 45 # To use debugger
40 46 # gem 'debugger'
41 47 #
42 48
43 49 #in-place editor
44 50 gem 'best_in_place', '~> 3.0.1'
45 51
46 52 # jquery addition
47 53 gem 'jquery-rails'
48 54 gem 'jquery-ui-rails'
49 55 gem 'jquery-timepicker-addon-rails'
50 56 gem 'jquery-tablesorter'
51 57 gem 'jquery-countdown-rails'
52 58
53 59 #syntax highlighter
54 60 gem 'rouge'
55 61
56 62 #add bootstrap
57 63 gem 'bootstrap-sass', '~> 3.2.0'
58 64 gem 'bootstrap-switch-rails'
59 65 gem 'bootstrap-toggle-rails'
60 66 gem 'autoprefixer-rails'
61 67
62 68 #bootstrap sortable
63 69 gem 'momentjs-rails'
64 70 gem 'rails_bootstrap_sortable'
65 71
72 + #----------- user interface -----------------
73 + #select 2
74 + gem 'select2-rails'
66 75 #ace editor
67 76 gem 'ace-rails-ap'
77 + #paginator
78 + gem 'will_paginate', '~> 3.0.7'
68 79
69 - gem 'haml'
70 - gem 'haml-rails'
71 80 gem 'mail'
72 81 gem 'rdiscount'
73 - gem 'test-unit'
74 - gem 'will_paginate', '~> 3.0.7'
75 82 gem 'dynamic_form'
76 83 gem 'in_place_editing'
77 84 gem 'verification', :git => 'https://github.com/sikachu/verification.git'
78 85
86 +
87 + #---------------- testiing -----------------------
88 + gem 'minitest-reporters'
@@ -1,221 +1,229
1 1 GIT
2 2 remote: https://github.com/sikachu/verification.git
3 3 revision: ff31697b940d7b0e2ec65f08764215c96104e76d
4 4 specs:
5 5 verification (1.0.3)
6 6 actionpack (>= 3.0.0, < 5.1)
7 7 activesupport (>= 3.0.0, < 5.1)
8 8
9 9 GEM
10 10 remote: https://rubygems.org/
11 11 specs:
12 12 ace-rails-ap (4.1.1)
13 13 actionmailer (4.2.7.1)
14 14 actionpack (= 4.2.7.1)
15 15 actionview (= 4.2.7.1)
16 16 activejob (= 4.2.7.1)
17 17 mail (~> 2.5, >= 2.5.4)
18 18 rails-dom-testing (~> 1.0, >= 1.0.5)
19 19 actionpack (4.2.7.1)
20 20 actionview (= 4.2.7.1)
21 21 activesupport (= 4.2.7.1)
22 22 rack (~> 1.6)
23 23 rack-test (~> 0.6.2)
24 24 rails-dom-testing (~> 1.0, >= 1.0.5)
25 25 rails-html-sanitizer (~> 1.0, >= 1.0.2)
26 26 actionview (4.2.7.1)
27 27 activesupport (= 4.2.7.1)
28 28 builder (~> 3.1)
29 29 erubis (~> 2.7.0)
30 30 rails-dom-testing (~> 1.0, >= 1.0.5)
31 31 rails-html-sanitizer (~> 1.0, >= 1.0.2)
32 32 activejob (4.2.7.1)
33 33 activesupport (= 4.2.7.1)
34 34 globalid (>= 0.3.0)
35 35 activemodel (4.2.7.1)
36 36 activesupport (= 4.2.7.1)
37 37 builder (~> 3.1)
38 38 activerecord (4.2.7.1)
39 39 activemodel (= 4.2.7.1)
40 40 activesupport (= 4.2.7.1)
41 41 arel (~> 6.0)
42 42 activerecord-session_store (1.0.0)
43 43 actionpack (>= 4.0, < 5.1)
44 44 activerecord (>= 4.0, < 5.1)
45 45 multi_json (~> 1.11, >= 1.11.2)
46 46 rack (>= 1.5.2, < 3)
47 47 railties (>= 4.0, < 5.1)
48 48 activesupport (4.2.7.1)
49 49 i18n (~> 0.7)
50 50 json (~> 1.7, >= 1.7.7)
51 51 minitest (~> 5.1)
52 52 thread_safe (~> 0.3, >= 0.3.4)
53 53 tzinfo (~> 1.1)
54 + ansi (1.5.0)
54 55 arel (6.0.4)
55 56 autoprefixer-rails (6.6.0)
56 57 execjs
57 58 best_in_place (3.0.3)
58 59 actionpack (>= 3.2)
59 60 railties (>= 3.2)
60 61 bootstrap-sass (3.2.0.2)
61 62 sass (~> 3.2)
62 63 bootstrap-switch-rails (3.3.3)
63 64 bootstrap-toggle-rails (2.2.1.0)
64 65 builder (3.2.2)
65 66 coffee-rails (4.2.1)
66 67 coffee-script (>= 2.2.0)
67 68 railties (>= 4.0.0, < 5.2.x)
68 69 coffee-script (2.4.1)
69 70 coffee-script-source
70 71 execjs
71 72 coffee-script-source (1.12.2)
72 73 concurrent-ruby (1.0.4)
73 74 dynamic_form (1.1.4)
74 75 erubis (2.7.0)
75 76 execjs (2.7.0)
76 77 globalid (0.3.7)
77 78 activesupport (>= 4.1.0)
78 79 haml (4.0.7)
79 80 tilt
80 81 haml-rails (0.9.0)
81 82 actionpack (>= 4.0.1)
82 83 activesupport (>= 4.0.1)
83 84 haml (>= 4.0.6, < 5.0)
84 85 html2haml (>= 1.0.1)
85 86 railties (>= 4.0.1)
86 87 html2haml (2.0.0)
87 88 erubis (~> 2.7.0)
88 89 haml (~> 4.0.0)
89 90 nokogiri (~> 1.6.0)
90 91 ruby_parser (~> 3.5)
91 92 i18n (0.7.0)
92 93 in_place_editing (1.2.0)
93 94 jquery-countdown-rails (2.0.2)
94 95 jquery-rails (4.2.1)
95 96 rails-dom-testing (>= 1, < 3)
96 97 railties (>= 4.2.0)
97 98 thor (>= 0.14, < 2.0)
98 99 jquery-tablesorter (1.23.3)
99 100 railties (>= 3.2, < 6)
100 101 jquery-timepicker-addon-rails (1.4.1)
101 102 railties (>= 3.1)
102 103 jquery-ui-rails (6.0.1)
103 104 railties (>= 3.2.16)
104 105 json (1.8.3)
105 106 loofah (2.0.3)
106 107 nokogiri (>= 1.5.9)
107 108 mail (2.6.4)
108 109 mime-types (>= 1.16, < 4)
109 110 mime-types (3.1)
110 111 mime-types-data (~> 3.2015)
111 112 mime-types-data (3.2016.0521)
112 113 mini_portile2 (2.1.0)
113 114 minitest (5.10.1)
115 + minitest-reporters (1.1.13)
116 + ansi
117 + builder
118 + minitest (>= 5.0)
119 + ruby-progressbar
114 120 momentjs-rails (2.15.1)
115 121 railties (>= 3.1)
116 122 multi_json (1.12.1)
117 123 mysql2 (0.4.5)
118 124 nokogiri (1.6.8.1)
119 125 mini_portile2 (~> 2.1.0)
120 - power_assert (0.4.1)
121 126 rack (1.6.5)
122 127 rack-test (0.6.3)
123 128 rack (>= 1.0)
124 129 rails (4.2.7.1)
125 130 actionmailer (= 4.2.7.1)
126 131 actionpack (= 4.2.7.1)
127 132 actionview (= 4.2.7.1)
128 133 activejob (= 4.2.7.1)
129 134 activemodel (= 4.2.7.1)
130 135 activerecord (= 4.2.7.1)
131 136 activesupport (= 4.2.7.1)
132 137 bundler (>= 1.3.0, < 2.0)
133 138 railties (= 4.2.7.1)
134 139 sprockets-rails
135 140 rails-deprecated_sanitizer (1.0.3)
136 141 activesupport (>= 4.2.0.alpha)
137 142 rails-dom-testing (1.0.8)
138 143 activesupport (>= 4.2.0.beta, < 5.0)
139 144 nokogiri (~> 1.6)
140 145 rails-deprecated_sanitizer (>= 1.0.1)
141 146 rails-html-sanitizer (1.0.3)
142 147 loofah (~> 2.0)
143 148 rails_bootstrap_sortable (2.0.1)
144 149 momentjs-rails (>= 2.8.3)
145 150 railties (4.2.7.1)
146 151 actionpack (= 4.2.7.1)
147 152 activesupport (= 4.2.7.1)
148 153 rake (>= 0.8.7)
149 154 thor (>= 0.18.1, < 2.0)
150 155 rake (12.0.0)
151 156 rdiscount (2.2.0.1)
152 157 rouge (2.0.7)
158 + ruby-progressbar (1.8.1)
153 159 ruby_parser (3.8.3)
154 160 sexp_processor (~> 4.1)
155 161 sass (3.4.23)
156 162 sass-rails (5.0.6)
157 163 railties (>= 4.0.0, < 6)
158 164 sass (~> 3.1)
159 165 sprockets (>= 2.8, < 4.0)
160 166 sprockets-rails (>= 2.0, < 4.0)
161 167 tilt (>= 1.1, < 3)
162 168 select2-rails (4.0.3)
163 169 thor (~> 0.14)
164 170 sexp_processor (4.7.0)
165 171 sprockets (3.7.1)
166 172 concurrent-ruby (~> 1.0)
167 173 rack (> 1, < 3)
168 174 sprockets-rails (3.2.0)
169 175 actionpack (>= 4.0)
170 176 activesupport (>= 4.0)
171 177 sprockets (>= 3.0.0)
172 178 sqlite3 (1.3.12)
173 - test-unit (3.2.3)
174 - power_assert
175 179 thor (0.19.4)
176 180 thread_safe (0.3.5)
177 181 tilt (2.0.5)
178 182 tzinfo (1.2.2)
179 183 thread_safe (~> 0.1)
180 184 uglifier (3.0.4)
181 185 execjs (>= 0.3.0, < 3)
182 186 will_paginate (3.0.12)
187 + yaml_db (0.4.2)
188 + rails (>= 3.0, < 5.1)
189 + rake (>= 0.8.7)
183 190
184 191 PLATFORMS
185 192 ruby
186 193
187 194 DEPENDENCIES
188 195 ace-rails-ap
189 196 activerecord-session_store
190 197 autoprefixer-rails
191 198 best_in_place (~> 3.0.1)
192 199 bootstrap-sass (~> 3.2.0)
193 200 bootstrap-switch-rails
194 201 bootstrap-toggle-rails
195 202 coffee-rails
196 203 dynamic_form
197 204 haml
198 205 haml-rails
199 206 in_place_editing
200 207 jquery-countdown-rails
201 208 jquery-rails
202 209 jquery-tablesorter
203 210 jquery-timepicker-addon-rails
204 211 jquery-ui-rails
205 212 mail
213 + minitest-reporters
206 214 momentjs-rails
207 215 mysql2
208 216 rails (~> 4.2.0)
209 217 rails_bootstrap_sortable
210 218 rdiscount
211 219 rouge
212 220 sass-rails
213 221 select2-rails
214 222 sqlite3
215 - test-unit
216 223 uglifier
217 224 verification!
218 225 will_paginate (~> 3.0.7)
226 + yaml_db
219 227
220 228 BUNDLED WITH
221 229 1.13.6
@@ -1,128 +1,137
1 1 class ApplicationController < ActionController::Base
2 2 protect_from_forgery
3 3
4 4 before_filter :current_user
5 5
6 6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
7 7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
8 8
9 9 #report and redirect for unauthorized activities
10 10 def unauthorized_redirect
11 11 flash[:notice] = 'You are not authorized to view the page you requested'
12 12 redirect_to :controller => 'main', :action => 'login'
13 13 end
14 14
15 15 # Returns the current logged-in user (if any).
16 16 def current_user
17 17 return nil unless session[:user_id]
18 18 @current_user ||= User.find(session[:user_id])
19 19 end
20 20
21 21 def admin_authorization
22 22 return false unless authenticate
23 23 user = User.includes(:roles).find(session[:user_id])
24 24 unless user.admin?
25 25 unauthorized_redirect
26 26 return false
27 27 end
28 28 return true
29 29 end
30 30
31 31 def authorization_by_roles(allowed_roles)
32 32 return false unless authenticate
33 33 user = User.find(session[:user_id])
34 34 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
35 35 unauthorized_redirect
36 36 return false
37 37 end
38 38 end
39 39
40 + def testcase_authorization
41 + #admin always has privileged
42 + if @current_user.admin?
43 + return true
44 + end
45 +
46 + unauthorized_redirect if GraderConfiguration["right.view_testcase"]
47 + end
48 +
40 49 protected
41 50
42 51 def authenticate
43 52 unless session[:user_id]
44 53 flash[:notice] = 'You need to login'
45 54 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
46 55 flash[:notice] = 'You need to login but you cannot log in at this time'
47 56 end
48 57 redirect_to :controller => 'main', :action => 'login'
49 58 return false
50 59 end
51 60
52 61 # check if run in single user mode
53 62 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
54 63 user = User.find_by_id(session[:user_id])
55 64 if user==nil or (not user.admin?)
56 65 flash[:notice] = 'You cannot log in at this time'
57 66 redirect_to :controller => 'main', :action => 'login'
58 67 return false
59 68 end
60 69 unless user.enabled?
61 70 flash[:notice] = 'Your account is disabled'
62 71 redirect_to :controller => 'main', :action => 'login'
63 72 return false
64 73 end
65 74 return true
66 75 end
67 76
68 77 if GraderConfiguration.multicontests?
69 78 user = User.find(session[:user_id])
70 79 return true if user.admin?
71 80 begin
72 81 if user.contest_stat(true).forced_logout
73 82 flash[:notice] = 'You have been automatically logged out.'
74 83 redirect_to :controller => 'main', :action => 'index'
75 84 end
76 85 rescue
77 86 end
78 87 end
79 88 return true
80 89 end
81 90
82 91 def authenticate_by_ip_address
83 92 #this assume that we have already authenticate normally
84 93 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
85 94 user = User.find(session[:user_id])
86 95 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
87 96 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
88 97 redirect_to :controller => 'main', :action => 'login'
89 98 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
90 99 return false
91 100 end
92 101 unless user.last_ip
93 102 user.last_ip = request.remote_ip
94 103 user.save
95 104 end
96 105 end
97 106 return true
98 107 end
99 108
100 109 def authorization
101 110 return false unless authenticate
102 111 user = User.find(session[:user_id])
103 112 unless user.roles.detect { |role|
104 113 role.rights.detect{ |right|
105 114 right.controller == self.class.controller_name and
106 115 (right.action == 'all' or right.action == action_name)
107 116 }
108 117 }
109 118 flash[:notice] = 'You are not authorized to view the page you requested'
110 119 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
111 120 redirect_to :controller => 'main', :action => 'login'
112 121 return false
113 122 end
114 123 end
115 124
116 125 def verify_time_limit
117 126 return true if session[:user_id]==nil
118 127 user = User.find(session[:user_id], :include => :site)
119 128 return true if user==nil or user.site == nil
120 129 if user.contest_finished?
121 130 flash[:notice] = 'Error: the contest you are participating is over.'
122 131 redirect_to :back
123 132 return false
124 133 end
125 134 return true
126 135 end
127 136
128 137 end
@@ -1,279 +1,284
1 1 class ProblemsController < ApplicationController
2 2
3 - before_filter :authenticate, :authorization
3 + before_action :authenticate, :authorization
4 + before_action :testcase_authorization, only: [:show_testcase]
4 5
5 6 in_place_edit_for :problem, :name
6 7 in_place_edit_for :problem, :full_name
7 8 in_place_edit_for :problem, :full_score
8 9
9 10 def index
10 11 @problems = Problem.order(date_added: :desc)
11 12 end
12 13
13 14 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
14 15 verify :method => :post, :only => [ :create, :quick_create,
15 16 :do_manage,
16 17 :do_import,
17 18 ],
18 19 :redirect_to => { :action => :index }
19 20
20 21 def show
21 22 @problem = Problem.find(params[:id])
22 23 end
23 24
24 25 def new
25 26 @problem = Problem.new
26 27 @description = nil
27 28 end
28 29
29 30 def create
30 31 @problem = Problem.new(params[:problem])
31 32 @description = Description.new(params[:description])
32 33 if @description.body!=''
33 34 if !@description.save
34 35 render :action => new and return
35 36 end
36 37 else
37 38 @description = nil
38 39 end
39 40 @problem.description = @description
40 41 if @problem.save
41 42 flash[:notice] = 'Problem was successfully created.'
42 43 redirect_to action: :index
43 44 else
44 45 render :action => 'new'
45 46 end
46 47 end
47 48
48 49 def quick_create
49 50 @problem = Problem.new(params[:problem])
50 51 @problem.full_name = @problem.name if @problem.full_name == ''
51 52 @problem.full_score = 100
52 53 @problem.available = false
53 54 @problem.test_allowed = true
54 55 @problem.output_only = false
55 56 @problem.date_added = Time.new
56 57 if @problem.save
57 58 flash[:notice] = 'Problem was successfully created.'
58 59 redirect_to action: :index
59 60 else
60 61 flash[:notice] = 'Error saving problem'
61 62 redirect_to action: :index
62 63 end
63 64 end
64 65
65 66 def edit
66 67 @problem = Problem.find(params[:id])
67 68 @description = @problem.description
68 69 end
69 70
70 71 def update
71 72 @problem = Problem.find(params[:id])
72 73 @description = @problem.description
73 74 if @description.nil? and params[:description][:body]!=''
74 75 @description = Description.new(params[:description])
75 76 if !@description.save
76 77 flash[:notice] = 'Error saving description'
77 78 render :action => 'edit' and return
78 79 end
79 80 @problem.description = @description
80 81 elsif @description
81 82 if !@description.update_attributes(params[:description])
82 83 flash[:notice] = 'Error saving description'
83 84 render :action => 'edit' and return
84 85 end
85 86 end
86 87 if params[:file] and params[:file].content_type != 'application/pdf'
87 88 flash[:notice] = 'Error: Uploaded file is not PDF'
88 89 render :action => 'edit' and return
89 90 end
90 91 if @problem.update_attributes(params[:problem])
91 92 flash[:notice] = 'Problem was successfully updated.'
92 93 unless params[:file] == nil or params[:file] == ''
93 94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
94 95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
95 96 if not FileTest.exists? out_dirname
96 97 Dir.mkdir out_dirname
97 98 end
98 99
99 100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
100 101 if FileTest.exists? out_filename
101 102 File.delete out_filename
102 103 end
103 104
104 105 File.open(out_filename,"wb") do |file|
105 106 file.write(params[:file].read)
106 107 end
107 108 @problem.description_filename = "#{@problem.name}.pdf"
108 109 @problem.save
109 110 end
110 111 redirect_to :action => 'show', :id => @problem
111 112 else
112 113 render :action => 'edit'
113 114 end
114 115 end
115 116
116 117 def destroy
117 118 p = Problem.find(params[:id]).destroy
118 119 redirect_to action: :index
119 120 end
120 121
121 122 def toggle
122 123 @problem = Problem.find(params[:id])
123 124 @problem.update_attributes(available: !(@problem.available) )
124 125 respond_to do |format|
125 126 format.js { }
126 127 end
127 128 end
128 129
129 130 def toggle_test
130 131 @problem = Problem.find(params[:id])
131 132 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
132 133 respond_to do |format|
133 134 format.js { }
134 135 end
135 136 end
136 137
137 138 def turn_all_off
138 139 Problem.available.all.each do |problem|
139 140 problem.available = false
140 141 problem.save
141 142 end
142 143 redirect_to action: :index
143 144 end
144 145
145 146 def turn_all_on
146 147 Problem.where.not(available: true).each do |problem|
147 148 problem.available = true
148 149 problem.save
149 150 end
150 151 redirect_to action: :index
151 152 end
152 153
153 154 def stat
154 155 @problem = Problem.find(params[:id])
155 156 unless @problem.available or session[:admin]
156 157 redirect_to :controller => 'main', :action => 'list'
157 158 return
158 159 end
159 160 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
160 161
161 162 #stat summary
162 163 range =65
163 164 @histogram = { data: Array.new(range,0), summary: {} }
164 165 user = Hash.new(0)
165 166 @submissions.find_each do |sub|
166 167 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
167 168 @histogram[:data][d.to_i] += 1 if d < range
168 169 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
169 170 end
170 171 @histogram[:summary][:max] = [@histogram[:data].max,1].max
171 172
172 173 @summary = { attempt: user.count, solve: 0 }
173 174 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
174 175 end
175 176
176 177 def manage
177 178 @problems = Problem.order(date_added: :desc)
178 179 end
179 180
180 181 def do_manage
181 182 if params.has_key? 'change_date_added'
182 183 change_date_added
183 184 elsif params.has_key? 'add_to_contest'
184 185 add_to_contest
185 186 elsif params.has_key? 'enable_problem'
186 187 set_available(true)
187 188 elsif params.has_key? 'disable_problem'
188 189 set_available(false)
189 190 end
190 191 redirect_to :action => 'manage'
191 192 end
192 193
193 194 def import
194 195 @allow_test_pair_import = allow_test_pair_import?
195 196 end
196 197
197 198 def do_import
198 199 old_problem = Problem.find_by_name(params[:name])
199 200 if !allow_test_pair_import? and params.has_key? :import_to_db
200 201 params.delete :import_to_db
201 202 end
202 203 @problem, import_log = Problem.create_from_import_form_params(params,
203 204 old_problem)
204 205
205 206 if !@problem.errors.empty?
206 207 render :action => 'import' and return
207 208 end
208 209
209 210 if old_problem!=nil
210 211 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
211 212 end
212 213 @log = import_log
213 214 end
214 215
215 216 def remove_contest
216 217 problem = Problem.find(params[:id])
217 218 contest = Contest.find(params[:contest_id])
218 219 if problem!=nil and contest!=nil
219 220 problem.contests.delete(contest)
220 221 end
221 222 redirect_to :action => 'manage'
222 223 end
223 224
225 + def show_testcase
226 + @problem = Problem.includes(:testcases).find(params[:id])
227 + end
228 +
224 229 ##################################
225 230 protected
226 231
227 232 def allow_test_pair_import?
228 233 if defined? ALLOW_TEST_PAIR_IMPORT
229 234 return ALLOW_TEST_PAIR_IMPORT
230 235 else
231 236 return false
232 237 end
233 238 end
234 239
235 240 def change_date_added
236 241 problems = get_problems_from_params
237 242 year = params[:date_added][:year].to_i
238 243 month = params[:date_added][:month].to_i
239 244 day = params[:date_added][:day].to_i
240 245 date = Date.new(year,month,day)
241 246 problems.each do |p|
242 247 p.date_added = date
243 248 p.save
244 249 end
245 250 end
246 251
247 252 def add_to_contest
248 253 problems = get_problems_from_params
249 254 contest = Contest.find(params[:contest][:id])
250 255 if contest!=nil and contest.enabled
251 256 problems.each do |p|
252 257 p.contests << contest
253 258 end
254 259 end
255 260 end
256 261
257 262 def set_available(avail)
258 263 problems = get_problems_from_params
259 264 problems.each do |p|
260 265 p.available = avail
261 266 p.save
262 267 end
263 268 end
264 269
265 270 def get_problems_from_params
266 271 problems = []
267 272 params.keys.each do |k|
268 273 if k.index('prob-')==0
269 274 name, id, order = k.split('-')
270 275 problems << Problem.find(id)
271 276 end
272 277 end
273 278 problems
274 279 end
275 280
276 281 def get_problems_stat
277 282 end
278 283
279 284 end
@@ -1,177 +1,183
1 1 require 'yaml'
2 2
3 3 #
4 4 # This class also contains various login of the system.
5 5 #
6 6 class GraderConfiguration < ActiveRecord::Base
7 7
8 8 SYSTEM_MODE_CONF_KEY = 'system.mode'
9 9 TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
10 10 MULTICONTESTS_KEY = 'system.multicontests'
11 11 CONTEST_TIME_LIMIT_KEY = 'contest.time_limit'
12 12 MULTIPLE_IP_LOGIN_KEY = 'right.multiple_ip_login'
13 + VIEW_TESTCASE = 'right.view_testcase'
14 + SINGLE_USER_KEY = 'system.single_user_mode'
13 15
14 16 cattr_accessor :config_cache
15 17 cattr_accessor :task_grading_info_cache
16 18 cattr_accessor :contest_time_str
17 19 cattr_accessor :contest_time
18 20
19 21 GraderConfiguration.config_cache = nil
20 22 GraderConfiguration.task_grading_info_cache = nil
21 23
22 24 def self.config_cached?
23 25 (defined? CONFIGURATION_CACHE_ENABLED) and (CONFIGURATION_CACHE_ENABLED)
24 26 end
25 27
26 28 def self.get(key)
27 29 if GraderConfiguration.config_cached?
28 30 if GraderConfiguration.config_cache == nil
29 31 self.read_config
30 32 end
31 33 return GraderConfiguration.config_cache[key]
32 34 else
33 35 return GraderConfiguration.read_one_key(key)
34 36 end
35 37 end
36 38
37 39 def self.[](key)
38 40 self.get(key)
39 41 end
40 42
41 43 def self.reload
42 44 self.read_config
43 45 end
44 46
45 47 def self.clear
46 48 GraderConfiguration.config_cache = nil
47 49 end
48 50
49 51 #
50 52 # View decision
51 53 #
52 54 def self.show_submitbox_to?(user)
53 55 mode = get(SYSTEM_MODE_CONF_KEY)
54 56 return false if mode=='analysis'
55 57 if (mode=='contest')
56 58 return false if (user.site!=nil) and
57 59 ((user.site.started!=true) or (user.site.finished?))
58 60 end
59 61 return true
60 62 end
61 63
62 64 def self.show_tasks_to?(user)
63 65 if time_limit_mode?
64 66 return false if not user.contest_started?
65 67 end
66 68 return true
67 69 end
68 70
69 71 def self.show_grading_result
70 72 return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
71 73 end
72 74
75 + def self.show_testcase
76 + return get(VIEW_TESTCASE)
77 + end
78 +
73 79 def self.allow_test_request(user)
74 80 mode = get(SYSTEM_MODE_CONF_KEY)
75 81 early_timeout = get(TEST_REQUEST_EARLY_TIMEOUT_KEY)
76 82 if (mode=='contest')
77 83 return false if ((user.site!=nil) and
78 84 ((user.site.started!=true) or
79 85 (early_timeout and (user.site.time_left < 30.minutes))))
80 86 end
81 87 return false if mode=='analysis'
82 88 return true
83 89 end
84 90
85 91 def self.task_grading_info
86 92 if GraderConfiguration.task_grading_info_cache==nil
87 93 read_grading_info
88 94 end
89 95 return GraderConfiguration.task_grading_info_cache
90 96 end
91 97
92 98 def self.standard_mode?
93 99 return get(SYSTEM_MODE_CONF_KEY) == 'standard'
94 100 end
95 101
96 102 def self.contest_mode?
97 103 return get(SYSTEM_MODE_CONF_KEY) == 'contest'
98 104 end
99 105
100 106 def self.indv_contest_mode?
101 107 return get(SYSTEM_MODE_CONF_KEY) == 'indv-contest'
102 108 end
103 109
104 110 def self.multicontests?
105 111 return get(MULTICONTESTS_KEY) == true
106 112 end
107 113
108 114 def self.time_limit_mode?
109 115 mode = get(SYSTEM_MODE_CONF_KEY)
110 116 return ((mode == 'contest') or (mode == 'indv-contest'))
111 117 end
112 118
113 119 def self.analysis_mode?
114 120 return get(SYSTEM_MODE_CONF_KEY) == 'analysis'
115 121 end
116 122
117 123 def self.contest_time_limit
118 124 contest_time_str = GraderConfiguration[CONTEST_TIME_LIMIT_KEY]
119 125
120 126 if not defined? GraderConfiguration.contest_time_str
121 127 GraderConfiguration.contest_time_str = nil
122 128 end
123 129
124 130 if GraderConfiguration.contest_time_str != contest_time_str
125 131 GraderConfiguration.contest_time_str = contest_time_str
126 132 if tmatch = /(\d+):(\d+)/.match(contest_time_str)
127 133 h = tmatch[1].to_i
128 134 m = tmatch[2].to_i
129 135
130 136 GraderConfiguration.contest_time = h.hour + m.minute
131 137 else
132 138 GraderConfiguration.contest_time = nil
133 139 end
134 140 end
135 141 return GraderConfiguration.contest_time
136 142 end
137 143
138 144 protected
139 145
140 146 def self.convert_type(val,type)
141 147 case type
142 148 when 'string'
143 149 return val
144 150
145 151 when 'integer'
146 152 return val.to_i
147 153
148 154 when 'boolean'
149 155 return (val=='true')
150 156 end
151 157 end
152 158
153 159 def self.read_config
154 160 GraderConfiguration.config_cache = {}
155 161 GraderConfiguration.all.each do |conf|
156 162 key = conf.key
157 163 val = conf.value
158 164 GraderConfiguration.config_cache[key] = GraderConfiguration.convert_type(val,conf.value_type)
159 165 end
160 166 end
161 167
162 168 def self.read_one_key(key)
163 169 conf = GraderConfiguration.find_by_key(key)
164 170 if conf
165 171 return GraderConfiguration.convert_type(conf.value,conf.value_type)
166 172 else
167 173 return nil
168 174 end
169 175 end
170 176
171 177 def self.read_grading_info
172 178 f = File.open(TASK_GRADING_INFO_FILENAME)
173 179 GraderConfiguration.task_grading_info_cache = YAML.load(f)
174 180 f.close
175 181 end
176 182
177 183 end
@@ -1,39 +1,39
1 1 %b= GraderConfiguration['ui.front.welcome_message']
2 2 %br/
3 3
4 4 - if !@hidelogin
5 5 =t 'login.message'
6 6 %br/
7 7 %br/
8 8
9 9 - if flash[:notice]
10 10 %hr/
11 11 %b= flash[:notice]
12 12 %hr/
13 13
14 14 %div{ :style => "border: solid 1px gray; padding: 4px; background: #eeeeff;"}
15 - = form_tag :controller => 'login', :action => 'login' do
15 + = form_tag login_login_path do
16 16 %table
17 17 %tr
18 18 %td{:align => "right"}
19 19 ="#{t 'login_label'}:"
20 20 %td= text_field_tag 'login'
21 21 %tr
22 22 %td{:align => "right"}
23 23 ="#{t 'password_label'}:"
24 24 %td= password_field_tag
25 25 - unless GraderConfiguration['right.bypass_agreement']
26 26 %tr
27 27 %td{:align => "right"}= check_box_tag 'accept_agree'
28 28 %td ยอมรับข้อตกลงการใช้งาน
29 29
30 30 = submit_tag t('login.login_submit')
31 31 %br/
32 32
33 33 - if GraderConfiguration['system.online_registration']
34 34 =t 'login.participation'
35 35 %b
36 36 = "#{t 'login.please'} "
37 37 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
38 38 %br/
39 39 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
@@ -1,27 +1,29
1 1
2 2 - if submission.nil?
3 3 = "-"
4 4 - else
5 5 - unless submission.graded_at
6 6 = t 'main.submitted_at'
7 7 = format_short_time(submission.submitted_at.localtime)
8 8 - else
9 9 %strong= t 'main.graded_at'
10 10 = "#{format_short_time(submission.graded_at.localtime)} "
11 11 %br
12 12 - if GraderConfiguration['ui.show_score']
13 13 %strong=t 'main.score'
14 14 = "#{(submission.points*100/submission.problem.full_score).to_i} "
15 15 = " ["
16 16 %tt
17 17 = submission.grader_comment
18 18 = "]"
19 19 %br
20 20 %strong View:
21 21 - if GraderConfiguration.show_grading_result
22 22 = link_to '[detailed result]', :action => 'result', :id => submission.id
23 23 /= link_to "#{t 'main.cmp_msg'}", {:action => 'compiler_msg', :id => submission.id}, {popup: true,class: 'btn btn-xs btn-info'}
24 24 = link_to "#{t 'main.cmp_msg'}", compiler_msg_submission_path(submission.id), {popup: true,remote: true,class: 'btn btn-xs btn-info'}
25 25 = link_to "#{t 'main.src_link'}",{:action => 'source', :id => submission.id}, class: 'btn btn-xs btn-info'
26 26 = link_to "#{t 'main.submissions_link'}", problem_submissions_path(problem_id), class: 'btn btn-xs btn-info'
27 + - if GraderConfiguration.show_testcase
28 + = link_to "testcases", show_testcase_problem_path(problem_id), class: 'btn btn-xs btn-info'
27 29
@@ -1,52 +1,63
1 1 - content_for :head do
2 2 = javascript_include_tag "announcement_refresh"
3 3
4 4 = user_title_bar(@user)
5 5
6 6 - if (GraderConfiguration.contest_mode?) and (@user.site!=nil) and (@user.site.started!=true)
7 7 %p=t 'main.start_soon'
8 8
9 9 .row
10 10 .col-md-7
11 11 - if GraderConfiguration.show_submitbox_to?(@user)
12 12 .panel.panel-primary
13 13 .panel-heading
14 14 Submission
15 15 .panel-body
16 16 = render :partial => 'submission_box'
17 17 - if GraderConfiguration.show_tasks_to?(@user)
18 18 - if not GraderConfiguration.multicontests?
19 19 %table.table.table-striped.table-condensed
20 20 %thead
21 21 %tr
22 22 %th Task name
23 23 %th Full name
24 24 %th # of sub(s)
25 25 %th Results
26 26 %th
27 27 %tbody
28 28 = render :partial => 'problem', :collection => @problems
29 29 - else
30 30 - @contest_problems.each do |cp|
31 31 - if cp[:problems].length > 0
32 32 %h2{:class =>'contest-title'}
33 33 = "#{cp[:contest] ? cp[:contest].title : 'Public problems'}"
34 34 %table.info
35 35 %tr.info-head
36 36 %th Task name
37 37 %th Full name
38 38 %th # of sub(s)
39 39 %th Results
40 40 %th
41 41 = render :partial => 'problem', :collection => cp[:problems]
42 42 .col-md-5
43 43 .panel.panel-info
44 44 .panel-heading
45 45 Announcement
46 46 %ul.list-group
47 47 = render :partial => 'announcement', :collection => @announcements
48 48
49 49 %script{:type => 'text/javascript'}
50 50 = "Announcement.refreshUrl = '#{url_for :controller => 'main', :action => 'announcements'}';"
51 51 Announcement.registerRefreshEventTimer();
52 52
53 + .modal.fade#compiler{tabindex: -1,role: 'dialog'}
54 + .modal-dialog.modal-lg{role:'document'}
55 + .modal-content
56 + .modal-header
57 + %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
58 + %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
59 + %h4 Compiler message
60 + .modal-body
61 + %pre#compiler_msg
62 + .modal-footer
63 + %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
@@ -1,3 +1,4
1 - :javascript
2 - $("#compiler_msg").html("#{j @submissionhcompiler_msg}")
1 + :plain
2 + $("#compiler_msg").html("#{j @submission.compiler_message}");
3 + $("#compiler").modal();
3 4
@@ -1,2 +1,2
1 - :javascript
1 + :plain
2 2 $("#latest_status").html("#{j render({partial: 'submission_short', locals: {submission: @submission, problem_name: @problem.name}})}")
@@ -1,77 +1,88
1 1 CafeGrader::Application.routes.draw do
2 2 get "sources/direct_edit"
3 3
4 4 root :to => 'main#login'
5 5
6 + #logins
7 + get 'login/login', to: 'login#login'
8 +
6 9 resources :contests
7 10
8 11 resources :sites
9 12
10 13 resources :announcements do
11 14 member do
12 15 get 'toggle','toggle_front'
13 16 end
14 17 end
15 18
16 19 resources :problems do
17 20 member do
18 21 get 'toggle'
19 22 get 'toggle_test'
20 23 get 'stat'
24 + get 'show_testcase'
21 25 end
22 26 collection do
23 27 get 'turn_all_off'
24 28 get 'turn_all_on'
25 29 get 'import'
26 30 get 'manage'
27 31 end
32 +
33 + resources :testcases, only: [] do
34 + member do
35 + get 'download_input'
36 + get 'download_sol'
37 + end
38 + end
28 39 end
29 40
30 41 resources :grader_configuration, controller: 'configurations'
31 42
32 43 resources :users do
33 44 member do
34 45 get 'toggle_activate', 'toggle_enable'
35 46 get 'stat'
36 47 end
37 48 end
38 49
39 50 resources :submissions do
40 51 member do
41 52 get 'download'
42 53 get 'compiler_msg'
43 54 end
44 55 collection do
45 56 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
46 57 get 'direct_edit_problem/:problem_id', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
47 58 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
48 59 end
49 60 end
50 61
51 62 get 'tasks/view/:file.:ext' => 'tasks#view'
52 63 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
53 64 get 'heartbeat/:id/edit' => 'heartbeat#edit'
54 65
55 66 #main
56 67 get "main/list"
57 68 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
58 69
59 70 #report
60 71 get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
61 72 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
62 73 get "report/login"
63 74 get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
64 75 post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
65 76
66 77 #grader
67 78 get 'graders/list', to: 'graders#list', as: 'grader_list'
68 79
69 80
70 81 get 'heartbeat/:id/edit' => 'heartbeat#edit'
71 82
72 83 # See how all your routes lay out with "rake routes"
73 84
74 85 # This is a legacy wild controller route that's not recommended for RESTful applications.
75 86 # Note: This route will make all actions in every controller accessible via GET requests.
76 87 match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
77 88 end
@@ -1,280 +1,280
1 1 # encoding: UTF-8
2 2 # This file is auto-generated from the current state of the database. Instead
3 3 # of editing this file, please use the migrations feature of Active Record to
4 4 # incrementally modify your database, and then regenerate this schema definition.
5 5 #
6 6 # Note that this schema.rb definition is the authoritative source for your
7 7 # database schema. If you need to create the application database on another
8 8 # system, you should be using db:schema:load, not running all the migrations
9 9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 11 #
12 12 # It's strongly recommended that you check this file into your version control system.
13 13
14 14 ActiveRecord::Schema.define(version: 20161031063337) do
15 15
16 16 create_table "announcements", force: :cascade do |t|
17 - t.string "author"
18 - t.text "body"
17 + t.string "author", limit: 255
18 + t.text "body", limit: 65535
19 19 t.boolean "published"
20 20 t.datetime "created_at", null: false
21 21 t.datetime "updated_at", null: false
22 22 t.boolean "frontpage", default: false
23 23 t.boolean "contest_only", default: false
24 - t.string "title"
25 - t.string "notes"
24 + t.string "title", limit: 255
25 + t.string "notes", limit: 255
26 26 end
27 27
28 28 create_table "contests", force: :cascade do |t|
29 - t.string "title"
29 + t.string "title", limit: 255
30 30 t.boolean "enabled"
31 31 t.datetime "created_at", null: false
32 32 t.datetime "updated_at", null: false
33 - t.string "name"
33 + t.string "name", limit: 255
34 34 end
35 35
36 36 create_table "contests_problems", id: false, force: :cascade do |t|
37 - t.integer "contest_id"
38 - t.integer "problem_id"
37 + t.integer "contest_id", limit: 4
38 + t.integer "problem_id", limit: 4
39 39 end
40 40
41 41 create_table "contests_users", id: false, force: :cascade do |t|
42 - t.integer "contest_id"
43 - t.integer "user_id"
42 + t.integer "contest_id", limit: 4
43 + t.integer "user_id", limit: 4
44 44 end
45 45
46 46 create_table "countries", force: :cascade do |t|
47 - t.string "name"
47 + t.string "name", limit: 255
48 48 t.datetime "created_at", null: false
49 49 t.datetime "updated_at", null: false
50 50 end
51 51
52 52 create_table "descriptions", force: :cascade do |t|
53 - t.text "body"
53 + t.text "body", limit: 65535
54 54 t.boolean "markdowned"
55 55 t.datetime "created_at", null: false
56 56 t.datetime "updated_at", null: false
57 57 end
58 58
59 59 create_table "grader_configurations", force: :cascade do |t|
60 - t.string "key"
61 - t.string "value_type"
62 - t.string "value"
60 + t.string "key", limit: 255
61 + t.string "value_type", limit: 255
62 + t.string "value", limit: 255
63 63 t.datetime "created_at", null: false
64 64 t.datetime "updated_at", null: false
65 - t.text "description"
65 + t.text "description", limit: 65535
66 66 end
67 67
68 68 create_table "grader_processes", force: :cascade do |t|
69 - t.string "host"
70 - t.integer "pid"
71 - t.string "mode"
69 + t.string "host", limit: 255
70 + t.integer "pid", limit: 4
71 + t.string "mode", limit: 255
72 72 t.boolean "active"
73 73 t.datetime "created_at", null: false
74 74 t.datetime "updated_at", null: false
75 - t.integer "task_id"
76 - t.string "task_type"
75 + t.integer "task_id", limit: 4
76 + t.string "task_type", limit: 255
77 77 t.boolean "terminated"
78 78 end
79 79
80 - add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
80 + add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid", using: :btree
81 81
82 82 create_table "heart_beats", force: :cascade do |t|
83 - t.integer "user_id"
84 - t.string "ip_address"
83 + t.integer "user_id", limit: 4
84 + t.string "ip_address", limit: 255
85 85 t.datetime "created_at", null: false
86 86 t.datetime "updated_at", null: false
87 - t.string "status"
87 + t.string "status", limit: 255
88 88 end
89 89
90 - add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at"
90 + add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at", using: :btree
91 91
92 92 create_table "languages", force: :cascade do |t|
93 93 t.string "name", limit: 10
94 - t.string "pretty_name"
94 + t.string "pretty_name", limit: 255
95 95 t.string "ext", limit: 10
96 - t.string "common_ext"
96 + t.string "common_ext", limit: 255
97 97 end
98 98
99 99 create_table "logins", force: :cascade do |t|
100 - t.integer "user_id"
101 - t.string "ip_address"
100 + t.integer "user_id", limit: 4
101 + t.string "ip_address", limit: 255
102 102 t.datetime "created_at", null: false
103 103 t.datetime "updated_at", null: false
104 104 end
105 105
106 106 create_table "messages", force: :cascade do |t|
107 - t.integer "sender_id"
108 - t.integer "receiver_id"
109 - t.integer "replying_message_id"
110 - t.text "body"
107 + t.integer "sender_id", limit: 4
108 + t.integer "receiver_id", limit: 4
109 + t.integer "replying_message_id", limit: 4
110 + t.text "body", limit: 65535
111 111 t.boolean "replied"
112 112 t.datetime "created_at", null: false
113 113 t.datetime "updated_at", null: false
114 114 end
115 115
116 116 create_table "problems", force: :cascade do |t|
117 117 t.string "name", limit: 30
118 - t.string "full_name"
119 - t.integer "full_score"
118 + t.string "full_name", limit: 255
119 + t.integer "full_score", limit: 4
120 120 t.date "date_added"
121 121 t.boolean "available"
122 - t.string "url"
123 - t.integer "description_id"
122 + t.string "url", limit: 255
123 + t.integer "description_id", limit: 4
124 124 t.boolean "test_allowed"
125 125 t.boolean "output_only"
126 - t.string "description_filename"
126 + t.string "description_filename", limit: 255
127 127 end
128 128
129 129 create_table "rights", force: :cascade do |t|
130 - t.string "name"
131 - t.string "controller"
132 - t.string "action"
130 + t.string "name", limit: 255
131 + t.string "controller", limit: 255
132 + t.string "action", limit: 255
133 133 end
134 134
135 135 create_table "rights_roles", id: false, force: :cascade do |t|
136 - t.integer "right_id"
137 - t.integer "role_id"
136 + t.integer "right_id", limit: 4
137 + t.integer "role_id", limit: 4
138 138 end
139 139
140 - add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id"
140 + add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree
141 141
142 142 create_table "roles", force: :cascade do |t|
143 - t.string "name"
143 + t.string "name", limit: 255
144 144 end
145 145
146 146 create_table "roles_users", id: false, force: :cascade do |t|
147 - t.integer "role_id"
148 - t.integer "user_id"
147 + t.integer "role_id", limit: 4
148 + t.integer "user_id", limit: 4
149 149 end
150 150
151 - add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id"
151 + add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree
152 152
153 153 create_table "sessions", force: :cascade do |t|
154 - t.string "session_id"
155 - t.text "data"
154 + t.string "session_id", limit: 255
155 + t.text "data", limit: 65535
156 156 t.datetime "updated_at"
157 157 end
158 158
159 - add_index "sessions", ["session_id"], name: "index_sessions_on_session_id"
160 - add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at"
159 + add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree
160 + add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree
161 161
162 162 create_table "sites", force: :cascade do |t|
163 - t.string "name"
163 + t.string "name", limit: 255
164 164 t.boolean "started"
165 165 t.datetime "start_time"
166 166 t.datetime "created_at", null: false
167 167 t.datetime "updated_at", null: false
168 - t.integer "country_id"
169 - t.string "password"
168 + t.integer "country_id", limit: 4
169 + t.string "password", limit: 255
170 170 end
171 171
172 172 create_table "submission_view_logs", force: :cascade do |t|
173 - t.integer "user_id"
174 - t.integer "submission_id"
173 + t.integer "user_id", limit: 4
174 + t.integer "submission_id", limit: 4
175 175 t.datetime "created_at", null: false
176 176 t.datetime "updated_at", null: false
177 177 end
178 178
179 179 create_table "submissions", force: :cascade do |t|
180 - t.integer "user_id"
181 - t.integer "problem_id"
182 - t.integer "language_id"
183 - t.text "source"
184 - t.binary "binary"
180 + t.integer "user_id", limit: 4
181 + t.integer "problem_id", limit: 4
182 + t.integer "language_id", limit: 4
183 + t.text "source", limit: 65535
184 + t.binary "binary", limit: 65535
185 185 t.datetime "submitted_at"
186 186 t.datetime "compiled_at"
187 - t.text "compiler_message"
187 + t.text "compiler_message", limit: 65535
188 188 t.datetime "graded_at"
189 - t.integer "points"
190 - t.text "grader_comment"
191 - t.integer "number"
192 - t.string "source_filename"
193 - t.float "max_runtime"
194 - t.integer "peak_memory"
195 - t.integer "effective_code_length"
196 - t.string "ip_address"
189 + t.integer "points", limit: 4
190 + t.text "grader_comment", limit: 65535
191 + t.integer "number", limit: 4
192 + t.string "source_filename", limit: 255
193 + t.float "max_runtime", limit: 24
194 + t.integer "peak_memory", limit: 4
195 + t.integer "effective_code_length", limit: 4
196 + t.string "ip_address", limit: 255
197 197 end
198 198
199 - add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
200 - add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
199 + add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree
200 + add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree
201 201
202 202 create_table "tasks", force: :cascade do |t|
203 - t.integer "submission_id"
203 + t.integer "submission_id", limit: 4
204 204 t.datetime "created_at"
205 - t.integer "status"
205 + t.integer "status", limit: 4
206 206 t.datetime "updated_at"
207 207 end
208 208
209 209 create_table "test_pairs", force: :cascade do |t|
210 - t.integer "problem_id"
210 + t.integer "problem_id", limit: 4
211 211 t.text "input", limit: 16777215
212 212 t.text "solution", limit: 16777215
213 213 t.datetime "created_at", null: false
214 214 t.datetime "updated_at", null: false
215 215 end
216 216
217 217 create_table "test_requests", force: :cascade do |t|
218 - t.integer "user_id"
219 - t.integer "problem_id"
220 - t.integer "submission_id"
221 - t.string "input_file_name"
222 - t.string "output_file_name"
223 - t.string "running_stat"
224 - t.integer "status"
218 + t.integer "user_id", limit: 4
219 + t.integer "problem_id", limit: 4
220 + t.integer "submission_id", limit: 4
221 + t.string "input_file_name", limit: 255
222 + t.string "output_file_name", limit: 255
223 + t.string "running_stat", limit: 255
224 + t.integer "status", limit: 4
225 225 t.datetime "updated_at", null: false
226 226 t.datetime "submitted_at"
227 227 t.datetime "compiled_at"
228 - t.text "compiler_message"
228 + t.text "compiler_message", limit: 65535
229 229 t.datetime "graded_at"
230 - t.string "grader_comment"
230 + t.string "grader_comment", limit: 255
231 231 t.datetime "created_at", null: false
232 - t.float "running_time"
233 - t.string "exit_status"
234 - t.integer "memory_usage"
232 + t.float "running_time", limit: 24
233 + t.string "exit_status", limit: 255
234 + t.integer "memory_usage", limit: 4
235 235 end
236 236
237 - add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
237 + add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree
238 238
239 239 create_table "testcases", force: :cascade do |t|
240 - t.integer "problem_id"
241 - t.integer "num"
242 - t.integer "group"
243 - t.integer "score"
244 - t.text "input"
245 - t.text "sol"
246 - t.datetime "created_at", null: false
247 - t.datetime "updated_at", null: false
240 + t.integer "problem_id", limit: 4
241 + t.integer "num", limit: 4
242 + t.integer "group", limit: 4
243 + t.integer "score", limit: 4
244 + t.text "input", limit: 65535
245 + t.text "sol", limit: 65535
246 + t.datetime "created_at"
247 + t.datetime "updated_at"
248 248 end
249 249
250 - add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id"
250 + add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree
251 251
252 252 create_table "user_contest_stats", force: :cascade do |t|
253 - t.integer "user_id"
253 + t.integer "user_id", limit: 4
254 254 t.datetime "started_at"
255 255 t.datetime "created_at", null: false
256 256 t.datetime "updated_at", null: false
257 257 t.boolean "forced_logout"
258 258 end
259 259
260 260 create_table "users", force: :cascade do |t|
261 261 t.string "login", limit: 50
262 - t.string "full_name"
263 - t.string "hashed_password"
262 + t.string "full_name", limit: 255
263 + t.string "hashed_password", limit: 255
264 264 t.string "salt", limit: 5
265 - t.string "alias"
266 - t.string "email"
267 - t.integer "site_id"
268 - t.integer "country_id"
265 + t.string "alias", limit: 255
266 + t.string "email", limit: 255
267 + t.integer "site_id", limit: 4
268 + t.integer "country_id", limit: 4
269 269 t.boolean "activated", default: false
270 270 t.datetime "created_at"
271 271 t.datetime "updated_at"
272 272 t.boolean "enabled", default: true
273 - t.string "remark"
274 - t.string "last_ip"
275 - t.string "section"
273 + t.string "remark", limit: 255
274 + t.string "last_ip", limit: 255
275 + t.string "section", limit: 255
276 276 end
277 277
278 - add_index "users", ["login"], name: "index_users_on_login", unique: true
278 + add_index "users", ["login"], name: "index_users_on_login", unique: true, using: :btree
279 279
280 280 end
@@ -1,245 +1,251
1 1 CONFIGURATIONS =
2 2 [
3 3 {
4 4 :key => 'system.single_user_mode',
5 5 :value_type => 'boolean',
6 6 :default_value => 'false',
7 7 :description => 'Only admins can log in to the system when running under single user mode.'
8 8 },
9 9
10 10 {
11 11 :key => 'ui.front.title',
12 12 :value_type => 'string',
13 13 :default_value => 'Grader'
14 14 },
15 15
16 16 {
17 17 :key => 'ui.front.welcome_message',
18 18 :value_type => 'string',
19 19 :default_value => 'Welcome!'
20 20 },
21 21
22 22 {
23 23 :key => 'ui.show_score',
24 24 :value_type => 'boolean',
25 25 :default_value => 'true'
26 26 },
27 27
28 28 {
29 29 :key => 'contest.time_limit',
30 30 :value_type => 'string',
31 31 :default_value => 'unlimited',
32 32 :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits. This config is CACHED. Restart the server before the change can take effect.'
33 33 },
34 34
35 35 {
36 36 :key => 'system.mode',
37 37 :value_type => 'string',
38 38 :default_value => 'standard',
39 39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 40 },
41 41
42 42 {
43 43 :key => 'contest.name',
44 44 :value_type => 'string',
45 45 :default_value => 'Grader',
46 46 :description => 'This name will be shown on the user header bar.'
47 47 },
48 48
49 49 {
50 50 :key => 'contest.multisites',
51 51 :value_type => 'boolean',
52 52 :default_value => 'false',
53 53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
54 54 },
55 55
56 56 #---------------------------- right --------------------------------
57 57 {
58 58 :key => 'right.user_hall_of_fame',
59 59 :value_type => 'boolean',
60 60 :default_value => 'false',
61 61 :description => 'If true, any user can access hall of fame page.'
62 62 },
63 63
64 64 {
65 65 :key => 'right.multiple_ip_login',
66 66 :value_type => 'boolean',
67 67 :default_value => 'true',
68 68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
69 69 },
70 70
71 71 {
72 72 :key => 'right.user_view_submission',
73 73 :value_type => 'boolean',
74 74 :default_value => 'false',
75 75 :description => 'If true, any user can view submissions of every one.'
76 76 },
77 77
78 78 {
79 79 :key => 'right.bypass_agreement',
80 80 :value_type => 'boolean',
81 81 :default_value => 'true',
82 82 :description => 'When false, a user must accept usage agreement before login'
83 83 },
84 84
85 85 {
86 86 :key => 'right.heartbeat_response',
87 87 :value_type => 'string',
88 88 :default_value => 'OK',
89 89 :description => 'Heart beat response text'
90 90 },
91 91
92 + {
93 + :key => 'right.view_testcase',
94 + :value_type => 'boolean',
95 + :default_value => 'false',
96 + :description => 'When true, any user can view/download test data'
97 + },
92 98 # If Configuration['system.online_registration'] is true, the
93 99 # system allows online registration, and will use these
94 100 # information for sending confirmation emails.
95 101 {
96 102 :key => 'system.online_registration.smtp',
97 103 :value_type => 'string',
98 104 :default_value => 'smtp.somehost.com'
99 105 },
100 106
101 107 {
102 108 :key => 'system.online_registration.from',
103 109 :value_type => 'string',
104 110 :default_value => 'your.email@address'
105 111 },
106 112
107 113 {
108 114 :key => 'system.admin_email',
109 115 :value_type => 'string',
110 116 :default_value => 'admin@admin.email'
111 117 },
112 118
113 119 {
114 120 :key => 'system.user_setting_enabled',
115 121 :value_type => 'boolean',
116 122 :default_value => 'true',
117 123 :description => 'If this option is true, users can change their settings'
118 124 },
119 125
120 126 {
121 127 :key => 'system.user_setting_enabled',
122 128 :value_type => 'boolean',
123 129 :default_value => 'true',
124 130 :description => 'If this option is true, users can change their settings'
125 131 },
126 132
127 133 # If Configuration['contest.test_request.early_timeout'] is true
128 134 # the user will not be able to use test request at 30 minutes
129 135 # before the contest ends.
130 136 {
131 137 :key => 'contest.test_request.early_timeout',
132 138 :value_type => 'boolean',
133 139 :default_value => 'false'
134 140 },
135 141
136 142 {
137 143 :key => 'system.multicontests',
138 144 :value_type => 'boolean',
139 145 :default_value => 'false'
140 146 },
141 147
142 148 {
143 149 :key => 'contest.confirm_indv_contest_start',
144 150 :value_type => 'boolean',
145 151 :default_value => 'false'
146 152 },
147 153
148 154 {
149 155 :key => 'contest.default_contest_name',
150 156 :value_type => 'string',
151 157 :default_value => 'none',
152 158 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
153 159 }
154 160
155 161 ]
156 162
157 163
158 164 def create_configuration_key(key,
159 165 value_type,
160 166 default_value,
161 167 description='')
162 168 conf = (GraderConfiguration.find_by_key(key) ||
163 169 GraderConfiguration.new(:key => key,
164 170 :value_type => value_type,
165 171 :value => default_value))
166 172 conf.description = description
167 173 conf.save
168 174 end
169 175
170 176 def seed_config
171 177 CONFIGURATIONS.each do |conf|
172 178 if conf.has_key? :description
173 179 desc = conf[:description]
174 180 else
175 181 desc = ''
176 182 end
177 183 create_configuration_key(conf[:key],
178 184 conf[:value_type],
179 185 conf[:default_value],
180 186 desc)
181 187 end
182 188 end
183 189
184 190 def seed_roles
185 191 return if Role.find_by_name('admin')
186 192
187 193 role = Role.create(:name => 'admin')
188 194 user_admin_right = Right.create(:name => 'user_admin',
189 195 :controller => 'user_admin',
190 196 :action => 'all')
191 197 problem_admin_right = Right.create(:name=> 'problem_admin',
192 198 :controller => 'problems',
193 199 :action => 'all')
194 200
195 201 graders_right = Right.create(:name => 'graders_admin',
196 202 :controller => 'graders',
197 203 :action => 'all')
198 204
199 205 role.rights << user_admin_right;
200 206 role.rights << problem_admin_right;
201 207 role.rights << graders_right;
202 208 role.save
203 209 end
204 210
205 211 def seed_root
206 212 return if User.find_by_login('root')
207 213
208 214 root = User.new(:login => 'root',
209 215 :full_name => 'Administrator',
210 216 :alias => 'root')
211 217 root.password = 'ioionrails';
212 218
213 219 class << root
214 220 public :encrypt_new_password
215 221 def valid?(context=nil)
216 222 true
217 223 end
218 224 end
219 225
220 226 root.encrypt_new_password
221 227
222 228 root.roles << Role.find_by_name('admin')
223 229
224 230 root.activated = true
225 231 root.save
226 232 end
227 233
228 234 def seed_users_and_roles
229 235 seed_roles
230 236 seed_root
231 237 end
232 238
233 239 def seed_more_languages
234 240 Language.delete_all
235 241 Language.create( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
236 242 Language.create( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
237 243 Language.create( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
238 244 Language.create( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
239 245 Language.create( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
240 246 Language.create( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
241 247 end
242 248
243 249 seed_config
244 250 seed_users_and_roles
245 251 seed_more_languages
@@ -1,58 +1,73
1 1 module GraderScript
2 2
3 3 def self.grader_control_enabled?
4 4 if defined? GRADER_ROOT_DIR
5 5 GRADER_ROOT_DIR != ''
6 6 else
7 7 false
8 8 end
9 9 end
10 10
11 11 def self.raw_dir
12 12 File.join GRADER_ROOT_DIR, "raw"
13 13 end
14 14
15 15 def self.call_grader(params)
16 16 if GraderScript.grader_control_enabled?
17 17 cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
18 18 system(cmd)
19 19 end
20 20 end
21 21
22 22 def self.stop_grader(pid)
23 23 GraderScript.call_grader "stop #{pid}"
24 24 end
25 25
26 26 def self.stop_graders(pids)
27 27 pid_str = (pids.map { |process| process.pid.to_s }).join ' '
28 28 GraderScript.call_grader "stop #{pid_str}"
29 29 end
30 30
31 31 def self.start_grader(env)
32 32 GraderScript.call_grader "#{env} queue --err-log &"
33 33 GraderScript.call_grader "#{env} test_request -err-log &"
34 34 end
35 35
36 36 def self.call_import_problem(problem_name,
37 37 problem_dir,
38 38 time_limit=1,
39 39 memory_limit=32,
40 40 checker_name='text')
41 41 if GraderScript.grader_control_enabled?
42 42 cur_dir = `pwd`.chomp
43 43 Dir.chdir(GRADER_ROOT_DIR)
44 44
45 45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 47 " -t #{time_limit} -m #{memory_limit}"
48 48
49 49 output = `#{cmd}`
50 50
51 51 Dir.chdir(cur_dir)
52 52
53 53 return "import CMD: #{cmd}\n" + output
54 54 end
55 55 return ''
56 56 end
57 57
58 + def self.call_import_testcase(problem_name)
59 + if GraderScript.grader_control_enabled?
60 + cur_dir = `pwd`.chomp
61 + Dir.chdir(GRADER_ROOT_DIR)
62 +
63 + script_name = File.join(GRADER_ROOT_DIR, "scripts/load_testcase")
64 + cmd = "#{script_name} #{problem_name}"
65 +
66 + output = `#{cmd}`
67 +
68 + Dir.chdir(cur_dir)
69 + return "Testcase import result:\n" + output
58 70 end
71 + end
72 +
73 + end
@@ -1,190 +1,193
1 1 require 'tmpdir'
2 2
3 3 class TestdataImporter
4 4
5 5 attr :log_msg
6 6
7 7 def initialize(problem)
8 8 @problem = problem
9 9 end
10 10
11 11 def import_from_file(tempfile,
12 12 time_limit,
13 13 memory_limit,
14 14 checker_name='text',
15 15 import_to_db=false)
16 16
17 17 dirname = extract(tempfile)
18 18 return false if not dirname
19 19 if not import_to_db
20 20 @log_msg = GraderScript.call_import_problem(@problem.name,
21 21 dirname,
22 22 time_limit,
23 23 memory_limit,
24 24 checker_name)
25 25 else
26 26 # Import test data to test pairs.
27 27
28 28 @problem.test_pairs.clear
29 29 if import_test_pairs(dirname)
30 30 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
31 31 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
32 32 else
33 33 @log_msg = "Importing test pair failed. (0 test pairs imported)"
34 34 end
35 35 end
36 36
37 37 @log_msg << import_problem_description(dirname)
38 38 @log_msg << import_problem_pdf(dirname)
39 39 @log_msg << import_full_score(dirname)
40 40
41 + #import test data
42 + @log_msg << GraderScript.call_import_testcase(@problem.name)
43 +
41 44 return true
42 45 end
43 46
44 47 protected
45 48
46 49 def self.long_ext(filename)
47 50 i = filename.index('.')
48 51 len = filename.length
49 52 return filename.slice(i..len)
50 53 end
51 54
52 55 def extract(tempfile)
53 56 testdata_filename = save_testdata_file(tempfile)
54 57 ext = TestdataImporter.long_ext(tempfile.original_filename)
55 58
56 59 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
57 60 if File.exists? extract_dir
58 61 backup_count = 0
59 62 begin
60 63 backup_count += 1
61 64 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
62 65 end while File.exists? backup_dirname
63 66 File.rename(extract_dir, backup_dirname)
64 67 end
65 68 Dir.mkdir extract_dir
66 69
67 70 if ext=='.tar.gz' or ext=='.tgz'
68 71 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
69 72 elsif ext=='.tar'
70 73 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
71 74 elsif ext=='.zip'
72 75 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
73 76 else
74 77 return nil
75 78 end
76 79
77 80 system(cmd)
78 81
79 82 files = Dir["#{extract_dir}/**/*1*.in"]
80 83 return nil if files.length==0
81 84
82 85 File.delete(testdata_filename)
83 86
84 87 return File.dirname(files[0])
85 88 end
86 89
87 90 def save_testdata_file(tempfile)
88 91 ext = TestdataImporter.long_ext(tempfile.original_filename)
89 92 testdata_filename = File.join(Dir.tmpdir,"#{@problem.name}#{ext}")
90 93
91 94 return nil if tempfile==""
92 95
93 96 if tempfile.instance_of?(Tempfile)
94 97 tempfile.close
95 98 FileUtils.move(tempfile.path,testdata_filename)
96 99 else
97 100 File.open(testdata_filename, "wb") do |f|
98 101 f.write(tempfile.read)
99 102 end
100 103 end
101 104
102 105 return testdata_filename
103 106 end
104 107
105 108 def import_test_pairs(dirname)
106 109 test_num = 1
107 110 while FileTest.exists? "#{dirname}/#{test_num}.in"
108 111 in_filename = "#{dirname}/#{test_num}.in"
109 112 sol_filename = "#{dirname}/#{test_num}.sol"
110 113
111 114 break if not FileTest.exists? sol_filename
112 115
113 116 test_pair = TestPair.new(:input => open(in_filename).read,
114 117 :solution => open(sol_filename).read,
115 118 :problem => @problem)
116 119 break if not test_pair.save
117 120
118 121 test_num += 1
119 122 end
120 123 return test_num > 1
121 124 end
122 125
123 126 def import_problem_description(dirname)
124 127 html_files = Dir["#{dirname}/*.html"]
125 128 markdown_files = Dir["#{dirname}/*.md"] + Dir["#{dirname}/*.markdown"]
126 129 if (html_files.length != 0) or (markdown_files.length != 0)
127 130 description = @problem.description || Description.new
128 131
129 132 if html_files.length != 0
130 133 filename = html_files[0]
131 134 description.markdowned = false
132 135 else
133 136 filename = markdown_files[0]
134 137 description.markdowned = true
135 138 end
136 139
137 140 description.body = open(filename).read
138 141 description.save
139 142 @problem.description = description
140 143 @problem.save
141 144 return "\nProblem description imported from #{filename}."
142 145 else
143 146 return ''
144 147 end
145 148 end
146 149
147 150 def import_problem_pdf(dirname)
148 151 pdf_files = Dir["#{dirname}/*.pdf"]
149 152 puts "CHECKING... #{dirname}"
150 153 if pdf_files.length != 0
151 154 puts "HAS PDF FILE"
152 155 filename = pdf_files[0]
153 156
154 157 @problem.save if not @problem.id
155 158 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
156 159 if not FileTest.exists? out_dirname
157 160 Dir.mkdir out_dirname
158 161 end
159 162
160 163 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
161 164
162 165 if FileTest.exists? out_filename
163 166 File.delete out_filename
164 167 end
165 168
166 169 File.rename(filename, out_filename)
167 170 @problem.description_filename = "#{@problem.name}.pdf"
168 171 @problem.save
169 172 return "\nProblem pdf imported from #{filename}."
170 173 else
171 174 return ""
172 175 end
173 176 end
174 177
175 178 #just set the full score to the total number of test case
176 179 #it is not perfect but works on most normal use case
177 180 def import_full_score(dirname)
178 181 num = 0
179 182 loop do
180 183 num += 1
181 184 in_file = Dir["#{dirname}/#{num}*.in"]
182 185 break if in_file.length == 0
183 186 end
184 187 full_score = (num - 1) * 10
185 188 @problem.full_score = full_score
186 189 @problem.save
187 190 return "\nFull score is set to #{full_score}."
188 191 end
189 192
190 193 end
@@ -1,5 +1,36
1 - # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 - one:
3 - id: 1
4 - two:
5 - id: 2
1 + Language_1:
2 + name: c
3 + pretty_name: C
4 + ext: c
5 + common_ext: c
6 +
7 + Language_2:
8 + name: cpp
9 + pretty_name: C++
10 + ext: cpp
11 + common_ext: cpp,cc
12 +
13 + Language_3:
14 + name: pas
15 + pretty_name: Pascal
16 + ext: pas
17 + common_ext: pas
18 +
19 + Language_4:
20 + name: ruby
21 + pretty_name: Ruby
22 + ext: rb
23 + common_ext: rb
24 +
25 + Language_5:
26 + name: python
27 + pretty_name: Python
28 + ext: py
29 + common_ext: py
30 +
31 + Language_6:
32 + name: java
33 + pretty_name: Java
34 + ext: java
35 + common_ext: java
36 +
@@ -1,38 +1,38
1 1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 2
3 3 <%
4 4 User.public_class_method :encrypt
5 5
6 6 salt = "abc"
7 7 %>
8 8
9 9 john:
10 10 login: john
11 11 full_name: john
12 12 hashed_password: <%= User.encrypt("hello",salt) %>
13 13 salt: <%= salt %>
14 14 activated: true
15 15
16 - mary:
17 - login: mary
18 - full_name: mary
19 - hashed_password: <%= User.encrypt("goodbye",salt) %>
16 + admin:
17 + login: admin
18 + full_name: admin
19 + hashed_password: <%= User.encrypt("admin",salt) %>
20 20 salt: <%= salt %>
21 21 roles: admin
22 22 activated: true
23 23
24 24 james:
25 25 login: james
26 26 full_name: James
27 27 hashed_password: <%= User.encrypt("morning",salt) %>
28 28 salt: <%= salt %>
29 29 contests: contest_a
30 30 activated: true
31 31
32 32 jack:
33 33 login: jack
34 34 full_name: Jack
35 35 hashed_password: <%= User.encrypt("morning",salt) %>
36 36 salt: <%= salt %>
37 37 contests: contest_a, contest_b
38 38 activated: true
@@ -1,13 +1,40
1 1 require 'test_helper'
2 2
3 3 class LoginTest < ActionDispatch::IntegrationTest
4 4 # test "the truth" do
5 5 # assert true
6 6 # end
7 7
8 - test "login with valid information" do
8 + test "login with invalid information" do
9 + get root_path
10 + assert_response :success
11 + post login_login_path, login: "root", password: "hahaha"
12 + assert_redirected_to root_path
13 + end
14 +
15 + test "normal user login" do
9 16 get root_path
10 17 assert_response :success
18 + post login_login_path, {login: "john", password: "hello" }
19 + assert_redirected_to main_list_path
20 + end
11 21
22 + test "normal user login in single_user mode" do
23 + GraderConfiguration.find_by(key: GraderConfiguration::SINGLE_USER_KEY).update_attributes(value: 'true')
24 + GraderConfiguration.reload
25 + get root_path
26 + assert_response :success
27 + post login_login_path, {login: "john", password: "hello" }
28 + follow_redirect!
29 + assert_redirected_to root_path
30 + end
31 +
32 + test "root login in in single_user mode" do
33 + GraderConfiguration.find_by(key: GraderConfiguration::SINGLE_USER_KEY).update_attributes(value: 'true')
34 + GraderConfiguration.reload
35 + get root_path
36 + assert_response :success
37 + post login_login_path, {login: "admin", password: "admin" }
38 + assert_redirected_to main_list_path
12 39 end
13 40 end
@@ -1,16 +1,20
1 1 ENV["RAILS_ENV"] = "test"
2 2 require File.expand_path('../../config/environment', __FILE__)
3 3 require 'rails/test_help'
4 4
5 + #reporter
6 + require "minitest/reporters"
7 + Minitest::Reporters.use!
8 +
5 9 class ActiveSupport::TestCase
6 10 # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
7 11 #
8 12 # Note: You'll currently still have to declare fixtures explicitly in integration tests
9 13 # -- they do not yet inherit this setting
10 14 fixtures :all
11 15
12 16 # Add more helper methods to be used by all tests here...
13 17
14 18 self.use_transactional_fixtures = true
15 19 self.use_instantiated_fixtures = false
16 20 end
You need to be logged in to leave comments. Login now