Description:
fixed indv contest timing bug (same as in codejom), added user contest stat reset
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r247:bdb708ab847b - - 4 files changed: 16 inserted, 2 deleted

@@ -1,30 +1,38
1 class ContestsController < ApplicationController
1 class ContestsController < ApplicationController
2
2
3 before_filter :admin_authorization
3 before_filter :admin_authorization
4
4
5 def index
5 def index
6 end
6 end
7
7
8 def user_stat
8 def user_stat
9 if not Configuration.indv_contest_mode?
9 if not Configuration.indv_contest_mode?
10 redirect_to :action => 'index' and return
10 redirect_to :action => 'index' and return
11 end
11 end
12
12
13 @users = User.find(:all)
13 @users = User.find(:all)
14 @start_times = {}
14 @start_times = {}
15 UserContestStat.find(:all).each do |stat|
15 UserContestStat.find(:all).each do |stat|
16 @start_times[stat.user_id] = stat.started_at
16 @start_times[stat.user_id] = stat.started_at
17 end
17 end
18 end
18 end
19
19
20 + def clear_stat
21 + user = User.find(params[:id])
22 + if user.contest_stat!=nil
23 + user.contest_stat.destroy
24 + end
25 + redirect_to :action => 'user_stat'
26 + end
27 +
20 def clear_all_stat
28 def clear_all_stat
21 if not Configuration.indv_contest_mode?
29 if not Configuration.indv_contest_mode?
22 redirect_to :action => 'index' and return
30 redirect_to :action => 'index' and return
23 end
31 end
24
32
25 UserContestStat.delete_all()
33 UserContestStat.delete_all()
26 flash[:notice] = 'All start time statistic cleared.'
34 flash[:notice] = 'All start time statistic cleared.'
27 redirect_to :action => 'index'
35 redirect_to :action => 'index'
28 end
36 end
29
37
30 end
38 end
@@ -1,40 +1,39
1 class LoginController < ApplicationController
1 class LoginController < ApplicationController
2
2
3 def index
3 def index
4 # show login screen
4 # show login screen
5 reset_session
5 reset_session
6 redirect_to :controller => 'main', :action => 'login'
6 redirect_to :controller => 'main', :action => 'login'
7 end
7 end
8
8
9 def login
9 def login
10 if user = User.authenticate(params[:login], params[:password])
10 if user = User.authenticate(params[:login], params[:password])
11 session[:user_id] = user.id
11 session[:user_id] = user.id
12 session[:admin] = user.admin?
12 session[:admin] = user.admin?
13 - UserContestStat.update_user_start_time(user)
14 redirect_to :controller => 'main', :action => 'list'
13 redirect_to :controller => 'main', :action => 'list'
15 else
14 else
16 flash[:notice] = 'Wrong password'
15 flash[:notice] = 'Wrong password'
17 redirect_to :controller => 'main', :action => 'login'
16 redirect_to :controller => 'main', :action => 'login'
18 end
17 end
19 end
18 end
20
19
21 def site_login
20 def site_login
22 begin
21 begin
23 site = Site.find(params[:login][:site_id])
22 site = Site.find(params[:login][:site_id])
24 rescue ActiveRecord::RecordNotFound
23 rescue ActiveRecord::RecordNotFound
25 site = nil
24 site = nil
26 end
25 end
27 if site==nil
26 if site==nil
28 flash[:notice] = 'Wrong site'
27 flash[:notice] = 'Wrong site'
29 redirect_to :controller => 'main', :action => 'login' and return
28 redirect_to :controller => 'main', :action => 'login' and return
30 end
29 end
31 if (site.password) and (site.password == params[:login][:password])
30 if (site.password) and (site.password == params[:login][:password])
32 session[:site_id] = site.id
31 session[:site_id] = site.id
33 redirect_to :controller => 'site', :action => 'index'
32 redirect_to :controller => 'site', :action => 'index'
34 else
33 else
35 flash[:notice] = 'Wrong site password'
34 flash[:notice] = 'Wrong site password'
36 redirect_to :controller => 'site', :action => 'login'
35 redirect_to :controller => 'site', :action => 'login'
37 end
36 end
38 end
37 end
39
38
40 end
39 end
@@ -1,101 +1,103
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 :update_user_start_time, :except => [:index, :login]
7 +
6 # COMMENTED OUT: filter in each action instead
8 # COMMENTED OUT: filter in each action instead
7 # before_filter :verify_time_limit, :only => [:submit]
9 # before_filter :verify_time_limit, :only => [:submit]
8
10
9 verify :method => :post, :only => [:submit],
11 verify :method => :post, :only => [:submit],
10 :redirect_to => { :action => :index }
12 :redirect_to => { :action => :index }
11
13
12 # COMMENT OUT: only need when having high load
14 # COMMENT OUT: only need when having high load
13 # caches_action :index, :login
15 # caches_action :index, :login
14
16
15 # NOTE: This method is not actually needed, 'config/routes.rb' has
17 # NOTE: This method is not actually needed, 'config/routes.rb' has
16 # assigned action login as a default action.
18 # assigned action login as a default action.
17 def index
19 def index
18 redirect_to :action => 'login'
20 redirect_to :action => 'login'
19 end
21 end
20
22
21 def login
23 def login
22 saved_notice = flash[:notice]
24 saved_notice = flash[:notice]
23 reset_session
25 reset_session
24 flash.now[:notice] = saved_notice
26 flash.now[:notice] = saved_notice
25
27
26 # EXPERIMENT:
28 # EXPERIMENT:
27 # Hide login if in single user mode and the url does not
29 # Hide login if in single user mode and the url does not
28 # explicitly specify /login
30 # explicitly specify /login
29 #
31 #
30 # logger.info "PATH: #{request.path}"
32 # logger.info "PATH: #{request.path}"
31 # if Configuration['system.single_user_mode'] and
33 # if Configuration['system.single_user_mode'] and
32 # request.path!='/main/login'
34 # request.path!='/main/login'
33 # @hidelogin = true
35 # @hidelogin = true
34 # end
36 # end
35
37
36 @announcements = Announcement.find_for_frontpage
38 @announcements = Announcement.find_for_frontpage
37 render :action => 'login', :layout => 'empty'
39 render :action => 'login', :layout => 'empty'
38 end
40 end
39
41
40 def list
42 def list
41 prepare_list_information
43 prepare_list_information
42 end
44 end
43
45
44 def help
46 def help
45 @user = User.find(session[:user_id])
47 @user = User.find(session[:user_id])
46 end
48 end
47
49
48 def submit
50 def submit
49 user = User.find(session[:user_id])
51 user = User.find(session[:user_id])
50
52
51 @submission = Submission.new(params[:submission])
53 @submission = Submission.new(params[:submission])
52 @submission.user = user
54 @submission.user = user
53 @submission.language_id = 0
55 @submission.language_id = 0
54 if (params['file']) and (params['file']!='')
56 if (params['file']) and (params['file']!='')
55 @submission.source = params['file'].read
57 @submission.source = params['file'].read
56 @submission.source_filename = params['file'].original_filename
58 @submission.source_filename = params['file'].original_filename
57 end
59 end
58 @submission.submitted_at = Time.new.gmtime
60 @submission.submitted_at = Time.new.gmtime
59
61
60 if Configuration.time_limit_mode? and user.contest_finished?
62 if Configuration.time_limit_mode? and user.contest_finished?
61 @submission.errors.add_to_base "The contest is over."
63 @submission.errors.add_to_base "The contest is over."
62 prepare_list_information
64 prepare_list_information
63 render :action => 'list' and return
65 render :action => 'list' and return
64 end
66 end
65
67
66 if @submission.valid?
68 if @submission.valid?
67 if @submission.save == false
69 if @submission.save == false
68 flash[:notice] = 'Error saving your submission'
70 flash[:notice] = 'Error saving your submission'
69 elsif Task.create(:submission_id => @submission.id,
71 elsif Task.create(:submission_id => @submission.id,
70 :status => Task::STATUS_INQUEUE) == false
72 :status => Task::STATUS_INQUEUE) == false
71 flash[:notice] = 'Error adding your submission to task queue'
73 flash[:notice] = 'Error adding your submission to task queue'
72 end
74 end
73 else
75 else
74 prepare_list_information
76 prepare_list_information
75 render :action => 'list' and return
77 render :action => 'list' and return
76 end
78 end
77 redirect_to :action => 'list'
79 redirect_to :action => 'list'
78 end
80 end
79
81
80 def source
82 def source
81 submission = Submission.find(params[:id])
83 submission = Submission.find(params[:id])
82 if submission.user_id == session[:user_id]
84 if submission.user_id == session[:user_id]
83 send_data(submission.source,
85 send_data(submission.source,
84 {:filename => submission.download_filename,
86 {:filename => submission.download_filename,
85 :type => 'text/plain'})
87 :type => 'text/plain'})
86 else
88 else
87 flash[:notice] = 'Error viewing source'
89 flash[:notice] = 'Error viewing source'
88 redirect_to :action => 'list'
90 redirect_to :action => 'list'
89 end
91 end
90 end
92 end
91
93
92 def compiler_msg
94 def compiler_msg
93 @submission = Submission.find(params[:id])
95 @submission = Submission.find(params[:id])
94 if @submission.user_id == session[:user_id]
96 if @submission.user_id == session[:user_id]
95 render :action => 'compiler_msg', :layout => 'empty'
97 render :action => 'compiler_msg', :layout => 'empty'
96 else
98 else
97 flash[:notice] = 'Error viewing source'
99 flash[:notice] = 'Error viewing source'
98 redirect_to :action => 'list'
100 redirect_to :action => 'list'
99 end
101 end
100 end
102 end
101
103
@@ -226,98 +228,103
226 trun_count = grading_info['testruns']
228 trun_count = grading_info['testruns']
227 trun_count.times do |i|
229 trun_count.times do |i|
228 @test_runs << [ read_grading_result(@user.login,
230 @test_runs << [ read_grading_result(@user.login,
229 submission.problem.name,
231 submission.problem.name,
230 submission.id,
232 submission.id,
231 i+1) ]
233 i+1) ]
232 end
234 end
233 else
235 else
234 grading_info['testruns'].keys.sort.each do |num|
236 grading_info['testruns'].keys.sort.each do |num|
235 run = []
237 run = []
236 testrun = grading_info['testruns'][num]
238 testrun = grading_info['testruns'][num]
237 testrun.each do |c|
239 testrun.each do |c|
238 run << read_grading_result(@user.login,
240 run << read_grading_result(@user.login,
239 submission.problem.name,
241 submission.problem.name,
240 submission.id,
242 submission.id,
241 c)
243 c)
242 end
244 end
243 @test_runs << run
245 @test_runs << run
244 end
246 end
245 end
247 end
246 end
248 end
247
249
248 def grading_result_dir(user_name, problem_name, submission_id, case_num)
250 def grading_result_dir(user_name, problem_name, submission_id, case_num)
249 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
251 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
250 end
252 end
251
253
252 def output_filename(user_name, problem_name, submission_id, case_num)
254 def output_filename(user_name, problem_name, submission_id, case_num)
253 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
255 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
254 return "#{dir}/output.txt"
256 return "#{dir}/output.txt"
255 end
257 end
256
258
257 def read_grading_result(user_name, problem_name, submission_id, case_num)
259 def read_grading_result(user_name, problem_name, submission_id, case_num)
258 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
260 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
259 result_file_name = "#{dir}/result"
261 result_file_name = "#{dir}/result"
260 if !FileTest.exists?(result_file_name)
262 if !FileTest.exists?(result_file_name)
261 return {:num => case_num, :msg => 'program did not run'}
263 return {:num => case_num, :msg => 'program did not run'}
262 else
264 else
263 results = File.open(result_file_name).readlines
265 results = File.open(result_file_name).readlines
264 run_stat = extract_running_stat(results)
266 run_stat = extract_running_stat(results)
265 output_filename = "#{dir}/output.txt"
267 output_filename = "#{dir}/output.txt"
266 if FileTest.exists?(output_filename)
268 if FileTest.exists?(output_filename)
267 output_file = true
269 output_file = true
268 output_size = File.size(output_filename)
270 output_size = File.size(output_filename)
269 else
271 else
270 output_file = false
272 output_file = false
271 output_size = 0
273 output_size = 0
272 end
274 end
273
275
274 return {
276 return {
275 :num => case_num,
277 :num => case_num,
276 :msg => results[0],
278 :msg => results[0],
277 :run_stat => run_stat,
279 :run_stat => run_stat,
278 :output => output_file,
280 :output => output_file,
279 :output_size => output_size
281 :output_size => output_size
280 }
282 }
281 end
283 end
282 end
284 end
283
285
284 # copied from grader/script/lib/test_request_helper.rb
286 # copied from grader/script/lib/test_request_helper.rb
285 def extract_running_stat(results)
287 def extract_running_stat(results)
286 running_stat_line = results[-1]
288 running_stat_line = results[-1]
287
289
288 # extract exit status line
290 # extract exit status line
289 run_stat = ""
291 run_stat = ""
290 if !(/[Cc]orrect/.match(results[0]))
292 if !(/[Cc]orrect/.match(results[0]))
291 run_stat = results[0].chomp
293 run_stat = results[0].chomp
292 else
294 else
293 run_stat = 'Program exited normally'
295 run_stat = 'Program exited normally'
294 end
296 end
295
297
296 logger.info "Stat line: #{running_stat_line}"
298 logger.info "Stat line: #{running_stat_line}"
297
299
298 # extract running time
300 # extract running time
299 if res = /r(.*)u(.*)s/.match(running_stat_line)
301 if res = /r(.*)u(.*)s/.match(running_stat_line)
300 seconds = (res[1].to_f + res[2].to_f)
302 seconds = (res[1].to_f + res[2].to_f)
301 time_stat = "Time used: #{seconds} sec."
303 time_stat = "Time used: #{seconds} sec."
302 else
304 else
303 seconds = nil
305 seconds = nil
304 time_stat = "Time used: n/a sec."
306 time_stat = "Time used: n/a sec."
305 end
307 end
306
308
307 # extract memory usage
309 # extract memory usage
308 if res = /s(.*)m/.match(running_stat_line)
310 if res = /s(.*)m/.match(running_stat_line)
309 memory_used = res[1].to_i
311 memory_used = res[1].to_i
310 else
312 else
311 memory_used = -1
313 memory_used = -1
312 end
314 end
313
315
314 return {
316 return {
315 :msg => "#{run_stat}\n#{time_stat}",
317 :msg => "#{run_stat}\n#{time_stat}",
316 :running_time => seconds,
318 :running_time => seconds,
317 :exit_status => run_stat,
319 :exit_status => run_stat,
318 :memory_usage => memory_used
320 :memory_usage => memory_used
319 }
321 }
320 end
322 end
321
323
324 + def update_user_start_time
325 + user = User.find(session[:user_id])
326 + UserContestStat.update_user_start_time(user)
327 + end
328 +
322 end
329 end
323
330
@@ -1,115 +1,115
1 require 'digest/sha1'
1 require 'digest/sha1'
2
2
3 class User < ActiveRecord::Base
3 class User < ActiveRecord::Base
4
4
5 has_and_belongs_to_many :roles
5 has_and_belongs_to_many :roles
6
6
7 has_many :test_requests, :order => "submitted_at DESC"
7 has_many :test_requests, :order => "submitted_at DESC"
8
8
9 has_many :messages,
9 has_many :messages,
10 :class_name => "Message",
10 :class_name => "Message",
11 :foreign_key => "sender_id",
11 :foreign_key => "sender_id",
12 :order => 'created_at DESC'
12 :order => 'created_at DESC'
13
13
14 has_many :replied_messages,
14 has_many :replied_messages,
15 :class_name => "Message",
15 :class_name => "Message",
16 :foreign_key => "receiver_id",
16 :foreign_key => "receiver_id",
17 :order => 'created_at DESC'
17 :order => 'created_at DESC'
18
18
19 - has_one :contest_stat, :class_name => "UserContestStat"
19 + has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
20
20
21 belongs_to :site
21 belongs_to :site
22 belongs_to :country
22 belongs_to :country
23
23
24 named_scope :activated_users, :conditions => {:activated => true}
24 named_scope :activated_users, :conditions => {:activated => true}
25
25
26 validates_presence_of :login
26 validates_presence_of :login
27 validates_uniqueness_of :login
27 validates_uniqueness_of :login
28 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
28 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
29 validates_length_of :login, :within => 3..30
29 validates_length_of :login, :within => 3..30
30
30
31 validates_presence_of :full_name
31 validates_presence_of :full_name
32 validates_length_of :full_name, :minimum => 1
32 validates_length_of :full_name, :minimum => 1
33
33
34 validates_presence_of :password, :if => :password_required?
34 validates_presence_of :password, :if => :password_required?
35 validates_length_of :password, :within => 4..20, :if => :password_required?
35 validates_length_of :password, :within => 4..20, :if => :password_required?
36 validates_confirmation_of :password, :if => :password_required?
36 validates_confirmation_of :password, :if => :password_required?
37
37
38 validates_format_of :email,
38 validates_format_of :email,
39 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
39 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
40 :if => :email_validation?
40 :if => :email_validation?
41 validate :uniqueness_of_email_from_activated_users,
41 validate :uniqueness_of_email_from_activated_users,
42 :if => :email_validation?
42 :if => :email_validation?
43 validate :enough_time_interval_between_same_email_registrations,
43 validate :enough_time_interval_between_same_email_registrations,
44 :if => :email_validation?
44 :if => :email_validation?
45
45
46 # these are for ytopc
46 # these are for ytopc
47 # disable for now
47 # disable for now
48 #validates_presence_of :province
48 #validates_presence_of :province
49
49
50 attr_accessor :password
50 attr_accessor :password
51
51
52 before_save :encrypt_new_password
52 before_save :encrypt_new_password
53 before_save :assign_default_site
53 before_save :assign_default_site
54
54
55 def self.authenticate(login, password)
55 def self.authenticate(login, password)
56 user = find_by_login(login)
56 user = find_by_login(login)
57 return user if user && user.authenticated?(password)
57 return user if user && user.authenticated?(password)
58 end
58 end
59
59
60 def authenticated?(password)
60 def authenticated?(password)
61 if self.activated
61 if self.activated
62 hashed_password == User.encrypt(password,self.salt)
62 hashed_password == User.encrypt(password,self.salt)
63 else
63 else
64 false
64 false
65 end
65 end
66 end
66 end
67
67
68 def admin?
68 def admin?
69 self.roles.detect {|r| r.name == 'admin' }
69 self.roles.detect {|r| r.name == 'admin' }
70 end
70 end
71
71
72 def email_for_editing
72 def email_for_editing
73 if self.email==nil
73 if self.email==nil
74 "(unknown)"
74 "(unknown)"
75 elsif self.email==''
75 elsif self.email==''
76 "(blank)"
76 "(blank)"
77 else
77 else
78 self.email
78 self.email
79 end
79 end
80 end
80 end
81
81
82 def email_for_editing=(e)
82 def email_for_editing=(e)
83 self.email=e
83 self.email=e
84 end
84 end
85
85
86 def alias_for_editing
86 def alias_for_editing
87 if self.alias==nil
87 if self.alias==nil
88 "(unknown)"
88 "(unknown)"
89 elsif self.alias==''
89 elsif self.alias==''
90 "(blank)"
90 "(blank)"
91 else
91 else
92 self.alias
92 self.alias
93 end
93 end
94 end
94 end
95
95
96 def alias_for_editing=(e)
96 def alias_for_editing=(e)
97 self.alias=e
97 self.alias=e
98 end
98 end
99
99
100 def activation_key
100 def activation_key
101 if self.hashed_password==nil
101 if self.hashed_password==nil
102 encrypt_new_password
102 encrypt_new_password
103 end
103 end
104 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
104 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
105 end
105 end
106
106
107 def verify_activation_key(key)
107 def verify_activation_key(key)
108 key == activation_key
108 key == activation_key
109 end
109 end
110
110
111 def self.random_password(length=5)
111 def self.random_password(length=5)
112 chars = 'abcdefghjkmnopqrstuvwxyz'
112 chars = 'abcdefghjkmnopqrstuvwxyz'
113 password = ''
113 password = ''
114 length.times { password << chars[rand(chars.length - 1)] }
114 length.times { password << chars[rand(chars.length - 1)] }
115 password
115 password
You need to be logged in to leave comments. Login now