Description:
update models to satisfy rails 4
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r618:45e8321629ae - - 7 files changed: 12 inserted, 16 deleted

@@ -1,8 +1,8
1 1 class Contest < ActiveRecord::Base
2 2
3 3 has_and_belongs_to_many :users
4 4 has_and_belongs_to_many :problems
5 5
6 - scope :enabled, :conditions => {:enabled => true}
6 + scope :enabled, -> { where(enabled: true) }
7 7
8 8 end
@@ -1,5 +1,4
1 1 class Login < ActiveRecord::Base
2 2 belongs_to :user
3 3
4 - attr_accessible :ip_address, :logged_in_at, :user_id
5 4 end
@@ -1,133 +1,133
1 1 class Problem < ActiveRecord::Base
2 2
3 3 belongs_to :description
4 4 has_and_belongs_to_many :contests, :uniq => true
5 5 has_many :test_pairs, :dependent => :delete_all
6 6 has_many :testcases, :dependent => :destroy
7 7
8 8 validates_presence_of :name
9 - validates_format_of :name, :with => /^\w+$/
9 + validates_format_of :name, :with => /\A\w+\z/
10 10 validates_presence_of :full_name
11 11
12 12 scope :available, :conditions => {:available => true}
13 13
14 14 DEFAULT_TIME_LIMIT = 1
15 15 DEFAULT_MEMORY_LIMIT = 32
16 16
17 17 def self.find_available_problems
18 18 Problem.available.all(:order => "date_added DESC, name ASC")
19 19 end
20 20
21 21 def self.create_from_import_form_params(params, old_problem=nil)
22 22 org_problem = old_problem || Problem.new
23 23 import_params, problem = Problem.extract_params_and_check(params,
24 24 org_problem)
25 25
26 26 if !problem.errors.empty?
27 27 return problem, 'Error importing'
28 28 end
29 29
30 30 problem.full_score = 100
31 31 problem.date_added = Time.new
32 32 problem.test_allowed = true
33 33 problem.output_only = false
34 34 problem.available = false
35 35
36 36 if not problem.save
37 37 return problem, 'Error importing'
38 38 end
39 39
40 40 import_to_db = params.has_key? :import_to_db
41 41
42 42 importer = TestdataImporter.new(problem)
43 43
44 44 if not importer.import_from_file(import_params[:file],
45 45 import_params[:time_limit],
46 46 import_params[:memory_limit],
47 47 import_params[:checker_name],
48 48 import_to_db)
49 49 problem.errors.add(:base,'Import error.')
50 50 end
51 51
52 52 return problem, importer.log_msg
53 53 end
54 54
55 55 def self.download_file_basedir
56 56 return "#{Rails.root}/data/tasks"
57 57 end
58 58
59 59 def get_submission_stat
60 60 result = Hash.new
61 61 #total number of submission
62 62 result[:total_sub] = Submission.where(problem_id: self.id).count
63 63 result[:attempted_user] = Submission.where(problem_id: self.id).group_by(:user_id)
64 64 end
65 65
66 66 def long_name
67 67 "[#{name}] #{full_name}"
68 68 end
69 69
70 70 protected
71 71
72 72 def self.to_i_or_default(st, default)
73 73 if st!=''
74 74 result = st.to_i
75 75 end
76 76 result ||= default
77 77 end
78 78
79 79 def self.to_f_or_default(st, default)
80 80 if st!=''
81 81 result = st.to_f
82 82 end
83 83 result ||= default
84 84 end
85 85
86 86 def self.extract_params_and_check(params, problem)
87 87 time_limit = Problem.to_f_or_default(params[:time_limit],
88 88 DEFAULT_TIME_LIMIT)
89 89 memory_limit = Problem.to_i_or_default(params[:memory_limit],
90 90 DEFAULT_MEMORY_LIMIT)
91 91
92 92 if time_limit<=0 or time_limit >60
93 93 problem.errors.add(:base,'Time limit out of range.')
94 94 end
95 95
96 96 if memory_limit==0 and params[:memory_limit]!='0'
97 97 problem.errors.add(:base,'Memory limit format errors.')
98 98 elsif memory_limit<=0 or memory_limit >512
99 99 problem.errors.add(:base,'Memory limit out of range.')
100 100 end
101 101
102 102 if params[:file]==nil or params[:file]==''
103 103 problem.errors.add(:base,'No testdata file.')
104 104 end
105 105
106 106 checker_name = 'text'
107 107 if ['text','float'].include? params[:checker]
108 108 checker_name = params[:checker]
109 109 end
110 110
111 111 file = params[:file]
112 112
113 113 if !problem.errors.empty?
114 114 return nil, problem
115 115 end
116 116
117 117 problem.name = params[:name]
118 118 if params[:full_name]!=''
119 119 problem.full_name = params[:full_name]
120 120 else
121 121 problem.full_name = params[:name]
122 122 end
123 123
124 124 return [{
125 125 :time_limit => time_limit,
126 126 :memory_limit => memory_limit,
127 127 :file => file,
128 128 :checker_name => checker_name
129 129 },
130 130 problem]
131 131 end
132 132
133 133 end
@@ -1,3 +1,3
1 1 class SubmissionViewLog < ActiveRecord::Base
2 - attr_accessible :submission_id, :user_id
2 + #attr_accessible :submission_id, :user_id
3 3 end
@@ -1,157 +1,156
1 1 #
2 2 # A TestRequest is a composition of submission with user's testdata.
3 3 #
4 4 # Note about TestRequest#problem: Usually, A TestRequest has to be
5 5 # associated with a problem, so that execution environment can be
6 6 # determined. However, to be more flexible, we have to ensure that
7 7 # it works as well with problem=nil. In this case, we shall provide
8 8 # a "default" execution environment for it. This can be done
9 9 # seamlessly by using TestRequest#problem_name or
10 10 # TestRequest#name_of(problem) when retrieving the name of the
11 11 # problem: #name_of would return problem.name when problem!=nil and
12 12 # it would return "default" when problem=nil, #problem_name just
13 13 # call #name_of.
14 14 #
15 15
16 16 require 'fileutils'
17 17
18 18 class TestRequest < Task
19 -
20 - set_table_name "test_requests"
19 + self.table_name = "test_requests"
21 20
22 21 belongs_to :user
23 22 belongs_to :problem
24 23 belongs_to :submission
25 24
26 25 validates_presence_of :submission
27 26 validate :must_have_valid_problem
28 27
29 28 def problem_name
30 29 TestRequest.name_of(self.problem)
31 30 end
32 31
33 32 def language
34 33 self.submission.language
35 34 end
36 35
37 36 def self.get_inqueue_and_change_status(status)
38 37 # since there will be only one grader grading TestRequest
39 38 # we do not need locking (hopefully)
40 39
41 40 test_request = TestRequest.find(:first,
42 41 :order => "created_at",
43 42 :conditions => {:status=> Task::STATUS_INQUEUE})
44 43 if test_request!=nil
45 44 test_request.status = status
46 45 test_request.save!
47 46 end
48 47
49 48 test_request
50 49 end
51 50
52 51 # interfacing with form
53 52 def self.new_from_form_params(user,params)
54 53 test_request = TestRequest.new
55 54 test_request.user = user
56 55 begin
57 56 problem = Problem.find(params[:problem_id])
58 57 rescue ActiveRecord::RecordNotFound
59 58 problem = nil
60 59 end
61 60 test_request.problem = problem
62 61 if problem!=nil
63 62 test_request.submission =
64 63 Submission.find_by_user_problem_number(user.id,
65 64 problem.id,
66 65 params[:submission_number])
67 66 else
68 67 test_request.submission = nil
69 68 end
70 69
71 70 # checks if the user submits any input file
72 71 if params[:input_file]==nil or params[:input_file]==""
73 72 test_request.errors.add(:base,"No input submitted.")
74 73 test_request.input_file_name = nil
75 74 else
76 75 test_request.input_file_name = save_input_file(params[:input_file], user, problem)
77 76 if test_request.input_file_name == nil
78 77 test_request.errors.adds(:base,"No input submitted.")
79 78 end
80 79 if params[:additional_file]!=nil and params[:additional_file]!=""
81 80 save_additional_file(params[:additional_file],
82 81 "#{test_request.input_file_name}.files")
83 82 end
84 83 end
85 84 test_request.submitted_at = Time.new.gmtime
86 85 test_request.status_inqueue
87 86 test_request
88 87 end
89 88
90 89 protected
91 90
92 91 def self.name_of(problem)
93 92 if problem!=nil
94 93 problem.name
95 94 else
96 95 "default"
97 96 end
98 97 end
99 98
100 99 def self.random_input_file_name(user,problem)
101 100 problem_name = TestRequest.name_of(problem)
102 101 begin
103 102 tmpname = TEST_REQUEST_INPUT_FILE_DIR + "/#{user.login}/#{problem_name}/#{rand(10000)}"
104 103 end while File.exists?(tmpname)
105 104 tmpname
106 105 end
107 106
108 107 def self.save_input_file(tempfile, user, problem)
109 108 new_file_name = random_input_file_name(user,problem)
110 109 dirname = File.dirname(new_file_name)
111 110 FileUtils.mkdir_p(File.dirname(new_file_name)) if !File.exists?(dirname)
112 111
113 112 # when the user did not submit any file
114 113 return nil if tempfile==""
115 114
116 115 if tempfile.instance_of?(Tempfile)
117 116 tempfile.close
118 117 FileUtils.move(tempfile.path,new_file_name)
119 118 else
120 119 File.open(new_file_name, "wb") do |f|
121 120 f.write(tempfile.read)
122 121 end
123 122 end
124 123 new_file_name
125 124 end
126 125
127 126 def self.save_additional_file(tempfile,dir)
128 127 new_file_name = "#{dir}/#{tempfile.original_filename}"
129 128 dirname = File.dirname(new_file_name)
130 129 FileUtils.mkdir_p(File.dirname(new_file_name)) if !File.exists?(dirname)
131 130
132 131 # when the user did not submit any file
133 132 return nil if tempfile==""
134 133
135 134 if tempfile.instance_of?(Tempfile)
136 135 tempfile.close
137 136 FileUtils.move(tempfile.path,new_file_name)
138 137 else
139 138 File.open(new_file_name, "wb") do |f|
140 139 f.write(tempfile.read)
141 140 end
142 141 end
143 142 new_file_name
144 143 end
145 144
146 145 #
147 146 # validations
148 147 #
149 148 def must_have_valid_problem
150 149 if problem==nil
151 150 errors.add('problem',"must be specified.")
152 151 elsif (!problem.available) and (self.new_record?)
153 152 errors.add('problem',"must be valid.")
154 153 end
155 154 end
156 155
157 156 end
@@ -1,4 +1,4
1 1 class Testcase < ActiveRecord::Base
2 2 belongs_to :problem
3 - attr_accessible :group, :input, :num, :score, :sol
3 + #attr_accessible :group, :input, :num, :score, :sol
4 4 end
@@ -1,381 +1,379
1 1 require 'digest/sha1'
2 2 require 'net/pop'
3 3 require 'net/https'
4 4 require 'net/http'
5 5 require 'json'
6 6
7 7 class User < ActiveRecord::Base
8 8
9 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, -> { order(created_at: DESC) },
14 14 :class_name => "Message",
15 - :foreign_key => "sender_id",
16 - :order => 'created_at DESC'
15 + :foreign_key => "sender_id"
17 16
18 - has_many :replied_messages,
17 + has_many :replied_messages, -> { order(created_at: DESC) },
19 18 :class_name => "Message",
20 - :foreign_key => "receiver_id",
21 - :order => 'created_at DESC'
19 + :foreign_key => "receiver_id"
22 20
23 21 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
24 22
25 23 belongs_to :site
26 24 belongs_to :country
27 25
28 - has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
26 + has_and_belongs_to_many :contests, -> { order(:name); uniq}
29 27
30 - scope :activated_users, :conditions => {:activated => true}
28 + scope :activated_users, -> {where activated: true}
31 29
32 30 validates_presence_of :login
33 31 validates_uniqueness_of :login
34 32 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
35 33 validates_length_of :login, :within => 3..30
36 34
37 35 validates_presence_of :full_name
38 36 validates_length_of :full_name, :minimum => 1
39 37
40 38 validates_presence_of :password, :if => :password_required?
41 39 validates_length_of :password, :within => 4..20, :if => :password_required?
42 40 validates_confirmation_of :password, :if => :password_required?
43 41
44 42 validates_format_of :email,
45 43 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
46 44 :if => :email_validation?
47 45 validate :uniqueness_of_email_from_activated_users,
48 46 :if => :email_validation?
49 47 validate :enough_time_interval_between_same_email_registrations,
50 48 :if => :email_validation?
51 49
52 50 # these are for ytopc
53 51 # disable for now
54 52 #validates_presence_of :province
55 53
56 54 attr_accessor :password
57 55
58 56 before_save :encrypt_new_password
59 57 before_save :assign_default_site
60 58 before_save :assign_default_contest
61 59
62 60 # this is for will_paginate
63 61 cattr_reader :per_page
64 62 @@per_page = 50
65 63
66 64 def self.authenticate(login, password)
67 65 user = find_by_login(login)
68 66 if user
69 67 return user if user.authenticated?(password)
70 68 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
71 69 user.password = password
72 70 user.save
73 71 return user
74 72 end
75 73 end
76 74 end
77 75
78 76 def authenticated?(password)
79 77 if self.activated
80 78 hashed_password == User.encrypt(password,self.salt)
81 79 else
82 80 false
83 81 end
84 82 end
85 83
86 84 def authenticated_by_pop3?(password)
87 85 Net::POP3.enable_ssl
88 86 pop = Net::POP3.new('pops.it.chula.ac.th')
89 87 authen = true
90 88 begin
91 89 pop.start(login, password)
92 90 pop.finish
93 91 return true
94 92 rescue
95 93 return false
96 94 end
97 95 end
98 96
99 97 def authenticated_by_cucas?(password)
100 98 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
101 99 appid = '41508763e340d5858c00f8c1a0f5a2bb'
102 100 appsecret ='d9cbb5863091dbe186fded85722a1e31'
103 101 post_args = {
104 102 'appid' => appid,
105 103 'appsecret' => appsecret,
106 104 'username' => login,
107 105 'password' => password
108 106 }
109 107
110 108 #simple call
111 109 begin
112 110 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
113 111 http.use_ssl = true
114 112 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
115 113 result = [ ]
116 114 http.start do |http|
117 115 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
118 116 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
119 117 resp = http.request(req,param)
120 118 result = JSON.parse resp.body
121 119 end
122 120 return true if result["type"] == "beanStudent"
123 121 rescue => e
124 122 return false
125 123 end
126 124 return false
127 125 end
128 126
129 127 def admin?
130 128 self.roles.detect {|r| r.name == 'admin' }
131 129 end
132 130
133 131 def email_for_editing
134 132 if self.email==nil
135 133 "(unknown)"
136 134 elsif self.email==''
137 135 "(blank)"
138 136 else
139 137 self.email
140 138 end
141 139 end
142 140
143 141 def email_for_editing=(e)
144 142 self.email=e
145 143 end
146 144
147 145 def alias_for_editing
148 146 if self.alias==nil
149 147 "(unknown)"
150 148 elsif self.alias==''
151 149 "(blank)"
152 150 else
153 151 self.alias
154 152 end
155 153 end
156 154
157 155 def alias_for_editing=(e)
158 156 self.alias=e
159 157 end
160 158
161 159 def activation_key
162 160 if self.hashed_password==nil
163 161 encrypt_new_password
164 162 end
165 163 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
166 164 end
167 165
168 166 def verify_activation_key(key)
169 167 key == activation_key
170 168 end
171 169
172 170 def self.random_password(length=5)
173 171 chars = 'abcdefghjkmnopqrstuvwxyz'
174 172 password = ''
175 173 length.times { password << chars[rand(chars.length - 1)] }
176 174 password
177 175 end
178 176
179 177 def self.find_non_admin_with_prefix(prefix='')
180 178 users = User.find(:all)
181 179 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
182 180 end
183 181
184 182 # Contest information
185 183
186 184 def self.find_users_with_no_contest()
187 185 users = User.find(:all)
188 186 return users.find_all { |u| u.contests.length == 0 }
189 187 end
190 188
191 189
192 190 def contest_time_left
193 191 if GraderConfiguration.contest_mode?
194 192 return nil if site==nil
195 193 return site.time_left
196 194 elsif GraderConfiguration.indv_contest_mode?
197 195 time_limit = GraderConfiguration.contest_time_limit
198 196 if time_limit == nil
199 197 return nil
200 198 end
201 199 if contest_stat==nil or contest_stat.started_at==nil
202 200 return (Time.now.gmtime + time_limit) - Time.now.gmtime
203 201 else
204 202 finish_time = contest_stat.started_at + time_limit
205 203 current_time = Time.now.gmtime
206 204 if current_time > finish_time
207 205 return 0
208 206 else
209 207 return finish_time - current_time
210 208 end
211 209 end
212 210 else
213 211 return nil
214 212 end
215 213 end
216 214
217 215 def contest_finished?
218 216 if GraderConfiguration.contest_mode?
219 217 return false if site==nil
220 218 return site.finished?
221 219 elsif GraderConfiguration.indv_contest_mode?
222 220 return false if self.contest_stat(true)==nil
223 221 return contest_time_left == 0
224 222 else
225 223 return false
226 224 end
227 225 end
228 226
229 227 def contest_started?
230 228 if GraderConfiguration.indv_contest_mode?
231 229 stat = self.contest_stat
232 230 return ((stat != nil) and (stat.started_at != nil))
233 231 elsif GraderConfiguration.contest_mode?
234 232 return true if site==nil
235 233 return site.started
236 234 else
237 235 return true
238 236 end
239 237 end
240 238
241 239 def update_start_time
242 240 stat = self.contest_stat
243 241 if stat.nil? or stat.started_at.nil?
244 242 stat ||= UserContestStat.new(:user => self)
245 243 stat.started_at = Time.now.gmtime
246 244 stat.save
247 245 end
248 246 end
249 247
250 248 def problem_in_user_contests?(problem)
251 249 problem_contests = problem.contests.all
252 250
253 251 if problem_contests.length == 0 # this is public contest
254 252 return true
255 253 end
256 254
257 255 contests.each do |contest|
258 256 if problem_contests.find {|c| c.id == contest.id }
259 257 return true
260 258 end
261 259 end
262 260 return false
263 261 end
264 262
265 263 def available_problems_group_by_contests
266 264 contest_problems = []
267 265 pin = {}
268 266 contests.enabled.each do |contest|
269 267 available_problems = contest.problems.available
270 268 contest_problems << {
271 269 :contest => contest,
272 270 :problems => available_problems
273 271 }
274 272 available_problems.each {|p| pin[p.id] = true}
275 273 end
276 274 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
277 275 contest_problems << {
278 276 :contest => nil,
279 277 :problems => other_avaiable_problems
280 278 }
281 279 return contest_problems
282 280 end
283 281
284 282 def available_problems
285 283 if not GraderConfiguration.multicontests?
286 284 return Problem.find_available_problems
287 285 else
288 286 contest_problems = []
289 287 pin = {}
290 288 contests.enabled.each do |contest|
291 289 contest.problems.available.each do |problem|
292 290 if not pin.has_key? problem.id
293 291 contest_problems << problem
294 292 end
295 293 pin[problem.id] = true
296 294 end
297 295 end
298 296 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
299 297 return contest_problems + other_avaiable_problems
300 298 end
301 299 end
302 300
303 301 def can_view_problem?(problem)
304 302 if not GraderConfiguration.multicontests?
305 303 return problem.available
306 304 else
307 305 return problem_in_user_contests? problem
308 306 end
309 307 end
310 308
311 309 def self.clear_last_login
312 310 User.update_all(:last_ip => nil)
313 311 end
314 312
315 313 protected
316 314 def encrypt_new_password
317 315 return if password.blank?
318 316 self.salt = (10+rand(90)).to_s
319 317 self.hashed_password = User.encrypt(self.password,self.salt)
320 318 end
321 319
322 320 def assign_default_site
323 321 # have to catch error when migrating (because self.site is not available).
324 322 begin
325 323 if self.site==nil
326 324 self.site = Site.find_by_name('default')
327 325 if self.site==nil
328 326 self.site = Site.find(1) # when 'default has be renamed'
329 327 end
330 328 end
331 329 rescue
332 330 end
333 331 end
334 332
335 333 def assign_default_contest
336 334 # have to catch error when migrating (because self.site is not available).
337 335 begin
338 336 if self.contests.length == 0
339 337 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
340 338 if default_contest
341 339 self.contests = [default_contest]
342 340 end
343 341 end
344 342 rescue
345 343 end
346 344 end
347 345
348 346 def password_required?
349 347 self.hashed_password.blank? || !self.password.blank?
350 348 end
351 349
352 350 def self.encrypt(string,salt)
353 351 Digest::SHA1.hexdigest(salt + string)
354 352 end
355 353
356 354 def uniqueness_of_email_from_activated_users
357 355 user = User.activated_users.find_by_email(self.email)
358 356 if user and (user.login != self.login)
359 357 self.errors.add(:base,"Email has already been taken")
360 358 end
361 359 end
362 360
363 361 def enough_time_interval_between_same_email_registrations
364 362 return if !self.new_record?
365 363 return if self.activated
366 364 open_user = User.find_by_email(self.email,
367 365 :order => 'created_at DESC')
368 366 if open_user and open_user.created_at and
369 367 (open_user.created_at > Time.now.gmtime - 5.minutes)
370 368 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
371 369 end
372 370 end
373 371
374 372 def email_validation?
375 373 begin
376 374 return VALIDATE_USER_EMAILS
377 375 rescue
378 376 return false
379 377 end
380 378 end
381 379 end
You need to be logged in to leave comments. Login now