Description:
logs out users after contests changed
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r294:069c049fbc3a - - 22 files changed: 191 inserted, 192 deleted

@@ -0,0 +1,87
1 + require 'spec_helper'
2 + require 'config_spec_helper'
3 + require 'delorean'
4 +
5 + describe "ContestManagements" do
6 + include ConfigSpecHelperMethods
7 +
8 + fixtures :users
9 + fixtures :problems
10 + fixtures :contests
11 + fixtures :roles
12 +
13 + before(:each) do
14 + @admin_user = users(:mary)
15 + @contest_b = contests(:contest_b)
16 + @james = users(:james)
17 + @jack = users(:jack)
18 +
19 + set_contest_time_limit('3:00')
20 + set_indv_contest_mode
21 + end
22 +
23 + it "should reset users' timer when their contests change" do
24 + james_session = open_session
25 + james_session.extend(MainSessionMethods)
26 +
27 + james_login_and_get_main_list(james_session)
28 + james_session.response.should_not have_text(/OVER/)
29 +
30 + Delorean.time_travel_to(190.minutes.since) do
31 + james_session.get_main_list
32 + james_session.response.should have_text(/OVER/)
33 +
34 + james_session.get '/' # logout
35 + james_session.get '/main/list' # clearly log out
36 + james_session.response.should_not render_template 'main/list'
37 +
38 + admin_change_users_contest_to("james", @contest_b, true)
39 +
40 + james_login_and_get_main_list(james_session)
41 + james_session.response.should_not have_text(/OVER/)
42 + end
43 + end
44 +
45 + private
46 +
47 + module MainSessionMethods
48 + def login(login_name, password)
49 + post '/login/login', :login => login_name, :password => password
50 + assert_redirected_to '/main/list'
51 + end
52 +
53 + def get_main_list
54 + get '/main/list'
55 + assert_template 'main/list'
56 + end
57 + end
58 +
59 + module ContestManagementSessionMethods
60 + def change_users_contest_to(user_login_list, contest, reset_timer=false)
61 + post_data = {
62 + :contest => {:id => contest.id},
63 + :operation => 'assign',
64 + :login_list => user_login_list
65 + }
66 + post_data[:reset_timer] = true if reset_timer
67 + post '/user_admin/manage_contest', post_data
68 + end
69 + end
70 +
71 + def admin_change_users_contest_to(user_list, contest, reset_timer)
72 + admin_session = open_session
73 + admin_session.extend(MainSessionMethods)
74 + admin_session.extend(ContestManagementSessionMethods)
75 +
76 + admin_session.login('mary','goodbye')
77 + admin_session.get '/main/list'
78 + admin_session.change_users_contest_to(user_list, contest, reset_timer)
79 + end
80 +
81 + def james_login_and_get_main_list(session)
82 + session.login('james', 'morning')
83 + session.get_main_list
84 + end
85 +
86 + end
87 +
@@ -187,42 +187,49
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 lines.split("\n").each do |line|
200 lines.split("\n").each do |line|
200 - puts line
201 user = User.find_by_login(line.chomp)
201 user = User.find_by_login(line.chomp)
202 - puts user
203 if user
202 if user
204 if operation=='add'
203 if operation=='add'
205 - user.contests << contest
204 + if ! user.contests.include? contest
205 + user.contests << contest
206 + end
206 elsif operation=='remove'
207 elsif operation=='remove'
207 user.contests.delete(contest)
208 user.contests.delete(contest)
208 else
209 else
209 user.contests = [contest]
210 user.contests = [contest]
210 end
211 end
211 -
212 +
212 user.contest_stat.destroy if params[:reset_timer]
213 user.contest_stat.destroy if params[:reset_timer]
213
214
214 note << user.login
215 note << user.login
216 + user_ids[user.id] = true
215 end
217 end
216 end
218 end
219 +
220 + if params[:reset_timer]
221 + logout_users(user_ids)
222 + end
223 +
217 flash[:notice] = 'User(s) ' + note.join(', ') +
224 flash[:notice] = 'User(s) ' + note.join(', ') +
218 ' were successfully modified. '
225 ' were successfully modified. '
219 redirect_to :action => 'contest_management'
226 redirect_to :action => 'contest_management'
220 end
227 end
221
228
222 # admin management
229 # admin management
223
230
224 def admin
231 def admin
225 @admins = User.find(:all).find_all {|user| user.admin? }
232 @admins = User.find(:all).find_all {|user| user.admin? }
226 end
233 end
227
234
228 def grant_admin
235 def grant_admin
@@ -315,13 +322,22
315 u.country = countries[user[:country_id]]
322 u.country = countries[user[:country_id]]
316 u.site = sites[user[:site_id]]
323 u.site = sites[user[:site_id]]
317 u.activated = true
324 u.activated = true
318 u.email = "empty-#{u.login}@none.com"
325 u.email = "empty-#{u.login}@none.com"
319 if not u.save
326 if not u.save
320 @import_log << "Errors\n"
327 @import_log << "Errors\n"
321 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
328 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
322 end
329 end
323 end
330 end
324
331
325 end
332 end
326
333
334 + def logout_users(user_ids)
335 + sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
336 + sessions.each do |session|
337 + if user_ids.has_key? session.data[:user_id]
338 + session.destroy
339 + end
340 + end
341 + end
342 +
327 end
343 end
@@ -1,21 +1,23
1 require 'yaml'
1 require 'yaml'
2
2
3 #
3 #
4 # This class also contains various login of the system.
4 # This class also contains various login of the system.
5 #
5 #
6 class Configuration < ActiveRecord::Base
6 class Configuration < ActiveRecord::Base
7
7
8 SYSTEM_MODE_CONF_KEY = 'system.mode'
8 SYSTEM_MODE_CONF_KEY = 'system.mode'
9 TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
9 TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
10 + MULTICONTESTS_KEY = 'system.multicontests'
11 + CONTEST_TIME_LIMIT_KEY = 'contest.time_limit'
10
12
11 cattr_accessor :cache
13 cattr_accessor :cache
12 cattr_accessor :config_cache
14 cattr_accessor :config_cache
13 cattr_accessor :task_grading_info_cache
15 cattr_accessor :task_grading_info_cache
14 cattr_accessor :contest_time_str
16 cattr_accessor :contest_time_str
15 cattr_accessor :contest_time
17 cattr_accessor :contest_time
16
18
17 # set @@cache = true to only reload once.
19 # set @@cache = true to only reload once.
18 Configuration.cache = false
20 Configuration.cache = false
19
21
20 Configuration.config_cache = nil
22 Configuration.config_cache = nil
21 Configuration.task_grading_info_cache = nil
23 Configuration.task_grading_info_cache = nil
@@ -98,39 +100,38
98 return get(SYSTEM_MODE_CONF_KEY) == 'standard'
100 return get(SYSTEM_MODE_CONF_KEY) == 'standard'
99 end
101 end
100
102
101 def self.contest_mode?
103 def self.contest_mode?
102 return get(SYSTEM_MODE_CONF_KEY) == 'contest'
104 return get(SYSTEM_MODE_CONF_KEY) == 'contest'
103 end
105 end
104
106
105 def self.indv_contest_mode?
107 def self.indv_contest_mode?
106 return get(SYSTEM_MODE_CONF_KEY) == 'indv-contest'
108 return get(SYSTEM_MODE_CONF_KEY) == 'indv-contest'
107 end
109 end
108
110
109 def self.multicontests?
111 def self.multicontests?
110 - g = get('system.multicontests')
112 + return get(MULTICONTESTS_KEY) == true
111 - return get('system.multicontests') == true
112 end
113 end
113
114
114 def self.time_limit_mode?
115 def self.time_limit_mode?
115 mode = get(SYSTEM_MODE_CONF_KEY)
116 mode = get(SYSTEM_MODE_CONF_KEY)
116 return ((mode == 'contest') or (mode == 'indv-contest'))
117 return ((mode == 'contest') or (mode == 'indv-contest'))
117 end
118 end
118
119
119 def self.analysis_mode?
120 def self.analysis_mode?
120 return get(SYSTEM_MODE_CONF_KEY) == 'analysis'
121 return get(SYSTEM_MODE_CONF_KEY) == 'analysis'
121 end
122 end
122
123
123 def self.contest_time_limit
124 def self.contest_time_limit
124 - contest_time_str = Configuration['contest.time_limit']
125 + contest_time_str = Configuration[CONTEST_TIME_LIMIT_KEY]
125
126
126 if not defined? Configuration.contest_time_str
127 if not defined? Configuration.contest_time_str
127 Configuration.contest_time_str = nil
128 Configuration.contest_time_str = nil
128 end
129 end
129
130
130 if Configuration.contest_time_str != contest_time_str
131 if Configuration.contest_time_str != contest_time_str
131 Configuration.contest_time_str = contest_time_str
132 Configuration.contest_time_str = contest_time_str
132 if tmatch = /(\d+):(\d+)/.match(contest_time_str)
133 if tmatch = /(\d+):(\d+)/.match(contest_time_str)
133 h = tmatch[1].to_i
134 h = tmatch[1].to_i
134 m = tmatch[2].to_i
135 m = tmatch[2].to_i
135
136
136 Configuration.contest_time = h.hour + m.minute
137 Configuration.contest_time = h.hour + m.minute
@@ -145,28 +145,25
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 - time_limit = Configuration.contest_time_limit
157 + return false if self.contest_stat(true)==nil
158 -
159 - return false if contest_stat==nil
160 -
161 return contest_time_left == 0
158 return contest_time_left == 0
162 else
159 else
163 return false
160 return false
164 end
161 end
165 end
162 end
166
163
167 def contest_started?
164 def contest_started?
168 if Configuration.contest_mode?
165 if Configuration.contest_mode?
169 return true if site==nil
166 return true if site==nil
170 return site.started
167 return site.started
171 else
168 else
172 return true
169 return true
@@ -20,25 +20,25
20 },
20 },
21
21
22 {
22 {
23 :key => 'ui.show_score',
23 :key => 'ui.show_score',
24 :value_type => 'boolean',
24 :value_type => 'boolean',
25 :default_value => 'true'
25 :default_value => 'true'
26 },
26 },
27
27
28 {
28 {
29 :key => 'contest.time_limit',
29 :key => 'contest.time_limit',
30 :value_type => 'string',
30 :value_type => 'string',
31 :default_value => 'unlimited',
31 :default_value => 'unlimited',
32 - :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits.'
32 + :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits. This config is CACHED. Restart the server before the change can take effect.'
33 },
33 },
34
34
35 {
35 {
36 :key => 'system.mode',
36 :key => 'system.mode',
37 :value_type => 'string',
37 :value_type => 'string',
38 :default_value => 'standard',
38 :default_value => 'standard',
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 },
40 },
41
41
42 {
42 {
43 :key => 'contest.name',
43 :key => 'contest.name',
44 :value_type => 'string',
44 :value_type => 'string',
@@ -1,20 +1,38
1
1
2 module ConfigSpecHelperMethods
2 module ConfigSpecHelperMethods
3
3
4 def find_or_create_and_set_config(key, type, value)
4 def find_or_create_and_set_config(key, type, value)
5 c = Configuration.find_by_key(key)
5 c = Configuration.find_by_key(key)
6 c ||= Configuration.new(:key => key,
6 c ||= Configuration.new(:key => key,
7 :value_type => type)
7 :value_type => type)
8 c.value = value
8 c.value = value
9 c.save!
9 c.save!
10 end
10 end
11
11
12 def enable_multicontest
12 def enable_multicontest
13 - find_or_create_and_set_config('system.multicontests','boolean','true')
13 + find_or_create_and_set_config(Configuration::MULTICONTESTS_KEY,
14 + 'boolean','true')
14 end
15 end
15
16
16 def disable_multicontest
17 def disable_multicontest
17 - find_or_create_and_set_config('system.multicontests','boolean','false')
18 + find_or_create_and_set_config(Configuration::MULTICONTESTS_KEY,
19 + 'boolean','false')
20 + end
21 +
22 + def set_indv_contest_mode
23 + find_or_create_and_set_config(Configuration::SYSTEM_MODE_CONF_KEY,
24 + 'string','indv-contest')
18 end
25 end
19
26
27 + def set_standard_mode
28 + find_or_create_and_set_config(Configuration::SYSTEM_MODE_CONF_KEY,
29 + 'string','standard')
30 + end
31 +
32 + def set_contest_time_limit(limit)
33 + find_or_create_and_set_config(Configuration::CONTEST_TIME_LIMIT_KEY,
34 + 'string',limit)
35 + # clear old value
36 + Configuration.contest_time_str = nil
37 + end
20 end
38 end
@@ -1,12 +1,14
1 + require 'delorean'
2 +
1 require File.dirname(__FILE__) + '/../spec_helper'
3 require File.dirname(__FILE__) + '/../spec_helper'
2 require File.dirname(__FILE__) + '/../config_spec_helper'
4 require File.dirname(__FILE__) + '/../config_spec_helper'
3
5
4 describe MainController, "when a user comes to list page" do
6 describe MainController, "when a user comes to list page" do
5
7
6 it "should redirect user to login page when unlogged-in user try to access main/list" do
8 it "should redirect user to login page when unlogged-in user try to access main/list" do
7 get 'list'
9 get 'list'
8 response.should redirect_to(:action => 'login')
10 response.should redirect_to(:action => 'login')
9 end
11 end
10
12
11 end
13 end
12
14
@@ -133,12 +135,59
133 response.should redirect_to(:action => 'list')
135 response.should redirect_to(:action => 'list')
134 end
136 end
135
137
136 it "should not let user sees other user's compiler message" do
138 it "should not let user sees other user's compiler message" do
137 get 'compiler_msg', {:id => @submission.id}, {:user_id => 2}
139 get 'compiler_msg', {:id => @submission.id}, {:user_id => 2}
138 flash[:notice].should =~ /[Ee]rror/
140 flash[:notice].should =~ /[Ee]rror/
139 response.should redirect_to(:action => 'list')
141 response.should redirect_to(:action => 'list')
140 end
142 end
141
143
142 end
144 end
143
145
144
146
147 + describe MainController, "during individual contest mode" do
148 +
149 + integrate_views
150 +
151 + include ConfigSpecHelperMethods
152 +
153 + fixtures :users
154 + fixtures :problems
155 + fixtures :contests
156 +
157 + before(:each) do
158 + set_contest_time_limit('3:00') # 3 hours
159 + set_indv_contest_mode
160 + end
161 +
162 + it "should allow newly login user to see problem list" do
163 + john = users(:john)
164 + get "list", {}, {:user_id => john.id}
165 +
166 + response.should render_template 'main/list'
167 + response.should have_text(/add/)
168 + response.should have_text(/easy_problem/)
169 + response.should have_text(/hard_problem/)
170 + end
171 +
172 + it "should not show 'contest over' sign before the contest ends" do
173 + john = users(:john)
174 + get "list", {}, {:user_id => john.id}
175 +
176 + Delorean.time_travel_to(179.minutes.since) do
177 + get "list", {}, {:user_id => john.id}
178 + response.should_not have_text(/OVER/)
179 + end
180 + end
181 +
182 + it "should show 'contest over' sign after the contest ends" do
183 + john = users(:john)
184 + get "list", {}, {:user_id => john.id}
185 +
186 + Delorean.time_travel_to(181.minutes.since) do
187 + get "list", {}, {:user_id => john.id}
188 + response.should have_text(/OVER/)
189 + end
190 + end
191 +
192 + end
193 +
@@ -1,3 +1,4
1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 admin:
2 admin:
3 + name: admin
3 rights: graders_right, user_admin_right, problems_right No newline at end of file
4 rights: graders_right, user_admin_right, problems_right
@@ -1,11 +1,11
1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
2
3 - one:
3 + first_site:
4 - name: MyString
4 + name: First site
5 started: false
5 started: false
6 start_time: 2008-04-09 14:08:28
6 start_time: 2008-04-09 14:08:28
7
7
8 - two:
8 + second_site:
9 - name: MyString
9 + name: Second site
10 started: false
10 started: false
11 start_time: 2008-04-09 14:08:28
11 start_time: 2008-04-09 14:08:28
@@ -2,33 +2,37
2
2
3 <%
3 <%
4 User.public_class_method :encrypt
4 User.public_class_method :encrypt
5
5
6 salt = "abc"
6 salt = "abc"
7 %>
7 %>
8
8
9 john:
9 john:
10 login: john
10 login: john
11 full_name: john
11 full_name: john
12 hashed_password: <%= User.encrypt("hello",salt) %>
12 hashed_password: <%= User.encrypt("hello",salt) %>
13 salt: <%= salt %>
13 salt: <%= salt %>
14 + activated: true
14
15
15 mary:
16 mary:
16 login: mary
17 login: mary
17 full_name: mary
18 full_name: mary
18 hashed_password: <%= User.encrypt("goodbye",salt) %>
19 hashed_password: <%= User.encrypt("goodbye",salt) %>
19 salt: <%= salt %>
20 salt: <%= salt %>
20 roles: admin
21 roles: admin
22 + activated: true
21
23
22 james:
24 james:
23 login: james
25 login: james
24 full_name: James
26 full_name: James
25 hashed_password: <%= User.encrypt("morning",salt) %>
27 hashed_password: <%= User.encrypt("morning",salt) %>
26 salt: <%= salt %>
28 salt: <%= salt %>
27 contests: contest_a
29 contests: contest_a
30 + activated: true
28
31
29 jack:
32 jack:
30 login: jack
33 login: jack
31 full_name: Jack
34 full_name: Jack
32 hashed_password: <%= User.encrypt("morning",salt) %>
35 hashed_password: <%= User.encrypt("morning",salt) %>
33 salt: <%= salt %>
36 salt: <%= salt %>
34 contests: contest_a, contest_b
37 contests: contest_a, contest_b
38 + activated: true
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
You need to be logged in to leave comments. Login now