Description:
added default contest
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r308:c400f7405eee - - 2 files changed: 22 inserted, 0 deleted

@@ -1,151 +1,152
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 + before_save :assign_default_contest
56
57
57 # this is for will_paginate
58 # this is for will_paginate
58 cattr_reader :per_page
59 cattr_reader :per_page
59 @@per_page = 50
60 @@per_page = 50
60
61
61 def self.authenticate(login, password)
62 def self.authenticate(login, password)
62 user = find_by_login(login)
63 user = find_by_login(login)
63 return user if user && user.authenticated?(password)
64 return user if user && user.authenticated?(password)
64 end
65 end
65
66
66 def authenticated?(password)
67 def authenticated?(password)
67 if self.activated
68 if self.activated
68 hashed_password == User.encrypt(password,self.salt)
69 hashed_password == User.encrypt(password,self.salt)
69 else
70 else
70 false
71 false
71 end
72 end
72 end
73 end
73
74
74 def admin?
75 def admin?
75 self.roles.detect {|r| r.name == 'admin' }
76 self.roles.detect {|r| r.name == 'admin' }
76 end
77 end
77
78
78 def email_for_editing
79 def email_for_editing
79 if self.email==nil
80 if self.email==nil
80 "(unknown)"
81 "(unknown)"
81 elsif self.email==''
82 elsif self.email==''
82 "(blank)"
83 "(blank)"
83 else
84 else
84 self.email
85 self.email
85 end
86 end
86 end
87 end
87
88
88 def email_for_editing=(e)
89 def email_for_editing=(e)
89 self.email=e
90 self.email=e
90 end
91 end
91
92
92 def alias_for_editing
93 def alias_for_editing
93 if self.alias==nil
94 if self.alias==nil
94 "(unknown)"
95 "(unknown)"
95 elsif self.alias==''
96 elsif self.alias==''
96 "(blank)"
97 "(blank)"
97 else
98 else
98 self.alias
99 self.alias
99 end
100 end
100 end
101 end
101
102
102 def alias_for_editing=(e)
103 def alias_for_editing=(e)
103 self.alias=e
104 self.alias=e
104 end
105 end
105
106
106 def activation_key
107 def activation_key
107 if self.hashed_password==nil
108 if self.hashed_password==nil
108 encrypt_new_password
109 encrypt_new_password
109 end
110 end
110 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
111 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
111 end
112 end
112
113
113 def verify_activation_key(key)
114 def verify_activation_key(key)
114 key == activation_key
115 key == activation_key
115 end
116 end
116
117
117 def self.random_password(length=5)
118 def self.random_password(length=5)
118 chars = 'abcdefghjkmnopqrstuvwxyz'
119 chars = 'abcdefghjkmnopqrstuvwxyz'
119 password = ''
120 password = ''
120 length.times { password << chars[rand(chars.length - 1)] }
121 length.times { password << chars[rand(chars.length - 1)] }
121 password
122 password
122 end
123 end
123
124
124 def self.find_non_admin_with_prefix(prefix='')
125 def self.find_non_admin_with_prefix(prefix='')
125 users = User.find(:all)
126 users = User.find(:all)
126 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
127 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
127 end
128 end
128
129
129 # Contest information
130 # Contest information
130
131
131 def self.find_users_with_no_contest()
132 def self.find_users_with_no_contest()
132 users = User.find(:all)
133 users = User.find(:all)
133 return users.find_all { |u| u.contests.length == 0 }
134 return users.find_all { |u| u.contests.length == 0 }
134 end
135 end
135
136
136
137
137 def contest_time_left
138 def contest_time_left
138 if Configuration.contest_mode?
139 if Configuration.contest_mode?
139 return nil if site==nil
140 return nil if site==nil
140 return site.time_left
141 return site.time_left
141 elsif Configuration.indv_contest_mode?
142 elsif Configuration.indv_contest_mode?
142 time_limit = Configuration.contest_time_limit
143 time_limit = Configuration.contest_time_limit
143 if time_limit == nil
144 if time_limit == nil
144 return nil
145 return nil
145 end
146 end
146 if contest_stat==nil or contest_stat.started_at==nil
147 if contest_stat==nil or contest_stat.started_at==nil
147 return (Time.now.gmtime + time_limit) - Time.now.gmtime
148 return (Time.now.gmtime + time_limit) - Time.now.gmtime
148 else
149 else
149 finish_time = contest_stat.started_at + time_limit
150 finish_time = contest_stat.started_at + time_limit
150 current_time = Time.now.gmtime
151 current_time = Time.now.gmtime
151 if current_time > finish_time
152 if current_time > finish_time
@@ -180,130 +181,143
180 return site.started
181 return site.started
181 else
182 else
182 return true
183 return true
183 end
184 end
184 end
185 end
185
186
186 def update_start_time
187 def update_start_time
187 stat = self.contest_stat
188 stat = self.contest_stat
188 if stat == nil or stat.started_at == nil
189 if stat == nil or stat.started_at == nil
189 stat ||= UserContestStat.new(:user => self)
190 stat ||= UserContestStat.new(:user => self)
190 stat.started_at = Time.now.gmtime
191 stat.started_at = Time.now.gmtime
191 stat.save
192 stat.save
192 end
193 end
193 end
194 end
194
195
195 def problem_in_user_contests?(problem)
196 def problem_in_user_contests?(problem)
196 problem_contests = problem.contests.all
197 problem_contests = problem.contests.all
197
198
198 if problem_contests.length == 0 # this is public contest
199 if problem_contests.length == 0 # this is public contest
199 return true
200 return true
200 end
201 end
201
202
202 contests.each do |contest|
203 contests.each do |contest|
203 if problem_contests.find {|c| c.id == contest.id }
204 if problem_contests.find {|c| c.id == contest.id }
204 return true
205 return true
205 end
206 end
206 end
207 end
207 return false
208 return false
208 end
209 end
209
210
210 def available_problems_group_by_contests
211 def available_problems_group_by_contests
211 contest_problems = []
212 contest_problems = []
212 pin = {}
213 pin = {}
213 contests.enabled.each do |contest|
214 contests.enabled.each do |contest|
214 available_problems = contest.problems.available
215 available_problems = contest.problems.available
215 contest_problems << {
216 contest_problems << {
216 :contest => contest,
217 :contest => contest,
217 :problems => available_problems
218 :problems => available_problems
218 }
219 }
219 available_problems.each {|p| pin[p.id] = true}
220 available_problems.each {|p| pin[p.id] = true}
220 end
221 end
221 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
222 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
222 contest_problems << {
223 contest_problems << {
223 :contest => nil,
224 :contest => nil,
224 :problems => other_avaiable_problems
225 :problems => other_avaiable_problems
225 }
226 }
226 return contest_problems
227 return contest_problems
227 end
228 end
228
229
229 def available_problems
230 def available_problems
230 if not Configuration.multicontests?
231 if not Configuration.multicontests?
231 return Problem.find_available_problems
232 return Problem.find_available_problems
232 else
233 else
233 contest_problems = []
234 contest_problems = []
234 pin = {}
235 pin = {}
235 contests.enabled.each do |contest|
236 contests.enabled.each do |contest|
236 contest.problems.available.each do |problem|
237 contest.problems.available.each do |problem|
237 if not pin.has_key? problem.id
238 if not pin.has_key? problem.id
238 contest_problems << problem
239 contest_problems << problem
239 end
240 end
240 pin[problem.id] = true
241 pin[problem.id] = true
241 end
242 end
242 end
243 end
243 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
244 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
244 return contest_problems + other_avaiable_problems
245 return contest_problems + other_avaiable_problems
245 end
246 end
246 end
247 end
247
248
248 def can_view_problem?(problem)
249 def can_view_problem?(problem)
249 if not Configuration.multicontests?
250 if not Configuration.multicontests?
250 return problem.available
251 return problem.available
251 else
252 else
252 return problem_in_user_contests? problem
253 return problem_in_user_contests? problem
253 end
254 end
254 end
255 end
255
256
256 protected
257 protected
257 def encrypt_new_password
258 def encrypt_new_password
258 return if password.blank?
259 return if password.blank?
259 self.salt = (10+rand(90)).to_s
260 self.salt = (10+rand(90)).to_s
260 self.hashed_password = User.encrypt(self.password,self.salt)
261 self.hashed_password = User.encrypt(self.password,self.salt)
261 end
262 end
262
263
263 def assign_default_site
264 def assign_default_site
264 # have to catch error when migrating (because self.site is not available).
265 # have to catch error when migrating (because self.site is not available).
265 begin
266 begin
266 if self.site==nil
267 if self.site==nil
267 self.site = Site.find_by_name('default')
268 self.site = Site.find_by_name('default')
268 if self.site==nil
269 if self.site==nil
269 self.site = Site.find(1) # when 'default has be renamed'
270 self.site = Site.find(1) # when 'default has be renamed'
270 end
271 end
271 end
272 end
272 rescue
273 rescue
273 end
274 end
274 end
275 end
275
276
277 + def assign_default_contest
278 + # have to catch error when migrating (because self.site is not available).
279 + begin
280 + if self.contests.length == 0
281 + default_contest = Contest.find_by_name(Configuration['contest.default_contest_name'])
282 + if default_contest
283 + self.contests = [default_contest]
284 + end
285 + end
286 + rescue
287 + end
288 + end
289 +
276 def password_required?
290 def password_required?
277 self.hashed_password.blank? || !self.password.blank?
291 self.hashed_password.blank? || !self.password.blank?
278 end
292 end
279
293
280 def self.encrypt(string,salt)
294 def self.encrypt(string,salt)
281 Digest::SHA1.hexdigest(salt + string)
295 Digest::SHA1.hexdigest(salt + string)
282 end
296 end
283
297
284 def uniqueness_of_email_from_activated_users
298 def uniqueness_of_email_from_activated_users
285 user = User.activated_users.find_by_email(self.email)
299 user = User.activated_users.find_by_email(self.email)
286 if user and (user.login != self.login)
300 if user and (user.login != self.login)
287 self.errors.add_to_base("Email has already been taken")
301 self.errors.add_to_base("Email has already been taken")
288 end
302 end
289 end
303 end
290
304
291 def enough_time_interval_between_same_email_registrations
305 def enough_time_interval_between_same_email_registrations
292 return if !self.new_record?
306 return if !self.new_record?
293 return if self.activated
307 return if self.activated
294 open_user = User.find_by_email(self.email,
308 open_user = User.find_by_email(self.email,
295 :order => 'created_at DESC')
309 :order => 'created_at DESC')
296 if open_user and open_user.created_at and
310 if open_user and open_user.created_at and
297 (open_user.created_at > Time.now.gmtime - 5.minutes)
311 (open_user.created_at > Time.now.gmtime - 5.minutes)
298 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
312 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
299 end
313 end
300 end
314 end
301
315
302 def email_validation?
316 def email_validation?
303 begin
317 begin
304 return VALIDATE_USER_EMAILS
318 return VALIDATE_USER_EMAILS
305 rescue
319 rescue
306 return false
320 return false
307 end
321 end
308 end
322 end
309 end
323 end
@@ -14,177 +14,185
14 },
14 },
15
15
16 {
16 {
17 :key => 'ui.front.welcome_message',
17 :key => 'ui.front.welcome_message',
18 :value_type => 'string',
18 :value_type => 'string',
19 :default_value => 'Welcome!'
19 :default_value => 'Welcome!'
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. This config is CACHED. Restart the server before the change can take effect.'
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',
45 :default_value => 'Grader',
45 :default_value => 'Grader',
46 :description => 'This name will be shown on the user header bar.'
46 :description => 'This name will be shown on the user header bar.'
47 },
47 },
48
48
49 {
49 {
50 :key => 'contest.multisites',
50 :key => 'contest.multisites',
51 :value_type => 'boolean',
51 :value_type => 'boolean',
52 :default_value => 'false',
52 :default_value => 'false',
53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
54 },
54 },
55
55
56 {
56 {
57 :key => 'system.online_registration',
57 :key => 'system.online_registration',
58 :value_type => 'boolean',
58 :value_type => 'boolean',
59 :default_value => 'false',
59 :default_value => 'false',
60 :description => 'This option enables online registration.'
60 :description => 'This option enables online registration.'
61 },
61 },
62
62
63 # If Configuration['system.online_registration'] is true, the
63 # If Configuration['system.online_registration'] is true, the
64 # system allows online registration, and will use these
64 # system allows online registration, and will use these
65 # information for sending confirmation emails.
65 # information for sending confirmation emails.
66 {
66 {
67 :key => 'system.online_registration.smtp',
67 :key => 'system.online_registration.smtp',
68 :value_type => 'string',
68 :value_type => 'string',
69 :default_value => 'smtp.somehost.com'
69 :default_value => 'smtp.somehost.com'
70 },
70 },
71
71
72 {
72 {
73 :key => 'system.online_registration.from',
73 :key => 'system.online_registration.from',
74 :value_type => 'string',
74 :value_type => 'string',
75 :default_value => 'your.email@address'
75 :default_value => 'your.email@address'
76 },
76 },
77
77
78 {
78 {
79 :key => 'system.admin_email',
79 :key => 'system.admin_email',
80 :value_type => 'string',
80 :value_type => 'string',
81 :default_value => 'admin@admin.email'
81 :default_value => 'admin@admin.email'
82 },
82 },
83
83
84 {
84 {
85 :key => 'system.user_setting_enabled',
85 :key => 'system.user_setting_enabled',
86 :value_type => 'boolean',
86 :value_type => 'boolean',
87 :default_value => 'true',
87 :default_value => 'true',
88 :description => 'If this option is true, users can change their settings'
88 :description => 'If this option is true, users can change their settings'
89 },
89 },
90
90
91 # If Configuration['contest.test_request.early_timeout'] is true
91 # If Configuration['contest.test_request.early_timeout'] is true
92 # the user will not be able to use test request at 30 minutes
92 # the user will not be able to use test request at 30 minutes
93 # before the contest ends.
93 # before the contest ends.
94 {
94 {
95 :key => 'contest.test_request.early_timeout',
95 :key => 'contest.test_request.early_timeout',
96 :value_type => 'boolean',
96 :value_type => 'boolean',
97 :default_value => 'false'
97 :default_value => 'false'
98 },
98 },
99
99
100 {
100 {
101 :key => 'system.multicontests',
101 :key => 'system.multicontests',
102 :value_type => 'boolean',
102 :value_type => 'boolean',
103 :default_value => 'false'
103 :default_value => 'false'
104 },
104 },
105
105
106 {
106 {
107 :key => 'contest.confirm_indv_contest_start',
107 :key => 'contest.confirm_indv_contest_start',
108 :value_type => 'boolean',
108 :value_type => 'boolean',
109 :default_value => 'false'
109 :default_value => 'false'
110 + },
111 +
112 + {
113 + :key => 'contest.default_contest_name',
114 + :value_type => 'string',
115 + :default_value => 'none',
116 + :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
110 }
117 }
118 +
111 ]
119 ]
112
120
113
121
114 def create_configuration_key(key,
122 def create_configuration_key(key,
115 value_type,
123 value_type,
116 default_value,
124 default_value,
117 description='')
125 description='')
118 conf = (Configuration.find_by_key(key) ||
126 conf = (Configuration.find_by_key(key) ||
119 Configuration.new(:key => key,
127 Configuration.new(:key => key,
120 :value_type => value_type,
128 :value_type => value_type,
121 :value => default_value))
129 :value => default_value))
122 conf.description = description
130 conf.description = description
123 conf.save
131 conf.save
124 end
132 end
125
133
126 def seed_config
134 def seed_config
127 CONFIGURATIONS.each do |conf|
135 CONFIGURATIONS.each do |conf|
128 if conf.has_key? :description
136 if conf.has_key? :description
129 desc = conf[:description]
137 desc = conf[:description]
130 else
138 else
131 desc = ''
139 desc = ''
132 end
140 end
133 create_configuration_key(conf[:key],
141 create_configuration_key(conf[:key],
134 conf[:value_type],
142 conf[:value_type],
135 conf[:default_value],
143 conf[:default_value],
136 desc)
144 desc)
137 end
145 end
138 end
146 end
139
147
140 def seed_roles
148 def seed_roles
141 return if Role.find_by_name('admin')
149 return if Role.find_by_name('admin')
142
150
143 role = Role.create(:name => 'admin')
151 role = Role.create(:name => 'admin')
144 user_admin_right = Right.create(:name => 'user_admin',
152 user_admin_right = Right.create(:name => 'user_admin',
145 :controller => 'user_admin',
153 :controller => 'user_admin',
146 :action => 'all')
154 :action => 'all')
147 problem_admin_right = Right.create(:name=> 'problem_admin',
155 problem_admin_right = Right.create(:name=> 'problem_admin',
148 :controller => 'problems',
156 :controller => 'problems',
149 :action => 'all')
157 :action => 'all')
150
158
151 graders_right = Right.create(:name => 'graders_admin',
159 graders_right = Right.create(:name => 'graders_admin',
152 :controller => 'graders',
160 :controller => 'graders',
153 :action => 'all')
161 :action => 'all')
154
162
155 role.rights << user_admin_right;
163 role.rights << user_admin_right;
156 role.rights << problem_admin_right;
164 role.rights << problem_admin_right;
157 role.rights << graders_right;
165 role.rights << graders_right;
158 role.save
166 role.save
159 end
167 end
160
168
161 def seed_root
169 def seed_root
162 return if User.find_by_login('root')
170 return if User.find_by_login('root')
163
171
164 root = User.new(:login => 'root',
172 root = User.new(:login => 'root',
165 :full_name => 'Administrator',
173 :full_name => 'Administrator',
166 :alias => 'root')
174 :alias => 'root')
167 root.password = 'ioionrails';
175 root.password = 'ioionrails';
168
176
169 class << root
177 class << root
170 public :encrypt_new_password
178 public :encrypt_new_password
171 def valid?
179 def valid?
172 true
180 true
173 end
181 end
174 end
182 end
175
183
176 root.encrypt_new_password
184 root.encrypt_new_password
177
185
178 root.roles << Role.find_by_name('admin')
186 root.roles << Role.find_by_name('admin')
179
187
180 root.activated = true
188 root.activated = true
181 root.save
189 root.save
182 end
190 end
183
191
184 def seed_users_and_roles
192 def seed_users_and_roles
185 seed_roles
193 seed_roles
186 seed_root
194 seed_root
187 end
195 end
188
196
189 seed_config
197 seed_config
190 seed_users_and_roles
198 seed_users_and_roles
You need to be logged in to leave comments. Login now