Description:
saves submitted output, checks time outs; updated submission front-end flows
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
r383:31aa87b1b1e9 - - 8 files changed: 116 inserted, 20 deleted
@@ -0,0 +1,5 | |||
|
1 | + class AddOutputToSubmissions < ActiveRecord::Migration | |
|
2 | + def change | |
|
3 | + add_column :submissions, :output, :text | |
|
4 | + end | |
|
5 | + end |
@@ -1,37 +1,77 | |||
|
1 | 1 | var TOIContest = { |
|
2 | 2 | NO_TIMEOUT: -1, |
|
3 | + SUBMISSION_TIMEOUT: 300, | |
|
3 | 4 | |
|
4 | 5 | timeOuts: {}, |
|
6 | + timeStarted: 0, | |
|
5 | 7 | |
|
6 | 8 | problemSelectClick: function() { |
|
7 | 9 | $$(".submission-submit-divs").each(function(item) { |
|
8 | 10 | item.hide(); |
|
9 | 11 | }); |
|
10 | 12 | var problem_id = $('submission_problem_id').value; |
|
11 | 13 | if ( problem_id < 0 ) { |
|
12 | 14 | return; |
|
13 | 15 | } |
|
14 | 16 | $("submission_submit_div_" + problem_id + "_id").show(); |
|
15 | 17 | }, |
|
16 | 18 | |
|
17 | - confirmDownload: function() { | |
|
18 | - return confirm("แน่ใจ?"); | |
|
19 | + confirmDownload: function(pid) { | |
|
20 | + result = confirm("คุณแน่ใจที่จะส่งข้อนี้หรือไม่?\nเมื่อคุณดาวน์โหลดข้อมูลชุดทดสอบแล้ว คุณจะต้องส่งข้อมูลส่งออกและโปรแกรมภายในเวลา 5 นาที"); | |
|
21 | + if ( result ) { | |
|
22 | + if ( TOIContest.timeOuts[ pid ] == TOIContest.NO_TIMEOUT ) { | |
|
23 | + TOIContest.refreshTimeOuts(); | |
|
24 | + | |
|
25 | + TOIContest.timeOuts[ pid ] = TOIContest.SUBMISSION_TIMEOUT; | |
|
26 | + | |
|
27 | + TOIContest.refreshTimeOutMessages(); | |
|
28 | + } | |
|
29 | + } | |
|
30 | + return result; | |
|
19 | 31 | }, |
|
20 | 32 | |
|
21 | 33 | refreshTimeOutMessages: function() { |
|
22 | 34 | for ( var pid in TOIContest.timeOuts ) { |
|
23 | 35 | var timeOut = TOIContest.timeOuts[ pid ]; |
|
24 | 36 | if ( timeOut != TOIContest.NO_TIMEOUT ) { |
|
25 | 37 | if ( timeOut > 0 ) { |
|
26 | 38 | var minLeft = parseInt(timeOut / 60); |
|
27 | 39 | var secLeft = parseInt(timeOut % 60); |
|
28 | 40 | $('submission_time_left_' + pid + '_id').innerHTML = '| <b>เหลือเวลาอีก ' + minLeft + ':' + secLeft + ' นาที</b>'; |
|
41 | + $('submission_form_'+ pid + '_id').show(); | |
|
29 | 42 | } else { |
|
30 | 43 | $('submission_time_left_' + pid + '_id').innerHTML = '| <b>หมดเวลาส่ง</a>'; |
|
31 | 44 | $('submission_form_'+ pid + '_id').hide(); |
|
32 | 45 | } |
|
33 | - } | |
|
46 | + } else { | |
|
47 | + $('submission_form_'+ pid + '_id').hide(); | |
|
34 | 48 | } |
|
35 | 49 | } |
|
50 | + }, | |
|
51 | + | |
|
52 | + refreshTimeOuts: function() { | |
|
53 | + if ( TOIContest.timeStarted == 0 ) { | |
|
54 | + TOIContest.timeStarted = (new Date()).getTime(); | |
|
55 | + } | |
|
56 | + | |
|
57 | + var timeElapsed = ((new Date()).getTime() - TOIContest.timeStarted)/1000; | |
|
58 | + for ( var pid in TOIContest.timeOuts ) { | |
|
59 | + var timeOut = TOIContest.timeOuts[ pid ]; | |
|
60 | + if ( timeOut > timeElapsed ) { | |
|
61 | + TOIContest.timeOuts[ pid ] -= timeElapsed; | |
|
62 | + } else if ( timeOut > 0 ) { | |
|
63 | + TOIContest.timeOuts[ pid ] = 0; | |
|
64 | + } | |
|
65 | + } | |
|
66 | + }, | |
|
67 | + | |
|
68 | + registerRefreshEvent: function() { | |
|
69 | + TOIContest.timeStarted = (new Date()).getTime(); | |
|
70 | + setTimeout(function () { | |
|
71 | + TOIContest.refreshTimeOuts(); | |
|
72 | + TOIContest.refreshTimeOutMessages(); | |
|
73 | + TOIContest.registerRefreshEvent(); | |
|
74 | + }, 1000); | |
|
75 | + }, | |
|
36 | 76 | }; |
|
37 | 77 |
@@ -1,6 +1,7 | |||
|
1 | + # coding: utf-8 | |
|
1 | 2 | class MainController < ApplicationController |
|
2 | 3 | |
|
3 | 4 | before_filter :authenticate, :except => [:index, :login] |
|
4 | 5 | before_filter :check_viewability, :except => [:index, :login] |
|
5 | 6 | |
|
6 | 7 | append_before_filter :confirm_and_update_start_time, |
@@ -45,30 +46,56 | |||
|
45 | 46 | |
|
46 | 47 | @announcements = Announcement.find_for_frontpage |
|
47 | 48 | render :action => 'login', :layout => 'empty' |
|
48 | 49 | end |
|
49 | 50 | |
|
50 | 51 | def list |
|
52 | + if session[:current_problem_id] | |
|
53 | + @current_problem = Problem.find(session[:current_problem_id]) | |
|
54 | + session[:current_problem_id] = nil | |
|
55 | + end | |
|
51 | 56 | prepare_list_information |
|
52 | 57 | end |
|
53 | 58 | |
|
54 | 59 | def help |
|
55 | 60 | @user = User.find(session[:user_id]) |
|
56 | 61 | end |
|
57 | 62 | |
|
58 | 63 | def submit |
|
59 | 64 | user = User.find(session[:user_id]) |
|
60 | 65 | |
|
61 | 66 | @submission = Submission.new |
|
62 |
- @ |
|
|
67 | + @current_problem = Problem.find(params[:submission][:problem_id]) | |
|
68 | + | |
|
69 | + if !@current_problem | |
|
70 | + flash[:notice] = 'Error: คุณยังไม่ได้ระบุข้อที่ต้องการส่ง' | |
|
71 | + redirect_to :action => 'list' | |
|
72 | + end | |
|
73 | + | |
|
74 | + assignment = user.get_test_pair_assignment_for(@current_problem) | |
|
75 | + if !assignment | |
|
76 | + flash[:notice] = 'Error: คุณยังไม่ได้ดาวน์โหลดข้อมูลทดสอบ' | |
|
77 | + prepare_list_information | |
|
78 | + render :action => 'list' and return | |
|
79 | + end | |
|
80 | + if assignment.expired? | |
|
81 | + flash[:notice] = 'Error: หมดเวลาส่งสำหรับข้อนี้' | |
|
82 | + prepare_list_information | |
|
83 | + render :action => 'list' and return | |
|
84 | + end | |
|
85 | + | |
|
86 | + @submission.problem = @current_problem | |
|
63 | 87 | @submission.user = user |
|
64 | 88 | @submission.language_id = 0 |
|
65 | 89 | if (params['file']) and (params['file']!='') |
|
66 | 90 | @submission.source = params['file'].read |
|
67 | 91 | @submission.source_filename = params['file'].original_filename |
|
68 | 92 | end |
|
93 | + if (params['output_file']) and (params['output_file']!='') | |
|
94 | + @submission.output = params['output_file'].read | |
|
95 | + end | |
|
69 | 96 | @submission.submitted_at = Time.new.gmtime |
|
70 | 97 | |
|
71 | 98 | if GraderConfiguration.time_limit_mode? and user.contest_finished? |
|
72 | 99 | @submission.errors.add(:base,"The contest is over.") |
|
73 | 100 | prepare_list_information |
|
74 | 101 | render :action => 'list' and return |
@@ -77,17 +104,23 | |||
|
77 | 104 | if @submission.valid? |
|
78 | 105 | if @submission.save == false |
|
79 | 106 | flash[:notice] = 'Error saving your submission' |
|
80 | 107 | elsif Task.create(:submission_id => @submission.id, |
|
81 | 108 | :status => Task::STATUS_INQUEUE) == false |
|
82 | 109 | flash[:notice] = 'Error adding your submission to task queue' |
|
110 | + else | |
|
111 | + flash[:notice] = 'จัดเก็บคำตอบและโปรแกรมที่คุณส่งเรียบร้อย' | |
|
83 | 112 | end |
|
84 | 113 | else |
|
85 | 114 | prepare_list_information |
|
86 | 115 | render :action => 'list' and return |
|
87 | 116 | end |
|
117 | + | |
|
118 | + if @current_problem | |
|
119 | + session[:current_problem_id] = @current_problem.id | |
|
120 | + end | |
|
88 | 121 | redirect_to :action => 'list' |
|
89 | 122 | end |
|
90 | 123 | |
|
91 | 124 | def source |
|
92 | 125 | submission = Submission.find(params[:id]) |
|
93 | 126 | if ((submission.user_id == session[:user_id]) and |
@@ -222,21 +255,17 | |||
|
222 | 255 | flash[:notice] = 'Error: problem is not available' |
|
223 | 256 | redirect_to :action => 'list' |
|
224 | 257 | else |
|
225 | 258 | test_pair = TestPair.get_for(problem, true) |
|
226 | 259 | |
|
227 | 260 | user = User.find(session[:user_id]) |
|
228 | - assignent = user.get_test_pair_assignment_for(problem) | |
|
261 | + assignment = user.get_test_pair_assignment_for(problem) | |
|
229 | 262 | |
|
230 | - if !assignent | |
|
231 |
- assignent = TestPairAssignment. |
|
|
232 |
- assignent. |
|
|
233 | - assignent.problem = problem | |
|
234 | - assignent.test_pair = test_pair | |
|
235 | - assignent.submitted = false | |
|
236 | - assignent.save | |
|
263 | + if !assignment | |
|
264 | + assignment = TestPairAssignment.create_for(user, problem, test_pair) | |
|
265 | + assignment.save | |
|
237 | 266 | end |
|
238 | 267 | |
|
239 | 268 | send_data(test_pair.input, |
|
240 | 269 | {:filename => problem.name + '-input.txt', |
|
241 | 270 | :type => 'text/plain'}) |
|
242 | 271 | end |
@@ -249,23 +278,24 | |||
|
249 | 278 | |
|
250 | 279 | if !problem or !problem.available |
|
251 | 280 | flash[:notice] = 'Error: problem is not available' |
|
252 | 281 | redirect_to :action => 'list' and return |
|
253 | 282 | end |
|
254 | 283 | |
|
284 | + @current_problem = problem | |
|
255 | 285 | test_pair = TestPair.get_for(problem, false) |
|
256 | 286 | if (params['output_file']) and (params['output_file']!='') |
|
257 | 287 | output = params['output_file'].read |
|
258 | 288 | |
|
259 | - @current_problem = problem | |
|
260 | 289 | @grading_result = grade(output, test_pair.solution) |
|
261 | 290 | prepare_list_information |
|
262 | 291 | render :action => 'list' and return |
|
263 | 292 | else |
|
264 | 293 | flash[:notice] = 'Error: output file errors' |
|
265 | - redirect_to :action => 'list' | |
|
294 | + prepare_list_information | |
|
295 | + render :action => 'list' and return | |
|
266 | 296 | end |
|
267 | 297 | end |
|
268 | 298 | |
|
269 | 299 | protected |
|
270 | 300 | |
|
271 | 301 | def grade(output, solution) |
@@ -7,12 +7,17 | |||
|
7 | 7 | before_validation :assign_problem |
|
8 | 8 | before_validation :assign_language |
|
9 | 9 | |
|
10 | 10 | validates_presence_of :source |
|
11 | 11 | validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'too long' |
|
12 | 12 | validates_length_of :source, :minimum => 1, :allow_blank => true, :message => 'too short' |
|
13 | + | |
|
14 | + validates_presence_of :output | |
|
15 | + validates_length_of :output, :maximum => 100_000, :allow_blank => true, :message => 'too long' | |
|
16 | + validates_length_of :output, :minimum => 1, :allow_blank => true, :message => 'too short' | |
|
17 | + | |
|
13 | 18 | validate :must_have_valid_problem |
|
14 | 19 | validate :must_specify_language |
|
15 | 20 | |
|
16 | 21 | before_save :assign_latest_number_if_new_recond |
|
17 | 22 | |
|
18 | 23 | def self.find_last_by_user_and_problem(user_id, problem_id) |
@@ -3,7 +3,17 | |||
|
3 | 3 | belongs_to :test_pair |
|
4 | 4 | belongs_to :user |
|
5 | 5 | |
|
6 | 6 | def expired? |
|
7 | 7 | return created_at + TEST_ASSIGNMENT_EXPIRATION_DURATION < Time.new.gmtime |
|
8 | 8 | end |
|
9 | + | |
|
10 | + def self.create_for(user, problem, test_pair) | |
|
11 | + assignment = TestPairAssignment.new | |
|
12 | + assignment.user = user | |
|
13 | + assignment.problem = problem | |
|
14 | + assignment.test_pair = test_pair | |
|
15 | + assignment.submitted = false | |
|
16 | + assignment.save | |
|
17 | + return assignment | |
|
9 | 18 | end |
|
19 | + end |
@@ -1,16 +1,17 | |||
|
1 | + <% selected_problem_id = @current_problem ? @current_problem.id : -1 %> | |
|
1 | 2 | <div class="submitbox"> |
|
2 | 3 | <b>Problem:</b> <%= select 'submission', 'problem_id', |
|
3 | 4 | [['กรุณาเลือกข้อที่ต้องการส่งหรือทดสอบ','-1']] + |
|
4 | 5 | @problems.collect {|p| [p.full_name, p.id]}, |
|
5 |
- { :selected => |
|
|
6 | + { :selected => selected_problem_id }, | |
|
6 | 7 | { :onchange => 'TOIContest.problemSelectClick()' } %> |
|
7 | 8 | </div> |
|
8 | 9 | |
|
9 | 10 | <% @problems.each do |problem| %> |
|
10 |
- <div class="submission-submit-divs" id="submission_submit_div_<%= problem.id %>_id" style="displa |
|
|
11 | + <div class="submission-submit-divs" id="submission_submit_div_<%= problem.id %>_id" style="display: none;"> | |
|
11 | 12 | <div style="border: 1px solid #c0c0c0; padding: 5px; margin: 5px 0 5px 0;"> |
|
12 | 13 | <b><%= problem.full_name %>: ข้อมูลสำหรับตรวจสอบ</b> (สามารถดาวน์โหลดและส่งกี่ครั้งก็ได้,ไม่มีคะแนน): |
|
13 | 14 | <%= link_to 'ดาวน์โหลด input', :action => 'verifying_testcase', :id => problem.id %> |
|
14 | 15 | <% if @current_problem and @current_problem.id == problem.id %> |
|
15 | 16 | <% if @grading_result %> |
|
16 | 17 | | <b>ผลการตรวจ:</b> <%= "#{@grading_result[:score]}/#{@grading_result[:full_score]} [#{@grading_result[:msg]}]" %> |
@@ -21,16 +22,17 | |||
|
21 | 22 | <%= file_field_tag 'output_file' %> |
|
22 | 23 | <%= submit_tag 'Submit' %> |
|
23 | 24 | <% end %> |
|
24 | 25 | </div> |
|
25 | 26 | <div style="border: 1px solid #c0c0c0; padding: 5px; margin: 5px 0 5px 0;"> |
|
26 | 27 | <b><%= problem.full_name %>: ข้อมูลทดสอบจริง</b> (ส่งกี่ครั้งก็ได้ภายในเวลา 5 นาทีหลังดาวน์โหลด): |
|
27 |
- <%= link_to 'ดาวน์โหลด input และเริ่มจับเวลา', { :action => 'testcase', :id => problem.id}, { :onclick => |
|
|
28 | + <%= link_to 'ดาวน์โหลด input และเริ่มจับเวลา', { :action => 'testcase', :id => problem.id}, { :onclick => "return TOIContest.confirmDownload(#{problem.id})" } %> | |
|
28 | 29 | <span id="submission_time_left_<%= problem.id %>_id"></span> |
|
29 |
- <%= form_tag({:controller => 'main', :action => 'submit' |
|
|
30 | + <%= form_tag({:controller => 'main', :action => 'submit'}, {:method => 'post', :multipart => true, :id => "submission_form_#{problem.id}_id" }) do %> | |
|
31 | + <%= hidden_field_tag 'submission[problem_id]', problem.id %> | |
|
30 | 32 | ข้อมูลส่งออก: <%= file_field_tag 'output_file' %> |
|
31 |
- โปรแกรมคำตอบ: <%= file_field_tag ' |
|
|
33 | + โปรแกรมคำตอบ: <%= file_field_tag 'file' %> | |
|
32 | 34 | <%= submit_tag 'Submit' %> |
|
33 | 35 | <% end %> |
|
34 | 36 | </div> |
|
35 | 37 | </div> |
|
36 | 38 | <% end %> |
@@ -46,14 +46,17 | |||
|
46 | 46 | %hr/ |
|
47 | 47 | |
|
48 | 48 | %script{:type => 'text/javascript'} |
|
49 | 49 | = "Announcement.refreshUrl = '#{url_for :controller => 'main', :action => 'announcements'}';" |
|
50 | 50 | Announcement.registerRefreshEventTimer(); |
|
51 | 51 | |
|
52 | + TOIContest.problemSelectClick() | |
|
53 | + | |
|
52 | 54 | TOIContest.timeOuts = {}; |
|
53 | 55 | - @problems.each do |p| |
|
54 | 56 | - if (@submission_timeouts.has_key? p.id) and (@submission_timeouts[p.id] != nil) |
|
55 | 57 | = "TOIContest.timeOuts[#{p.id}] = #{@submission_timeouts[p.id]};" |
|
56 | 58 | - else |
|
57 | 59 | = "TOIContest.timeOuts[#{p.id}] = TOIContest.NO_TIMEOUT;" |
|
58 | 60 | |
|
59 | 61 | TOIContest.refreshTimeOutMessages(); |
|
62 | + TOIContest.registerRefreshEvent(); |
@@ -8,13 +8,13 | |||
|
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 to check this file into your version control system. |
|
13 | 13 | |
|
14 |
- ActiveRecord::Schema.define(:version => 2015012 |
|
|
14 | + ActiveRecord::Schema.define(:version => 20150129021221) do | |
|
15 | 15 | |
|
16 | 16 | create_table "announcements", :force => true do |t| |
|
17 | 17 | t.string "author" |
|
18 | 18 | t.text "body" |
|
19 | 19 | t.boolean "published" |
|
20 | 20 | t.datetime "created_at", :null => false |
@@ -163,12 +163,13 | |||
|
163 | 163 | t.text "compiler_message" |
|
164 | 164 | t.datetime "graded_at" |
|
165 | 165 | t.integer "points" |
|
166 | 166 | t.text "grader_comment" |
|
167 | 167 | t.integer "number" |
|
168 | 168 | t.string "source_filename" |
|
169 | + t.text "output" | |
|
169 | 170 | end |
|
170 | 171 | |
|
171 | 172 | add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true |
|
172 | 173 | add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id" |
|
173 | 174 | |
|
174 | 175 | create_table "tasks", :force => true do |t| |
You need to be logged in to leave comments.
Login now