Description:
a cleaner, testable way to log out user after contest changed
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r295:4f81b9ab5d77 - - 11 files changed: 170 inserted, 18 deleted

@@ -0,0 +1,9
1 + class AddForcedLogoutToUserContestStat < ActiveRecord::Migration
2 + def self.up
3 + add_column :user_contest_stats, :forced_logout, :boolean
4 + end
5 +
6 + def self.down
7 + remove_column :user_contest_stats, :forced_logout, :boolean
8 + end
9 + end
@@ -0,0 +1,73
1 + require 'delorean'
2 +
3 + require File.dirname(__FILE__) + '/../spec_helper'
4 + require File.dirname(__FILE__) + '/../config_spec_helper'
5 +
6 + describe UserAdminController, "when manage contest" do
7 +
8 + include ConfigSpecHelperMethods
9 +
10 + fixtures :users
11 + fixtures :problems
12 + fixtures :contests
13 + fixtures :roles
14 +
15 + def change_users_contest_to(user_login_list, contest, reset_timer=false)
16 + post_data = {
17 + :contest => {:id => contest.id},
18 + :operation => 'assign',
19 + :login_list => user_login_list
20 + }
21 + post_data[:reset_timer] = true if reset_timer
22 + post 'manage_contest', post_data, {:user_id => @admin_user.id}
23 + end
24 +
25 + before(:each) do
26 + @admin_user = users(:mary)
27 + @contest_b = contests(:contest_b)
28 + @james = users(:james)
29 + @jack = users(:jack)
30 +
31 + set_contest_time_limit('3:00')
32 + set_indv_contest_mode
33 + end
34 +
35 + it "should allow admin to see contest management page" do
36 + get 'contest_management', {}, {:user_id => @admin_user.id}
37 +
38 + response.should render_template 'user_admin/contest_management'
39 + end
40 +
41 + it "should change users' contest" do
42 + change_users_contest_to("james\njack", @contest_b)
43 + response.should redirect_to :action => 'contest_management'
44 +
45 + @james.contests(true).should include @contest_b
46 + @jack.contests(true).should_not include @contest_a
47 + end
48 +
49 + it "should reset users' timer when their contests change" do
50 + @james.update_start_time
51 +
52 + Delorean.time_travel_to(190.minutes.since) do
53 + @james.contest_finished?.should be_true
54 +
55 + change_users_contest_to("james", @contest_b, true)
56 +
57 + @james.contest_finished?.should be_false
58 + end
59 + end
60 +
61 + it "should set forced_logout flag for users when their contests change" do
62 + @james.update_start_time
63 +
64 + Delorean.time_travel_to(190.minutes.since) do
65 + @james.contest_finished?.should be_true
66 +
67 + change_users_contest_to("james", @contest_b, true)
68 +
69 + @james.contest_stat(true).forced_logout.should be_true
70 + end
71 + end
72 +
73 + end
@@ -1,74 +1,84
1 # Filters added to this controller apply to all controllers in the application.
1 # Filters added to this controller apply to all controllers in the application.
2 # Likewise, all the methods added will be available for all controllers.
2 # Likewise, all the methods added will be available for all controllers.
3
3
4 class ApplicationController < ActionController::Base
4 class ApplicationController < ActionController::Base
5
5
6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
7
7
8 def admin_authorization
8 def admin_authorization
9 return false unless authenticate
9 return false unless authenticate
10 user = User.find(session[:user_id], :include => ['roles'])
10 user = User.find(session[:user_id], :include => ['roles'])
11 redirect_to :controller => 'main', :action => 'login' unless user.admin?
11 redirect_to :controller => 'main', :action => 'login' unless user.admin?
12 end
12 end
13
13
14 def authorization_by_roles(allowed_roles)
14 def authorization_by_roles(allowed_roles)
15 return false unless authenticate
15 return false unless authenticate
16 user = User.find(session[:user_id])
16 user = User.find(session[:user_id])
17 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
17 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
18 flash[:notice] = 'You are not authorized to view the page you requested'
18 flash[:notice] = 'You are not authorized to view the page you requested'
19 redirect_to :controller => 'main', :action => 'login'
19 redirect_to :controller => 'main', :action => 'login'
20 return false
20 return false
21 end
21 end
22 end
22 end
23
23
24 protected
24 protected
25
25
26 def authenticate
26 def authenticate
27 unless session[:user_id]
27 unless session[:user_id]
28 redirect_to :controller => 'main', :action => 'login'
28 redirect_to :controller => 'main', :action => 'login'
29 return false
29 return false
30 end
30 end
31
31
32 - #Configuration.reload
33 # check if run in single user mode
32 # check if run in single user mode
34 - if (Configuration[SINGLE_USER_MODE_CONF_KEY])
33 + if Configuration[SINGLE_USER_MODE_CONF_KEY]
35 user = User.find(session[:user_id])
34 user = User.find(session[:user_id])
36 if user==nil or (not user.admin?)
35 if user==nil or (not user.admin?)
37 redirect_to :controller => 'main', :action => 'login'
36 redirect_to :controller => 'main', :action => 'login'
38 return false
37 return false
39 end
38 end
39 + return true
40 end
40 end
41
41
42 + if Configuration.multicontests?
43 + user = User.find(session[:user_id])
44 + begin
45 + if user.contest_stat(true).forced_logout
46 + flash[:notice] = 'You have been automatically logged out.'
47 + redirect_to :controller => 'main', :action => 'index'
48 + end
49 + rescue
50 + end
51 + end
42 return true
52 return true
43 end
53 end
44
54
45 def authorization
55 def authorization
46 return false unless authenticate
56 return false unless authenticate
47 user = User.find(session[:user_id])
57 user = User.find(session[:user_id])
48 unless user.roles.detect { |role|
58 unless user.roles.detect { |role|
49 role.rights.detect{ |right|
59 role.rights.detect{ |right|
50 right.controller == self.class.controller_name and
60 right.controller == self.class.controller_name and
51 (right.action == 'all' or right.action == action_name)
61 (right.action == 'all' or right.action == action_name)
52 }
62 }
53 }
63 }
54 flash[:notice] = 'You are not authorized to view the page you requested'
64 flash[:notice] = 'You are not authorized to view the page you requested'
55 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
65 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
56 redirect_to :controller => 'main', :action => 'login'
66 redirect_to :controller => 'main', :action => 'login'
57 return false
67 return false
58 end
68 end
59 end
69 end
60
70
61 def verify_time_limit
71 def verify_time_limit
62 return true if session[:user_id]==nil
72 return true if session[:user_id]==nil
63 user = User.find(session[:user_id], :include => :site)
73 user = User.find(session[:user_id], :include => :site)
64 return true if user==nil or user.site == nil
74 return true if user==nil or user.site == nil
65 if user.contest_finished?
75 if user.contest_finished?
66 flash[:notice] = 'Error: the contest you are participating is over.'
76 flash[:notice] = 'Error: the contest you are participating is over.'
67 redirect_to :back
77 redirect_to :back
68 return false
78 return false
69 end
79 end
70 return true
80 return true
71 end
81 end
72
82
73 end
83 end
74
84
@@ -1,39 +1,51
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 +
14 + # clear forced logout flag for multicontests contest change
15 + if Configuration.multicontests?
16 + contest_stat = user.contest_stat
17 + if contest_stat.respond_to? :forced_logout
18 + if contest_stat.forced_logout
19 + contest_stat.forced_logout = false
20 + contest_stat.save
21 + end
22 + end
23 + end
24 +
13 redirect_to :controller => 'main', :action => 'list'
25 redirect_to :controller => 'main', :action => 'list'
14 else
26 else
15 flash[:notice] = 'Wrong password'
27 flash[:notice] = 'Wrong password'
16 redirect_to :controller => 'main', :action => 'login'
28 redirect_to :controller => 'main', :action => 'login'
17 end
29 end
18 end
30 end
19
31
20 def site_login
32 def site_login
21 begin
33 begin
22 site = Site.find(params[:login][:site_id])
34 site = Site.find(params[:login][:site_id])
23 rescue ActiveRecord::RecordNotFound
35 rescue ActiveRecord::RecordNotFound
24 site = nil
36 site = nil
25 end
37 end
26 if site==nil
38 if site==nil
27 flash[:notice] = 'Wrong site'
39 flash[:notice] = 'Wrong site'
28 redirect_to :controller => 'main', :action => 'login' and return
40 redirect_to :controller => 'main', :action => 'login' and return
29 end
41 end
30 if (site.password) and (site.password == params[:login][:password])
42 if (site.password) and (site.password == params[:login][:password])
31 session[:site_id] = site.id
43 session[:site_id] = site.id
32 redirect_to :controller => 'site', :action => 'index'
44 redirect_to :controller => 'site', :action => 'index'
33 else
45 else
34 flash[:notice] = 'Wrong site password'
46 flash[:notice] = 'Wrong site password'
35 redirect_to :controller => 'site', :action => 'login'
47 redirect_to :controller => 'site', :action => 'login'
36 end
48 end
37 end
49 end
38
50
39 end
51 end
@@ -154,196 +154,203
154 flash[:notice] = 'Output not found.'
154 flash[:notice] = 'Output not found.'
155 redirect_to :action => 'list' and return
155 redirect_to :action => 'list' and return
156 end
156 end
157
157
158 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
158 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
159 response.headers['Content-Type'] = "application/force-download"
159 response.headers['Content-Type'] = "application/force-download"
160 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
160 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
161 response.headers["X-Sendfile"] = out_filename
161 response.headers["X-Sendfile"] = out_filename
162 response.headers['Content-length'] = File.size(out_filename)
162 response.headers['Content-length'] = File.size(out_filename)
163 render :nothing => true
163 render :nothing => true
164 else
164 else
165 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
165 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
166 end
166 end
167 end
167 end
168
168
169 def error
169 def error
170 @user = User.find(session[:user_id])
170 @user = User.find(session[:user_id])
171 end
171 end
172
172
173 # announcement refreshing and hiding methods
173 # announcement refreshing and hiding methods
174
174
175 def announcements
175 def announcements
176 if params.has_key? 'recent'
176 if params.has_key? 'recent'
177 prepare_announcements(params[:recent])
177 prepare_announcements(params[:recent])
178 else
178 else
179 prepare_announcements
179 prepare_announcements
180 end
180 end
181 render(:partial => 'announcement',
181 render(:partial => 'announcement',
182 :collection => @announcements,
182 :collection => @announcements,
183 :locals => {:announcement_effect => true})
183 :locals => {:announcement_effect => true})
184 end
184 end
185
185
186 protected
186 protected
187
187
188 def prepare_announcements(recent=nil)
188 def prepare_announcements(recent=nil)
189 if Configuration.show_tasks_to?(@user)
189 if Configuration.show_tasks_to?(@user)
190 @announcements = Announcement.find_published(true)
190 @announcements = Announcement.find_published(true)
191 else
191 else
192 @announcements = Announcement.find_published
192 @announcements = Announcement.find_published
193 end
193 end
194 if recent!=nil
194 if recent!=nil
195 recent_id = recent.to_i
195 recent_id = recent.to_i
196 @announcements = @announcements.find_all { |a| a.id > recent_id }
196 @announcements = @announcements.find_all { |a| a.id > recent_id }
197 end
197 end
198 end
198 end
199
199
200 def prepare_list_information
200 def prepare_list_information
201 @user = User.find(session[:user_id])
201 @user = User.find(session[:user_id])
202 if not Configuration.multicontests?
202 if not Configuration.multicontests?
203 @problems = @user.available_problems
203 @problems = @user.available_problems
204 else
204 else
205 @contest_problems = @user.available_problems_group_by_contests
205 @contest_problems = @user.available_problems_group_by_contests
206 @problems = @user.available_problems
206 @problems = @user.available_problems
207 end
207 end
208 @prob_submissions = {}
208 @prob_submissions = {}
209 @problems.each do |p|
209 @problems.each do |p|
210 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
210 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
211 if sub!=nil
211 if sub!=nil
212 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
212 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
213 else
213 else
214 @prob_submissions[p.id] = { :count => 0, :submission => nil }
214 @prob_submissions[p.id] = { :count => 0, :submission => nil }
215 end
215 end
216 end
216 end
217 prepare_announcements
217 prepare_announcements
218 end
218 end
219
219
220 def check_viewability
220 def check_viewability
221 @user = User.find(session[:user_id])
221 @user = User.find(session[:user_id])
222 if (!Configuration.show_tasks_to?(@user)) and
222 if (!Configuration.show_tasks_to?(@user)) and
223 ((action_name=='submission') or (action_name=='submit'))
223 ((action_name=='submission') or (action_name=='submit'))
224 redirect_to :action => 'list' and return
224 redirect_to :action => 'list' and return
225 end
225 end
226 end
226 end
227
227
228 def prepare_grading_result(submission)
228 def prepare_grading_result(submission)
229 if Configuration.task_grading_info.has_key? submission.problem.name
229 if Configuration.task_grading_info.has_key? submission.problem.name
230 grading_info = Configuration.task_grading_info[submission.problem.name]
230 grading_info = Configuration.task_grading_info[submission.problem.name]
231 else
231 else
232 # guess task info from problem.full_score
232 # guess task info from problem.full_score
233 cases = submission.problem.full_score / 10
233 cases = submission.problem.full_score / 10
234 grading_info = {
234 grading_info = {
235 'testruns' => cases,
235 'testruns' => cases,
236 'testcases' => cases
236 'testcases' => cases
237 }
237 }
238 end
238 end
239 @test_runs = []
239 @test_runs = []
240 if grading_info['testruns'].is_a? Integer
240 if grading_info['testruns'].is_a? Integer
241 trun_count = grading_info['testruns']
241 trun_count = grading_info['testruns']
242 trun_count.times do |i|
242 trun_count.times do |i|
243 @test_runs << [ read_grading_result(@user.login,
243 @test_runs << [ read_grading_result(@user.login,
244 submission.problem.name,
244 submission.problem.name,
245 submission.id,
245 submission.id,
246 i+1) ]
246 i+1) ]
247 end
247 end
248 else
248 else
249 grading_info['testruns'].keys.sort.each do |num|
249 grading_info['testruns'].keys.sort.each do |num|
250 run = []
250 run = []
251 testrun = grading_info['testruns'][num]
251 testrun = grading_info['testruns'][num]
252 testrun.each do |c|
252 testrun.each do |c|
253 run << read_grading_result(@user.login,
253 run << read_grading_result(@user.login,
254 submission.problem.name,
254 submission.problem.name,
255 submission.id,
255 submission.id,
256 c)
256 c)
257 end
257 end
258 @test_runs << run
258 @test_runs << run
259 end
259 end
260 end
260 end
261 end
261 end
262
262
263 def grading_result_dir(user_name, problem_name, submission_id, case_num)
263 def grading_result_dir(user_name, problem_name, submission_id, case_num)
264 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
264 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
265 end
265 end
266
266
267 def output_filename(user_name, problem_name, submission_id, case_num)
267 def output_filename(user_name, problem_name, submission_id, case_num)
268 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
268 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
269 return "#{dir}/output.txt"
269 return "#{dir}/output.txt"
270 end
270 end
271
271
272 def read_grading_result(user_name, problem_name, submission_id, case_num)
272 def read_grading_result(user_name, problem_name, submission_id, case_num)
273 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
273 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
274 result_file_name = "#{dir}/result"
274 result_file_name = "#{dir}/result"
275 if !FileTest.exists?(result_file_name)
275 if !FileTest.exists?(result_file_name)
276 return {:num => case_num, :msg => 'program did not run'}
276 return {:num => case_num, :msg => 'program did not run'}
277 else
277 else
278 results = File.open(result_file_name).readlines
278 results = File.open(result_file_name).readlines
279 run_stat = extract_running_stat(results)
279 run_stat = extract_running_stat(results)
280 output_filename = "#{dir}/output.txt"
280 output_filename = "#{dir}/output.txt"
281 if FileTest.exists?(output_filename)
281 if FileTest.exists?(output_filename)
282 output_file = true
282 output_file = true
283 output_size = File.size(output_filename)
283 output_size = File.size(output_filename)
284 else
284 else
285 output_file = false
285 output_file = false
286 output_size = 0
286 output_size = 0
287 end
287 end
288
288
289 return {
289 return {
290 :num => case_num,
290 :num => case_num,
291 :msg => results[0],
291 :msg => results[0],
292 :run_stat => run_stat,
292 :run_stat => run_stat,
293 :output => output_file,
293 :output => output_file,
294 :output_size => output_size
294 :output_size => output_size
295 }
295 }
296 end
296 end
297 end
297 end
298
298
299 # copied from grader/script/lib/test_request_helper.rb
299 # copied from grader/script/lib/test_request_helper.rb
300 def extract_running_stat(results)
300 def extract_running_stat(results)
301 running_stat_line = results[-1]
301 running_stat_line = results[-1]
302
302
303 # extract exit status line
303 # extract exit status line
304 run_stat = ""
304 run_stat = ""
305 if !(/[Cc]orrect/.match(results[0]))
305 if !(/[Cc]orrect/.match(results[0]))
306 run_stat = results[0].chomp
306 run_stat = results[0].chomp
307 else
307 else
308 run_stat = 'Program exited normally'
308 run_stat = 'Program exited normally'
309 end
309 end
310
310
311 logger.info "Stat line: #{running_stat_line}"
311 logger.info "Stat line: #{running_stat_line}"
312
312
313 # extract running time
313 # extract running time
314 if res = /r(.*)u(.*)s/.match(running_stat_line)
314 if res = /r(.*)u(.*)s/.match(running_stat_line)
315 seconds = (res[1].to_f + res[2].to_f)
315 seconds = (res[1].to_f + res[2].to_f)
316 time_stat = "Time used: #{seconds} sec."
316 time_stat = "Time used: #{seconds} sec."
317 else
317 else
318 seconds = nil
318 seconds = nil
319 time_stat = "Time used: n/a sec."
319 time_stat = "Time used: n/a sec."
320 end
320 end
321
321
322 # extract memory usage
322 # extract memory usage
323 if res = /s(.*)m/.match(running_stat_line)
323 if res = /s(.*)m/.match(running_stat_line)
324 memory_used = res[1].to_i
324 memory_used = res[1].to_i
325 else
325 else
326 memory_used = -1
326 memory_used = -1
327 end
327 end
328
328
329 return {
329 return {
330 :msg => "#{run_stat}\n#{time_stat}",
330 :msg => "#{run_stat}\n#{time_stat}",
331 :running_time => seconds,
331 :running_time => seconds,
332 :exit_status => run_stat,
332 :exit_status => run_stat,
333 :memory_usage => memory_used
333 :memory_usage => memory_used
334 }
334 }
335 end
335 end
336
336
337 def update_user_start_time
337 def update_user_start_time
338 user = User.find(session[:user_id])
338 user = User.find(session[:user_id])
339 user.update_start_time
339 user.update_start_time
340 end
340 end
341
341
342 def reject_announcement_refresh_when_logged_out
342 def reject_announcement_refresh_when_logged_out
343 if not session[:user_id]
343 if not session[:user_id]
344 render :text => 'Access forbidden', :status => 403
344 render :text => 'Access forbidden', :status => 403
345 end
345 end
346 +
347 + if Configuration.multicontests?
348 + user = User.find(session[:user_id])
349 + if user.contest_stat.forced_logout
350 + render :text => 'Access forbidden', :status => 403
351 + end
352 + end
346 end
353 end
347
354
348 end
355 end
349
356
@@ -7,337 +7,341
7 render :action => 'list'
7 render :action => 'list'
8 end
8 end
9
9
10 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
10 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
11 verify :method => :post, :only => [ :destroy,
11 verify :method => :post, :only => [ :destroy,
12 :create, :create_from_list,
12 :create, :create_from_list,
13 :update ],
13 :update ],
14 :redirect_to => { :action => :list }
14 :redirect_to => { :action => :list }
15
15
16 def list
16 def list
17 @users = User.find(:all)
17 @users = User.find(:all)
18 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
18 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
19 @contests = Contest.all(:conditions => {:enabled => true})
19 @contests = Contest.all(:conditions => {:enabled => true})
20 end
20 end
21
21
22 def active
22 def active
23 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
23 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
24 @users = []
24 @users = []
25 sessions.each do |session|
25 sessions.each do |session|
26 if session.data[:user_id]
26 if session.data[:user_id]
27 @users << User.find(session.data[:user_id])
27 @users << User.find(session.data[:user_id])
28 end
28 end
29 end
29 end
30 end
30 end
31
31
32 def show
32 def show
33 @user = User.find(params[:id])
33 @user = User.find(params[:id])
34 end
34 end
35
35
36 def new
36 def new
37 @user = User.new
37 @user = User.new
38 end
38 end
39
39
40 def create
40 def create
41 @user = User.new(params[:user])
41 @user = User.new(params[:user])
42 @user.activated = true
42 @user.activated = true
43 if @user.save
43 if @user.save
44 flash[:notice] = 'User was successfully created.'
44 flash[:notice] = 'User was successfully created.'
45 redirect_to :action => 'list'
45 redirect_to :action => 'list'
46 else
46 else
47 render :action => 'new'
47 render :action => 'new'
48 end
48 end
49 end
49 end
50
50
51 def create_from_list
51 def create_from_list
52 lines = params[:user_list]
52 lines = params[:user_list]
53
53
54 note = []
54 note = []
55
55
56 lines.split("\n").each do |line|
56 lines.split("\n").each do |line|
57 items = line.chomp.split(',')
57 items = line.chomp.split(',')
58 if items.length>=2
58 if items.length>=2
59 login = items[0]
59 login = items[0]
60 full_name = items[1]
60 full_name = items[1]
61
61
62 added_random_password = false
62 added_random_password = false
63 if items.length>=3
63 if items.length>=3
64 password = items[2]
64 password = items[2]
65 user_alias = (items.length>=4) ? items[3] : login
65 user_alias = (items.length>=4) ? items[3] : login
66 else
66 else
67 password = random_password
67 password = random_password
68 user_alias = (items.length>=4) ? items[3] : login
68 user_alias = (items.length>=4) ? items[3] : login
69 added_random_password = true
69 added_random_password = true
70 end
70 end
71
71
72 user = User.new({:login => login,
72 user = User.new({:login => login,
73 :full_name => full_name,
73 :full_name => full_name,
74 :password => password,
74 :password => password,
75 :password_confirmation => password,
75 :password_confirmation => password,
76 :alias => user_alias})
76 :alias => user_alias})
77 user.activated = true
77 user.activated = true
78 user.save
78 user.save
79
79
80 if added_random_password
80 if added_random_password
81 note << "'#{login}' (+)"
81 note << "'#{login}' (+)"
82 else
82 else
83 note << login
83 note << login
84 end
84 end
85 end
85 end
86 end
86 end
87 flash[:notice] = 'User(s) ' + note.join(', ') +
87 flash[:notice] = 'User(s) ' + note.join(', ') +
88 ' were successfully created. ' +
88 ' were successfully created. ' +
89 '( (+) - created with random passwords.)'
89 '( (+) - created with random passwords.)'
90 redirect_to :action => 'list'
90 redirect_to :action => 'list'
91 end
91 end
92
92
93 def edit
93 def edit
94 @user = User.find(params[:id])
94 @user = User.find(params[:id])
95 end
95 end
96
96
97 def update
97 def update
98 @user = User.find(params[:id])
98 @user = User.find(params[:id])
99 if @user.update_attributes(params[:user])
99 if @user.update_attributes(params[:user])
100 flash[:notice] = 'User was successfully updated.'
100 flash[:notice] = 'User was successfully updated.'
101 redirect_to :action => 'show', :id => @user
101 redirect_to :action => 'show', :id => @user
102 else
102 else
103 render :action => 'edit'
103 render :action => 'edit'
104 end
104 end
105 end
105 end
106
106
107 def destroy
107 def destroy
108 User.find(params[:id]).destroy
108 User.find(params[:id]).destroy
109 redirect_to :action => 'list'
109 redirect_to :action => 'list'
110 end
110 end
111
111
112 def user_stat
112 def user_stat
113 @problems = Problem.find_available_problems
113 @problems = Problem.find_available_problems
114 @users = User.find(:all)
114 @users = User.find(:all)
115 @scorearray = Array.new
115 @scorearray = Array.new
116 @users.each do |u|
116 @users.each do |u|
117 ustat = Array.new
117 ustat = Array.new
118 ustat[0] = u
118 ustat[0] = u
119 @problems.each do |p|
119 @problems.each do |p|
120 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
120 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
121 if (sub!=nil) and (sub.points!=nil)
121 if (sub!=nil) and (sub.points!=nil)
122 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
122 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
123 else
123 else
124 ustat << [0,false]
124 ustat << [0,false]
125 end
125 end
126 end
126 end
127 @scorearray << ustat
127 @scorearray << ustat
128 end
128 end
129 end
129 end
130
130
131 def import
131 def import
132 if params[:file]==''
132 if params[:file]==''
133 flash[:notice] = 'Error importing no file'
133 flash[:notice] = 'Error importing no file'
134 redirect_to :action => 'list' and return
134 redirect_to :action => 'list' and return
135 end
135 end
136 import_from_file(params[:file])
136 import_from_file(params[:file])
137 end
137 end
138
138
139 def random_all_passwords
139 def random_all_passwords
140 users = User.find(:all)
140 users = User.find(:all)
141 @prefix = params[:prefix] || ''
141 @prefix = params[:prefix] || ''
142 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
142 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
143 @changed = false
143 @changed = false
144 if request.request_method == :post
144 if request.request_method == :post
145 @non_admin_users.each do |user|
145 @non_admin_users.each do |user|
146 password = random_password
146 password = random_password
147 user.password = password
147 user.password = password
148 user.password_confirmation = password
148 user.password_confirmation = password
149 user.save
149 user.save
150 end
150 end
151 @changed = true
151 @changed = true
152 end
152 end
153 end
153 end
154
154
155 # contest management
155 # contest management
156
156
157 def add_to_contest
157 def add_to_contest
158 user = User.find(params[:id])
158 user = User.find(params[:id])
159 contest = Contest.find(params[:contest_id])
159 contest = Contest.find(params[:contest_id])
160 if user and contest
160 if user and contest
161 user.contests << contest
161 user.contests << contest
162 end
162 end
163 redirect_to :action => 'list'
163 redirect_to :action => 'list'
164 end
164 end
165
165
166 def remove_from_contest
166 def remove_from_contest
167 user = User.find(params[:id])
167 user = User.find(params[:id])
168 contest = Contest.find(params[:contest_id])
168 contest = Contest.find(params[:contest_id])
169 if user and contest
169 if user and contest
170 user.contests.delete(contest)
170 user.contests.delete(contest)
171 end
171 end
172 redirect_to :action => 'list'
172 redirect_to :action => 'list'
173 end
173 end
174
174
175 def contest_management
175 def contest_management
176 end
176 end
177
177
178 def manage_contest
178 def manage_contest
179 contest = Contest.find(params[:contest][:id])
179 contest = Contest.find(params[:contest][:id])
180 if !contest
180 if !contest
181 flash[:notice] = 'You did not choose the contest.'
181 flash[:notice] = 'You did not choose the contest.'
182 redirect_to :action => 'contest_management' and return
182 redirect_to :action => 'contest_management' and return
183 end
183 end
184
184
185 operation = params[:operation]
185 operation = params[:operation]
186
186
187 if not ['add','remove','assign'].include? operation
187 if not ['add','remove','assign'].include? operation
188 flash[:notice] = 'You did not choose the operation to perform.'
188 flash[:notice] = 'You did not choose the operation to perform.'
189 redirect_to :action => 'contest_management' and return
189 redirect_to :action => 'contest_management' and return
190 end
190 end
191
191
192 lines = params[:login_list]
192 lines = params[:login_list]
193 if !lines or lines.blank?
193 if !lines or lines.blank?
194 flash[:notice] = 'You entered an empty list.'
194 flash[:notice] = 'You entered an empty list.'
195 redirect_to :action => 'contest_management' and return
195 redirect_to :action => 'contest_management' and return
196 end
196 end
197
197
198 note = []
198 note = []
199 - user_ids = {}
199 + users = []
200 lines.split("\n").each do |line|
200 lines.split("\n").each do |line|
201 user = User.find_by_login(line.chomp)
201 user = User.find_by_login(line.chomp)
202 if user
202 if user
203 if operation=='add'
203 if operation=='add'
204 if ! user.contests.include? contest
204 if ! user.contests.include? contest
205 user.contests << contest
205 user.contests << contest
206 end
206 end
207 elsif operation=='remove'
207 elsif operation=='remove'
208 user.contests.delete(contest)
208 user.contests.delete(contest)
209 else
209 else
210 user.contests = [contest]
210 user.contests = [contest]
211 end
211 end
212
212
213 - user.contest_stat.destroy if params[:reset_timer]
213 + if params[:reset_timer]
214 + user.contest_stat.forced_logout = true
215 + user.contest_stat.reset_timer_and_save
216 + end
214
217
215 note << user.login
218 note << user.login
216 - user_ids[user.id] = true
219 + users << user
217 end
220 end
218 end
221 end
219
222
220 if params[:reset_timer]
223 if params[:reset_timer]
221 - logout_users(user_ids)
224 + logout_users(users)
222 end
225 end
223
226
224 flash[:notice] = 'User(s) ' + note.join(', ') +
227 flash[:notice] = 'User(s) ' + note.join(', ') +
225 ' were successfully modified. '
228 ' were successfully modified. '
226 redirect_to :action => 'contest_management'
229 redirect_to :action => 'contest_management'
227 end
230 end
228
231
229 # admin management
232 # admin management
230
233
231 def admin
234 def admin
232 @admins = User.find(:all).find_all {|user| user.admin? }
235 @admins = User.find(:all).find_all {|user| user.admin? }
233 end
236 end
234
237
235 def grant_admin
238 def grant_admin
236 login = params[:login]
239 login = params[:login]
237 user = User.find_by_login(login)
240 user = User.find_by_login(login)
238 if user!=nil
241 if user!=nil
239 admin_role = Role.find_by_name('admin')
242 admin_role = Role.find_by_name('admin')
240 user.roles << admin_role
243 user.roles << admin_role
241 else
244 else
242 flash[:notice] = 'Unknown user'
245 flash[:notice] = 'Unknown user'
243 end
246 end
244 flash[:notice] = 'User added as admins'
247 flash[:notice] = 'User added as admins'
245 redirect_to :action => 'admin'
248 redirect_to :action => 'admin'
246 end
249 end
247
250
248 def revoke_admin
251 def revoke_admin
249 user = User.find(params[:id])
252 user = User.find(params[:id])
250 if user==nil
253 if user==nil
251 flash[:notice] = 'Unknown user'
254 flash[:notice] = 'Unknown user'
252 redirect_to :action => 'admin' and return
255 redirect_to :action => 'admin' and return
253 elsif user.login == 'root'
256 elsif user.login == 'root'
254 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
257 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
255 redirect_to :action => 'admin' and return
258 redirect_to :action => 'admin' and return
256 end
259 end
257
260
258 admin_role = Role.find_by_name('admin')
261 admin_role = Role.find_by_name('admin')
259 user.roles.delete(admin_role)
262 user.roles.delete(admin_role)
260 flash[:notice] = 'User permission revoked'
263 flash[:notice] = 'User permission revoked'
261 redirect_to :action => 'admin'
264 redirect_to :action => 'admin'
262 end
265 end
263
266
264 protected
267 protected
265
268
266 def random_password(length=5)
269 def random_password(length=5)
267 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
270 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
268 newpass = ""
271 newpass = ""
269 length.times { newpass << chars[rand(chars.size-1)] }
272 length.times { newpass << chars[rand(chars.size-1)] }
270 return newpass
273 return newpass
271 end
274 end
272
275
273 def import_from_file(f)
276 def import_from_file(f)
274 data_hash = YAML.load(f)
277 data_hash = YAML.load(f)
275 @import_log = ""
278 @import_log = ""
276
279
277 country_data = data_hash[:countries]
280 country_data = data_hash[:countries]
278 site_data = data_hash[:sites]
281 site_data = data_hash[:sites]
279 user_data = data_hash[:users]
282 user_data = data_hash[:users]
280
283
281 # import country
284 # import country
282 countries = {}
285 countries = {}
283 country_data.each_pair do |id,country|
286 country_data.each_pair do |id,country|
284 c = Country.find_by_name(country[:name])
287 c = Country.find_by_name(country[:name])
285 if c!=nil
288 if c!=nil
286 countries[id] = c
289 countries[id] = c
287 @import_log << "Found #{country[:name]}\n"
290 @import_log << "Found #{country[:name]}\n"
288 else
291 else
289 countries[id] = Country.new(:name => country[:name])
292 countries[id] = Country.new(:name => country[:name])
290 countries[id].save
293 countries[id].save
291 @import_log << "Created #{country[:name]}\n"
294 @import_log << "Created #{country[:name]}\n"
292 end
295 end
293 end
296 end
294
297
295 # import sites
298 # import sites
296 sites = {}
299 sites = {}
297 site_data.each_pair do |id,site|
300 site_data.each_pair do |id,site|
298 s = Site.find_by_name(site[:name])
301 s = Site.find_by_name(site[:name])
299 if s!=nil
302 if s!=nil
300 @import_log << "Found #{site[:name]}\n"
303 @import_log << "Found #{site[:name]}\n"
301 else
304 else
302 s = Site.new(:name => site[:name])
305 s = Site.new(:name => site[:name])
303 @import_log << "Created #{site[:name]}\n"
306 @import_log << "Created #{site[:name]}\n"
304 end
307 end
305 s.password = site[:password]
308 s.password = site[:password]
306 s.country = countries[site[:country_id]]
309 s.country = countries[site[:country_id]]
307 s.save
310 s.save
308 sites[id] = s
311 sites[id] = s
309 end
312 end
310
313
311 # import users
314 # import users
312 user_data.each_pair do |id,user|
315 user_data.each_pair do |id,user|
313 u = User.find_by_login(user[:login])
316 u = User.find_by_login(user[:login])
314 if u!=nil
317 if u!=nil
315 @import_log << "Found #{user[:login]}\n"
318 @import_log << "Found #{user[:login]}\n"
316 else
319 else
317 u = User.new(:login => user[:login])
320 u = User.new(:login => user[:login])
318 @import_log << "Created #{user[:login]}\n"
321 @import_log << "Created #{user[:login]}\n"
319 end
322 end
320 u.full_name = user[:name]
323 u.full_name = user[:name]
321 u.password = user[:password]
324 u.password = user[:password]
322 u.country = countries[user[:country_id]]
325 u.country = countries[user[:country_id]]
323 u.site = sites[user[:site_id]]
326 u.site = sites[user[:site_id]]
324 u.activated = true
327 u.activated = true
325 u.email = "empty-#{u.login}@none.com"
328 u.email = "empty-#{u.login}@none.com"
326 if not u.save
329 if not u.save
327 @import_log << "Errors\n"
330 @import_log << "Errors\n"
328 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
331 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
329 end
332 end
330 end
333 end
331
334
332 end
335 end
333
336
334 - def logout_users(user_ids)
337 + def logout_users(users)
335 - sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
338 + users.each do |user|
336 - sessions.each do |session|
339 + contest_stat = user.contest_stat(true)
337 - if user_ids.has_key? session.data[:user_id]
340 + if contest_stat and !contest_stat.forced_logout
338 - session.destroy
341 + contest_stat.forced_logout = true
342 + contest_stat.save
339 end
343 end
340 end
344 end
341 end
345 end
342
346
343 end
347 end
@@ -1,296 +1,296
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", :dependent => :destroy
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 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
24 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
25
25
26 named_scope :activated_users, :conditions => {:activated => true}
26 named_scope :activated_users, :conditions => {:activated => true}
27
27
28 validates_presence_of :login
28 validates_presence_of :login
29 validates_uniqueness_of :login
29 validates_uniqueness_of :login
30 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
30 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
31 validates_length_of :login, :within => 3..30
31 validates_length_of :login, :within => 3..30
32
32
33 validates_presence_of :full_name
33 validates_presence_of :full_name
34 validates_length_of :full_name, :minimum => 1
34 validates_length_of :full_name, :minimum => 1
35
35
36 validates_presence_of :password, :if => :password_required?
36 validates_presence_of :password, :if => :password_required?
37 validates_length_of :password, :within => 4..20, :if => :password_required?
37 validates_length_of :password, :within => 4..20, :if => :password_required?
38 validates_confirmation_of :password, :if => :password_required?
38 validates_confirmation_of :password, :if => :password_required?
39
39
40 validates_format_of :email,
40 validates_format_of :email,
41 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
41 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
42 :if => :email_validation?
42 :if => :email_validation?
43 validate :uniqueness_of_email_from_activated_users,
43 validate :uniqueness_of_email_from_activated_users,
44 :if => :email_validation?
44 :if => :email_validation?
45 validate :enough_time_interval_between_same_email_registrations,
45 validate :enough_time_interval_between_same_email_registrations,
46 :if => :email_validation?
46 :if => :email_validation?
47
47
48 # these are for ytopc
48 # these are for ytopc
49 # disable for now
49 # disable for now
50 #validates_presence_of :province
50 #validates_presence_of :province
51
51
52 attr_accessor :password
52 attr_accessor :password
53
53
54 before_save :encrypt_new_password
54 before_save :encrypt_new_password
55 before_save :assign_default_site
55 before_save :assign_default_site
56
56
57 def self.authenticate(login, password)
57 def self.authenticate(login, password)
58 user = find_by_login(login)
58 user = find_by_login(login)
59 return user if user && user.authenticated?(password)
59 return user if user && user.authenticated?(password)
60 end
60 end
61
61
62 def authenticated?(password)
62 def authenticated?(password)
63 if self.activated
63 if self.activated
64 hashed_password == User.encrypt(password,self.salt)
64 hashed_password == User.encrypt(password,self.salt)
65 else
65 else
66 false
66 false
67 end
67 end
68 end
68 end
69
69
70 def admin?
70 def admin?
71 self.roles.detect {|r| r.name == 'admin' }
71 self.roles.detect {|r| r.name == 'admin' }
72 end
72 end
73
73
74 def email_for_editing
74 def email_for_editing
75 if self.email==nil
75 if self.email==nil
76 "(unknown)"
76 "(unknown)"
77 elsif self.email==''
77 elsif self.email==''
78 "(blank)"
78 "(blank)"
79 else
79 else
80 self.email
80 self.email
81 end
81 end
82 end
82 end
83
83
84 def email_for_editing=(e)
84 def email_for_editing=(e)
85 self.email=e
85 self.email=e
86 end
86 end
87
87
88 def alias_for_editing
88 def alias_for_editing
89 if self.alias==nil
89 if self.alias==nil
90 "(unknown)"
90 "(unknown)"
91 elsif self.alias==''
91 elsif self.alias==''
92 "(blank)"
92 "(blank)"
93 else
93 else
94 self.alias
94 self.alias
95 end
95 end
96 end
96 end
97
97
98 def alias_for_editing=(e)
98 def alias_for_editing=(e)
99 self.alias=e
99 self.alias=e
100 end
100 end
101
101
102 def activation_key
102 def activation_key
103 if self.hashed_password==nil
103 if self.hashed_password==nil
104 encrypt_new_password
104 encrypt_new_password
105 end
105 end
106 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
106 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
107 end
107 end
108
108
109 def verify_activation_key(key)
109 def verify_activation_key(key)
110 key == activation_key
110 key == activation_key
111 end
111 end
112
112
113 def self.random_password(length=5)
113 def self.random_password(length=5)
114 chars = 'abcdefghjkmnopqrstuvwxyz'
114 chars = 'abcdefghjkmnopqrstuvwxyz'
115 password = ''
115 password = ''
116 length.times { password << chars[rand(chars.length - 1)] }
116 length.times { password << chars[rand(chars.length - 1)] }
117 password
117 password
118 end
118 end
119
119
120 def self.find_non_admin_with_prefix(prefix='')
120 def self.find_non_admin_with_prefix(prefix='')
121 users = User.find(:all)
121 users = User.find(:all)
122 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
122 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
123 end
123 end
124
124
125 # Contest information
125 # Contest information
126
126
127 def contest_time_left
127 def contest_time_left
128 if Configuration.contest_mode?
128 if Configuration.contest_mode?
129 return nil if site==nil
129 return nil if site==nil
130 return site.time_left
130 return site.time_left
131 elsif Configuration.indv_contest_mode?
131 elsif Configuration.indv_contest_mode?
132 time_limit = Configuration.contest_time_limit
132 time_limit = Configuration.contest_time_limit
133 if time_limit == nil
133 if time_limit == nil
134 return nil
134 return nil
135 end
135 end
136 - if contest_stat==nil
136 + if contest_stat==nil or contest_stat.started_at==nil
137 return (Time.now.gmtime + time_limit) - Time.now.gmtime
137 return (Time.now.gmtime + time_limit) - Time.now.gmtime
138 else
138 else
139 finish_time = contest_stat.started_at + time_limit
139 finish_time = contest_stat.started_at + time_limit
140 current_time = Time.now.gmtime
140 current_time = Time.now.gmtime
141 if current_time > finish_time
141 if current_time > finish_time
142 return 0
142 return 0
143 else
143 else
144 return finish_time - current_time
144 return finish_time - current_time
145 end
145 end
146 end
146 end
147 else
147 else
148 return nil
148 return nil
149 end
149 end
150 end
150 end
151
151
152 def contest_finished?
152 def contest_finished?
153 if Configuration.contest_mode?
153 if Configuration.contest_mode?
154 return false if site==nil
154 return false if site==nil
155 return site.finished?
155 return site.finished?
156 elsif Configuration.indv_contest_mode?
156 elsif Configuration.indv_contest_mode?
157 return false if self.contest_stat(true)==nil
157 return false if self.contest_stat(true)==nil
158 return contest_time_left == 0
158 return contest_time_left == 0
159 else
159 else
160 return false
160 return false
161 end
161 end
162 end
162 end
163
163
164 def contest_started?
164 def contest_started?
165 if Configuration.contest_mode?
165 if Configuration.contest_mode?
166 return true if site==nil
166 return true if site==nil
167 return site.started
167 return site.started
168 else
168 else
169 return true
169 return true
170 end
170 end
171 end
171 end
172
172
173 def update_start_time
173 def update_start_time
174 stat = self.contest_stat
174 stat = self.contest_stat
175 - if stat == nil
175 + if stat == nil or stat.started_at == nil
176 - stat = UserContestStat.new(:user => self,
176 + stat ||= UserContestStat.new(:user => self)
177 - :started_at => Time.now.gmtime)
177 + stat.started_at = Time.now.gmtime
178 stat.save
178 stat.save
179 end
179 end
180 end
180 end
181
181
182 def problem_in_user_contests?(problem)
182 def problem_in_user_contests?(problem)
183 problem_contests = problem.contests.all
183 problem_contests = problem.contests.all
184
184
185 if problem_contests.length == 0 # this is public contest
185 if problem_contests.length == 0 # this is public contest
186 return true
186 return true
187 end
187 end
188
188
189 contests.each do |contest|
189 contests.each do |contest|
190 if problem_contests.find {|c| c.id == contest.id }
190 if problem_contests.find {|c| c.id == contest.id }
191 return true
191 return true
192 end
192 end
193 end
193 end
194 return false
194 return false
195 end
195 end
196
196
197 def available_problems_group_by_contests
197 def available_problems_group_by_contests
198 contest_problems = []
198 contest_problems = []
199 pin = {}
199 pin = {}
200 contests.enabled.each do |contest|
200 contests.enabled.each do |contest|
201 available_problems = contest.problems.available
201 available_problems = contest.problems.available
202 contest_problems << {
202 contest_problems << {
203 :contest => contest,
203 :contest => contest,
204 :problems => available_problems
204 :problems => available_problems
205 }
205 }
206 available_problems.each {|p| pin[p.id] = true}
206 available_problems.each {|p| pin[p.id] = true}
207 end
207 end
208 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
208 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
209 contest_problems << {
209 contest_problems << {
210 :contest => nil,
210 :contest => nil,
211 :problems => other_avaiable_problems
211 :problems => other_avaiable_problems
212 }
212 }
213 return contest_problems
213 return contest_problems
214 end
214 end
215
215
216 def available_problems
216 def available_problems
217 if not Configuration.multicontests?
217 if not Configuration.multicontests?
218 return Problem.find_available_problems
218 return Problem.find_available_problems
219 else
219 else
220 contest_problems = []
220 contest_problems = []
221 pin = {}
221 pin = {}
222 contests.enabled.each do |contest|
222 contests.enabled.each do |contest|
223 contest.problems.available.each do |problem|
223 contest.problems.available.each do |problem|
224 if not pin.has_key? problem.id
224 if not pin.has_key? problem.id
225 contest_problems << problem
225 contest_problems << problem
226 end
226 end
227 pin[problem.id] = true
227 pin[problem.id] = true
228 end
228 end
229 end
229 end
230 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
230 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
231 return contest_problems + other_avaiable_problems
231 return contest_problems + other_avaiable_problems
232 end
232 end
233 end
233 end
234
234
235 def can_view_problem?(problem)
235 def can_view_problem?(problem)
236 if not Configuration.multicontests?
236 if not Configuration.multicontests?
237 return problem.available
237 return problem.available
238 else
238 else
239 return problem_in_user_contests? problem
239 return problem_in_user_contests? problem
240 end
240 end
241 end
241 end
242
242
243 protected
243 protected
244 def encrypt_new_password
244 def encrypt_new_password
245 return if password.blank?
245 return if password.blank?
246 self.salt = (10+rand(90)).to_s
246 self.salt = (10+rand(90)).to_s
247 self.hashed_password = User.encrypt(self.password,self.salt)
247 self.hashed_password = User.encrypt(self.password,self.salt)
248 end
248 end
249
249
250 def assign_default_site
250 def assign_default_site
251 # have to catch error when migrating (because self.site is not available).
251 # have to catch error when migrating (because self.site is not available).
252 begin
252 begin
253 if self.site==nil
253 if self.site==nil
254 self.site = Site.find_by_name('default')
254 self.site = Site.find_by_name('default')
255 if self.site==nil
255 if self.site==nil
256 self.site = Site.find(1) # when 'default has be renamed'
256 self.site = Site.find(1) # when 'default has be renamed'
257 end
257 end
258 end
258 end
259 rescue
259 rescue
260 end
260 end
261 end
261 end
262
262
263 def password_required?
263 def password_required?
264 self.hashed_password.blank? || !self.password.blank?
264 self.hashed_password.blank? || !self.password.blank?
265 end
265 end
266
266
267 def self.encrypt(string,salt)
267 def self.encrypt(string,salt)
268 Digest::SHA1.hexdigest(salt + string)
268 Digest::SHA1.hexdigest(salt + string)
269 end
269 end
270
270
271 def uniqueness_of_email_from_activated_users
271 def uniqueness_of_email_from_activated_users
272 user = User.activated_users.find_by_email(self.email)
272 user = User.activated_users.find_by_email(self.email)
273 if user and (user.login != self.login)
273 if user and (user.login != self.login)
274 self.errors.add_to_base("Email has already been taken")
274 self.errors.add_to_base("Email has already been taken")
275 end
275 end
276 end
276 end
277
277
278 def enough_time_interval_between_same_email_registrations
278 def enough_time_interval_between_same_email_registrations
279 return if !self.new_record?
279 return if !self.new_record?
280 return if self.activated
280 return if self.activated
281 open_user = User.find_by_email(self.email,
281 open_user = User.find_by_email(self.email,
282 :order => 'created_at DESC')
282 :order => 'created_at DESC')
283 if open_user and open_user.created_at and
283 if open_user and open_user.created_at and
284 (open_user.created_at > Time.now.gmtime - 5.minutes)
284 (open_user.created_at > Time.now.gmtime - 5.minutes)
285 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
285 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
286 end
286 end
287 end
287 end
288
288
289 def email_validation?
289 def email_validation?
290 begin
290 begin
291 return VALIDATE_USER_EMAILS
291 return VALIDATE_USER_EMAILS
292 rescue
292 rescue
293 return false
293 return false
294 end
294 end
295 end
295 end
296 end
296 end
@@ -1,5 +1,10
1 class UserContestStat < ActiveRecord::Base
1 class UserContestStat < ActiveRecord::Base
2
2
3 belongs_to :user
3 belongs_to :user
4
4
5 + def reset_timer_and_save
6 + self.started_at = nil
7 + save
8 + end
9 +
5 end
10 end
@@ -1,231 +1,232
1 # This file is auto-generated from the current state of the database. Instead of editing this file,
1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 # please use the migrations feature of Active Record to incrementally modify your database, and
2 # please use the migrations feature of Active Record to incrementally modify your database, and
3 # then regenerate this schema definition.
3 # then regenerate this schema definition.
4 #
4 #
5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 # to create the application database on another system, you should be using db:schema:load, not running
6 # to create the application database on another system, you should be using db:schema:load, not running
7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 # you'll amass, the slower it'll run and the greater likelihood for issues).
8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 #
9 #
10 # It's strongly recommended to check this file into your version control system.
10 # It's strongly recommended to check this file into your version control system.
11
11
12 - ActiveRecord::Schema.define(:version => 20100303095700) do
12 + ActiveRecord::Schema.define(:version => 20100328123325) do
13
13
14 create_table "announcements", :force => true do |t|
14 create_table "announcements", :force => true do |t|
15 t.string "author"
15 t.string "author"
16 t.text "body"
16 t.text "body"
17 t.boolean "published"
17 t.boolean "published"
18 t.datetime "created_at"
18 t.datetime "created_at"
19 t.datetime "updated_at"
19 t.datetime "updated_at"
20 t.boolean "frontpage", :default => false
20 t.boolean "frontpage", :default => false
21 t.boolean "contest_only", :default => false
21 t.boolean "contest_only", :default => false
22 t.string "title"
22 t.string "title"
23 end
23 end
24
24
25 create_table "configurations", :force => true do |t|
25 create_table "configurations", :force => true do |t|
26 t.string "key"
26 t.string "key"
27 t.string "value_type"
27 t.string "value_type"
28 t.string "value"
28 t.string "value"
29 t.datetime "created_at"
29 t.datetime "created_at"
30 t.datetime "updated_at"
30 t.datetime "updated_at"
31 t.text "description"
31 t.text "description"
32 end
32 end
33
33
34 create_table "contests", :force => true do |t|
34 create_table "contests", :force => true do |t|
35 t.string "title"
35 t.string "title"
36 t.boolean "enabled"
36 t.boolean "enabled"
37 t.datetime "created_at"
37 t.datetime "created_at"
38 t.datetime "updated_at"
38 t.datetime "updated_at"
39 t.string "name"
39 t.string "name"
40 end
40 end
41
41
42 create_table "contests_problems", :id => false, :force => true do |t|
42 create_table "contests_problems", :id => false, :force => true do |t|
43 t.integer "contest_id"
43 t.integer "contest_id"
44 t.integer "problem_id"
44 t.integer "problem_id"
45 end
45 end
46
46
47 create_table "contests_users", :id => false, :force => true do |t|
47 create_table "contests_users", :id => false, :force => true do |t|
48 t.integer "contest_id"
48 t.integer "contest_id"
49 t.integer "user_id"
49 t.integer "user_id"
50 end
50 end
51
51
52 create_table "countries", :force => true do |t|
52 create_table "countries", :force => true do |t|
53 t.string "name"
53 t.string "name"
54 t.datetime "created_at"
54 t.datetime "created_at"
55 t.datetime "updated_at"
55 t.datetime "updated_at"
56 end
56 end
57
57
58 create_table "descriptions", :force => true do |t|
58 create_table "descriptions", :force => true do |t|
59 t.text "body"
59 t.text "body"
60 t.boolean "markdowned"
60 t.boolean "markdowned"
61 t.datetime "created_at"
61 t.datetime "created_at"
62 t.datetime "updated_at"
62 t.datetime "updated_at"
63 end
63 end
64
64
65 create_table "grader_processes", :force => true do |t|
65 create_table "grader_processes", :force => true do |t|
66 t.string "host", :limit => 20
66 t.string "host", :limit => 20
67 t.integer "pid"
67 t.integer "pid"
68 t.string "mode"
68 t.string "mode"
69 t.boolean "active"
69 t.boolean "active"
70 t.datetime "created_at"
70 t.datetime "created_at"
71 t.datetime "updated_at"
71 t.datetime "updated_at"
72 t.integer "task_id"
72 t.integer "task_id"
73 t.string "task_type"
73 t.string "task_type"
74 t.boolean "terminated"
74 t.boolean "terminated"
75 end
75 end
76
76
77 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
77 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
78
78
79 create_table "languages", :force => true do |t|
79 create_table "languages", :force => true do |t|
80 t.string "name", :limit => 10
80 t.string "name", :limit => 10
81 t.string "pretty_name"
81 t.string "pretty_name"
82 t.string "ext", :limit => 10
82 t.string "ext", :limit => 10
83 t.string "common_ext"
83 t.string "common_ext"
84 end
84 end
85
85
86 create_table "messages", :force => true do |t|
86 create_table "messages", :force => true do |t|
87 t.integer "sender_id"
87 t.integer "sender_id"
88 t.integer "receiver_id"
88 t.integer "receiver_id"
89 t.integer "replying_message_id"
89 t.integer "replying_message_id"
90 t.text "body"
90 t.text "body"
91 t.boolean "replied"
91 t.boolean "replied"
92 t.datetime "created_at"
92 t.datetime "created_at"
93 t.datetime "updated_at"
93 t.datetime "updated_at"
94 end
94 end
95
95
96 create_table "problems", :force => true do |t|
96 create_table "problems", :force => true do |t|
97 t.string "name", :limit => 30
97 t.string "name", :limit => 30
98 t.string "full_name"
98 t.string "full_name"
99 t.integer "full_score"
99 t.integer "full_score"
100 t.date "date_added"
100 t.date "date_added"
101 t.boolean "available"
101 t.boolean "available"
102 t.string "url"
102 t.string "url"
103 t.integer "description_id"
103 t.integer "description_id"
104 t.boolean "test_allowed"
104 t.boolean "test_allowed"
105 t.boolean "output_only"
105 t.boolean "output_only"
106 t.string "description_filename"
106 t.string "description_filename"
107 end
107 end
108
108
109 create_table "rights", :force => true do |t|
109 create_table "rights", :force => true do |t|
110 t.string "name"
110 t.string "name"
111 t.string "controller"
111 t.string "controller"
112 t.string "action"
112 t.string "action"
113 end
113 end
114
114
115 create_table "rights_roles", :id => false, :force => true do |t|
115 create_table "rights_roles", :id => false, :force => true do |t|
116 t.integer "right_id"
116 t.integer "right_id"
117 t.integer "role_id"
117 t.integer "role_id"
118 end
118 end
119
119
120 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
120 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
121
121
122 create_table "roles", :force => true do |t|
122 create_table "roles", :force => true do |t|
123 t.string "name"
123 t.string "name"
124 end
124 end
125
125
126 create_table "roles_users", :id => false, :force => true do |t|
126 create_table "roles_users", :id => false, :force => true do |t|
127 t.integer "role_id"
127 t.integer "role_id"
128 t.integer "user_id"
128 t.integer "user_id"
129 end
129 end
130
130
131 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
131 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
132
132
133 create_table "sessions", :force => true do |t|
133 create_table "sessions", :force => true do |t|
134 t.string "session_id"
134 t.string "session_id"
135 t.text "data"
135 t.text "data"
136 t.datetime "updated_at"
136 t.datetime "updated_at"
137 end
137 end
138
138
139 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
139 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
140 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
140 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
141
141
142 create_table "sites", :force => true do |t|
142 create_table "sites", :force => true do |t|
143 t.string "name"
143 t.string "name"
144 t.boolean "started"
144 t.boolean "started"
145 t.datetime "start_time"
145 t.datetime "start_time"
146 t.datetime "created_at"
146 t.datetime "created_at"
147 t.datetime "updated_at"
147 t.datetime "updated_at"
148 t.integer "country_id"
148 t.integer "country_id"
149 t.string "password"
149 t.string "password"
150 end
150 end
151
151
152 create_table "submissions", :force => true do |t|
152 create_table "submissions", :force => true do |t|
153 t.integer "user_id"
153 t.integer "user_id"
154 t.integer "problem_id"
154 t.integer "problem_id"
155 t.integer "language_id"
155 t.integer "language_id"
156 t.text "source"
156 t.text "source"
157 t.binary "binary"
157 t.binary "binary"
158 t.datetime "submitted_at"
158 t.datetime "submitted_at"
159 t.datetime "compiled_at"
159 t.datetime "compiled_at"
160 t.text "compiler_message"
160 t.text "compiler_message"
161 t.datetime "graded_at"
161 t.datetime "graded_at"
162 t.integer "points"
162 t.integer "points"
163 t.text "grader_comment"
163 t.text "grader_comment"
164 t.integer "number"
164 t.integer "number"
165 t.string "source_filename"
165 t.string "source_filename"
166 end
166 end
167
167
168 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
168 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
169 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
169 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
170
170
171 create_table "tasks", :force => true do |t|
171 create_table "tasks", :force => true do |t|
172 t.integer "submission_id"
172 t.integer "submission_id"
173 t.datetime "created_at"
173 t.datetime "created_at"
174 t.integer "status"
174 t.integer "status"
175 t.datetime "updated_at"
175 t.datetime "updated_at"
176 end
176 end
177
177
178 create_table "test_pairs", :force => true do |t|
178 create_table "test_pairs", :force => true do |t|
179 t.integer "problem_id"
179 t.integer "problem_id"
180 t.text "input", :limit => 16777215
180 t.text "input", :limit => 16777215
181 t.text "solution", :limit => 16777215
181 t.text "solution", :limit => 16777215
182 t.datetime "created_at"
182 t.datetime "created_at"
183 t.datetime "updated_at"
183 t.datetime "updated_at"
184 end
184 end
185
185
186 create_table "test_requests", :force => true do |t|
186 create_table "test_requests", :force => true do |t|
187 t.integer "user_id"
187 t.integer "user_id"
188 t.integer "problem_id"
188 t.integer "problem_id"
189 t.integer "submission_id"
189 t.integer "submission_id"
190 t.string "input_file_name"
190 t.string "input_file_name"
191 t.string "output_file_name"
191 t.string "output_file_name"
192 t.string "running_stat"
192 t.string "running_stat"
193 t.integer "status"
193 t.integer "status"
194 t.datetime "updated_at"
194 t.datetime "updated_at"
195 t.datetime "submitted_at"
195 t.datetime "submitted_at"
196 t.datetime "compiled_at"
196 t.datetime "compiled_at"
197 t.text "compiler_message"
197 t.text "compiler_message"
198 t.datetime "graded_at"
198 t.datetime "graded_at"
199 t.string "grader_comment"
199 t.string "grader_comment"
200 t.datetime "created_at"
200 t.datetime "created_at"
201 t.float "running_time"
201 t.float "running_time"
202 t.string "exit_status"
202 t.string "exit_status"
203 t.integer "memory_usage"
203 t.integer "memory_usage"
204 end
204 end
205
205
206 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
206 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
207
207
208 create_table "user_contest_stats", :force => true do |t|
208 create_table "user_contest_stats", :force => true do |t|
209 t.integer "user_id"
209 t.integer "user_id"
210 t.datetime "started_at"
210 t.datetime "started_at"
211 t.datetime "created_at"
211 t.datetime "created_at"
212 t.datetime "updated_at"
212 t.datetime "updated_at"
213 + t.boolean "forced_logout"
213 end
214 end
214
215
215 create_table "users", :force => true do |t|
216 create_table "users", :force => true do |t|
216 t.string "login", :limit => 50
217 t.string "login", :limit => 50
217 t.string "full_name"
218 t.string "full_name"
218 t.string "hashed_password"
219 t.string "hashed_password"
219 t.string "salt", :limit => 5
220 t.string "salt", :limit => 5
220 t.string "alias"
221 t.string "alias"
221 t.string "email"
222 t.string "email"
222 t.integer "site_id"
223 t.integer "site_id"
223 t.integer "country_id"
224 t.integer "country_id"
224 t.boolean "activated", :default => false
225 t.boolean "activated", :default => false
225 t.datetime "created_at"
226 t.datetime "created_at"
226 t.datetime "updated_at"
227 t.datetime "updated_at"
227 end
228 end
228
229
229 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
230 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
230
231
231 end
232 end
@@ -1,40 +1,41
1
1
2 var Announcement = {
2 var Announcement = {
3
3
4 mostRecentId: 0,
4 mostRecentId: 0,
5
5
6 refreshUrl: '/main/announcements',
6 refreshUrl: '/main/announcements',
7
7
8 setMostRecentId: function(id) {
8 setMostRecentId: function(id) {
9 Announcement.mostRecentId = id;
9 Announcement.mostRecentId = id;
10 },
10 },
11
11
12 updateRecentId: function(id) {
12 updateRecentId: function(id) {
13 if(Announcement.mostRecentId < id)
13 if(Announcement.mostRecentId < id)
14 Announcement.mostRecentId = id;
14 Announcement.mostRecentId = id;
15 },
15 },
16
16
17 refreshAnnouncement: function() {
17 refreshAnnouncement: function() {
18 var url = Announcement.refreshUrl;
18 var url = Announcement.refreshUrl;
19 new Ajax.Request(url, {
19 new Ajax.Request(url, {
20 method: 'get',
20 method: 'get',
21 parameters: { recent: Announcement.mostRecentId },
21 parameters: { recent: Announcement.mostRecentId },
22 onSuccess: function(transport) {
22 onSuccess: function(transport) {
23 - if(transport.responseText.match(/\S/)!=null) {
23 + if((transport.status == 200) &&
24 + (transport.responseText.match(/\S/)!=null)) {
24 var announcementBody = $("announcementbox-body");
25 var announcementBody = $("announcementbox-body");
25 announcementBody.insert({ top: transport.responseText });
26 announcementBody.insert({ top: transport.responseText });
26 var announcementBoxes = $$(".announcementbox");
27 var announcementBoxes = $$(".announcementbox");
27 if(announcementBoxes.length!=0)
28 if(announcementBoxes.length!=0)
28 announcementBoxes[0].show();
29 announcementBoxes[0].show();
30 + Announcement.registerRefreshEventTimer();
29 }
31 }
30 }
32 }
31 });
33 });
32 - Announcement.registerRefreshEventTimer();
33 },
34 },
34
35
35 registerRefreshEventTimer: function() {
36 registerRefreshEventTimer: function() {
36 setTimeout(function () {
37 setTimeout(function () {
37 Announcement.refreshAnnouncement();
38 Announcement.refreshAnnouncement();
38 }, 30000);
39 }, 30000);
39 }
40 }
40 };
41 };
@@ -1,87 +1,117
1 require 'spec_helper'
1 require 'spec_helper'
2 require 'config_spec_helper'
2 require 'config_spec_helper'
3 require 'delorean'
3 require 'delorean'
4
4
5 describe "ContestManagements" do
5 describe "ContestManagements" do
6 include ConfigSpecHelperMethods
6 include ConfigSpecHelperMethods
7
7
8 fixtures :users
8 fixtures :users
9 fixtures :problems
9 fixtures :problems
10 fixtures :contests
10 fixtures :contests
11 fixtures :roles
11 fixtures :roles
12
12
13 before(:each) do
13 before(:each) do
14 @admin_user = users(:mary)
14 @admin_user = users(:mary)
15 @contest_b = contests(:contest_b)
15 @contest_b = contests(:contest_b)
16 @james = users(:james)
16 @james = users(:james)
17 @jack = users(:jack)
17 @jack = users(:jack)
18
18
19 set_contest_time_limit('3:00')
19 set_contest_time_limit('3:00')
20 set_indv_contest_mode
20 set_indv_contest_mode
21 + enable_multicontest
21 end
22 end
22
23
23 it "should reset users' timer when their contests change" do
24 it "should reset users' timer when their contests change" do
24 james_session = open_session
25 james_session = open_session
25 james_session.extend(MainSessionMethods)
26 james_session.extend(MainSessionMethods)
26
27
27 james_login_and_get_main_list(james_session)
28 james_login_and_get_main_list(james_session)
28 james_session.response.should_not have_text(/OVER/)
29 james_session.response.should_not have_text(/OVER/)
29
30
30 Delorean.time_travel_to(190.minutes.since) do
31 Delorean.time_travel_to(190.minutes.since) do
31 james_session.get_main_list
32 james_session.get_main_list
32 james_session.response.should have_text(/OVER/)
33 james_session.response.should have_text(/OVER/)
33
34
34 james_session.get '/' # logout
35 james_session.get '/' # logout
35 james_session.get '/main/list' # clearly log out
36 james_session.get '/main/list' # clearly log out
36 james_session.response.should_not render_template 'main/list'
37 james_session.response.should_not render_template 'main/list'
37
38
38 admin_change_users_contest_to("james", @contest_b, true)
39 admin_change_users_contest_to("james", @contest_b, true)
39
40
40 james_login_and_get_main_list(james_session)
41 james_login_and_get_main_list(james_session)
41 james_session.response.should_not have_text(/OVER/)
42 james_session.response.should_not have_text(/OVER/)
42 end
43 end
43 end
44 end
44
45
46 + it "should force users to log out when their contests change" do
47 + james_session = open_session
48 + james_session.extend(MainSessionMethods)
49 +
50 + james_login_and_get_main_list(james_session)
51 + james_session.response.should_not have_text(/OVER/)
52 +
53 + Delorean.time_travel_to(190.minutes.since) do
54 + james_session.get_main_list
55 + james_session.response.should have_text(/OVER/)
56 +
57 + admin_change_users_contest_to("james", @contest_b, true)
58 +
59 + james_session.get '/main/list'
60 + james_session.response.should_not render_template 'main/list'
61 + james_session.should be_redirect
62 +
63 + Delorean.time_travel_to(200.minutes.since) do
64 + james_login_and_get_main_list(james_session)
65 + james_session.response.should_not have_text(/OVER/)
66 + end
67 + end
68 + end
69 +
45 private
70 private
46
71
47 module MainSessionMethods
72 module MainSessionMethods
48 def login(login_name, password)
73 def login(login_name, password)
49 post '/login/login', :login => login_name, :password => password
74 post '/login/login', :login => login_name, :password => password
50 assert_redirected_to '/main/list'
75 assert_redirected_to '/main/list'
51 end
76 end
52
77
53 def get_main_list
78 def get_main_list
54 get '/main/list'
79 get '/main/list'
55 assert_template 'main/list'
80 assert_template 'main/list'
56 end
81 end
82 +
83 + def get_main_list_and_assert_logout
84 + get '/main/list'
85 + assert_redirected_to '/main'
86 + end
57 end
87 end
58
88
59 module ContestManagementSessionMethods
89 module ContestManagementSessionMethods
60 def change_users_contest_to(user_login_list, contest, reset_timer=false)
90 def change_users_contest_to(user_login_list, contest, reset_timer=false)
61 post_data = {
91 post_data = {
62 :contest => {:id => contest.id},
92 :contest => {:id => contest.id},
63 :operation => 'assign',
93 :operation => 'assign',
64 :login_list => user_login_list
94 :login_list => user_login_list
65 }
95 }
66 post_data[:reset_timer] = true if reset_timer
96 post_data[:reset_timer] = true if reset_timer
67 post '/user_admin/manage_contest', post_data
97 post '/user_admin/manage_contest', post_data
68 end
98 end
69 end
99 end
70
100
71 def admin_change_users_contest_to(user_list, contest, reset_timer)
101 def admin_change_users_contest_to(user_list, contest, reset_timer)
72 admin_session = open_session
102 admin_session = open_session
73 admin_session.extend(MainSessionMethods)
103 admin_session.extend(MainSessionMethods)
74 admin_session.extend(ContestManagementSessionMethods)
104 admin_session.extend(ContestManagementSessionMethods)
75
105
76 admin_session.login('mary','goodbye')
106 admin_session.login('mary','goodbye')
77 admin_session.get '/main/list'
107 admin_session.get '/main/list'
78 admin_session.change_users_contest_to(user_list, contest, reset_timer)
108 admin_session.change_users_contest_to(user_list, contest, reset_timer)
79 end
109 end
80
110
81 def james_login_and_get_main_list(session)
111 def james_login_and_get_main_list(session)
82 session.login('james', 'morning')
112 session.login('james', 'morning')
83 session.get_main_list
113 session.get_main_list
84 end
114 end
85
115
86 end
116 end
87
117
You need to be logged in to leave comments. Login now