Description:
merge
Commit status:
[Not Reviewed]
References:
merge java
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r514:41d1cd2793ff - - 11 files changed: 301 inserted, 132 deleted

@@ -0,0 +1,44
1 + - param = {} unless param
2 + - graph_height = param[:graph_height] || 100
3 + - bar_width = param[:bar_width] || 14
4 + - graph_width = (bar_width * histogram[:data].count) + 20
5 + :css
6 + .hist_bar {
7 + width: #{bar_width-1}px;
8 + position: absolute;
9 + background-color: lightblue;
10 + }
11 + .hist_fill {
12 + width: #{bar_width-1}px;
13 + position: absolute;
14 + background-color: #eee;
15 + }
16 + .hist_text {
17 + position: absolute;
18 + font-size:5px;
19 + }
20 +
21 + %div{style: "position: relative; width: #{graph_width}px; height: 125px; background-color:#fff;" }
22 + //draw background
23 + - histogram[:data].each_index do |i|
24 + - height = histogram[:data][i] * graph_height / histogram[:summary][:max]
25 + - top = graph_height - height
26 + - left = graph_width - (i+1)*bar_width
27 + %div.hist_fill{style: "top: 0px; height: #{graph_height - height}px; left: #{left}px;" }
28 + // draw horizontal line
29 + - line = 3
30 + - line.times do |i|
31 + - top = graph_height - graph_height * (i+0.5)/ line
32 + %div{style: "position:absolute;width: #{graph_width-21}px;height: 1px;left: 20px;top:#{top}px;background-color: #333;"}
33 + %div.hist_text{style: "position:absolute;left: 0px;top:#{top-6}px"}
34 + =((i+0.5) * histogram[:summary][:max] / line).to_i
35 + // draw the actual bar and text
36 + - @histogram[:data].each_index do |i|
37 + - height = histogram[:data][i] * graph_height / histogram[:summary][:max]
38 + - top = graph_height - height
39 + - left = graph_width - (i+1)*bar_width
40 + %div.hist_bar{style: "top: #{top}px; height: #{height}px; left: #{left}px; dae: #{histogram[:data][i]}" }
41 + - if i % 7 == 1
42 + %div.hist_text{style: "top:#{graph_height + 5}px;left: #{left}px;"} #{(Time.zone.today - i.day).strftime('%-d')}
43 + - if (Time.now.in_time_zone - i.day).day == 15
44 + %div.hist_text{style: "top:#{graph_height + 15}px;left: #{left}px;"} #{(Time.zone.today - i.day).strftime('%b')}
@@ -57,204 +57,221
57 @problem.full_score = 100
57 @problem.full_score = 100
58 @problem.available = false
58 @problem.available = false
59 @problem.test_allowed = true
59 @problem.test_allowed = true
60 @problem.output_only = false
60 @problem.output_only = false
61 @problem.date_added = Time.new
61 @problem.date_added = Time.new
62 if @problem.save
62 if @problem.save
63 flash[:notice] = 'Problem was successfully created.'
63 flash[:notice] = 'Problem was successfully created.'
64 redirect_to :action => 'list'
64 redirect_to :action => 'list'
65 else
65 else
66 flash[:notice] = 'Error saving problem'
66 flash[:notice] = 'Error saving problem'
67 redirect_to :action => 'list'
67 redirect_to :action => 'list'
68 end
68 end
69 end
69 end
70
70
71 def edit
71 def edit
72 @problem = Problem.find(params[:id])
72 @problem = Problem.find(params[:id])
73 @description = @problem.description
73 @description = @problem.description
74 end
74 end
75
75
76 def update
76 def update
77 @problem = Problem.find(params[:id])
77 @problem = Problem.find(params[:id])
78 @description = @problem.description
78 @description = @problem.description
79 if @description == nil and params[:description][:body]!=''
79 if @description == nil and params[:description][:body]!=''
80 @description = Description.new(params[:description])
80 @description = Description.new(params[:description])
81 if !@description.save
81 if !@description.save
82 flash[:notice] = 'Error saving description'
82 flash[:notice] = 'Error saving description'
83 render :action => 'edit' and return
83 render :action => 'edit' and return
84 end
84 end
85 @problem.description = @description
85 @problem.description = @description
86 elsif @description!=nil
86 elsif @description!=nil
87 if !@description.update_attributes(params[:description])
87 if !@description.update_attributes(params[:description])
88 flash[:notice] = 'Error saving description'
88 flash[:notice] = 'Error saving description'
89 render :action => 'edit' and return
89 render :action => 'edit' and return
90 end
90 end
91 end
91 end
92 if params[:file] and params[:file].content_type != 'application/pdf'
92 if params[:file] and params[:file].content_type != 'application/pdf'
93 flash[:notice] = 'Error: Uploaded file is not PDF'
93 flash[:notice] = 'Error: Uploaded file is not PDF'
94 render :action => 'edit' and return
94 render :action => 'edit' and return
95 end
95 end
96 if @problem.update_attributes(params[:problem])
96 if @problem.update_attributes(params[:problem])
97 flash[:notice] = 'Problem was successfully updated.'
97 flash[:notice] = 'Problem was successfully updated.'
98 unless params[:file] == nil or params[:file] == ''
98 unless params[:file] == nil or params[:file] == ''
99 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
99 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
100 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
100 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
101 if not FileTest.exists? out_dirname
101 if not FileTest.exists? out_dirname
102 Dir.mkdir out_dirname
102 Dir.mkdir out_dirname
103 end
103 end
104
104
105 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
105 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
106 if FileTest.exists? out_filename
106 if FileTest.exists? out_filename
107 File.delete out_filename
107 File.delete out_filename
108 end
108 end
109
109
110 File.open(out_filename,"wb") do |file|
110 File.open(out_filename,"wb") do |file|
111 file.write(params[:file].read)
111 file.write(params[:file].read)
112 end
112 end
113 @problem.description_filename = "#{@problem.name}.pdf"
113 @problem.description_filename = "#{@problem.name}.pdf"
114 @problem.save
114 @problem.save
115 end
115 end
116 redirect_to :action => 'show', :id => @problem
116 redirect_to :action => 'show', :id => @problem
117 else
117 else
118 render :action => 'edit'
118 render :action => 'edit'
119 end
119 end
120 end
120 end
121
121
122 def destroy
122 def destroy
123 Problem.find(params[:id]).destroy
123 Problem.find(params[:id]).destroy
124 redirect_to :action => 'list'
124 redirect_to :action => 'list'
125 end
125 end
126
126
127 def toggle
127 def toggle
128 @problem = Problem.find(params[:id])
128 @problem = Problem.find(params[:id])
129 @problem.available = !(@problem.available)
129 @problem.available = !(@problem.available)
130 @problem.save
130 @problem.save
131 end
131 end
132
132
133 def turn_all_off
133 def turn_all_off
134 Problem.find(:all,
134 Problem.find(:all,
135 :conditions => "available = 1").each do |problem|
135 :conditions => "available = 1").each do |problem|
136 problem.available = false
136 problem.available = false
137 problem.save
137 problem.save
138 end
138 end
139 redirect_to :action => 'list'
139 redirect_to :action => 'list'
140 end
140 end
141
141
142 def turn_all_on
142 def turn_all_on
143 Problem.find(:all,
143 Problem.find(:all,
144 :conditions => "available = 0").each do |problem|
144 :conditions => "available = 0").each do |problem|
145 problem.available = true
145 problem.available = true
146 problem.save
146 problem.save
147 end
147 end
148 redirect_to :action => 'list'
148 redirect_to :action => 'list'
149 end
149 end
150
150
151 def stat
151 def stat
152 @problem = Problem.find(params[:id])
152 @problem = Problem.find(params[:id])
153 - if !@problem.available
153 + unless @problem.available or session[:admin]
154 redirect_to :controller => 'main', :action => 'list'
154 redirect_to :controller => 'main', :action => 'list'
155 - else
155 + return
156 - @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
157 end
156 end
157 + @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
158 +
159 + #stat summary
160 + range =65
161 + @histogram = { data: Array.new(range,0), summary: {} }
162 + user = Hash.new(0)
163 + @submissions.find_each do |sub|
164 + d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
165 + @histogram[:data][d.to_i] += 1 if d < range
166 + user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
167 + end
168 + @histogram[:summary][:max] = [@histogram[:data].max,1].max
169 +
170 + @summary = { attempt: user.count, solve: 0 }
171 + user.each_value { |v| @summary[:solve] += 1 if v == 1 }
158 end
172 end
159
173
160 def manage
174 def manage
161 @problems = Problem.find(:all, :order => 'date_added DESC')
175 @problems = Problem.find(:all, :order => 'date_added DESC')
162 end
176 end
163
177
164 def do_manage
178 def do_manage
165 if params.has_key? 'change_date_added'
179 if params.has_key? 'change_date_added'
166 change_date_added
180 change_date_added
167 elsif params.has_key? 'add_to_contest'
181 elsif params.has_key? 'add_to_contest'
168 add_to_contest
182 add_to_contest
169 elsif params.has_key? 'enable_problem'
183 elsif params.has_key? 'enable_problem'
170 set_available(true)
184 set_available(true)
171 elsif params.has_key? 'disable_problem'
185 elsif params.has_key? 'disable_problem'
172 set_available(false)
186 set_available(false)
173 end
187 end
174 redirect_to :action => 'manage'
188 redirect_to :action => 'manage'
175 end
189 end
176
190
177 def import
191 def import
178 @allow_test_pair_import = allow_test_pair_import?
192 @allow_test_pair_import = allow_test_pair_import?
179 end
193 end
180
194
181 def do_import
195 def do_import
182 old_problem = Problem.find_by_name(params[:name])
196 old_problem = Problem.find_by_name(params[:name])
183 if !allow_test_pair_import? and params.has_key? :import_to_db
197 if !allow_test_pair_import? and params.has_key? :import_to_db
184 params.delete :import_to_db
198 params.delete :import_to_db
185 end
199 end
186 @problem, import_log = Problem.create_from_import_form_params(params,
200 @problem, import_log = Problem.create_from_import_form_params(params,
187 old_problem)
201 old_problem)
188
202
189 if !@problem.errors.empty?
203 if !@problem.errors.empty?
190 render :action => 'import' and return
204 render :action => 'import' and return
191 end
205 end
192
206
193 if old_problem!=nil
207 if old_problem!=nil
194 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
208 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
195 end
209 end
196 @log = import_log
210 @log = import_log
197 end
211 end
198
212
199 def remove_contest
213 def remove_contest
200 problem = Problem.find(params[:id])
214 problem = Problem.find(params[:id])
201 contest = Contest.find(params[:contest_id])
215 contest = Contest.find(params[:contest_id])
202 if problem!=nil and contest!=nil
216 if problem!=nil and contest!=nil
203 problem.contests.delete(contest)
217 problem.contests.delete(contest)
204 end
218 end
205 redirect_to :action => 'manage'
219 redirect_to :action => 'manage'
206 end
220 end
207
221
208 ##################################
222 ##################################
209 protected
223 protected
210
224
211 def allow_test_pair_import?
225 def allow_test_pair_import?
212 if defined? ALLOW_TEST_PAIR_IMPORT
226 if defined? ALLOW_TEST_PAIR_IMPORT
213 return ALLOW_TEST_PAIR_IMPORT
227 return ALLOW_TEST_PAIR_IMPORT
214 else
228 else
215 return false
229 return false
216 end
230 end
217 end
231 end
218
232
219 def change_date_added
233 def change_date_added
220 problems = get_problems_from_params
234 problems = get_problems_from_params
221 year = params[:date_added][:year].to_i
235 year = params[:date_added][:year].to_i
222 month = params[:date_added][:month].to_i
236 month = params[:date_added][:month].to_i
223 day = params[:date_added][:day].to_i
237 day = params[:date_added][:day].to_i
224 date = Date.new(year,month,day)
238 date = Date.new(year,month,day)
225 problems.each do |p|
239 problems.each do |p|
226 p.date_added = date
240 p.date_added = date
227 p.save
241 p.save
228 end
242 end
229 end
243 end
230
244
231 def add_to_contest
245 def add_to_contest
232 problems = get_problems_from_params
246 problems = get_problems_from_params
233 contest = Contest.find(params[:contest][:id])
247 contest = Contest.find(params[:contest][:id])
234 if contest!=nil and contest.enabled
248 if contest!=nil and contest.enabled
235 problems.each do |p|
249 problems.each do |p|
236 p.contests << contest
250 p.contests << contest
237 end
251 end
238 end
252 end
239 end
253 end
240
254
241 def set_available(avail)
255 def set_available(avail)
242 problems = get_problems_from_params
256 problems = get_problems_from_params
243 problems.each do |p|
257 problems.each do |p|
244 p.available = avail
258 p.available = avail
245 p.save
259 p.save
246 end
260 end
247 end
261 end
248
262
249 def get_problems_from_params
263 def get_problems_from_params
250 problems = []
264 problems = []
251 params.keys.each do |k|
265 params.keys.each do |k|
252 if k.index('prob-')==0
266 if k.index('prob-')==0
253 name, id, order = k.split('-')
267 name, id, order = k.split('-')
254 problems << Problem.find(id)
268 problems << Problem.find(id)
255 end
269 end
256 end
270 end
257 problems
271 problems
258 end
272 end
259
273
274 + def get_problems_stat
275 + end
276 +
260 end
277 end
@@ -12,184 +12,180
12 }
12 }
13
13
14 def login_stat
14 def login_stat
15 @logins = Array.new
15 @logins = Array.new
16
16
17 date_and_time = '%Y-%m-%d %H:%M'
17 date_and_time = '%Y-%m-%d %H:%M'
18 begin
18 begin
19 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
19 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
20 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
20 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
21 rescue
21 rescue
22 @since_time = DateTime.new(1000,1,1)
22 @since_time = DateTime.new(1000,1,1)
23 end
23 end
24 begin
24 begin
25 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
25 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
26 @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
26 @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
27 rescue
27 rescue
28 @until_time = DateTime.new(3000,1,1)
28 @until_time = DateTime.new(3000,1,1)
29 end
29 end
30
30
31 User.all.each do |user|
31 User.all.each do |user|
32 @logins << { id: user.id,
32 @logins << { id: user.id,
33 login: user.login,
33 login: user.login,
34 full_name: user.full_name,
34 full_name: user.full_name,
35 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
35 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
36 user.id,@since_time,@until_time)
36 user.id,@since_time,@until_time)
37 .count(:id),
37 .count(:id),
38 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
38 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
39 user.id,@since_time,@until_time)
39 user.id,@since_time,@until_time)
40 .minimum(:created_at),
40 .minimum(:created_at),
41 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
41 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
42 user.id,@since_time,@until_time)
42 user.id,@since_time,@until_time)
43 .maximum(:created_at),
43 .maximum(:created_at),
44 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
44 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
45 user.id,@since_time,@until_time)
45 user.id,@since_time,@until_time)
46 .select(:ip_address).uniq
46 .select(:ip_address).uniq
47
47
48 }
48 }
49 end
49 end
50 end
50 end
51
51
52 def submission_stat
52 def submission_stat
53
53
54 date_and_time = '%Y-%m-%d %H:%M'
54 date_and_time = '%Y-%m-%d %H:%M'
55 begin
55 begin
56 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
56 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
57 rescue
57 rescue
58 @since_time = DateTime.new(1000,1,1)
58 @since_time = DateTime.new(1000,1,1)
59 end
59 end
60 begin
60 begin
61 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
61 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
62 rescue
62 rescue
63 @until_time = DateTime.new(3000,1,1)
63 @until_time = DateTime.new(3000,1,1)
64 end
64 end
65
65
66 @submissions = {}
66 @submissions = {}
67
67
68 User.find_each do |user|
68 User.find_each do |user|
69 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
69 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
70 end
70 end
71
71
72 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
72 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
73 if @submissions[s.user_id]
73 if @submissions[s.user_id]
74 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
74 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
75 a = nil
75 a = nil
76 begin
76 begin
77 a = Problem.find(s.problem_id)
77 a = Problem.find(s.problem_id)
78 rescue
78 rescue
79 a = nil
79 a = nil
80 end
80 end
81 @submissions[s.user_id][:sub][s.problem_id] =
81 @submissions[s.user_id][:sub][s.problem_id] =
82 { prob_name: (a ? a.full_name : '(NULL)'),
82 { prob_name: (a ? a.full_name : '(NULL)'),
83 sub_ids: [s.id] }
83 sub_ids: [s.id] }
84 else
84 else
85 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
85 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
86 end
86 end
87 @submissions[s.user_id][:count] += 1
87 @submissions[s.user_id][:count] += 1
88 end
88 end
89 end
89 end
90 end
90 end
91
91
92 def problem_hof
92 def problem_hof
93 # gen problem list
93 # gen problem list
94 @user = User.find(session[:user_id])
94 @user = User.find(session[:user_id])
95 @problems = @user.available_problems
95 @problems = @user.available_problems
96
96
97 # get selected problems or the default
97 # get selected problems or the default
98 if params[:id]
98 if params[:id]
99 begin
99 begin
100 @problem = Problem.available.find(params[:id])
100 @problem = Problem.available.find(params[:id])
101 rescue
101 rescue
102 redirect_to action: :problem_hof
102 redirect_to action: :problem_hof
103 flash[:notice] = 'Error: submissions for that problem are not viewable.'
103 flash[:notice] = 'Error: submissions for that problem are not viewable.'
104 return
104 return
105 end
105 end
106 end
106 end
107
107
108 - if @problem
108 + return unless @problem
109 - #aggregrate by language
109 +
110 - @by_lang = {}
110 + @by_lang = {} #aggregrate by language
111 - Submission.where(problem_id: @problem.id).find_each do |sub|
112 - lang = Language.find_by_id(sub.language_id)
113 - next unless lang
114 - next unless sub.points >= @problem.full_score
115
111
116 - #initialize
112 + range =65
117 - unless @by_lang.has_key?(lang.pretty_name)
113 + @histogram = { data: Array.new(range,0), summary: {} }
118 - @by_lang[lang.pretty_name] = {
114 + @summary = {count: 0, solve: 0, attempt: 0}
119 - runtime: { avail: false, value: 2**30-1 },
115 + user = Hash.new(0)
120 - memory: { avail: false, value: 2**30-1 },
116 + Submission.where(problem_id: @problem.id).find_each do |sub|
121 - length: { avail: false, value: 2**30-1 },
117 + #histogram
122 - first: { avail: false, value: DateTime.new(3000,1,1) }
118 + d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
123 - }
119 + @histogram[:data][d.to_i] += 1 if d < range
124 - end
125
120
126 - if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
121 + @summary[:count] += 1
127 - @by_lang[lang.pretty_name][:runtime] = {
122 + user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
128 - avail: true,
129 - user_id: sub.user_id,
130 - value: sub.max_runtime,
131 - sub_id: sub.id
132 - }
133 - end
134
123
135 - if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
124 + lang = Language.find_by_id(sub.language_id)
136 - @by_lang[lang.pretty_name][:memory] = {
125 + next unless lang
137 - avail: true,
126 + next unless sub.points >= @problem.full_score
138 - user_id: sub.user_id,
139 - value: sub.peak_memory,
140 - sub_id: sub.id
141 - }
142 - end
143
127
144 - if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
128 + #initialize
145 - !sub.user.admin?
129 + unless @by_lang.has_key?(lang.pretty_name)
146 - @by_lang[lang.pretty_name][:first] = {
130 + @by_lang[lang.pretty_name] = {
147 - avail: true,
131 + runtime: { avail: false, value: 2**30-1 },
148 - user_id: sub.user_id,
132 + memory: { avail: false, value: 2**30-1 },
149 - value: sub.submitted_at,
133 + length: { avail: false, value: 2**30-1 },
150 - sub_id: sub.id
134 + first: { avail: false, value: DateTime.new(3000,1,1) }
151 - }
135 + }
152 - end
136 + end
153
137
154 - if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
138 + if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
155 - @by_lang[lang.pretty_name][:length] = {
139 + @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
156 - avail: true,
157 - user_id: sub.user_id,
158 - value: sub.effective_code_length,
159 - sub_id: sub.id
160 - }
161 - end
162 - end
163 -
164 - #process user_id
165 - @by_lang.each do |lang,prop|
166 - prop.each do |k,v|
167 - v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
168 - end
169 end
140 end
170
141
171 - #sum into best
142 + if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
172 - if @by_lang and @by_lang.first
143 + @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
173 - @best = @by_lang.first[1].clone
144 + end
174 - @by_lang.each do |lang,prop|
145 +
175 - if @best[:runtime][:value] >= prop[:runtime][:value]
146 + if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
176 - @best[:runtime] = prop[:runtime]
147 + !sub.user.admin?
177 - @best[:runtime][:lang] = lang
148 + @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
178 - end
149 + end
179 - if @best[:memory][:value] >= prop[:memory][:value]
150 +
180 - @best[:memory] = prop[:memory]
151 + if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
181 - @best[:memory][:lang] = lang
152 + @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
182 - end
153 + end
183 - if @best[:length][:value] >= prop[:length][:value]
154 + end
184 - @best[:length] = prop[:length]
155 +
185 - @best[:length][:lang] = lang
156 + #process user_id
186 - end
157 + @by_lang.each do |lang,prop|
187 - if @best[:first][:value] >= prop[:first][:value]
158 + prop.each do |k,v|
188 - @best[:first] = prop[:first]
159 + v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
189 - @best[:first][:lang] = lang
160 + end
190 - end
161 + end
162 +
163 + #sum into best
164 + if @by_lang and @by_lang.first
165 + @best = @by_lang.first[1].clone
166 + @by_lang.each do |lang,prop|
167 + if @best[:runtime][:value] >= prop[:runtime][:value]
168 + @best[:runtime] = prop[:runtime]
169 + @best[:runtime][:lang] = lang
170 + end
171 + if @best[:memory][:value] >= prop[:memory][:value]
172 + @best[:memory] = prop[:memory]
173 + @best[:memory][:lang] = lang
174 + end
175 + if @best[:length][:value] >= prop[:length][:value]
176 + @best[:length] = prop[:length]
177 + @best[:length][:lang] = lang
178 + end
179 + if @best[:first][:value] >= prop[:first][:value]
180 + @best[:first] = prop[:first]
181 + @best[:first][:lang] = lang
191 end
182 end
192 end
183 end
193 end
184 end
185 +
186 + @histogram[:summary][:max] = [@histogram[:data].max,1].max
187 + @summary[:attempt] = user.count
188 + user.each_value { |v| @summary[:solve] += 1 if v == 1 }
194 end
189 end
190 +
195 end
191 end
@@ -18,159 +18,177
18
18
19 verify :method => :post, :only => [:chg_passwd],
19 verify :method => :post, :only => [:chg_passwd],
20 :redirect_to => { :action => :index }
20 :redirect_to => { :action => :index }
21
21
22 #in_place_edit_for :user, :alias_for_editing
22 #in_place_edit_for :user, :alias_for_editing
23 #in_place_edit_for :user, :email_for_editing
23 #in_place_edit_for :user, :email_for_editing
24
24
25 def index
25 def index
26 if !GraderConfiguration['system.user_setting_enabled']
26 if !GraderConfiguration['system.user_setting_enabled']
27 redirect_to :controller => 'main', :action => 'list'
27 redirect_to :controller => 'main', :action => 'list'
28 else
28 else
29 @user = User.find(session[:user_id])
29 @user = User.find(session[:user_id])
30 end
30 end
31 end
31 end
32
32
33 def chg_passwd
33 def chg_passwd
34 user = User.find(session[:user_id])
34 user = User.find(session[:user_id])
35 user.password = params[:passwd]
35 user.password = params[:passwd]
36 user.password_confirmation = params[:passwd_verify]
36 user.password_confirmation = params[:passwd_verify]
37 if user.save
37 if user.save
38 flash[:notice] = 'password changed'
38 flash[:notice] = 'password changed'
39 else
39 else
40 flash[:notice] = 'Error: password changing failed'
40 flash[:notice] = 'Error: password changing failed'
41 end
41 end
42 redirect_to :action => 'index'
42 redirect_to :action => 'index'
43 end
43 end
44
44
45 def new
45 def new
46 @user = User.new
46 @user = User.new
47 render :action => 'new', :layout => 'empty'
47 render :action => 'new', :layout => 'empty'
48 end
48 end
49
49
50 def register
50 def register
51 if(params[:cancel])
51 if(params[:cancel])
52 redirect_to :controller => 'main', :action => 'login'
52 redirect_to :controller => 'main', :action => 'login'
53 return
53 return
54 end
54 end
55 @user = User.new(params[:user])
55 @user = User.new(params[:user])
56 @user.password_confirmation = @user.password = User.random_password
56 @user.password_confirmation = @user.password = User.random_password
57 @user.activated = false
57 @user.activated = false
58 if (@user.valid?) and (@user.save)
58 if (@user.valid?) and (@user.save)
59 if send_confirmation_email(@user)
59 if send_confirmation_email(@user)
60 render :action => 'new_splash', :layout => 'empty'
60 render :action => 'new_splash', :layout => 'empty'
61 else
61 else
62 @admin_email = GraderConfiguration['system.admin_email']
62 @admin_email = GraderConfiguration['system.admin_email']
63 render :action => 'email_error', :layout => 'empty'
63 render :action => 'email_error', :layout => 'empty'
64 end
64 end
65 else
65 else
66 @user.errors.add_to_base("Email cannot be blank") if @user.email==''
66 @user.errors.add_to_base("Email cannot be blank") if @user.email==''
67 render :action => 'new', :layout => 'empty'
67 render :action => 'new', :layout => 'empty'
68 end
68 end
69 end
69 end
70
70
71 def confirm
71 def confirm
72 login = params[:login]
72 login = params[:login]
73 key = params[:activation]
73 key = params[:activation]
74 @user = User.find_by_login(login)
74 @user = User.find_by_login(login)
75 if (@user) and (@user.verify_activation_key(key))
75 if (@user) and (@user.verify_activation_key(key))
76 if @user.valid? # check uniquenss of email
76 if @user.valid? # check uniquenss of email
77 @user.activated = true
77 @user.activated = true
78 @user.save
78 @user.save
79 @result = :successful
79 @result = :successful
80 else
80 else
81 @result = :email_used
81 @result = :email_used
82 end
82 end
83 else
83 else
84 @result = :failed
84 @result = :failed
85 end
85 end
86 render :action => 'confirm', :layout => 'empty'
86 render :action => 'confirm', :layout => 'empty'
87 end
87 end
88
88
89 def forget
89 def forget
90 render :action => 'forget', :layout => 'empty'
90 render :action => 'forget', :layout => 'empty'
91 end
91 end
92
92
93 def retrieve_password
93 def retrieve_password
94 email = params[:email]
94 email = params[:email]
95 user = User.find_by_email(email)
95 user = User.find_by_email(email)
96 if user
96 if user
97 last_updated_time = user.updated_at || user.created_at || (Time.now.gmtime - 1.hour)
97 last_updated_time = user.updated_at || user.created_at || (Time.now.gmtime - 1.hour)
98 if last_updated_time > Time.now.gmtime - 5.minutes
98 if last_updated_time > Time.now.gmtime - 5.minutes
99 flash[:notice] = 'The account has recently created or new password has recently been requested. Please wait for 5 minutes'
99 flash[:notice] = 'The account has recently created or new password has recently been requested. Please wait for 5 minutes'
100 else
100 else
101 user.password = user.password_confirmation = User.random_password
101 user.password = user.password_confirmation = User.random_password
102 user.save
102 user.save
103 send_new_password_email(user)
103 send_new_password_email(user)
104 flash[:notice] = 'New password has been mailed to you.'
104 flash[:notice] = 'New password has been mailed to you.'
105 end
105 end
106 else
106 else
107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
108 end
108 end
109 redirect_to :action => 'forget'
109 redirect_to :action => 'forget'
110 end
110 end
111
111
112 def profile
112 def profile
113 @user = User.find(params[:id])
113 @user = User.find(params[:id])
114 - @submission = Submission.where(user_id: params[:id]).all
114 + @submission = Submission.includes(:problem).where(user_id: params[:id])
115 +
116 + range = 120
117 + @histogram = { data: Array.new(range,0), summary: {} }
118 + @summary = {count: 0, solve: 0, attempt: 0}
119 + problem = Hash.new(0)
120 +
121 + @submission.find_each do |sub|
122 + #histogram
123 + d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
124 + @histogram[:data][d.to_i] += 1 if d < range
125 +
126 + @summary[:count] += 1
127 + problem[sub.problem] = [problem[sub.problem], (sub.points >= sub.problem.full_score) ? 1 : 0].max
128 + end
129 +
130 + @histogram[:summary][:max] = [@histogram[:data].max,1].max
131 + @summary[:attempt] = problem.count
132 + problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
115 end
133 end
116
134
117 protected
135 protected
118
136
119 def verify_online_registration
137 def verify_online_registration
120 if !GraderConfiguration['system.online_registration']
138 if !GraderConfiguration['system.online_registration']
121 redirect_to :controller => 'main', :action => 'login'
139 redirect_to :controller => 'main', :action => 'login'
122 end
140 end
123 end
141 end
124
142
125 def send_confirmation_email(user)
143 def send_confirmation_email(user)
126 contest_name = GraderConfiguration['contest.name']
144 contest_name = GraderConfiguration['contest.name']
127 activation_url = url_for(:action => 'confirm',
145 activation_url = url_for(:action => 'confirm',
128 :login => user.login,
146 :login => user.login,
129 :activation => user.activation_key)
147 :activation => user.activation_key)
130 home_url = url_for(:controller => 'main', :action => 'index')
148 home_url = url_for(:controller => 'main', :action => 'index')
131 mail_subject = "[#{contest_name}] Confirmation"
149 mail_subject = "[#{contest_name}] Confirmation"
132 mail_body = t('registration.email_body', {
150 mail_body = t('registration.email_body', {
133 :full_name => user.full_name,
151 :full_name => user.full_name,
134 :contest_name => contest_name,
152 :contest_name => contest_name,
135 :login => user.login,
153 :login => user.login,
136 :password => user.password,
154 :password => user.password,
137 :activation_url => activation_url,
155 :activation_url => activation_url,
138 :admin_email => admin_email
156 :admin_email => admin_email
139 })
157 })
140
158
141 logger.info mail_body
159 logger.info mail_body
142
160
143 send_mail(user.email, mail_subject, mail_body)
161 send_mail(user.email, mail_subject, mail_body)
144 end
162 end
145
163
146 def send_new_password_email(user)
164 def send_new_password_email(user)
147 contest_name = GraderConfiguration['contest.name']
165 contest_name = GraderConfiguration['contest.name']
148 mail_subject = "[#{contest_name}] Password recovery"
166 mail_subject = "[#{contest_name}] Password recovery"
149 mail_body = t('registration.password_retrieval.email_body', {
167 mail_body = t('registration.password_retrieval.email_body', {
150 :full_name => user.full_name,
168 :full_name => user.full_name,
151 :contest_name => contest_name,
169 :contest_name => contest_name,
152 :login => user.login,
170 :login => user.login,
153 :password => user.password,
171 :password => user.password,
154 :admin_email => admin_email
172 :admin_email => admin_email
155 })
173 })
156
174
157 logger.info mail_body
175 logger.info mail_body
158
176
159 send_mail(user.email, mail_subject, mail_body)
177 send_mail(user.email, mail_subject, mail_body)
160 end
178 end
161
179
162 # allow viewing of regular user profile only when options allow so
180 # allow viewing of regular user profile only when options allow so
163 # only admins can view admins profile
181 # only admins can view admins profile
164 def profile_authorization
182 def profile_authorization
165 #if view admins' profile, allow only admin
183 #if view admins' profile, allow only admin
166 return false unless(params[:id])
184 return false unless(params[:id])
167 user = User.find(params[:id])
185 user = User.find(params[:id])
168 return false unless user
186 return false unless user
169 return admin_authorization if user.admin?
187 return admin_authorization if user.admin?
170 return true if GraderConfiguration["right.user_view_submission"]
188 return true if GraderConfiguration["right.user_view_submission"]
171
189
172 #finally, we allow only admin
190 #finally, we allow only admin
173 admin_authorization
191 admin_authorization
174 end
192 end
175
193
176 end
194 end
@@ -1,121 +1,128
1 class Problem < ActiveRecord::Base
1 class Problem < ActiveRecord::Base
2
2
3 belongs_to :description
3 belongs_to :description
4 has_and_belongs_to_many :contests, :uniq => true
4 has_and_belongs_to_many :contests, :uniq => true
5 has_many :test_pairs, :dependent => :delete_all
5 has_many :test_pairs, :dependent => :delete_all
6
6
7 validates_presence_of :name
7 validates_presence_of :name
8 validates_format_of :name, :with => /^\w+$/
8 validates_format_of :name, :with => /^\w+$/
9 validates_presence_of :full_name
9 validates_presence_of :full_name
10
10
11 scope :available, :conditions => {:available => true}
11 scope :available, :conditions => {:available => true}
12
12
13 DEFAULT_TIME_LIMIT = 1
13 DEFAULT_TIME_LIMIT = 1
14 DEFAULT_MEMORY_LIMIT = 32
14 DEFAULT_MEMORY_LIMIT = 32
15
15
16 def self.find_available_problems
16 def self.find_available_problems
17 Problem.available.all(:order => "date_added DESC, name ASC")
17 Problem.available.all(:order => "date_added DESC, name ASC")
18 end
18 end
19
19
20 def self.create_from_import_form_params(params, old_problem=nil)
20 def self.create_from_import_form_params(params, old_problem=nil)
21 org_problem = old_problem || Problem.new
21 org_problem = old_problem || Problem.new
22 import_params, problem = Problem.extract_params_and_check(params,
22 import_params, problem = Problem.extract_params_and_check(params,
23 org_problem)
23 org_problem)
24
24
25 if !problem.errors.empty?
25 if !problem.errors.empty?
26 return problem, 'Error importing'
26 return problem, 'Error importing'
27 end
27 end
28
28
29 problem.full_score = 100
29 problem.full_score = 100
30 problem.date_added = Time.new
30 problem.date_added = Time.new
31 problem.test_allowed = true
31 problem.test_allowed = true
32 problem.output_only = false
32 problem.output_only = false
33 problem.available = false
33 problem.available = false
34
34
35 if not problem.save
35 if not problem.save
36 return problem, 'Error importing'
36 return problem, 'Error importing'
37 end
37 end
38
38
39 import_to_db = params.has_key? :import_to_db
39 import_to_db = params.has_key? :import_to_db
40
40
41 importer = TestdataImporter.new(problem)
41 importer = TestdataImporter.new(problem)
42
42
43 if not importer.import_from_file(import_params[:file],
43 if not importer.import_from_file(import_params[:file],
44 import_params[:time_limit],
44 import_params[:time_limit],
45 import_params[:memory_limit],
45 import_params[:memory_limit],
46 import_params[:checker_name],
46 import_params[:checker_name],
47 import_to_db)
47 import_to_db)
48 problem.errors.add_to_base('Import error.')
48 problem.errors.add_to_base('Import error.')
49 end
49 end
50
50
51 return problem, importer.log_msg
51 return problem, importer.log_msg
52 end
52 end
53
53
54 def self.download_file_basedir
54 def self.download_file_basedir
55 return "#{Rails.root}/data/tasks"
55 return "#{Rails.root}/data/tasks"
56 end
56 end
57 +
58 + def get_submission_stat
59 + result = Hash.new
60 + #total number of submission
61 + result[:total_sub] = Submission.where(problem_id: self.id).count
62 + result[:attempted_user] = Submission.where(problem_id: self.id).group_by(:user_id)
63 + end
57
64
58 protected
65 protected
59
66
60 def self.to_i_or_default(st, default)
67 def self.to_i_or_default(st, default)
61 if st!=''
68 if st!=''
62 result = st.to_i
69 result = st.to_i
63 end
70 end
64 result ||= default
71 result ||= default
65 end
72 end
66
73
67 def self.to_f_or_default(st, default)
74 def self.to_f_or_default(st, default)
68 if st!=''
75 if st!=''
69 result = st.to_f
76 result = st.to_f
70 end
77 end
71 result ||= default
78 result ||= default
72 end
79 end
73
80
74 def self.extract_params_and_check(params, problem)
81 def self.extract_params_and_check(params, problem)
75 time_limit = Problem.to_f_or_default(params[:time_limit],
82 time_limit = Problem.to_f_or_default(params[:time_limit],
76 DEFAULT_TIME_LIMIT)
83 DEFAULT_TIME_LIMIT)
77 memory_limit = Problem.to_i_or_default(params[:memory_limit],
84 memory_limit = Problem.to_i_or_default(params[:memory_limit],
78 DEFAULT_MEMORY_LIMIT)
85 DEFAULT_MEMORY_LIMIT)
79
86
80 if time_limit<=0 or time_limit >60
87 if time_limit<=0 or time_limit >60
81 problem.errors.add_to_base('Time limit out of range.')
88 problem.errors.add_to_base('Time limit out of range.')
82 end
89 end
83
90
84 if memory_limit==0 and params[:memory_limit]!='0'
91 if memory_limit==0 and params[:memory_limit]!='0'
85 problem.errors.add_to_base('Memory limit format errors.')
92 problem.errors.add_to_base('Memory limit format errors.')
86 elsif memory_limit<=0 or memory_limit >512
93 elsif memory_limit<=0 or memory_limit >512
87 problem.errors.add_to_base('Memory limit out of range.')
94 problem.errors.add_to_base('Memory limit out of range.')
88 end
95 end
89
96
90 if params[:file]==nil or params[:file]==''
97 if params[:file]==nil or params[:file]==''
91 problem.errors.add_to_base('No testdata file.')
98 problem.errors.add_to_base('No testdata file.')
92 end
99 end
93
100
94 checker_name = 'text'
101 checker_name = 'text'
95 if ['text','float'].include? params[:checker]
102 if ['text','float'].include? params[:checker]
96 checker_name = params[:checker]
103 checker_name = params[:checker]
97 end
104 end
98
105
99 file = params[:file]
106 file = params[:file]
100
107
101 if !problem.errors.empty?
108 if !problem.errors.empty?
102 return nil, problem
109 return nil, problem
103 end
110 end
104
111
105 problem.name = params[:name]
112 problem.name = params[:name]
106 if params[:full_name]!=''
113 if params[:full_name]!=''
107 problem.full_name = params[:full_name]
114 problem.full_name = params[:full_name]
108 else
115 else
109 problem.full_name = params[:name]
116 problem.full_name = params[:name]
110 end
117 end
111
118
112 return [{
119 return [{
113 :time_limit => time_limit,
120 :time_limit => time_limit,
114 :memory_limit => memory_limit,
121 :memory_limit => memory_limit,
115 :file => file,
122 :file => file,
116 :checker_name => checker_name
123 :checker_name => checker_name
117 },
124 },
118 problem]
125 problem]
119 end
126 end
120
127
121 end
128 end
@@ -1,61 +1,67
1 %style{type: "text/css"}
1 %style{type: "text/css"}
2 = @css_style
2 = @css_style
3 :css
3 :css
4 .field {
4 .field {
5 font-weight: bold;
5 font-weight: bold;
6 text-align: right;
6 text-align: right;
7 padding: 3px;
7 padding: 3px;
8 }
8 }
9
9
10
10
11 %h1= "Submission: #{@submission.id}"
11 %h1= "Submission: #{@submission.id}"
12
12
13
13
14 %h2 Stat
14 %h2 Stat
15
15
16 %table.info
16 %table.info
17 %thead
17 %thead
18 %tr.info-head
18 %tr.info-head
19 %th Field
19 %th Field
20 %th Value
20 %th Value
21 %tbody
21 %tbody
22 %tr{class: cycle('info-even','info-odd')}
22 %tr{class: cycle('info-even','info-odd')}
23 %td.field User:
23 %td.field User:
24 - %td.value= "(#{@submission.user.login}) #{@submission.user.full_name}"
24 + %td.value
25 + - if @submission.user
26 + = link_to "(#{@submission.user.login})", controller: "users", action: "profile", id: @submission.user
27 + = @submission.user.full_name
28 + - else
29 + = "(n/a)"
25 %tr{class: cycle('info-even','info-odd')}
30 %tr{class: cycle('info-even','info-odd')}
26 %td.field Problem:
31 %td.field Problem:
27 %td.value
32 %td.value
28 - if @submission.problem!=nil
33 - if @submission.problem!=nil
29 - = "(#{@submission.problem.name}) #{@submission.problem.full_name}"
34 + = link_to "(#{@submission.problem.name})", controller: "problems", action: "stat", id: @submission.problem
35 + = @submission.problem.full_name
30 - else
36 - else
31 = "(n/a)"
37 = "(n/a)"
32 %tr{class: cycle('info-even','info-odd')}
38 %tr{class: cycle('info-even','info-odd')}
33 %td.field Tries:
39 %td.field Tries:
34 %td.value= @submission.number
40 %td.value= @submission.number
35 %tr{class: cycle('info-even','info-odd')}
41 %tr{class: cycle('info-even','info-odd')}
36 %td.field Submitted:
42 %td.field Submitted:
37 %td.value #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
43 %td.value #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
38 %tr{class: cycle('info-even','info-odd')}
44 %tr{class: cycle('info-even','info-odd')}
39 %td.field Graded:
45 %td.field Graded:
40 %td.value #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
46 %td.value #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
41 %tr{class: cycle('info-even','info-odd')}
47 %tr{class: cycle('info-even','info-odd')}
42 %td.field Points:
48 %td.field Points:
43 %td.value #{@submission.points}/#{@submission.problem.full_score}
49 %td.value #{@submission.points}/#{@submission.problem.full_score}
44 %tr{class: cycle('info-even','info-odd')}
50 %tr{class: cycle('info-even','info-odd')}
45 %td.field Comment:
51 %td.field Comment:
46 %td.value #{@submission.grader_comment}
52 %td.value #{@submission.grader_comment}
47 %tr{class: cycle('info-even','info-odd')}
53 %tr{class: cycle('info-even','info-odd')}
48 %td.field Runtime (s):
54 %td.field Runtime (s):
49 %td.value #{@submission.max_runtime}
55 %td.value #{@submission.max_runtime}
50 %tr{class: cycle('info-even','info-odd')}
56 %tr{class: cycle('info-even','info-odd')}
51 %td.field Memory (kb):
57 %td.field Memory (kb):
52 %td.value #{@submission.peak_memory}
58 %td.value #{@submission.peak_memory}
53 - if session[:admin]
59 - if session[:admin]
54 %tr{class: cycle('info-even','info-odd')}
60 %tr{class: cycle('info-even','info-odd')}
55 %td.field IP:
61 %td.field IP:
56 %td.value #{@submission.ip_address}
62 %td.value #{@submission.ip_address}
57
63
58 %h2 Source code
64 %h2 Source code
59 //%div.highlight{:style => "border: 1px solid black;"}
65 //%div.highlight{:style => "border: 1px solid black;"}
60 =@formatted_code.html_safe
66 =@formatted_code.html_safe
61
67
@@ -1,34 +1,51
1 :css
1 :css
2 .fix-width {
2 .fix-width {
3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
4 }
4 }
5
5
6 %h1 Problem stat: #{@problem.name}
6 %h1 Problem stat: #{@problem.name}
7 %h2 Overview
7 %h2 Overview
8
8
9 +
10 + %table.info
11 + %thead
12 + %tr.info-head
13 + %th Stat
14 + %th Value
15 + %tbody
16 + %tr{class: cycle('info-even','info-odd')}
17 + %td Submissions
18 + %td= @submissions.count
19 + %tr{class: cycle('info-even','info-odd')}
20 + %td Solved/Attempted User
21 + %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
22 +
23 + %h2 Submissions Count
24 + = render partial: 'application/bar_graph', locals: { histogram: @histogram }
25 +
9 %h2 Submissions
26 %h2 Submissions
10 - if @submissions and @submissions.count > 0
27 - if @submissions and @submissions.count > 0
11 %table.info#main_table
28 %table.info#main_table
12 %thead
29 %thead
13 %tr.info-head
30 %tr.info-head
14 %th ID
31 %th ID
15 %th Login
32 %th Login
16 %th Name
33 %th Name
17 %th Submitted_at
34 %th Submitted_at
18 %th Points
35 %th Points
19 %th comment
36 %th comment
20 %tbody
37 %tbody
21 - row_odd,curr = true,''
38 - row_odd,curr = true,''
22 - @submissions.each do |sub|
39 - @submissions.each do |sub|
23 - next unless sub.user
40 - next unless sub.user
24 - row_odd,curr = !row_odd, sub.user if curr != sub.user
41 - row_odd,curr = !row_odd, sub.user if curr != sub.user
25 %tr{class: row_odd ? "info-odd" : "info-even"}
42 %tr{class: row_odd ? "info-odd" : "info-even"}
26 %td= link_to sub.id, controller: 'graders', action: 'submission', id: sub.id
43 %td= link_to sub.id, controller: 'graders', action: 'submission', id: sub.id
27 %td= link_to sub.user.login, controller: :users, action: :profile, id: sub.user.id
44 %td= link_to sub.user.login, controller: :users, action: :profile, id: sub.user.id
28 %td= sub.user.full_name
45 %td= sub.user.full_name
29 %td= time_ago_in_words(sub.submitted_at) + " ago"
46 %td= time_ago_in_words(sub.submitted_at) + " ago"
30 %td= sub.points
47 %td= sub.points
31 %td.fix-width= sub.grader_comment
48 %td.fix-width= sub.grader_comment
32 - else
49 - else
33 No submission
50 No submission
34
51
@@ -1,79 +1,128
1 + - content_for :header do
2 + = javascript_include_tag 'local_jquery'
3 +
4 + :javascript
5 + $(document).ready( function() {
6 + $("#mem_remark").hover( function() {
7 + $("#mem_remark_box").show();
8 + }, function() {
9 + $("#mem_remark_box").hide();
10 + });
11 + });
12 + alert("hahaha");
1 :css
13 :css
2 .hof_user { color: orangered; font-style: italic; }
14 .hof_user { color: orangered; font-style: italic; }
3 .hof_language { color: green; font-style: italic; }
15 .hof_language { color: green; font-style: italic; }
4 .hof_value { color: deeppink;font-style: italic; }
16 .hof_value { color: deeppink;font-style: italic; }
17 + .info_param { font-weight: bold;text-align: right; }
18 + .tooltip {
19 + font-family: Verdana,sans-serif;
20 + font-weight: normal;
21 + text-align: left;
22 + font-size: 1.0em;
23 + color: black;
24 + line-height: 1.1;
25 + display: none;
26 + min-width: 20em;
27 + position: absolute;
28 + left: 25px;
29 + bottom: 5px;
30 + border: 1px solid;
31 + padding: 5px;
32 + background-color: #FFF;
33 + word-wrap: break-word;
34 + z-index: 9999;
35 + overflow: auto;
36 + }
5
37
6 - %h2 Overall of #{Problem.find(params[:id]).full_name}
38 + %h1 (#{Problem.find(params[:id]).name}) #{Problem.find(params[:id]).full_name}
39 +
40 + %h2 Problem Stat
41 + %table.info
42 + %thead
43 + %tr.info-head
44 + %th Stat
45 + %th Value
46 + %tbody
47 + %tr{class: cycle('info-even','info-odd')}
48 + %td.info_param Submissions
49 + %td= @summary[:count]
50 + %tr{class: cycle('info-even','info-odd')}
51 + %td.info_param Solved/Attempted User
52 + %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
53 + - if @best
54 + %tr{class: cycle('info-even','info-odd')}
55 + %td.info_param Best Runtime
56 + %td
57 + by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
58 + using <span class="hof_language">#{@best[:runtime][:lang]}</span>
59 + with <span class="hof_value">#{@best[:runtime][:value] * 1000} milliseconds</span>
60 + at submission
61 + = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
62 +
63 + %tr{class: cycle('info-even','info-odd')}
64 + %td.info_param
65 + Best Memory Usage
66 + %sup{ id: "mem_remark", style: "position:relative; color: blue;"}
67 + [?]
68 + %span.tooltip#mem_remark_box
69 + This counts only for submission with 100% score.
70 + Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
71 + %td
72 + by #{link_to @best[:memory][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
73 + using <span class="hof_language">#{@best[:memory][:lang]}</span>
74 + with <span class="hof_value">#{number_with_delimiter(@best[:memory][:value])} kbytes </span>
75 + at submission
76 + = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
77 +
78 + %tr{class: cycle('info-even','info-odd')}
79 + %td.info_param Shortest Code
80 + %td
81 + by #{link_to @best[:length][:user], controller:'users', action:'profile', id:@best[:length][:user_id]}
82 + using <span class="hof_language">#{@best[:length][:lang]}</span>
83 + with <span class="hof_value">#{@best[:length][:value]} bytes</span>
84 + at submission
85 + = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
86 +
87 + %tr{class: cycle('info-even','info-odd')}
88 + %td.info_param First solver
89 + %td
90 + #{link_to @best[:first][:user], controller:'users', action:'profile', id:@best[:first][:user_id]} is the first solver
91 + using <span class="hof_language">#{@best[:first][:lang]}</span>
92 + on <span class="hof_value">#{@best[:first][:value]}</span>
93 + at submission
94 + = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
7
95
8 - if @best
96 - if @best
9 - %b Best Runtime:
10 - by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
11 - using <span class="hof_language">#{@best[:runtime][:lang]}</span>
12 - with <span class="hof_value">#{@best[:runtime][:value] * 1000} milliseconds</span>
13 - at submission
14 - = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
15 - %br/
16 -
17 - %b Best Memory Usage:
18 - by #{link_to @best[:memory][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
19 - using <span class="hof_language">#{@best[:memory][:lang]}</span>
20 - with <span class="hof_value">#{number_with_delimiter(@best[:memory][:value])} kbytes </span>
21 - at submission
22 - = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
23 - %br/
24 -
25 - %b Shortest Code:
26 - by #{link_to @best[:length][:user], controller:'users', action:'profile', id:@best[:length][:user_id]}
27 - using <span class="hof_language">#{@best[:length][:lang]}</span>
28 - with <span class="hof_value">#{@best[:length][:value]} bytes</span>
29 - at submission
30 - = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
31 - %br/
32 -
33 - %b First solver:
34 - #{link_to @best[:first][:user], controller:'users', action:'profile', id:@best[:first][:user_id]} is the first solver
35 - using <span class="hof_language">#{@best[:first][:lang]}</span>
36 - on <span class="hof_value">#{@best[:first][:value]}</span>
37 - at submission
38 - = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
39 - %br/
40 -
41 -
42 - %p
43 - This counts only for submission with 100% score <br/>
44 - Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
45 -
46 %h2 By language
97 %h2 By language
47
98
48 %table.info
99 %table.info
49 %thead
100 %thead
50 %tr.info-head
101 %tr.info-head
51 %th Language
102 %th Language
52 %th Best runtime (ms)
103 %th Best runtime (ms)
53 %th Best memory (kbytes)
104 %th Best memory (kbytes)
54 %th Shortest Code (bytes)
105 %th Shortest Code (bytes)
55 %th First solver
106 %th First solver
56 %tbody
107 %tbody
57 - @by_lang.each do |lang,value|
108 - @by_lang.each do |lang,value|
58 %tr{class: cycle('info-even','info-odd')}
109 %tr{class: cycle('info-even','info-odd')}
59 %td= lang
110 %td= lang
60 %td
111 %td
61 = link_to value[:runtime][:user], controller: 'users', action: 'profile', id: value[:runtime][:user_id]
112 = link_to value[:runtime][:user], controller: 'users', action: 'profile', id: value[:runtime][:user_id]
62 = "(#{(value[:runtime][:value] * 1000).to_i} @"
113 = "(#{(value[:runtime][:value] * 1000).to_i} @"
63 = "#{link_to("#" + value[:runtime][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:runtime][:sub_id])} )".html_safe
114 = "#{link_to("#" + value[:runtime][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:runtime][:sub_id])} )".html_safe
64 %td
115 %td
65 = link_to value[:memory][:user], controller: 'users', action: 'profile', id: value[:memory][:user_id]
116 = link_to value[:memory][:user], controller: 'users', action: 'profile', id: value[:memory][:user_id]
66 = "(#{number_with_delimiter(value[:memory][:value])} @"
117 = "(#{number_with_delimiter(value[:memory][:value])} @"
67 = "#{link_to("#" + value[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:memory][:sub_id])} )".html_safe
118 = "#{link_to("#" + value[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:memory][:sub_id])} )".html_safe
68 %td
119 %td
69 = link_to value[:length][:user], controller: 'users', action: 'profile', id: value[:length][:user_id]
120 = link_to value[:length][:user], controller: 'users', action: 'profile', id: value[:length][:user_id]
70 = "(#{value[:length][:value]} @"
121 = "(#{value[:length][:value]} @"
71 = "#{link_to("#" + value[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:length][:sub_id])} )".html_safe
122 = "#{link_to("#" + value[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:length][:sub_id])} )".html_safe
72 %td
123 %td
73 - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
124 - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
74 = link_to value[:first][:user], controller: 'users', action: 'profile', id: value[:first][:user_id]
125 = link_to value[:first][:user], controller: 'users', action: 'profile', id: value[:first][:user_id]
75 = "(#{value[:first][:value]} @"
126 = "(#{value[:first][:value]} @"
76 = "#{link_to("#" + value[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:first][:sub_id])} )".html_safe
127 = "#{link_to("#" + value[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:first][:sub_id])} )".html_safe
77
128
78 - - else
79 - %h3 No submissions
@@ -1,22 +1,23
1
1
2 /- if params[:id]
2 /- if params[:id]
3 / %h1 Tasks Hall of Fame
3 / %h1 Tasks Hall of Fame
4 / = link_to('[back to All-Time Hall of Fame]', action: 'problem_hof', id: nil )
4 / = link_to('[back to All-Time Hall of Fame]', action: 'problem_hof', id: nil )
5 /- else
5 /- else
6 / %h1 All-Time Hall of Fame
6 / %h1 All-Time Hall of Fame
7
7
8
8
9 - %h1 Tasks Hall of Fame
9 + %h1 Hall of Fame
10 .task-menu
10 .task-menu
11 Tasks
11 Tasks
12 %br/
12 %br/
13 - @problems.each do |prob|
13 - @problems.each do |prob|
14 = link_to( "[#{prob.name}]", {id: prob.id})
14 = link_to( "[#{prob.name}]", {id: prob.id})
15
15
16 - unless params[:id]
16 - unless params[:id]
17 /=render partial: 'all_time_hof'
17 /=render partial: 'all_time_hof'
18 Please select a problem.
18 Please select a problem.
19 - else
19 - else
20 =render partial: 'task_hof'
20 =render partial: 'task_hof'
21 + %h2 Submission History
22 + =render partial: 'application/bar_graph', locals: { histogram: @histogram }
21
23
22 -
@@ -1,52 +1,66
1 - content_for :header do
1 - content_for :header do
2 = javascript_include_tag 'local_jquery'
2 = javascript_include_tag 'local_jquery'
3
3
4 - %script{:type=>"text/javascript"}
4 + :javascript
5 $(function () {
5 $(function () {
6 - $('#submission_table').tablesorter({widgets: ['zebra']});
6 + $('#submission_table').tablesorter({widgets: ['zebra']});
7 });
7 });
8
8
9 :css
9 :css
10 .fix-width {
10 .fix-width {
11 font-family: Droid Sans Mono,Consolas, monospace, mono, Courier New, Courier;
11 font-family: Droid Sans Mono,Consolas, monospace, mono, Courier New, Courier;
12 }
12 }
13
13
14 - %h1= @user.full_name + ' Profile'
14 + %h1= @user.full_name
15
15
16 - %h2 Basic info
17 <b>Login:</b> #{@user.login} <br/>
16 <b>Login:</b> #{@user.login} <br/>
18 <b>Full name:</b> #{@user.full_name} <br />
17 <b>Full name:</b> #{@user.full_name} <br />
19
18
20
19
21 %h2 Problem Stat
20 %h2 Problem Stat
21 + %table.info
22 + %thead
23 + %tr.info-head
24 + %th Stat
25 + %th Value
26 + %tbody
27 + %tr{class: cycle('info-even','info-odd')}
28 + %td.info_param Submissions
29 + %td= @summary[:count]
30 + %tr{class: cycle('info-even','info-odd')}
31 + %td.info_param Solved/Attempted Problem
32 + %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
22
33
23 - %h2 Submissions
34 + %h2 Submission History
35 +
36 + =render partial: 'application/bar_graph', locals: {histogram: @histogram, param: {bar_width: 7}}
37 +
24
38
25 %table.tablesorter-cafe#submission_table
39 %table.tablesorter-cafe#submission_table
26 %thead
40 %thead
27 %tr
41 %tr
28 %th ID
42 %th ID
29 %th Problem code
43 %th Problem code
30 %th Problem full name
44 %th Problem full name
31 %th Language
45 %th Language
32 %th Submitted at
46 %th Submitted at
33 %th Result
47 %th Result
34 %th Score
48 %th Score
35 - if session[:admin]
49 - if session[:admin]
36 %th IP
50 %th IP
37 %tbody
51 %tbody
38 - @submission.each do |s|
52 - @submission.each do |s|
39 - next unless s.problem
53 - next unless s.problem
40 %tr
54 %tr
41 %td= link_to "#{s.id}", controller: "graders", action: "submission", id: s.id
55 %td= link_to "#{s.id}", controller: "graders", action: "submission", id: s.id
42 - %td= s.problem.name
56 + %td= link_to s.problem.name, controller: "problems", action: "stat", id: s.problem
43 %td= s.problem.full_name
57 %td= s.problem.full_name
44 %td= s.language.pretty_name
58 %td= s.language.pretty_name
45 %td #{s.submitted_at.strftime('%Y-%m-%d %H:%M')} (#{time_ago_in_words(s.submitted_at)} ago)
59 %td #{s.submitted_at.strftime('%Y-%m-%d %H:%M')} (#{time_ago_in_words(s.submitted_at)} ago)
46 %td.fix-width= s.grader_comment
60 %td.fix-width= s.grader_comment
47 %td= (s.points*100)/s.problem.full_score
61 %td= (s.points*100)/s.problem.full_score
48 - if session[:admin]
62 - if session[:admin]
49 %td= s.ip_address
63 %td= s.ip_address
50
64
51
65
52
66
@@ -1,58 +1,58
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 &"
32 + GraderScript.call_grader "#{env} queue --err-log &"
33 - GraderScript.call_grader "#{env} test_request &"
33 + GraderScript.call_grader "#{env} test_request -err-log &"
34 end
34 end
35
35
36 def self.call_import_problem(problem_name,
36 def self.call_import_problem(problem_name,
37 problem_dir,
37 problem_dir,
38 time_limit=1,
38 time_limit=1,
39 memory_limit=32,
39 memory_limit=32,
40 checker_name='text')
40 checker_name='text')
41 if GraderScript.grader_control_enabled?
41 if GraderScript.grader_control_enabled?
42 cur_dir = `pwd`.chomp
42 cur_dir = `pwd`.chomp
43 Dir.chdir(GRADER_ROOT_DIR)
43 Dir.chdir(GRADER_ROOT_DIR)
44
44
45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 " -t #{time_limit} -m #{memory_limit}"
47 " -t #{time_limit} -m #{memory_limit}"
48
48
49 output = `#{cmd}`
49 output = `#{cmd}`
50
50
51 Dir.chdir(cur_dir)
51 Dir.chdir(cur_dir)
52
52
53 return "import CMD: #{cmd}\n" + output
53 return "import CMD: #{cmd}\n" + output
54 end
54 end
55 return ''
55 return ''
56 end
56 end
57
57
58 end
58 end
You need to be logged in to leave comments. Login now