Description:
merge algo feature
Commit status:
[Not Reviewed]
References:
merge java
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r509:bb124a034509 - - 8 files changed: 95 inserted, 36 deleted

@@ -0,0 +1,5
1 + class AddIpToSubmissions < ActiveRecord::Migration
2 + def change
3 + add_column :submissions, :ip_address, :string
4 + end
5 + end
@@ -1,381 +1,382
1 class MainController < ApplicationController
1 class MainController < ApplicationController
2
2
3 before_filter :authenticate, :except => [:index, :login]
3 before_filter :authenticate, :except => [:index, :login]
4 before_filter :check_viewability, :except => [:index, :login]
4 before_filter :check_viewability, :except => [:index, :login]
5
5
6 append_before_filter :confirm_and_update_start_time,
6 append_before_filter :confirm_and_update_start_time,
7 :except => [:index,
7 :except => [:index,
8 :login,
8 :login,
9 :confirm_contest_start]
9 :confirm_contest_start]
10
10
11 # to prevent log in box to be shown when user logged out of the
11 # to prevent log in box to be shown when user logged out of the
12 # system only in some tab
12 # system only in some tab
13 prepend_before_filter :reject_announcement_refresh_when_logged_out,
13 prepend_before_filter :reject_announcement_refresh_when_logged_out,
14 :only => [:announcements]
14 :only => [:announcements]
15
15
16 # COMMENTED OUT: filter in each action instead
16 # COMMENTED OUT: filter in each action instead
17 # before_filter :verify_time_limit, :only => [:submit]
17 # before_filter :verify_time_limit, :only => [:submit]
18
18
19 verify :method => :post, :only => [:submit],
19 verify :method => :post, :only => [:submit],
20 :redirect_to => { :action => :index }
20 :redirect_to => { :action => :index }
21
21
22 # COMMENT OUT: only need when having high load
22 # COMMENT OUT: only need when having high load
23 # caches_action :index, :login
23 # caches_action :index, :login
24
24
25 # NOTE: This method is not actually needed, 'config/routes.rb' has
25 # NOTE: This method is not actually needed, 'config/routes.rb' has
26 # assigned action login as a default action.
26 # assigned action login as a default action.
27 def index
27 def index
28 redirect_to :action => 'login'
28 redirect_to :action => 'login'
29 end
29 end
30
30
31 def login
31 def login
32 saved_notice = flash[:notice]
32 saved_notice = flash[:notice]
33 reset_session
33 reset_session
34 flash.now[:notice] = saved_notice
34 flash.now[:notice] = saved_notice
35
35
36 # EXPERIMENT:
36 # EXPERIMENT:
37 # Hide login if in single user mode and the url does not
37 # Hide login if in single user mode and the url does not
38 # explicitly specify /login
38 # explicitly specify /login
39 #
39 #
40 # logger.info "PATH: #{request.path}"
40 # logger.info "PATH: #{request.path}"
41 # if GraderConfiguration['system.single_user_mode'] and
41 # if GraderConfiguration['system.single_user_mode'] and
42 # request.path!='/main/login'
42 # request.path!='/main/login'
43 # @hidelogin = true
43 # @hidelogin = true
44 # end
44 # end
45
45
46 @announcements = Announcement.find_for_frontpage
46 @announcements = Announcement.find_for_frontpage
47 render :action => 'login', :layout => 'empty'
47 render :action => 'login', :layout => 'empty'
48 end
48 end
49
49
50 def list
50 def list
51 prepare_list_information
51 prepare_list_information
52 end
52 end
53
53
54 def help
54 def help
55 @user = User.find(session[:user_id])
55 @user = User.find(session[:user_id])
56 end
56 end
57
57
58 def submit
58 def submit
59 user = User.find(session[:user_id])
59 user = User.find(session[:user_id])
60
60
61 @submission = Submission.new
61 @submission = Submission.new
62 @submission.problem_id = params[:submission][:problem_id]
62 @submission.problem_id = params[:submission][:problem_id]
63 @submission.user = user
63 @submission.user = user
64 @submission.language_id = 0
64 @submission.language_id = 0
65 if (params['file']) and (params['file']!='')
65 if (params['file']) and (params['file']!='')
66 @submission.source = params['file'].read
66 @submission.source = params['file'].read
67 @submission.source_filename = params['file'].original_filename
67 @submission.source_filename = params['file'].original_filename
68 end
68 end
69 @submission.submitted_at = Time.new.gmtime
69 @submission.submitted_at = Time.new.gmtime
70 + @submission.ip_address = request.remote_ip
70
71
71 if GraderConfiguration.time_limit_mode? and user.contest_finished?
72 if GraderConfiguration.time_limit_mode? and user.contest_finished?
72 @submission.errors.add_to_base "The contest is over."
73 @submission.errors.add_to_base "The contest is over."
73 prepare_list_information
74 prepare_list_information
74 render :action => 'list' and return
75 render :action => 'list' and return
75 end
76 end
76
77
77 if @submission.valid?
78 if @submission.valid?
78 if @submission.save == false
79 if @submission.save == false
79 flash[:notice] = 'Error saving your submission'
80 flash[:notice] = 'Error saving your submission'
80 elsif Task.create(:submission_id => @submission.id,
81 elsif Task.create(:submission_id => @submission.id,
81 :status => Task::STATUS_INQUEUE) == false
82 :status => Task::STATUS_INQUEUE) == false
82 flash[:notice] = 'Error adding your submission to task queue'
83 flash[:notice] = 'Error adding your submission to task queue'
83 end
84 end
84 else
85 else
85 prepare_list_information
86 prepare_list_information
86 render :action => 'list' and return
87 render :action => 'list' and return
87 end
88 end
88 redirect_to :action => 'list'
89 redirect_to :action => 'list'
89 end
90 end
90
91
91 def source
92 def source
92 submission = Submission.find(params[:id])
93 submission = Submission.find(params[:id])
93 if ((submission.user_id == session[:user_id]) and
94 if ((submission.user_id == session[:user_id]) and
94 (submission.problem != nil) and
95 (submission.problem != nil) and
95 (submission.problem.available))
96 (submission.problem.available))
96 send_data(submission.source,
97 send_data(submission.source,
97 {:filename => submission.download_filename,
98 {:filename => submission.download_filename,
98 :type => 'text/plain'})
99 :type => 'text/plain'})
99 else
100 else
100 flash[:notice] = 'Error viewing source'
101 flash[:notice] = 'Error viewing source'
101 redirect_to :action => 'list'
102 redirect_to :action => 'list'
102 end
103 end
103 end
104 end
104
105
105 def compiler_msg
106 def compiler_msg
106 @submission = Submission.find(params[:id])
107 @submission = Submission.find(params[:id])
107 if @submission.user_id == session[:user_id]
108 if @submission.user_id == session[:user_id]
108 render :action => 'compiler_msg', :layout => 'empty'
109 render :action => 'compiler_msg', :layout => 'empty'
109 else
110 else
110 flash[:notice] = 'Error viewing source'
111 flash[:notice] = 'Error viewing source'
111 redirect_to :action => 'list'
112 redirect_to :action => 'list'
112 end
113 end
113 end
114 end
114
115
115 def submission
116 def submission
116 @user = User.find(session[:user_id])
117 @user = User.find(session[:user_id])
117 @problems = @user.available_problems
118 @problems = @user.available_problems
118 if params[:id]==nil
119 if params[:id]==nil
119 @problem = nil
120 @problem = nil
120 @submissions = nil
121 @submissions = nil
121 else
122 else
122 @problem = Problem.find_by_name(params[:id])
123 @problem = Problem.find_by_name(params[:id])
123 if not @problem.available
124 if not @problem.available
124 redirect_to :action => 'list'
125 redirect_to :action => 'list'
125 flash[:notice] = 'Error: submissions for that problem are not viewable.'
126 flash[:notice] = 'Error: submissions for that problem are not viewable.'
126 return
127 return
127 end
128 end
128 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
129 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
129 end
130 end
130 end
131 end
131
132
132 def result
133 def result
133 if !GraderConfiguration.show_grading_result
134 if !GraderConfiguration.show_grading_result
134 redirect_to :action => 'list' and return
135 redirect_to :action => 'list' and return
135 end
136 end
136 @user = User.find(session[:user_id])
137 @user = User.find(session[:user_id])
137 @submission = Submission.find(params[:id])
138 @submission = Submission.find(params[:id])
138 if @submission.user!=@user
139 if @submission.user!=@user
139 flash[:notice] = 'You are not allowed to view result of other users.'
140 flash[:notice] = 'You are not allowed to view result of other users.'
140 redirect_to :action => 'list' and return
141 redirect_to :action => 'list' and return
141 end
142 end
142 prepare_grading_result(@submission)
143 prepare_grading_result(@submission)
143 end
144 end
144
145
145 def load_output
146 def load_output
146 if !GraderConfiguration.show_grading_result or params[:num]==nil
147 if !GraderConfiguration.show_grading_result or params[:num]==nil
147 redirect_to :action => 'list' and return
148 redirect_to :action => 'list' and return
148 end
149 end
149 @user = User.find(session[:user_id])
150 @user = User.find(session[:user_id])
150 @submission = Submission.find(params[:id])
151 @submission = Submission.find(params[:id])
151 if @submission.user!=@user
152 if @submission.user!=@user
152 flash[:notice] = 'You are not allowed to view result of other users.'
153 flash[:notice] = 'You are not allowed to view result of other users.'
153 redirect_to :action => 'list' and return
154 redirect_to :action => 'list' and return
154 end
155 end
155 case_num = params[:num].to_i
156 case_num = params[:num].to_i
156 out_filename = output_filename(@user.login,
157 out_filename = output_filename(@user.login,
157 @submission.problem.name,
158 @submission.problem.name,
158 @submission.id,
159 @submission.id,
159 case_num)
160 case_num)
160 if !FileTest.exists?(out_filename)
161 if !FileTest.exists?(out_filename)
161 flash[:notice] = 'Output not found.'
162 flash[:notice] = 'Output not found.'
162 redirect_to :action => 'list' and return
163 redirect_to :action => 'list' and return
163 end
164 end
164
165
165 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
166 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
166 response.headers['Content-Type'] = "application/force-download"
167 response.headers['Content-Type'] = "application/force-download"
167 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
168 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
168 response.headers["X-Sendfile"] = out_filename
169 response.headers["X-Sendfile"] = out_filename
169 response.headers['Content-length'] = File.size(out_filename)
170 response.headers['Content-length'] = File.size(out_filename)
170 render :nothing => true
171 render :nothing => true
171 else
172 else
172 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
173 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
173 end
174 end
174 end
175 end
175
176
176 def error
177 def error
177 @user = User.find(session[:user_id])
178 @user = User.find(session[:user_id])
178 end
179 end
179
180
180 # announcement refreshing and hiding methods
181 # announcement refreshing and hiding methods
181
182
182 def announcements
183 def announcements
183 if params.has_key? 'recent'
184 if params.has_key? 'recent'
184 prepare_announcements(params[:recent])
185 prepare_announcements(params[:recent])
185 else
186 else
186 prepare_announcements
187 prepare_announcements
187 end
188 end
188 render(:partial => 'announcement',
189 render(:partial => 'announcement',
189 :collection => @announcements,
190 :collection => @announcements,
190 :locals => {:announcement_effect => true})
191 :locals => {:announcement_effect => true})
191 end
192 end
192
193
193 def confirm_contest_start
194 def confirm_contest_start
194 user = User.find(session[:user_id])
195 user = User.find(session[:user_id])
195 if request.method == :post
196 if request.method == :post
196 user.update_start_time
197 user.update_start_time
197 redirect_to :action => 'list'
198 redirect_to :action => 'list'
198 else
199 else
199 @contests = user.contests
200 @contests = user.contests
200 @user = user
201 @user = user
201 end
202 end
202 end
203 end
203
204
204 protected
205 protected
205
206
206 def prepare_announcements(recent=nil)
207 def prepare_announcements(recent=nil)
207 if GraderConfiguration.show_tasks_to?(@user)
208 if GraderConfiguration.show_tasks_to?(@user)
208 @announcements = Announcement.find_published(true)
209 @announcements = Announcement.find_published(true)
209 else
210 else
210 @announcements = Announcement.find_published
211 @announcements = Announcement.find_published
211 end
212 end
212 if recent!=nil
213 if recent!=nil
213 recent_id = recent.to_i
214 recent_id = recent.to_i
214 @announcements = @announcements.find_all { |a| a.id > recent_id }
215 @announcements = @announcements.find_all { |a| a.id > recent_id }
215 end
216 end
216 end
217 end
217
218
218 def prepare_list_information
219 def prepare_list_information
219 @user = User.find(session[:user_id])
220 @user = User.find(session[:user_id])
220 if not GraderConfiguration.multicontests?
221 if not GraderConfiguration.multicontests?
221 @problems = @user.available_problems
222 @problems = @user.available_problems
222 else
223 else
223 @contest_problems = @user.available_problems_group_by_contests
224 @contest_problems = @user.available_problems_group_by_contests
224 @problems = @user.available_problems
225 @problems = @user.available_problems
225 end
226 end
226 @prob_submissions = {}
227 @prob_submissions = {}
227 @problems.each do |p|
228 @problems.each do |p|
228 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
229 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
229 if sub!=nil
230 if sub!=nil
230 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
231 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
231 else
232 else
232 @prob_submissions[p.id] = { :count => 0, :submission => nil }
233 @prob_submissions[p.id] = { :count => 0, :submission => nil }
233 end
234 end
234 end
235 end
235 prepare_announcements
236 prepare_announcements
236 end
237 end
237
238
238 def check_viewability
239 def check_viewability
239 @user = User.find(session[:user_id])
240 @user = User.find(session[:user_id])
240 if (!GraderConfiguration.show_tasks_to?(@user)) and
241 if (!GraderConfiguration.show_tasks_to?(@user)) and
241 ((action_name=='submission') or (action_name=='submit'))
242 ((action_name=='submission') or (action_name=='submit'))
242 redirect_to :action => 'list' and return
243 redirect_to :action => 'list' and return
243 end
244 end
244 end
245 end
245
246
246 def prepare_grading_result(submission)
247 def prepare_grading_result(submission)
247 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
248 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
248 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
249 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
249 else
250 else
250 # guess task info from problem.full_score
251 # guess task info from problem.full_score
251 cases = submission.problem.full_score / 10
252 cases = submission.problem.full_score / 10
252 grading_info = {
253 grading_info = {
253 'testruns' => cases,
254 'testruns' => cases,
254 'testcases' => cases
255 'testcases' => cases
255 }
256 }
256 end
257 end
257 @test_runs = []
258 @test_runs = []
258 if grading_info['testruns'].is_a? Integer
259 if grading_info['testruns'].is_a? Integer
259 trun_count = grading_info['testruns']
260 trun_count = grading_info['testruns']
260 trun_count.times do |i|
261 trun_count.times do |i|
261 @test_runs << [ read_grading_result(@user.login,
262 @test_runs << [ read_grading_result(@user.login,
262 submission.problem.name,
263 submission.problem.name,
263 submission.id,
264 submission.id,
264 i+1) ]
265 i+1) ]
265 end
266 end
266 else
267 else
267 grading_info['testruns'].keys.sort.each do |num|
268 grading_info['testruns'].keys.sort.each do |num|
268 run = []
269 run = []
269 testrun = grading_info['testruns'][num]
270 testrun = grading_info['testruns'][num]
270 testrun.each do |c|
271 testrun.each do |c|
271 run << read_grading_result(@user.login,
272 run << read_grading_result(@user.login,
272 submission.problem.name,
273 submission.problem.name,
273 submission.id,
274 submission.id,
274 c)
275 c)
275 end
276 end
276 @test_runs << run
277 @test_runs << run
277 end
278 end
278 end
279 end
279 end
280 end
280
281
281 def grading_result_dir(user_name, problem_name, submission_id, case_num)
282 def grading_result_dir(user_name, problem_name, submission_id, case_num)
282 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
283 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
283 end
284 end
284
285
285 def output_filename(user_name, problem_name, submission_id, case_num)
286 def output_filename(user_name, problem_name, submission_id, case_num)
286 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
287 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
287 return "#{dir}/output.txt"
288 return "#{dir}/output.txt"
288 end
289 end
289
290
290 def read_grading_result(user_name, problem_name, submission_id, case_num)
291 def read_grading_result(user_name, problem_name, submission_id, case_num)
291 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
292 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
292 result_file_name = "#{dir}/result"
293 result_file_name = "#{dir}/result"
293 if !FileTest.exists?(result_file_name)
294 if !FileTest.exists?(result_file_name)
294 return {:num => case_num, :msg => 'program did not run'}
295 return {:num => case_num, :msg => 'program did not run'}
295 else
296 else
296 results = File.open(result_file_name).readlines
297 results = File.open(result_file_name).readlines
297 run_stat = extract_running_stat(results)
298 run_stat = extract_running_stat(results)
298 output_filename = "#{dir}/output.txt"
299 output_filename = "#{dir}/output.txt"
299 if FileTest.exists?(output_filename)
300 if FileTest.exists?(output_filename)
300 output_file = true
301 output_file = true
301 output_size = File.size(output_filename)
302 output_size = File.size(output_filename)
302 else
303 else
303 output_file = false
304 output_file = false
304 output_size = 0
305 output_size = 0
305 end
306 end
306
307
307 return {
308 return {
308 :num => case_num,
309 :num => case_num,
309 :msg => results[0],
310 :msg => results[0],
310 :run_stat => run_stat,
311 :run_stat => run_stat,
311 :output => output_file,
312 :output => output_file,
312 :output_size => output_size
313 :output_size => output_size
313 }
314 }
314 end
315 end
315 end
316 end
316
317
317 # copied from grader/script/lib/test_request_helper.rb
318 # copied from grader/script/lib/test_request_helper.rb
318 def extract_running_stat(results)
319 def extract_running_stat(results)
319 running_stat_line = results[-1]
320 running_stat_line = results[-1]
320
321
321 # extract exit status line
322 # extract exit status line
322 run_stat = ""
323 run_stat = ""
323 if !(/[Cc]orrect/.match(results[0]))
324 if !(/[Cc]orrect/.match(results[0]))
324 run_stat = results[0].chomp
325 run_stat = results[0].chomp
325 else
326 else
326 run_stat = 'Program exited normally'
327 run_stat = 'Program exited normally'
327 end
328 end
328
329
329 logger.info "Stat line: #{running_stat_line}"
330 logger.info "Stat line: #{running_stat_line}"
330
331
331 # extract running time
332 # extract running time
332 if res = /r(.*)u(.*)s/.match(running_stat_line)
333 if res = /r(.*)u(.*)s/.match(running_stat_line)
333 seconds = (res[1].to_f + res[2].to_f)
334 seconds = (res[1].to_f + res[2].to_f)
334 time_stat = "Time used: #{seconds} sec."
335 time_stat = "Time used: #{seconds} sec."
335 else
336 else
336 seconds = nil
337 seconds = nil
337 time_stat = "Time used: n/a sec."
338 time_stat = "Time used: n/a sec."
338 end
339 end
339
340
340 # extract memory usage
341 # extract memory usage
341 if res = /s(.*)m/.match(running_stat_line)
342 if res = /s(.*)m/.match(running_stat_line)
342 memory_used = res[1].to_i
343 memory_used = res[1].to_i
343 else
344 else
344 memory_used = -1
345 memory_used = -1
345 end
346 end
346
347
347 return {
348 return {
348 :msg => "#{run_stat}\n#{time_stat}",
349 :msg => "#{run_stat}\n#{time_stat}",
349 :running_time => seconds,
350 :running_time => seconds,
350 :exit_status => run_stat,
351 :exit_status => run_stat,
351 :memory_usage => memory_used
352 :memory_usage => memory_used
352 }
353 }
353 end
354 end
354
355
355 def confirm_and_update_start_time
356 def confirm_and_update_start_time
356 user = User.find(session[:user_id])
357 user = User.find(session[:user_id])
357 if (GraderConfiguration.indv_contest_mode? and
358 if (GraderConfiguration.indv_contest_mode? and
358 GraderConfiguration['contest.confirm_indv_contest_start'] and
359 GraderConfiguration['contest.confirm_indv_contest_start'] and
359 !user.contest_started?)
360 !user.contest_started?)
360 redirect_to :action => 'confirm_contest_start' and return
361 redirect_to :action => 'confirm_contest_start' and return
361 end
362 end
362 if not GraderConfiguration.analysis_mode?
363 if not GraderConfiguration.analysis_mode?
363 user.update_start_time
364 user.update_start_time
364 end
365 end
365 end
366 end
366
367
367 def reject_announcement_refresh_when_logged_out
368 def reject_announcement_refresh_when_logged_out
368 if not session[:user_id]
369 if not session[:user_id]
369 render :text => 'Access forbidden', :status => 403
370 render :text => 'Access forbidden', :status => 403
370 end
371 end
371
372
372 if GraderConfiguration.multicontests?
373 if GraderConfiguration.multicontests?
373 user = User.find(session[:user_id])
374 user = User.find(session[:user_id])
374 if user.contest_stat.forced_logout
375 if user.contest_stat.forced_logout
375 render :text => 'Access forbidden', :status => 403
376 render :text => 'Access forbidden', :status => 403
376 end
377 end
377 end
378 end
378 end
379 end
379
380
380 end
381 end
381
382
@@ -1,189 +1,195
1 class ReportController < ApplicationController
1 class ReportController < ApplicationController
2
2
3 before_filter :admin_authorization, only: [:login_stat,:submission_stat]
3 before_filter :admin_authorization, only: [:login_stat,:submission_stat]
4 before_filter(only: [:problem_hof]) { |c|
4 before_filter(only: [:problem_hof]) { |c|
5 return false unless authenticate
5 return false unless authenticate
6
6
7 if GraderConfiguration["right.user_view_submission"]
7 if GraderConfiguration["right.user_view_submission"]
8 return true;
8 return true;
9 end
9 end
10
10
11 admin_authorization
11 admin_authorization
12 }
12 }
13
13
14 def login_stat
14 def login_stat
15 @logins = Array.new
15 @logins = Array.new
16
16
17 date_and_time = '%Y-%m-%d %H:%M'
17 date_and_time = '%Y-%m-%d %H:%M'
18 begin
18 begin
19 - @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
19 + md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
20 + @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
20 rescue
21 rescue
21 @since_time = DateTime.new(1000,1,1)
22 @since_time = DateTime.new(1000,1,1)
22 end
23 end
23 begin
24 begin
24 - @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
25 + md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
26 + @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
25 rescue
27 rescue
26 @until_time = DateTime.new(3000,1,1)
28 @until_time = DateTime.new(3000,1,1)
27 end
29 end
28
30
29 User.all.each do |user|
31 User.all.each do |user|
30 @logins << { id: user.id,
32 @logins << { id: user.id,
31 login: user.login,
33 login: user.login,
32 full_name: user.full_name,
34 full_name: user.full_name,
33 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
35 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
34 user.id,@since_time,@until_time)
36 user.id,@since_time,@until_time)
35 .count(:id),
37 .count(:id),
36 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
38 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
37 user.id,@since_time,@until_time)
39 user.id,@since_time,@until_time)
38 .minimum(:created_at),
40 .minimum(:created_at),
39 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
41 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
40 user.id,@since_time,@until_time)
42 user.id,@since_time,@until_time)
41 - .maximum(:created_at)
43 + .maximum(:created_at),
44 + ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
45 + user.id,@since_time,@until_time)
46 + .select(:ip_address).uniq
47 +
42 }
48 }
43 end
49 end
44 end
50 end
45
51
46 def submission_stat
52 def submission_stat
47
53
48 date_and_time = '%Y-%m-%d %H:%M'
54 date_and_time = '%Y-%m-%d %H:%M'
49 begin
55 begin
50 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
56 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
51 rescue
57 rescue
52 @since_time = DateTime.new(1000,1,1)
58 @since_time = DateTime.new(1000,1,1)
53 end
59 end
54 begin
60 begin
55 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
61 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
56 rescue
62 rescue
57 @until_time = DateTime.new(3000,1,1)
63 @until_time = DateTime.new(3000,1,1)
58 end
64 end
59
65
60 @submissions = {}
66 @submissions = {}
61
67
62 User.find_each do |user|
68 User.find_each do |user|
63 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
69 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
64 end
70 end
65
71
66 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
72 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
67 if @submissions[s.user_id]
73 if @submissions[s.user_id]
68 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
74 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
69 a = nil
75 a = nil
70 begin
76 begin
71 a = Problem.find(s.problem_id)
77 a = Problem.find(s.problem_id)
72 rescue
78 rescue
73 a = nil
79 a = nil
74 end
80 end
75 @submissions[s.user_id][:sub][s.problem_id] =
81 @submissions[s.user_id][:sub][s.problem_id] =
76 { prob_name: (a ? a.full_name : '(NULL)'),
82 { prob_name: (a ? a.full_name : '(NULL)'),
77 sub_ids: [s.id] }
83 sub_ids: [s.id] }
78 else
84 else
79 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
85 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
80 end
86 end
81 @submissions[s.user_id][:count] += 1
87 @submissions[s.user_id][:count] += 1
82 end
88 end
83 end
89 end
84 end
90 end
85
91
86 def problem_hof
92 def problem_hof
87 # gen problem list
93 # gen problem list
88 @user = User.find(session[:user_id])
94 @user = User.find(session[:user_id])
89 @problems = @user.available_problems
95 @problems = @user.available_problems
90
96
91 # get selected problems or the default
97 # get selected problems or the default
92 if params[:id]
98 if params[:id]
93 begin
99 begin
94 @problem = Problem.available.find(params[:id])
100 @problem = Problem.available.find(params[:id])
95 rescue
101 rescue
96 redirect_to action: :problem_hof
102 redirect_to action: :problem_hof
97 flash[:notice] = 'Error: submissions for that problem are not viewable.'
103 flash[:notice] = 'Error: submissions for that problem are not viewable.'
98 return
104 return
99 end
105 end
100 end
106 end
101
107
102 if @problem
108 if @problem
103 #aggregrate by language
109 #aggregrate by language
104 @by_lang = {}
110 @by_lang = {}
105 Submission.where(problem_id: @problem.id).find_each do |sub|
111 Submission.where(problem_id: @problem.id).find_each do |sub|
106 lang = Language.find_by_id(sub.language_id)
112 lang = Language.find_by_id(sub.language_id)
107 next unless lang
113 next unless lang
108 next unless sub.points >= @problem.full_score
114 next unless sub.points >= @problem.full_score
109
115
110 #initialize
116 #initialize
111 unless @by_lang.has_key?(lang.pretty_name)
117 unless @by_lang.has_key?(lang.pretty_name)
112 @by_lang[lang.pretty_name] = {
118 @by_lang[lang.pretty_name] = {
113 runtime: { avail: false, value: 2**30-1 },
119 runtime: { avail: false, value: 2**30-1 },
114 memory: { avail: false, value: 2**30-1 },
120 memory: { avail: false, value: 2**30-1 },
115 length: { avail: false, value: 2**30-1 },
121 length: { avail: false, value: 2**30-1 },
116 first: { avail: false, value: DateTime.new(3000,1,1) }
122 first: { avail: false, value: DateTime.new(3000,1,1) }
117 }
123 }
118 end
124 end
119
125
120 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
126 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
121 @by_lang[lang.pretty_name][:runtime] = {
127 @by_lang[lang.pretty_name][:runtime] = {
122 avail: true,
128 avail: true,
123 user_id: sub.user_id,
129 user_id: sub.user_id,
124 value: sub.max_runtime,
130 value: sub.max_runtime,
125 sub_id: sub.id
131 sub_id: sub.id
126 }
132 }
127 end
133 end
128
134
129 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
135 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
130 @by_lang[lang.pretty_name][:memory] = {
136 @by_lang[lang.pretty_name][:memory] = {
131 avail: true,
137 avail: true,
132 user_id: sub.user_id,
138 user_id: sub.user_id,
133 value: sub.peak_memory,
139 value: sub.peak_memory,
134 sub_id: sub.id
140 sub_id: sub.id
135 }
141 }
136 end
142 end
137
143
138 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
144 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
139 !sub.user.admin?
145 !sub.user.admin?
140 @by_lang[lang.pretty_name][:first] = {
146 @by_lang[lang.pretty_name][:first] = {
141 avail: true,
147 avail: true,
142 user_id: sub.user_id,
148 user_id: sub.user_id,
143 value: sub.submitted_at,
149 value: sub.submitted_at,
144 sub_id: sub.id
150 sub_id: sub.id
145 }
151 }
146 end
152 end
147
153
148 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
154 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
149 @by_lang[lang.pretty_name][:length] = {
155 @by_lang[lang.pretty_name][:length] = {
150 avail: true,
156 avail: true,
151 user_id: sub.user_id,
157 user_id: sub.user_id,
152 value: sub.effective_code_length,
158 value: sub.effective_code_length,
153 sub_id: sub.id
159 sub_id: sub.id
154 }
160 }
155 end
161 end
156 end
162 end
157
163
158 #process user_id
164 #process user_id
159 @by_lang.each do |lang,prop|
165 @by_lang.each do |lang,prop|
160 prop.each do |k,v|
166 prop.each do |k,v|
161 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
167 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
162 end
168 end
163 end
169 end
164
170
165 #sum into best
171 #sum into best
166 if @by_lang and @by_lang.first
172 if @by_lang and @by_lang.first
167 - @best = @by_lang.first[1]
173 + @best = @by_lang.first[1].clone
168 @by_lang.each do |lang,prop|
174 @by_lang.each do |lang,prop|
169 if @best[:runtime][:value] >= prop[:runtime][:value]
175 if @best[:runtime][:value] >= prop[:runtime][:value]
170 @best[:runtime] = prop[:runtime]
176 @best[:runtime] = prop[:runtime]
171 @best[:runtime][:lang] = lang
177 @best[:runtime][:lang] = lang
172 end
178 end
173 if @best[:memory][:value] >= prop[:memory][:value]
179 if @best[:memory][:value] >= prop[:memory][:value]
174 @best[:memory] = prop[:memory]
180 @best[:memory] = prop[:memory]
175 @best[:memory][:lang] = lang
181 @best[:memory][:lang] = lang
176 end
182 end
177 if @best[:length][:value] >= prop[:length][:value]
183 if @best[:length][:value] >= prop[:length][:value]
178 @best[:length] = prop[:length]
184 @best[:length] = prop[:length]
179 @best[:length][:lang] = lang
185 @best[:length][:lang] = lang
180 end
186 end
181 if @best[:first][:value] >= prop[:first][:value]
187 if @best[:first][:value] >= prop[:first][:value]
182 @best[:first] = prop[:first]
188 @best[:first] = prop[:first]
183 @best[:first][:lang] = lang
189 @best[:first][:lang] = lang
184 end
190 end
185 end
191 end
186 end
192 end
187 end
193 end
188 end
194 end
189 end
195 end
@@ -1,27 +1,61
1 %style{type: "text/css"}
1 %style{type: "text/css"}
2 = @css_style
2 = @css_style
3 + :css
4 + .field {
5 + font-weight: bold;
6 + text-align: right;
7 + padding: 3px;
8 + }
9 +
3
10
4 %h1= "Submission: #{@submission.id}"
11 %h1= "Submission: #{@submission.id}"
5
12
6 - %p
13 +
7 - User:
14 + %h2 Stat
8 - = "(#{@submission.user.login}) #{@submission.user.full_name}"
15 +
9 - %br/
16 + %table.info
10 - Problem:
17 + %thead
18 + %tr.info-head
19 + %th Field
20 + %th Value
21 + %tbody
22 + %tr{class: cycle('info-even','info-odd')}
23 + %td.field User:
24 + %td.value= "(#{@submission.user.login}) #{@submission.user.full_name}"
25 + %tr{class: cycle('info-even','info-odd')}
26 + %td.field Problem:
27 + %td.value
11 - if @submission.problem!=nil
28 - if @submission.problem!=nil
12 - = "#{@submission.problem.full_name}"
29 + = "(#{@submission.problem.name}) #{@submission.problem.full_name}"
13 - else
30 - else
14 = "(n/a)"
31 = "(n/a)"
15 - %br/
32 + %tr{class: cycle('info-even','info-odd')}
16 - = "Number: #{@submission.number}"
33 + %td.field Tries:
17 - %br/
34 + %td.value= @submission.number
18 - = "Submitted at: #{format_short_time(@submission.submitted_at)}"
35 + %tr{class: cycle('info-even','info-odd')}
19 - %br/
36 + %td.field Submitted:
20 - = "Points : #{@submission.points}/#{@submission.problem.full_score}"
37 + %td.value #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
21 - %br/
38 + %tr{class: cycle('info-even','info-odd')}
22 - = "Comment : #{@submission.grader_comment}"
39 + %td.field Graded:
40 + %td.value #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
41 + %tr{class: cycle('info-even','info-odd')}
42 + %td.field Points:
43 + %td.value #{@submission.points}/#{@submission.problem.full_score}
44 + %tr{class: cycle('info-even','info-odd')}
45 + %td.field Comment:
46 + %td.value #{@submission.grader_comment}
47 + %tr{class: cycle('info-even','info-odd')}
48 + %td.field Runtime (s):
49 + %td.value #{@submission.max_runtime}
50 + %tr{class: cycle('info-even','info-odd')}
51 + %td.field Memory (kb):
52 + %td.value #{@submission.peak_memory}
53 + - if session[:admin]
54 + %tr{class: cycle('info-even','info-odd')}
55 + %td.field IP:
56 + %td.value #{@submission.ip_address}
23
57
24 - %b Source code (first 10kb)
58 + %h2 Source code
25 //%div.highlight{:style => "border: 1px solid black;"}
59 //%div.highlight{:style => "border: 1px solid black;"}
26 =@formatted_code.html_safe
60 =@formatted_code.html_safe
27
61
@@ -1,79 +1,79
1 :css
1 :css
2 .hof_user { color: orangered; font-style: italic; }
2 .hof_user { color: orangered; font-style: italic; }
3 .hof_language { color: green; font-style: italic; }
3 .hof_language { color: green; font-style: italic; }
4 .hof_value { color: deeppink;font-style: italic; }
4 .hof_value { color: deeppink;font-style: italic; }
5
5
6 - %h2 Overall
6 + %h2 Overall of #{Problem.find(params[:id]).full_name}
7
7
8 - if @best
8 - if @best
9 %b Best Runtime:
9 %b Best Runtime:
10 by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
10 by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
11 using <span class="hof_language">#{@best[:runtime][:lang]}</span>
11 using <span class="hof_language">#{@best[:runtime][:lang]}</span>
12 with <span class="hof_value">#{@best[:runtime][:value] * 1000} milliseconds</span>
12 with <span class="hof_value">#{@best[:runtime][:value] * 1000} milliseconds</span>
13 at submission
13 at submission
14 = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
14 = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
15 %br/
15 %br/
16
16
17 %b Best Memory Usage:
17 %b Best Memory Usage:
18 by #{link_to @best[:memory][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
18 by #{link_to @best[:memory][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
19 using <span class="hof_language">#{@best[:memory][:lang]}</span>
19 using <span class="hof_language">#{@best[:memory][:lang]}</span>
20 - with <span class="hof_value">#{@best[:memory][:value]} kbytes </span>
20 + with <span class="hof_value">#{number_with_delimiter(@best[:memory][:value])} kbytes </span>
21 at submission
21 at submission
22 = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
22 = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
23 %br/
23 %br/
24
24
25 %b Shortest Code:
25 %b Shortest Code:
26 by #{link_to @best[:length][:user], controller:'users', action:'profile', id:@best[:length][:user_id]}
26 by #{link_to @best[:length][:user], controller:'users', action:'profile', id:@best[:length][:user_id]}
27 using <span class="hof_language">#{@best[:length][:lang]}</span>
27 using <span class="hof_language">#{@best[:length][:lang]}</span>
28 with <span class="hof_value">#{@best[:length][:value]} bytes</span>
28 with <span class="hof_value">#{@best[:length][:value]} bytes</span>
29 at submission
29 at submission
30 = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
30 = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
31 %br/
31 %br/
32
32
33 %b First solver:
33 %b First solver:
34 #{link_to @best[:first][:user], controller:'users', action:'profile', id:@best[:first][:user_id]} is the first solver
34 #{link_to @best[:first][:user], controller:'users', action:'profile', id:@best[:first][:user_id]} is the first solver
35 using <span class="hof_language">#{@best[:first][:lang]}</span>
35 using <span class="hof_language">#{@best[:first][:lang]}</span>
36 on <span class="hof_value">#{@best[:first][:value]}</span>
36 on <span class="hof_value">#{@best[:first][:value]}</span>
37 at submission
37 at submission
38 = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
38 = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
39 %br/
39 %br/
40
40
41
41
42 %p
42 %p
43 This counts only for submission with 100% score <br/>
43 This counts only for submission with 100% score <br/>
44 Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
44 Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
45
45
46 %h2 By language
46 %h2 By language
47
47
48 %table.info
48 %table.info
49 %thead
49 %thead
50 %tr.info-head
50 %tr.info-head
51 %th Language
51 %th Language
52 %th Best runtime (ms)
52 %th Best runtime (ms)
53 %th Best memory (kbytes)
53 %th Best memory (kbytes)
54 %th Shortest Code (bytes)
54 %th Shortest Code (bytes)
55 %th First solver
55 %th First solver
56 %tbody
56 %tbody
57 - @by_lang.each do |lang,value|
57 - @by_lang.each do |lang,value|
58 %tr{class: cycle('info-even','info-odd')}
58 %tr{class: cycle('info-even','info-odd')}
59 %td= lang
59 %td= lang
60 %td
60 %td
61 = link_to value[:runtime][:user], controller: 'users', action: 'profile', id: value[:runtime][:user_id]
61 = link_to value[:runtime][:user], controller: 'users', action: 'profile', id: value[:runtime][:user_id]
62 = "(#{(value[:runtime][:value] * 1000).to_i} @"
62 = "(#{(value[:runtime][:value] * 1000).to_i} @"
63 = "#{link_to("#" + value[:runtime][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:runtime][:sub_id])} )".html_safe
63 = "#{link_to("#" + value[:runtime][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:runtime][:sub_id])} )".html_safe
64 %td
64 %td
65 = link_to value[:memory][:user], controller: 'users', action: 'profile', id: value[:memory][:user_id]
65 = link_to value[:memory][:user], controller: 'users', action: 'profile', id: value[:memory][:user_id]
66 - = "(#{value[:memory][:value]} @"
66 + = "(#{number_with_delimiter(value[:memory][:value])} @"
67 = "#{link_to("#" + value[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:memory][:sub_id])} )".html_safe
67 = "#{link_to("#" + value[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:memory][:sub_id])} )".html_safe
68 %td
68 %td
69 = link_to value[:length][:user], controller: 'users', action: 'profile', id: value[:length][:user_id]
69 = link_to value[:length][:user], controller: 'users', action: 'profile', id: value[:length][:user_id]
70 = "(#{value[:length][:value]} @"
70 = "(#{value[:length][:value]} @"
71 = "#{link_to("#" + value[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:length][:sub_id])} )".html_safe
71 = "#{link_to("#" + value[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:length][:sub_id])} )".html_safe
72 %td
72 %td
73 - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
73 - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
74 = link_to value[:first][:user], controller: 'users', action: 'profile', id: value[:first][:user_id]
74 = link_to value[:first][:user], controller: 'users', action: 'profile', id: value[:first][:user_id]
75 = "(#{value[:first][:value]} @"
75 = "(#{value[:first][:value]} @"
76 = "#{link_to("#" + value[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:first][:sub_id])} )".html_safe
76 = "#{link_to("#" + value[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:first][:sub_id])} )".html_safe
77
77
78 - else
78 - else
79 %h3 No submissions
79 %h3 No submissions
@@ -1,32 +1,36
1 - content_for :header do
1 - content_for :header do
2 = stylesheet_link_tag 'tablesorter-theme.cafe'
2 = stylesheet_link_tag 'tablesorter-theme.cafe'
3 = javascript_include_tag 'new'
3 = javascript_include_tag 'new'
4
4
5 %script{:type=>"text/javascript"}
5 %script{:type=>"text/javascript"}
6 $(function () {
6 $(function () {
7 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
7 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 $('#my_table').tablesorter({widthFixed: true, widgets: ['zebra']});
9 $('#my_table').tablesorter({widthFixed: true, widgets: ['zebra']});
10 });
10 });
11
11
12 %h1 Login status
12 %h1 Login status
13
13
14 =render partial: 'report_menu'
14 =render partial: 'report_menu'
15 =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' }
15 =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' }
16
16
17 %table.tablesorter-cafe#my_table
17 %table.tablesorter-cafe#my_table
18 %thead
18 %thead
19 %tr
19 %tr
20 %th login
20 %th login
21 %th full name
21 %th full name
22 %th login count
22 %th login count
23 %th earliest
23 %th earliest
24 %th latest
24 %th latest
25 + %th IP
25 %tbody
26 %tbody
26 - @logins.each do |l|
27 - @logins.each do |l|
27 %tr{class: cycle('info-even','info-odd')}
28 %tr{class: cycle('info-even','info-odd')}
28 %td= link_to l[:login], controller: 'users', action: 'profile', id: l[:id]
29 %td= link_to l[:login], controller: 'users', action: 'profile', id: l[:id]
29 %td= l[:full_name]
30 %td= l[:full_name]
30 %td= l[:count]
31 %td= l[:count]
31 %td= l[:min] ? l[:min].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
32 %td= l[:min] ? l[:min].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
32 - %td= l[:max] ? time_ago_in_words(l[:max].in_time_zone) + ' ago' : ''
33 + %td= l[:max] ? "#{l[:max].in_time_zone.strftime('%Y-%m-%d %H:%M.%S')} (#{time_ago_in_words(l[:max].in_time_zone)} ago)" : ''
34 + %td
35 + - l[:ip].each do |ip|
36 + #{ip.ip_address} <br/>
@@ -1,46 +1,50
1 - content_for :header do
1 - content_for :header do
2 = javascript_include_tag 'new'
2 = javascript_include_tag 'new'
3
3
4 %script{:type=>"text/javascript"}
4 %script{:type=>"text/javascript"}
5 $(function () {
5 $(function () {
6 $('#submission_table').tablesorter({widgets: ['zebra','filter']});
6 $('#submission_table').tablesorter({widgets: ['zebra','filter']});
7 });
7 });
8
8
9 :css
9 :css
10 .fix-width {
10 .fix-width {
11 font-family: Droid Sans Mono,Consolas, monospace, mono, Courier New, Courier;
11 font-family: Droid Sans Mono,Consolas, monospace, mono, Courier New, Courier;
12 }
12 }
13
13
14 %h1= @user.full_name + ' Profile'
14 %h1= @user.full_name + ' Profile'
15
15
16 %h2 Basic info
16 %h2 Basic info
17 <b>Login:</b> #{@user.login} <br/>
17 <b>Login:</b> #{@user.login} <br/>
18 <b>Full name:</b> #{@user.full_name} <br />
18 <b>Full name:</b> #{@user.full_name} <br />
19
19
20
20
21 %h2 Problem Stat
21 %h2 Problem Stat
22
22
23 %h2 Submissions
23 %h2 Submissions
24
24
25 %table.tablesorter-cafe#submission_table
25 %table.tablesorter-cafe#submission_table
26 %thead
26 %thead
27 %tr
27 %tr
28 %th ID
28 %th ID
29 %th Problem code
29 %th Problem code
30 %th Problem name
30 %th Problem name
31 %th Language
31 %th Language
32 %th Result
32 %th Result
33 %th Score
33 %th Score
34 + - if session[:admin]
35 + %th IP
34 %tbody
36 %tbody
35 - @submission.each do |s|
37 - @submission.each do |s|
36 - next unless s.problem
38 - next unless s.problem
37 %tr
39 %tr
38 %td= link_to "#{s.id}", controller: "graders", action: "submission", id: s.id
40 %td= link_to "#{s.id}", controller: "graders", action: "submission", id: s.id
39 %td= s.problem.name
41 %td= s.problem.name
40 %td= s.problem.full_name
42 %td= s.problem.full_name
41 %td= s.language.pretty_name
43 %td= s.language.pretty_name
42 %td.fix-width= s.grader_comment
44 %td.fix-width= s.grader_comment
43 - %td= s.points/s.problem.full_score * 100
45 + %td= (s.points*100)/s.problem.full_score
46 + - if session[:admin]
47 + %td= s.ip_address
44
48
45
49
46
50
@@ -1,242 +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 => 20140826095949) do
14 + ActiveRecord::Schema.define(:version => 20140917150629) 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", :limit => 16777215
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", :limit => 16777215
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", :limit => 16777215
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 "logins", :force => true do |t|
89 create_table "logins", :force => true do |t|
90 t.string "user_id"
90 t.string "user_id"
91 t.string "ip_address"
91 t.string "ip_address"
92 t.datetime "created_at", :null => false
92 t.datetime "created_at", :null => false
93 t.datetime "updated_at", :null => false
93 t.datetime "updated_at", :null => false
94 end
94 end
95
95
96 create_table "messages", :force => true do |t|
96 create_table "messages", :force => true do |t|
97 t.integer "sender_id"
97 t.integer "sender_id"
98 t.integer "receiver_id"
98 t.integer "receiver_id"
99 t.integer "replying_message_id"
99 t.integer "replying_message_id"
100 - t.text "body", :limit => 16777215
100 + t.text "body"
101 t.boolean "replied"
101 t.boolean "replied"
102 t.datetime "created_at", :null => false
102 t.datetime "created_at", :null => false
103 t.datetime "updated_at", :null => false
103 t.datetime "updated_at", :null => false
104 end
104 end
105
105
106 create_table "problems", :force => true do |t|
106 create_table "problems", :force => true do |t|
107 t.string "name", :limit => 30
107 t.string "name", :limit => 30
108 t.string "full_name"
108 t.string "full_name"
109 t.integer "full_score"
109 t.integer "full_score"
110 t.date "date_added"
110 t.date "date_added"
111 t.boolean "available"
111 t.boolean "available"
112 t.string "url"
112 t.string "url"
113 t.integer "description_id"
113 t.integer "description_id"
114 t.boolean "test_allowed"
114 t.boolean "test_allowed"
115 t.boolean "output_only"
115 t.boolean "output_only"
116 t.string "description_filename"
116 t.string "description_filename"
117 end
117 end
118
118
119 create_table "rights", :force => true do |t|
119 create_table "rights", :force => true do |t|
120 t.string "name"
120 t.string "name"
121 t.string "controller"
121 t.string "controller"
122 t.string "action"
122 t.string "action"
123 end
123 end
124
124
125 create_table "rights_roles", :id => false, :force => true do |t|
125 create_table "rights_roles", :id => false, :force => true do |t|
126 t.integer "right_id"
126 t.integer "right_id"
127 t.integer "role_id"
127 t.integer "role_id"
128 end
128 end
129
129
130 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
130 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
131
131
132 create_table "roles", :force => true do |t|
132 create_table "roles", :force => true do |t|
133 t.string "name"
133 t.string "name"
134 end
134 end
135
135
136 create_table "roles_users", :id => false, :force => true do |t|
136 create_table "roles_users", :id => false, :force => true do |t|
137 t.integer "role_id"
137 t.integer "role_id"
138 t.integer "user_id"
138 t.integer "user_id"
139 end
139 end
140
140
141 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
141 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
142
142
143 create_table "sessions", :force => true do |t|
143 create_table "sessions", :force => true do |t|
144 t.string "session_id"
144 t.string "session_id"
145 - t.text "data", :limit => 16777215
145 + t.text "data"
146 t.datetime "updated_at"
146 t.datetime "updated_at"
147 end
147 end
148
148
149 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
149 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
150 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
150 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
151
151
152 create_table "sites", :force => true do |t|
152 create_table "sites", :force => true do |t|
153 t.string "name"
153 t.string "name"
154 t.boolean "started"
154 t.boolean "started"
155 t.datetime "start_time"
155 t.datetime "start_time"
156 t.datetime "created_at", :null => false
156 t.datetime "created_at", :null => false
157 t.datetime "updated_at", :null => false
157 t.datetime "updated_at", :null => false
158 t.integer "country_id"
158 t.integer "country_id"
159 t.string "password"
159 t.string "password"
160 end
160 end
161
161
162 create_table "submissions", :force => true do |t|
162 create_table "submissions", :force => true do |t|
163 t.integer "user_id"
163 t.integer "user_id"
164 t.integer "problem_id"
164 t.integer "problem_id"
165 t.integer "language_id"
165 t.integer "language_id"
166 - t.text "source", :limit => 16777215
166 + t.text "source"
167 t.binary "binary"
167 t.binary "binary"
168 t.datetime "submitted_at"
168 t.datetime "submitted_at"
169 t.datetime "compiled_at"
169 t.datetime "compiled_at"
170 - t.text "compiler_message", :limit => 16777215
170 + t.text "compiler_message"
171 t.datetime "graded_at"
171 t.datetime "graded_at"
172 t.integer "points"
172 t.integer "points"
173 - t.text "grader_comment", :limit => 16777215
173 + t.text "grader_comment"
174 t.integer "number"
174 t.integer "number"
175 t.string "source_filename"
175 t.string "source_filename"
176 + t.float "max_runtime"
177 + t.integer "peak_memory"
178 + t.integer "effective_code_length"
179 + t.string "ip_address"
176 end
180 end
177
181
178 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
182 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
179 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
183 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
180
184
181 create_table "tasks", :force => true do |t|
185 create_table "tasks", :force => true do |t|
182 t.integer "submission_id"
186 t.integer "submission_id"
183 t.datetime "created_at"
187 t.datetime "created_at"
184 t.integer "status"
188 t.integer "status"
185 t.datetime "updated_at"
189 t.datetime "updated_at"
186 end
190 end
187
191
188 create_table "test_pairs", :force => true do |t|
192 create_table "test_pairs", :force => true do |t|
189 t.integer "problem_id"
193 t.integer "problem_id"
190 - t.text "input", :limit => 2147483647
194 + t.text "input", :limit => 16777215
191 - t.text "solution", :limit => 2147483647
195 + t.text "solution", :limit => 16777215
192 t.datetime "created_at", :null => false
196 t.datetime "created_at", :null => false
193 t.datetime "updated_at", :null => false
197 t.datetime "updated_at", :null => false
194 end
198 end
195
199
196 create_table "test_requests", :force => true do |t|
200 create_table "test_requests", :force => true do |t|
197 t.integer "user_id"
201 t.integer "user_id"
198 t.integer "problem_id"
202 t.integer "problem_id"
199 t.integer "submission_id"
203 t.integer "submission_id"
200 t.string "input_file_name"
204 t.string "input_file_name"
201 t.string "output_file_name"
205 t.string "output_file_name"
202 t.string "running_stat"
206 t.string "running_stat"
203 t.integer "status"
207 t.integer "status"
204 t.datetime "updated_at", :null => false
208 t.datetime "updated_at", :null => false
205 t.datetime "submitted_at"
209 t.datetime "submitted_at"
206 t.datetime "compiled_at"
210 t.datetime "compiled_at"
207 - t.text "compiler_message", :limit => 16777215
211 + t.text "compiler_message"
208 t.datetime "graded_at"
212 t.datetime "graded_at"
209 t.string "grader_comment"
213 t.string "grader_comment"
210 t.datetime "created_at", :null => false
214 t.datetime "created_at", :null => false
211 t.float "running_time"
215 t.float "running_time"
212 t.string "exit_status"
216 t.string "exit_status"
213 t.integer "memory_usage"
217 t.integer "memory_usage"
214 end
218 end
215
219
216 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
220 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
217
221
218 create_table "user_contest_stats", :force => true do |t|
222 create_table "user_contest_stats", :force => true do |t|
219 t.integer "user_id"
223 t.integer "user_id"
220 t.datetime "started_at"
224 t.datetime "started_at"
221 t.datetime "created_at", :null => false
225 t.datetime "created_at", :null => false
222 t.datetime "updated_at", :null => false
226 t.datetime "updated_at", :null => false
223 t.boolean "forced_logout"
227 t.boolean "forced_logout"
224 end
228 end
225
229
226 create_table "users", :force => true do |t|
230 create_table "users", :force => true do |t|
227 t.string "login", :limit => 50
231 t.string "login", :limit => 50
228 t.string "full_name"
232 t.string "full_name"
229 t.string "hashed_password"
233 t.string "hashed_password"
230 t.string "salt", :limit => 5
234 t.string "salt", :limit => 5
231 t.string "alias"
235 t.string "alias"
232 t.string "email"
236 t.string "email"
233 t.integer "site_id"
237 t.integer "site_id"
234 t.integer "country_id"
238 t.integer "country_id"
235 t.boolean "activated", :default => false
239 t.boolean "activated", :default => false
236 t.datetime "created_at"
240 t.datetime "created_at"
237 t.datetime "updated_at"
241 t.datetime "updated_at"
242 + t.string "section"
238 end
243 end
239
244
240 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
245 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
241
246
242 end
247 end
You need to be logged in to leave comments. Login now