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: 41 inserted, 2 deleted

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