Description:
- after submission, redirecto to edit_submission_path - add more info to submission status - fix bug #20 and #21
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r696:0b7243db68e6 - - 11 files changed: 33 inserted, 23 deleted

@@ -76,49 +76,49
76 76 @submission.source_filename = "live_edit.#{language.ext}"
77 77 @submission.language = language
78 78 end
79 79
80 80 @submission.submitted_at = Time.new.gmtime
81 81 @submission.ip_address = request.remote_ip
82 82
83 83 if GraderConfiguration.time_limit_mode? and user.contest_finished?
84 84 @submission.errors.add(:base,"The contest is over.")
85 85 prepare_list_information
86 86 render :action => 'list' and return
87 87 end
88 88
89 89 if @submission.valid?(@current_user)
90 90 if @submission.save == false
91 91 flash[:notice] = 'Error saving your submission'
92 92 elsif Task.create(:submission_id => @submission.id,
93 93 :status => Task::STATUS_INQUEUE) == false
94 94 flash[:notice] = 'Error adding your submission to task queue'
95 95 end
96 96 else
97 97 prepare_list_information
98 98 render :action => 'list' and return
99 99 end
100 - redirect_to :action => 'list'
100 + redirect_to edit_submission_path(@submission)
101 101 end
102 102
103 103 def source
104 104 submission = Submission.find(params[:id])
105 105 if ((submission.user_id == session[:user_id]) and
106 106 (submission.problem != nil) and
107 107 (submission.problem.available))
108 108 send_data(submission.source,
109 109 {:filename => submission.download_filename,
110 110 :type => 'text/plain'})
111 111 else
112 112 flash[:notice] = 'Error viewing source'
113 113 redirect_to :action => 'list'
114 114 end
115 115 end
116 116
117 117 def compiler_msg
118 118 @submission = Submission.find(params[:id])
119 119 if @submission.user_id == session[:user_id]
120 120 render :action => 'compiler_msg', :layout => 'empty'
121 121 else
122 122 flash[:notice] = 'Error viewing source'
123 123 redirect_to :action => 'list'
124 124 end
@@ -31,48 +31,50
31 31 end
32 32
33 33 def show_max_score
34 34 #process parameters
35 35 #problems
36 36 @problems = []
37 37 if params[:problem_id]
38 38 params[:problem_id].each do |id|
39 39 next unless id.strip != ""
40 40 pid = Problem.find_by_id(id.to_i)
41 41 @problems << pid if pid
42 42 end
43 43 end
44 44
45 45 #users
46 46 @users = if params[:user] == "all" then
47 47 User.includes(:contests).includes(:contest_stat)
48 48 else
49 49 User.includes(:contests).includes(:contest_stat).where(enabled: true)
50 50 end
51 51
52 52 #set up range from param
53 53 @since_id = params.fetch(:from_id, 0).to_i
54 54 @until_id = params.fetch(:to_id, 0).to_i
55 + @since_id = nil if @since_id == 0
56 + @until_id = nil if @until_id == 0
55 57
56 58 #calculate the routine
57 59 @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
58 60
59 61 #rencer accordingly
60 62 if params[:button] == 'download' then
61 63 csv = gen_csv_from_scorearray(@scorearray,@problems)
62 64 send_data csv, filename: 'max_score.csv'
63 65 else
64 66 #render template: 'user_admin/user_stat'
65 67 render 'max_score'
66 68 end
67 69
68 70 end
69 71
70 72 def score
71 73 if params[:commit] == 'download csv'
72 74 @problems = Problem.all
73 75 else
74 76 @problems = Problem.available_problems
75 77 end
76 78 @users = User.includes(:contests, :contest_stat).where(enabled: true)
77 79 @scorearray = Array.new
78 80 @users.each do |u|
@@ -64,63 +64,66
64 64 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
65 65 end
66 66
67 67 if GraderConfiguration['right.user_hall_of_fame']
68 68 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
69 69 end
70 70 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
71 71
72 72 if GraderConfiguration['system.user_setting_enabled']
73 73 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
74 74 end
75 75 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
76 76
77 77 menu_items.html_safe
78 78 end
79 79
80 80 def append_to(option,label, controller, action)
81 81 option << ' ' if option!=''
82 82 option << link_to_unless_current(label,
83 83 :controller => controller,
84 84 :action => action)
85 85 end
86 86
87 87 def format_short_time(time)
88 - now = Time.now.gmtime
88 + now = Time.zone.now
89 89 st = ''
90 - if (time.yday != now.yday) or
91 - (time.year != now.year)
92 - st = time.strftime("%x ")
90 + if (time.yday != now.yday) or (time.year != now.year)
91 + st = time.strftime("%d/%m/%y ")
93 92 end
94 93 st + time.strftime("%X")
95 94 end
96 95
97 96 def format_short_duration(duration)
98 97 return '' if duration==nil
99 98 d = duration.to_f
100 99 return Time.at(d).gmtime.strftime("%X")
101 100 end
102 101
102 + def format_full_time_ago(time)
103 + st = time_ago_in_words(time) + ' ago (' + format_short_time(time) + ')'
104 + end
105 +
103 106 def read_textfile(fname,max_size=2048)
104 107 begin
105 108 File.open(fname).read(max_size)
106 109 rescue
107 110 nil
108 111 end
109 112 end
110 113
111 114 def toggle_button(on,toggle_url,id, option={})
112 115 btn_size = option[:size] || 'btn-xs'
113 116 link_to (on ? "Yes" : "No"), toggle_url,
114 117 {class: "btn btn-block #{btn_size} btn-#{on ? 'success' : 'default'} ajax-toggle",
115 118 id: id,
116 119 data: {remote: true, method: 'get'}}
117 120 end
118 121
119 122 def get_ace_mode(language)
120 123 # return ace mode string from Language
121 124
122 125 case language.pretty_name
123 126 when 'Pascal'
124 127 'ace/mode/pascal'
125 128 when 'C++','C'
126 129 'ace/mode/c_cpp'
@@ -13,50 +13,50
13 13 validate :must_have_valid_problem
14 14 validate :must_specify_language
15 15
16 16 has_one :task
17 17
18 18 before_save :assign_latest_number_if_new_recond
19 19
20 20 def self.find_last_by_user_and_problem(user_id, problem_id)
21 21 where("user_id = ? AND problem_id = ?",user_id,problem_id).last
22 22 end
23 23
24 24 def self.find_all_last_by_problem(problem_id)
25 25 # need to put in SQL command, maybe there's a better way
26 26 Submission.includes(:user).find_by_sql("SELECT * FROM submissions " +
27 27 "WHERE id = " +
28 28 "(SELECT MAX(id) FROM submissions AS subs " +
29 29 "WHERE subs.user_id = submissions.user_id AND " +
30 30 "problem_id = " + problem_id.to_s + " " +
31 31 "GROUP BY user_id) " +
32 32 "ORDER BY user_id")
33 33 end
34 34
35 35 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
36 36 records = Submission.where(problem_id: problem_id,user_id: user_id)
37 - records = records.where('id >= ?',since_id) if since_id > 0
38 - records = records.where('id <= ?',until_id) if until_id > 0
37 + records = records.where('id >= ?',since_id) if since_id and since_id > 0
38 + records = records.where('id <= ?',until_id) if until_id and until_id > 0
39 39 records.all
40 40 end
41 41
42 42 def self.find_last_for_all_available_problems(user_id)
43 43 submissions = Array.new
44 44 problems = Problem.available_problems
45 45 problems.each do |problem|
46 46 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
47 47 submissions << sub if sub!=nil
48 48 end
49 49 submissions
50 50 end
51 51
52 52 def self.find_by_user_problem_number(user_id, problem_id, number)
53 53 where("user_id = ? AND problem_id = ? AND number = ?",user_id,problem_id,number).first
54 54 end
55 55
56 56 def self.find_all_by_user_problem(user_id, problem_id)
57 57 where("user_id = ? AND problem_id = ?",user_id,problem_id)
58 58 end
59 59
60 60 def download_filename
61 61 if self.problem.output_only
62 62 return self.source_filename
@@ -1,26 +1,28
1 -
2 1 - if submission.nil?
3 2 = "-"
4 3 - else
4 + %strong= "Submission ID:"
5 + = submission.id
6 + %br
5 7 - unless submission.graded_at
6 - = t 'main.submitted_at'
7 - = format_short_time(submission.submitted_at.localtime)
8 + %strong= t 'main.submitted_at:'
9 + = format_full_time_ago(submission.submitted_at.localtime)
8 10 - else
9 - %strong= t 'main.graded_at'
10 - = "#{format_short_time(submission.graded_at.localtime)} "
11 + %strong= t 'main.graded_at:'
12 + = format_full_time_ago(submission.graded_at.localtime)
11 13 %br
12 14 - if GraderConfiguration['ui.show_score']
13 15 %strong=t 'main.score'
14 16 = "#{(submission.points*100/submission.problem.full_score).to_i} "
15 17 = " ["
16 18 %tt
17 19 = submission.grader_comment
18 20 = "]"
19 21 %br
20 - %strong View:
21 - - if GraderConfiguration.show_grading_result
22 - = link_to '[detailed result]', :action => 'result', :id => submission.id
23 - = link_to "#{t 'main.cmp_msg'}", {:action => 'compiler_msg', :id => submission.id}, {popup: true,class: 'btn btn-xs btn-info'}
22 + %strong View:
23 + - if GraderConfiguration.show_grading_result
24 + = link_to '[detailed result]', :action => 'result', :id => submission.id
25 + = link_to "#{t 'main.cmp_msg'}", {:action => 'compiler_msg', :id => submission.id}, {popup: true,class: 'btn btn-xs btn-info'} if submission.graded_at
24 26 = link_to "#{t 'main.src_link'}", download_submission_path(submission.id), class: 'btn btn-xs btn-info'
25 27 = link_to "#{t 'main.submissions_link'}", problem_submissions_path(problem_id), class: 'btn btn-xs btn-info'
26 28
@@ -12,38 +12,38
12 12 = label_tag :problem_id, "Problems"
13 13 = select_tag 'problem_id[]',
14 14 options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
15 15 { class: 'select2 form-control', multiple: "true" }
16 16 .col-md-4
17 17 .panel.panel-primary
18 18 .panel-heading
19 19 Submission range
20 20 .panel-body
21 21 %p
22 22 Input minimum and maximum range of submission ID that should be included. A blank value for min and max means -1 and infinity, respectively.
23 23 .form-group
24 24 = label_tag :from, "Min"
25 25 = text_field_tag 'from_id', @since_id, class: "form-control"
26 26 .form-group
27 27 = label_tag :from, "Max"
28 28 = text_field_tag 'to_id', @until_id, class: "form-control"
29 29 .col-md-4
30 30 .panel.panel-primary
31 31 .panel-heading
32 32 Users
33 33 .panel-body
34 34 .radio
35 35 %label
36 - = radio_button_tag 'users', 'all', true
36 + = radio_button_tag 'users', 'all', (params[:users] == "all")
37 37 All users
38 38 .radio
39 39 %label
40 - = radio_button_tag 'users', 'enabled'
40 + = radio_button_tag 'users', 'enabled', (params[:users] == "enabled")
41 41 Only enabled users
42 42 .row
43 43 .col-md-12
44 44 = button_tag 'Show', class: "btn btn-primary btn-large", value: "show"
45 45 = button_tag 'Download CSV', class: "btn btn-primary btn-large", value: "download"
46 46
47 47 - if @scorearray
48 48 %h2 Result
49 49 =render "score_table"
@@ -6,49 +6,49
6 6 .row
7 7 .col-md-12
8 8 .alert.alert-info
9 9 Write your code in the following box, choose language, and click submit button when finished
10 10 .row
11 11 .col-md-8
12 12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
13 13 .col-md-4
14 14 - # submission form
15 15 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
16 16
17 17 = hidden_field_tag 'editor_text', @source
18 18 = hidden_field_tag 'submission[problem_id]', @problem.id
19 19 .form-group
20 20 = label_tag "Task:"
21 21 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
22 22
23 23 .form-group
24 24 = label_tag 'Language'
25 25 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
26 26 .form-group
27 27 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
28 28 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
29 29 - # latest submission status
30 - .panel.panel-info
30 + .panel{class: (@submission && @submission.graded_at) ? "panel-info" : "panel-warning"}
31 31 .panel-heading
32 32 Latest Submission Status
33 33 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
34 34 .panel-body
35 35 - if @submission
36 36 = render :partial => 'submission_short',
37 37 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
38 38 .row
39 39 .col-md-12
40 40 %h2 Console
41 41 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
42 42
43 43 :javascript
44 44 $(document).ready(function() {
45 45 e = ace.edit("editor")
46 46 e.setValue($("#text_sourcecode").val());
47 47 e.gotoLine(1);
48 48 $("#language_id").trigger('change');
49 49 brython();
50 50 });
51 51
52 52
53 53 %script#__main__{type:'text/python3'}
54 54 :plain
@@ -44,29 +44,29
44 44
45 45 # Use SQL instead of Active Record's schema dumper when creating the database.
46 46 # This is necessary if your schema can't be completely dumped by the schema dumper,
47 47 # like if you have constraints or database-specific column types
48 48 # config.active_record.schema_format = :sql
49 49
50 50 # Enable the asset pipeline
51 51 config.assets.enabled = true
52 52
53 53 # Version of your assets, change this if you want to expire all your assets
54 54 config.assets.version = '1.0'
55 55
56 56 # ---------------- IMPORTANT ----------------------
57 57 # If we deploy the app into a subdir name "grader", be sure to do "rake assets:precompile RAILS_RELATIVE_URL_ROOT=/grader"
58 58 # moreover, using the following line instead also known to works
59 59 #config.action_controller.relative_url_root = '/grader'
60 60
61 61 #font path
62 62 config.assets.paths << "#{Rails}/vendor/assets/fonts"
63 63
64 64 config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js']
65 65 config.assets.precompile += ['local_jquery.js','tablesorter-theme.cafe.css']
66 66 %w( announcements submissions configurations contests contest_management graders heartbeat
67 67 login main messages problems report site sites sources tasks
68 - test user_admin users ).each do |controller|
68 + test user_admin users testcases).each do |controller|
69 69 config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
70 70 end
71 71 end
72 72 end
@@ -1,23 +1,23
1 1 # Be sure to restart your server when you modify this file.
2 2
3 3 # Version of your assets, change this if you want to expire all your assets.
4 4 Rails.application.config.assets.version = '1.0'
5 5
6 6 # Add additional assets to the asset load path.
7 7 # Rails.application.config.assets.paths << Emoji.images_path
8 8 # Add Yarn node_modules folder to the asset load path.
9 9 Rails.application.config.assets.paths << Rails.root.join('node_modules')
10 10 Rails.application.config.assets.paths << Rails.root.join('vendor/assets/fonts')
11 11
12 12 # Precompile additional assets.
13 13 # application.js, application.css, and all non-JS/CSS in the app/assets
14 14 # folder are already added.
15 15 # Rails.application.config.assets.precompile += %w( admin.js admin.css )
16 16
17 17 Rails.application.config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js']
18 18 Rails.application.config.assets.precompile += ['local_jquery.js','tablesorter-theme.cafe.css']
19 19 %w( announcements submissions configurations contests contest_management graders heartbeat
20 20 login main messages problems report site sites sources tasks groups
21 - test user_admin users tags).each do |controller|
21 + test user_admin users tags testcases).each do |controller|
22 22 Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
23 23 end
@@ -12,48 +12,49
12 12 File.join GRADER_ROOT_DIR, "raw"
13 13 end
14 14
15 15 def self.call_grader(params)
16 16 if GraderScript.grader_control_enabled?
17 17 cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
18 18 system(cmd)
19 19 end
20 20 end
21 21
22 22 def self.stop_grader(pid)
23 23 GraderScript.call_grader "stop #{pid}"
24 24 end
25 25
26 26 def self.stop_graders(pids)
27 27 pid_str = (pids.map { |process| process.pid.to_s }).join ' '
28 28 GraderScript.call_grader "stop #{pid_str}"
29 29 end
30 30
31 31 def self.start_grader(env)
32 32 GraderScript.call_grader "#{env} queue --err-log &"
33 33 GraderScript.call_grader "#{env} test_request -err-log &"
34 34 end
35 35
36 + #call the import problem script
36 37 def self.call_import_problem(problem_name,
37 38 problem_dir,
38 39 time_limit=1,
39 40 memory_limit=32,
40 41 checker_name='text')
41 42 if GraderScript.grader_control_enabled?
42 43 cur_dir = `pwd`.chomp
43 44 Dir.chdir(GRADER_ROOT_DIR)
44 45
45 46 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 47 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 48 " -t #{time_limit} -m #{memory_limit}"
48 49
49 50 output = `#{cmd}`
50 51
51 52 Dir.chdir(cur_dir)
52 53
53 54 return "import CMD: #{cmd}\n" + output
54 55 end
55 56 return ''
56 57 end
57 58
58 59 def self.call_import_testcase(problem_name)
59 60 if GraderScript.grader_control_enabled?
@@ -1,78 +1,80
1 1 require 'tmpdir'
2 2
3 3 class TestdataImporter
4 4
5 5 attr :log_msg
6 6
7 7 def initialize(problem)
8 8 @problem = problem
9 9 end
10 10
11 - def import_from_file(tempfile,
12 - time_limit,
11 + #Create or update problem according to the parameter
12 + def import_from_file(tempfile,
13 + time_limit,
13 14 memory_limit,
14 15 checker_name='text',
15 16 import_to_db=false)
16 17
17 18 dirname = extract(tempfile)
18 19 return false if not dirname
19 20 if not import_to_db
20 21 @log_msg = GraderScript.call_import_problem(@problem.name,
21 22 dirname,
22 23 time_limit,
23 24 memory_limit,
24 25 checker_name)
25 26 else
26 27 # Import test data to test pairs.
27 28
28 29 @problem.test_pairs.clear
29 30 if import_test_pairs(dirname)
30 31 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
31 32 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
32 33 else
33 34 @log_msg = "Importing test pair failed. (0 test pairs imported)"
34 35 end
35 36 end
36 37
37 38 @log_msg << import_problem_description(dirname)
38 39 @log_msg << import_problem_pdf(dirname)
39 40 @log_msg << import_full_score(dirname)
40 41
41 42 #import test data
42 43 @log_msg << GraderScript.call_import_testcase(@problem.name)
43 44
44 45 return true
45 46 end
46 47
47 48 protected
48 49
49 50 def self.long_ext(filename)
50 51 i = filename.index('.')
51 52 len = filename.length
52 53 return filename.slice(i..len)
53 54 end
54 55
56 + # extract an archive file located at +tempfile+ to the +raw_dir+
55 57 def extract(tempfile)
56 58 testdata_filename = save_testdata_file(tempfile)
57 59 ext = TestdataImporter.long_ext(tempfile.original_filename)
58 60
59 61 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
60 62 if File.exists? extract_dir
61 63 backup_count = 0
62 64 begin
63 65 backup_count += 1
64 66 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
65 67 end while File.exists? backup_dirname
66 68 File.rename(extract_dir, backup_dirname)
67 69 end
68 70 Dir.mkdir extract_dir
69 71
70 72 if ext=='.tar.gz' or ext=='.tgz'
71 73 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
72 74 elsif ext=='.tar'
73 75 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
74 76 elsif ext=='.zip'
75 77 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
76 78 else
77 79 return nil
78 80 end
You need to be logged in to leave comments. Login now