Description:
bring back cucas login to algo-bm
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r496:038086c2ebdc - - 1 file changed: 47 inserted, 0 deleted

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