Description:
added codejom_status model for computing level with basic user update
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r219:95cc49d72ca8 - - 9 files changed: 79 inserted, 1 deleted

@@ -0,0 +1,5
1 + class CodejomStatus < ActiveRecord::Base
2 +
3 + belongs_to :user
4 +
5 + end
@@ -0,0 +1,15
1 + class CreateCodejomStatuses < ActiveRecord::Migration
2 + def self.up
3 + create_table :codejom_statuses do |t|
4 + t.integer :user_id
5 + t.boolean :alive
6 + t.integer :num_problems_passed
7 +
8 + t.timestamps
9 + end
10 + end
11 +
12 + def self.down
13 + drop_table :codejom_statuses
14 + end
15 + end
@@ -0,0 +1,11
1 + # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 +
3 + one:
4 + user_id: 1
5 + alive: false
6 + num_problems_passed: 1
7 +
8 + two:
9 + user_id: 1
10 + alive: false
11 + num_problems_passed: 1
@@ -0,0 +1,8
1 + require 'test_helper'
2 +
3 + class CodejomStatusTest < ActiveSupport::TestCase
4 + # Replace this with your real tests.
5 + test "the truth" do
6 + assert true
7 + end
8 + end
@@ -1,408 +1,409
1 1 class MainController < ApplicationController
2 2
3 3 before_filter :authenticate, :except => [:index, :login]
4 4 before_filter :check_viewability, :except => [:index, :login]
5 5
6 6 # COMMENTED OUT: filter in each action instead
7 7 # before_filter :verify_time_limit, :only => [:submit]
8 8
9 9 verify :method => :post, :only => [:submit, :download_input, :submit_solution],
10 10 :redirect_to => { :action => :index }
11 11
12 12 # COMMENT OUT: only need when having high load
13 13 # caches_action :index, :login
14 14
15 15 # NOTE: This method is not actually needed, 'config/routes.rb' has
16 16 # assigned action login as a default action.
17 17 def index
18 18 redirect_to :action => 'login'
19 19 end
20 20
21 21 def login
22 22 saved_notice = flash[:notice]
23 23 reset_session
24 24 flash[:notice] = saved_notice
25 25
26 26 # EXPERIMENT:
27 27 # Hide login if in single user mode and the url does not
28 28 # explicitly specify /login
29 29 #
30 30 # logger.info "PATH: #{request.path}"
31 31 # if Configuration['system.single_user_mode'] and
32 32 # request.path!='/main/login'
33 33 # @hidelogin = true
34 34 # end
35 35
36 36 @announcements = Announcement.find_for_frontpage
37 37 render :action => 'login', :layout => 'empty'
38 38 end
39 39
40 40 def list
41 41 prepare_list_information
42 42 end
43 43
44 44 def help
45 45 @user = User.find(session[:user_id])
46 46 end
47 47
48 48 def submit
49 49 user = User.find(session[:user_id])
50 50
51 51 @submission = Submission.new(params[:submission])
52 52 @submission.user = user
53 53 @submission.language_id = 0
54 54 if (params['file']) and (params['file']!='')
55 55 @submission.source = params['file'].read
56 56 @submission.source_filename = params['file'].original_filename
57 57 end
58 58 @submission.submitted_at = Time.new.gmtime
59 59
60 60 if Configuration.time_limit_mode? and user.contest_finished?
61 61 @submission.errors.add_to_base "The contest is over."
62 62 prepare_list_information
63 63 render :action => 'list' and return
64 64 end
65 65
66 66 if @submission.valid?
67 67 if @submission.save == false
68 68 flash[:notice] = 'Error saving your submission'
69 69 elsif Task.create(:submission_id => @submission.id,
70 70 :status => Task::STATUS_INQUEUE) == false
71 71 flash[:notice] = 'Error adding your submission to task queue'
72 72 end
73 73 else
74 74 prepare_list_information
75 75 render :action => 'list' and return
76 76 end
77 77 redirect_to :action => 'list'
78 78 end
79 79
80 80 def source
81 81 submission = Submission.find(params[:id])
82 82 if submission.user_id == session[:user_id]
83 83 send_data(submission.source,
84 84 {:filename => submission.download_filename,
85 85 :type => 'text/plain'})
86 86 else
87 87 flash[:notice] = 'Error viewing source'
88 88 redirect_to :action => 'list'
89 89 end
90 90 end
91 91
92 92 def compiler_msg
93 93 @submission = Submission.find(params[:id])
94 94 if @submission.user_id == session[:user_id]
95 95 render :action => 'compiler_msg', :layout => 'empty'
96 96 else
97 97 flash[:notice] = 'Error viewing source'
98 98 redirect_to :action => 'list'
99 99 end
100 100 end
101 101
102 102 def submission
103 103 @user = User.find(session[:user_id])
104 104 @problems = Problem.find_available_problems
105 105 if params[:id]==nil
106 106 @problem = nil
107 107 @submissions = nil
108 108 else
109 109 @problem = Problem.find_by_name(params[:id])
110 110 if not @problem.available
111 111 redirect_to :action => 'list'
112 112 flash[:notice] = 'Error: submissions for that problem are not viewable.'
113 113 return
114 114 end
115 115 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
116 116 end
117 117 end
118 118
119 119 def result
120 120 if !Configuration.show_grading_result
121 121 redirect_to :action => 'list' and return
122 122 end
123 123 @user = User.find(session[:user_id])
124 124 @submission = Submission.find(params[:id])
125 125 if @submission.user!=@user
126 126 flash[:notice] = 'You are not allowed to view result of other users.'
127 127 redirect_to :action => 'list' and return
128 128 end
129 129 prepare_grading_result(@submission)
130 130 end
131 131
132 132 def load_output
133 133 if !Configuration.show_grading_result or params[:num]==nil
134 134 redirect_to :action => 'list' and return
135 135 end
136 136 @user = User.find(session[:user_id])
137 137 @submission = Submission.find(params[:id])
138 138 if @submission.user!=@user
139 139 flash[:notice] = 'You are not allowed to view result of other users.'
140 140 redirect_to :action => 'list' and return
141 141 end
142 142 case_num = params[:num].to_i
143 143 out_filename = output_filename(@user.login,
144 144 @submission.problem.name,
145 145 @submission.id,
146 146 case_num)
147 147 if !FileTest.exists?(out_filename)
148 148 flash[:notice] = 'Output not found.'
149 149 redirect_to :action => 'list' and return
150 150 end
151 151
152 152 response.headers['Content-Type'] = "application/force-download"
153 153 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
154 154 response.headers["X-Sendfile"] = out_filename
155 155 response.headers['Content-length'] = File.size(out_filename)
156 156 render :nothing => true
157 157 end
158 158
159 159 def error
160 160 @user = User.find(session[:user_id])
161 161 end
162 162
163 163 # announcement refreshing and hiding methods
164 164
165 165 def announcements
166 166 if params.has_key? 'recent'
167 167 prepare_announcements(params[:recent])
168 168 else
169 169 prepare_announcements
170 170 end
171 171 render(:partial => 'announcement',
172 172 :collection => @announcements,
173 173 :locals => {:announcement_effect => true})
174 174 end
175 175
176 176 #
177 177 # actions for Code Jom
178 178 #
179 179 def download_input
180 180 problem = Problem.find(params[:id])
181 181 user = User.find(session[:user_id])
182 182 if user.can_request_new_test_pair_for? problem
183 183 assignment = user.get_new_test_pair_assignment_for problem
184 184 assignment.save
185 185
186 186 send_data(assignment.test_pair.input,
187 187 { :filename => "#{problem.name}-#{assignment.request_number}.in",
188 188 :type => 'text/plain' })
189 189 else
190 190 recent_assignment = user.get_recent_test_pair_assignment_for problem
191 191 send_data(recent_assignment.test_pair.input,
192 192 { :filename => "#{problem.name}-#{recent_assignment.request_number}.in",
193 193 :type => 'text/plain' })
194 194 end
195 195 end
196 196
197 197 def submit_solution
198 198 problem = Problem.find(params[:id])
199 199 user = User.find(session[:user_id])
200 200 recent_assignment = user.get_recent_test_pair_assignment_for problem
201 201 if recent_assignment == nil
202 202 flash[:notice] = 'You have not requested for any input data for this problem. Please download an input first.'
203 203 redirect_to :action => 'list' and return
204 204 end
205 205
206 206 if recent_assignment.submitted
207 207 flash[:notice] = 'You have already submitted an incorrect solution for this input. Please download a new input data.'
208 208 redirect_to :action => 'list' and return
209 209 end
210 210
211 211 if params[:file] == nil
212 212 flash[:notice] = 'You have not submitted any output.'
213 213 redirect_to :action => 'list' and return
214 214 end
215 215
216 216 submitted_solution = params[:file].read
217 217 test_pair = recent_assignment.test_pair
218 218 passed = test_pair.grade(submitted_solution)
219 219 points = passed ? 100 : 0
220 220 submission = Submission.new(:user => user,
221 221 :problem => problem,
222 222 :source => submitted_solution,
223 223 :source_filename => params['file'].original_filename,
224 224 :language_id => 0,
225 225 :submitted_at => Time.new.gmtime,
226 226 :graded_at => Time.new.gmtime,
227 227 :points => points)
228 228 submission.save
229 229 recent_assignment.submitted = true
230 230 recent_assignment.save
231 231
232 232 status = user.get_submission_status_for(problem)
233 233 if status == nil
234 234 status = SubmissionStatus.new :user => user, :problem => problem, :submission_count => 0
235 235 end
236 236
237 237 status.submission_count += 1
238 238 status.passed = passed
239 239 status.save
240 240
241 241 if passed
242 242 flash[:notice] = 'Correct solution.'
243 + user.update_codejom_status
243 244 else
244 245 flash[:notice] = 'Incorrect solution.'
245 246 end
246 247 redirect_to :action => 'list'
247 248 end
248 249
249 250 protected
250 251
251 252 def prepare_announcements(recent=nil)
252 253 if Configuration.show_tasks_to?(@user)
253 254 @announcements = Announcement.find_published(true)
254 255 else
255 256 @announcements = Announcement.find_published
256 257 end
257 258 if recent!=nil
258 259 recent_id = recent.to_i
259 260 @announcements = @announcements.find_all { |a| a.id > recent_id }
260 261 end
261 262 end
262 263
263 264 def prepare_list_information
264 265 @user = User.find(session[:user_id])
265 266
266 267 all_problems = Problem.find_available_problems
267 268
268 269 passed = {}
269 270 sub_count = {}
270 271 @user.submission_statuses.each do |status|
271 272 if status.passed
272 273 passed[status.problem_id] = true
273 274 end
274 275 sub_count[status.problem_id] = status.submission_count
275 276 end
276 277
277 278 @problems = all_problems.reject { |problem| passed.has_key? problem.id }
278 279
279 280 @prob_submissions = Array.new
280 281 @problems.each do |p|
281 282 if sub_count.has_key? p.id
282 283 @prob_submissions << { :count => sub_count[p.id] }
283 284 else
284 285 @prob_submissions << { :count => 0 }
285 286 end
286 287 end
287 288 prepare_announcements
288 289 end
289 290
290 291 def check_viewability
291 292 @user = User.find(session[:user_id])
292 293 if (!Configuration.show_tasks_to?(@user)) and
293 294 ((action_name=='submission') or (action_name=='submit'))
294 295 redirect_to :action => 'list' and return
295 296 end
296 297 end
297 298
298 299 def prepare_grading_result(submission)
299 300 if Configuration.task_grading_info.has_key? submission.problem.name
300 301 grading_info = Configuration.task_grading_info[submission.problem.name]
301 302 else
302 303 # guess task info from problem.full_score
303 304 cases = submission.problem.full_score / 10
304 305 grading_info = {
305 306 'testruns' => cases,
306 307 'testcases' => cases
307 308 }
308 309 end
309 310 @test_runs = []
310 311 if grading_info['testruns'].is_a? Integer
311 312 trun_count = grading_info['testruns']
312 313 trun_count.times do |i|
313 314 @test_runs << [ read_grading_result(@user.login,
314 315 submission.problem.name,
315 316 submission.id,
316 317 i+1) ]
317 318 end
318 319 else
319 320 grading_info['testruns'].keys.sort.each do |num|
320 321 run = []
321 322 testrun = grading_info['testruns'][num]
322 323 testrun.each do |c|
323 324 run << read_grading_result(@user.login,
324 325 submission.problem.name,
325 326 submission.id,
326 327 c)
327 328 end
328 329 @test_runs << run
329 330 end
330 331 end
331 332 end
332 333
333 334 def grading_result_dir(user_name, problem_name, submission_id, case_num)
334 335 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
335 336 end
336 337
337 338 def output_filename(user_name, problem_name, submission_id, case_num)
338 339 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
339 340 return "#{dir}/output.txt"
340 341 end
341 342
342 343 def read_grading_result(user_name, problem_name, submission_id, case_num)
343 344 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
344 345 result_file_name = "#{dir}/result"
345 346 if !FileTest.exists?(result_file_name)
346 347 return {:num => case_num, :msg => 'program did not run'}
347 348 else
348 349 results = File.open(result_file_name).readlines
349 350 run_stat = extract_running_stat(results)
350 351 output_filename = "#{dir}/output.txt"
351 352 if FileTest.exists?(output_filename)
352 353 output_file = true
353 354 output_size = File.size(output_filename)
354 355 else
355 356 output_file = false
356 357 output_size = 0
357 358 end
358 359
359 360 return {
360 361 :num => case_num,
361 362 :msg => results[0],
362 363 :run_stat => run_stat,
363 364 :output => output_file,
364 365 :output_size => output_size
365 366 }
366 367 end
367 368 end
368 369
369 370 # copied from grader/script/lib/test_request_helper.rb
370 371 def extract_running_stat(results)
371 372 running_stat_line = results[-1]
372 373
373 374 # extract exit status line
374 375 run_stat = ""
375 376 if !(/[Cc]orrect/.match(results[0]))
376 377 run_stat = results[0].chomp
377 378 else
378 379 run_stat = 'Program exited normally'
379 380 end
380 381
381 382 logger.info "Stat line: #{running_stat_line}"
382 383
383 384 # extract running time
384 385 if res = /r(.*)u(.*)s/.match(running_stat_line)
385 386 seconds = (res[1].to_f + res[2].to_f)
386 387 time_stat = "Time used: #{seconds} sec."
387 388 else
388 389 seconds = nil
389 390 time_stat = "Time used: n/a sec."
390 391 end
391 392
392 393 # extract memory usage
393 394 if res = /s(.*)m/.match(running_stat_line)
394 395 memory_used = res[1].to_i
395 396 else
396 397 memory_used = -1
397 398 end
398 399
399 400 return {
400 401 :msg => "#{run_stat}\n#{time_stat}",
401 402 :running_time => seconds,
402 403 :exit_status => run_stat,
403 404 :memory_usage => memory_used
404 405 }
405 406 end
406 407
407 408 end
408 409
@@ -1,116 +1,121
1 1 class Problem < ActiveRecord::Base
2 2
3 3 belongs_to :description
4 4 has_many :test_pairs, :dependent => :delete_all
5 5
6 6 validates_presence_of :name
7 7 validates_format_of :name, :with => /^\w+$/
8 8 validates_presence_of :full_name
9 9
10 10 DEFAULT_TIME_LIMIT = 1
11 11 DEFAULT_MEMORY_LIMIT = 32
12 12
13 13 def test_pair_count
14 14 @test_pair_count ||= test_pairs.size
15 15 end
16 16
17 17 def uses_random_test_pair?
18 18 test_pair_count != 0
19 19 end
20 20
21 21 def random_test_pair(forbidden_numbers=nil)
22 22 begin
23 23 test_num = 1 + rand(test_pair_count)
24 24 end while forbidden_numbers!=nil and forbidden_numbers.include? test_num
25 25 test_pairs.find_by_number test_num
26 26 end
27 27
28 28 def self.find_available_problems
29 29 find(:all, :conditions => {:available => true}, :order => "date_added DESC")
30 30 end
31 31
32 + # TODO: may try to optimize this using cache
33 + def self.available_problem_count
34 + return Problem.find_available_problems.length
35 + end
36 +
32 37 def self.create_from_import_form_params(params, old_problem=nil)
33 38 problem = old_problem || Problem.new
34 39 import_params = Problem.extract_params_and_check(params, problem)
35 40
36 41 if not problem.valid?
37 42 return problem, 'Error importing'
38 43 end
39 44
40 45 problem.full_score = 100
41 46 problem.date_added = Time.new
42 47 problem.test_allowed = true
43 48 problem.output_only = false
44 49 problem.available = false
45 50
46 51 if not problem.save
47 52 return problem, 'Error importing'
48 53 end
49 54
50 55 import_to_db = params.has_key? :import_to_db
51 56
52 57 importer = TestdataImporter.new(problem)
53 58
54 59 if not importer.import_from_file(import_params[:file],
55 60 import_params[:time_limit],
56 61 import_params[:memory_limit],
57 62 import_to_db)
58 63 problem.errors.add_to_base('Import error.')
59 64 end
60 65
61 66 return problem, importer.log_msg
62 67 end
63 68
64 69 protected
65 70
66 71 def self.to_i_or_default(st, default)
67 72 if st!=''
68 73 st.to_i
69 74 else
70 75 default
71 76 end
72 77 end
73 78
74 79 def self.extract_params_and_check(params, problem)
75 80 time_limit = Problem.to_i_or_default(params[:time_limit],
76 81 DEFAULT_TIME_LIMIT)
77 82 memory_limit = Problem.to_i_or_default(params[:memory_limit],
78 83 DEFAULT_MEMORY_LIMIT)
79 84
80 85 if time_limit==0 and time_limit_s!='0'
81 86 problem.errors.add_to_base('Time limit format errors.')
82 87 elsif time_limit<=0 or time_limit >60
83 88 problem.errors.add_to_base('Time limit out of range.')
84 89 end
85 90
86 91 if memory_limit==0 and memory_limit_s!='0'
87 92 problem.errors.add_to_base('Memory limit format errors.')
88 93 elsif memory_limit<=0 or memory_limit >512
89 94 problem.errors.add_to_base('Memory limit out of range.')
90 95 end
91 96
92 97 if params[:file]==nil or params[:file]==''
93 98 problem.errors.add_to_base('No testdata file.')
94 99 end
95 100
96 101 file = params[:file]
97 102
98 103 if problem.errors.length!=0
99 104 return problem
100 105 end
101 106
102 107 problem.name = params[:name]
103 108 if params[:full_name]!=''
104 109 problem.full_name = params[:full_name]
105 110 else
106 111 problem.full_name = params[:name]
107 112 end
108 113
109 114 return {
110 115 :time_limit => time_limit,
111 116 :memory_limit => memory_limit,
112 117 :file => file
113 118 }
114 119 end
115 120
116 121 end
@@ -1,277 +1,298
1 1 require 'digest/sha1'
2 2
3 3 class User < ActiveRecord::Base
4 4
5 5 has_and_belongs_to_many :roles
6 6
7 7 has_many :test_requests, :order => "submitted_at DESC"
8 8
9 9 has_many :messages,
10 10 :class_name => "Message",
11 11 :foreign_key => "sender_id",
12 12 :order => 'created_at DESC'
13 13
14 14 has_many :replied_messages,
15 15 :class_name => "Message",
16 16 :foreign_key => "receiver_id",
17 17 :order => 'created_at DESC'
18 18
19 19 has_many :test_pair_assignments, :dependent => :delete_all
20 20 has_many :submission_statuses
21 21
22 22 has_one :contest_stat, :class_name => "UserContestStat"
23 23
24 24 belongs_to :site
25 25 belongs_to :country
26 26
27 + # For Code Jom
28 + has_one :codejom_status
29 +
27 30 named_scope :activated_users, :conditions => {:activated => true}
28 31
29 32 validates_presence_of :login
30 33 validates_uniqueness_of :login
31 34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
32 35 validates_length_of :login, :within => 3..30
33 36
34 37 validates_presence_of :full_name
35 38 validates_length_of :full_name, :minimum => 1
36 39
37 40 validates_presence_of :password, :if => :password_required?
38 41 validates_length_of :password, :within => 4..20, :if => :password_required?
39 42 validates_confirmation_of :password, :if => :password_required?
40 43
41 44 validates_format_of :email,
42 45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
43 46 :if => :email_validation?
44 47 validate :uniqueness_of_email_from_activated_users,
45 48 :if => :email_validation?
46 49 validate :enough_time_interval_between_same_email_registrations,
47 50 :if => :email_validation?
48 51
49 52 # these are for ytopc
50 53 # disable for now
51 54 #validates_presence_of :province
52 55
53 56 attr_accessor :password
54 57
55 58 before_save :encrypt_new_password
56 59 before_save :assign_default_site
57 60
58 61 def self.authenticate(login, password)
59 62 user = find_by_login(login)
60 63 return user if user && user.authenticated?(password)
61 64 end
62 65
63 66 def authenticated?(password)
64 67 if self.activated
65 68 hashed_password == User.encrypt(password,self.salt)
66 69 else
67 70 false
68 71 end
69 72 end
70 73
71 74 def admin?
72 75 self.roles.detect {|r| r.name == 'admin' }
73 76 end
74 77
75 78 # These are methods related to test pairs
76 79
77 80 def get_test_pair_assignments_for(problem)
78 81 test_pair_assignments.find_all { |a| a.problem_id == problem.id }
79 82 end
80 83
81 84 def get_recent_test_pair_assignment_for(problem)
82 85 assignments = get_test_pair_assignments_for problem
83 86 if assignments.length == 0
84 87 return nil
85 88 else
86 89 recent = assignments[0]
87 90 assignments.each do |a|
88 91 recent = a if a.request_number > recent.request_number
89 92 end
90 93 return recent
91 94 end
92 95 end
93 96
94 97 def can_request_new_test_pair_for?(problem)
95 98 recent = get_recent_test_pair_assignment_for problem
96 99 return (recent == nil or recent.submitted)
97 100 end
98 101
99 102 def get_new_test_pair_assignment_for(problem)
100 103 previous_assignment_numbers =
101 104 get_test_pair_assignments_for(problem).collect {|a| a.test_pair_number }
102 105 test_pair = problem.random_test_pair(previous_assignment_numbers)
103 106 if test_pair
104 107 assignment = TestPairAssignment.new(:user => self,
105 108 :problem => problem,
106 109 :test_pair => test_pair,
107 110 :test_pair_number => test_pair.number,
108 111 :request_number =>
109 112 previous_assignment_numbers.length + 1,
110 113 :submitted => false)
111 114 return assignment
112 115 else
113 116 return nil
114 117 end
115 118 end
116 119
117 120 def get_submission_status_for(problem)
118 121 SubmissionStatus.find(:first,
119 122 :conditions => {
120 123 :user_id => id,
121 124 :problem_id => problem.id
122 125 })
123 126 end
124 127
125 128 def email_for_editing
126 129 if self.email==nil
127 130 "(unknown)"
128 131 elsif self.email==''
129 132 "(blank)"
130 133 else
131 134 self.email
132 135 end
133 136 end
134 137
135 138 def email_for_editing=(e)
136 139 self.email=e
137 140 end
138 141
139 142 def alias_for_editing
140 143 if self.alias==nil
141 144 "(unknown)"
142 145 elsif self.alias==''
143 146 "(blank)"
144 147 else
145 148 self.alias
146 149 end
147 150 end
148 151
149 152 def alias_for_editing=(e)
150 153 self.alias=e
151 154 end
152 155
153 156 def activation_key
154 157 if self.hashed_password==nil
155 158 encrypt_new_password
156 159 end
157 160 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
158 161 end
159 162
160 163 def verify_activation_key(key)
161 164 key == activation_key
162 165 end
163 166
164 167 def self.random_password(length=5)
165 168 chars = 'abcdefghjkmnopqrstuvwxyz'
166 169 password = ''
167 170 length.times { password << chars[rand(chars.length - 1)] }
168 171 password
169 172 end
170 173
171 174 def self.find_non_admin_with_prefix(prefix='')
172 175 users = User.find(:all)
173 176 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
174 177 end
175 178
176 179 # Contest information
177 180
178 181 def contest_time_left
179 182 if Configuration.contest_mode?
180 183 return nil if site==nil
181 184 return site.time_left
182 185 elsif Configuration.indv_contest_mode?
183 186 time_limit = Configuration.contest_time_limit
184 187 if contest_stat==nil
185 188 return (Time.now.gmtime + time_limit) - Time.now.gmtime
186 189 else
187 190 finish_time = contest_stat.started_at + time_limit
188 191 current_time = Time.now.gmtime
189 192 if current_time > finish_time
190 193 return 0
191 194 else
192 195 return finish_time - current_time
193 196 end
194 197 end
195 198 else
196 199 return nil
197 200 end
198 201 end
199 202
200 203 def contest_finished?
201 204 if Configuration.contest_mode?
202 205 return false if site==nil
203 206 return site.finished?
204 207 elsif Configuration.indv_contest_mode?
205 208 time_limit = Configuration.contest_time_limit
206 209
207 210 return false if contest_stat==nil
208 211
209 212 return contest_time_left == 0
210 213 else
211 214 return false
212 215 end
213 216 end
214 217
215 218 def contest_started?
216 219 if Configuration.contest_mode?
217 220 return true if site==nil
218 221 return site.started
219 222 else
220 223 return true
221 224 end
222 225 end
223 226
227 + # For Code Jom
228 + def update_codejom_status
229 + status = codejom_status || CodejomStatus.new(:user => self)
230 + problem_count = Problem.available_problem_count
231 + status.num_problems_passed = (self.submission_statuses.find_all {|s| s.passed}).length
232 + status.alive = (problem_count - (status.num_problems_passed)) <= CODEJOM_MAX_ALIVE_LEVEL
233 + status.save
234 + end
235 +
236 + def codejom_level
237 + problem_count = Problem.available_problem_count
238 + if codejom_status!=nil
239 + return problem_count - codejom_status.num_problems_passed
240 + else
241 + return problem_count
242 + end
243 + end
244 +
224 245 protected
225 246 def encrypt_new_password
226 247 return if password.blank?
227 248 self.salt = (10+rand(90)).to_s
228 249 self.hashed_password = User.encrypt(self.password,self.salt)
229 250 end
230 251
231 252 def assign_default_site
232 253 # have to catch error when migrating (because self.site is not available).
233 254 begin
234 255 if self.site==nil
235 256 self.site = Site.find_by_name('default')
236 257 if self.site==nil
237 258 self.site = Site.find(1) # when 'default has be renamed'
238 259 end
239 260 end
240 261 rescue
241 262 end
242 263 end
243 264
244 265 def password_required?
245 266 self.hashed_password.blank? || !self.password.blank?
246 267 end
247 268
248 269 def self.encrypt(string,salt)
249 270 Digest::SHA1.hexdigest(salt + string)
250 271 end
251 272
252 273 def uniqueness_of_email_from_activated_users
253 274 user = User.activated_users.find_by_email(self.email)
254 275 if user and (user.login != self.login)
255 276 self.errors.add_to_base("Email has already been taken")
256 277 end
257 278 end
258 279
259 280 def enough_time_interval_between_same_email_registrations
260 281 return if !self.new_record?
261 282 return if self.activated
262 283 open_user = User.find_by_email(self.email,
263 284 :order => 'created_at DESC')
264 285 if open_user and open_user.created_at and
265 286 (open_user.created_at > Time.now.gmtime - 5.minutes)
266 287 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
267 288 end
268 289 end
269 290
270 291 def email_validation?
271 292 begin
272 293 return VALIDATE_USER_EMAILS
273 294 rescue
274 295 return false
275 296 end
276 297 end
277 298 end
@@ -1,105 +1,109
1 1 # Be sure to restart your web server when you modify this file.
2 2
3 3 # Uncomment below to force Rails into production mode when
4 4 # you don't control web/app server and can't set it the proper way
5 5 # ENV['RAILS_ENV'] ||= 'production'
6 6
7 7 # Specifies gem version of Rails to use when vendor/rails is not present
8 8 RAILS_GEM_VERSION = '2.3.4' unless defined? RAILS_GEM_VERSION
9 9
10 10 # Bootstrap the Rails environment, frameworks, and default configuration
11 11 require File.join(File.dirname(__FILE__), 'boot')
12 12
13 13 Rails::Initializer.run do |config|
14 14 # Settings in config/environments/* take precedence over those specified here
15 15
16 16 # Skip frameworks you're not going to use (only works if using vendor/rails)
17 17 # config.frameworks -= [ :action_web_service, :action_mailer ]
18 18
19 19 # Only load the plugins named here, by default all plugins in vendor/plugins are loaded
20 20 # config.plugins = %W( exception_notification ssl_requirement )
21 21
22 22 # Add additional load paths for your own custom dirs
23 23 # config.load_paths += %W( #{RAILS_ROOT}/extras )
24 24
25 25 # Force all environments to use the same logger level
26 26 # (by default production uses :info, the others :debug)
27 27 # config.log_level = :debug
28 28
29 29 # Use the database for sessions instead of the file system
30 30 # (create the session table with 'rake db:sessions:create')
31 31 config.action_controller.session_store = :active_record_store
32 32
33 33 # Use SQL instead of Active Record's schema dumper when creating the test database.
34 34 # This is necessary if your schema can't be completely dumped by the schema dumper,
35 35 # like if you have constraints or database-specific column types
36 36 # config.active_record.schema_format = :sql
37 37
38 38 # Activate observers that should always be running
39 39 # config.active_record.observers = :cacher, :garbage_collector
40 40
41 41 # Make Active Record use UTC-base instead of local time
42 42 config.time_zone = 'UTC'
43 43
44 44 # Setting locales
45 45 config.i18n.default_locale = 'en'
46 46
47 47 # See Rails::Configuration for more options
48 48
49 49 # -------------
50 50 # Required gems
51 51 # -------------
52 52 config.gem "haml"
53 53 config.gem "tmail"
54 54 config.gem "rdiscount", :lib => "rdiscount"
55 55
56 56 # NOTES on rspec: if you wan to test with rspec, you have to install
57 57 # rspec yourself, just call: [sudo] gem install rspec-rails
58 58
59 59 end
60 60
61 61 # Add new inflection rules using the following format
62 62 # (all these examples are active by default):
63 63 # Inflector.inflections do |inflect|
64 64 # inflect.plural /^(ox)$/i, '\1en'
65 65 # inflect.singular /^(ox)en/i, '\1'
66 66 # inflect.irregular 'person', 'people'
67 67 # inflect.uncountable %w( fish sheep )
68 68 # end
69 69
70 70 # Add new mime types for use in respond_to blocks:
71 71 # Mime::Type.register "text/richtext", :rtf
72 72 # Mime::Type.register "application/x-mobile", :mobile
73 73
74 74 # Include your application configuration below
75 75
76 76 # If you want to manage graders through web interface, set the path to
77 77 # the grader directory below. This dir is where raw, ev, ev-exam,
78 78 # scripts reside. All grader scripts will be in
79 79 # #{GRADER_ROOT_DIR}/scripts.
80 80 GRADER_ROOT_DIR = ''
81 81
82 82 # These are where inputs and outputs of test requests are stored
83 83 TEST_REQUEST_INPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/input'
84 84 TEST_REQUEST_OUTPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/output'
85 85
86 86 # To use ANALYSIS MODE, provide the testcases/testruns breakdown,
87 87 # and the directory of the grading result (usually in judge's dir).
88 88 TASK_GRADING_INFO_FILENAME = RAILS_ROOT + '/config/tasks.yml'
89 89
90 90 # TODO: change this to where results are kept.
91 91 GRADING_RESULT_DIR = 'RESULT-DIR'
92 92
93 93 # Change this to allow importing testdata into database as test-pairs.
94 94 # This is mainly for Code Jom contest.
95 95 ALLOW_TEST_PAIR_IMPORT = false
96 96
97 97 # Uncomment so that the system validates user e-mails
98 98 # VALIDATE_USER_EMAILS = true
99 99
100 100 # Uncomment so that Apache X-Sendfile is used when delivering files
101 101 # (e.g., in /tasks/view).
102 102 # USE_APACHE_XSENDFILE = true
103 103
104 104 # Uncomment so that configuration is read only once when the server is loaded
105 105 # Configuration.enable_caching
106 +
107 + # OPTIONS FOR CODE JOM
108 + # --------------------
109 + CODEJOM_MAX_ALIVE_LEVEL = 10
@@ -1,233 +1,241
1 1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 2 # please use the migrations feature of Active Record to incrementally modify your database, and
3 3 # then regenerate this schema definition.
4 4 #
5 5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 6 # to create the application database on another system, you should be using db:schema:load, not running
7 7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11
12 - ActiveRecord::Schema.define(:version => 20100124054458) do
12 + ActiveRecord::Schema.define(:version => 20100124191250) do
13 13
14 14 create_table "announcements", :force => true do |t|
15 15 t.string "author"
16 16 t.text "body"
17 17 t.boolean "published"
18 18 t.datetime "created_at"
19 19 t.datetime "updated_at"
20 20 t.boolean "frontpage", :default => false
21 21 t.boolean "contest_only", :default => false
22 22 t.string "title"
23 23 end
24 24
25 + create_table "codejom_statuses", :force => true do |t|
26 + t.integer "user_id"
27 + t.boolean "alive"
28 + t.integer "num_problems_passed"
29 + t.datetime "created_at"
30 + t.datetime "updated_at"
31 + end
32 +
25 33 create_table "configurations", :force => true do |t|
26 34 t.string "key"
27 35 t.string "value_type"
28 36 t.string "value"
29 37 t.datetime "created_at"
30 38 t.datetime "updated_at"
31 39 t.text "description"
32 40 end
33 41
34 42 create_table "countries", :force => true do |t|
35 43 t.string "name"
36 44 t.datetime "created_at"
37 45 t.datetime "updated_at"
38 46 end
39 47
40 48 create_table "descriptions", :force => true do |t|
41 49 t.text "body"
42 50 t.boolean "markdowned"
43 51 t.datetime "created_at"
44 52 t.datetime "updated_at"
45 53 end
46 54
47 55 create_table "grader_processes", :force => true do |t|
48 56 t.string "host", :limit => 20
49 57 t.integer "pid"
50 58 t.string "mode"
51 59 t.boolean "active"
52 60 t.datetime "created_at"
53 61 t.datetime "updated_at"
54 62 t.integer "task_id"
55 63 t.string "task_type"
56 64 t.boolean "terminated"
57 65 end
58 66
59 67 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
60 68
61 69 create_table "languages", :force => true do |t|
62 70 t.string "name", :limit => 10
63 71 t.string "pretty_name"
64 72 t.string "ext", :limit => 10
65 73 t.string "common_ext"
66 74 end
67 75
68 76 create_table "messages", :force => true do |t|
69 77 t.integer "sender_id"
70 78 t.integer "receiver_id"
71 79 t.integer "replying_message_id"
72 80 t.text "body"
73 81 t.boolean "replied"
74 82 t.datetime "created_at"
75 83 t.datetime "updated_at"
76 84 end
77 85
78 86 create_table "problems", :force => true do |t|
79 87 t.string "name", :limit => 30
80 88 t.string "full_name"
81 89 t.integer "full_score"
82 90 t.date "date_added"
83 91 t.boolean "available"
84 92 t.string "url"
85 93 t.integer "description_id"
86 94 t.boolean "test_allowed"
87 95 t.boolean "output_only"
88 96 end
89 97
90 98 create_table "rights", :force => true do |t|
91 99 t.string "name"
92 100 t.string "controller"
93 101 t.string "action"
94 102 end
95 103
96 104 create_table "rights_roles", :id => false, :force => true do |t|
97 105 t.integer "right_id"
98 106 t.integer "role_id"
99 107 end
100 108
101 109 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
102 110
103 111 create_table "roles", :force => true do |t|
104 112 t.string "name"
105 113 end
106 114
107 115 create_table "roles_users", :id => false, :force => true do |t|
108 116 t.integer "role_id"
109 117 t.integer "user_id"
110 118 end
111 119
112 120 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
113 121
114 122 create_table "sessions", :force => true do |t|
115 123 t.string "session_id"
116 124 t.text "data"
117 125 t.datetime "updated_at"
118 126 end
119 127
120 128 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
121 129 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
122 130
123 131 create_table "sites", :force => true do |t|
124 132 t.string "name"
125 133 t.boolean "started"
126 134 t.datetime "start_time"
127 135 t.datetime "created_at"
128 136 t.datetime "updated_at"
129 137 t.integer "country_id"
130 138 t.string "password"
131 139 end
132 140
133 141 create_table "submission_statuses", :force => true do |t|
134 142 t.integer "user_id"
135 143 t.integer "problem_id"
136 144 t.boolean "passed"
137 145 t.integer "submission_count"
138 146 t.datetime "created_at"
139 147 t.datetime "updated_at"
140 148 end
141 149
142 150 create_table "submissions", :force => true do |t|
143 151 t.integer "user_id"
144 152 t.integer "problem_id"
145 153 t.integer "language_id"
146 154 t.text "source"
147 155 t.binary "binary"
148 156 t.datetime "submitted_at"
149 157 t.datetime "compiled_at"
150 158 t.text "compiler_message"
151 159 t.datetime "graded_at"
152 160 t.integer "points"
153 161 t.text "grader_comment"
154 162 t.integer "number"
155 163 t.string "source_filename"
156 164 end
157 165
158 166 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
159 167 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
160 168
161 169 create_table "tasks", :force => true do |t|
162 170 t.integer "submission_id"
163 171 t.datetime "created_at"
164 172 t.integer "status"
165 173 t.datetime "updated_at"
166 174 end
167 175
168 176 create_table "test_pair_assignments", :force => true do |t|
169 177 t.integer "user_id"
170 178 t.integer "problem_id"
171 179 t.integer "test_pair_id"
172 180 t.integer "test_pair_number"
173 181 t.integer "request_number"
174 182 t.datetime "created_at"
175 183 t.datetime "updated_at"
176 184 t.boolean "submitted"
177 185 end
178 186
179 187 create_table "test_pairs", :force => true do |t|
180 188 t.integer "problem_id"
181 189 t.text "input"
182 190 t.text "solution"
183 191 t.datetime "created_at"
184 192 t.datetime "updated_at"
185 193 t.integer "number"
186 194 end
187 195
188 196 create_table "test_requests", :force => true do |t|
189 197 t.integer "user_id"
190 198 t.integer "problem_id"
191 199 t.integer "submission_id"
192 200 t.string "input_file_name"
193 201 t.string "output_file_name"
194 202 t.string "running_stat"
195 203 t.integer "status"
196 204 t.datetime "updated_at"
197 205 t.datetime "submitted_at"
198 206 t.datetime "compiled_at"
199 207 t.text "compiler_message"
200 208 t.datetime "graded_at"
201 209 t.string "grader_comment"
202 210 t.datetime "created_at"
203 211 t.float "running_time"
204 212 t.string "exit_status"
205 213 t.integer "memory_usage"
206 214 end
207 215
208 216 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
209 217
210 218 create_table "user_contest_stats", :force => true do |t|
211 219 t.integer "user_id"
212 220 t.datetime "started_at"
213 221 t.datetime "created_at"
214 222 t.datetime "updated_at"
215 223 end
216 224
217 225 create_table "users", :force => true do |t|
218 226 t.string "login", :limit => 50
219 227 t.string "full_name"
220 228 t.string "hashed_password"
221 229 t.string "salt", :limit => 5
222 230 t.string "alias"
223 231 t.string "email"
224 232 t.integer "site_id"
225 233 t.integer "country_id"
226 234 t.boolean "activated", :default => false
227 235 t.datetime "created_at"
228 236 t.datetime "updated_at"
229 237 end
230 238
231 239 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
232 240
233 241 end
You need to be logged in to leave comments. Login now