Description:
fix authen pop3 bugs and redundant code
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r406:b2fd7182e3dc - - 1 file changed: 2 inserted, 13 deleted

@@ -1,380 +1,369
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 + require 'net/https'
4 + require 'net/http'
3 require 'json'
5 require 'json'
4
6
5 class User < ActiveRecord::Base
7 class User < ActiveRecord::Base
6
8
7 has_and_belongs_to_many :roles
9 has_and_belongs_to_many :roles
8
10
9 has_many :test_requests, :order => "submitted_at DESC"
11 has_many :test_requests, :order => "submitted_at DESC"
10
12
11 has_many :messages,
13 has_many :messages,
12 :class_name => "Message",
14 :class_name => "Message",
13 :foreign_key => "sender_id",
15 :foreign_key => "sender_id",
14 :order => 'created_at DESC'
16 :order => 'created_at DESC'
15
17
16 has_many :replied_messages,
18 has_many :replied_messages,
17 :class_name => "Message",
19 :class_name => "Message",
18 :foreign_key => "receiver_id",
20 :foreign_key => "receiver_id",
19 :order => 'created_at DESC'
21 :order => 'created_at DESC'
20
22
21 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
23 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
22
24
23 belongs_to :site
25 belongs_to :site
24 belongs_to :country
26 belongs_to :country
25
27
26 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
28 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
27
29
28 scope :activated_users, :conditions => {:activated => true}
30 scope :activated_users, :conditions => {:activated => true}
29
31
30 validates_presence_of :login
32 validates_presence_of :login
31 validates_uniqueness_of :login
33 validates_uniqueness_of :login
32 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
33 validates_length_of :login, :within => 3..30
35 validates_length_of :login, :within => 3..30
34
36
35 validates_presence_of :full_name
37 validates_presence_of :full_name
36 validates_length_of :full_name, :minimum => 1
38 validates_length_of :full_name, :minimum => 1
37
39
38 validates_presence_of :password, :if => :password_required?
40 validates_presence_of :password, :if => :password_required?
39 validates_length_of :password, :within => 4..20, :if => :password_required?
41 validates_length_of :password, :within => 4..20, :if => :password_required?
40 validates_confirmation_of :password, :if => :password_required?
42 validates_confirmation_of :password, :if => :password_required?
41
43
42 validates_format_of :email,
44 validates_format_of :email,
43 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
44 :if => :email_validation?
46 :if => :email_validation?
45 validate :uniqueness_of_email_from_activated_users,
47 validate :uniqueness_of_email_from_activated_users,
46 :if => :email_validation?
48 :if => :email_validation?
47 validate :enough_time_interval_between_same_email_registrations,
49 validate :enough_time_interval_between_same_email_registrations,
48 :if => :email_validation?
50 :if => :email_validation?
49
51
50 # these are for ytopc
52 # these are for ytopc
51 # disable for now
53 # disable for now
52 #validates_presence_of :province
54 #validates_presence_of :province
53
55
54 attr_accessor :password
56 attr_accessor :password
55
57
56 before_save :encrypt_new_password
58 before_save :encrypt_new_password
57 before_save :assign_default_site
59 before_save :assign_default_site
58 before_save :assign_default_contest
60 before_save :assign_default_contest
59
61
60 # this is for will_paginate
62 # this is for will_paginate
61 cattr_reader :per_page
63 cattr_reader :per_page
62 @@per_page = 50
64 @@per_page = 50
63
65
64 def self.authenticate(login, password)
66 def self.authenticate(login, password)
65 user = find_by_login(login)
67 user = find_by_login(login)
66 if user
68 if user
67 return user if user.authenticated?(password)
69 return user if user.authenticated?(password)
68 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
70 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
69 user.password = password
71 user.password = password
70 user.save
72 user.save
71 return user
73 return user
72 end
74 end
73 end
75 end
74 end
76 end
75
77
76 def authenticated?(password)
78 def authenticated?(password)
77 if self.activated
79 if self.activated
78 hashed_password == User.encrypt(password,self.salt)
80 hashed_password == User.encrypt(password,self.salt)
79 else
81 else
80 false
82 false
81 end
83 end
82 end
84 end
83
85
84 def authenticated_by_pop3?(password)
86 def authenticated_by_pop3?(password)
85 Net::POP3.enable_ssl
87 Net::POP3.enable_ssl
86 pop = Net::POP3.new('pops.it.chula.ac.th')
88 pop = Net::POP3.new('pops.it.chula.ac.th')
87 authen = true
89 authen = true
88 begin
90 begin
89 - pop.start(login, password) # (1)
90 - pop.finish
91 - return true
92 - rescue
93 - return false
94 - end
95 - end
96 -
97 - def authenticated_by_pop3?(password)
98 - Net::POP3.enable_ssl
99 - pop = Net::POP3.new('pops.it.chula.ac.th')
100 - authen = true
101 - begin
102 pop.start(login, password)
91 pop.start(login, password)
103 pop.finish
92 pop.finish
104 return true
93 return true
105 rescue
94 rescue
106 return false
95 return false
107 end
96 end
108 end
97 end
109
98
110 def authenticated_by_cucas?(password)
99 def authenticated_by_cucas?(password)
111 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
100 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
112 appid = '41508763e340d5858c00f8c1a0f5a2bb'
101 appid = '41508763e340d5858c00f8c1a0f5a2bb'
113 appsecret ='d9cbb5863091dbe186fded85722a1e31'
102 appsecret ='d9cbb5863091dbe186fded85722a1e31'
114 post_args = {
103 post_args = {
115 'appid' => appid,
104 'appid' => appid,
116 'appsecret' => appsecret,
105 'appsecret' => appsecret,
117 'username' => login,
106 'username' => login,
118 'password' => password
107 'password' => password
119 }
108 }
120
109
121 #simple call
110 #simple call
122 begin
111 begin
123 resp = Net::HTTP.post_form(url, post_args)
112 resp = Net::HTTP.post_form(url, post_args)
124 result = JSON.parse resp.body
113 result = JSON.parse resp.body
125 return true if result["type"] == "beanStudent"
114 return true if result["type"] == "beanStudent"
126 rescue
115 rescue
127 return false
116 return false
128 end
117 end
129 return false
118 return false
130 end
119 end
131
120
132 def admin?
121 def admin?
133 self.roles.detect {|r| r.name == 'admin' }
122 self.roles.detect {|r| r.name == 'admin' }
134 end
123 end
135
124
136 def email_for_editing
125 def email_for_editing
137 if self.email==nil
126 if self.email==nil
138 "(unknown)"
127 "(unknown)"
139 elsif self.email==''
128 elsif self.email==''
140 "(blank)"
129 "(blank)"
141 else
130 else
142 self.email
131 self.email
143 end
132 end
144 end
133 end
145
134
146 def email_for_editing=(e)
135 def email_for_editing=(e)
147 self.email=e
136 self.email=e
148 end
137 end
149
138
150 def alias_for_editing
139 def alias_for_editing
151 if self.alias==nil
140 if self.alias==nil
152 "(unknown)"
141 "(unknown)"
153 elsif self.alias==''
142 elsif self.alias==''
154 "(blank)"
143 "(blank)"
155 else
144 else
156 self.alias
145 self.alias
157 end
146 end
158 end
147 end
159
148
160 def alias_for_editing=(e)
149 def alias_for_editing=(e)
161 self.alias=e
150 self.alias=e
162 end
151 end
163
152
164 def activation_key
153 def activation_key
165 if self.hashed_password==nil
154 if self.hashed_password==nil
166 encrypt_new_password
155 encrypt_new_password
167 end
156 end
168 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
157 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
169 end
158 end
170
159
171 def verify_activation_key(key)
160 def verify_activation_key(key)
172 key == activation_key
161 key == activation_key
173 end
162 end
174
163
175 def self.random_password(length=5)
164 def self.random_password(length=5)
176 chars = 'abcdefghjkmnopqrstuvwxyz'
165 chars = 'abcdefghjkmnopqrstuvwxyz'
177 password = ''
166 password = ''
178 length.times { password << chars[rand(chars.length - 1)] }
167 length.times { password << chars[rand(chars.length - 1)] }
179 password
168 password
180 end
169 end
181
170
182 def self.find_non_admin_with_prefix(prefix='')
171 def self.find_non_admin_with_prefix(prefix='')
183 users = User.find(:all)
172 users = User.find(:all)
184 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
173 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
185 end
174 end
186
175
187 # Contest information
176 # Contest information
188
177
189 def self.find_users_with_no_contest()
178 def self.find_users_with_no_contest()
190 users = User.find(:all)
179 users = User.find(:all)
191 return users.find_all { |u| u.contests.length == 0 }
180 return users.find_all { |u| u.contests.length == 0 }
192 end
181 end
193
182
194
183
195 def contest_time_left
184 def contest_time_left
196 if GraderConfiguration.contest_mode?
185 if GraderConfiguration.contest_mode?
197 return nil if site==nil
186 return nil if site==nil
198 return site.time_left
187 return site.time_left
199 elsif GraderConfiguration.indv_contest_mode?
188 elsif GraderConfiguration.indv_contest_mode?
200 time_limit = GraderConfiguration.contest_time_limit
189 time_limit = GraderConfiguration.contest_time_limit
201 if time_limit == nil
190 if time_limit == nil
202 return nil
191 return nil
203 end
192 end
204 if contest_stat==nil or contest_stat.started_at==nil
193 if contest_stat==nil or contest_stat.started_at==nil
205 return (Time.now.gmtime + time_limit) - Time.now.gmtime
194 return (Time.now.gmtime + time_limit) - Time.now.gmtime
206 else
195 else
207 finish_time = contest_stat.started_at + time_limit
196 finish_time = contest_stat.started_at + time_limit
208 current_time = Time.now.gmtime
197 current_time = Time.now.gmtime
209 if current_time > finish_time
198 if current_time > finish_time
210 return 0
199 return 0
211 else
200 else
212 return finish_time - current_time
201 return finish_time - current_time
213 end
202 end
214 end
203 end
215 else
204 else
216 return nil
205 return nil
217 end
206 end
218 end
207 end
219
208
220 def contest_finished?
209 def contest_finished?
221 if GraderConfiguration.contest_mode?
210 if GraderConfiguration.contest_mode?
222 return false if site==nil
211 return false if site==nil
223 return site.finished?
212 return site.finished?
224 elsif GraderConfiguration.indv_contest_mode?
213 elsif GraderConfiguration.indv_contest_mode?
225 return false if self.contest_stat(true)==nil
214 return false if self.contest_stat(true)==nil
226 return contest_time_left == 0
215 return contest_time_left == 0
227 else
216 else
228 return false
217 return false
229 end
218 end
230 end
219 end
231
220
232 def contest_started?
221 def contest_started?
233 if GraderConfiguration.indv_contest_mode?
222 if GraderConfiguration.indv_contest_mode?
234 stat = self.contest_stat
223 stat = self.contest_stat
235 return ((stat != nil) and (stat.started_at != nil))
224 return ((stat != nil) and (stat.started_at != nil))
236 elsif GraderConfiguration.contest_mode?
225 elsif GraderConfiguration.contest_mode?
237 return true if site==nil
226 return true if site==nil
238 return site.started
227 return site.started
239 else
228 else
240 return true
229 return true
241 end
230 end
242 end
231 end
243
232
244 def update_start_time
233 def update_start_time
245 stat = self.contest_stat
234 stat = self.contest_stat
246 if stat == nil or stat.started_at == nil
235 if stat == nil or stat.started_at == nil
247 stat ||= UserContestStat.new(:user => self)
236 stat ||= UserContestStat.new(:user => self)
248 stat.started_at = Time.now.gmtime
237 stat.started_at = Time.now.gmtime
249 stat.save
238 stat.save
250 end
239 end
251 end
240 end
252
241
253 def problem_in_user_contests?(problem)
242 def problem_in_user_contests?(problem)
254 problem_contests = problem.contests.all
243 problem_contests = problem.contests.all
255
244
256 if problem_contests.length == 0 # this is public contest
245 if problem_contests.length == 0 # this is public contest
257 return true
246 return true
258 end
247 end
259
248
260 contests.each do |contest|
249 contests.each do |contest|
261 if problem_contests.find {|c| c.id == contest.id }
250 if problem_contests.find {|c| c.id == contest.id }
262 return true
251 return true
263 end
252 end
264 end
253 end
265 return false
254 return false
266 end
255 end
267
256
268 def available_problems_group_by_contests
257 def available_problems_group_by_contests
269 contest_problems = []
258 contest_problems = []
270 pin = {}
259 pin = {}
271 contests.enabled.each do |contest|
260 contests.enabled.each do |contest|
272 available_problems = contest.problems.available
261 available_problems = contest.problems.available
273 contest_problems << {
262 contest_problems << {
274 :contest => contest,
263 :contest => contest,
275 :problems => available_problems
264 :problems => available_problems
276 }
265 }
277 available_problems.each {|p| pin[p.id] = true}
266 available_problems.each {|p| pin[p.id] = true}
278 end
267 end
279 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
268 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
280 contest_problems << {
269 contest_problems << {
281 :contest => nil,
270 :contest => nil,
282 :problems => other_avaiable_problems
271 :problems => other_avaiable_problems
283 }
272 }
284 return contest_problems
273 return contest_problems
285 end
274 end
286
275
287 def available_problems
276 def available_problems
288 if not GraderConfiguration.multicontests?
277 if not GraderConfiguration.multicontests?
289 return Problem.find_available_problems
278 return Problem.find_available_problems
290 else
279 else
291 contest_problems = []
280 contest_problems = []
292 pin = {}
281 pin = {}
293 contests.enabled.each do |contest|
282 contests.enabled.each do |contest|
294 contest.problems.available.each do |problem|
283 contest.problems.available.each do |problem|
295 if not pin.has_key? problem.id
284 if not pin.has_key? problem.id
296 contest_problems << problem
285 contest_problems << problem
297 end
286 end
298 pin[problem.id] = true
287 pin[problem.id] = true
299 end
288 end
300 end
289 end
301 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
290 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
302 return contest_problems + other_avaiable_problems
291 return contest_problems + other_avaiable_problems
303 end
292 end
304 end
293 end
305
294
306 def can_view_problem?(problem)
295 def can_view_problem?(problem)
307 if not GraderConfiguration.multicontests?
296 if not GraderConfiguration.multicontests?
308 return problem.available
297 return problem.available
309 else
298 else
310 return problem_in_user_contests? problem
299 return problem_in_user_contests? problem
311 end
300 end
312 end
301 end
313
302
314 protected
303 protected
315 def encrypt_new_password
304 def encrypt_new_password
316 return if password.blank?
305 return if password.blank?
317 self.salt = (10+rand(90)).to_s
306 self.salt = (10+rand(90)).to_s
318 self.hashed_password = User.encrypt(self.password,self.salt)
307 self.hashed_password = User.encrypt(self.password,self.salt)
319 end
308 end
320
309
321 def assign_default_site
310 def assign_default_site
322 # have to catch error when migrating (because self.site is not available).
311 # have to catch error when migrating (because self.site is not available).
323 begin
312 begin
324 if self.site==nil
313 if self.site==nil
325 self.site = Site.find_by_name('default')
314 self.site = Site.find_by_name('default')
326 if self.site==nil
315 if self.site==nil
327 self.site = Site.find(1) # when 'default has be renamed'
316 self.site = Site.find(1) # when 'default has be renamed'
328 end
317 end
329 end
318 end
330 rescue
319 rescue
331 end
320 end
332 end
321 end
333
322
334 def assign_default_contest
323 def assign_default_contest
335 # have to catch error when migrating (because self.site is not available).
324 # have to catch error when migrating (because self.site is not available).
336 begin
325 begin
337 if self.contests.length == 0
326 if self.contests.length == 0
338 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
327 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
339 if default_contest
328 if default_contest
340 self.contests = [default_contest]
329 self.contests = [default_contest]
341 end
330 end
342 end
331 end
343 rescue
332 rescue
344 end
333 end
345 end
334 end
346
335
347 def password_required?
336 def password_required?
348 self.hashed_password.blank? || !self.password.blank?
337 self.hashed_password.blank? || !self.password.blank?
349 end
338 end
350
339
351 def self.encrypt(string,salt)
340 def self.encrypt(string,salt)
352 Digest::SHA1.hexdigest(salt + string)
341 Digest::SHA1.hexdigest(salt + string)
353 end
342 end
354
343
355 def uniqueness_of_email_from_activated_users
344 def uniqueness_of_email_from_activated_users
356 user = User.activated_users.find_by_email(self.email)
345 user = User.activated_users.find_by_email(self.email)
357 if user and (user.login != self.login)
346 if user and (user.login != self.login)
358 self.errors.add_to_base("Email has already been taken")
347 self.errors.add_to_base("Email has already been taken")
359 end
348 end
360 end
349 end
361
350
362 def enough_time_interval_between_same_email_registrations
351 def enough_time_interval_between_same_email_registrations
363 return if !self.new_record?
352 return if !self.new_record?
364 return if self.activated
353 return if self.activated
365 open_user = User.find_by_email(self.email,
354 open_user = User.find_by_email(self.email,
366 :order => 'created_at DESC')
355 :order => 'created_at DESC')
367 if open_user and open_user.created_at and
356 if open_user and open_user.created_at and
368 (open_user.created_at > Time.now.gmtime - 5.minutes)
357 (open_user.created_at > Time.now.gmtime - 5.minutes)
369 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
358 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
370 end
359 end
371 end
360 end
372
361
373 def email_validation?
362 def email_validation?
374 begin
363 begin
375 return VALIDATE_USER_EMAILS
364 return VALIDATE_USER_EMAILS
376 rescue
365 rescue
377 return false
366 return false
378 end
367 end
379 end
368 end
380 end
369 end
You need to be logged in to leave comments. Login now