Description:
bring back cucas login to algo-bm
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r496:038086c2ebdc - - 1 file changed: 47 inserted, 0 deleted

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