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

r405:f3f0ea35cff3 - - 1 file changed: 43 inserted, 4 deleted

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