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

r688:b31aedc6a96e - - 1 file changed: 14 inserted, 9 deleted

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