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

r879:60919c3675f4 - - 13 files changed: 87 inserted, 104 deleted

@@ -101,236 +101,240
101 101 sassc-rails (>= 2.0.0)
102 102 builder (3.2.4)
103 103 byebug (11.1.3)
104 104 capybara (3.37.1)
105 105 addressable
106 106 matrix
107 107 mini_mime (>= 0.1.3)
108 108 nokogiri (~> 1.8)
109 109 rack (>= 1.6.0)
110 110 rack-test (>= 0.6.3)
111 111 regexp_parser (>= 1.5, < 3.0)
112 112 xpath (~> 3.2)
113 113 childprocess (4.1.0)
114 114 coffee-rails (5.0.0)
115 115 coffee-script (>= 2.2.0)
116 116 railties (>= 5.2.0)
117 117 coffee-script (2.4.1)
118 118 coffee-script-source
119 119 execjs
120 120 coffee-script-source (1.12.2)
121 121 concurrent-ruby (1.1.10)
122 122 crass (1.0.6)
123 123 digest (3.1.0)
124 124 erubi (1.11.0)
125 125 erubis (2.7.0)
126 126 execjs (2.8.1)
127 127 ffi (1.15.5)
128 128 fuzzy-string-match (1.0.1)
129 129 RubyInline (>= 3.8.6)
130 130 globalid (1.0.0)
131 131 activesupport (>= 5.0)
132 132 haml (5.2.2)
133 133 temple (>= 0.8.0)
134 134 tilt
135 135 haml-rails (2.0.1)
136 136 actionpack (>= 5.1)
137 137 activesupport (>= 5.1)
138 138 haml (>= 4.0.6, < 6.0)
139 139 html2haml (>= 1.0.1)
140 140 railties (>= 5.1)
141 141 html2haml (2.2.0)
142 142 erubis (~> 2.7.0)
143 143 haml (>= 4.0, < 6)
144 144 nokogiri (>= 1.6.0)
145 145 ruby_parser (~> 3.5)
146 146 i18n (1.12.0)
147 147 concurrent-ruby (~> 1.0)
148 148 importmap-rails (1.1.5)
149 149 actionpack (>= 6.0.0)
150 150 railties (>= 6.0.0)
151 151 jbuilder (2.11.5)
152 152 actionview (>= 5.0.0)
153 153 activesupport (>= 5.0.0)
154 154 jquery-rails (4.5.0)
155 155 rails-dom-testing (>= 1, < 3)
156 156 railties (>= 4.2.0)
157 157 thor (>= 0.14, < 2.0)
158 158 listen (3.0.8)
159 159 rb-fsevent (~> 0.9, >= 0.9.4)
160 160 rb-inotify (~> 0.9, >= 0.9.7)
161 161 loofah (2.19.0)
162 162 crass (~> 1.0.2)
163 163 nokogiri (>= 1.5.9)
164 164 mail (2.7.1)
165 165 mini_mime (>= 0.1.1)
166 166 marcel (1.0.2)
167 167 material_icons (2.2.1)
168 168 railties (>= 3.2)
169 169 matrix (0.4.2)
170 170 method_source (1.0.0)
171 171 mini_mime (1.1.2)
172 172 minitest (5.16.3)
173 173 minitest-reporters (1.5.0)
174 174 ansi
175 175 builder
176 176 minitest (>= 5.0)
177 177 ruby-progressbar
178 178 momentjs-rails (2.29.4.1)
179 179 railties (>= 3.1)
180 180 msgpack (1.5.6)
181 181 mysql2 (0.5.4)
182 182 net-imap (0.2.3)
183 183 digest
184 184 net-protocol
185 185 strscan
186 186 net-pop (0.1.1)
187 187 digest
188 188 net-protocol
189 189 timeout
190 190 net-protocol (0.1.3)
191 191 timeout
192 192 net-smtp (0.3.1)
193 193 digest
194 194 net-protocol
195 195 timeout
196 196 nio4r (2.5.8)
197 + nokogiri (1.13.8-x86_64-darwin)
198 + racc (~> 1.4)
197 199 nokogiri (1.13.8-x86_64-linux)
198 200 racc (~> 1.4)
199 201 popper_js (2.11.6)
200 202 public_suffix (5.0.0)
201 203 puma (5.6.5)
202 204 nio4r (~> 2.0)
203 205 racc (1.6.0)
204 206 rack (2.2.4)
205 207 rack-test (2.0.2)
206 208 rack (>= 1.3)
207 209 rails (7.0.4)
208 210 actioncable (= 7.0.4)
209 211 actionmailbox (= 7.0.4)
210 212 actionmailer (= 7.0.4)
211 213 actionpack (= 7.0.4)
212 214 actiontext (= 7.0.4)
213 215 actionview (= 7.0.4)
214 216 activejob (= 7.0.4)
215 217 activemodel (= 7.0.4)
216 218 activerecord (= 7.0.4)
217 219 activestorage (= 7.0.4)
218 220 activesupport (= 7.0.4)
219 221 bundler (>= 1.15.0)
220 222 railties (= 7.0.4)
221 223 rails-dom-testing (2.0.3)
222 224 activesupport (>= 4.2.0)
223 225 nokogiri (>= 1.6)
224 226 rails-html-sanitizer (1.4.3)
225 227 loofah (~> 2.3)
226 228 railties (7.0.4)
227 229 actionpack (= 7.0.4)
228 230 activesupport (= 7.0.4)
229 231 method_source
230 232 rake (>= 12.2)
231 233 thor (~> 1.0)
232 234 zeitwerk (~> 2.5)
233 235 rake (13.0.6)
234 236 rb-fsevent (0.11.2)
235 237 rb-inotify (0.10.1)
236 238 ffi (~> 1.0)
237 239 rdiscount (2.2.0.2)
238 240 regexp_parser (2.5.0)
239 241 rexml (3.2.5)
240 242 rouge (4.0.0)
241 243 ruby-progressbar (1.11.0)
242 244 ruby_parser (3.19.1)
243 245 sexp_processor (~> 4.16)
244 246 rubyzip (2.3.2)
245 247 sassc (2.4.0)
246 248 ffi (~> 1.9)
247 249 sassc-rails (2.1.2)
248 250 railties (>= 4.0.0)
249 251 sassc (>= 2.0)
250 252 sprockets (> 3.0)
251 253 sprockets-rails
252 254 tilt
253 255 selenium-webdriver (4.4.0)
254 256 childprocess (>= 0.5, < 5.0)
255 257 rexml (~> 3.2, >= 3.2.5)
256 258 rubyzip (>= 1.2.2, < 3.0)
257 259 websocket (~> 1.0)
258 260 sexp_processor (4.16.1)
259 261 spring (2.1.1)
260 262 spring-watcher-listen (2.0.1)
261 263 listen (>= 2.7, < 4.0)
262 264 spring (>= 1.2, < 3.0)
263 265 sprockets (4.1.1)
264 266 concurrent-ruby (~> 1.0)
265 267 rack (> 1, < 3)
266 268 sprockets-rails (3.4.2)
267 269 actionpack (>= 5.2)
268 270 activesupport (>= 5.2)
269 271 sprockets (>= 3.0.0)
272 + sqlite3 (1.5.0-x86_64-darwin)
270 273 sqlite3 (1.5.0-x86_64-linux)
271 274 strscan (3.0.4)
272 275 temple (0.8.2)
273 276 thor (1.2.1)
274 277 tilt (2.0.11)
275 278 timeout (0.3.0)
276 279 tzinfo (2.0.5)
277 280 concurrent-ruby (~> 1.0)
278 281 web-console (4.2.0)
279 282 actionview (>= 6.0.0)
280 283 activemodel (>= 6.0.0)
281 284 bindex (>= 0.4.0)
282 285 railties (>= 6.0.0)
283 286 webdrivers (5.1.0)
284 287 nokogiri (~> 1.6)
285 288 rubyzip (>= 1.3.0)
286 289 selenium-webdriver (~> 4.0)
287 290 websocket (1.2.9)
288 291 websocket-driver (0.7.5)
289 292 websocket-extensions (>= 0.1.0)
290 293 websocket-extensions (0.1.5)
291 294 xpath (3.2.0)
292 295 nokogiri (~> 1.8)
293 296 zeitwerk (2.6.0)
294 297
295 298 PLATFORMS
299 + x86_64-darwin-20
296 300 x86_64-linux
297 301
298 302 DEPENDENCIES
299 303 ace-rails-ap
300 304 best_in_place!
301 305 bootsnap
302 306 bootstrap (~> 5.2)
303 307 byebug
304 308 capybara
305 309 coffee-rails
306 310 fuzzy-string-match
307 311 haml
308 312 haml-rails
309 313 importmap-rails (~> 1.1)
310 314 jbuilder
311 315 jquery-rails
312 316 listen (>= 3.0.5, < 3.2)
313 317 mail
314 318 material_icons
315 319 minitest-reporters
316 320 momentjs-rails
317 321 mysql2
318 322 puma
319 323 rails (~> 7.0)
320 324 rdiscount
321 325 rouge
322 326 sassc-rails
323 327 selenium-webdriver
324 328 simple_form!
325 329 spring
326 330 spring-watcher-listen (~> 2.0.0)
327 331 sprockets-rails
328 332 sqlite3
329 333 web-console (>= 3.3.0)
330 334 webdrivers
331 335
332 336 RUBY VERSION
333 337 ruby 3.1.2p20
334 338
335 339 BUNDLED WITH
336 340 2.3.22
@@ -1,168 +1,155
1 1 require 'ipaddr'
2 2 require "securerandom"
3 3
4 4 class ApplicationController < ActionController::Base
5 5 protect_from_forgery
6 6
7 7 before_action :current_user
8 8 before_action :nav_announcement
9 9 before_action :unique_visitor_id
10 10 before_action :active_controller_action
11 11
12 12 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
13 13 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
14 14 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
15 15 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
16 16
17 17 #report and redirect for unauthorized activities
18 - def unauthorized_redirect(notice = 'You are not authorized to view the page you requested')
19 - flash[:notice] = notice
20 - redirect_to login_main_path
18 + def unauthorized_redirect(msg = 'You are not authorized to view the page you requested')
19 + redirect_to login_main_path, alert: msg
21 20 end
22 21
23 22 # Returns the current logged-in user (if any).
24 23 def current_user
25 24 return nil unless session[:user_id]
26 25 @current_user ||= User.find(session[:user_id])
27 26 end
28 27
29 28 def nav_announcement
30 29 @nav_announcement = Announcement.where(on_nav_bar: true)
31 30 end
32 31
33 32 def active_controller_action
34 33 #so that we can override this value inside each action
35 34 @active_controller = controller_name
36 35 @active_action = action_name
37 36 end
38 37
39 38 def admin_authorization
40 39 return false unless check_valid_login
41 40 user = User.includes(:roles).find(session[:user_id])
42 41 unless user.admin?
43 42 unauthorized_redirect
44 43 return false
45 44 end
46 45 return true
47 46 end
48 47
49 - #admin always count as every roles
50 - def role_authorization(roles)
48 + def authorization_by_roles(allowed_roles)
51 49 return false unless check_valid_login
52 - user = User.find(session[:user_id])
53 - return true if user.admin?
50 + return true if @current_user.admin?
54 51 roles.each do |r|
55 - return true if user.has_role?(r)
52 + return true if @current_user.has_role?(r)
56 53 end
57 54 unauthorized_redirect
58 55 end
59 56
60 - def authorization_by_roles(allowed_roles)
61 - return false unless check_valid_login
62 - unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) }
63 - unauthorized_redirect
64 - return false
65 - end
66 - end
67 -
68 57 def testcase_authorization
69 58 #admin always has privileged
70 - if @current_user.admin?
71 - return true
72 - end
59 + return true if @current_user.admin?
73 60
74 61 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
75 62 end
76 63
77 64 def unique_visitor_id
78 65 unless cookies.encrypted[:uuid]
79 66 value = SecureRandom.uuid
80 67 cookies.encrypted[:uuid] = { value: value, expires: 20.year }
81 68 end
82 69 end
83 70
84 71 protected
85 72
86 73 #redirect to root (and also force logout)
87 74 #if the user is not logged_in or the system is in "ADMIN ONLY" mode
88 75 def check_valid_login
89 76 #check if logged in
90 77 unless session[:user_id]
91 78 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
92 79 unauthorized_redirect('You need to login but you cannot log in at this time')
93 80 else
94 81 unauthorized_redirect('You need to login')
95 82 end
96 83 return false
97 84 end
98 85
99 86 # check if run in single user mode
100 87 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
101 88 if @current_user==nil || (!@current_user.admin?)
102 89 unauthorized_redirect('You cannot log in at this time')
103 90 return false
104 91 end
105 92 end
106 93
107 94 # check if the user is enabled
108 95 unless @current_user.enabled? || @current_user.admin?
109 96 unauthorized_redirect 'Your account is disabled'
110 97 return false
111 98 end
112 99
113 100 # check if user ip is allowed
114 101 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
115 102 unless is_request_ip_allowed?
116 103 unauthorized_redirect 'Your IP is not allowed to login at this time.'
117 104 return false
118 105 end
119 106 end
120 107
121 108 if GraderConfiguration.multicontests?
122 109 return true if @current_user.admin?
123 110 begin
124 111 if @current_user.contest_stat(true).forced_logout
125 112 flash[:notice] = 'You have been automatically logged out.'
126 113 redirect_to :controller => 'main', :action => 'index'
127 114 end
128 115 rescue
129 116 end
130 117 end
131 118 return true
132 119 end
133 120
134 121 #redirect to root (and also force logout)
135 122 #if the user use different ip from the previous connection
136 123 # only applicable when MULTIPLE_IP_LOGIN options is false only
137 124 def authenticate_by_ip_address
138 125 #this assume that we have already authenticate normally
139 126 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
140 127 user = User.find(session[:user_id])
141 128 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
142 129 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
143 130 redirect_to :controller => 'main', :action => 'login'
144 131 return false
145 132 end
146 133 unless user.last_ip
147 134 user.last_ip = request.remote_ip
148 135 user.save
149 136 end
150 137 end
151 138 return true
152 139 end
153 140
154 141 def authorization
155 142 return false unless check_valid_login
156 143 user = User.find(session[:user_id])
157 144 unless user.roles.detect { |role|
158 145 role.rights.detect{ |right|
159 146 right.controller == self.class.controller_name and
160 147 (right.action == 'all' || right.action == action_name)
161 148 }
162 149 }
163 150 flash[:notice] = 'You are not authorized to view the page you requested'
164 151 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
165 152 redirect_to :controller => 'main', :action => 'login'
166 153 return false
167 154 end
168 155 end
@@ -1,99 +1,97
1 1 class LoginController < ApplicationController
2 2
3 3 @@authenticators = []
4 4
5 5 def index
6 6 # show login screen
7 7 reset_session
8 8 redirect_to :controller => 'main', :action => 'login'
9 9 end
10 10
11 11 def login
12 12 user = get_authenticated_user(params[:login], params[:password])
13 13 unless user
14 - flash[:notice] = 'Wrong password'
15 - redirect_to :controller => 'main', :action => 'login'
14 + redirect_to login_main_path, alert: 'Wrong password'
16 15 return
17 16 end
18 17
19 18 if (!GraderConfiguration['right.bypass_agreement']) and (!params[:accept_agree]) and !user.admin?
20 - flash[:notice] = 'You must accept the agreement before logging in'
21 - redirect_to :controller => 'main', :action => 'login'
19 + redirect_to login_main_path, alert: 'You must accept the agreement before logging in'
22 20 return
23 21 end
24 22
25 23 #store uuid when login
26 24 if user.last_ip.nil?
27 25 user.last_ip = cookies.encrypted[:uuid]
28 26 else
29 27 if user.last_ip != cookies.encrypted[:uuid]
30 28 user.last_ip =cookies.encrypted[:uuid]
31 29 #log different login
32 30 end
33 31 end
34 32
35 33 #process logging in
36 34 session[:user_id] = user.id
37 35 session[:admin] = user.admin?
38 36
39 37 # clear forced logout flag for multicontests contest change
40 38 if GraderConfiguration.multicontests?
41 39 contest_stat = user.contest_stat
42 40 if contest_stat.respond_to? :forced_logout
43 41 if contest_stat.forced_logout
44 42 contest_stat.forced_logout = false
45 43 contest_stat.save
46 44 end
47 45 end
48 46 end
49 47
50 48 #save login information
51 49 Login.create(user_id: user.id, ip_address: cookies.encrypted[:uuid])
52 50
53 51 redirect_to :controller => 'main', :action => 'list'
54 52 end
55 53
56 54 def site_login
57 55 begin
58 56 site = Site.find(params[:login][:site_id])
59 57 rescue ActiveRecord::RecordNotFound
60 58 site = nil
61 59 end
62 60 if site==nil
63 - flash[:notice] = 'Wrong site'
61 + flash[:alert] = 'Wrong site'
64 62 redirect_to :controller => 'main', :action => 'login' and return
65 63 end
66 64 if (site.password) and (site.password == params[:login][:password])
67 65 session[:site_id] = site.id
68 66 redirect_to :controller => 'site', :action => 'index'
69 67 else
70 - flash[:notice] = 'Wrong site password'
68 + flash[:alert] = 'Wrong site password'
71 69 redirect_to :controller => 'site', :action => 'login'
72 70 end
73 71 end
74 72
75 73 def logout
76 74 redirect_to root_path
77 75 end
78 76
79 77 def self.add_authenticator(authenticator)
80 78 @@authenticators << authenticator
81 79 end
82 80
83 81 protected
84 82
85 83 def get_authenticated_user(login, password)
86 84 if @@authenticators.empty?
87 85 return User.authenticate(login, password)
88 86 else
89 87 user = User.authenticate(login, password)
90 88 @@authenticators.each do |authenticator|
91 89 if not user
92 90 user = authenticator.authenticate(login, password)
93 91 end
94 92 end
95 93 return user
96 94 end
97 95 end
98 96
99 97 end
@@ -1,119 +1,118
1 1 class MainController < ApplicationController
2 2
3 3 before_action :check_valid_login, :except => [:login]
4 4 before_action :check_viewability, :except => [:index, :login]
5 5
6 6 append_before_action :confirm_and_update_start_time,
7 7 :except => [:index,
8 8 :login,
9 9 :confirm_contest_start]
10 10
11 11 # to prevent log in box to be shown when user logged out of the
12 12 # system only in some tab
13 13 prepend_before_action :reject_announcement_refresh_when_logged_out,
14 14 :only => [:announcements]
15 15
16 16 before_action :authenticate_by_ip_address, :only => [:list]
17 17
18 18 #reset login, clear session
19 19 #front page
20 20 def login
21 - saved_notice = flash[:notice]
22 - reset_session
23 - flash.now[:notice] = saved_notice
21 + #saved_notice = flash[:notice]
22 + #flash[:notice] = saved_notice
24 23 @remote_ip = request.remote_ip
25 24
26 25 # EXPERIMENT:
27 26 # Hide login if in single user mode and the url does not
28 27 # explicitly specify /login
29 28 #
30 29 # logger.info "PATH: #{request.path}"
31 30 # if GraderConfiguration['system.single_user_mode'] and
32 31 # request.path!='/main/login'
33 32 # @hidelogin = true
34 33 # end
35 34
36 35 @announcements = Announcement.frontpage
37 36 render :action => 'login', locals: {skip_header: true}
38 37 end
39 38
40 39 def logout
41 40 reset_session
42 41 redirect_to root_path
43 42 end
44 43
45 44 def list
46 45 prepare_list_information
47 46 end
48 47
49 48 def help
50 49 @user = User.find(session[:user_id])
51 50 end
52 51
53 52 def submit
54 53 user = User.find(session[:user_id])
55 54
56 55 @submission = Submission.new
57 56 @submission.problem_id = params[:submission][:problem_id]
58 57 @submission.user = user
59 58 @submission.language_id = 0
60 59 if (params['file']) and (params['file']!='')
61 60 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
62 61 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
63 62 @submission.source_filename = params['file'].original_filename
64 63 end
65 64
66 65 if (params[:editor_text])
67 66 language = Language.find_by_id(params[:language_id])
68 67 @submission.source = params[:editor_text]
69 68 @submission.source_filename = "live_edit.#{language.ext}"
70 69 @submission.language = language
71 70 end
72 71
73 72 @submission.submitted_at = Time.new.gmtime
74 73 @submission.ip_address = cookies.encrypted[:uuid]
75 74
76 75 if @current_user.admin? == false && GraderConfiguration.time_limit_mode? && @current_user.contest_finished?
77 76 @submission.errors.add(:base,"The contest is over.")
78 77 prepare_list_information
79 78 render :action => 'list' and return
80 79 end
81 80
82 81 if @submission.valid?(@current_user)
83 82 if @submission.save == false
84 83 flash[:notice] = 'Error saving your submission'
85 84 elsif Task.create(:submission_id => @submission.id,
86 85 :status => Task::STATUS_INQUEUE) == false
87 86 flash[:notice] = 'Error adding your submission to task queue'
88 87 end
89 88 else
90 89 prepare_list_information
91 90 render :action => 'list' and return
92 91 end
93 92 redirect_to edit_submission_path(@submission)
94 93 end
95 94
96 95 def source
97 96 submission = Submission.find(params[:id])
98 97 if ((submission.user_id == session[:user_id]) and
99 98 (submission.problem != nil) and
100 99 (submission.problem.available))
101 100 send_data(submission.source,
102 101 {:filename => submission.download_filename,
103 102 :type => 'text/plain'})
104 103 else
105 104 flash[:notice] = 'Error viewing source'
106 105 redirect_to :action => 'list'
107 106 end
108 107 end
109 108
110 109 def compiler_msg
111 110 @submission = Submission.find(params[:id])
112 111 if @submission.user_id == session[:user_id]
113 112 render :action => 'compiler_msg', :layout => 'empty'
114 113 else
115 114 flash[:notice] = 'Error viewing source'
116 115 redirect_to :action => 'list'
117 116 end
118 117 end
119 118
@@ -1,101 +1,101
1 1 class SubmissionsController < ApplicationController
2 2 before_action :set_submission, only: [:show,:download,:compiler_msg,:rejudge,:set_tag, :edit]
3 3 before_action :check_valid_login
4 4 before_action :submission_authorization, only: [:show, :download, :edit]
5 - before_action only: [:rejudge, :set_tag] do role_authorization([:ta]) end
5 + before_action only: [:rejudge, :set_tag] do authorization_by_roles([:ta]) end
6 6
7 7 # GET /submissions
8 8 # GET /submissions.json
9 9 # Show problem selection and user's submission of that problem
10 10 def index
11 11 @user = @current_user
12 12 @problems = @user.available_problems
13 13
14 14 if params[:problem_id]==nil
15 15 @problem = nil
16 16 @submissions = nil
17 17 else
18 18 @problem = Problem.find_by_id(params[:problem_id])
19 19 if (@problem == nil) or (not @problem.available)
20 20 redirect_to list_main_path
21 21 flash[:error] = 'Authorization error: You have no right to view submissions for this problem'
22 22 return
23 23 end
24 24 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
25 25 end
26 26 end
27 27
28 28 # GET /submissions/1
29 29 # GET /submissions/1.json
30 30 def show
31 31 #log the viewing
32 32 user = User.find(session[:user_id])
33 33 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
34 34
35 35 @task = @submission.task
36 36 end
37 37
38 38 def download
39 39 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
40 40 end
41 41
42 42 def compiler_msg
43 43 respond_to do |format|
44 44 format.js
45 45 end
46 46 end
47 47
48 48 #on-site new submission on specific problem
49 49 def direct_edit_problem
50 50 @problem = Problem.find(params[:problem_id])
51 51 unless @current_user.can_view_problem?(@problem)
52 52 unauthorized_redirect
53 53 return
54 54 end
55 55 @source = ''
56 56 if (params[:view_latest])
57 57 sub = Submission.find_last_by_user_and_problem(@current_user.id,@problem.id)
58 58 @source = @submission.source.to_s if @submission and @submission.source
59 59 end
60 60 render 'edit'
61 61 end
62 62
63 63 # GET /submissions/1/edit
64 64 def edit
65 65 @source = @submission.source.to_s
66 66 @problem = @submission.problem
67 67 @lang_id = @submission.language.id
68 68 end
69 69
70 70
71 71 def get_latest_submission_status
72 72 @problem = Problem.find(params[:pid])
73 73 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
74 74 respond_to do |format|
75 75 format.js
76 76 end
77 77 end
78 78
79 79 # GET /submissions/:id/rejudge
80 80 def rejudge
81 81 @task = @submission.task
82 82 @task.status_inqueue! if @task
83 83 respond_to do |format|
84 84 format.js
85 85 end
86 86 end
87 87
88 88 def set_tag
89 89 @submission.update(tag: params[:tag])
90 90 redirect_to @submission
91 91 end
92 92
93 93 protected
94 94
95 95 def submission_authorization
96 96 #admin always has privileged
97 97 return true if @current_user.admin?
98 98 return true if @current_user.has_role?('ta') && (['show','download'].include? action_name)
99 99
100 100 sub = Submission.find(params[:id])
101 101 if @current_user.available_problems.include? sub.problem
@@ -1,61 +1,61
1 1 class TagsController < ApplicationController
2 2 before_action :admin_authorization
3 3 before_action :set_tag, only: [:show, :edit, :update, :destroy]
4 4
5 5 # GET /tags
6 6 def index
7 7 @tags = Tag.all
8 8 end
9 9
10 10 # GET /tags/1
11 11 def show
12 12 end
13 13
14 14 # GET /tags/new
15 15 def new
16 16 @tag = Tag.new
17 17 end
18 18
19 19 # GET /tags/1/edit
20 20 def edit
21 21 end
22 22
23 23 # POST /tags
24 24 def create
25 25 @tag = Tag.new(tag_params)
26 26
27 27 if @tag.save
28 - redirect_to @tag, notice: 'Tag was successfully created.'
28 + redirect_to tags_path, notice: 'Tag was successfully created.'
29 29 else
30 30 render :new
31 31 end
32 32 end
33 33
34 34 # PATCH/PUT /tags/1
35 35 def update
36 36 if @tag.update(tag_params)
37 37 redirect_to @tag, notice: 'Tag was successfully updated.'
38 38 else
39 39 render :edit
40 40 end
41 41 end
42 42
43 43 # DELETE /tags/1
44 44 def destroy
45 45 #remove any association
46 46 ProblemTag.where(tag_id: @tag.id).destroy_all
47 47 @tag.destroy
48 48 redirect_to tags_url, notice: 'Tag was successfully destroyed.'
49 49 end
50 50
51 51 private
52 52 # Use callbacks to share common setup or constraints between actions.
53 53 def set_tag
54 54 @tag = Tag.find(params[:id])
55 55 end
56 56
57 57 # Only allow a trusted parameter "white list" through.
58 58 def tag_params
59 59 params.require(:tag).permit(:name, :description, :public)
60 60 end
61 61 end
@@ -1,23 +1,23
1 1 %h1 Groups
2 2
3 3 %p
4 4 = link_to 'New Group', new_group_path, class: 'btn btn-success'
5 5 %table.table.table-hover
6 6 %thead
7 7 %tr
8 8 %th Name
9 9 %th Description
10 10 %th Enabled?
11 11 %th
12 12 %tbody
13 13 - @groups.each do |group|
14 14 %tr{:class => "#{(group.enabled?) ? "success" : "danger"}", id: "group-#{group.id}"}
15 15 %td= group.name
16 16 %td= group.description
17 17 %td= toggle_button(group.enabled?, toggle_group_path(group), "group-enabled-#{group.id}", block: ' ')
18 18 %td
19 - = link_to 'Edit members and problems', group, class: 'btn btn-secondary btn-sm'
19 + = link_to 'Edit members and problems', group, class: 'btn btn-info btn-sm'
20 20 = link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger btn-sm'
21 21
22 22 %br
23 23
@@ -1,93 +1,93
1 1 %header
2 2 %nav.navbar.fixed-top.navbar-dark.bg-primary.navbar-expand-lg
3 3 .container-fluid
4 4 %a.navbar-brand{href: list_main_path}
5 5 %span.mi.mi-bs home
6 6 MAIN
7 7 %button.navbar-toggler.collapsed{ type: :button, 'data-bs': {toggle: 'collapse', target: '#navbar-collapse'} }
8 8 %span.navbar-toggler-icon
9 9 .collapse.navbar-collapse#navbar-collapse
10 10 %ul.navbar-nav.me-auto.mb-2.mb-lg-0
11 11 / submission
12 12 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
13 13 %li.nav-item.dropdown.mx-2
14 14 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {expanded:"false"}, role: "button"}
15 15 = "#{I18n.t 'menu.submissions'}"
16 16 %ul.dropdown-menu
17 17 %li= link_to 'View', submissions_path, class: 'dropdown-item '+active_class_when(controller: :submissions)
18 18 %li= link_to 'Self Test', test_index_path, class:'dropdown-item'
19 19 / hall of fame
20 20 - if GraderConfiguration['right.user_hall_of_fame']
21 21 %li= link_to "#{I18n.t 'menu.hall_of_fame'}", problem_hof_report_path, class: 'nav-link mx-2'+active_class_when(controller: :report, action: :problem_hof)
22 22 / display MODE button (with countdown in contest mode)
23 23 - if GraderConfiguration.analysis_mode?
24 24 %div.btn.btn-success#countdown= "ANALYSIS MODE"
25 25 - elsif GraderConfiguration.time_limit_mode?
26 26 - if @current_user.contest_finished?
27 27 %div.btn.btn-danger#countdown= "Contest is over"
28 28 - elsif !@current_user.contest_started?
29 29 %div.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
30 30 - else
31 31 %div.btn.btn-primary#countdown asdf
32 32 :javascript
33 33 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
34 34 / admin section
35 35 - if (@current_user!=nil) and (session[:admin])
36 36 / management
37 37 %li.nav-item.dropdown.mx-2
38 38 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
39 39 Manage
40 40 %ul.dropdown-menu
41 41 %li= link_to 'Announcements', announcements_path, class: 'dropdown-item'+active_class_when(controller: :announcements)
42 42 %li= link_to 'Problems', problems_path, class: 'dropdown-item'+active_class_when(controller: :problems)
43 43 %li= link_to 'Tags', tags_path, class: 'dropdown-item'+active_class_when(controller: :tags)
44 44 %li= link_to 'Users', user_admin_index_path, class: 'dropdown-item'+active_class_when(controller: :user_admin)
45 45 %li= link_to 'User Groups', groups_path, class: 'dropdown-item'+active_class_when(controller: :groups)
46 46 %li= link_to 'Graders', graders_list_path, class: 'dropdown-item'+active_class_when(controller: :graders)
47 47 %li= link_to 'Message ', console_messages_path, class: 'dropdown-item'+active_class_when(controller: :messages)
48 48 %li
49 49 %hr.dropdown-divider
50 50 %li= link_to 'System config', grader_configuration_index_path, class: 'dropdown-item'+active_class_when(controller: :grader_configuration)
51 51 %li
52 52 %hr.dropdown-divider
53 53 %li= link_to 'Sites', sites_path, class: 'dropdown-item'+active_class_when(controller: :sites)
54 54 %li= link_to 'Contests', contest_management_index_path, class: 'dropdown-item'+active_class_when(controller: :contest_management)
55 55 -#
56 56 / report
57 57 %li.nav-item.dropdown.mx-2
58 58 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
59 59 Report
60 60 %ul.dropdown-menu
61 61 %li= link_to 'Current Score', current_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :current_score)
62 62 %li= link_to 'Score Report', max_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :max_score)
63 63 %li= link_to 'Submission Report', submission_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :submission)
64 64 %li= link_to 'Login Report', login_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :login)
65 65 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
66 66 =link_to "#{ungraded} backlogs!",
67 67 graders_list_path,
68 68 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
69 69 / announcement
70 70 - @nav_announcement.each do |ann|
71 71 %p.navbar-text
72 72 = ann.body.html_safe
73 73 %ul.navbar-nav
74 74 %li.nav-item
75 75 %a.nav-link{href: help_main_path}
76 76 %span.mi.mi-bs.md-18 help
77 77 %li.nav-item
78 78 %a.nav-link{href: messages_path}
79 79 %span.mi.mi-bs.md-18 chat
80 80 - if GraderConfiguration['system.user_setting_enabled']
81 81 %li.nav-item
82 82 %a.nav-link{href: profile_users_path}
83 83 %span.mi.mi-bs.md-18 settings
84 84 %li.nav-item
85 - %a.nav-link{href: login_main_path}
85 + %a.nav-link{href: logout_main_path}
86 86 %span.mi.mi-bs.md-18 exit_to_app
87 87 = @current_user.full_name
88 88 :javascript
89 89 $('.active-with-children').each( (index,obj) => {
90 90 if ($(obj).siblings('.dropdown-menu').has('.active').length > 0) {
91 91 $(obj).addClass('active')
92 92 }
93 93 } )
@@ -1,88 +1,87
1 1
2 2 .card
3 3 .card-body
4 4 .card-title
5 5 %h3= GraderConfiguration['ui.front.welcome_message']
6 6 - if !@hidelogin
7 7 .card-subtitle=t 'login.message'
8 8
9 9 - if flash[:notice]
10 - %hr/
11 - %b= flash[:notice]
12 - %hr/
10 + .alert.alert-danger
11 + = flash[:notice]
13 12
14 13 .card
15 14 .card-body{ style: "background: #eeeeff;"}
16 15 = form_with url: login_login_path do |f|
17 16 .mb-3
18 17 = f.label :login, "Login", class: 'form-label'
19 18 = f.text_field :login, class: 'form-control'
20 19 .mb-3
21 20 = f.label :password, "Password", class: 'form-label'
22 21 = f.password_field :password, class: 'form-control'
23 22 - unless GraderConfiguration['right.bypass_agreement']
24 23 .col-sm-offset-3.col-sm-9
25 24 .checkbox
26 25 %label
27 26 = check_box_tag 'accept_agree'
28 27 ΰΈ’ΰΈ­ΰΈ‘ΰΈ£ΰΈ±ΰΈšΰΈ‚ΰΉ‰ΰΈ­ΰΈ•ΰΈΰΈ₯ΰΈ‡ΰΈΰΈ²ΰΈ£ΰΉƒΰΈŠΰΉ‰ΰΈ‡ΰΈ²ΰΈ™
29 28 .mb-3
30 29 .col-sm-offset-3.col-sm-9
31 30 = submit_tag t('login.login_submit'), class: 'btn btn-primary'
32 31 - else
33 32 Login is not possible right now
34 33
35 34 %br/
36 35
37 36 - if GraderConfiguration['system.online_registration']
38 37 =t 'login.participation'
39 38 %b
40 39 = "#{t 'login.please'} "
41 40 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
42 41 %br/
43 42 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
44 43 -#
45 44 %br/
46 45
47 46 - if !@hidelogin
48 47 =t 'login.message'
49 48 %br/
50 49 %br/
51 50
52 51 - if flash[:notice]
53 52 %hr/
54 53 %b= flash[:notice]
55 54 %hr/
56 55
57 56 %div{ :style => "border: solid 1px gray; padding: 4px; background: #eeeeff;"}
58 57 = form_tag login_login_path, {class: 'form-horizontal'} do
59 58 .form-group
60 59 =label_tag :login, "Login",class: 'col-sm-3 control-label'
61 60 .col-sm-9
62 61 =text_field_tag :login, nil, class: 'form-control'
63 62 .form-group
64 63 =label_tag :password, "Password", class: 'col-sm-3 control-label'
65 64 .col-sm-9
66 65 =password_field_tag :password, nil, class: 'form-control'
67 66 - unless GraderConfiguration['right.bypass_agreement']
68 67 .form-group
69 68 .col-sm-offset-3.col-sm-9
70 69 .checkbox
71 70 %label
72 71 = check_box_tag 'accept_agree'
73 72 ΰΈ’ΰΈ­ΰΈ‘ΰΈ£ΰΈ±ΰΈšΰΈ‚ΰΉ‰ΰΈ­ΰΈ•ΰΈΰΈ₯ΰΈ‡ΰΈΰΈ²ΰΈ£ΰΉƒΰΈŠΰΉ‰ΰΈ‡ΰΈ²ΰΈ™
74 73
75 74 .form-group
76 75 .col-sm-offset-3.col-sm-9
77 76 = submit_tag t('login.login_submit'), class: 'btn btn-primary'
78 77 - else
79 78
80 79 %br/
81 80
82 81 - if GraderConfiguration['system.online_registration']
83 82 =t 'login.participation'
84 83 %b
85 84 = "#{t 'login.please'} "
86 85 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
87 86 %br/
88 87 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
@@ -1,22 +1,7
1 - = form_for @tag do |f|
2 - - if @tag.errors.any?
3 - #error_explanation
4 - %h2= "#{pluralize(@tag.errors.count, "error")} prohibited this tag from being saved:"
5 - %ul
6 - - @tag.errors.full_messages.each do |msg|
7 - %li= msg
8 -
1 + = simple_form_for @tag do |f|
9 2 .row
10 3 .col-md-6
11 - .form-group.field
12 - = f.label :name
13 - = f.text_field :name, class: 'form-control'
14 - .form-group.field
15 - = f.label :description
16 - = f.text_area :description, class: 'form-control'
17 - .form-group.field
18 - = f.label :public
19 - = f.text_field :public, class: 'form-control'
20 - .actions
4 + = f.input :name
5 + = f.input :description
6 + = f.input :public
21 7 = f.submit 'Save', class: 'btn btn-primary'
22 - .col-md-6
@@ -1,26 +1,26
1 1 %h1 Tags
2 2
3 3 = link_to 'New Tag', new_tag_path, class: 'btn btn-success'
4 4
5 5 %table.table.table-hover
6 6 %thead
7 7 %tr
8 8 %th Name
9 9 %th Description
10 10 %th Public
11 11 %th
12 12 %th
13 13 %th
14 14
15 15 %tbody
16 16 - @tags.each do |tag|
17 17 %tr
18 18 %td= tag.name
19 19 %td= tag.description
20 20 %td= tag.public
21 - %td= link_to 'Show', tag
22 - %td= link_to 'Edit', edit_tag_path(tag)
23 - %td= link_to 'Destroy', tag, :method => :delete, :data => { :confirm => 'Are you sure?' }
21 + %td= link_to 'Show', tag, class: 'btn btn-info'
22 + %td= link_to 'Edit', edit_tag_path(tag), class: 'btn btn-info'
23 + %td= button_to 'Destroy', tag, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger'
24 24
25 25 %br
26 26
@@ -1,91 +1,91
1 1 %h1 Users
2 2
3 3 .card.border-success.mb-3
4 4 .card-header.text-bg-success.border-success
5 5 Quick Add
6 6 .card-body
7 7 = form_with url: user_admin_index_path, scope: :user, class: 'row row-cols-lg-auto g-3 align-items-center' do |f|
8 8 .col-12
9 9 = f.text_field 'login', :size => 10,class: 'form-control', placeholder: 'login'
10 10 .form-group
11 11 = f.text_field 'full_name', :size => 10,class: 'form-control', placeholder: 'full name'
12 12 .form-group
13 13 = f.password_field 'password', :size => 10,class: 'form-control', placeholder: 'password'
14 14 .form-group
15 15 = f.password_field 'password_confirmation', :size => 10,class: 'form-control', placeholder: 'password confirmation'
16 16 .form-group
17 17 = f.text_field 'email', :size => 10,class: 'form-control', placeholder: 'email'
18 18 =submit_tag "Create", class: 'btn btn-success align-items-bottom'
19 19
20 20 .card.border-success.mb-3
21 21 .card-header.text-bg-success.border-success
22 22 Import from site management
23 23 .card-body
24 24 = form_with url: import_user_admin_index_path, :multipart => true do |f|
25 25 .row
26 26 .col-auto
27 27 = f.label :file, 'File:', class: 'col-form-label'
28 28 .col-auto
29 29 = f.file_field :file, class: 'form-control'
30 30 .col-auto
31 31 = f.submit 'Submit', class: 'btn btn-secondary'
32 32
33 33
34 34 %p
35 35 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
36 36 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
37 37 = link_to 'Bulk Manage', { action: :bulk_manage} , { class: 'btn btn-secondary btn-info'}
38 38 = link_to 'View administrators',{ :action => 'admin'}, { class: 'btn btn-secondary '}
39 39 = link_to 'Random passwords',{ :action => 'random_all_passwords'}, { class: 'btn btn-secondary '}
40 40 = link_to 'View active users',{ :action => 'active'}, { class: 'btn btn-secondary '}
41 41 = link_to 'Mass mailing',{ :action => 'mass_mailing'}, { class: 'btn btn-secondary '}
42 42
43 43 - if GraderConfiguration.multicontests?
44 44 %br/
45 45 %b Multi-contest:
46 46 = link_to '[Manage bulk users in contests]', :action => 'contest_management'
47 47 View users in:
48 48 - @contests.each do |contest|
49 49 = link_to "[#{contest.name}]", :action => 'contests', :id => contest.id
50 50 = link_to "[no contest]", :action => 'contests', :id => 'none'
51 51
52 52 %table.table.table-hover.table-condense.datatable
53 53 %thead
54 54 %th Login
55 55 %th Full name
56 56 %th email
57 57 %th Remark
58 58 %th
59 59 Activated
60 60 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'User has already confirmed the email?' } [?]
61 61 %th
62 62 Enabled
63 63 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'Allow the user to login?' } [?]
64 64 %th Last IP
65 65 %th
66 66 %th
67 67 %th
68 68 %th
69 69 - for user in @users
70 70 %tr
71 71 %td= link_to user.login, stat_user_path(user)
72 72 %td= user.full_name
73 73 %td= user.email
74 74 %td= user.remark
75 75 %td= toggle_button(user.activated?, toggle_activate_user_path(user),"toggle_activate_user_#{user.id}")
76 76 %td= toggle_button(user.enabled?, toggle_enable_user_path(user),"toggle_enable_user_#{user.id}")
77 77 %td= user.last_ip
78 78 %td= link_to 'Clear IP', {:action => 'clear_last_ip', :id => user, :page=>params[:page]}, :confirm => 'This will reset last logging in ip of the user, are you sure?', class: 'btn btn-secondary btn-sm btn-block'
79 - %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-secondary btn-sm btn-block'
80 - %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-secondary btn-sm btn-block'
79 + %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-info btn-sm btn-block'
80 + %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-info btn-sm btn-block'
81 81 %td= link_to 'Destroy', {action: :destroy, id: user}, data: {confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-danger btn-sm btn-block'
82 82 %br/
83 83 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
84 84 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
85 85
86 86 :javascript
87 87 $(document).on('import-map-loaded',(e) => {
88 88 $('.datatable').DataTable({
89 89 'pageLength': 50
90 90 });
91 91 })
@@ -1,346 +1,357
1 1 # This file is auto-generated from the current state of the database. Instead
2 2 # of editing this file, please use the migrations feature of Active Record to
3 3 # incrementally modify your database, and then regenerate this schema definition.
4 4 #
5 5 # This file is the source Rails uses to define your schema when running `bin/rails
6 6 # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7 7 # be faster and is potentially less error prone than running all of your
8 8 # migrations from scratch. Old migrations may fail to apply correctly if those
9 9 # migrations use external dependencies or application code.
10 10 #
11 11 # It's strongly recommended that you check this file into your version control system.
12 12
13 13 ActiveRecord::Schema[7.0].define(version: 2022_09_27_074644) do
14 - create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
14 + create_table "active_storage_attachments", charset: "latin1", force: :cascade do |t|
15 15 t.string "name", null: false
16 16 t.string "record_type", null: false
17 17 t.bigint "record_id", null: false
18 18 t.bigint "blob_id", null: false
19 19 t.datetime "created_at", null: false
20 20 t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
21 21 t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
22 22 end
23 23
24 - create_table "active_storage_blobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
24 + create_table "active_storage_blobs", charset: "latin1", force: :cascade do |t|
25 25 t.string "key", null: false
26 26 t.string "filename", null: false
27 27 t.string "content_type"
28 28 t.text "metadata"
29 29 t.string "service_name", null: false
30 30 t.bigint "byte_size", null: false
31 31 t.string "checksum"
32 32 t.datetime "created_at", null: false
33 33 t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
34 34 end
35 35
36 - create_table "active_storage_variant_records", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
36 + create_table "active_storage_variant_records", charset: "latin1", force: :cascade do |t|
37 37 t.bigint "blob_id", null: false
38 38 t.string "variation_digest", null: false
39 39 t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
40 40 end
41 41
42 - create_table "announcements", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
42 + create_table "announcements", id: :integer, charset: "utf8", force: :cascade do |t|
43 43 t.string "author"
44 - t.text "body"
44 + t.text "body", size: :medium
45 45 t.boolean "published"
46 46 t.datetime "created_at", precision: nil, null: false
47 47 t.datetime "updated_at", precision: nil, null: false
48 48 t.boolean "frontpage", default: false
49 49 t.boolean "contest_only", default: false
50 50 t.string "title"
51 51 t.string "notes"
52 52 t.boolean "on_nav_bar", default: false
53 53 end
54 54
55 - create_table "contests", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
55 + create_table "contests", id: :integer, charset: "utf8", force: :cascade do |t|
56 56 t.string "title"
57 57 t.boolean "enabled"
58 58 t.datetime "created_at", precision: nil, null: false
59 59 t.datetime "updated_at", precision: nil, null: false
60 60 t.string "name"
61 61 end
62 62
63 - create_table "contests_problems", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
63 + create_table "contests_problems", id: false, charset: "utf8", force: :cascade do |t|
64 64 t.integer "contest_id"
65 65 t.integer "problem_id"
66 66 end
67 67
68 - create_table "contests_users", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
68 + create_table "contests_users", id: false, charset: "utf8", force: :cascade do |t|
69 69 t.integer "contest_id"
70 70 t.integer "user_id"
71 71 end
72 72
73 - create_table "countries", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
73 + create_table "countries", id: :integer, charset: "utf8", force: :cascade do |t|
74 74 t.string "name"
75 75 t.datetime "created_at", precision: nil, null: false
76 76 t.datetime "updated_at", precision: nil, null: false
77 77 end
78 78
79 - create_table "descriptions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
80 - t.text "body"
79 + create_table "descriptions", id: :integer, charset: "utf8", force: :cascade do |t|
80 + t.text "body", size: :medium
81 81 t.boolean "markdowned"
82 82 t.datetime "created_at", precision: nil, null: false
83 83 t.datetime "updated_at", precision: nil, null: false
84 84 end
85 85
86 - create_table "grader_configurations", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
86 + create_table "grader_configurations", id: :integer, charset: "utf8", force: :cascade do |t|
87 87 t.string "key"
88 88 t.string "value_type"
89 89 t.string "value"
90 90 t.datetime "created_at", precision: nil, null: false
91 91 t.datetime "updated_at", precision: nil, null: false
92 - t.text "description"
92 + t.text "description", size: :medium
93 93 end
94 94
95 - create_table "grader_processes", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
95 + create_table "grader_processes", id: :integer, charset: "utf8", force: :cascade do |t|
96 96 t.string "host"
97 97 t.integer "pid"
98 98 t.string "mode"
99 99 t.boolean "active"
100 100 t.datetime "created_at", precision: nil, null: false
101 101 t.datetime "updated_at", precision: nil, null: false
102 102 t.integer "task_id"
103 103 t.string "task_type"
104 104 t.boolean "terminated"
105 105 t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
106 106 end
107 107
108 108 create_table "groups", id: :integer, charset: "latin1", force: :cascade do |t|
109 109 t.string "name"
110 110 t.string "description"
111 111 t.boolean "enabled", default: true
112 112 end
113 113
114 114 create_table "groups_problems", id: false, charset: "latin1", force: :cascade do |t|
115 115 t.integer "problem_id", null: false
116 116 t.integer "group_id", null: false
117 117 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
118 118 end
119 119
120 120 create_table "groups_users", charset: "latin1", force: :cascade do |t|
121 121 t.integer "group_id", null: false
122 122 t.integer "user_id", null: false
123 123 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
124 124 end
125 125
126 - create_table "heart_beats", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
126 + create_table "heart_beats", id: :integer, charset: "latin1", force: :cascade do |t|
127 127 t.integer "user_id"
128 128 t.string "ip_address"
129 129 t.datetime "created_at", precision: nil, null: false
130 130 t.datetime "updated_at", precision: nil, null: false
131 131 t.string "status"
132 132 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
133 133 end
134 134
135 - create_table "languages", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
135 + create_table "languages", id: :integer, charset: "utf8", force: :cascade do |t|
136 136 t.string "name", limit: 10
137 137 t.string "pretty_name"
138 138 t.string "ext", limit: 10
139 139 t.string "common_ext"
140 140 end
141 141
142 - create_table "logins", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
142 + create_table "logins", id: :integer, charset: "latin1", force: :cascade do |t|
143 143 t.integer "user_id"
144 144 t.string "ip_address"
145 145 t.datetime "created_at", precision: nil, null: false
146 146 t.datetime "updated_at", precision: nil, null: false
147 147 t.index ["user_id"], name: "index_logins_on_user_id"
148 148 end
149 149
150 - create_table "messages", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
150 + create_table "messages", id: :integer, charset: "utf8", force: :cascade do |t|
151 151 t.integer "sender_id"
152 152 t.integer "receiver_id"
153 153 t.integer "replying_message_id"
154 - t.text "body"
154 + t.text "body", size: :medium
155 155 t.boolean "replied"
156 156 t.datetime "created_at", precision: nil, null: false
157 157 t.datetime "updated_at", precision: nil, null: false
158 158 end
159 159
160 - create_table "problems", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
161 - t.string "name", limit: 30
160 + create_table "problems", id: :bigint, default: nil, charset: "utf8", force: :cascade do |t|
161 + t.string "name", limit: 100
162 162 t.string "full_name"
163 163 t.integer "full_score"
164 164 t.date "date_added"
165 165 t.boolean "available"
166 166 t.string "url"
167 167 t.integer "description_id"
168 168 t.boolean "test_allowed"
169 169 t.boolean "output_only"
170 170 t.string "description_filename"
171 171 t.boolean "view_testcase"
172 172 t.integer "difficulty"
173 173 t.text "description"
174 174 t.boolean "markdown"
175 175 end
176 176
177 - create_table "problems_tags", id: :integer, charset: "latin1", force: :cascade do |t|
178 - t.integer "problem_id"
177 + create_table "problems_tags", id: :bigint, default: nil, charset: "latin1", force: :cascade do |t|
178 + t.bigint "problem_id"
179 179 t.integer "tag_id"
180 180 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
181 181 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
182 182 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
183 183 end
184 184
185 - create_table "rights", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
185 + create_table "rights", id: :integer, charset: "utf8", force: :cascade do |t|
186 186 t.string "name"
187 187 t.string "controller"
188 188 t.string "action"
189 189 end
190 190
191 - create_table "rights_roles", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
191 + create_table "rights_roles", id: false, charset: "utf8", force: :cascade do |t|
192 192 t.integer "right_id"
193 193 t.integer "role_id"
194 194 t.index ["role_id"], name: "index_rights_roles_on_role_id"
195 195 end
196 196
197 - create_table "roles", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
197 + create_table "roles", id: :integer, charset: "utf8", force: :cascade do |t|
198 198 t.string "name"
199 199 end
200 200
201 - create_table "roles_users", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
201 + create_table "roles_users", id: false, charset: "utf8", force: :cascade do |t|
202 202 t.integer "role_id"
203 203 t.integer "user_id"
204 204 t.index ["user_id"], name: "index_roles_users_on_user_id"
205 205 end
206 206
207 - create_table "sessions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
207 + create_table "sessions", id: :integer, charset: "utf8", force: :cascade do |t|
208 208 t.string "session_id"
209 - t.text "data"
209 + t.text "data", size: :medium
210 210 t.datetime "updated_at", precision: nil
211 211 t.index ["session_id"], name: "index_sessions_on_session_id"
212 212 t.index ["updated_at"], name: "index_sessions_on_updated_at"
213 213 end
214 214
215 - create_table "sites", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
215 + create_table "sites", id: :integer, charset: "utf8", force: :cascade do |t|
216 216 t.string "name"
217 217 t.boolean "started"
218 218 t.datetime "start_time", precision: nil
219 219 t.datetime "created_at", precision: nil, null: false
220 220 t.datetime "updated_at", precision: nil, null: false
221 221 t.integer "country_id"
222 222 t.string "password"
223 223 end
224 224
225 - create_table "submission_view_logs", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
225 + create_table "solutions", charset: "latin1", force: :cascade do |t|
226 + t.string "solution"
227 + t.bigint "problem_id"
228 + t.bigint "submission_id"
229 + t.integer "type"
230 + t.index ["problem_id"], name: "index_solutions_on_problem_id"
231 + t.index ["submission_id"], name: "index_solutions_on_submission_id"
232 + end
233 +
234 + create_table "submission_view_logs", id: :integer, charset: "latin1", force: :cascade do |t|
226 235 t.integer "user_id"
227 236 t.integer "submission_id"
228 237 t.datetime "created_at", precision: nil, null: false
229 238 t.datetime "updated_at", precision: nil, null: false
230 239 end
231 240
232 - create_table "submissions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
241 + create_table "submissions", id: :bigint, default: nil, charset: "utf8", force: :cascade do |t|
233 242 t.integer "user_id"
234 243 t.integer "problem_id"
235 244 t.integer "language_id"
236 245 t.text "source", size: :medium
237 246 t.binary "binary"
238 247 t.datetime "submitted_at", precision: nil
239 248 t.datetime "compiled_at", precision: nil
240 - t.text "compiler_message"
249 + t.text "compiler_message", size: :medium
241 250 t.datetime "graded_at", precision: nil
242 251 t.integer "points"
243 - t.text "grader_comment"
252 + t.text "grader_comment", size: :medium
244 253 t.integer "number"
245 254 t.string "source_filename"
246 255 t.float "max_runtime"
247 256 t.integer "peak_memory"
248 257 t.integer "effective_code_length"
249 258 t.string "ip_address"
250 259 t.integer "tag", default: 0
251 260 t.index ["submitted_at"], name: "index_submissions_on_submitted_at"
252 261 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
253 262 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
254 263 end
255 264
256 265 create_table "tags", id: :integer, charset: "latin1", force: :cascade do |t|
257 266 t.string "name", null: false
258 267 t.text "description"
259 268 t.boolean "public"
260 269 t.datetime "created_at", precision: nil, null: false
261 270 t.datetime "updated_at", precision: nil, null: false
262 271 end
263 272
264 - create_table "tasks", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
273 + create_table "tasks", id: :integer, charset: "utf8", force: :cascade do |t|
265 274 t.integer "submission_id"
266 275 t.datetime "created_at", precision: nil
267 276 t.integer "status"
268 277 t.datetime "updated_at", precision: nil
269 278 t.index ["status"], name: "index_tasks_on_status"
270 279 t.index ["submission_id"], name: "index_tasks_on_submission_id"
271 280 end
272 281
273 - create_table "test_pairs", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
282 + create_table "test_pairs", id: :integer, charset: "utf8", force: :cascade do |t|
274 283 t.integer "problem_id"
275 - t.text "input", size: :medium
276 - t.text "solution", size: :medium
284 + t.text "input", size: :long
285 + t.text "solution", size: :long
277 286 t.datetime "created_at", precision: nil, null: false
278 287 t.datetime "updated_at", precision: nil, null: false
279 288 end
280 289
281 - create_table "test_requests", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
290 + create_table "test_requests", id: :integer, charset: "utf8", force: :cascade do |t|
282 291 t.integer "user_id"
283 292 t.integer "problem_id"
284 293 t.integer "submission_id"
285 294 t.string "input_file_name"
286 295 t.string "output_file_name"
287 296 t.string "running_stat"
288 297 t.integer "status"
289 298 t.datetime "updated_at", precision: nil, null: false
290 299 t.datetime "submitted_at", precision: nil
291 300 t.datetime "compiled_at", precision: nil
292 - t.text "compiler_message"
301 + t.text "compiler_message", size: :medium
293 302 t.datetime "graded_at", precision: nil
294 303 t.string "grader_comment"
295 304 t.datetime "created_at", precision: nil, null: false
296 305 t.float "running_time"
297 306 t.string "exit_status"
298 307 t.integer "memory_usage"
299 308 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
300 309 end
301 310
302 311 create_table "testcases", id: :integer, charset: "latin1", force: :cascade do |t|
303 312 t.integer "problem_id"
304 313 t.integer "num"
305 314 t.integer "group"
306 315 t.integer "score"
307 316 t.text "input", size: :long
308 317 t.text "sol", size: :long
309 - t.datetime "created_at", precision: nil
310 - t.datetime "updated_at", precision: nil
318 + t.datetime "created_at", precision: nil, null: false
319 + t.datetime "updated_at", precision: nil, null: false
311 320 t.index ["problem_id"], name: "index_testcases_on_problem_id"
312 321 end
313 322
314 - create_table "user_contest_stats", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
323 + create_table "user_contest_stats", id: :integer, charset: "utf8", force: :cascade do |t|
315 324 t.integer "user_id"
316 325 t.datetime "started_at", precision: nil
317 326 t.datetime "created_at", precision: nil, null: false
318 327 t.datetime "updated_at", precision: nil, null: false
319 328 t.boolean "forced_logout"
320 329 end
321 330
322 - create_table "users", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
331 + create_table "users", id: :integer, charset: "utf8", force: :cascade do |t|
323 332 t.string "login", limit: 50
324 333 t.string "full_name"
325 334 t.string "hashed_password"
326 335 t.string "salt", limit: 5
327 336 t.string "alias"
328 337 t.string "email"
329 338 t.integer "site_id"
330 339 t.integer "country_id"
331 340 t.boolean "activated", default: false
332 341 t.datetime "created_at", precision: nil
333 342 t.datetime "updated_at", precision: nil
343 + t.string "section"
334 344 t.boolean "enabled", default: true
335 345 t.string "remark"
336 346 t.string "last_ip"
337 - t.string "section"
338 347 t.integer "default_language"
339 348 t.index ["login"], name: "index_users_on_login", unique: true
340 349 end
341 350
342 351 add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
343 352 add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
344 353 add_foreign_key "problems_tags", "problems"
345 354 add_foreign_key "problems_tags", "tags"
355 + add_foreign_key "solutions", "problems"
356 + add_foreign_key "solutions", "submissions"
346 357 end
You need to be logged in to leave comments. Login now