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

r833:913658e11037 - - 1 file changed: 43 inserted, 0 deleted

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