Description:
make report max_score remember user options
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r647:bb242b3ef68d - - 3 files changed: 8 inserted, 6 deleted

@@ -1,247 +1,249
1 require 'csv'
1 require 'csv'
2
2
3 class ReportController < ApplicationController
3 class ReportController < ApplicationController
4
4
5 before_filter :authenticate
5 before_filter :authenticate
6
6
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 params[:problem_id].each do |id|
38 params[:problem_id].each do |id|
38 next unless id.strip != ""
39 next unless id.strip != ""
39 pid = Problem.find_by_id(id.to_i)
40 pid = Problem.find_by_id(id.to_i)
40 @problems << pid if pid
41 @problems << pid if pid
41 end
42 end
43 + end
42
44
43 #users
45 #users
44 @users = if params[:user] == "all" then
46 @users = if params[:user] == "all" then
45 User.includes(:contests).includes(:contest_stat)
47 User.includes(:contests).includes(:contest_stat)
46 else
48 else
47 User.includes(:contests).includes(:contest_stat).where(enabled: true)
49 User.includes(:contests).includes(:contest_stat).where(enabled: true)
48 end
50 end
49
51
50 #set up range from param
52 #set up range from param
51 - since_id = params.fetch(:from_id, 0).to_i
53 + @since_id = params.fetch(:from_id, 0).to_i
52 - until_id = params.fetch(:to_id, 0).to_i
54 + @until_id = params.fetch(:to_id, 0).to_i
53
55
54 #calculate the routine
56 #calculate the routine
55 - @scorearray = calculate_max_score(@problems, @users,since_id,until_id)
57 + @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
56
58
57 #rencer accordingly
59 #rencer accordingly
58 if params[:button] == 'download' then
60 if params[:button] == 'download' then
59 csv = gen_csv_from_scorearray(@scorearray,@problems)
61 csv = gen_csv_from_scorearray(@scorearray,@problems)
60 send_data csv, filename: 'max_score.csv'
62 send_data csv, filename: 'max_score.csv'
61 else
63 else
62 #render template: 'user_admin/user_stat'
64 #render template: 'user_admin/user_stat'
63 render 'max_score'
65 render 'max_score'
64 end
66 end
65
67
66 end
68 end
67
69
68 def score
70 def score
69 if params[:commit] == 'download csv'
71 if params[:commit] == 'download csv'
70 @problems = Problem.all
72 @problems = Problem.all
71 else
73 else
72 @problems = Problem.available_problems
74 @problems = Problem.available_problems
73 end
75 end
74 @users = User.includes(:contests, :contest_stat).where(enabled: true)
76 @users = User.includes(:contests, :contest_stat).where(enabled: true)
75 @scorearray = Array.new
77 @scorearray = Array.new
76 @users.each do |u|
78 @users.each do |u|
77 ustat = Array.new
79 ustat = Array.new
78 ustat[0] = u
80 ustat[0] = u
79 @problems.each do |p|
81 @problems.each do |p|
80 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
82 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
81 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
83 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
82 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
84 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
83 else
85 else
84 ustat << [0,false]
86 ustat << [0,false]
85 end
87 end
86 end
88 end
87 @scorearray << ustat
89 @scorearray << ustat
88 end
90 end
89 if params[:commit] == 'download csv' then
91 if params[:commit] == 'download csv' then
90 csv = gen_csv_from_scorearray(@scorearray,@problems)
92 csv = gen_csv_from_scorearray(@scorearray,@problems)
91 send_data csv, filename: 'last_score.csv'
93 send_data csv, filename: 'last_score.csv'
92 else
94 else
93 render template: 'user_admin/user_stat'
95 render template: 'user_admin/user_stat'
94 end
96 end
95
97
96 end
98 end
97
99
98 def login_stat
100 def login_stat
99 @logins = Array.new
101 @logins = Array.new
100
102
101 date_and_time = '%Y-%m-%d %H:%M'
103 date_and_time = '%Y-%m-%d %H:%M'
102 begin
104 begin
103 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
105 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
104 @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)
106 @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)
105 rescue
107 rescue
106 @since_time = DateTime.new(1000,1,1)
108 @since_time = DateTime.new(1000,1,1)
107 end
109 end
108 begin
110 begin
109 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
111 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
110 @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)
112 @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)
111 rescue
113 rescue
112 @until_time = DateTime.new(3000,1,1)
114 @until_time = DateTime.new(3000,1,1)
113 end
115 end
114
116
115 User.all.each do |user|
117 User.all.each do |user|
116 @logins << { id: user.id,
118 @logins << { id: user.id,
117 login: user.login,
119 login: user.login,
118 full_name: user.full_name,
120 full_name: user.full_name,
119 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
121 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
120 user.id,@since_time,@until_time)
122 user.id,@since_time,@until_time)
121 .count(:id),
123 .count(:id),
122 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
124 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
123 user.id,@since_time,@until_time)
125 user.id,@since_time,@until_time)
124 .minimum(:created_at),
126 .minimum(:created_at),
125 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
127 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
126 user.id,@since_time,@until_time)
128 user.id,@since_time,@until_time)
127 .maximum(:created_at),
129 .maximum(:created_at),
128 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
130 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
129 user.id,@since_time,@until_time)
131 user.id,@since_time,@until_time)
130 .select(:ip_address).uniq
132 .select(:ip_address).uniq
131
133
132 }
134 }
133 end
135 end
134 end
136 end
135
137
136 def submission_stat
138 def submission_stat
137
139
138 date_and_time = '%Y-%m-%d %H:%M'
140 date_and_time = '%Y-%m-%d %H:%M'
139 begin
141 begin
140 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
142 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
141 rescue
143 rescue
142 @since_time = DateTime.new(1000,1,1)
144 @since_time = DateTime.new(1000,1,1)
143 end
145 end
144 begin
146 begin
145 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
147 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
146 rescue
148 rescue
147 @until_time = DateTime.new(3000,1,1)
149 @until_time = DateTime.new(3000,1,1)
148 end
150 end
149
151
150 @submissions = {}
152 @submissions = {}
151
153
152 User.find_each do |user|
154 User.find_each do |user|
153 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
155 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
154 end
156 end
155
157
156 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
158 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
157 if @submissions[s.user_id]
159 if @submissions[s.user_id]
158 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
160 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
159 a = Problem.find_by_id(s.problem_id)
161 a = Problem.find_by_id(s.problem_id)
160 @submissions[s.user_id][:sub][s.problem_id] =
162 @submissions[s.user_id][:sub][s.problem_id] =
161 { prob_name: (a ? a.full_name : '(NULL)'),
163 { prob_name: (a ? a.full_name : '(NULL)'),
162 sub_ids: [s.id] }
164 sub_ids: [s.id] }
163 else
165 else
164 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
166 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
165 end
167 end
166 @submissions[s.user_id][:count] += 1
168 @submissions[s.user_id][:count] += 1
167 end
169 end
168 end
170 end
169 end
171 end
170
172
171 def problem_hof
173 def problem_hof
172 # gen problem list
174 # gen problem list
173 @user = User.find(session[:user_id])
175 @user = User.find(session[:user_id])
174 @problems = @user.available_problems
176 @problems = @user.available_problems
175
177
176 # get selected problems or the default
178 # get selected problems or the default
177 if params[:id]
179 if params[:id]
178 begin
180 begin
179 @problem = Problem.available.find(params[:id])
181 @problem = Problem.available.find(params[:id])
180 rescue
182 rescue
181 redirect_to action: :problem_hof
183 redirect_to action: :problem_hof
182 flash[:notice] = 'Error: submissions for that problem are not viewable.'
184 flash[:notice] = 'Error: submissions for that problem are not viewable.'
183 return
185 return
184 end
186 end
185 end
187 end
186
188
187 return unless @problem
189 return unless @problem
188
190
189 @by_lang = {} #aggregrate by language
191 @by_lang = {} #aggregrate by language
190
192
191 range =65
193 range =65
192 @histogram = { data: Array.new(range,0), summary: {} }
194 @histogram = { data: Array.new(range,0), summary: {} }
193 @summary = {count: 0, solve: 0, attempt: 0}
195 @summary = {count: 0, solve: 0, attempt: 0}
194 user = Hash.new(0)
196 user = Hash.new(0)
195 Submission.where(problem_id: @problem.id).find_each do |sub|
197 Submission.where(problem_id: @problem.id).find_each do |sub|
196 #histogram
198 #histogram
197 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
199 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
198 @histogram[:data][d.to_i] += 1 if d < range
200 @histogram[:data][d.to_i] += 1 if d < range
199
201
200 next unless sub.points
202 next unless sub.points
201 @summary[:count] += 1
203 @summary[:count] += 1
202 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
204 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
203
205
204 lang = Language.find_by_id(sub.language_id)
206 lang = Language.find_by_id(sub.language_id)
205 next unless lang
207 next unless lang
206 next unless sub.points >= @problem.full_score
208 next unless sub.points >= @problem.full_score
207
209
208 #initialize
210 #initialize
209 unless @by_lang.has_key?(lang.pretty_name)
211 unless @by_lang.has_key?(lang.pretty_name)
210 @by_lang[lang.pretty_name] = {
212 @by_lang[lang.pretty_name] = {
211 runtime: { avail: false, value: 2**30-1 },
213 runtime: { avail: false, value: 2**30-1 },
212 memory: { avail: false, value: 2**30-1 },
214 memory: { avail: false, value: 2**30-1 },
213 length: { avail: false, value: 2**30-1 },
215 length: { avail: false, value: 2**30-1 },
214 first: { avail: false, value: DateTime.new(3000,1,1) }
216 first: { avail: false, value: DateTime.new(3000,1,1) }
215 }
217 }
216 end
218 end
217
219
218 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
220 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
219 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
221 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
220 end
222 end
221
223
222 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
224 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
223 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
225 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
224 end
226 end
225
227
226 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
228 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
227 !sub.user.admin?
229 !sub.user.admin?
228 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
230 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
229 end
231 end
230
232
231 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
233 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
232 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
234 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
233 end
235 end
234 end
236 end
235
237
236 #process user_id
238 #process user_id
237 @by_lang.each do |lang,prop|
239 @by_lang.each do |lang,prop|
238 prop.each do |k,v|
240 prop.each do |k,v|
239 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
241 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
240 end
242 end
241 end
243 end
242
244
243 #sum into best
245 #sum into best
244 if @by_lang and @by_lang.first
246 if @by_lang and @by_lang.first
245 @best = @by_lang.first[1].clone
247 @best = @by_lang.first[1].clone
246 @by_lang.each do |lang,prop|
248 @by_lang.each do |lang,prop|
247 if @best[:runtime][:value] >= prop[:runtime][:value]
249 if @best[:runtime][:value] >= prop[:runtime][:value]
@@ -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', nil, 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', nil, 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', true
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'
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,2 +1,2
1 :plain
1 :plain
2 - $("body").prepend("<div class=\"alert alert-info\"> Submission #{@submission.id}'s task status has been chaned to \"#{@task.status_str}\" </div>")
2 + $("body").prepend("<div class=\"alert alert-info\"> Submission #{@submission.id}'s task status has been changed to \"#{@task.status_str}\". It will be re-judged soon. </div>")
You need to be logged in to leave comments. Login now