Description:
add pop3 authentication for chula create both bookmark and branch so that github will work too
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r390:edc9bac52078 - - 1 file changed: 17 inserted, 0 deleted

@@ -1,266 +1,283
1 require 'digest/sha1'
1 require 'digest/sha1'
2 + require 'net/pop'
2
3
3 class User < ActiveRecord::Base
4 class User < ActiveRecord::Base
4
5
5 has_and_belongs_to_many :roles
6 has_and_belongs_to_many :roles
6
7
7 has_many :test_requests, :order => "submitted_at DESC"
8 has_many :test_requests, :order => "submitted_at DESC"
8
9
9 has_many :messages,
10 has_many :messages,
10 :class_name => "Message",
11 :class_name => "Message",
11 :foreign_key => "sender_id",
12 :foreign_key => "sender_id",
12 :order => 'created_at DESC'
13 :order => 'created_at DESC'
13
14
14 has_many :replied_messages,
15 has_many :replied_messages,
15 :class_name => "Message",
16 :class_name => "Message",
16 :foreign_key => "receiver_id",
17 :foreign_key => "receiver_id",
17 :order => 'created_at DESC'
18 :order => 'created_at DESC'
18
19
19 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
20 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
20
21
21 belongs_to :site
22 belongs_to :site
22 belongs_to :country
23 belongs_to :country
23
24
24 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
25 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
25
26
26 scope :activated_users, :conditions => {:activated => true}
27 scope :activated_users, :conditions => {:activated => true}
27
28
28 validates_presence_of :login
29 validates_presence_of :login
29 validates_uniqueness_of :login
30 validates_uniqueness_of :login
30 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
31 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
31 validates_length_of :login, :within => 3..30
32 validates_length_of :login, :within => 3..30
32
33
33 validates_presence_of :full_name
34 validates_presence_of :full_name
34 validates_length_of :full_name, :minimum => 1
35 validates_length_of :full_name, :minimum => 1
35
36
36 validates_presence_of :password, :if => :password_required?
37 validates_presence_of :password, :if => :password_required?
37 validates_length_of :password, :within => 4..20, :if => :password_required?
38 validates_length_of :password, :within => 4..20, :if => :password_required?
38 validates_confirmation_of :password, :if => :password_required?
39 validates_confirmation_of :password, :if => :password_required?
39
40
40 validates_format_of :email,
41 validates_format_of :email,
41 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
42 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
42 :if => :email_validation?
43 :if => :email_validation?
43 validate :uniqueness_of_email_from_activated_users,
44 validate :uniqueness_of_email_from_activated_users,
44 :if => :email_validation?
45 :if => :email_validation?
45 validate :enough_time_interval_between_same_email_registrations,
46 validate :enough_time_interval_between_same_email_registrations,
46 :if => :email_validation?
47 :if => :email_validation?
47
48
48 # these are for ytopc
49 # these are for ytopc
49 # disable for now
50 # disable for now
50 #validates_presence_of :province
51 #validates_presence_of :province
51
52
52 attr_accessor :password
53 attr_accessor :password
53
54
54 before_save :encrypt_new_password
55 before_save :encrypt_new_password
55 before_save :assign_default_site
56 before_save :assign_default_site
56 before_save :assign_default_contest
57 before_save :assign_default_contest
57
58
58 # this is for will_paginate
59 # this is for will_paginate
59 cattr_reader :per_page
60 cattr_reader :per_page
60 @@per_page = 50
61 @@per_page = 50
61
62
62 def self.authenticate(login, password)
63 def self.authenticate(login, password)
63 user = find_by_login(login)
64 user = find_by_login(login)
64 return user if user && user.authenticated?(password)
65 return user if user && user.authenticated?(password)
66 + if user.authenticated_by_pop3?(password)
67 + user.password = password
68 + end
65 end
69 end
66
70
67 def authenticated?(password)
71 def authenticated?(password)
68 if self.activated
72 if self.activated
69 hashed_password == User.encrypt(password,self.salt)
73 hashed_password == User.encrypt(password,self.salt)
70 else
74 else
71 false
75 false
72 end
76 end
73 end
77 end
74
78
79 + def authenticated_by_pop3?(password)
80 + Net::POP3.enable_ssl
81 + pop = Net::POP3.new('pops.it.chula.ac.th')
82 + authen = true
83 + begin
84 + pop.start(login, password) # (1)
85 + pop.finish
86 + return true
87 + rescue
88 + return false
89 + end
90 + end
91 +
75 def admin?
92 def admin?
76 self.roles.detect {|r| r.name == 'admin' }
93 self.roles.detect {|r| r.name == 'admin' }
77 end
94 end
78
95
79 def email_for_editing
96 def email_for_editing
80 if self.email==nil
97 if self.email==nil
81 "(unknown)"
98 "(unknown)"
82 elsif self.email==''
99 elsif self.email==''
83 "(blank)"
100 "(blank)"
84 else
101 else
85 self.email
102 self.email
86 end
103 end
87 end
104 end
88
105
89 def email_for_editing=(e)
106 def email_for_editing=(e)
90 self.email=e
107 self.email=e
91 end
108 end
92
109
93 def alias_for_editing
110 def alias_for_editing
94 if self.alias==nil
111 if self.alias==nil
95 "(unknown)"
112 "(unknown)"
96 elsif self.alias==''
113 elsif self.alias==''
97 "(blank)"
114 "(blank)"
98 else
115 else
99 self.alias
116 self.alias
100 end
117 end
101 end
118 end
102
119
103 def alias_for_editing=(e)
120 def alias_for_editing=(e)
104 self.alias=e
121 self.alias=e
105 end
122 end
106
123
107 def activation_key
124 def activation_key
108 if self.hashed_password==nil
125 if self.hashed_password==nil
109 encrypt_new_password
126 encrypt_new_password
110 end
127 end
111 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
128 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
112 end
129 end
113
130
114 def verify_activation_key(key)
131 def verify_activation_key(key)
115 key == activation_key
132 key == activation_key
116 end
133 end
117
134
118 def self.random_password(length=5)
135 def self.random_password(length=5)
119 chars = 'abcdefghjkmnopqrstuvwxyz'
136 chars = 'abcdefghjkmnopqrstuvwxyz'
120 password = ''
137 password = ''
121 length.times { password << chars[rand(chars.length - 1)] }
138 length.times { password << chars[rand(chars.length - 1)] }
122 password
139 password
123 end
140 end
124
141
125 def self.find_non_admin_with_prefix(prefix='')
142 def self.find_non_admin_with_prefix(prefix='')
126 users = User.find(:all)
143 users = User.find(:all)
127 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
144 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
128 end
145 end
129
146
130 # Contest information
147 # Contest information
131
148
132 def self.find_users_with_no_contest()
149 def self.find_users_with_no_contest()
133 users = User.find(:all)
150 users = User.find(:all)
134 return users.find_all { |u| u.contests.length == 0 }
151 return users.find_all { |u| u.contests.length == 0 }
135 end
152 end
136
153
137
154
138 def contest_time_left
155 def contest_time_left
139 if GraderConfiguration.contest_mode?
156 if GraderConfiguration.contest_mode?
140 return nil if site==nil
157 return nil if site==nil
141 return site.time_left
158 return site.time_left
142 elsif GraderConfiguration.indv_contest_mode?
159 elsif GraderConfiguration.indv_contest_mode?
143 time_limit = GraderConfiguration.contest_time_limit
160 time_limit = GraderConfiguration.contest_time_limit
144 if time_limit == nil
161 if time_limit == nil
145 return nil
162 return nil
146 end
163 end
147 if contest_stat==nil or contest_stat.started_at==nil
164 if contest_stat==nil or contest_stat.started_at==nil
148 return (Time.now.gmtime + time_limit) - Time.now.gmtime
165 return (Time.now.gmtime + time_limit) - Time.now.gmtime
149 else
166 else
150 finish_time = contest_stat.started_at + time_limit
167 finish_time = contest_stat.started_at + time_limit
151 current_time = Time.now.gmtime
168 current_time = Time.now.gmtime
152 if current_time > finish_time
169 if current_time > finish_time
153 return 0
170 return 0
154 else
171 else
155 return finish_time - current_time
172 return finish_time - current_time
156 end
173 end
157 end
174 end
158 else
175 else
159 return nil
176 return nil
160 end
177 end
161 end
178 end
162
179
163 def contest_finished?
180 def contest_finished?
164 if GraderConfiguration.contest_mode?
181 if GraderConfiguration.contest_mode?
165 return false if site==nil
182 return false if site==nil
166 return site.finished?
183 return site.finished?
167 elsif GraderConfiguration.indv_contest_mode?
184 elsif GraderConfiguration.indv_contest_mode?
168 return false if self.contest_stat(true)==nil
185 return false if self.contest_stat(true)==nil
169 return contest_time_left == 0
186 return contest_time_left == 0
170 else
187 else
171 return false
188 return false
172 end
189 end
173 end
190 end
174
191
175 def contest_started?
192 def contest_started?
176 if GraderConfiguration.indv_contest_mode?
193 if GraderConfiguration.indv_contest_mode?
177 stat = self.contest_stat
194 stat = self.contest_stat
178 return ((stat != nil) and (stat.started_at != nil))
195 return ((stat != nil) and (stat.started_at != nil))
179 elsif GraderConfiguration.contest_mode?
196 elsif GraderConfiguration.contest_mode?
180 return true if site==nil
197 return true if site==nil
181 return site.started
198 return site.started
182 else
199 else
183 return true
200 return true
184 end
201 end
185 end
202 end
186
203
187 def update_start_time
204 def update_start_time
188 stat = self.contest_stat
205 stat = self.contest_stat
189 if stat == nil or stat.started_at == nil
206 if stat == nil or stat.started_at == nil
190 stat ||= UserContestStat.new(:user => self)
207 stat ||= UserContestStat.new(:user => self)
191 stat.started_at = Time.now.gmtime
208 stat.started_at = Time.now.gmtime
192 stat.save
209 stat.save
193 end
210 end
194 end
211 end
195
212
196 def problem_in_user_contests?(problem)
213 def problem_in_user_contests?(problem)
197 problem_contests = problem.contests.all
214 problem_contests = problem.contests.all
198
215
199 if problem_contests.length == 0 # this is public contest
216 if problem_contests.length == 0 # this is public contest
200 return true
217 return true
201 end
218 end
202
219
203 contests.each do |contest|
220 contests.each do |contest|
204 if problem_contests.find {|c| c.id == contest.id }
221 if problem_contests.find {|c| c.id == contest.id }
205 return true
222 return true
206 end
223 end
207 end
224 end
208 return false
225 return false
209 end
226 end
210
227
211 def available_problems_group_by_contests
228 def available_problems_group_by_contests
212 contest_problems = []
229 contest_problems = []
213 pin = {}
230 pin = {}
214 contests.enabled.each do |contest|
231 contests.enabled.each do |contest|
215 available_problems = contest.problems.available
232 available_problems = contest.problems.available
216 contest_problems << {
233 contest_problems << {
217 :contest => contest,
234 :contest => contest,
218 :problems => available_problems
235 :problems => available_problems
219 }
236 }
220 available_problems.each {|p| pin[p.id] = true}
237 available_problems.each {|p| pin[p.id] = true}
221 end
238 end
222 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
239 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
223 contest_problems << {
240 contest_problems << {
224 :contest => nil,
241 :contest => nil,
225 :problems => other_avaiable_problems
242 :problems => other_avaiable_problems
226 }
243 }
227 return contest_problems
244 return contest_problems
228 end
245 end
229
246
230 def available_problems
247 def available_problems
231 if not GraderConfiguration.multicontests?
248 if not GraderConfiguration.multicontests?
232 return Problem.find_available_problems
249 return Problem.find_available_problems
233 else
250 else
234 contest_problems = []
251 contest_problems = []
235 pin = {}
252 pin = {}
236 contests.enabled.each do |contest|
253 contests.enabled.each do |contest|
237 contest.problems.available.each do |problem|
254 contest.problems.available.each do |problem|
238 if not pin.has_key? problem.id
255 if not pin.has_key? problem.id
239 contest_problems << problem
256 contest_problems << problem
240 end
257 end
241 pin[problem.id] = true
258 pin[problem.id] = true
242 end
259 end
243 end
260 end
244 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
261 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
245 return contest_problems + other_avaiable_problems
262 return contest_problems + other_avaiable_problems
246 end
263 end
247 end
264 end
248
265
249 def can_view_problem?(problem)
266 def can_view_problem?(problem)
250 if not GraderConfiguration.multicontests?
267 if not GraderConfiguration.multicontests?
251 return problem.available
268 return problem.available
252 else
269 else
253 return problem_in_user_contests? problem
270 return problem_in_user_contests? problem
254 end
271 end
255 end
272 end
256
273
257 protected
274 protected
258 def encrypt_new_password
275 def encrypt_new_password
259 return if password.blank?
276 return if password.blank?
260 self.salt = (10+rand(90)).to_s
277 self.salt = (10+rand(90)).to_s
261 self.hashed_password = User.encrypt(self.password,self.salt)
278 self.hashed_password = User.encrypt(self.password,self.salt)
262 end
279 end
263
280
264 def assign_default_site
281 def assign_default_site
265 # have to catch error when migrating (because self.site is not available).
282 # have to catch error when migrating (because self.site is not available).
266 begin
283 begin
You need to be logged in to leave comments. Login now