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

r845:daf5f8de8a3f - - 1 file changed: 4 inserted, 0 deleted

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