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 var TOIContest = {
1 var TOIContest = {
2 NO_TIMEOUT: -1,
2 NO_TIMEOUT: -1,
3 + SUBMISSION_TIMEOUT: 300,
3
4
4 timeOuts: {},
5 timeOuts: {},
6 + timeStarted: 0,
5
7
6 problemSelectClick: function() {
8 problemSelectClick: function() {
7 $$(".submission-submit-divs").each(function(item) {
9 $$(".submission-submit-divs").each(function(item) {
8 item.hide();
10 item.hide();
9 });
11 });
10 var problem_id = $('submission_problem_id').value;
12 var problem_id = $('submission_problem_id').value;
11 if ( problem_id < 0 ) {
13 if ( problem_id < 0 ) {
12 return;
14 return;
13 }
15 }
14 $("submission_submit_div_" + problem_id + "_id").show();
16 $("submission_submit_div_" + problem_id + "_id").show();
15 },
17 },
16
18
17 - confirmDownload: function() {
19 + confirmDownload: function(pid) {
18 - return confirm("แน่ใจ?");
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 refreshTimeOutMessages: function() {
33 refreshTimeOutMessages: function() {
22 for ( var pid in TOIContest.timeOuts ) {
34 for ( var pid in TOIContest.timeOuts ) {
23 var timeOut = TOIContest.timeOuts[ pid ];
35 var timeOut = TOIContest.timeOuts[ pid ];
24 if ( timeOut != TOIContest.NO_TIMEOUT ) {
36 if ( timeOut != TOIContest.NO_TIMEOUT ) {
25 if ( timeOut > 0 ) {
37 if ( timeOut > 0 ) {
26 var minLeft = parseInt(timeOut / 60);
38 var minLeft = parseInt(timeOut / 60);
27 var secLeft = parseInt(timeOut % 60);
39 var secLeft = parseInt(timeOut % 60);
28 $('submission_time_left_' + pid + '_id').innerHTML = '| <b>เหลือเวลาอีก ' + minLeft + ':' + secLeft + ' นาที</b>';
40 $('submission_time_left_' + pid + '_id').innerHTML = '| <b>เหลือเวลาอีก ' + minLeft + ':' + secLeft + ' นาที</b>';
41 + $('submission_form_'+ pid + '_id').show();
29 } else {
42 } else {
30 $('submission_time_left_' + pid + '_id').innerHTML = '| <b>หมดเวลาส่ง</a>';
43 $('submission_time_left_' + pid + '_id').innerHTML = '| <b>หมดเวลาส่ง</a>';
31 $('submission_form_'+ pid + '_id').hide();
44 $('submission_form_'+ pid + '_id').hide();
32 }
45 }
46 + } else {
47 + $('submission_form_'+ pid + '_id').hide();
33 }
48 }
34 }
49 }
35 - }
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,482 +1,512
1 + # coding: utf-8
1 class MainController < ApplicationController
2 class MainController < ApplicationController
2
3
3 before_filter :authenticate, :except => [:index, :login]
4 before_filter :authenticate, :except => [:index, :login]
4 before_filter :check_viewability, :except => [:index, :login]
5 before_filter :check_viewability, :except => [:index, :login]
5
6
6 append_before_filter :confirm_and_update_start_time,
7 append_before_filter :confirm_and_update_start_time,
7 :except => [:index,
8 :except => [:index,
8 :login,
9 :login,
9 :confirm_contest_start]
10 :confirm_contest_start]
10
11
11 # to prevent log in box to be shown when user logged out of the
12 # to prevent log in box to be shown when user logged out of the
12 # system only in some tab
13 # system only in some tab
13 prepend_before_filter :reject_announcement_refresh_when_logged_out,
14 prepend_before_filter :reject_announcement_refresh_when_logged_out,
14 :only => [:announcements]
15 :only => [:announcements]
15
16
16 # COMMENTED OUT: filter in each action instead
17 # COMMENTED OUT: filter in each action instead
17 # before_filter :verify_time_limit, :only => [:submit]
18 # before_filter :verify_time_limit, :only => [:submit]
18
19
19 verify :method => :post, :only => [:submit],
20 verify :method => :post, :only => [:submit],
20 :redirect_to => { :action => :index }
21 :redirect_to => { :action => :index }
21
22
22 # COMMENT OUT: only need when having high load
23 # COMMENT OUT: only need when having high load
23 # caches_action :index, :login
24 # caches_action :index, :login
24
25
25 # NOTE: This method is not actually needed, 'config/routes.rb' has
26 # NOTE: This method is not actually needed, 'config/routes.rb' has
26 # assigned action login as a default action.
27 # assigned action login as a default action.
27 def index
28 def index
28 redirect_to :action => 'login'
29 redirect_to :action => 'login'
29 end
30 end
30
31
31 def login
32 def login
32 saved_notice = flash[:notice]
33 saved_notice = flash[:notice]
33 reset_session
34 reset_session
34 flash.now[:notice] = saved_notice
35 flash.now[:notice] = saved_notice
35
36
36 # EXPERIMENT:
37 # EXPERIMENT:
37 # Hide login if in single user mode and the url does not
38 # Hide login if in single user mode and the url does not
38 # explicitly specify /login
39 # explicitly specify /login
39 #
40 #
40 # logger.info "PATH: #{request.path}"
41 # logger.info "PATH: #{request.path}"
41 # if GraderConfiguration['system.single_user_mode'] and
42 # if GraderConfiguration['system.single_user_mode'] and
42 # request.path!='/main/login'
43 # request.path!='/main/login'
43 # @hidelogin = true
44 # @hidelogin = true
44 # end
45 # end
45
46
46 @announcements = Announcement.find_for_frontpage
47 @announcements = Announcement.find_for_frontpage
47 render :action => 'login', :layout => 'empty'
48 render :action => 'login', :layout => 'empty'
48 end
49 end
49
50
50 def list
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 prepare_list_information
56 prepare_list_information
52 end
57 end
53
58
54 def help
59 def help
55 @user = User.find(session[:user_id])
60 @user = User.find(session[:user_id])
56 end
61 end
57
62
58 def submit
63 def submit
59 user = User.find(session[:user_id])
64 user = User.find(session[:user_id])
60
65
61 @submission = Submission.new
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 @submission.user = user
87 @submission.user = user
64 @submission.language_id = 0
88 @submission.language_id = 0
65 if (params['file']) and (params['file']!='')
89 if (params['file']) and (params['file']!='')
66 @submission.source = params['file'].read
90 @submission.source = params['file'].read
67 @submission.source_filename = params['file'].original_filename
91 @submission.source_filename = params['file'].original_filename
68 end
92 end
93 + if (params['output_file']) and (params['output_file']!='')
94 + @submission.output = params['output_file'].read
95 + end
69 @submission.submitted_at = Time.new.gmtime
96 @submission.submitted_at = Time.new.gmtime
70
97
71 if GraderConfiguration.time_limit_mode? and user.contest_finished?
98 if GraderConfiguration.time_limit_mode? and user.contest_finished?
72 @submission.errors.add(:base,"The contest is over.")
99 @submission.errors.add(:base,"The contest is over.")
73 prepare_list_information
100 prepare_list_information
74 render :action => 'list' and return
101 render :action => 'list' and return
75 end
102 end
76
103
77 if @submission.valid?
104 if @submission.valid?
78 if @submission.save == false
105 if @submission.save == false
79 flash[:notice] = 'Error saving your submission'
106 flash[:notice] = 'Error saving your submission'
80 elsif Task.create(:submission_id => @submission.id,
107 elsif Task.create(:submission_id => @submission.id,
81 :status => Task::STATUS_INQUEUE) == false
108 :status => Task::STATUS_INQUEUE) == false
82 flash[:notice] = 'Error adding your submission to task queue'
109 flash[:notice] = 'Error adding your submission to task queue'
110 + else
111 + flash[:notice] = 'จัดเก็บคำตอบและโปรแกรมที่คุณส่งเรียบร้อย'
83 end
112 end
84 else
113 else
85 prepare_list_information
114 prepare_list_information
86 render :action => 'list' and return
115 render :action => 'list' and return
87 end
116 end
117 +
118 + if @current_problem
119 + session[:current_problem_id] = @current_problem.id
120 + end
88 redirect_to :action => 'list'
121 redirect_to :action => 'list'
89 end
122 end
90
123
91 def source
124 def source
92 submission = Submission.find(params[:id])
125 submission = Submission.find(params[:id])
93 if ((submission.user_id == session[:user_id]) and
126 if ((submission.user_id == session[:user_id]) and
94 (submission.problem != nil) and
127 (submission.problem != nil) and
95 (submission.problem.available))
128 (submission.problem.available))
96 send_data(submission.source,
129 send_data(submission.source,
97 {:filename => submission.download_filename,
130 {:filename => submission.download_filename,
98 :type => 'text/plain'})
131 :type => 'text/plain'})
99 else
132 else
100 flash[:notice] = 'Error viewing source'
133 flash[:notice] = 'Error viewing source'
101 redirect_to :action => 'list'
134 redirect_to :action => 'list'
102 end
135 end
103 end
136 end
104
137
105 def compiler_msg
138 def compiler_msg
106 @submission = Submission.find(params[:id])
139 @submission = Submission.find(params[:id])
107 if @submission.user_id == session[:user_id]
140 if @submission.user_id == session[:user_id]
108 render :action => 'compiler_msg', :layout => 'empty'
141 render :action => 'compiler_msg', :layout => 'empty'
109 else
142 else
110 flash[:notice] = 'Error viewing source'
143 flash[:notice] = 'Error viewing source'
111 redirect_to :action => 'list'
144 redirect_to :action => 'list'
112 end
145 end
113 end
146 end
114
147
115 def submission
148 def submission
116 @user = User.find(session[:user_id])
149 @user = User.find(session[:user_id])
117 @problems = @user.available_problems
150 @problems = @user.available_problems
118 if params[:id]==nil
151 if params[:id]==nil
119 @problem = nil
152 @problem = nil
120 @submissions = nil
153 @submissions = nil
121 else
154 else
122 @problem = Problem.find_by_name(params[:id])
155 @problem = Problem.find_by_name(params[:id])
123 if not @problem.available
156 if not @problem.available
124 redirect_to :action => 'list'
157 redirect_to :action => 'list'
125 flash[:notice] = 'Error: submissions for that problem are not viewable.'
158 flash[:notice] = 'Error: submissions for that problem are not viewable.'
126 return
159 return
127 end
160 end
128 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
161 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
129 end
162 end
130 end
163 end
131
164
132 def result
165 def result
133 if !GraderConfiguration.show_grading_result
166 if !GraderConfiguration.show_grading_result
134 redirect_to :action => 'list' and return
167 redirect_to :action => 'list' and return
135 end
168 end
136 @user = User.find(session[:user_id])
169 @user = User.find(session[:user_id])
137 @submission = Submission.find(params[:id])
170 @submission = Submission.find(params[:id])
138 if @submission.user!=@user
171 if @submission.user!=@user
139 flash[:notice] = 'You are not allowed to view result of other users.'
172 flash[:notice] = 'You are not allowed to view result of other users.'
140 redirect_to :action => 'list' and return
173 redirect_to :action => 'list' and return
141 end
174 end
142 prepare_grading_result(@submission)
175 prepare_grading_result(@submission)
143 end
176 end
144
177
145 def load_output
178 def load_output
146 if !GraderConfiguration.show_grading_result or params[:num]==nil
179 if !GraderConfiguration.show_grading_result or params[:num]==nil
147 redirect_to :action => 'list' and return
180 redirect_to :action => 'list' and return
148 end
181 end
149 @user = User.find(session[:user_id])
182 @user = User.find(session[:user_id])
150 @submission = Submission.find(params[:id])
183 @submission = Submission.find(params[:id])
151 if @submission.user!=@user
184 if @submission.user!=@user
152 flash[:notice] = 'You are not allowed to view result of other users.'
185 flash[:notice] = 'You are not allowed to view result of other users.'
153 redirect_to :action => 'list' and return
186 redirect_to :action => 'list' and return
154 end
187 end
155 case_num = params[:num].to_i
188 case_num = params[:num].to_i
156 out_filename = output_filename(@user.login,
189 out_filename = output_filename(@user.login,
157 @submission.problem.name,
190 @submission.problem.name,
158 @submission.id,
191 @submission.id,
159 case_num)
192 case_num)
160 if !FileTest.exists?(out_filename)
193 if !FileTest.exists?(out_filename)
161 flash[:notice] = 'Output not found.'
194 flash[:notice] = 'Output not found.'
162 redirect_to :action => 'list' and return
195 redirect_to :action => 'list' and return
163 end
196 end
164
197
165 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
198 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
166 response.headers['Content-Type'] = "application/force-download"
199 response.headers['Content-Type'] = "application/force-download"
167 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
200 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
168 response.headers["X-Sendfile"] = out_filename
201 response.headers["X-Sendfile"] = out_filename
169 response.headers['Content-length'] = File.size(out_filename)
202 response.headers['Content-length'] = File.size(out_filename)
170 render :nothing => true
203 render :nothing => true
171 else
204 else
172 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
205 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
173 end
206 end
174 end
207 end
175
208
176 def error
209 def error
177 @user = User.find(session[:user_id])
210 @user = User.find(session[:user_id])
178 end
211 end
179
212
180 # announcement refreshing and hiding methods
213 # announcement refreshing and hiding methods
181
214
182 def announcements
215 def announcements
183 if params.has_key? 'recent'
216 if params.has_key? 'recent'
184 prepare_announcements(params[:recent])
217 prepare_announcements(params[:recent])
185 else
218 else
186 prepare_announcements
219 prepare_announcements
187 end
220 end
188 render(:partial => 'announcement',
221 render(:partial => 'announcement',
189 :collection => @announcements,
222 :collection => @announcements,
190 :locals => {:announcement_effect => true})
223 :locals => {:announcement_effect => true})
191 end
224 end
192
225
193 def confirm_contest_start
226 def confirm_contest_start
194 user = User.find(session[:user_id])
227 user = User.find(session[:user_id])
195 if request.method == 'POST'
228 if request.method == 'POST'
196 user.update_start_time
229 user.update_start_time
197 redirect_to :action => 'list'
230 redirect_to :action => 'list'
198 else
231 else
199 @contests = user.contests
232 @contests = user.contests
200 @user = user
233 @user = user
201 end
234 end
202 end
235 end
203
236
204 # thailandoi contests
237 # thailandoi contests
205
238
206 def verifying_testcase
239 def verifying_testcase
207 problem = Problem.find(params[:id])
240 problem = Problem.find(params[:id])
208 if !problem.available
241 if !problem.available
209 flash[:notice] = 'Error: problem is not available'
242 flash[:notice] = 'Error: problem is not available'
210 redirect_to :action => 'list'
243 redirect_to :action => 'list'
211 else
244 else
212 test_pair = TestPair.get_for(problem, false)
245 test_pair = TestPair.get_for(problem, false)
213 send_data(test_pair.input,
246 send_data(test_pair.input,
214 {:filename => problem.name + '-verifying-input.txt',
247 {:filename => problem.name + '-verifying-input.txt',
215 :type => 'text/plain'})
248 :type => 'text/plain'})
216 end
249 end
217 end
250 end
218
251
219 def testcase
252 def testcase
220 problem = Problem.find(params[:id])
253 problem = Problem.find(params[:id])
221 if !problem.available
254 if !problem.available
222 flash[:notice] = 'Error: problem is not available'
255 flash[:notice] = 'Error: problem is not available'
223 redirect_to :action => 'list'
256 redirect_to :action => 'list'
224 else
257 else
225 test_pair = TestPair.get_for(problem, true)
258 test_pair = TestPair.get_for(problem, true)
226
259
227 user = User.find(session[:user_id])
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
263 + if !assignment
231 - assignent = TestPairAssignment.new
264 + assignment = TestPairAssignment.create_for(user, problem, test_pair)
232 - assignent.user = user
265 + assignment.save
233 - assignent.problem = problem
234 - assignent.test_pair = test_pair
235 - assignent.submitted = false
236 - assignent.save
237 end
266 end
238
267
239 send_data(test_pair.input,
268 send_data(test_pair.input,
240 {:filename => problem.name + '-input.txt',
269 {:filename => problem.name + '-input.txt',
241 :type => 'text/plain'})
270 :type => 'text/plain'})
242 end
271 end
243 end
272 end
244
273
245 def verifying_submit
274 def verifying_submit
246 user = User.find(session[:user_id])
275 user = User.find(session[:user_id])
247 problem_id = params[:id]
276 problem_id = params[:id]
248 problem = Problem.find(problem_id)
277 problem = Problem.find(problem_id)
249
278
250 if !problem or !problem.available
279 if !problem or !problem.available
251 flash[:notice] = 'Error: problem is not available'
280 flash[:notice] = 'Error: problem is not available'
252 redirect_to :action => 'list' and return
281 redirect_to :action => 'list' and return
253 end
282 end
254
283
284 + @current_problem = problem
255 test_pair = TestPair.get_for(problem, false)
285 test_pair = TestPair.get_for(problem, false)
256 if (params['output_file']) and (params['output_file']!='')
286 if (params['output_file']) and (params['output_file']!='')
257 output = params['output_file'].read
287 output = params['output_file'].read
258
288
259 - @current_problem = problem
260 @grading_result = grade(output, test_pair.solution)
289 @grading_result = grade(output, test_pair.solution)
261 prepare_list_information
290 prepare_list_information
262 render :action => 'list' and return
291 render :action => 'list' and return
263 else
292 else
264 flash[:notice] = 'Error: output file errors'
293 flash[:notice] = 'Error: output file errors'
265 - redirect_to :action => 'list'
294 + prepare_list_information
295 + render :action => 'list' and return
266 end
296 end
267 end
297 end
268
298
269 protected
299 protected
270
300
271 def grade(output, solution)
301 def grade(output, solution)
272 out_items = output.split
302 out_items = output.split
273 sol_items = solution.split
303 sol_items = solution.split
274 res = ''
304 res = ''
275 f = 0
305 f = 0
276 s = 0
306 s = 0
277 sol_items.length.times do |i|
307 sol_items.length.times do |i|
278 f += 1
308 f += 1
279 if out_items[i] == sol_items[i]
309 if out_items[i] == sol_items[i]
280 res = res + 'P'
310 res = res + 'P'
281 s += 1
311 s += 1
282 else
312 else
283 res = res + '-'
313 res = res + '-'
284 end
314 end
285 end
315 end
286 return { :score => s, :full_score => f, :msg => res }
316 return { :score => s, :full_score => f, :msg => res }
287 end
317 end
288
318
289 def prepare_announcements(recent=nil)
319 def prepare_announcements(recent=nil)
290 if GraderConfiguration.show_tasks_to?(@user)
320 if GraderConfiguration.show_tasks_to?(@user)
291 @announcements = Announcement.find_published(true)
321 @announcements = Announcement.find_published(true)
292 else
322 else
293 @announcements = Announcement.find_published
323 @announcements = Announcement.find_published
294 end
324 end
295 if recent!=nil
325 if recent!=nil
296 recent_id = recent.to_i
326 recent_id = recent.to_i
297 @announcements = @announcements.find_all { |a| a.id > recent_id }
327 @announcements = @announcements.find_all { |a| a.id > recent_id }
298 end
328 end
299 end
329 end
300
330
301 def prepare_timeout_information(problems)
331 def prepare_timeout_information(problems)
302 @submission_timeouts = {}
332 @submission_timeouts = {}
303 problems.each do |problem|
333 problems.each do |problem|
304 assignment = @user.get_test_pair_assignment_for(problem)
334 assignment = @user.get_test_pair_assignment_for(problem)
305 if assignment == nil
335 if assignment == nil
306 timeout = nil
336 timeout = nil
307 else
337 else
308 if (assignment.expired?) or (assignment.submitted)
338 if (assignment.expired?) or (assignment.submitted)
309 timeout = 0
339 timeout = 0
310 else
340 else
311 timeout = assignment.created_at + TEST_ASSIGNMENT_EXPIRATION_DURATION - Time.new.gmtime
341 timeout = assignment.created_at + TEST_ASSIGNMENT_EXPIRATION_DURATION - Time.new.gmtime
312 end
342 end
313 end
343 end
314 @submission_timeouts[problem.id] = timeout
344 @submission_timeouts[problem.id] = timeout
315 end
345 end
316 end
346 end
317
347
318 def prepare_list_information
348 def prepare_list_information
319 @user = User.find(session[:user_id])
349 @user = User.find(session[:user_id])
320 if not GraderConfiguration.multicontests?
350 if not GraderConfiguration.multicontests?
321 @problems = @user.available_problems
351 @problems = @user.available_problems
322 else
352 else
323 @contest_problems = @user.available_problems_group_by_contests
353 @contest_problems = @user.available_problems_group_by_contests
324 @problems = @user.available_problems
354 @problems = @user.available_problems
325 end
355 end
326 @prob_submissions = {}
356 @prob_submissions = {}
327 @problems.each do |p|
357 @problems.each do |p|
328 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
358 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
329 if sub!=nil
359 if sub!=nil
330 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
360 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
331 else
361 else
332 @prob_submissions[p.id] = { :count => 0, :submission => nil }
362 @prob_submissions[p.id] = { :count => 0, :submission => nil }
333 end
363 end
334 end
364 end
335 prepare_announcements
365 prepare_announcements
336 prepare_timeout_information(@problems)
366 prepare_timeout_information(@problems)
337 end
367 end
338
368
339 def check_viewability
369 def check_viewability
340 @user = User.find(session[:user_id])
370 @user = User.find(session[:user_id])
341 if (!GraderConfiguration.show_tasks_to?(@user)) and
371 if (!GraderConfiguration.show_tasks_to?(@user)) and
342 ((action_name=='submission') or (action_name=='submit'))
372 ((action_name=='submission') or (action_name=='submit'))
343 redirect_to :action => 'list' and return
373 redirect_to :action => 'list' and return
344 end
374 end
345 end
375 end
346
376
347 def prepare_grading_result(submission)
377 def prepare_grading_result(submission)
348 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
378 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
349 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
379 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
350 else
380 else
351 # guess task info from problem.full_score
381 # guess task info from problem.full_score
352 cases = submission.problem.full_score / 10
382 cases = submission.problem.full_score / 10
353 grading_info = {
383 grading_info = {
354 'testruns' => cases,
384 'testruns' => cases,
355 'testcases' => cases
385 'testcases' => cases
356 }
386 }
357 end
387 end
358 @test_runs = []
388 @test_runs = []
359 if grading_info['testruns'].is_a? Integer
389 if grading_info['testruns'].is_a? Integer
360 trun_count = grading_info['testruns']
390 trun_count = grading_info['testruns']
361 trun_count.times do |i|
391 trun_count.times do |i|
362 @test_runs << [ read_grading_result(@user.login,
392 @test_runs << [ read_grading_result(@user.login,
363 submission.problem.name,
393 submission.problem.name,
364 submission.id,
394 submission.id,
365 i+1) ]
395 i+1) ]
366 end
396 end
367 else
397 else
368 grading_info['testruns'].keys.sort.each do |num|
398 grading_info['testruns'].keys.sort.each do |num|
369 run = []
399 run = []
370 testrun = grading_info['testruns'][num]
400 testrun = grading_info['testruns'][num]
371 testrun.each do |c|
401 testrun.each do |c|
372 run << read_grading_result(@user.login,
402 run << read_grading_result(@user.login,
373 submission.problem.name,
403 submission.problem.name,
374 submission.id,
404 submission.id,
375 c)
405 c)
376 end
406 end
377 @test_runs << run
407 @test_runs << run
378 end
408 end
379 end
409 end
380 end
410 end
381
411
382 def grading_result_dir(user_name, problem_name, submission_id, case_num)
412 def grading_result_dir(user_name, problem_name, submission_id, case_num)
383 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
413 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
384 end
414 end
385
415
386 def output_filename(user_name, problem_name, submission_id, case_num)
416 def output_filename(user_name, problem_name, submission_id, case_num)
387 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
417 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
388 return "#{dir}/output.txt"
418 return "#{dir}/output.txt"
389 end
419 end
390
420
391 def read_grading_result(user_name, problem_name, submission_id, case_num)
421 def read_grading_result(user_name, problem_name, submission_id, case_num)
392 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
422 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
393 result_file_name = "#{dir}/result"
423 result_file_name = "#{dir}/result"
394 if !FileTest.exists?(result_file_name)
424 if !FileTest.exists?(result_file_name)
395 return {:num => case_num, :msg => 'program did not run'}
425 return {:num => case_num, :msg => 'program did not run'}
396 else
426 else
397 results = File.open(result_file_name).readlines
427 results = File.open(result_file_name).readlines
398 run_stat = extract_running_stat(results)
428 run_stat = extract_running_stat(results)
399 output_filename = "#{dir}/output.txt"
429 output_filename = "#{dir}/output.txt"
400 if FileTest.exists?(output_filename)
430 if FileTest.exists?(output_filename)
401 output_file = true
431 output_file = true
402 output_size = File.size(output_filename)
432 output_size = File.size(output_filename)
403 else
433 else
404 output_file = false
434 output_file = false
405 output_size = 0
435 output_size = 0
406 end
436 end
407
437
408 return {
438 return {
409 :num => case_num,
439 :num => case_num,
410 :msg => results[0],
440 :msg => results[0],
411 :run_stat => run_stat,
441 :run_stat => run_stat,
412 :output => output_file,
442 :output => output_file,
413 :output_size => output_size
443 :output_size => output_size
414 }
444 }
415 end
445 end
416 end
446 end
417
447
418 # copied from grader/script/lib/test_request_helper.rb
448 # copied from grader/script/lib/test_request_helper.rb
419 def extract_running_stat(results)
449 def extract_running_stat(results)
420 running_stat_line = results[-1]
450 running_stat_line = results[-1]
421
451
422 # extract exit status line
452 # extract exit status line
423 run_stat = ""
453 run_stat = ""
424 if !(/[Cc]orrect/.match(results[0]))
454 if !(/[Cc]orrect/.match(results[0]))
425 run_stat = results[0].chomp
455 run_stat = results[0].chomp
426 else
456 else
427 run_stat = 'Program exited normally'
457 run_stat = 'Program exited normally'
428 end
458 end
429
459
430 logger.info "Stat line: #{running_stat_line}"
460 logger.info "Stat line: #{running_stat_line}"
431
461
432 # extract running time
462 # extract running time
433 if res = /r(.*)u(.*)s/.match(running_stat_line)
463 if res = /r(.*)u(.*)s/.match(running_stat_line)
434 seconds = (res[1].to_f + res[2].to_f)
464 seconds = (res[1].to_f + res[2].to_f)
435 time_stat = "Time used: #{seconds} sec."
465 time_stat = "Time used: #{seconds} sec."
436 else
466 else
437 seconds = nil
467 seconds = nil
438 time_stat = "Time used: n/a sec."
468 time_stat = "Time used: n/a sec."
439 end
469 end
440
470
441 # extract memory usage
471 # extract memory usage
442 if res = /s(.*)m/.match(running_stat_line)
472 if res = /s(.*)m/.match(running_stat_line)
443 memory_used = res[1].to_i
473 memory_used = res[1].to_i
444 else
474 else
445 memory_used = -1
475 memory_used = -1
446 end
476 end
447
477
448 return {
478 return {
449 :msg => "#{run_stat}\n#{time_stat}",
479 :msg => "#{run_stat}\n#{time_stat}",
450 :running_time => seconds,
480 :running_time => seconds,
451 :exit_status => run_stat,
481 :exit_status => run_stat,
452 :memory_usage => memory_used
482 :memory_usage => memory_used
453 }
483 }
454 end
484 end
455
485
456 def confirm_and_update_start_time
486 def confirm_and_update_start_time
457 user = User.find(session[:user_id])
487 user = User.find(session[:user_id])
458 if (GraderConfiguration.indv_contest_mode? and
488 if (GraderConfiguration.indv_contest_mode? and
459 GraderConfiguration['contest.confirm_indv_contest_start'] and
489 GraderConfiguration['contest.confirm_indv_contest_start'] and
460 !user.contest_started?)
490 !user.contest_started?)
461 redirect_to :action => 'confirm_contest_start' and return
491 redirect_to :action => 'confirm_contest_start' and return
462 end
492 end
463 if not GraderConfiguration.analysis_mode?
493 if not GraderConfiguration.analysis_mode?
464 user.update_start_time
494 user.update_start_time
465 end
495 end
466 end
496 end
467
497
468 def reject_announcement_refresh_when_logged_out
498 def reject_announcement_refresh_when_logged_out
469 if not session[:user_id]
499 if not session[:user_id]
470 render :text => 'Access forbidden', :status => 403
500 render :text => 'Access forbidden', :status => 403
471 end
501 end
472
502
473 if GraderConfiguration.multicontests?
503 if GraderConfiguration.multicontests?
474 user = User.find(session[:user_id])
504 user = User.find(session[:user_id])
475 if user.contest_stat.forced_logout
505 if user.contest_stat.forced_logout
476 render :text => 'Access forbidden', :status => 403
506 render :text => 'Access forbidden', :status => 403
477 end
507 end
478 end
508 end
479 end
509 end
480
510
481 end
511 end
482
512
@@ -1,173 +1,178
1 class Submission < ActiveRecord::Base
1 class Submission < ActiveRecord::Base
2
2
3 belongs_to :language
3 belongs_to :language
4 belongs_to :problem
4 belongs_to :problem
5 belongs_to :user
5 belongs_to :user
6
6
7 before_validation :assign_problem
7 before_validation :assign_problem
8 before_validation :assign_language
8 before_validation :assign_language
9
9
10 validates_presence_of :source
10 validates_presence_of :source
11 validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'too long'
11 validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'too long'
12 validates_length_of :source, :minimum => 1, :allow_blank => true, :message => 'too short'
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 validate :must_have_valid_problem
18 validate :must_have_valid_problem
14 validate :must_specify_language
19 validate :must_specify_language
15
20
16 before_save :assign_latest_number_if_new_recond
21 before_save :assign_latest_number_if_new_recond
17
22
18 def self.find_last_by_user_and_problem(user_id, problem_id)
23 def self.find_last_by_user_and_problem(user_id, problem_id)
19 last_sub = find(:first,
24 last_sub = find(:first,
20 :conditions => {:user_id => user_id,
25 :conditions => {:user_id => user_id,
21 :problem_id => problem_id},
26 :problem_id => problem_id},
22 :order => 'number DESC')
27 :order => 'number DESC')
23 return last_sub
28 return last_sub
24 end
29 end
25
30
26 def self.find_all_last_by_problem(problem_id)
31 def self.find_all_last_by_problem(problem_id)
27 # need to put in SQL command, maybe there's a better way
32 # need to put in SQL command, maybe there's a better way
28 Submission.find_by_sql("SELECT * FROM submissions " +
33 Submission.find_by_sql("SELECT * FROM submissions " +
29 "WHERE id = " +
34 "WHERE id = " +
30 "(SELECT MAX(id) FROM submissions AS subs " +
35 "(SELECT MAX(id) FROM submissions AS subs " +
31 "WHERE subs.user_id = submissions.user_id AND " +
36 "WHERE subs.user_id = submissions.user_id AND " +
32 "problem_id = " + problem_id.to_s + " " +
37 "problem_id = " + problem_id.to_s + " " +
33 "GROUP BY user_id) " +
38 "GROUP BY user_id) " +
34 "ORDER BY user_id")
39 "ORDER BY user_id")
35 end
40 end
36
41
37 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
42 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
38 records = Submission.where(problem_id: problem_id,user_id: user_id)
43 records = Submission.where(problem_id: problem_id,user_id: user_id)
39 records = records.where('id >= ?',since_id) if since_id > 0
44 records = records.where('id >= ?',since_id) if since_id > 0
40 records = records.where('id <= ?',until_id) if until_id > 0
45 records = records.where('id <= ?',until_id) if until_id > 0
41 records.all
46 records.all
42 end
47 end
43
48
44 def self.find_last_for_all_available_problems(user_id)
49 def self.find_last_for_all_available_problems(user_id)
45 submissions = Array.new
50 submissions = Array.new
46 problems = Problem.find_available_problems
51 problems = Problem.find_available_problems
47 problems.each do |problem|
52 problems.each do |problem|
48 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
53 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
49 submissions << sub if sub!=nil
54 submissions << sub if sub!=nil
50 end
55 end
51 submissions
56 submissions
52 end
57 end
53
58
54 def self.find_by_user_problem_number(user_id, problem_id, number)
59 def self.find_by_user_problem_number(user_id, problem_id, number)
55 Submission.find(:first,
60 Submission.find(:first,
56 :conditions => {
61 :conditions => {
57 :user_id => user_id,
62 :user_id => user_id,
58 :problem_id => problem_id,
63 :problem_id => problem_id,
59 :number => number
64 :number => number
60 })
65 })
61 end
66 end
62
67
63 def self.find_all_by_user_problem(user_id, problem_id)
68 def self.find_all_by_user_problem(user_id, problem_id)
64 Submission.find(:all,
69 Submission.find(:all,
65 :conditions => {
70 :conditions => {
66 :user_id => user_id,
71 :user_id => user_id,
67 :problem_id => problem_id,
72 :problem_id => problem_id,
68 })
73 })
69 end
74 end
70
75
71 def download_filename
76 def download_filename
72 if self.problem.output_only
77 if self.problem.output_only
73 return self.source_filename
78 return self.source_filename
74 else
79 else
75 timestamp = self.submitted_at.localtime.strftime("%H%M%S")
80 timestamp = self.submitted_at.localtime.strftime("%H%M%S")
76 return "#{self.problem.name}-#{timestamp}.#{self.language.ext}"
81 return "#{self.problem.name}-#{timestamp}.#{self.language.ext}"
77 end
82 end
78 end
83 end
79
84
80 protected
85 protected
81
86
82 def self.find_option_in_source(option, source)
87 def self.find_option_in_source(option, source)
83 if source==nil
88 if source==nil
84 return nil
89 return nil
85 end
90 end
86 i = 0
91 i = 0
87 source.each_line do |s|
92 source.each_line do |s|
88 if s =~ option
93 if s =~ option
89 words = s.split
94 words = s.split
90 return words[1]
95 return words[1]
91 end
96 end
92 i = i + 1
97 i = i + 1
93 if i==10
98 if i==10
94 return nil
99 return nil
95 end
100 end
96 end
101 end
97 return nil
102 return nil
98 end
103 end
99
104
100 def self.find_language_in_source(source, source_filename="")
105 def self.find_language_in_source(source, source_filename="")
101 langopt = find_option_in_source(/^LANG:/,source)
106 langopt = find_option_in_source(/^LANG:/,source)
102 if langopt
107 if langopt
103 return (Language.find_by_name(langopt) ||
108 return (Language.find_by_name(langopt) ||
104 Language.find_by_pretty_name(langopt))
109 Language.find_by_pretty_name(langopt))
105 else
110 else
106 if source_filename
111 if source_filename
107 return Language.find_by_extension(source_filename.split('.').last)
112 return Language.find_by_extension(source_filename.split('.').last)
108 else
113 else
109 return nil
114 return nil
110 end
115 end
111 end
116 end
112 end
117 end
113
118
114 def self.find_problem_in_source(source, source_filename="")
119 def self.find_problem_in_source(source, source_filename="")
115 prob_opt = find_option_in_source(/^TASK:/,source)
120 prob_opt = find_option_in_source(/^TASK:/,source)
116 if problem = Problem.find_by_name(prob_opt)
121 if problem = Problem.find_by_name(prob_opt)
117 return problem
122 return problem
118 else
123 else
119 if source_filename
124 if source_filename
120 return Problem.find_by_name(source_filename.split('.').first)
125 return Problem.find_by_name(source_filename.split('.').first)
121 else
126 else
122 return nil
127 return nil
123 end
128 end
124 end
129 end
125 end
130 end
126
131
127 def assign_problem
132 def assign_problem
128 if self.problem_id!=-1
133 if self.problem_id!=-1
129 begin
134 begin
130 self.problem = Problem.find(self.problem_id)
135 self.problem = Problem.find(self.problem_id)
131 rescue ActiveRecord::RecordNotFound
136 rescue ActiveRecord::RecordNotFound
132 self.problem = nil
137 self.problem = nil
133 end
138 end
134 else
139 else
135 self.problem = Submission.find_problem_in_source(self.source,
140 self.problem = Submission.find_problem_in_source(self.source,
136 self.source_filename)
141 self.source_filename)
137 end
142 end
138 end
143 end
139
144
140 def assign_language
145 def assign_language
141 self.language = Submission.find_language_in_source(self.source,
146 self.language = Submission.find_language_in_source(self.source,
142 self.source_filename)
147 self.source_filename)
143 end
148 end
144
149
145 # validation codes
150 # validation codes
146 def must_specify_language
151 def must_specify_language
147 return if self.source==nil
152 return if self.source==nil
148
153
149 # for output_only tasks
154 # for output_only tasks
150 return if self.problem!=nil and self.problem.output_only
155 return if self.problem!=nil and self.problem.output_only
151
156
152 if self.language==nil
157 if self.language==nil
153 errors.add('source',"must specify programming language") unless self.language!=nil
158 errors.add('source',"must specify programming language") unless self.language!=nil
154 end
159 end
155 end
160 end
156
161
157 def must_have_valid_problem
162 def must_have_valid_problem
158 return if self.source==nil
163 return if self.source==nil
159 if self.problem==nil
164 if self.problem==nil
160 errors.add('problem',"must be specified.")
165 errors.add('problem',"must be specified.")
161 elsif (!self.problem.available) and (self.new_record?)
166 elsif (!self.problem.available) and (self.new_record?)
162 errors.add('problem',"must be valid.")
167 errors.add('problem',"must be valid.")
163 end
168 end
164 end
169 end
165
170
166 # callbacks
171 # callbacks
167 def assign_latest_number_if_new_recond
172 def assign_latest_number_if_new_recond
168 return if !self.new_record?
173 return if !self.new_record?
169 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
174 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
170 self.number = (latest==nil) ? 1 : latest.number + 1;
175 self.number = (latest==nil) ? 1 : latest.number + 1;
171 end
176 end
172
177
173 end
178 end
@@ -1,9 +1,19
1 class TestPairAssignment < ActiveRecord::Base
1 class TestPairAssignment < ActiveRecord::Base
2 belongs_to :problem
2 belongs_to :problem
3 belongs_to :test_pair
3 belongs_to :test_pair
4 belongs_to :user
4 belongs_to :user
5
5
6 def expired?
6 def expired?
7 return created_at + TEST_ASSIGNMENT_EXPIRATION_DURATION < Time.new.gmtime
7 return created_at + TEST_ASSIGNMENT_EXPIRATION_DURATION < Time.new.gmtime
8 end
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
18 + end
9 end
19 end
@@ -1,36 +1,38
1 + <% selected_problem_id = @current_problem ? @current_problem.id : -1 %>
1 <div class="submitbox">
2 <div class="submitbox">
2 <b>Problem:</b> <%= select 'submission', 'problem_id',
3 <b>Problem:</b> <%= select 'submission', 'problem_id',
3 [['กรุณาเลือกข้อที่ต้องการส่งหรือทดสอบ','-1']] +
4 [['กรุณาเลือกข้อที่ต้องการส่งหรือทดสอบ','-1']] +
4 @problems.collect {|p| [p.full_name, p.id]},
5 @problems.collect {|p| [p.full_name, p.id]},
5 - { :selected => '-1' },
6 + { :selected => selected_problem_id },
6 { :onchange => 'TOIContest.problemSelectClick()' } %>
7 { :onchange => 'TOIContest.problemSelectClick()' } %>
7 </div>
8 </div>
8
9
9 <% @problems.each do |problem| %>
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 <div style="border: 1px solid #c0c0c0; padding: 5px; margin: 5px 0 5px 0;">
12 <div style="border: 1px solid #c0c0c0; padding: 5px; margin: 5px 0 5px 0;">
12 <b><%= problem.full_name %>: ข้อมูลสำหรับตรวจสอบ</b> (สามารถดาวน์โหลดและส่งกี่ครั้งก็ได้,ไม่มีคะแนน):
13 <b><%= problem.full_name %>: ข้อมูลสำหรับตรวจสอบ</b> (สามารถดาวน์โหลดและส่งกี่ครั้งก็ได้,ไม่มีคะแนน):
13 <%= link_to 'ดาวน์โหลด input', :action => 'verifying_testcase', :id => problem.id %>
14 <%= link_to 'ดาวน์โหลด input', :action => 'verifying_testcase', :id => problem.id %>
14 <% if @current_problem and @current_problem.id == problem.id %>
15 <% if @current_problem and @current_problem.id == problem.id %>
15 <% if @grading_result %>
16 <% if @grading_result %>
16 | <b>ผลการตรวจ:</b> <%= "#{@grading_result[:score]}/#{@grading_result[:full_score]} [#{@grading_result[:msg]}]" %>
17 | <b>ผลการตรวจ:</b> <%= "#{@grading_result[:score]}/#{@grading_result[:full_score]} [#{@grading_result[:msg]}]" %>
17 <% end %>
18 <% end %>
18 <% end %>
19 <% end %>
19 <%= form_tag({:controller => 'main', :action => 'verifying_submit', :id => problem.id}, {:method => 'post', :multipart => true }) do %>
20 <%= form_tag({:controller => 'main', :action => 'verifying_submit', :id => problem.id}, {:method => 'post', :multipart => true }) do %>
20 ส่งคำตอบของข้อมูลสำหรับตรวจสอบ:
21 ส่งคำตอบของข้อมูลสำหรับตรวจสอบ:
21 <%= file_field_tag 'output_file' %>
22 <%= file_field_tag 'output_file' %>
22 <%= submit_tag 'Submit' %>
23 <%= submit_tag 'Submit' %>
23 <% end %>
24 <% end %>
24 </div>
25 </div>
25 <div style="border: 1px solid #c0c0c0; padding: 5px; margin: 5px 0 5px 0;">
26 <div style="border: 1px solid #c0c0c0; padding: 5px; margin: 5px 0 5px 0;">
26 <b><%= problem.full_name %>: ข้อมูลทดสอบจริง</b> (ส่งกี่ครั้งก็ได้ภายในเวลา 5 นาทีหลังดาวน์โหลด):
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 <span id="submission_time_left_<%= problem.id %>_id"></span>
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 ข้อมูลส่งออก: <%= file_field_tag 'output_file' %>
32 ข้อมูลส่งออก: <%= file_field_tag 'output_file' %>
31 - โปรแกรมคำตอบ: <%= file_field_tag 'source_file' %>
33 + โปรแกรมคำตอบ: <%= file_field_tag 'file' %>
32 <%= submit_tag 'Submit' %>
34 <%= submit_tag 'Submit' %>
33 <% end %>
35 <% end %>
34 </div>
36 </div>
35 </div>
37 </div>
36 <% end %>
38 <% end %>
@@ -1,59 +1,62
1 - content_for :head do
1 - content_for :head do
2 = javascript_include_tag "announcement_refresh"
2 = javascript_include_tag "announcement_refresh"
3 = javascript_include_tag "toicontest"
3 = javascript_include_tag "toicontest"
4
4
5 = user_title_bar(@user)
5 = user_title_bar(@user)
6
6
7 .announcementbox{:style => (@announcements.length==0 ? "display:none" : "")}
7 .announcementbox{:style => (@announcements.length==0 ? "display:none" : "")}
8 %span{:class => 'title'}
8 %span{:class => 'title'}
9 Announcements
9 Announcements
10 #announcementbox-body
10 #announcementbox-body
11 = render :partial => 'announcement', :collection => @announcements
11 = render :partial => 'announcement', :collection => @announcements
12
12
13 - if GraderConfiguration.show_submitbox_to?(@user)
13 - if GraderConfiguration.show_submitbox_to?(@user)
14 = error_messages_for 'submission'
14 = error_messages_for 'submission'
15 = render :partial => 'submission_box'
15 = render :partial => 'submission_box'
16
16
17
17
18 %hr/
18 %hr/
19
19
20 - if (GraderConfiguration.contest_mode?) and (@user.site!=nil) and (@user.site.started!=true)
20 - if (GraderConfiguration.contest_mode?) and (@user.site!=nil) and (@user.site.started!=true)
21 %p=t 'main.start_soon'
21 %p=t 'main.start_soon'
22
22
23 - if GraderConfiguration.show_tasks_to?(@user)
23 - if GraderConfiguration.show_tasks_to?(@user)
24 - if not GraderConfiguration.multicontests?
24 - if not GraderConfiguration.multicontests?
25 %table.info
25 %table.info
26 %tr.info-head
26 %tr.info-head
27 %th
27 %th
28 %th Tasks
28 %th Tasks
29 %th # of sub(s)
29 %th # of sub(s)
30 %th Results
30 %th Results
31 = render :partial => 'problem', :collection => @problems
31 = render :partial => 'problem', :collection => @problems
32 - else
32 - else
33 - @contest_problems.each do |cp|
33 - @contest_problems.each do |cp|
34 - if cp[:problems].length > 0
34 - if cp[:problems].length > 0
35 %h2{:class =>'contest-title'}
35 %h2{:class =>'contest-title'}
36 = "#{cp[:contest] ? cp[:contest].title : 'Public problems'}"
36 = "#{cp[:contest] ? cp[:contest].title : 'Public problems'}"
37 %table.info
37 %table.info
38 %tr.info-head
38 %tr.info-head
39 %th
39 %th
40 %th Tasks
40 %th Tasks
41 %th # of sub(s)
41 %th # of sub(s)
42 %th Results
42 %th Results
43 = render :partial => 'problem', :collection => cp[:problems]
43 = render :partial => 'problem', :collection => cp[:problems]
44
44
45
45
46 %hr/
46 %hr/
47
47
48 %script{:type => 'text/javascript'}
48 %script{:type => 'text/javascript'}
49 = "Announcement.refreshUrl = '#{url_for :controller => 'main', :action => 'announcements'}';"
49 = "Announcement.refreshUrl = '#{url_for :controller => 'main', :action => 'announcements'}';"
50 Announcement.registerRefreshEventTimer();
50 Announcement.registerRefreshEventTimer();
51
51
52 + TOIContest.problemSelectClick()
53 +
52 TOIContest.timeOuts = {};
54 TOIContest.timeOuts = {};
53 - @problems.each do |p|
55 - @problems.each do |p|
54 - if (@submission_timeouts.has_key? p.id) and (@submission_timeouts[p.id] != nil)
56 - if (@submission_timeouts.has_key? p.id) and (@submission_timeouts[p.id] != nil)
55 = "TOIContest.timeOuts[#{p.id}] = #{@submission_timeouts[p.id]};"
57 = "TOIContest.timeOuts[#{p.id}] = #{@submission_timeouts[p.id]};"
56 - else
58 - else
57 = "TOIContest.timeOuts[#{p.id}] = TOIContest.NO_TIMEOUT;"
59 = "TOIContest.timeOuts[#{p.id}] = TOIContest.NO_TIMEOUT;"
58
60
59 TOIContest.refreshTimeOutMessages();
61 TOIContest.refreshTimeOutMessages();
62 + TOIContest.registerRefreshEvent();
@@ -1,246 +1,247
1 # encoding: UTF-8
1 # encoding: UTF-8
2 # This file is auto-generated from the current state of the database. Instead
2 # This file is auto-generated from the current state of the database. Instead
3 # of editing this file, please use the migrations feature of Active Record to
3 # of editing this file, please use the migrations feature of Active Record to
4 # incrementally modify your database, and then regenerate this schema definition.
4 # incrementally modify your database, and then regenerate this schema definition.
5 #
5 #
6 # Note that this schema.rb definition is the authoritative source for your
6 # Note that this schema.rb definition is the authoritative source for your
7 # database schema. If you need to create the application database on another
7 # database schema. If you need to create the application database on another
8 # system, you should be using db:schema:load, not running all the migrations
8 # system, you should be using db:schema:load, not running all the migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 #
11 #
12 # It's strongly recommended to check this file into your version control system.
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 create_table "announcements", :force => true do |t|
16 create_table "announcements", :force => true do |t|
17 t.string "author"
17 t.string "author"
18 t.text "body"
18 t.text "body"
19 t.boolean "published"
19 t.boolean "published"
20 t.datetime "created_at", :null => false
20 t.datetime "created_at", :null => false
21 t.datetime "updated_at", :null => false
21 t.datetime "updated_at", :null => false
22 t.boolean "frontpage", :default => false
22 t.boolean "frontpage", :default => false
23 t.boolean "contest_only", :default => false
23 t.boolean "contest_only", :default => false
24 t.string "title"
24 t.string "title"
25 t.string "notes"
25 t.string "notes"
26 end
26 end
27
27
28 create_table "contests", :force => true do |t|
28 create_table "contests", :force => true do |t|
29 t.string "title"
29 t.string "title"
30 t.boolean "enabled"
30 t.boolean "enabled"
31 t.datetime "created_at", :null => false
31 t.datetime "created_at", :null => false
32 t.datetime "updated_at", :null => false
32 t.datetime "updated_at", :null => false
33 t.string "name"
33 t.string "name"
34 end
34 end
35
35
36 create_table "contests_problems", :id => false, :force => true do |t|
36 create_table "contests_problems", :id => false, :force => true do |t|
37 t.integer "contest_id"
37 t.integer "contest_id"
38 t.integer "problem_id"
38 t.integer "problem_id"
39 end
39 end
40
40
41 create_table "contests_users", :id => false, :force => true do |t|
41 create_table "contests_users", :id => false, :force => true do |t|
42 t.integer "contest_id"
42 t.integer "contest_id"
43 t.integer "user_id"
43 t.integer "user_id"
44 end
44 end
45
45
46 create_table "countries", :force => true do |t|
46 create_table "countries", :force => true do |t|
47 t.string "name"
47 t.string "name"
48 t.datetime "created_at", :null => false
48 t.datetime "created_at", :null => false
49 t.datetime "updated_at", :null => false
49 t.datetime "updated_at", :null => false
50 end
50 end
51
51
52 create_table "descriptions", :force => true do |t|
52 create_table "descriptions", :force => true do |t|
53 t.text "body"
53 t.text "body"
54 t.boolean "markdowned"
54 t.boolean "markdowned"
55 t.datetime "created_at", :null => false
55 t.datetime "created_at", :null => false
56 t.datetime "updated_at", :null => false
56 t.datetime "updated_at", :null => false
57 end
57 end
58
58
59 create_table "grader_configurations", :force => true do |t|
59 create_table "grader_configurations", :force => true do |t|
60 t.string "key"
60 t.string "key"
61 t.string "value_type"
61 t.string "value_type"
62 t.string "value"
62 t.string "value"
63 t.datetime "created_at", :null => false
63 t.datetime "created_at", :null => false
64 t.datetime "updated_at", :null => false
64 t.datetime "updated_at", :null => false
65 t.text "description"
65 t.text "description"
66 end
66 end
67
67
68 create_table "grader_processes", :force => true do |t|
68 create_table "grader_processes", :force => true do |t|
69 t.string "host", :limit => 20
69 t.string "host", :limit => 20
70 t.integer "pid"
70 t.integer "pid"
71 t.string "mode"
71 t.string "mode"
72 t.boolean "active"
72 t.boolean "active"
73 t.datetime "created_at", :null => false
73 t.datetime "created_at", :null => false
74 t.datetime "updated_at", :null => false
74 t.datetime "updated_at", :null => false
75 t.integer "task_id"
75 t.integer "task_id"
76 t.string "task_type"
76 t.string "task_type"
77 t.boolean "terminated"
77 t.boolean "terminated"
78 end
78 end
79
79
80 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
80 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
81
81
82 create_table "languages", :force => true do |t|
82 create_table "languages", :force => true do |t|
83 t.string "name", :limit => 10
83 t.string "name", :limit => 10
84 t.string "pretty_name"
84 t.string "pretty_name"
85 t.string "ext", :limit => 10
85 t.string "ext", :limit => 10
86 t.string "common_ext"
86 t.string "common_ext"
87 end
87 end
88
88
89 create_table "messages", :force => true do |t|
89 create_table "messages", :force => true do |t|
90 t.integer "sender_id"
90 t.integer "sender_id"
91 t.integer "receiver_id"
91 t.integer "receiver_id"
92 t.integer "replying_message_id"
92 t.integer "replying_message_id"
93 t.text "body"
93 t.text "body"
94 t.boolean "replied"
94 t.boolean "replied"
95 t.datetime "created_at", :null => false
95 t.datetime "created_at", :null => false
96 t.datetime "updated_at", :null => false
96 t.datetime "updated_at", :null => false
97 end
97 end
98
98
99 create_table "problems", :force => true do |t|
99 create_table "problems", :force => true do |t|
100 t.string "name", :limit => 30
100 t.string "name", :limit => 30
101 t.string "full_name"
101 t.string "full_name"
102 t.integer "full_score"
102 t.integer "full_score"
103 t.date "date_added"
103 t.date "date_added"
104 t.boolean "available"
104 t.boolean "available"
105 t.string "url"
105 t.string "url"
106 t.integer "description_id"
106 t.integer "description_id"
107 t.boolean "test_allowed"
107 t.boolean "test_allowed"
108 t.boolean "output_only"
108 t.boolean "output_only"
109 t.string "description_filename"
109 t.string "description_filename"
110 end
110 end
111
111
112 create_table "rights", :force => true do |t|
112 create_table "rights", :force => true do |t|
113 t.string "name"
113 t.string "name"
114 t.string "controller"
114 t.string "controller"
115 t.string "action"
115 t.string "action"
116 end
116 end
117
117
118 create_table "rights_roles", :id => false, :force => true do |t|
118 create_table "rights_roles", :id => false, :force => true do |t|
119 t.integer "right_id"
119 t.integer "right_id"
120 t.integer "role_id"
120 t.integer "role_id"
121 end
121 end
122
122
123 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
123 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
124
124
125 create_table "roles", :force => true do |t|
125 create_table "roles", :force => true do |t|
126 t.string "name"
126 t.string "name"
127 end
127 end
128
128
129 create_table "roles_users", :id => false, :force => true do |t|
129 create_table "roles_users", :id => false, :force => true do |t|
130 t.integer "role_id"
130 t.integer "role_id"
131 t.integer "user_id"
131 t.integer "user_id"
132 end
132 end
133
133
134 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
134 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
135
135
136 create_table "sessions", :force => true do |t|
136 create_table "sessions", :force => true do |t|
137 t.string "session_id"
137 t.string "session_id"
138 t.text "data"
138 t.text "data"
139 t.datetime "updated_at"
139 t.datetime "updated_at"
140 end
140 end
141
141
142 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
142 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
143 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
143 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
144
144
145 create_table "sites", :force => true do |t|
145 create_table "sites", :force => true do |t|
146 t.string "name"
146 t.string "name"
147 t.boolean "started"
147 t.boolean "started"
148 t.datetime "start_time"
148 t.datetime "start_time"
149 t.datetime "created_at", :null => false
149 t.datetime "created_at", :null => false
150 t.datetime "updated_at", :null => false
150 t.datetime "updated_at", :null => false
151 t.integer "country_id"
151 t.integer "country_id"
152 t.string "password"
152 t.string "password"
153 end
153 end
154
154
155 create_table "submissions", :force => true do |t|
155 create_table "submissions", :force => true do |t|
156 t.integer "user_id"
156 t.integer "user_id"
157 t.integer "problem_id"
157 t.integer "problem_id"
158 t.integer "language_id"
158 t.integer "language_id"
159 t.text "source"
159 t.text "source"
160 t.binary "binary"
160 t.binary "binary"
161 t.datetime "submitted_at"
161 t.datetime "submitted_at"
162 t.datetime "compiled_at"
162 t.datetime "compiled_at"
163 t.text "compiler_message"
163 t.text "compiler_message"
164 t.datetime "graded_at"
164 t.datetime "graded_at"
165 t.integer "points"
165 t.integer "points"
166 t.text "grader_comment"
166 t.text "grader_comment"
167 t.integer "number"
167 t.integer "number"
168 t.string "source_filename"
168 t.string "source_filename"
169 + t.text "output"
169 end
170 end
170
171
171 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
172 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
172 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
173 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
173
174
174 create_table "tasks", :force => true do |t|
175 create_table "tasks", :force => true do |t|
175 t.integer "submission_id"
176 t.integer "submission_id"
176 t.datetime "created_at"
177 t.datetime "created_at"
177 t.integer "status"
178 t.integer "status"
178 t.datetime "updated_at"
179 t.datetime "updated_at"
179 end
180 end
180
181
181 create_table "test_pair_assignments", :force => true do |t|
182 create_table "test_pair_assignments", :force => true do |t|
182 t.integer "user_id"
183 t.integer "user_id"
183 t.integer "problem_id"
184 t.integer "problem_id"
184 t.integer "test_pair_id"
185 t.integer "test_pair_id"
185 t.integer "request_number"
186 t.integer "request_number"
186 t.boolean "submitted"
187 t.boolean "submitted"
187 t.datetime "created_at", :null => false
188 t.datetime "created_at", :null => false
188 t.datetime "updated_at", :null => false
189 t.datetime "updated_at", :null => false
189 end
190 end
190
191
191 create_table "test_pairs", :force => true do |t|
192 create_table "test_pairs", :force => true do |t|
192 t.integer "problem_id"
193 t.integer "problem_id"
193 t.text "input", :limit => 16777215
194 t.text "input", :limit => 16777215
194 t.text "solution", :limit => 16777215
195 t.text "solution", :limit => 16777215
195 t.datetime "created_at", :null => false
196 t.datetime "created_at", :null => false
196 t.datetime "updated_at", :null => false
197 t.datetime "updated_at", :null => false
197 t.boolean "is_private"
198 t.boolean "is_private"
198 end
199 end
199
200
200 create_table "test_requests", :force => true do |t|
201 create_table "test_requests", :force => true do |t|
201 t.integer "user_id"
202 t.integer "user_id"
202 t.integer "problem_id"
203 t.integer "problem_id"
203 t.integer "submission_id"
204 t.integer "submission_id"
204 t.string "input_file_name"
205 t.string "input_file_name"
205 t.string "output_file_name"
206 t.string "output_file_name"
206 t.string "running_stat"
207 t.string "running_stat"
207 t.integer "status"
208 t.integer "status"
208 t.datetime "updated_at", :null => false
209 t.datetime "updated_at", :null => false
209 t.datetime "submitted_at"
210 t.datetime "submitted_at"
210 t.datetime "compiled_at"
211 t.datetime "compiled_at"
211 t.text "compiler_message"
212 t.text "compiler_message"
212 t.datetime "graded_at"
213 t.datetime "graded_at"
213 t.string "grader_comment"
214 t.string "grader_comment"
214 t.datetime "created_at", :null => false
215 t.datetime "created_at", :null => false
215 t.float "running_time"
216 t.float "running_time"
216 t.string "exit_status"
217 t.string "exit_status"
217 t.integer "memory_usage"
218 t.integer "memory_usage"
218 end
219 end
219
220
220 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
221 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
221
222
222 create_table "user_contest_stats", :force => true do |t|
223 create_table "user_contest_stats", :force => true do |t|
223 t.integer "user_id"
224 t.integer "user_id"
224 t.datetime "started_at"
225 t.datetime "started_at"
225 t.datetime "created_at", :null => false
226 t.datetime "created_at", :null => false
226 t.datetime "updated_at", :null => false
227 t.datetime "updated_at", :null => false
227 t.boolean "forced_logout"
228 t.boolean "forced_logout"
228 end
229 end
229
230
230 create_table "users", :force => true do |t|
231 create_table "users", :force => true do |t|
231 t.string "login", :limit => 50
232 t.string "login", :limit => 50
232 t.string "full_name"
233 t.string "full_name"
233 t.string "hashed_password"
234 t.string "hashed_password"
234 t.string "salt", :limit => 5
235 t.string "salt", :limit => 5
235 t.string "alias"
236 t.string "alias"
236 t.string "email"
237 t.string "email"
237 t.integer "site_id"
238 t.integer "site_id"
238 t.integer "country_id"
239 t.integer "country_id"
239 t.boolean "activated", :default => false
240 t.boolean "activated", :default => false
240 t.datetime "created_at"
241 t.datetime "created_at"
241 t.datetime "updated_at"
242 t.datetime "updated_at"
242 end
243 end
243
244
244 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
245 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
245
246
246 end
247 end
You need to be logged in to leave comments. Login now