Description:
saves submitted output, checks time outs; updated submission front-end flows
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

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 - @submission.problem_id = params[:submission][:problem_id]
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.new
232 - assignent.user = user
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 => '-1' },
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="displanny: none;">
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 => 'return TOIContest.confirmDownload()' } %>
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', :id => problem.id}, {:method => 'post', :multipart => true, :id => "submission_form_#{problem.id}_id" }) do %>
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 'source_file' %>
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 => 20150128165518) do
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