Description:
saves and grades submission in standard mode
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r388:b5766b7ed3ec - - 2 files changed: 14 inserted, 2 deleted

@@ -1,494 +1,506
1 1 # coding: utf-8
2 2 class MainController < ApplicationController
3 3
4 4 before_filter :authenticate, :except => [:index, :login]
5 5 before_filter :check_viewability, :except => [:index, :login]
6 6
7 7 append_before_filter :confirm_and_update_start_time,
8 8 :except => [:index,
9 9 :login,
10 10 :confirm_contest_start]
11 11
12 12 # to prevent log in box to be shown when user logged out of the
13 13 # system only in some tab
14 14 prepend_before_filter :reject_announcement_refresh_when_logged_out,
15 15 :only => [:announcements]
16 16
17 17 # COMMENTED OUT: filter in each action instead
18 18 # before_filter :verify_time_limit, :only => [:submit]
19 19
20 20 verify :method => :post, :only => [:submit],
21 21 :redirect_to => { :action => :index }
22 22
23 23 # COMMENT OUT: only need when having high load
24 24 # caches_action :index, :login
25 25
26 26 # NOTE: This method is not actually needed, 'config/routes.rb' has
27 27 # assigned action login as a default action.
28 28 def index
29 29 redirect_to :action => 'login'
30 30 end
31 31
32 32 def login
33 33 saved_notice = flash[:notice]
34 34 reset_session
35 35 flash.now[:notice] = saved_notice
36 36
37 37 # EXPERIMENT:
38 38 # Hide login if in single user mode and the url does not
39 39 # explicitly specify /login
40 40 #
41 41 # logger.info "PATH: #{request.path}"
42 42 # if GraderConfiguration['system.single_user_mode'] and
43 43 # request.path!='/main/login'
44 44 # @hidelogin = true
45 45 # end
46 46
47 47 @announcements = Announcement.find_for_frontpage
48 48 render :action => 'login', :layout => 'empty'
49 49 end
50 50
51 51 def list
52 52 if session[:current_problem_id]
53 53 @current_problem = Problem.find(session[:current_problem_id])
54 54 session[:current_problem_id] = nil
55 55 end
56 56 prepare_list_information
57 57 end
58 58
59 59 def help
60 60 @user = User.find(session[:user_id])
61 61 end
62 62
63 63 def submit
64 64 user = User.find(session[:user_id])
65 65
66 66 @submission = Submission.new
67 67 @current_problem = Problem.find(params[:submission][:problem_id])
68 68
69 69 if !@current_problem
70 70 flash[:notice] = 'Error: คุณยังไม่ได้ระบุข้อที่ต้องการส่ง'
71 71 redirect_to :action => 'list'
72 72 end
73 73
74 74 assignment = user.get_test_pair_assignment_for(@current_problem)
75 75 if !assignment
76 76 flash[:notice] = 'Error: คุณยังไม่ได้ดาวน์โหลดข้อมูลทดสอบ'
77 77 prepare_list_information
78 78 render :action => 'list' and return
79 79 end
80 - if assignment.expired?
80 + if (assignment.expired?) and (!GraderConfiguration.standard_mode?)
81 81 flash[:notice] = 'Error: หมดเวลาส่งสำหรับข้อนี้'
82 82 prepare_list_information
83 83 render :action => 'list' and return
84 84 end
85 85
86 86 @submission.problem = @current_problem
87 87 @submission.user = user
88 88 @submission.language_id = 0
89 89 if (params['file']) and (params['file']!='')
90 90 @submission.source = params['file'].read
91 91 @submission.source_filename = params['file'].original_filename
92 92 end
93 93 if (params['output_file']) and (params['output_file']!='')
94 94 @submission.output = params['output_file'].read
95 95 end
96 96 @submission.submitted_at = Time.new.gmtime
97 97
98 98 if GraderConfiguration.time_limit_mode? and user.contest_finished?
99 99 @submission.errors.add(:base,"The contest is over.")
100 100 prepare_list_information
101 101 render :action => 'list' and return
102 102 end
103 103
104 + if GraderConfiguration.standard_mode?
105 + test_pair = assignment.test_pair
106 + result = test_pair.grade(@submission.output)
107 + @submission.points = result[:score]*100 / result[:full_score]
108 + @submission.grader_comment = result[:msg]
109 + @submission.graded_at = Time.now.gmtime
110 + end
111 +
104 112 if @submission.valid?
105 113 if @submission.save == false
106 114 flash[:notice] = 'Error saving your submission'
107 115 elsif Task.create(:submission_id => @submission.id,
108 116 :status => Task::STATUS_INQUEUE) == false
109 117 flash[:notice] = 'Error adding your submission to task queue'
110 118 else
111 119 flash[:notice] = 'จัดเก็บคำตอบและโปรแกรมที่คุณส่งเรียบร้อย'
112 120 end
113 121 else
114 122 prepare_list_information
115 123 render :action => 'list' and return
116 124 end
117 125
118 126 if @current_problem
119 127 session[:current_problem_id] = @current_problem.id
120 128 end
121 129 redirect_to :action => 'list'
122 130 end
123 131
124 132 def source
125 133 submission = Submission.find(params[:id])
126 134 if ((submission.user_id == session[:user_id]) and
127 135 (submission.problem != nil) and
128 136 (submission.problem.available))
129 137 send_data(submission.source,
130 138 {:filename => submission.download_filename,
131 139 :type => 'text/plain'})
132 140 else
133 141 flash[:notice] = 'Error viewing source'
134 142 redirect_to :action => 'list'
135 143 end
136 144 end
137 145
138 146 def compiler_msg
139 147 @submission = Submission.find(params[:id])
140 148 if @submission.user_id == session[:user_id]
141 149 render :action => 'compiler_msg', :layout => 'empty'
142 150 else
143 151 flash[:notice] = 'Error viewing source'
144 152 redirect_to :action => 'list'
145 153 end
146 154 end
147 155
148 156 def submission
149 157 @user = User.find(session[:user_id])
150 158 @problems = @user.available_problems
151 159 if params[:id]==nil
152 160 @problem = nil
153 161 @submissions = nil
154 162 else
155 163 @problem = Problem.find_by_name(params[:id])
156 164 if not @problem.available
157 165 redirect_to :action => 'list'
158 166 flash[:notice] = 'Error: submissions for that problem are not viewable.'
159 167 return
160 168 end
161 169 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
162 170 end
163 171 end
164 172
165 173 def result
166 174 if !GraderConfiguration.show_grading_result
167 175 redirect_to :action => 'list' and return
168 176 end
169 177 @user = User.find(session[:user_id])
170 178 @submission = Submission.find(params[:id])
171 179 if @submission.user!=@user
172 180 flash[:notice] = 'You are not allowed to view result of other users.'
173 181 redirect_to :action => 'list' and return
174 182 end
175 183 prepare_grading_result(@submission)
176 184 end
177 185
178 186 def load_output
179 187 if !GraderConfiguration.show_grading_result or params[:num]==nil
180 188 redirect_to :action => 'list' and return
181 189 end
182 190 @user = User.find(session[:user_id])
183 191 @submission = Submission.find(params[:id])
184 192 if @submission.user!=@user
185 193 flash[:notice] = 'You are not allowed to view result of other users.'
186 194 redirect_to :action => 'list' and return
187 195 end
188 196 case_num = params[:num].to_i
189 197 out_filename = output_filename(@user.login,
190 198 @submission.problem.name,
191 199 @submission.id,
192 200 case_num)
193 201 if !FileTest.exists?(out_filename)
194 202 flash[:notice] = 'Output not found.'
195 203 redirect_to :action => 'list' and return
196 204 end
197 205
198 206 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
199 207 response.headers['Content-Type'] = "application/force-download"
200 208 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
201 209 response.headers["X-Sendfile"] = out_filename
202 210 response.headers['Content-length'] = File.size(out_filename)
203 211 render :nothing => true
204 212 else
205 213 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
206 214 end
207 215 end
208 216
209 217 def error
210 218 @user = User.find(session[:user_id])
211 219 end
212 220
213 221 # announcement refreshing and hiding methods
214 222
215 223 def announcements
216 224 if params.has_key? 'recent'
217 225 prepare_announcements(params[:recent])
218 226 else
219 227 prepare_announcements
220 228 end
221 229 render(:partial => 'announcement',
222 230 :collection => @announcements,
223 231 :locals => {:announcement_effect => true})
224 232 end
225 233
226 234 def confirm_contest_start
227 235 user = User.find(session[:user_id])
228 236 if request.method == 'POST'
229 237 user.update_start_time
230 238 redirect_to :action => 'list'
231 239 else
232 240 @contests = user.contests
233 241 @user = user
234 242 end
235 243 end
236 244
237 245 # thailandoi contests
238 246
239 247 def verifying_testcase
240 248 problem = Problem.find(params[:id])
241 249 if !problem.available
242 250 flash[:notice] = 'Error: problem is not available'
243 251 redirect_to :action => 'list'
244 252 else
245 253 test_pair = TestPair.get_for(problem, false)
246 254 send_data(test_pair.input,
247 255 {:filename => problem.name + '-verifying-input.txt',
248 256 :type => 'text/plain'})
249 257 end
250 258 end
251 259
252 260 def testcase
253 261 problem = Problem.find(params[:id])
254 262 if !problem.available
255 263 flash[:notice] = 'Error: problem is not available'
256 264 redirect_to :action => 'list'
257 265 else
258 266 test_pair = TestPair.get_for(problem, true)
259 267
260 268 user = User.find(session[:user_id])
261 269 assignment = user.get_test_pair_assignment_for(problem)
262 270
263 271 if !assignment
264 272 assignment = TestPairAssignment.create_for(user, problem, test_pair)
265 273 assignment.save
266 274 end
267 275
268 276 send_data(test_pair.input,
269 277 {:filename => problem.name + '-input.txt',
270 278 :type => 'text/plain'})
271 279 end
272 280 end
273 281
274 282 def verifying_submit
275 283 user = User.find(session[:user_id])
276 284 problem_id = params[:id]
277 285 problem = Problem.find(problem_id)
278 286
279 287 if !problem or !problem.available
280 288 flash[:notice] = 'Error: problem is not available'
281 289 redirect_to :action => 'list' and return
282 290 end
283 291
284 292 @current_problem = problem
285 293 test_pair = TestPair.get_for(problem, false)
286 294 if (params['output_file']) and (params['output_file']!='')
287 295 output = params['output_file'].read
288 296
289 297 @grading_result = test_pair.grade(output)
290 298 prepare_list_information
291 299 render :action => 'list' and return
292 300 else
293 301 flash[:notice] = 'Error: output file errors'
294 302 prepare_list_information
295 303 render :action => 'list' and return
296 304 end
297 305 end
298 306
299 307 protected
300 308
301 309 def prepare_announcements(recent=nil)
302 310 if GraderConfiguration.show_tasks_to?(@user)
303 311 @announcements = Announcement.find_published(true)
304 312 else
305 313 @announcements = Announcement.find_published
306 314 end
307 315 if recent!=nil
308 316 recent_id = recent.to_i
309 317 @announcements = @announcements.find_all { |a| a.id > recent_id }
310 318 end
311 319 end
312 320
313 321 def prepare_timeout_information(problems)
314 322 @submission_timeouts = {}
315 323 problems.each do |problem|
316 324 assignment = @user.get_test_pair_assignment_for(problem)
325 + if GraderConfiguration.standard_mode?
326 + timeout = nil
327 + else
317 328 if assignment == nil
318 329 timeout = nil
319 330 else
320 331 if (assignment.expired?) or (assignment.submitted)
321 332 timeout = 0
322 333 else
323 334 timeout = assignment.created_at + TEST_ASSIGNMENT_EXPIRATION_DURATION - Time.new.gmtime
324 335 end
325 336 end
337 + end
326 338 @submission_timeouts[problem.id] = timeout
327 339 end
328 340 end
329 341
330 342 def prepare_list_information
331 343 @user = User.find(session[:user_id])
332 344 if not GraderConfiguration.multicontests?
333 345 @problems = @user.available_problems
334 346 else
335 347 @contest_problems = @user.available_problems_group_by_contests
336 348 @problems = @user.available_problems
337 349 end
338 350 @prob_submissions = {}
339 351 @problems.each do |p|
340 352 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
341 353 if sub!=nil
342 354 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
343 355 else
344 356 @prob_submissions[p.id] = { :count => 0, :submission => nil }
345 357 end
346 358 end
347 359 prepare_announcements
348 360 prepare_timeout_information(@problems)
349 361 end
350 362
351 363 def check_viewability
352 364 @user = User.find(session[:user_id])
353 365 if (!GraderConfiguration.show_tasks_to?(@user)) and
354 366 ((action_name=='submission') or (action_name=='submit'))
355 367 redirect_to :action => 'list' and return
356 368 end
357 369 end
358 370
359 371 def prepare_grading_result(submission)
360 372 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
361 373 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
362 374 else
363 375 # guess task info from problem.full_score
364 376 cases = submission.problem.full_score / 10
365 377 grading_info = {
366 378 'testruns' => cases,
367 379 'testcases' => cases
368 380 }
369 381 end
370 382 @test_runs = []
371 383 if grading_info['testruns'].is_a? Integer
372 384 trun_count = grading_info['testruns']
373 385 trun_count.times do |i|
374 386 @test_runs << [ read_grading_result(@user.login,
375 387 submission.problem.name,
376 388 submission.id,
377 389 i+1) ]
378 390 end
379 391 else
380 392 grading_info['testruns'].keys.sort.each do |num|
381 393 run = []
382 394 testrun = grading_info['testruns'][num]
383 395 testrun.each do |c|
384 396 run << read_grading_result(@user.login,
385 397 submission.problem.name,
386 398 submission.id,
387 399 c)
388 400 end
389 401 @test_runs << run
390 402 end
391 403 end
392 404 end
393 405
394 406 def grading_result_dir(user_name, problem_name, submission_id, case_num)
395 407 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
396 408 end
397 409
398 410 def output_filename(user_name, problem_name, submission_id, case_num)
399 411 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
400 412 return "#{dir}/output.txt"
401 413 end
402 414
403 415 def read_grading_result(user_name, problem_name, submission_id, case_num)
404 416 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
405 417 result_file_name = "#{dir}/result"
406 418 if !FileTest.exists?(result_file_name)
407 419 return {:num => case_num, :msg => 'program did not run'}
408 420 else
409 421 results = File.open(result_file_name).readlines
410 422 run_stat = extract_running_stat(results)
411 423 output_filename = "#{dir}/output.txt"
412 424 if FileTest.exists?(output_filename)
413 425 output_file = true
414 426 output_size = File.size(output_filename)
415 427 else
416 428 output_file = false
417 429 output_size = 0
418 430 end
419 431
420 432 return {
421 433 :num => case_num,
422 434 :msg => results[0],
423 435 :run_stat => run_stat,
424 436 :output => output_file,
425 437 :output_size => output_size
426 438 }
427 439 end
428 440 end
429 441
430 442 # copied from grader/script/lib/test_request_helper.rb
431 443 def extract_running_stat(results)
432 444 running_stat_line = results[-1]
433 445
434 446 # extract exit status line
435 447 run_stat = ""
436 448 if !(/[Cc]orrect/.match(results[0]))
437 449 run_stat = results[0].chomp
438 450 else
439 451 run_stat = 'Program exited normally'
440 452 end
441 453
442 454 logger.info "Stat line: #{running_stat_line}"
443 455
444 456 # extract running time
445 457 if res = /r(.*)u(.*)s/.match(running_stat_line)
446 458 seconds = (res[1].to_f + res[2].to_f)
447 459 time_stat = "Time used: #{seconds} sec."
448 460 else
449 461 seconds = nil
450 462 time_stat = "Time used: n/a sec."
451 463 end
452 464
453 465 # extract memory usage
454 466 if res = /s(.*)m/.match(running_stat_line)
455 467 memory_used = res[1].to_i
456 468 else
457 469 memory_used = -1
458 470 end
459 471
460 472 return {
461 473 :msg => "#{run_stat}\n#{time_stat}",
462 474 :running_time => seconds,
463 475 :exit_status => run_stat,
464 476 :memory_usage => memory_used
465 477 }
466 478 end
467 479
468 480 def confirm_and_update_start_time
469 481 user = User.find(session[:user_id])
470 482 if (GraderConfiguration.indv_contest_mode? and
471 483 GraderConfiguration['contest.confirm_indv_contest_start'] and
472 484 !user.contest_started?)
473 485 redirect_to :action => 'confirm_contest_start' and return
474 486 end
475 487 if not GraderConfiguration.analysis_mode?
476 488 user.update_start_time
477 489 end
478 490 end
479 491
480 492 def reject_announcement_refresh_when_logged_out
481 493 if not session[:user_id]
482 494 render :text => 'Access forbidden', :status => 403
483 495 end
484 496
485 497 if GraderConfiguration.multicontests?
486 498 user = User.find(session[:user_id])
487 499 if user.contest_stat.forced_logout
488 500 render :text => 'Access forbidden', :status => 403
489 501 end
490 502 end
491 503 end
492 504
493 505 end
494 506
@@ -1,38 +1,38
1 1 <% selected_problem_id = @current_problem ? @current_problem.id : -1 %>
2 2 <div class="submitbox">
3 3 <b>Problem:</b> <%= select 'submission', 'problem_id',
4 4 [['กรุณาเลือกข้อที่ต้องการส่งหรือทดสอบ','-1']] +
5 5 @problems.collect {|p| [p.full_name, p.id]},
6 6 { :selected => selected_problem_id },
7 7 { :onchange => 'TOIContest.problemSelectClick()' } %>
8 8 </div>
9 9
10 10 <% @problems.each do |problem| %>
11 11 <div class="submission-submit-divs" id="submission_submit_div_<%= problem.id %>_id" style="display: none;">
12 12 <div style="border: 1px solid #c0c0c0; padding: 5px; margin: 5px 0 5px 0;">
13 13 <b><%= problem.full_name %>: ข้อมูลสำหรับตรวจสอบ</b> (สามารถดาวน์โหลดและส่งกี่ครั้งก็ได้,ไม่มีคะแนน):
14 14 <%= link_to 'ดาวน์โหลด input', :action => 'verifying_testcase', :id => problem.id %>
15 15 <% if @current_problem and @current_problem.id == problem.id %>
16 16 <% if @grading_result %>
17 17 | <b>ผลการตรวจ:</b> <%= "#{@grading_result[:score]}/#{@grading_result[:full_score]} [#{@grading_result[:msg]}]" %>
18 18 <% end %>
19 19 <% end %>
20 20 <%= form_tag({:controller => 'main', :action => 'verifying_submit', :id => problem.id}, {:method => 'post', :multipart => true }) do %>
21 21 ส่งคำตอบของข้อมูลสำหรับตรวจสอบ:
22 22 <%= file_field_tag 'output_file' %>
23 23 <%= submit_tag 'Submit' %>
24 24 <% end %>
25 25 </div>
26 26 <div style="border: 1px solid #c0c0c0; padding: 5px; margin: 5px 0 5px 0;">
27 27 <b><%= problem.full_name %>: ข้อมูลทดสอบจริง</b> (ส่งกี่ครั้งก็ได้ภายในเวลา 5 นาทีหลังดาวน์โหลด):
28 28 <%= link_to 'ดาวน์โหลด input และเริ่มจับเวลา', { :action => 'testcase', :id => problem.id}, { :onclick => "return TOIContest.confirmDownload(#{problem.id})" } %>
29 29 <span id="submission_time_left_<%= problem.id %>_id"></span>
30 30 <%= form_tag({:controller => 'main', :action => 'submit'}, {:method => 'post', :multipart => true, :id => "submission_form_#{problem.id}_id" }) do %>
31 31 <%= hidden_field_tag 'submission[problem_id]', problem.id %>
32 32 ข้อมูลส่งออก: <%= file_field_tag 'output_file' %>
33 - โปรแกรมคำตอบ: <%= file_field_tag 'file' %>
33 + โปรแกรมของคุณ: <%= file_field_tag 'file' %>
34 34 <%= submit_tag 'Submit' %>
35 35 <% end %>
36 36 </div>
37 37 </div>
38 38 <% end %>
You need to be logged in to leave comments. Login now