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

@@ -52,97 +52,97
52 def list
52 def list
53 prepare_list_information
53 prepare_list_information
54 end
54 end
55
55
56 def help
56 def help
57 @user = User.find(session[:user_id])
57 @user = User.find(session[:user_id])
58 end
58 end
59
59
60 def submit
60 def submit
61 user = User.find(session[:user_id])
61 user = User.find(session[:user_id])
62
62
63 @submission = Submission.new
63 @submission = Submission.new
64 @submission.problem_id = params[:submission][:problem_id]
64 @submission.problem_id = params[:submission][:problem_id]
65 @submission.user = user
65 @submission.user = user
66 @submission.language_id = 0
66 @submission.language_id = 0
67 if (params['file']) and (params['file']!='')
67 if (params['file']) and (params['file']!='')
68 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
68 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
69 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
69 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
70 @submission.source_filename = params['file'].original_filename
70 @submission.source_filename = params['file'].original_filename
71 end
71 end
72
72
73 if (params[:editor_text])
73 if (params[:editor_text])
74 language = Language.find_by_id(params[:language_id])
74 language = Language.find_by_id(params[:language_id])
75 @submission.source = params[:editor_text]
75 @submission.source = params[:editor_text]
76 @submission.source_filename = "live_edit.#{language.ext}"
76 @submission.source_filename = "live_edit.#{language.ext}"
77 @submission.language = language
77 @submission.language = language
78 end
78 end
79
79
80 @submission.submitted_at = Time.new.gmtime
80 @submission.submitted_at = Time.new.gmtime
81 @submission.ip_address = request.remote_ip
81 @submission.ip_address = request.remote_ip
82
82
83 if GraderConfiguration.time_limit_mode? and user.contest_finished?
83 if GraderConfiguration.time_limit_mode? and user.contest_finished?
84 @submission.errors.add(:base,"The contest is over.")
84 @submission.errors.add(:base,"The contest is over.")
85 prepare_list_information
85 prepare_list_information
86 render :action => 'list' and return
86 render :action => 'list' and return
87 end
87 end
88
88
89 if @submission.valid?(@current_user)
89 if @submission.valid?(@current_user)
90 if @submission.save == false
90 if @submission.save == false
91 flash[:notice] = 'Error saving your submission'
91 flash[:notice] = 'Error saving your submission'
92 elsif Task.create(:submission_id => @submission.id,
92 elsif Task.create(:submission_id => @submission.id,
93 :status => Task::STATUS_INQUEUE) == false
93 :status => Task::STATUS_INQUEUE) == false
94 flash[:notice] = 'Error adding your submission to task queue'
94 flash[:notice] = 'Error adding your submission to task queue'
95 end
95 end
96 else
96 else
97 prepare_list_information
97 prepare_list_information
98 render :action => 'list' and return
98 render :action => 'list' and return
99 end
99 end
100 - redirect_to :action => 'list'
100 + redirect_to edit_submission_path(@submission)
101 end
101 end
102
102
103 def source
103 def source
104 submission = Submission.find(params[:id])
104 submission = Submission.find(params[:id])
105 if ((submission.user_id == session[:user_id]) and
105 if ((submission.user_id == session[:user_id]) and
106 (submission.problem != nil) and
106 (submission.problem != nil) and
107 (submission.problem.available))
107 (submission.problem.available))
108 send_data(submission.source,
108 send_data(submission.source,
109 {:filename => submission.download_filename,
109 {:filename => submission.download_filename,
110 :type => 'text/plain'})
110 :type => 'text/plain'})
111 else
111 else
112 flash[:notice] = 'Error viewing source'
112 flash[:notice] = 'Error viewing source'
113 redirect_to :action => 'list'
113 redirect_to :action => 'list'
114 end
114 end
115 end
115 end
116
116
117 def compiler_msg
117 def compiler_msg
118 @submission = Submission.find(params[:id])
118 @submission = Submission.find(params[:id])
119 if @submission.user_id == session[:user_id]
119 if @submission.user_id == session[:user_id]
120 render :action => 'compiler_msg', :layout => 'empty'
120 render :action => 'compiler_msg', :layout => 'empty'
121 else
121 else
122 flash[:notice] = 'Error viewing source'
122 flash[:notice] = 'Error viewing source'
123 redirect_to :action => 'list'
123 redirect_to :action => 'list'
124 end
124 end
125 end
125 end
126
126
127 def result
127 def result
128 if !GraderConfiguration.show_grading_result
128 if !GraderConfiguration.show_grading_result
129 redirect_to :action => 'list' and return
129 redirect_to :action => 'list' and return
130 end
130 end
131 @user = User.find(session[:user_id])
131 @user = User.find(session[:user_id])
132 @submission = Submission.find(params[:id])
132 @submission = Submission.find(params[:id])
133 if @submission.user!=@user
133 if @submission.user!=@user
134 flash[:notice] = 'You are not allowed to view result of other users.'
134 flash[:notice] = 'You are not allowed to view result of other users.'
135 redirect_to :action => 'list' and return
135 redirect_to :action => 'list' and return
136 end
136 end
137 prepare_grading_result(@submission)
137 prepare_grading_result(@submission)
138 end
138 end
139
139
140 def load_output
140 def load_output
141 if !GraderConfiguration.show_grading_result or params[:num]==nil
141 if !GraderConfiguration.show_grading_result or params[:num]==nil
142 redirect_to :action => 'list' and return
142 redirect_to :action => 'list' and return
143 end
143 end
144 @user = User.find(session[:user_id])
144 @user = User.find(session[:user_id])
145 @submission = Submission.find(params[:id])
145 @submission = Submission.find(params[:id])
146 if @submission.user!=@user
146 if @submission.user!=@user
147 flash[:notice] = 'You are not allowed to view result of other users.'
147 flash[:notice] = 'You are not allowed to view result of other users.'
148 redirect_to :action => 'list' and return
148 redirect_to :action => 'list' and return
@@ -7,96 +7,98
7 before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score]
7 before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score]
8
8
9 before_filter(only: [:problem_hof]) { |c|
9 before_filter(only: [:problem_hof]) { |c|
10 return false unless authenticate
10 return false unless authenticate
11
11
12 admin_authorization unless GraderConfiguration["right.user_view_submission"]
12 admin_authorization unless GraderConfiguration["right.user_view_submission"]
13 }
13 }
14
14
15 def max_score
15 def max_score
16 end
16 end
17
17
18 def current_score
18 def current_score
19 @problems = Problem.available_problems
19 @problems = Problem.available_problems
20 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
20 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
21 @scorearray = calculate_max_score(@problems, @users,0,0,true)
21 @scorearray = calculate_max_score(@problems, @users,0,0,true)
22
22
23 #rencer accordingly
23 #rencer accordingly
24 if params[:button] == 'download' then
24 if params[:button] == 'download' then
25 csv = gen_csv_from_scorearray(@scorearray,@problems)
25 csv = gen_csv_from_scorearray(@scorearray,@problems)
26 send_data csv, filename: 'max_score.csv'
26 send_data csv, filename: 'max_score.csv'
27 else
27 else
28 #render template: 'user_admin/user_stat'
28 #render template: 'user_admin/user_stat'
29 render 'current_score'
29 render 'current_score'
30 end
30 end
31 end
31 end
32
32
33 def show_max_score
33 def show_max_score
34 #process parameters
34 #process parameters
35 #problems
35 #problems
36 @problems = []
36 @problems = []
37 if params[:problem_id]
37 if params[:problem_id]
38 params[:problem_id].each do |id|
38 params[:problem_id].each do |id|
39 next unless id.strip != ""
39 next unless id.strip != ""
40 pid = Problem.find_by_id(id.to_i)
40 pid = Problem.find_by_id(id.to_i)
41 @problems << pid if pid
41 @problems << pid if pid
42 end
42 end
43 end
43 end
44
44
45 #users
45 #users
46 @users = if params[:user] == "all" then
46 @users = if params[:user] == "all" then
47 User.includes(:contests).includes(:contest_stat)
47 User.includes(:contests).includes(:contest_stat)
48 else
48 else
49 User.includes(:contests).includes(:contest_stat).where(enabled: true)
49 User.includes(:contests).includes(:contest_stat).where(enabled: true)
50 end
50 end
51
51
52 #set up range from param
52 #set up range from param
53 @since_id = params.fetch(:from_id, 0).to_i
53 @since_id = params.fetch(:from_id, 0).to_i
54 @until_id = params.fetch(:to_id, 0).to_i
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 #calculate the routine
58 #calculate the routine
57 @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
59 @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
58
60
59 #rencer accordingly
61 #rencer accordingly
60 if params[:button] == 'download' then
62 if params[:button] == 'download' then
61 csv = gen_csv_from_scorearray(@scorearray,@problems)
63 csv = gen_csv_from_scorearray(@scorearray,@problems)
62 send_data csv, filename: 'max_score.csv'
64 send_data csv, filename: 'max_score.csv'
63 else
65 else
64 #render template: 'user_admin/user_stat'
66 #render template: 'user_admin/user_stat'
65 render 'max_score'
67 render 'max_score'
66 end
68 end
67
69
68 end
70 end
69
71
70 def score
72 def score
71 if params[:commit] == 'download csv'
73 if params[:commit] == 'download csv'
72 @problems = Problem.all
74 @problems = Problem.all
73 else
75 else
74 @problems = Problem.available_problems
76 @problems = Problem.available_problems
75 end
77 end
76 @users = User.includes(:contests, :contest_stat).where(enabled: true)
78 @users = User.includes(:contests, :contest_stat).where(enabled: true)
77 @scorearray = Array.new
79 @scorearray = Array.new
78 @users.each do |u|
80 @users.each do |u|
79 ustat = Array.new
81 ustat = Array.new
80 ustat[0] = u
82 ustat[0] = u
81 @problems.each do |p|
83 @problems.each do |p|
82 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
84 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
83 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
85 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
84 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
86 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
85 else
87 else
86 ustat << [0,false]
88 ustat << [0,false]
87 end
89 end
88 end
90 end
89 @scorearray << ustat
91 @scorearray << ustat
90 end
92 end
91 if params[:commit] == 'download csv' then
93 if params[:commit] == 'download csv' then
92 csv = gen_csv_from_scorearray(@scorearray,@problems)
94 csv = gen_csv_from_scorearray(@scorearray,@problems)
93 send_data csv, filename: 'last_score.csv'
95 send_data csv, filename: 'last_score.csv'
94 else
96 else
95 render template: 'user_admin/user_stat'
97 render template: 'user_admin/user_stat'
96 end
98 end
97
99
98 end
100 end
99
101
100 def login_stat
102 def login_stat
101 @logins = Array.new
103 @logins = Array.new
102
104
@@ -40,111 +40,114
40
40
41 if (user!=nil) and (session[:admin])
41 if (user!=nil) and (session[:admin])
42 # admin menu
42 # admin menu
43 menu_items << "<b>Administrative task:</b> "
43 menu_items << "<b>Administrative task:</b> "
44 append_to menu_items, '[Announcements]', 'announcements', 'index'
44 append_to menu_items, '[Announcements]', 'announcements', 'index'
45 append_to menu_items, '[Msg console]', 'messages', 'console'
45 append_to menu_items, '[Msg console]', 'messages', 'console'
46 append_to menu_items, '[Problems]', 'problems', 'index'
46 append_to menu_items, '[Problems]', 'problems', 'index'
47 append_to menu_items, '[Users]', 'user_admin', 'index'
47 append_to menu_items, '[Users]', 'user_admin', 'index'
48 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
48 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
49 append_to menu_items, '[Report]', 'report', 'multiple_login'
49 append_to menu_items, '[Report]', 'report', 'multiple_login'
50 append_to menu_items, '[Graders]', 'graders', 'list'
50 append_to menu_items, '[Graders]', 'graders', 'list'
51 append_to menu_items, '[Contests]', 'contest_management', 'index'
51 append_to menu_items, '[Contests]', 'contest_management', 'index'
52 append_to menu_items, '[Sites]', 'sites', 'index'
52 append_to menu_items, '[Sites]', 'sites', 'index'
53 append_to menu_items, '[System config]', 'configurations', 'index'
53 append_to menu_items, '[System config]', 'configurations', 'index'
54 menu_items << "<br/>"
54 menu_items << "<br/>"
55 end
55 end
56
56
57 # main page
57 # main page
58 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
58 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
59 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
59 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
60
60
61 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
61 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
62 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
62 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
63 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
63 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
64 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
64 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
65 end
65 end
66
66
67 if GraderConfiguration['right.user_hall_of_fame']
67 if GraderConfiguration['right.user_hall_of_fame']
68 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
68 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
69 end
69 end
70 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
70 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
71
71
72 if GraderConfiguration['system.user_setting_enabled']
72 if GraderConfiguration['system.user_setting_enabled']
73 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
73 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
74 end
74 end
75 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
75 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
76
76
77 menu_items.html_safe
77 menu_items.html_safe
78 end
78 end
79
79
80 def append_to(option,label, controller, action)
80 def append_to(option,label, controller, action)
81 option << ' ' if option!=''
81 option << ' ' if option!=''
82 option << link_to_unless_current(label,
82 option << link_to_unless_current(label,
83 :controller => controller,
83 :controller => controller,
84 :action => action)
84 :action => action)
85 end
85 end
86
86
87 def format_short_time(time)
87 def format_short_time(time)
88 - now = Time.now.gmtime
88 + now = Time.zone.now
89 st = ''
89 st = ''
90 - if (time.yday != now.yday) or
90 + if (time.yday != now.yday) or (time.year != now.year)
91 - (time.year != now.year)
91 + st = time.strftime("%d/%m/%y ")
92 - st = time.strftime("%x ")
93 end
92 end
94 st + time.strftime("%X")
93 st + time.strftime("%X")
95 end
94 end
96
95
97 def format_short_duration(duration)
96 def format_short_duration(duration)
98 return '' if duration==nil
97 return '' if duration==nil
99 d = duration.to_f
98 d = duration.to_f
100 return Time.at(d).gmtime.strftime("%X")
99 return Time.at(d).gmtime.strftime("%X")
101 end
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 def read_textfile(fname,max_size=2048)
106 def read_textfile(fname,max_size=2048)
104 begin
107 begin
105 File.open(fname).read(max_size)
108 File.open(fname).read(max_size)
106 rescue
109 rescue
107 nil
110 nil
108 end
111 end
109 end
112 end
110
113
111 def toggle_button(on,toggle_url,id, option={})
114 def toggle_button(on,toggle_url,id, option={})
112 btn_size = option[:size] || 'btn-xs'
115 btn_size = option[:size] || 'btn-xs'
113 link_to (on ? "Yes" : "No"), toggle_url,
116 link_to (on ? "Yes" : "No"), toggle_url,
114 {class: "btn btn-block #{btn_size} btn-#{on ? 'success' : 'default'} ajax-toggle",
117 {class: "btn btn-block #{btn_size} btn-#{on ? 'success' : 'default'} ajax-toggle",
115 id: id,
118 id: id,
116 data: {remote: true, method: 'get'}}
119 data: {remote: true, method: 'get'}}
117 end
120 end
118
121
119 def get_ace_mode(language)
122 def get_ace_mode(language)
120 # return ace mode string from Language
123 # return ace mode string from Language
121
124
122 case language.pretty_name
125 case language.pretty_name
123 when 'Pascal'
126 when 'Pascal'
124 'ace/mode/pascal'
127 'ace/mode/pascal'
125 when 'C++','C'
128 when 'C++','C'
126 'ace/mode/c_cpp'
129 'ace/mode/c_cpp'
127 when 'Ruby'
130 when 'Ruby'
128 'ace/mode/ruby'
131 'ace/mode/ruby'
129 when 'Python'
132 when 'Python'
130 'ace/mode/python'
133 'ace/mode/python'
131 when 'Java'
134 when 'Java'
132 'ace/mode/java'
135 'ace/mode/java'
133 else
136 else
134 'ace/mode/c_cpp'
137 'ace/mode/c_cpp'
135 end
138 end
136 end
139 end
137
140
138
141
139 def user_title_bar(user)
142 def user_title_bar(user)
140 header = ''
143 header = ''
141 time_left = ''
144 time_left = ''
142
145
143 #
146 #
144 # if the contest is over
147 # if the contest is over
145 if GraderConfiguration.time_limit_mode?
148 if GraderConfiguration.time_limit_mode?
146 if user.contest_finished?
149 if user.contest_finished?
147 header = <<CONTEST_OVER
150 header = <<CONTEST_OVER
148 <tr><td colspan="2" align="center">
151 <tr><td colspan="2" align="center">
149 <span class="contest-over-msg">THE CONTEST IS OVER</span>
152 <span class="contest-over-msg">THE CONTEST IS OVER</span>
150 </td></tr>
153 </td></tr>
@@ -1,86 +1,86
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 has_one :task
16 has_one :task
17
17
18 before_save :assign_latest_number_if_new_recond
18 before_save :assign_latest_number_if_new_recond
19
19
20 def self.find_last_by_user_and_problem(user_id, problem_id)
20 def self.find_last_by_user_and_problem(user_id, problem_id)
21 where("user_id = ? AND problem_id = ?",user_id,problem_id).last
21 where("user_id = ? AND problem_id = ?",user_id,problem_id).last
22 end
22 end
23
23
24 def self.find_all_last_by_problem(problem_id)
24 def self.find_all_last_by_problem(problem_id)
25 # need to put in SQL command, maybe there's a better way
25 # need to put in SQL command, maybe there's a better way
26 Submission.includes(:user).find_by_sql("SELECT * FROM submissions " +
26 Submission.includes(:user).find_by_sql("SELECT * FROM submissions " +
27 "WHERE id = " +
27 "WHERE id = " +
28 "(SELECT MAX(id) FROM submissions AS subs " +
28 "(SELECT MAX(id) FROM submissions AS subs " +
29 "WHERE subs.user_id = submissions.user_id AND " +
29 "WHERE subs.user_id = submissions.user_id AND " +
30 "problem_id = " + problem_id.to_s + " " +
30 "problem_id = " + problem_id.to_s + " " +
31 "GROUP BY user_id) " +
31 "GROUP BY user_id) " +
32 "ORDER BY user_id")
32 "ORDER BY user_id")
33 end
33 end
34
34
35 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
35 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
36 records = Submission.where(problem_id: problem_id,user_id: user_id)
36 records = Submission.where(problem_id: problem_id,user_id: user_id)
37 - records = records.where('id >= ?',since_id) if since_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 > 0
38 + records = records.where('id <= ?',until_id) if until_id and until_id > 0
39 records.all
39 records.all
40 end
40 end
41
41
42 def self.find_last_for_all_available_problems(user_id)
42 def self.find_last_for_all_available_problems(user_id)
43 submissions = Array.new
43 submissions = Array.new
44 problems = Problem.available_problems
44 problems = Problem.available_problems
45 problems.each do |problem|
45 problems.each do |problem|
46 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
46 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
47 submissions << sub if sub!=nil
47 submissions << sub if sub!=nil
48 end
48 end
49 submissions
49 submissions
50 end
50 end
51
51
52 def self.find_by_user_problem_number(user_id, problem_id, number)
52 def self.find_by_user_problem_number(user_id, problem_id, number)
53 where("user_id = ? AND problem_id = ? AND number = ?",user_id,problem_id,number).first
53 where("user_id = ? AND problem_id = ? AND number = ?",user_id,problem_id,number).first
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 where("user_id = ? AND problem_id = ?",user_id,problem_id)
57 where("user_id = ? AND problem_id = ?",user_id,problem_id)
58 end
58 end
59
59
60 def download_filename
60 def download_filename
61 if self.problem.output_only
61 if self.problem.output_only
62 return self.source_filename
62 return self.source_filename
63 else
63 else
64 timestamp = self.submitted_at.localtime.strftime("%H%M%S")
64 timestamp = self.submitted_at.localtime.strftime("%H%M%S")
65 return "#{self.problem.name}-#{timestamp}.#{self.language.ext}"
65 return "#{self.problem.name}-#{timestamp}.#{self.language.ext}"
66 end
66 end
67 end
67 end
68
68
69 protected
69 protected
70
70
71 def self.find_option_in_source(option, source)
71 def self.find_option_in_source(option, source)
72 if source==nil
72 if source==nil
73 return nil
73 return nil
74 end
74 end
75 i = 0
75 i = 0
76 source.each_line do |s|
76 source.each_line do |s|
77 if s =~ option
77 if s =~ option
78 words = s.split
78 words = s.split
79 return words[1]
79 return words[1]
80 end
80 end
81 i = i + 1
81 i = i + 1
82 if i==10
82 if i==10
83 return nil
83 return nil
84 end
84 end
85 end
85 end
86 return nil
86 return nil
@@ -1,26 +1,28
1 -
2 - if submission.nil?
1 - if submission.nil?
3 = "-"
2 = "-"
4 - else
3 - else
4 + %strong= "Submission ID:"
5 + = submission.id
6 + %br
5 - unless submission.graded_at
7 - unless submission.graded_at
6 - = t 'main.submitted_at'
8 + %strong= t 'main.submitted_at:'
7 - = format_short_time(submission.submitted_at.localtime)
9 + = format_full_time_ago(submission.submitted_at.localtime)
8 - else
10 - else
9 - %strong= t 'main.graded_at'
11 + %strong= t 'main.graded_at:'
10 - = "#{format_short_time(submission.graded_at.localtime)} "
12 + = format_full_time_ago(submission.graded_at.localtime)
11 %br
13 %br
12 - if GraderConfiguration['ui.show_score']
14 - if GraderConfiguration['ui.show_score']
13 %strong=t 'main.score'
15 %strong=t 'main.score'
14 = "#{(submission.points*100/submission.problem.full_score).to_i} "
16 = "#{(submission.points*100/submission.problem.full_score).to_i} "
15 = " ["
17 = " ["
16 %tt
18 %tt
17 = submission.grader_comment
19 = submission.grader_comment
18 = "]"
20 = "]"
19 %br
21 %br
20 - %strong View:
22 + %strong View:
21 - - if GraderConfiguration.show_grading_result
23 + - if GraderConfiguration.show_grading_result
22 - = link_to '[detailed result]', :action => 'result', :id => submission.id
24 + = 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'}
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 = link_to "#{t 'main.src_link'}", download_submission_path(submission.id), class: 'btn btn-xs btn-info'
26 = link_to "#{t 'main.src_link'}", download_submission_path(submission.id), class: 'btn btn-xs btn-info'
25 = link_to "#{t 'main.submissions_link'}", problem_submissions_path(problem_id), class: 'btn btn-xs btn-info'
27 = link_to "#{t 'main.submissions_link'}", problem_submissions_path(problem_id), class: 'btn btn-xs btn-info'
26
28
@@ -1,49 +1,49
1 %h1 Maximum score
1 %h1 Maximum score
2
2
3 = form_tag report_show_max_score_path
3 = form_tag report_show_max_score_path
4 .row
4 .row
5 .col-md-4
5 .col-md-4
6 .panel.panel-primary
6 .panel.panel-primary
7 .panel-heading
7 .panel-heading
8 Problems
8 Problems
9 .panel-body
9 .panel-body
10 %p
10 %p
11 Select problem(s) that we wish to know the score.
11 Select problem(s) that we wish to know the score.
12 = label_tag :problem_id, "Problems"
12 = label_tag :problem_id, "Problems"
13 = select_tag 'problem_id[]',
13 = select_tag 'problem_id[]',
14 options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
14 options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
15 { class: 'select2 form-control', multiple: "true" }
15 { class: 'select2 form-control', multiple: "true" }
16 .col-md-4
16 .col-md-4
17 .panel.panel-primary
17 .panel.panel-primary
18 .panel-heading
18 .panel-heading
19 Submission range
19 Submission range
20 .panel-body
20 .panel-body
21 %p
21 %p
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.
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 .form-group
23 .form-group
24 = label_tag :from, "Min"
24 = label_tag :from, "Min"
25 = text_field_tag 'from_id', @since_id, class: "form-control"
25 = text_field_tag 'from_id', @since_id, class: "form-control"
26 .form-group
26 .form-group
27 = label_tag :from, "Max"
27 = label_tag :from, "Max"
28 = text_field_tag 'to_id', @until_id, class: "form-control"
28 = text_field_tag 'to_id', @until_id, class: "form-control"
29 .col-md-4
29 .col-md-4
30 .panel.panel-primary
30 .panel.panel-primary
31 .panel-heading
31 .panel-heading
32 Users
32 Users
33 .panel-body
33 .panel-body
34 .radio
34 .radio
35 %label
35 %label
36 - = radio_button_tag 'users', 'all', true
36 + = radio_button_tag 'users', 'all', (params[:users] == "all")
37 All users
37 All users
38 .radio
38 .radio
39 %label
39 %label
40 - = radio_button_tag 'users', 'enabled'
40 + = radio_button_tag 'users', 'enabled', (params[:users] == "enabled")
41 Only enabled users
41 Only enabled users
42 .row
42 .row
43 .col-md-12
43 .col-md-12
44 = button_tag 'Show', class: "btn btn-primary btn-large", value: "show"
44 = button_tag 'Show', class: "btn btn-primary btn-large", value: "show"
45 = button_tag 'Download CSV', class: "btn btn-primary btn-large", value: "download"
45 = button_tag 'Download CSV', class: "btn btn-primary btn-large", value: "download"
46
46
47 - if @scorearray
47 - if @scorearray
48 %h2 Result
48 %h2 Result
49 =render "score_table"
49 =render "score_table"
@@ -1,78 +1,78
1 %h2 Live submit
1 %h2 Live submit
2 %br
2 %br
3
3
4 %textarea#text_sourcecode{style: "display:none"}~ @source
4 %textarea#text_sourcecode{style: "display:none"}~ @source
5 .container
5 .container
6 .row
6 .row
7 .col-md-12
7 .col-md-12
8 .alert.alert-info
8 .alert.alert-info
9 Write your code in the following box, choose language, and click submit button when finished
9 Write your code in the following box, choose language, and click submit button when finished
10 .row
10 .row
11 .col-md-8
11 .col-md-8
12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
13 .col-md-4
13 .col-md-4
14 - # submission form
14 - # submission form
15 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
15 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
16
16
17 = hidden_field_tag 'editor_text', @source
17 = hidden_field_tag 'editor_text', @source
18 = hidden_field_tag 'submission[problem_id]', @problem.id
18 = hidden_field_tag 'submission[problem_id]', @problem.id
19 .form-group
19 .form-group
20 = label_tag "Task:"
20 = label_tag "Task:"
21 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
21 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
22
22
23 .form-group
23 .form-group
24 = label_tag 'Language'
24 = label_tag 'Language'
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"
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 .form-group
26 .form-group
27 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
27 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
28 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
28 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
29 - # latest submission status
29 - # latest submission status
30 - .panel.panel-info
30 + .panel{class: (@submission && @submission.graded_at) ? "panel-info" : "panel-warning"}
31 .panel-heading
31 .panel-heading
32 Latest Submission Status
32 Latest Submission Status
33 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
33 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
34 .panel-body
34 .panel-body
35 - if @submission
35 - if @submission
36 = render :partial => 'submission_short',
36 = render :partial => 'submission_short',
37 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
37 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
38 .row
38 .row
39 .col-md-12
39 .col-md-12
40 %h2 Console
40 %h2 Console
41 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
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 :javascript
43 :javascript
44 $(document).ready(function() {
44 $(document).ready(function() {
45 e = ace.edit("editor")
45 e = ace.edit("editor")
46 e.setValue($("#text_sourcecode").val());
46 e.setValue($("#text_sourcecode").val());
47 e.gotoLine(1);
47 e.gotoLine(1);
48 $("#language_id").trigger('change');
48 $("#language_id").trigger('change');
49 brython();
49 brython();
50 });
50 });
51
51
52
52
53 %script#__main__{type:'text/python3'}
53 %script#__main__{type:'text/python3'}
54 :plain
54 :plain
55 import sys
55 import sys
56 import traceback
56 import traceback
57
57
58 from browser import document as doc
58 from browser import document as doc
59 from browser import window, alert, console
59 from browser import window, alert, console
60
60
61 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
61 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
62 for supporting Python development. See www.python.org for more information."""
62 for supporting Python development. See www.python.org for more information."""
63
63
64 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
64 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
65 All Rights Reserved.
65 All Rights Reserved.
66
66
67 Copyright (c) 2001-2013 Python Software Foundation.
67 Copyright (c) 2001-2013 Python Software Foundation.
68 All Rights Reserved.
68 All Rights Reserved.
69
69
70 Copyright (c) 2000 BeOpen.com.
70 Copyright (c) 2000 BeOpen.com.
71 All Rights Reserved.
71 All Rights Reserved.
72
72
73 Copyright (c) 1995-2001 Corporation for National Research Initiatives.
73 Copyright (c) 1995-2001 Corporation for National Research Initiatives.
74 All Rights Reserved.
74 All Rights Reserved.
75
75
76 Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
76 Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
77 All Rights Reserved."""
77 All Rights Reserved."""
78
78
@@ -20,53 +20,53
20
20
21 # Only load the plugins named here, in the order given (default is alphabetical).
21 # Only load the plugins named here, in the order given (default is alphabetical).
22 # :all can be used as a placeholder for all plugins not explicitly named.
22 # :all can be used as a placeholder for all plugins not explicitly named.
23 # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
23 # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
24
24
25 # Activate observers that should always be running.
25 # Activate observers that should always be running.
26 # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
26 # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
27
27
28 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
28 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
29 # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
29 # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
30 config.time_zone = 'UTC'
30 config.time_zone = 'UTC'
31
31
32 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
32 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
33 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
33 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
34 config.i18n.default_locale = :en
34 config.i18n.default_locale = :en
35
35
36 # Configure the default encoding used in templates for Ruby 1.9.
36 # Configure the default encoding used in templates for Ruby 1.9.
37 config.encoding = "utf-8"
37 config.encoding = "utf-8"
38
38
39 # Configure sensitive parameters which will be filtered from the log file.
39 # Configure sensitive parameters which will be filtered from the log file.
40 config.filter_parameters += [:password]
40 config.filter_parameters += [:password]
41
41
42 # Enable escaping HTML in JSON.
42 # Enable escaping HTML in JSON.
43 config.active_support.escape_html_entities_in_json = true
43 config.active_support.escape_html_entities_in_json = true
44
44
45 # Use SQL instead of Active Record's schema dumper when creating the database.
45 # Use SQL instead of Active Record's schema dumper when creating the database.
46 # This is necessary if your schema can't be completely dumped by the schema dumper,
46 # This is necessary if your schema can't be completely dumped by the schema dumper,
47 # like if you have constraints or database-specific column types
47 # like if you have constraints or database-specific column types
48 # config.active_record.schema_format = :sql
48 # config.active_record.schema_format = :sql
49
49
50 # Enable the asset pipeline
50 # Enable the asset pipeline
51 config.assets.enabled = true
51 config.assets.enabled = true
52
52
53 # Version of your assets, change this if you want to expire all your assets
53 # Version of your assets, change this if you want to expire all your assets
54 config.assets.version = '1.0'
54 config.assets.version = '1.0'
55
55
56 # ---------------- IMPORTANT ----------------------
56 # ---------------- IMPORTANT ----------------------
57 # If we deploy the app into a subdir name "grader", be sure to do "rake assets:precompile RAILS_RELATIVE_URL_ROOT=/grader"
57 # If we deploy the app into a subdir name "grader", be sure to do "rake assets:precompile RAILS_RELATIVE_URL_ROOT=/grader"
58 # moreover, using the following line instead also known to works
58 # moreover, using the following line instead also known to works
59 #config.action_controller.relative_url_root = '/grader'
59 #config.action_controller.relative_url_root = '/grader'
60
60
61 #font path
61 #font path
62 config.assets.paths << "#{Rails}/vendor/assets/fonts"
62 config.assets.paths << "#{Rails}/vendor/assets/fonts"
63
63
64 config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js']
64 config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js']
65 config.assets.precompile += ['local_jquery.js','tablesorter-theme.cafe.css']
65 config.assets.precompile += ['local_jquery.js','tablesorter-theme.cafe.css']
66 %w( announcements submissions configurations contests contest_management graders heartbeat
66 %w( announcements submissions configurations contests contest_management graders heartbeat
67 login main messages problems report site sites sources tasks
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 config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
69 config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
70 end
70 end
71 end
71 end
72 end
72 end
@@ -1,23 +1,23
1 # Be sure to restart your server when you modify this file.
1 # Be sure to restart your server when you modify this file.
2
2
3 # Version of your assets, change this if you want to expire all your assets.
3 # Version of your assets, change this if you want to expire all your assets.
4 Rails.application.config.assets.version = '1.0'
4 Rails.application.config.assets.version = '1.0'
5
5
6 # Add additional assets to the asset load path.
6 # Add additional assets to the asset load path.
7 # Rails.application.config.assets.paths << Emoji.images_path
7 # Rails.application.config.assets.paths << Emoji.images_path
8 # Add Yarn node_modules folder to the asset load path.
8 # Add Yarn node_modules folder to the asset load path.
9 Rails.application.config.assets.paths << Rails.root.join('node_modules')
9 Rails.application.config.assets.paths << Rails.root.join('node_modules')
10 Rails.application.config.assets.paths << Rails.root.join('vendor/assets/fonts')
10 Rails.application.config.assets.paths << Rails.root.join('vendor/assets/fonts')
11
11
12 # Precompile additional assets.
12 # Precompile additional assets.
13 # application.js, application.css, and all non-JS/CSS in the app/assets
13 # application.js, application.css, and all non-JS/CSS in the app/assets
14 # folder are already added.
14 # folder are already added.
15 # Rails.application.config.assets.precompile += %w( admin.js admin.css )
15 # Rails.application.config.assets.precompile += %w( admin.js admin.css )
16
16
17 Rails.application.config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js']
17 Rails.application.config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js']
18 Rails.application.config.assets.precompile += ['local_jquery.js','tablesorter-theme.cafe.css']
18 Rails.application.config.assets.precompile += ['local_jquery.js','tablesorter-theme.cafe.css']
19 %w( announcements submissions configurations contests contest_management graders heartbeat
19 %w( announcements submissions configurations contests contest_management graders heartbeat
20 login main messages problems report site sites sources tasks groups
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 Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
22 Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
23 end
23 end
@@ -1,73 +1,74
1 module GraderScript
1 module GraderScript
2
2
3 def self.grader_control_enabled?
3 def self.grader_control_enabled?
4 if defined? GRADER_ROOT_DIR
4 if defined? GRADER_ROOT_DIR
5 GRADER_ROOT_DIR != ''
5 GRADER_ROOT_DIR != ''
6 else
6 else
7 false
7 false
8 end
8 end
9 end
9 end
10
10
11 def self.raw_dir
11 def self.raw_dir
12 File.join GRADER_ROOT_DIR, "raw"
12 File.join GRADER_ROOT_DIR, "raw"
13 end
13 end
14
14
15 def self.call_grader(params)
15 def self.call_grader(params)
16 if GraderScript.grader_control_enabled?
16 if GraderScript.grader_control_enabled?
17 cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
17 cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
18 system(cmd)
18 system(cmd)
19 end
19 end
20 end
20 end
21
21
22 def self.stop_grader(pid)
22 def self.stop_grader(pid)
23 GraderScript.call_grader "stop #{pid}"
23 GraderScript.call_grader "stop #{pid}"
24 end
24 end
25
25
26 def self.stop_graders(pids)
26 def self.stop_graders(pids)
27 pid_str = (pids.map { |process| process.pid.to_s }).join ' '
27 pid_str = (pids.map { |process| process.pid.to_s }).join ' '
28 GraderScript.call_grader "stop #{pid_str}"
28 GraderScript.call_grader "stop #{pid_str}"
29 end
29 end
30
30
31 def self.start_grader(env)
31 def self.start_grader(env)
32 GraderScript.call_grader "#{env} queue --err-log &"
32 GraderScript.call_grader "#{env} queue --err-log &"
33 GraderScript.call_grader "#{env} test_request -err-log &"
33 GraderScript.call_grader "#{env} test_request -err-log &"
34 end
34 end
35
35
36 + #call the import problem script
36 def self.call_import_problem(problem_name,
37 def self.call_import_problem(problem_name,
37 problem_dir,
38 problem_dir,
38 time_limit=1,
39 time_limit=1,
39 memory_limit=32,
40 memory_limit=32,
40 checker_name='text')
41 checker_name='text')
41 if GraderScript.grader_control_enabled?
42 if GraderScript.grader_control_enabled?
42 cur_dir = `pwd`.chomp
43 cur_dir = `pwd`.chomp
43 Dir.chdir(GRADER_ROOT_DIR)
44 Dir.chdir(GRADER_ROOT_DIR)
44
45
45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 " -t #{time_limit} -m #{memory_limit}"
48 " -t #{time_limit} -m #{memory_limit}"
48
49
49 output = `#{cmd}`
50 output = `#{cmd}`
50
51
51 Dir.chdir(cur_dir)
52 Dir.chdir(cur_dir)
52
53
53 return "import CMD: #{cmd}\n" + output
54 return "import CMD: #{cmd}\n" + output
54 end
55 end
55 return ''
56 return ''
56 end
57 end
57
58
58 def self.call_import_testcase(problem_name)
59 def self.call_import_testcase(problem_name)
59 if GraderScript.grader_control_enabled?
60 if GraderScript.grader_control_enabled?
60 cur_dir = `pwd`.chomp
61 cur_dir = `pwd`.chomp
61 Dir.chdir(GRADER_ROOT_DIR)
62 Dir.chdir(GRADER_ROOT_DIR)
62
63
63 script_name = File.join(GRADER_ROOT_DIR, "scripts/load_testcase")
64 script_name = File.join(GRADER_ROOT_DIR, "scripts/load_testcase")
64 cmd = "#{script_name} #{problem_name}"
65 cmd = "#{script_name} #{problem_name}"
65
66
66 output = `#{cmd}`
67 output = `#{cmd}`
67
68
68 Dir.chdir(cur_dir)
69 Dir.chdir(cur_dir)
69 return "Testcase import result:\n" + output
70 return "Testcase import result:\n" + output
70 end
71 end
71 end
72 end
72
73
73 end
74 end
@@ -1,102 +1,104
1 require 'tmpdir'
1 require 'tmpdir'
2
2
3 class TestdataImporter
3 class TestdataImporter
4
4
5 attr :log_msg
5 attr :log_msg
6
6
7 def initialize(problem)
7 def initialize(problem)
8 @problem = problem
8 @problem = problem
9 end
9 end
10
10
11 - def import_from_file(tempfile,
11 + #Create or update problem according to the parameter
12 - time_limit,
12 + def import_from_file(tempfile,
13 + time_limit,
13 memory_limit,
14 memory_limit,
14 checker_name='text',
15 checker_name='text',
15 import_to_db=false)
16 import_to_db=false)
16
17
17 dirname = extract(tempfile)
18 dirname = extract(tempfile)
18 return false if not dirname
19 return false if not dirname
19 if not import_to_db
20 if not import_to_db
20 @log_msg = GraderScript.call_import_problem(@problem.name,
21 @log_msg = GraderScript.call_import_problem(@problem.name,
21 dirname,
22 dirname,
22 time_limit,
23 time_limit,
23 memory_limit,
24 memory_limit,
24 checker_name)
25 checker_name)
25 else
26 else
26 # Import test data to test pairs.
27 # Import test data to test pairs.
27
28
28 @problem.test_pairs.clear
29 @problem.test_pairs.clear
29 if import_test_pairs(dirname)
30 if import_test_pairs(dirname)
30 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
31 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
31 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
32 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
32 else
33 else
33 @log_msg = "Importing test pair failed. (0 test pairs imported)"
34 @log_msg = "Importing test pair failed. (0 test pairs imported)"
34 end
35 end
35 end
36 end
36
37
37 @log_msg << import_problem_description(dirname)
38 @log_msg << import_problem_description(dirname)
38 @log_msg << import_problem_pdf(dirname)
39 @log_msg << import_problem_pdf(dirname)
39 @log_msg << import_full_score(dirname)
40 @log_msg << import_full_score(dirname)
40
41
41 #import test data
42 #import test data
42 @log_msg << GraderScript.call_import_testcase(@problem.name)
43 @log_msg << GraderScript.call_import_testcase(@problem.name)
43
44
44 return true
45 return true
45 end
46 end
46
47
47 protected
48 protected
48
49
49 def self.long_ext(filename)
50 def self.long_ext(filename)
50 i = filename.index('.')
51 i = filename.index('.')
51 len = filename.length
52 len = filename.length
52 return filename.slice(i..len)
53 return filename.slice(i..len)
53 end
54 end
54
55
56 + # extract an archive file located at +tempfile+ to the +raw_dir+
55 def extract(tempfile)
57 def extract(tempfile)
56 testdata_filename = save_testdata_file(tempfile)
58 testdata_filename = save_testdata_file(tempfile)
57 ext = TestdataImporter.long_ext(tempfile.original_filename)
59 ext = TestdataImporter.long_ext(tempfile.original_filename)
58
60
59 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
61 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
60 if File.exists? extract_dir
62 if File.exists? extract_dir
61 backup_count = 0
63 backup_count = 0
62 begin
64 begin
63 backup_count += 1
65 backup_count += 1
64 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
66 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
65 end while File.exists? backup_dirname
67 end while File.exists? backup_dirname
66 File.rename(extract_dir, backup_dirname)
68 File.rename(extract_dir, backup_dirname)
67 end
69 end
68 Dir.mkdir extract_dir
70 Dir.mkdir extract_dir
69
71
70 if ext=='.tar.gz' or ext=='.tgz'
72 if ext=='.tar.gz' or ext=='.tgz'
71 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
73 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
72 elsif ext=='.tar'
74 elsif ext=='.tar'
73 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
75 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
74 elsif ext=='.zip'
76 elsif ext=='.zip'
75 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
77 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
76 else
78 else
77 return nil
79 return nil
78 end
80 end
79
81
80 system(cmd)
82 system(cmd)
81
83
82 files = Dir["#{extract_dir}/**/*1*.in"]
84 files = Dir["#{extract_dir}/**/*1*.in"]
83 return nil if files.length==0
85 return nil if files.length==0
84
86
85 File.delete(testdata_filename)
87 File.delete(testdata_filename)
86
88
87 return File.dirname(files[0])
89 return File.dirname(files[0])
88 end
90 end
89
91
90 def save_testdata_file(tempfile)
92 def save_testdata_file(tempfile)
91 ext = TestdataImporter.long_ext(tempfile.original_filename)
93 ext = TestdataImporter.long_ext(tempfile.original_filename)
92 testdata_filename = File.join(Dir.tmpdir,"#{@problem.name}#{ext}")
94 testdata_filename = File.join(Dir.tmpdir,"#{@problem.name}#{ext}")
93
95
94 return nil if tempfile==""
96 return nil if tempfile==""
95
97
96 if tempfile.instance_of?(Tempfile)
98 if tempfile.instance_of?(Tempfile)
97 tempfile.close
99 tempfile.close
98 FileUtils.move(tempfile.path,testdata_filename)
100 FileUtils.move(tempfile.path,testdata_filename)
99 else
101 else
100 File.open(testdata_filename, "wb") do |f|
102 File.open(testdata_filename, "wb") do |f|
101 f.write(tempfile.read)
103 f.write(tempfile.read)
102 end
104 end
You need to be logged in to leave comments. Login now