diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb --- a/app/controllers/main_controller.rb +++ b/app/controllers/main_controller.rb @@ -51,6 +51,23 @@ end end + def test + @user = User.find(session[:user_id]) + @submissions = Submission.find_last_for_all_available_problems(@user.id) + @problems = @submissions.collect { |submission| submission.problem } + end + + def test_submit + @user = User.find(session[:user_id]) + test_request = TestRequest.new_from_form_params(@user,params[:test_request]) + if test_request.save + redirect_to :action => 'test' + else + flash[:notice] = 'Error saving your test submission' + render :action => 'test' + end + end + protected def prepare_list_information @problems = Problem.find_available_problems diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,34 +2,32 @@ module ApplicationHelper def user_header - options = '' + menu_items = '' user = User.find(session[:user_id]) # main page - options += link_to_unless_current '[Main]', - :controller => 'main', :action => 'list' - options += ' ' + append_to menu_items, '[Main]', 'main', 'list' + append_to menu_items, '[Test]', 'main', 'test' # admin menu if (user!=nil) and (user.admin?) - options += - (link_to_unless_current '[Problem admin]', - :controller => 'problems', :action => 'index') + ' ' - options += - (link_to_unless_current '[User admin]', - :controller => 'user_admin', :action => 'index') + ' ' - options += - (link_to_unless_current '[User stat]', - :controller => 'user_admin', :action => 'user_stat') + ' ' + append_to menu_items, '[Problem admin]', 'problems', 'index' + append_to menu_items, '[User admin]', 'user_admin', 'index' + append_to menu_items, '[User stat]', 'user_admin', 'user_stat' end # general options - options += link_to_unless_current '[Settings]', - :controller => 'users', :action => 'index' - options += ' ' - options += - link_to('[Log out]', {:controller => 'main', :action => 'login'}) - options + append_to menu_items, '[Settings]', 'users', 'index' + append_to menu_items, '[Log out]', 'main', 'login' + + menu_items + end + + def append_to(option,label, controller, action) + option << ' ' if option!='' + option << link_to_unless_current(label, + :controller => controller, + :action => action) end end diff --git a/app/models/submission.rb b/app/models/submission.rb --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -30,6 +30,25 @@ "GROUP BY user_id)") end + def self.find_last_for_all_available_problems(user_id) + submissions = Array.new + problems = Problem.find_available_problems + problems.each do |problem| + sub = Submission.find_last_by_user_and_problem(user_id, problem.id) + submissions << sub if sub!=nil + end + submissions + end + + def self.find_by_user_problem_number(user_id, problem_id, number) + Submission.find(:first, + :conditions => { + :user_id => user_id, + :problem_id => problem_id, + :number => number + }) + end + protected def self.find_option_in_source(option, source) diff --git a/app/models/task.rb b/app/models/task.rb --- a/app/models/task.rb +++ b/app/models/task.rb @@ -31,6 +31,17 @@ self.save end + def status_str + case self.status + when Task::STATUS_INQUEUE + "inqueue" + when Task::STATUS_GRADING + "grading" + when Task::STATUS_COMPLETE + "complete" + end + end + def self.get_inqueue_and_change_status(status) task = nil begin diff --git a/app/models/test_request.rb b/app/models/test_request.rb new file mode 100644 --- /dev/null +++ b/app/models/test_request.rb @@ -0,0 +1,64 @@ +require 'fileutils' + +class TestRequest < Task + + set_table_name "test_requests" + + belongs_to :user + belongs_to :problem + belongs_to :submission + + def self.get_inqueue_and_change_status(status) + # since there will be only one grader grading TestRequest + # we do not need locking (hopefully) + + task = Task.find(:first, + :order => "created_at", + :conditions => {:status=> Task::STATUS_INQUEUE}) + if task!=nil + task.status = status + task.save! + end + + task + end + + # interfacing with form + def self.new_from_form_params(user,params) + test_request = TestRequest.new + test_request.user = user + problem = Problem.find(params[:problem_id]) + test_request.problem = problem + test_request.submission = + Submission.find_by_user_problem_number(user.id, + problem.id, + params[:submission_number]) + test_request.input_file_name = save_input_file(params[:input_file], user, problem) + test_request.submitted_at = Time.new + test_request.status_inqueue + test_request + end + + protected + def self.input_file_name(user,problem) + begin + tmpname = UPLOADED_INPUT_FILE_DIR + "/#{user.login}/#{problem.name}/#{rand(10000)}" + end while File.exists?(tmpname) + tmpname + end + + def self.save_input_file(tempfile, user, problem) + new_file_name = input_file_name(user,problem) + dirname = File.dirname(new_file_name) + FileUtils.mkdir_p(File.dirname(new_file_name)) if !File.exists?(dirname) + if tempfile.instance_of?(Tempfile) + tempfile.close + FileUtils.move(tempfile.path,new_file_name) + else + File.open(new_file_name, "wb") do |f| + f.write(tempfile.read) + end + end + new_file_name + end +end diff --git a/app/models/user.rb b/app/models/user.rb --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,6 +4,8 @@ has_and_belongs_to_many :roles + has_many :test_requests, :order => "problem_id" + validates_presence_of :login validates_presence_of :full_name validates_length_of :full_name, :minimum => 1 diff --git a/app/views/main/_test_request.html.haml b/app/views/main/_test_request.html.haml new file mode 100644 --- /dev/null +++ b/app/views/main/_test_request.html.haml @@ -0,0 +1,5 @@ +%tr.test-request + %td= test_request_counter +1 + %td= test_request.problem.full_name + %td= test_request.submission_id + %td= test_request.status_str diff --git a/app/views/main/test.html.erb b/app/views/main/test.html.erb new file mode 100644 --- /dev/null +++ b/app/views/main/test.html.erb @@ -0,0 +1,67 @@ +

