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

r846:4279bf26f98b - - 1 file changed: 78 inserted, 5 deleted

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