Description:
added submission_status to store grading results, first page shows only unpassed problems.
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r216:fa11dca6b078 - - 10 files changed: 149 inserted, 74 deleted

@@ -0,0 +1,6
1 + class SubmissionStatus < ActiveRecord::Base
2 +
3 + belongs_to :user
4 + belongs_to :problem
5 +
6 + end
@@ -0,0 +1,18
1 + .problem-panel{:id => "problem-panel-#{problem.id}", :style => "display:none"}
2 + .problem-form{:id => "problem-form-#{problem.id}"}
3 + - form_tag({ :action => 'download_input', :id => problem.id }, :method => :post) do
4 + %b Input:
5 + %input{:type => "submit", :value => "Download input"}
6 + - form_tag({ :action => 'submit_solution', :id => problem.id }, :method => :post, :multipart => true) do
7 + %b Submit output:
8 + %input{:type => "file", :name => "file"}
9 + %input{:type => "submit", :value => "Submit solution"}
10 +
11 + .problem-description
12 + - if problem.description!=nil
13 + - if problem.description.markdowned
14 + = markdown(problem.description.body)
15 + - else
16 + = problem.description.body
17 + - else
18 + (not available)
@@ -0,0 +1,16
1 + class CreateSubmissionStatuses < ActiveRecord::Migration
2 + def self.up
3 + create_table :submission_statuses do |t|
4 + t.integer :user_id
5 + t.integer :problem_id
6 + t.boolean :passed
7 + t.integer :submission_count
8 +
9 + t.timestamps
10 + end
11 + end
12 +
13 + def self.down
14 + drop_table :submission_statuses
15 + end
16 + end
@@ -0,0 +1,13
1 + # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 +
3 + one:
4 + user_id: 1
5 + problem_id: 1
6 + passed: false
7 + submission_count: 1
8 +
9 + two:
10 + user_id: 1
11 + problem_id: 1
12 + passed: false
13 + submission_count: 1
@@ -0,0 +1,8
1 + require 'test_helper'
2 +
3 + class SubmissionStatusTest < ActiveSupport::TestCase
4 + # Replace this with your real tests.
5 + test "the truth" do
6 + assert true
7 + end
8 + end
@@ -1,59 +1,59
1 class MainController < ApplicationController
1 class MainController < ApplicationController
2
2
3 SYSTEM_MODE_CONF_KEY = 'system.mode'
3 SYSTEM_MODE_CONF_KEY = 'system.mode'
4
4
5 before_filter :authenticate, :except => [:index, :login]
5 before_filter :authenticate, :except => [:index, :login]
6 before_filter :check_viewability, :except => [:index, :login]
6 before_filter :check_viewability, :except => [:index, :login]
7
7
8 # COMMENTED OUT: filter in each action instead
8 # COMMENTED OUT: filter in each action instead
9 # before_filter :verify_time_limit, :only => [:submit]
9 # before_filter :verify_time_limit, :only => [:submit]
10
10
11 - verify :method => :post, :only => [:submit, :new_input, :download_input, :submit_solution],
11 + verify :method => :post, :only => [:submit, :download_input, :submit_solution],
12 :redirect_to => { :action => :index }
12 :redirect_to => { :action => :index }
13
13
14 # COMMENT OUT: only need when having high load
14 # COMMENT OUT: only need when having high load
15 # caches_action :index, :login
15 # caches_action :index, :login
16
16
17 # NOTE: This method is not actually needed, 'config/routes.rb' has
17 # NOTE: This method is not actually needed, 'config/routes.rb' has
18 # assigned action login as a default action.
18 # assigned action login as a default action.
19 def index
19 def index
20 redirect_to :action => 'login'
20 redirect_to :action => 'login'
21 end
21 end
22
22
23 def login
23 def login
24 saved_notice = flash[:notice]
24 saved_notice = flash[:notice]
25 reset_session
25 reset_session
26 flash[:notice] = saved_notice
26 flash[:notice] = saved_notice
27
27
28 # EXPERIMENT:
28 # EXPERIMENT:
29 # Hide login if in single user mode and the url does not
29 # Hide login if in single user mode and the url does not
30 # explicitly specify /login
30 # explicitly specify /login
31 #
31 #
32 # logger.info "PATH: #{request.path}"
32 # logger.info "PATH: #{request.path}"
33 # if Configuration['system.single_user_mode'] and
33 # if Configuration['system.single_user_mode'] and
34 # request.path!='/main/login'
34 # request.path!='/main/login'
35 # @hidelogin = true
35 # @hidelogin = true
36 # end
36 # end
37
37
38 @announcements = Announcement.find_for_frontpage
38 @announcements = Announcement.find_for_frontpage
39 render :action => 'login', :layout => 'empty'
39 render :action => 'login', :layout => 'empty'
40 end
40 end
41
41
42 def list
42 def list
43 prepare_list_information
43 prepare_list_information
44 end
44 end
45
45
46 def help
46 def help
47 @user = User.find(session[:user_id])
47 @user = User.find(session[:user_id])
48 end
48 end
49
49
50 def submit
50 def submit
51 user = User.find(session[:user_id])
51 user = User.find(session[:user_id])
52
52
53 @submission = Submission.new(params[:submission])
53 @submission = Submission.new(params[:submission])
54 @submission.user = user
54 @submission.user = user
55 @submission.language_id = 0
55 @submission.language_id = 0
56 if (params['file']) and (params['file']!='')
56 if (params['file']) and (params['file']!='')
57 @submission.source = params['file'].read
57 @submission.source = params['file'].read
58 @submission.source_filename = params['file'].original_filename
58 @submission.source_filename = params['file'].original_filename
59 end
59 end
@@ -131,183 +131,205
131 end
131 end
132 prepare_grading_result(@submission)
132 prepare_grading_result(@submission)
133 end
133 end
134
134
135 def load_output
135 def load_output
136 if !Configuration.show_grading_result or params[:num]==nil
136 if !Configuration.show_grading_result or params[:num]==nil
137 redirect_to :action => 'list' and return
137 redirect_to :action => 'list' and return
138 end
138 end
139 @user = User.find(session[:user_id])
139 @user = User.find(session[:user_id])
140 @submission = Submission.find(params[:id])
140 @submission = Submission.find(params[:id])
141 if @submission.user!=@user
141 if @submission.user!=@user
142 flash[:notice] = 'You are not allowed to view result of other users.'
142 flash[:notice] = 'You are not allowed to view result of other users.'
143 redirect_to :action => 'list' and return
143 redirect_to :action => 'list' and return
144 end
144 end
145 case_num = params[:num].to_i
145 case_num = params[:num].to_i
146 out_filename = output_filename(@user.login,
146 out_filename = output_filename(@user.login,
147 @submission.problem.name,
147 @submission.problem.name,
148 @submission.id,
148 @submission.id,
149 case_num)
149 case_num)
150 if !FileTest.exists?(out_filename)
150 if !FileTest.exists?(out_filename)
151 flash[:notice] = 'Output not found.'
151 flash[:notice] = 'Output not found.'
152 redirect_to :action => 'list' and return
152 redirect_to :action => 'list' and return
153 end
153 end
154
154
155 response.headers['Content-Type'] = "application/force-download"
155 response.headers['Content-Type'] = "application/force-download"
156 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
156 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
157 response.headers["X-Sendfile"] = out_filename
157 response.headers["X-Sendfile"] = out_filename
158 response.headers['Content-length'] = File.size(out_filename)
158 response.headers['Content-length'] = File.size(out_filename)
159 render :nothing => true
159 render :nothing => true
160 end
160 end
161
161
162 def error
162 def error
163 @user = User.find(session[:user_id])
163 @user = User.find(session[:user_id])
164 end
164 end
165
165
166 # announcement refreshing and hiding methods
166 # announcement refreshing and hiding methods
167
167
168 def announcements
168 def announcements
169 if params.has_key? 'recent'
169 if params.has_key? 'recent'
170 prepare_announcements(params[:recent])
170 prepare_announcements(params[:recent])
171 else
171 else
172 prepare_announcements
172 prepare_announcements
173 end
173 end
174 render(:partial => 'announcement',
174 render(:partial => 'announcement',
175 :collection => @announcements,
175 :collection => @announcements,
176 :locals => {:announcement_effect => true})
176 :locals => {:announcement_effect => true})
177 end
177 end
178
178
179 + #
179 # actions for Code Jom
180 # actions for Code Jom
180 - def new_input
181 + #
182 + def download_input
181 problem = Problem.find(params[:id])
183 problem = Problem.find(params[:id])
182 user = User.find(session[:user_id])
184 user = User.find(session[:user_id])
183 if user.can_request_new_test_pair_for? problem
185 if user.can_request_new_test_pair_for? problem
184 assignment = user.get_new_test_pair_assignment_for problem
186 assignment = user.get_new_test_pair_assignment_for problem
185 assignment.save
187 assignment.save
186
188
187 send_data(assignment.test_pair.input,
189 send_data(assignment.test_pair.input,
188 { :filename => "#{problem.name}-#{assignment.request_number}.in",
190 { :filename => "#{problem.name}-#{assignment.request_number}.in",
189 :type => 'text/plain' })
191 :type => 'text/plain' })
190 - else
192 + else
191 - flash[:notice] = 'You cannot request new input now.'
193 + recent_assignment = user.get_recent_test_pair_assignment_for problem
192 - redirect_to :action => 'list'
193 - end
194 - end
195 -
196 - def download_input
197 - problem = Problem.find(params[:id])
198 - user = User.find(session[:user_id])
199 - recent_assignment = user.get_recent_test_pair_assignment_for problem
200 - if recent_assignment != nil
201 send_data(recent_assignment.test_pair.input,
194 send_data(recent_assignment.test_pair.input,
202 { :filename => "#{problem.name}-#{recent_assignment.request_number}.in",
195 { :filename => "#{problem.name}-#{recent_assignment.request_number}.in",
203 :type => 'text/plain' })
196 :type => 'text/plain' })
204 - else
205 - flash[:notice] = 'You have not requested for any input data for this problem.'
206 - redirect_to :action => 'list'
207 end
197 end
208 end
198 end
209
199
210 def submit_solution
200 def submit_solution
211 problem = Problem.find(params[:id])
201 problem = Problem.find(params[:id])
212 user = User.find(session[:user_id])
202 user = User.find(session[:user_id])
213 recent_assignment = user.get_recent_test_pair_assignment_for problem
203 recent_assignment = user.get_recent_test_pair_assignment_for problem
214 - if recent_assignment != nil
204 + if recent_assignment == nil
215 - submitted_solution = params[:file].read
205 + flash[:notice] = 'You have not requested for any input data for this problem. Please download an input first.'
216 - test_pair = recent_assignment.test_pair
206 + redirect_to :action => 'list' and return
217 - passed = test_pair.grade(submitted_solution)
207 + end
218 - points = passed ? 100 : 0
208 +
219 - submission = Submission.new(:user => user,
209 + if recent_assignment.submitted
220 - :problem => problem,
210 + flash[:notice] = 'You have already submitted an incorrect solution for this input. Please download a new input data.'
221 - :source => params[:file].read,
211 + redirect_to :action => 'list' and return
222 - :source_filename => params['file'].original_filename,
212 + end
223 - :language_id => 0,
213 +
224 - :submitted_at => Time.new.gmtime,
214 + if params[:file] == nil
225 - :graded_at => Time.new.gmtime,
215 + flash[:notice] = 'You have not submitted any output.'
226 - :points => points)
216 + redirect_to :action => 'list' and return
227 - submission.save
217 + end
228 - recent_assignment.submitted = true
218 +
229 - recent_assignment.save
219 + submitted_solution = params[:file].read
230 - if passed
220 + test_pair = recent_assignment.test_pair
231 - flash[:notice] = 'Correct solution'
221 + passed = test_pair.grade(submitted_solution)
232 - else
222 + points = passed ? 100 : 0
233 - flash[:notice] = 'Incorrect solution'
223 + submission = Submission.new(:user => user,
234 - end
224 + :problem => problem,
235 - redirect_to :action => 'list'
225 + :source => submitted_solution,
226 + :source_filename => params['file'].original_filename,
227 + :language_id => 0,
228 + :submitted_at => Time.new.gmtime,
229 + :graded_at => Time.new.gmtime,
230 + :points => points)
231 + submission.save
232 + recent_assignment.submitted = true
233 + recent_assignment.save
234 +
235 + status = user.get_submission_status_for(problem)
236 + if status == nil
237 + status = SubmissionStatus.new :user => user, :problem => problem, :submission_count => 0
238 + end
239 +
240 + status.submission_count += 1
241 + status.passed = passed
242 + status.save
243 +
244 + if passed
245 + flash[:notice] = 'Correct solution.'
236 else
246 else
237 - flash[:notice] = 'You have not requested for any input data for this problem.'
247 + flash[:notice] = 'Incorrect solution.'
238 - redirect_to :action => 'list'
239 end
248 end
249 + redirect_to :action => 'list'
240 end
250 end
241
251
242 protected
252 protected
243
253
244 def prepare_announcements(recent=nil)
254 def prepare_announcements(recent=nil)
245 if Configuration.show_tasks_to?(@user)
255 if Configuration.show_tasks_to?(@user)
246 @announcements = Announcement.find_published(true)
256 @announcements = Announcement.find_published(true)
247 else
257 else
248 @announcements = Announcement.find_published
258 @announcements = Announcement.find_published
249 end
259 end
250 if recent!=nil
260 if recent!=nil
251 recent_id = recent.to_i
261 recent_id = recent.to_i
252 @announcements = @announcements.find_all { |a| a.id > recent_id }
262 @announcements = @announcements.find_all { |a| a.id > recent_id }
253 end
263 end
254 end
264 end
255
265
256 def prepare_list_information
266 def prepare_list_information
257 - @problems = Problem.find_available_problems
267 + @user = User.find(session[:user_id])
268 +
269 + all_problems = Problem.find_available_problems
270 +
271 + passed = {}
272 + sub_count = {}
273 + @user.submission_statuses.each do |status|
274 + if status.passed
275 + passed[status.problem_id] = true
276 + end
277 + sub_count[status.problem_id] = status.submission_count
278 + end
279 +
280 + @problems = all_problems.reject { |problem| passed.has_key? problem.id }
281 +
258 @prob_submissions = Array.new
282 @prob_submissions = Array.new
259 - @user = User.find(session[:user_id])
260 @problems.each do |p|
283 @problems.each do |p|
261 - sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
284 + if sub_count.has_key? p.id
262 - if sub!=nil
285 + @prob_submissions << { :count => sub_count[p.id] }
263 - @prob_submissions << { :count => sub.number, :submission => sub }
264 else
286 else
265 - @prob_submissions << { :count => 0, :submission => nil }
287 + @prob_submissions << { :count => 0 }
266 end
288 end
267 end
289 end
268 prepare_announcements
290 prepare_announcements
269 end
291 end
270
292
271 def check_viewability
293 def check_viewability
272 @user = User.find(session[:user_id])
294 @user = User.find(session[:user_id])
273 if (!Configuration.show_tasks_to?(@user)) and
295 if (!Configuration.show_tasks_to?(@user)) and
274 ((action_name=='submission') or (action_name=='submit'))
296 ((action_name=='submission') or (action_name=='submit'))
275 redirect_to :action => 'list' and return
297 redirect_to :action => 'list' and return
276 end
298 end
277 end
299 end
278
300
279 def prepare_grading_result(submission)
301 def prepare_grading_result(submission)
280 if Configuration.task_grading_info.has_key? submission.problem.name
302 if Configuration.task_grading_info.has_key? submission.problem.name
281 grading_info = Configuration.task_grading_info[submission.problem.name]
303 grading_info = Configuration.task_grading_info[submission.problem.name]
282 else
304 else
283 # guess task info from problem.full_score
305 # guess task info from problem.full_score
284 cases = submission.problem.full_score / 10
306 cases = submission.problem.full_score / 10
285 grading_info = {
307 grading_info = {
286 'testruns' => cases,
308 'testruns' => cases,
287 'testcases' => cases
309 'testcases' => cases
288 }
310 }
289 end
311 end
290 @test_runs = []
312 @test_runs = []
291 if grading_info['testruns'].is_a? Integer
313 if grading_info['testruns'].is_a? Integer
292 trun_count = grading_info['testruns']
314 trun_count = grading_info['testruns']
293 trun_count.times do |i|
315 trun_count.times do |i|
294 @test_runs << [ read_grading_result(@user.login,
316 @test_runs << [ read_grading_result(@user.login,
295 submission.problem.name,
317 submission.problem.name,
296 submission.id,
318 submission.id,
297 i+1) ]
319 i+1) ]
298 end
320 end
299 else
321 else
300 grading_info['testruns'].keys.sort.each do |num|
322 grading_info['testruns'].keys.sort.each do |num|
301 run = []
323 run = []
302 testrun = grading_info['testruns'][num]
324 testrun = grading_info['testruns'][num]
303 testrun.each do |c|
325 testrun.each do |c|
304 run << read_grading_result(@user.login,
326 run << read_grading_result(@user.login,
305 submission.problem.name,
327 submission.problem.name,
306 submission.id,
328 submission.id,
307 c)
329 c)
308 end
330 end
309 @test_runs << run
331 @test_runs << run
310 end
332 end
311 end
333 end
312 end
334 end
313
335
@@ -1,62 +1,62
1 class Submission < ActiveRecord::Base
1 class Submission < ActiveRecord::Base
2
2
3 belongs_to :language
3 belongs_to :language
4 belongs_to :problem
4 belongs_to :problem
5 belongs_to :user
5 belongs_to :user
6
6
7 before_validation :assign_problem
7 before_validation :assign_problem
8 before_validation :assign_language
8 before_validation :assign_language
9
9
10 validates_presence_of :source
10 validates_presence_of :source
11 validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'too long'
11 validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'too long'
12 validates_length_of :source, :minimum => 1, :allow_blank => true, :message => 'too short'
12 validates_length_of :source, :minimum => 1, :allow_blank => true, :message => 'too short'
13 validate :must_have_valid_problem
13 validate :must_have_valid_problem
14 - validate :must_specify_language
14 + #validate :must_specify_language
15
15
16 before_save :assign_latest_number_if_new_recond
16 before_save :assign_latest_number_if_new_recond
17
17
18 def self.find_last_by_user_and_problem(user_id, problem_id)
18 def self.find_last_by_user_and_problem(user_id, problem_id)
19 last_sub = find(:first,
19 last_sub = find(:first,
20 :conditions => {:user_id => user_id,
20 :conditions => {:user_id => user_id,
21 :problem_id => problem_id},
21 :problem_id => problem_id},
22 :order => 'number DESC')
22 :order => 'number DESC')
23 return last_sub
23 return last_sub
24 end
24 end
25
25
26 def self.find_all_last_by_problem(problem_id)
26 def self.find_all_last_by_problem(problem_id)
27 # need to put in SQL command, maybe there's a better way
27 # need to put in SQL command, maybe there's a better way
28 Submission.find_by_sql("SELECT * FROM submissions " +
28 Submission.find_by_sql("SELECT * FROM submissions " +
29 "WHERE id = " +
29 "WHERE id = " +
30 "(SELECT MAX(id) FROM submissions AS subs " +
30 "(SELECT MAX(id) FROM submissions AS subs " +
31 "WHERE subs.user_id = submissions.user_id AND " +
31 "WHERE subs.user_id = submissions.user_id AND " +
32 "problem_id = " + problem_id.to_s + " " +
32 "problem_id = " + problem_id.to_s + " " +
33 "GROUP BY user_id) " +
33 "GROUP BY user_id) " +
34 "ORDER BY user_id")
34 "ORDER BY user_id")
35 end
35 end
36
36
37 def self.find_last_for_all_available_problems(user_id)
37 def self.find_last_for_all_available_problems(user_id)
38 submissions = Array.new
38 submissions = Array.new
39 problems = Problem.find_available_problems
39 problems = Problem.find_available_problems
40 problems.each do |problem|
40 problems.each do |problem|
41 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
41 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
42 submissions << sub if sub!=nil
42 submissions << sub if sub!=nil
43 end
43 end
44 submissions
44 submissions
45 end
45 end
46
46
47 def self.find_by_user_problem_number(user_id, problem_id, number)
47 def self.find_by_user_problem_number(user_id, problem_id, number)
48 Submission.find(:first,
48 Submission.find(:first,
49 :conditions => {
49 :conditions => {
50 :user_id => user_id,
50 :user_id => user_id,
51 :problem_id => problem_id,
51 :problem_id => problem_id,
52 :number => number
52 :number => number
53 })
53 })
54 end
54 end
55
55
56 def self.find_all_by_user_problem(user_id, problem_id)
56 def self.find_all_by_user_problem(user_id, problem_id)
57 Submission.find(:all,
57 Submission.find(:all,
58 :conditions => {
58 :conditions => {
59 :user_id => user_id,
59 :user_id => user_id,
60 :problem_id => problem_id,
60 :problem_id => problem_id,
61 })
61 })
62 end
62 end
@@ -1,161 +1,170
1 require 'digest/sha1'
1 require 'digest/sha1'
2
2
3 class User < ActiveRecord::Base
3 class User < ActiveRecord::Base
4
4
5 has_and_belongs_to_many :roles
5 has_and_belongs_to_many :roles
6
6
7 has_many :test_requests, :order => "submitted_at DESC"
7 has_many :test_requests, :order => "submitted_at DESC"
8
8
9 has_many :messages,
9 has_many :messages,
10 :class_name => "Message",
10 :class_name => "Message",
11 :foreign_key => "sender_id",
11 :foreign_key => "sender_id",
12 :order => 'created_at DESC'
12 :order => 'created_at DESC'
13
13
14 has_many :replied_messages,
14 has_many :replied_messages,
15 :class_name => "Message",
15 :class_name => "Message",
16 :foreign_key => "receiver_id",
16 :foreign_key => "receiver_id",
17 :order => 'created_at DESC'
17 :order => 'created_at DESC'
18
18
19 has_many :test_pair_assignments, :dependent => :delete_all
19 has_many :test_pair_assignments, :dependent => :delete_all
20 + has_many :submission_statuses
20
21
21 belongs_to :site
22 belongs_to :site
22 belongs_to :country
23 belongs_to :country
23
24
24 named_scope :activated_users, :conditions => {:activated => true}
25 named_scope :activated_users, :conditions => {:activated => true}
25
26
26 validates_presence_of :login
27 validates_presence_of :login
27 validates_uniqueness_of :login
28 validates_uniqueness_of :login
28 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
29 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
29 validates_length_of :login, :within => 3..30
30 validates_length_of :login, :within => 3..30
30
31
31 validates_presence_of :full_name
32 validates_presence_of :full_name
32 validates_length_of :full_name, :minimum => 1
33 validates_length_of :full_name, :minimum => 1
33
34
34 validates_presence_of :password, :if => :password_required?
35 validates_presence_of :password, :if => :password_required?
35 validates_length_of :password, :within => 4..20, :if => :password_required?
36 validates_length_of :password, :within => 4..20, :if => :password_required?
36 validates_confirmation_of :password, :if => :password_required?
37 validates_confirmation_of :password, :if => :password_required?
37
38
38 validates_format_of :email,
39 validates_format_of :email,
39 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
40 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
40 :if => :email_validation?
41 :if => :email_validation?
41 validate :uniqueness_of_email_from_activated_users,
42 validate :uniqueness_of_email_from_activated_users,
42 :if => :email_validation?
43 :if => :email_validation?
43 validate :enough_time_interval_between_same_email_registrations,
44 validate :enough_time_interval_between_same_email_registrations,
44 :if => :email_validation?
45 :if => :email_validation?
45
46
46 # these are for ytopc
47 # these are for ytopc
47 # disable for now
48 # disable for now
48 #validates_presence_of :province
49 #validates_presence_of :province
49
50
50 attr_accessor :password
51 attr_accessor :password
51
52
52 before_save :encrypt_new_password
53 before_save :encrypt_new_password
53 before_save :assign_default_site
54 before_save :assign_default_site
54
55
55 def self.authenticate(login, password)
56 def self.authenticate(login, password)
56 user = find_by_login(login)
57 user = find_by_login(login)
57 return user if user && user.authenticated?(password)
58 return user if user && user.authenticated?(password)
58 end
59 end
59
60
60 def authenticated?(password)
61 def authenticated?(password)
61 if self.activated
62 if self.activated
62 hashed_password == User.encrypt(password,self.salt)
63 hashed_password == User.encrypt(password,self.salt)
63 else
64 else
64 false
65 false
65 end
66 end
66 end
67 end
67
68
68 def admin?
69 def admin?
69 self.roles.detect {|r| r.name == 'admin' }
70 self.roles.detect {|r| r.name == 'admin' }
70 end
71 end
71
72
72 # These are methods related to test pairs
73 # These are methods related to test pairs
73
74
74 def get_test_pair_assignments_for(problem)
75 def get_test_pair_assignments_for(problem)
75 test_pair_assignments.find_all { |a| a.problem_id == problem.id }
76 test_pair_assignments.find_all { |a| a.problem_id == problem.id }
76 end
77 end
77
78
78 def get_recent_test_pair_assignment_for(problem)
79 def get_recent_test_pair_assignment_for(problem)
79 assignments = get_test_pair_assignments_for problem
80 assignments = get_test_pair_assignments_for problem
80 if assignments.length == 0
81 if assignments.length == 0
81 return nil
82 return nil
82 else
83 else
83 recent = assignments[0]
84 recent = assignments[0]
84 assignments.each do |a|
85 assignments.each do |a|
85 recent = a if a.request_number > recent.request_number
86 recent = a if a.request_number > recent.request_number
86 end
87 end
87 return recent
88 return recent
88 end
89 end
89 end
90 end
90
91
91 def can_request_new_test_pair_for?(problem)
92 def can_request_new_test_pair_for?(problem)
92 recent = get_recent_test_pair_assignment_for problem
93 recent = get_recent_test_pair_assignment_for problem
93 return (recent == nil or recent.submitted)
94 return (recent == nil or recent.submitted)
94 end
95 end
95
96
96 def get_new_test_pair_assignment_for(problem)
97 def get_new_test_pair_assignment_for(problem)
97 previous_assignment_numbers =
98 previous_assignment_numbers =
98 get_test_pair_assignments_for(problem).collect {|a| a.test_pair_number }
99 get_test_pair_assignments_for(problem).collect {|a| a.test_pair_number }
99 test_pair = problem.random_test_pair(previous_assignment_numbers)
100 test_pair = problem.random_test_pair(previous_assignment_numbers)
100 if test_pair
101 if test_pair
101 assignment = TestPairAssignment.new(:user => self,
102 assignment = TestPairAssignment.new(:user => self,
102 :problem => problem,
103 :problem => problem,
103 :test_pair => test_pair,
104 :test_pair => test_pair,
104 :test_pair_number => test_pair.number,
105 :test_pair_number => test_pair.number,
105 :request_number =>
106 :request_number =>
106 previous_assignment_numbers.length + 1,
107 previous_assignment_numbers.length + 1,
107 :submitted => false)
108 :submitted => false)
108 return assignment
109 return assignment
109 else
110 else
110 return nil
111 return nil
111 end
112 end
112 end
113 end
113
114
115 + def get_submission_status_for(problem)
116 + SubmissionStatus.find(:first,
117 + :conditions => {
118 + :user_id => id,
119 + :problem_id => problem.id
120 + })
121 + end
122 +
114 def email_for_editing
123 def email_for_editing
115 if self.email==nil
124 if self.email==nil
116 "(unknown)"
125 "(unknown)"
117 elsif self.email==''
126 elsif self.email==''
118 "(blank)"
127 "(blank)"
119 else
128 else
120 self.email
129 self.email
121 end
130 end
122 end
131 end
123
132
124 def email_for_editing=(e)
133 def email_for_editing=(e)
125 self.email=e
134 self.email=e
126 end
135 end
127
136
128 def alias_for_editing
137 def alias_for_editing
129 if self.alias==nil
138 if self.alias==nil
130 "(unknown)"
139 "(unknown)"
131 elsif self.alias==''
140 elsif self.alias==''
132 "(blank)"
141 "(blank)"
133 else
142 else
134 self.alias
143 self.alias
135 end
144 end
136 end
145 end
137
146
138 def alias_for_editing=(e)
147 def alias_for_editing=(e)
139 self.alias=e
148 self.alias=e
140 end
149 end
141
150
142 def activation_key
151 def activation_key
143 if self.hashed_password==nil
152 if self.hashed_password==nil
144 encrypt_new_password
153 encrypt_new_password
145 end
154 end
146 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
155 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
147 end
156 end
148
157
149 def verify_activation_key(key)
158 def verify_activation_key(key)
150 key == activation_key
159 key == activation_key
151 end
160 end
152
161
153 def self.random_password(length=5)
162 def self.random_password(length=5)
154 chars = 'abcdefghjkmnopqrstuvwxyz'
163 chars = 'abcdefghjkmnopqrstuvwxyz'
155 password = ''
164 password = ''
156 length.times { password << chars[rand(chars.length - 1)] }
165 length.times { password << chars[rand(chars.length - 1)] }
157 password
166 password
158 end
167 end
159
168
160 def self.find_non_admin_with_prefix(prefix='')
169 def self.find_non_admin_with_prefix(prefix='')
161 users = User.find(:all)
170 users = User.find(:all)
@@ -1,60 +1,60
1 # This file is auto-generated from the current state of the database. Instead of editing this file,
1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 # please use the migrations feature of Active Record to incrementally modify your database, and
2 # please use the migrations feature of Active Record to incrementally modify your database, and
3 # then regenerate this schema definition.
3 # then regenerate this schema definition.
4 #
4 #
5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 # to create the application database on another system, you should be using db:schema:load, not running
6 # to create the application database on another system, you should be using db:schema:load, not running
7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 # you'll amass, the slower it'll run and the greater likelihood for issues).
8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 #
9 #
10 # It's strongly recommended to check this file into your version control system.
10 # It's strongly recommended to check this file into your version control system.
11
11
12 - ActiveRecord::Schema.define(:version => 20100118174404) do
12 + ActiveRecord::Schema.define(:version => 20100123154326) do
13
13
14 create_table "announcements", :force => true do |t|
14 create_table "announcements", :force => true do |t|
15 t.string "author"
15 t.string "author"
16 t.text "body"
16 t.text "body"
17 t.boolean "published"
17 t.boolean "published"
18 t.datetime "created_at"
18 t.datetime "created_at"
19 t.datetime "updated_at"
19 t.datetime "updated_at"
20 t.boolean "frontpage", :default => false
20 t.boolean "frontpage", :default => false
21 t.boolean "contest_only", :default => false
21 t.boolean "contest_only", :default => false
22 t.string "title"
22 t.string "title"
23 end
23 end
24
24
25 create_table "configurations", :force => true do |t|
25 create_table "configurations", :force => true do |t|
26 t.string "key"
26 t.string "key"
27 t.string "value_type"
27 t.string "value_type"
28 t.string "value"
28 t.string "value"
29 t.datetime "created_at"
29 t.datetime "created_at"
30 t.datetime "updated_at"
30 t.datetime "updated_at"
31 end
31 end
32
32
33 create_table "countries", :force => true do |t|
33 create_table "countries", :force => true do |t|
34 t.string "name"
34 t.string "name"
35 t.datetime "created_at"
35 t.datetime "created_at"
36 t.datetime "updated_at"
36 t.datetime "updated_at"
37 end
37 end
38
38
39 create_table "descriptions", :force => true do |t|
39 create_table "descriptions", :force => true do |t|
40 t.text "body"
40 t.text "body"
41 t.boolean "markdowned"
41 t.boolean "markdowned"
42 t.datetime "created_at"
42 t.datetime "created_at"
43 t.datetime "updated_at"
43 t.datetime "updated_at"
44 end
44 end
45
45
46 create_table "grader_processes", :force => true do |t|
46 create_table "grader_processes", :force => true do |t|
47 t.string "host", :limit => 20
47 t.string "host", :limit => 20
48 t.integer "pid"
48 t.integer "pid"
49 t.string "mode"
49 t.string "mode"
50 t.boolean "active"
50 t.boolean "active"
51 t.datetime "created_at"
51 t.datetime "created_at"
52 t.datetime "updated_at"
52 t.datetime "updated_at"
53 t.integer "task_id"
53 t.integer "task_id"
54 t.string "task_type"
54 t.string "task_type"
55 t.boolean "terminated"
55 t.boolean "terminated"
56 end
56 end
57
57
58 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
58 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
59
59
60 create_table "languages", :force => true do |t|
60 create_table "languages", :force => true do |t|
@@ -84,96 +84,105
84 t.integer "description_id"
84 t.integer "description_id"
85 t.boolean "test_allowed"
85 t.boolean "test_allowed"
86 t.boolean "output_only"
86 t.boolean "output_only"
87 end
87 end
88
88
89 create_table "rights", :force => true do |t|
89 create_table "rights", :force => true do |t|
90 t.string "name"
90 t.string "name"
91 t.string "controller"
91 t.string "controller"
92 t.string "action"
92 t.string "action"
93 end
93 end
94
94
95 create_table "rights_roles", :id => false, :force => true do |t|
95 create_table "rights_roles", :id => false, :force => true do |t|
96 t.integer "right_id"
96 t.integer "right_id"
97 t.integer "role_id"
97 t.integer "role_id"
98 end
98 end
99
99
100 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
100 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
101
101
102 create_table "roles", :force => true do |t|
102 create_table "roles", :force => true do |t|
103 t.string "name"
103 t.string "name"
104 end
104 end
105
105
106 create_table "roles_users", :id => false, :force => true do |t|
106 create_table "roles_users", :id => false, :force => true do |t|
107 t.integer "role_id"
107 t.integer "role_id"
108 t.integer "user_id"
108 t.integer "user_id"
109 end
109 end
110
110
111 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
111 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
112
112
113 create_table "sessions", :force => true do |t|
113 create_table "sessions", :force => true do |t|
114 t.string "session_id"
114 t.string "session_id"
115 t.text "data"
115 t.text "data"
116 t.datetime "updated_at"
116 t.datetime "updated_at"
117 end
117 end
118
118
119 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
119 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
120 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
120 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
121
121
122 create_table "sites", :force => true do |t|
122 create_table "sites", :force => true do |t|
123 t.string "name"
123 t.string "name"
124 t.boolean "started"
124 t.boolean "started"
125 t.datetime "start_time"
125 t.datetime "start_time"
126 t.datetime "created_at"
126 t.datetime "created_at"
127 t.datetime "updated_at"
127 t.datetime "updated_at"
128 t.integer "country_id"
128 t.integer "country_id"
129 t.string "password"
129 t.string "password"
130 end
130 end
131
131
132 + create_table "submission_statuses", :force => true do |t|
133 + t.integer "user_id"
134 + t.integer "problem_id"
135 + t.boolean "passed"
136 + t.integer "submission_count"
137 + t.datetime "created_at"
138 + t.datetime "updated_at"
139 + end
140 +
132 create_table "submissions", :force => true do |t|
141 create_table "submissions", :force => true do |t|
133 t.integer "user_id"
142 t.integer "user_id"
134 t.integer "problem_id"
143 t.integer "problem_id"
135 t.integer "language_id"
144 t.integer "language_id"
136 t.text "source"
145 t.text "source"
137 t.binary "binary"
146 t.binary "binary"
138 t.datetime "submitted_at"
147 t.datetime "submitted_at"
139 t.datetime "compiled_at"
148 t.datetime "compiled_at"
140 t.text "compiler_message"
149 t.text "compiler_message"
141 t.datetime "graded_at"
150 t.datetime "graded_at"
142 t.integer "points"
151 t.integer "points"
143 t.text "grader_comment"
152 t.text "grader_comment"
144 t.integer "number"
153 t.integer "number"
145 t.string "source_filename"
154 t.string "source_filename"
146 end
155 end
147
156
148 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
157 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
149 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
158 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
150
159
151 create_table "tasks", :force => true do |t|
160 create_table "tasks", :force => true do |t|
152 t.integer "submission_id"
161 t.integer "submission_id"
153 t.datetime "created_at"
162 t.datetime "created_at"
154 t.integer "status"
163 t.integer "status"
155 t.datetime "updated_at"
164 t.datetime "updated_at"
156 end
165 end
157
166
158 create_table "test_pair_assignments", :force => true do |t|
167 create_table "test_pair_assignments", :force => true do |t|
159 t.integer "user_id"
168 t.integer "user_id"
160 t.integer "problem_id"
169 t.integer "problem_id"
161 t.integer "test_pair_id"
170 t.integer "test_pair_id"
162 t.integer "test_pair_number"
171 t.integer "test_pair_number"
163 t.integer "request_number"
172 t.integer "request_number"
164 t.datetime "created_at"
173 t.datetime "created_at"
165 t.datetime "updated_at"
174 t.datetime "updated_at"
166 t.boolean "submitted"
175 t.boolean "submitted"
167 end
176 end
168
177
169 create_table "test_pairs", :force => true do |t|
178 create_table "test_pairs", :force => true do |t|
170 t.integer "problem_id"
179 t.integer "problem_id"
171 t.text "input"
180 t.text "input"
172 t.text "solution"
181 t.text "solution"
173 t.datetime "created_at"
182 t.datetime "created_at"
174 t.datetime "updated_at"
183 t.datetime "updated_at"
175 t.integer "number"
184 t.integer "number"
176 end
185 end
177
186
178 create_table "test_requests", :force => true do |t|
187 create_table "test_requests", :force => true do |t|
179 t.integer "user_id"
188 t.integer "user_id"
deleted file
You need to be logged in to leave comments. Login now