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:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
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 | 48 | :type => 'text/plain'}) |
|
49 | 49 | else |
|
50 | 50 | flash[:notice] = 'Error viewing source' |
|
51 | 51 | end |
|
52 | 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 | 71 | protected |
|
55 | 72 | def prepare_list_information |
|
56 | 73 | @problems = Problem.find_available_problems |
|
57 | 74 | @prob_submissions = Array.new |
|
58 | 75 | @user = User.find(session[:user_id]) |
|
59 | 76 | @problems.each do |p| |
@@ -1,35 +1,33 | |||
|
1 | 1 | # Methods added to this helper will be available to all templates in the application. |
|
2 | 2 | module ApplicationHelper |
|
3 | 3 | |
|
4 | 4 | def user_header |
|
5 |
- |
|
|
5 | + menu_items = '' | |
|
6 | 6 | user = User.find(session[:user_id]) |
|
7 | 7 | |
|
8 | 8 | # main page |
|
9 | - options += link_to_unless_current '[Main]', | |
|
10 | - :controller => 'main', :action => 'list' | |
|
11 | - options += ' ' | |
|
9 | + append_to menu_items, '[Main]', 'main', 'list' | |
|
10 | + append_to menu_items, '[Test]', 'main', 'test' | |
|
12 | 11 | |
|
13 | 12 | # admin menu |
|
14 | 13 | if (user!=nil) and (user.admin?) |
|
15 | - options += | |
|
16 | - (link_to_unless_current '[Problem admin]', | |
|
17 | - :controller => 'problems', :action => 'index') + ' ' | |
|
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') + ' ' | |
|
14 | + append_to menu_items, '[Problem admin]', 'problems', 'index' | |
|
15 | + append_to menu_items, '[User admin]', 'user_admin', 'index' | |
|
16 | + append_to menu_items, '[User stat]', 'user_admin', 'user_stat' | |
|
24 | 17 | end |
|
25 | 18 | |
|
26 | 19 | # general options |
|
27 | - options += link_to_unless_current '[Settings]', | |
|
28 | - :controller => 'users', :action => 'index' | |
|
29 | - options += ' ' | |
|
30 | - options += | |
|
31 | - link_to('[Log out]', {:controller => 'main', :action => 'login'}) | |
|
32 | - options | |
|
20 | + append_to menu_items, '[Settings]', 'users', 'index' | |
|
21 | + append_to menu_items, '[Log out]', 'main', 'login' | |
|
22 | + | |
|
23 | + menu_items | |
|
24 | + end | |
|
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 | 31 | end |
|
34 | 32 | |
|
35 | 33 | end |
@@ -27,12 +27,31 | |||
|
27 | 27 | "(SELECT MAX(id) FROM submissions AS subs " + |
|
28 | 28 | "WHERE subs.user_id = submissions.user_id AND " + |
|
29 | 29 | "problem_id = " + problem_id.to_s + " " + |
|
30 | 30 | "GROUP BY user_id)") |
|
31 | 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 | 52 | protected |
|
34 | 53 | |
|
35 | 54 | def self.find_option_in_source(option, source) |
|
36 | 55 | if source==nil |
|
37 | 56 | return nil |
|
38 | 57 | end |
@@ -28,12 +28,23 | |||
|
28 | 28 | |
|
29 | 29 | def status_complete! |
|
30 | 30 | status_complete |
|
31 | 31 | self.save |
|
32 | 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 | 45 | def self.get_inqueue_and_change_status(status) |
|
35 | 46 | task = nil |
|
36 | 47 | begin |
|
37 | 48 | Task.transaction do |
|
38 | 49 | task = Task.find(:first, |
|
39 | 50 | :order => "created_at", |
@@ -1,12 +1,14 | |||
|
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 | + has_many :test_requests, :order => "problem_id" | |
|
8 | + | |
|
7 | 9 | validates_presence_of :login |
|
8 | 10 | validates_presence_of :full_name |
|
9 | 11 | validates_length_of :full_name, :minimum => 1 |
|
10 | 12 | |
|
11 | 13 | validates_presence_of :password, :if => :password_required? |
|
12 | 14 | validates_length_of :password, :within => 4..20, :if => :password_required? |
@@ -55,6 +55,8 | |||
|
55 | 55 | |
|
56 | 56 | # Add new mime types for use in respond_to blocks: |
|
57 | 57 | # Mime::Type.register "text/richtext", :rtf |
|
58 | 58 | # Mime::Type.register "application/x-mobile", :mobile |
|
59 | 59 | |
|
60 | 60 | # Include your application configuration below |
|
61 | + | |
|
62 | + UPLOADED_INPUT_FILE_DIR = '/home/jittat/web_grader/upload/' |
@@ -6,13 +6,13 | |||
|
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 => 1 |
|
|
12 | + ActiveRecord::Schema.define(:version => 19) do | |
|
13 | 13 | |
|
14 | 14 | create_table "grader_processes", :force => true do |t| |
|
15 | 15 | t.string "host", :limit => 20 |
|
16 | 16 | t.integer "pid" |
|
17 | 17 | t.string "mode" |
|
18 | 18 | t.boolean "active" |
@@ -93,12 +93,31 | |||
|
93 | 93 | t.integer "submission_id" |
|
94 | 94 | t.datetime "created_at" |
|
95 | 95 | t.integer "status" |
|
96 | 96 | t.datetime "updated_at" |
|
97 | 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 | 118 | create_table "users", :force => true do |t| |
|
100 | 119 | t.string "login", :limit => 10 |
|
101 | 120 | t.string "full_name" |
|
102 | 121 | t.string "hashed_password" |
|
103 | 122 | t.string "salt", :limit => 5 |
|
104 | 123 | t.string "alias" |
You need to be logged in to leave comments.
Login now