Description:
shows recent problem after wrong submissions
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r223:1586858ff9d5 - - 4 files changed: 21 inserted, 1 deleted

@@ -105,274 +105,287
105 105 if params[:id]==nil
106 106 @problem = nil
107 107 @submissions = nil
108 108 else
109 109 @problem = Problem.find_by_name(params[:id])
110 110 if not @problem.available
111 111 redirect_to :action => 'list'
112 112 flash[:notice] = 'Error: submissions for that problem are not viewable.'
113 113 return
114 114 end
115 115 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
116 116 end
117 117 end
118 118
119 119 def result
120 120 if !Configuration.show_grading_result
121 121 redirect_to :action => 'list' and return
122 122 end
123 123 @user = User.find(session[:user_id])
124 124 @submission = Submission.find(params[:id])
125 125 if @submission.user!=@user
126 126 flash[:notice] = 'You are not allowed to view result of other users.'
127 127 redirect_to :action => 'list' and return
128 128 end
129 129 prepare_grading_result(@submission)
130 130 end
131 131
132 132 def load_output
133 133 if !Configuration.show_grading_result or params[:num]==nil
134 134 redirect_to :action => 'list' and return
135 135 end
136 136 @user = User.find(session[:user_id])
137 137 @submission = Submission.find(params[:id])
138 138 if @submission.user!=@user
139 139 flash[:notice] = 'You are not allowed to view result of other users.'
140 140 redirect_to :action => 'list' and return
141 141 end
142 142 case_num = params[:num].to_i
143 143 out_filename = output_filename(@user.login,
144 144 @submission.problem.name,
145 145 @submission.id,
146 146 case_num)
147 147 if !FileTest.exists?(out_filename)
148 148 flash[:notice] = 'Output not found.'
149 149 redirect_to :action => 'list' and return
150 150 end
151 151
152 152 response.headers['Content-Type'] = "application/force-download"
153 153 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
154 154 response.headers["X-Sendfile"] = out_filename
155 155 response.headers['Content-length'] = File.size(out_filename)
156 156 render :nothing => true
157 157 end
158 158
159 159 def error
160 160 @user = User.find(session[:user_id])
161 161 end
162 162
163 163 # announcement refreshing and hiding methods
164 164
165 165 def announcements
166 166 if params.has_key? 'recent'
167 167 prepare_announcements(params[:recent])
168 168 else
169 169 prepare_announcements
170 170 end
171 171 render(:partial => 'announcement',
172 172 :collection => @announcements,
173 173 :locals => {:announcement_effect => true})
174 174 end
175 175
176 176 #
177 177 # actions for Code Jom
178 178 #
179 179 def download_input
180 180 problem = Problem.find(params[:id])
181 181 user = User.find(session[:user_id])
182 182 if user.can_request_new_test_pair_for? problem
183 183 assignment = user.get_new_test_pair_assignment_for problem
184 184 assignment.save
185 185
186 186 send_data(assignment.test_pair.input,
187 187 { :filename => "#{problem.name}-#{assignment.request_number}.in",
188 188 :type => 'text/plain' })
189 189 else
190 190 recent_assignment = user.get_recent_test_pair_assignment_for problem
191 191 send_data(recent_assignment.test_pair.input,
192 192 { :filename => "#{problem.name}-#{recent_assignment.request_number}.in",
193 193 :type => 'text/plain' })
194 194 end
195 195 end
196 196
197 197 def submit_solution
198 198 problem = Problem.find(params[:id])
199 199 user = User.find(session[:user_id])
200 200 recent_assignment = user.get_recent_test_pair_assignment_for problem
201 +
201 202 if recent_assignment == nil
202 203 flash[:notice] = 'You have not requested for any input data for this problem. Please download an input first.'
204 + session[:current_problem_id] = problem.id
203 205 redirect_to :action => 'list' and return
204 206 end
205 207
206 208 if recent_assignment.expired?
207 209 flash[:notice] = 'The current input is expired. Please download a new input data.'
210 + session[:current_problem_id] = problem.id
208 211 redirect_to :action => 'list' and return
209 212 end
210 213
211 214 if recent_assignment.submitted
212 215 flash[:notice] = 'You have already submitted an incorrect solution for this input. Please download a new input data.'
216 + session[:current_problem_id] = problem.id
213 217 redirect_to :action => 'list' and return
214 218 end
215 219
216 220 if params[:file] == nil
217 221 flash[:notice] = 'You have not submitted any output.'
222 + session[:current_problem_id] = problem.id
218 223 redirect_to :action => 'list' and return
219 224 end
220 225
221 226 submitted_solution = params[:file].read
222 227 test_pair = recent_assignment.test_pair
223 228 passed = test_pair.grade(submitted_solution)
224 229 points = passed ? 100 : 0
225 230 submission = Submission.new(:user => user,
226 231 :problem => problem,
227 232 :source => submitted_solution,
228 233 :source_filename => params['file'].original_filename,
229 234 :language_id => 0,
230 235 :submitted_at => Time.new.gmtime,
231 236 :graded_at => Time.new.gmtime,
232 237 :points => points)
233 238 submission.save
234 239 recent_assignment.submitted = true
235 240 recent_assignment.save
236 241
237 242 status = user.get_submission_status_for(problem)
238 243 if status == nil
239 244 status = SubmissionStatus.new :user => user, :problem => problem, :submission_count => 0
240 245 end
241 246
242 247 status.submission_count += 1
243 248 status.passed = passed
244 249 status.save
245 250
246 251 if passed
247 252 flash[:notice] = 'Correct solution.'
248 253 user.update_codejom_status
249 254 else
255 + session[:current_problem_id] = problem.id
250 256 flash[:notice] = 'Incorrect solution.'
251 257 end
252 258 redirect_to :action => 'list'
253 259 end
254 260
255 261 protected
256 262
257 263 def prepare_announcements(recent=nil)
258 264 if Configuration.show_tasks_to?(@user)
259 265 @announcements = Announcement.find_published(true)
260 266 else
261 267 @announcements = Announcement.find_published
262 268 end
263 269 if recent!=nil
264 270 recent_id = recent.to_i
265 271 @announcements = @announcements.find_all { |a| a.id > recent_id }
266 272 end
267 273 end
268 274
269 275 def prepare_list_information
270 276 @user = User.find(session[:user_id])
271 277
272 278 all_problems = Problem.find_available_problems
273 279
274 280 passed = {}
275 281 sub_count = {}
276 282 @user.submission_statuses.each do |status|
277 283 if status.passed
278 284 passed[status.problem_id] = true
279 285 end
280 286 sub_count[status.problem_id] = status.submission_count
281 287 end
282 288
289 + if session.has_key? :current_problem_id
290 + @current_problem_id = session[:current_problem_id]
291 + session.delete(:current_problem_id)
292 + else
293 + @current_problem_id = nil
294 + end
295 +
283 296 @problems = all_problems.reject { |problem| passed.has_key? problem.id }
284 297
285 298 @prob_submissions = Array.new
286 299 @problems.each do |p|
287 300 if sub_count.has_key? p.id
288 301 @prob_submissions << { :count => sub_count[p.id] }
289 302 else
290 303 @prob_submissions << { :count => 0 }
291 304 end
292 305 end
293 306 prepare_announcements
294 307 end
295 308
296 309 def check_viewability
297 310 @user = User.find(session[:user_id])
298 311 if (!Configuration.show_tasks_to?(@user)) and
299 312 ((action_name=='submission') or (action_name=='submit'))
300 313 redirect_to :action => 'list' and return
301 314 end
302 315 end
303 316
304 317 def prepare_grading_result(submission)
305 318 if Configuration.task_grading_info.has_key? submission.problem.name
306 319 grading_info = Configuration.task_grading_info[submission.problem.name]
307 320 else
308 321 # guess task info from problem.full_score
309 322 cases = submission.problem.full_score / 10
310 323 grading_info = {
311 324 'testruns' => cases,
312 325 'testcases' => cases
313 326 }
314 327 end
315 328 @test_runs = []
316 329 if grading_info['testruns'].is_a? Integer
317 330 trun_count = grading_info['testruns']
318 331 trun_count.times do |i|
319 332 @test_runs << [ read_grading_result(@user.login,
320 333 submission.problem.name,
321 334 submission.id,
322 335 i+1) ]
323 336 end
324 337 else
325 338 grading_info['testruns'].keys.sort.each do |num|
326 339 run = []
327 340 testrun = grading_info['testruns'][num]
328 341 testrun.each do |c|
329 342 run << read_grading_result(@user.login,
330 343 submission.problem.name,
331 344 submission.id,
332 345 c)
333 346 end
334 347 @test_runs << run
335 348 end
336 349 end
337 350 end
338 351
339 352 def grading_result_dir(user_name, problem_name, submission_id, case_num)
340 353 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
341 354 end
342 355
343 356 def output_filename(user_name, problem_name, submission_id, case_num)
344 357 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
345 358 return "#{dir}/output.txt"
346 359 end
347 360
348 361 def read_grading_result(user_name, problem_name, submission_id, case_num)
349 362 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
350 363 result_file_name = "#{dir}/result"
351 364 if !FileTest.exists?(result_file_name)
352 365 return {:num => case_num, :msg => 'program did not run'}
353 366 else
354 367 results = File.open(result_file_name).readlines
355 368 run_stat = extract_running_stat(results)
356 369 output_filename = "#{dir}/output.txt"
357 370 if FileTest.exists?(output_filename)
358 371 output_file = true
359 372 output_size = File.size(output_filename)
360 373 else
361 374 output_file = false
362 375 output_size = 0
363 376 end
364 377
365 378 return {
366 379 :num => case_num,
367 380 :msg => results[0],
368 381 :run_stat => run_stat,
369 382 :output => output_file,
370 383 :output_size => output_size
371 384 }
372 385 end
373 386 end
374 387
375 388 # copied from grader/script/lib/test_request_helper.rb
376 389 def extract_running_stat(results)
377 390 running_stat_line = results[-1]
378 391
@@ -1,120 +1,124
1 1 class Problem < ActiveRecord::Base
2 2
3 3 belongs_to :description
4 4 has_many :test_pairs, :dependent => :delete_all
5 5
6 6 validates_presence_of :name
7 7 validates_format_of :name, :with => /^\w+$/
8 8 validates_presence_of :full_name
9 9
10 10 DEFAULT_TIME_LIMIT = 1
11 11 DEFAULT_MEMORY_LIMIT = 32
12 12
13 13 def test_pair_count
14 14 @test_pair_count ||= test_pairs.size
15 15 end
16 16
17 17 def uses_random_test_pair?
18 18 test_pair_count != 0
19 19 end
20 20
21 21 def random_test_pair(forbidden_numbers=nil)
22 + if forbidden_numbers.length < test_pair_count
22 23 begin
23 24 test_num = 1 + rand(test_pair_count)
24 25 end while forbidden_numbers!=nil and forbidden_numbers.include? test_num
26 + else
27 + test_num = 1 + rand(test_pair_count)
28 + end
25 29 test_pairs.find_by_number test_num
26 30 end
27 31
28 32 def self.find_available_problems
29 33 find(:all, :conditions => {:available => true}, :order => "date_added DESC")
30 34 end
31 35
32 36 # TODO: may try to optimize this using cache
33 37 def self.available_problem_count
34 38 return Problem.find_available_problems.length
35 39 end
36 40
37 41 def self.create_from_import_form_params(params, old_problem=nil)
38 42 problem = old_problem || Problem.new
39 43 import_params = Problem.extract_params_and_check(params, problem)
40 44
41 45 if not problem.valid?
42 46 return problem, 'Error importing'
43 47 end
44 48
45 49 problem.full_score = 100
46 50 problem.date_added = Time.new
47 51 problem.test_allowed = true
48 52 problem.output_only = false
49 53 problem.available = false
50 54
51 55 if not problem.save
52 56 return problem, 'Error importing'
53 57 end
54 58
55 59 import_to_db = params.has_key? :import_to_db
56 60
57 61 importer = TestdataImporter.new(problem)
58 62
59 63 if not importer.import_from_file(import_params[:file],
60 64 import_params[:time_limit],
61 65 import_params[:memory_limit],
62 66 import_to_db)
63 67 problem.errors.add_to_base('Import error.')
64 68 end
65 69
66 70 return problem, importer.log_msg
67 71 end
68 72
69 73 protected
70 74
71 75 def self.to_i_or_default(st, default)
72 76 if st!=''
73 77 st.to_i
74 78 else
75 79 default
76 80 end
77 81 end
78 82
79 83 def self.extract_params_and_check(params, problem)
80 84 time_limit = Problem.to_i_or_default(params[:time_limit],
81 85 DEFAULT_TIME_LIMIT)
82 86 memory_limit = Problem.to_i_or_default(params[:memory_limit],
83 87 DEFAULT_MEMORY_LIMIT)
84 88
85 89 if time_limit==0 and time_limit_s!='0'
86 90 problem.errors.add_to_base('Time limit format errors.')
87 91 elsif time_limit<=0 or time_limit >60
88 92 problem.errors.add_to_base('Time limit out of range.')
89 93 end
90 94
91 95 if memory_limit==0 and memory_limit_s!='0'
92 96 problem.errors.add_to_base('Memory limit format errors.')
93 97 elsif memory_limit<=0 or memory_limit >512
94 98 problem.errors.add_to_base('Memory limit out of range.')
95 99 end
96 100
97 101 if params[:file]==nil or params[:file]==''
98 102 problem.errors.add_to_base('No testdata file.')
99 103 end
100 104
101 105 file = params[:file]
102 106
103 107 if problem.errors.length!=0
104 108 return problem
105 109 end
106 110
107 111 problem.name = params[:name]
108 112 if params[:full_name]!=''
109 113 problem.full_name = params[:full_name]
110 114 else
111 115 problem.full_name = params[:name]
112 116 end
113 117
114 118 return {
115 119 :time_limit => time_limit,
116 120 :memory_limit => memory_limit,
117 121 :file => file
118 122 }
119 123 end
120 124
@@ -1,19 +1,21
1 - .problem-panel{:id => "problem-panel-#{problem.id}", :style => "display:none"}
1 + .problem-panel{:id => "problem-panel-#{problem.id}", :style => "#{(problem.id != @current_problem_id) ? "display:none" : ""}"}
2 2 .problem-form{:id => "problem-form-#{problem.id}"}
3 3 - form_tag({ :action => 'download_input', :id => problem.id }, :method => :post) do
4 4 %b Input:
5 5 %input{:type => "submit", :value => "Download input"}
6 + %span{:id => "problem-timing-message-#{problem.id}"}
6 7 = "After downloading, you have #{TEST_ASSIGNMENT_EXPIRATION_DURATION/60} minutes to submit."
8 + %div{:id => "problem-submission-form-#{problem.id}"}
7 9 - form_tag({ :action => 'submit_solution', :id => problem.id }, :method => :post, :multipart => true) do
8 10 %b Submit output:
9 11 %input{:type => "file", :name => "file"}
10 12 %input{:type => "submit", :value => "Submit solution"}
11 13
12 14 .problem-description
13 15 - if problem.description!=nil
14 16 - if problem.description.markdowned
15 17 = markdown(problem.description.body)
16 18 - else
17 19 = problem.description.body
18 20 - else
19 21 (not available)
@@ -1,34 +1,35
1 1 - content_for :head do
2 2 = javascript_include_tag :defaults
3 3 %script{:type => 'text/javascript', :src => '/javascripts/announcement_refresh.js'}
4 4
5 5 = user_title_bar(@user)
6 6
7 7 - if @announcements.length!=0
8 8 .announcementbox
9 9 %span{:class => 'title'}
10 10 Announcements
11 11 #announcementbox-body
12 12 = render :partial => 'announcement', :collection => @announcements
13 13
14 14 %hr/
15 15
16 16 - if (Configuration.contest_mode?) and (@user.site!=nil) and (@user.site.started!=true)
17 17 %p=t 'main.start_soon'
18 18
19 19 - if Configuration.show_tasks_to?(@user)
20 20 .problem-list
21 21 = render :partial => 'problem_title', :collection => @problems, :as => :problem
22 22 .problem-content
23 + - if @current_problem_id==nil
23 24 %span{:id => "problem-panel-filler"}
24 25 %b Welcome to Code Jom
25 26 %br/
26 27 Choose problems from the list on the right.
27 28 = render :partial => 'problem', :collection => @problems
28 29
29 30 %br{:clear=>'both'}/
30 31 %hr/
31 32
32 33 :javascript
33 34 Announcement.registerRefreshEventTimer();
34 35
You need to be logged in to leave comments. Login now