Test Interface

+ +<% if @problems.length==0 %> + "There is no submission" + <% return %> +<% end %> + + + +<% form_for :test_request, nil, + :url => { :action => 'test_submit'}, + :html => { :multipart => true } do |f| %> + + + + + + + + + + + + + + + +
Task: + <%= select(:test_request, + :problem_id, + @problems.collect {|p| [p.name, p.id]}, {}, + { :onclick => "updateSubmissionList();" }) %> +
Submission: + <%= select(:test_request, + :submission_number, + (1..@submissions[0].number).collect {|n| [n,n]}) %> +
Input data:<%= f.file_field :input_file %>
+ <%= submit_tag 'submit' %> +
+<% end %> + +

Previous requests

+ + + + + + + +<%= render :partial => 'test_request', :collection => @user.test_requests %> +
+ problem#status
diff --git a/config/environment.rb b/config/environment.rb --- a/config/environment.rb +++ b/config/environment.rb @@ -58,3 +58,5 @@ # Mime::Type.register "application/x-mobile", :mobile # Include your application configuration below + +UPLOADED_INPUT_FILE_DIR = '/home/jittat/web_grader/upload/' diff --git a/db/migrate/019_create_test_requests.rb b/db/migrate/019_create_test_requests.rb new file mode 100644 --- /dev/null +++ b/db/migrate/019_create_test_requests.rb @@ -0,0 +1,30 @@ +class CreateTestRequests < ActiveRecord::Migration + def self.up + create_table :test_requests do |t| + t.column :user_id, :integer + t.column :problem_id, :integer + t.column :submission_id, :integer + t.column :input_file_name, :string + t.column :output_file_name, :string + t.column :running_stat, :string + + # these are similar to tasks + t.column :status, :integer + t.column :updated_at, :datetime + + # these are intentionally similar to submissions + t.column :submitted_at, :datetime + t.column :compiled_at, :datetime + t.column :compiler_message, :string + t.column :graded_at, :datetime + t.column :grader_comment, :string + t.timestamps + end + add_index :test_requests, [:user_id, :problem_id] + end + + def self.down + remove_index :test_requests, :column => [:user_id, :problem_id] + drop_table :test_requests + end +end diff --git a/db/schema.rb b/db/schema.rb --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 18) do +ActiveRecord::Schema.define(:version => 19) do create_table "grader_processes", :force => true do |t| t.string "host", :limit => 20 @@ -96,6 +96,25 @@ t.datetime "updated_at" end + create_table "test_requests", :force => true do |t| + t.integer "user_id" + t.integer "problem_id" + t.integer "submission_id" + t.string "input_file_name" + t.string "output_file_name" + t.string "running_stat" + t.integer "status" + t.datetime "updated_at" + t.datetime "submitted_at" + t.datetime "compiled_at" + t.string "compiler_message" + t.datetime "graded_at" + t.string "grader_comment" + t.datetime "created_at" + end + + add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id" + create_table "users", :force => true do |t| t.string "login", :limit => 10 t.string "full_name" diff --git a/test/fixtures/test_requests.yml b/test/fixtures/test_requests.yml new file mode 100644 --- /dev/null +++ b/test/fixtures/test_requests.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/test/unit/test_request_test.rb b/test/unit/test_request_test.rb new file mode 100644 --- /dev/null +++ b/test/unit/test_request_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class TestRequestTest < ActiveSupport::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end