Description:
test interface upload git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@81 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r36:a3144ce1a174 - - 13 files changed: 269 inserted, 20 deleted

@@ -0,0 +1,64
1 + require 'fileutils'
2 +
3 + class TestRequest < Task
4 +
5 + set_table_name "test_requests"
6 +
7 + belongs_to :user
8 + belongs_to :problem
9 + belongs_to :submission
10 +
11 + def self.get_inqueue_and_change_status(status)
12 + # since there will be only one grader grading TestRequest
13 + # we do not need locking (hopefully)
14 +
15 + task = Task.find(:first,
16 + :order => "created_at",
17 + :conditions => {:status=> Task::STATUS_INQUEUE})
18 + if task!=nil
19 + task.status = status
20 + task.save!
21 + end
22 +
23 + task
24 + end
25 +
26 + # interfacing with form
27 + def self.new_from_form_params(user,params)
28 + test_request = TestRequest.new
29 + test_request.user = user
30 + problem = Problem.find(params[:problem_id])
31 + test_request.problem = problem
32 + test_request.submission =
33 + Submission.find_by_user_problem_number(user.id,
34 + problem.id,
35 + params[:submission_number])
36 + test_request.input_file_name = save_input_file(params[:input_file], user, problem)
37 + test_request.submitted_at = Time.new
38 + test_request.status_inqueue
39 + test_request
40 + end
41 +
42 + protected
43 + def self.input_file_name(user,problem)
44 + begin
45 + tmpname = UPLOADED_INPUT_FILE_DIR + "/#{user.login}/#{problem.name}/#{rand(10000)}"
46 + end while File.exists?(tmpname)
47 + tmpname
48 + end
49 +
50 + def self.save_input_file(tempfile, user, problem)
51 + new_file_name = input_file_name(user,problem)
52 + dirname = File.dirname(new_file_name)
53 + FileUtils.mkdir_p(File.dirname(new_file_name)) if !File.exists?(dirname)
54 + if tempfile.instance_of?(Tempfile)
55 + tempfile.close
56 + FileUtils.move(tempfile.path,new_file_name)
57 + else
58 + File.open(new_file_name, "wb") do |f|
59 + f.write(tempfile.read)
60 + end
61 + end
62 + new_file_name
63 + end
64 + end
@@ -0,0 +1,5
1 + %tr.test-request
2 + %td= test_request_counter +1
3 + %td= test_request.problem.full_name
4 + %td= test_request.submission_id
5 + %td= test_request.status_str
@@ -0,0 +1,67
1 + <h2>Test Interface</h2>
2 +
3 + <% if @problems.length==0 %>
4 + "There is no submission"
5 + <% return %>
6 + <% end %>
7 +
8 + <script type="text/javascript">
9 + var submissionCount = {
10 + <% @submissions.each do |submission| %>
11 + <%= submission.problem_id %> : <%= submission.number %>,
12 + <% end %>
13 + };
14 + function updateSubmissionList() {
15 + currentProb = document.getElementById("test_request_problem_id").value;
16 + count = submissionCount[currentProb];
17 + submissionSelect = document.getElementById("test_request_submission_number");
18 + submissionSelect.options.length = 0;
19 + for(i=0; i<count; i++) {
20 + submissionSelect.options[i] = new Option(""+(i+1),""+(i+1),false,false);
21 + }
22 + }
23 + </script>
24 +
25 + <% form_for :test_request, nil,
26 + :url => { :action => 'test_submit'},
27 + :html => { :multipart => true } do |f| %>
28 + <table>
29 + <tr>
30 + <td>Task:</td>
31 + <td>
32 + <%= select(:test_request,
33 + :problem_id,
34 + @problems.collect {|p| [p.name, p.id]}, {},
35 + { :onclick => "updateSubmissionList();" }) %>
36 + </td>
37 + </tr>
38 + <tr>
39 + <td>Submission:</td>
40 + <td>
41 + <%= select(:test_request,
42 + :submission_number,
43 + (1..@submissions[0].number).collect {|n| [n,n]}) %>
44 + </td>
45 + </tr>
46 + <tr>
47 + <td>Input data:</td>
48 + <td><%= f.file_field :input_file %></td>
49 + <tr>
50 + <td colspan="2">
51 + <%= submit_tag 'submit' %>
52 + </td>
53 + </tr>
54 + </table>
55 + <% end %>
56 +
57 + <h3>Previous requests</h3>
58 +
59 + <table border="1">
60 + <tr>
61 + <th></td>
62 + <th>problem</th>
63 + <th>#</th>
64 + <th>status</th>
65 + </tr>
66 + <%= render :partial => 'test_request', :collection => @user.test_requests %>
67 + </table>
@@ -0,0 +1,30
1 + class CreateTestRequests < ActiveRecord::Migration
2 + def self.up
3 + create_table :test_requests do |t|
4 + t.column :user_id, :integer
5 + t.column :problem_id, :integer
6 + t.column :submission_id, :integer
7 + t.column :input_file_name, :string
8 + t.column :output_file_name, :string
9 + t.column :running_stat, :string
10 +
11 + # these are similar to tasks
12 + t.column :status, :integer
13 + t.column :updated_at, :datetime
14 +
15 + # these are intentionally similar to submissions
16 + t.column :submitted_at, :datetime
17 + t.column :compiled_at, :datetime
18 + t.column :compiler_message, :string
19 + t.column :graded_at, :datetime
20 + t.column :grader_comment, :string
21 + t.timestamps
22 + end
23 + add_index :test_requests, [:user_id, :problem_id]
24 + end
25 +
26 + def self.down
27 + remove_index :test_requests, :column => [:user_id, :problem_id]
28 + drop_table :test_requests
29 + end
30 + end
@@ -0,0 +1,7
1 + # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 +
3 + # one:
4 + # column: value
5 + #
6 + # two:
7 + # column: value
@@ -0,0 +1,8
1 + require File.dirname(__FILE__) + '/../test_helper'
2 +
3 + class TestRequestTest < ActiveSupport::TestCase
4 + # Replace this with your real tests.
5 + def test_truth
6 + assert true
7 + end
8 + end
@@ -48,12 +48,29
48 :type => 'text/plain'})
48 :type => 'text/plain'})
49 else
49 else
50 flash[:notice] = 'Error viewing source'
50 flash[:notice] = 'Error viewing source'
51 end
51 end
52 end
52 end
53
53
54 + def test
55 + @user = User.find(session[:user_id])
56 + @submissions = Submission.find_last_for_all_available_problems(@user.id)
57 + @problems = @submissions.collect { |submission| submission.problem }
58 + end
59 +
60 + def test_submit
61 + @user = User.find(session[:user_id])
62 + test_request = TestRequest.new_from_form_params(@user,params[:test_request])
63 + if test_request.save
64 + redirect_to :action => 'test'
65 + else
66 + flash[:notice] = 'Error saving your test submission'
67 + render :action => 'test'
68 + end
69 + end
70 +
54 protected
71 protected
55 def prepare_list_information
72 def prepare_list_information
56 @problems = Problem.find_available_problems
73 @problems = Problem.find_available_problems
57 @prob_submissions = Array.new
74 @prob_submissions = Array.new
58 @user = User.find(session[:user_id])
75 @user = User.find(session[:user_id])
59 @problems.each do |p|
76 @problems.each do |p|
@@ -1,35 +1,33
1 # Methods added to this helper will be available to all templates in the application.
1 # Methods added to this helper will be available to all templates in the application.
2 module ApplicationHelper
2 module ApplicationHelper
3
3
4 def user_header
4 def user_header
5 - options = ''
5 + menu_items = ''
6 user = User.find(session[:user_id])
6 user = User.find(session[:user_id])
7
7
8 # main page
8 # main page
9 - options += link_to_unless_current '[Main]',
9 + append_to menu_items, '[Main]', 'main', 'list'
10 - :controller => 'main', :action => 'list'
10 + append_to menu_items, '[Test]', 'main', 'test'
11 - options += ' '
12
11
13 # admin menu
12 # admin menu
14 if (user!=nil) and (user.admin?)
13 if (user!=nil) and (user.admin?)
15 - options +=
14 + append_to menu_items, '[Problem admin]', 'problems', 'index'
16 - (link_to_unless_current '[Problem admin]',
15 + append_to menu_items, '[User admin]', 'user_admin', 'index'
17 - :controller => 'problems', :action => 'index') + ' '
16 + append_to menu_items, '[User stat]', 'user_admin', 'user_stat'
18 - options +=
19 - (link_to_unless_current '[User admin]',
20 - :controller => 'user_admin', :action => 'index') + ' '
21 - options +=
22 - (link_to_unless_current '[User stat]',
23 - :controller => 'user_admin', :action => 'user_stat') + ' '
24 end
17 end
25
18
26 # general options
19 # general options
27 - options += link_to_unless_current '[Settings]',
20 + append_to menu_items, '[Settings]', 'users', 'index'
28 - :controller => 'users', :action => 'index'
21 + append_to menu_items, '[Log out]', 'main', 'login'
29 - options += ' '
22 +
30 - options +=
23 + menu_items
31 - link_to('[Log out]', {:controller => 'main', :action => 'login'})
24 + end
32 - options
25 +
26 + def append_to(option,label, controller, action)
27 + option << ' ' if option!=''
28 + option << link_to_unless_current(label,
29 + :controller => controller,
30 + :action => action)
33 end
31 end
34
32
35 end
33 end
@@ -27,12 +27,31
27 "(SELECT MAX(id) FROM submissions AS subs " +
27 "(SELECT MAX(id) FROM submissions AS subs " +
28 "WHERE subs.user_id = submissions.user_id AND " +
28 "WHERE subs.user_id = submissions.user_id AND " +
29 "problem_id = " + problem_id.to_s + " " +
29 "problem_id = " + problem_id.to_s + " " +
30 "GROUP BY user_id)")
30 "GROUP BY user_id)")
31 end
31 end
32
32
33 + def self.find_last_for_all_available_problems(user_id)
34 + submissions = Array.new
35 + problems = Problem.find_available_problems
36 + problems.each do |problem|
37 + sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
38 + submissions << sub if sub!=nil
39 + end
40 + submissions
41 + end
42 +
43 + def self.find_by_user_problem_number(user_id, problem_id, number)
44 + Submission.find(:first,
45 + :conditions => {
46 + :user_id => user_id,
47 + :problem_id => problem_id,
48 + :number => number
49 + })
50 + end
51 +
33 protected
52 protected
34
53
35 def self.find_option_in_source(option, source)
54 def self.find_option_in_source(option, source)
36 if source==nil
55 if source==nil
37 return nil
56 return nil
38 end
57 end
@@ -28,12 +28,23
28
28
29 def status_complete!
29 def status_complete!
30 status_complete
30 status_complete
31 self.save
31 self.save
32 end
32 end
33
33
34 + def status_str
35 + case self.status
36 + when Task::STATUS_INQUEUE
37 + "inqueue"
38 + when Task::STATUS_GRADING
39 + "grading"
40 + when Task::STATUS_COMPLETE
41 + "complete"
42 + end
43 + end
44 +
34 def self.get_inqueue_and_change_status(status)
45 def self.get_inqueue_and_change_status(status)
35 task = nil
46 task = nil
36 begin
47 begin
37 Task.transaction do
48 Task.transaction do
38 task = Task.find(:first,
49 task = Task.find(:first,
39 :order => "created_at",
50 :order => "created_at",
@@ -1,12 +1,14
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 => "problem_id"
8 +
7 validates_presence_of :login
9 validates_presence_of :login
8 validates_presence_of :full_name
10 validates_presence_of :full_name
9 validates_length_of :full_name, :minimum => 1
11 validates_length_of :full_name, :minimum => 1
10
12
11 validates_presence_of :password, :if => :password_required?
13 validates_presence_of :password, :if => :password_required?
12 validates_length_of :password, :within => 4..20, :if => :password_required?
14 validates_length_of :password, :within => 4..20, :if => :password_required?
@@ -55,6 +55,8
55
55
56 # Add new mime types for use in respond_to blocks:
56 # Add new mime types for use in respond_to blocks:
57 # Mime::Type.register "text/richtext", :rtf
57 # Mime::Type.register "text/richtext", :rtf
58 # Mime::Type.register "application/x-mobile", :mobile
58 # Mime::Type.register "application/x-mobile", :mobile
59
59
60 # Include your application configuration below
60 # Include your application configuration below
61 +
62 + UPLOADED_INPUT_FILE_DIR = '/home/jittat/web_grader/upload/'
@@ -6,13 +6,13
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 => 18) do
12 + ActiveRecord::Schema.define(:version => 19) do
13
13
14 create_table "grader_processes", :force => true do |t|
14 create_table "grader_processes", :force => true do |t|
15 t.string "host", :limit => 20
15 t.string "host", :limit => 20
16 t.integer "pid"
16 t.integer "pid"
17 t.string "mode"
17 t.string "mode"
18 t.boolean "active"
18 t.boolean "active"
@@ -93,12 +93,31
93 t.integer "submission_id"
93 t.integer "submission_id"
94 t.datetime "created_at"
94 t.datetime "created_at"
95 t.integer "status"
95 t.integer "status"
96 t.datetime "updated_at"
96 t.datetime "updated_at"
97 end
97 end
98
98
99 + create_table "test_requests", :force => true do |t|
100 + t.integer "user_id"
101 + t.integer "problem_id"
102 + t.integer "submission_id"
103 + t.string "input_file_name"
104 + t.string "output_file_name"
105 + t.string "running_stat"
106 + t.integer "status"
107 + t.datetime "updated_at"
108 + t.datetime "submitted_at"
109 + t.datetime "compiled_at"
110 + t.string "compiler_message"
111 + t.datetime "graded_at"
112 + t.string "grader_comment"
113 + t.datetime "created_at"
114 + end
115 +
116 + add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
117 +
99 create_table "users", :force => true do |t|
118 create_table "users", :force => true do |t|
100 t.string "login", :limit => 10
119 t.string "login", :limit => 10
101 t.string "full_name"
120 t.string "full_name"
102 t.string "hashed_password"
121 t.string "hashed_password"
103 t.string "salt", :limit => 5
122 t.string "salt", :limit => 5
104 t.string "alias"
123 t.string "alias"
You need to be logged in to leave comments. Login now