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,439 +1,441
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]
248 @best[:runtime] = prop[:runtime]
250 @best[:runtime] = prop[:runtime]
249 @best[:runtime][:lang] = lang
251 @best[:runtime][:lang] = lang
250 end
252 end
251 if @best[:memory][:value] >= prop[:memory][:value]
253 if @best[:memory][:value] >= prop[:memory][:value]
252 @best[:memory] = prop[:memory]
254 @best[:memory] = prop[:memory]
253 @best[:memory][:lang] = lang
255 @best[:memory][:lang] = lang
254 end
256 end
255 if @best[:length][:value] >= prop[:length][:value]
257 if @best[:length][:value] >= prop[:length][:value]
256 @best[:length] = prop[:length]
258 @best[:length] = prop[:length]
257 @best[:length][:lang] = lang
259 @best[:length][:lang] = lang
258 end
260 end
259 if @best[:first][:value] >= prop[:first][:value]
261 if @best[:first][:value] >= prop[:first][:value]
260 @best[:first] = prop[:first]
262 @best[:first] = prop[:first]
261 @best[:first][:lang] = lang
263 @best[:first][:lang] = lang
262 end
264 end
263 end
265 end
264 end
266 end
265
267
266 @histogram[:summary][:max] = [@histogram[:data].max,1].max
268 @histogram[:summary][:max] = [@histogram[:data].max,1].max
267 @summary[:attempt] = user.count
269 @summary[:attempt] = user.count
268 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
270 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
269 end
271 end
270
272
271 def stuck #report struggling user,problem
273 def stuck #report struggling user,problem
272 # init
274 # init
273 user,problem = nil
275 user,problem = nil
274 solve = true
276 solve = true
275 tries = 0
277 tries = 0
276 @struggle = Array.new
278 @struggle = Array.new
277 record = {}
279 record = {}
278 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
280 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
279 next unless sub.problem and sub.user
281 next unless sub.problem and sub.user
280 if user != sub.user_id or problem != sub.problem_id
282 if user != sub.user_id or problem != sub.problem_id
281 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
283 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
282 record = {user: sub.user, problem: sub.problem}
284 record = {user: sub.user, problem: sub.problem}
283 user,problem = sub.user_id, sub.problem_id
285 user,problem = sub.user_id, sub.problem_id
284 solve = false
286 solve = false
285 tries = 0
287 tries = 0
286 end
288 end
287 if sub.points >= sub.problem.full_score
289 if sub.points >= sub.problem.full_score
288 solve = true
290 solve = true
289 else
291 else
290 tries += 1
292 tries += 1
291 end
293 end
292 end
294 end
293 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
295 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
294 @struggle = @struggle[0..50]
296 @struggle = @struggle[0..50]
295 end
297 end
296
298
297
299
298 def multiple_login
300 def multiple_login
299 #user with multiple IP
301 #user with multiple IP
300 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
302 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
301 last,count = 0,0
303 last,count = 0,0
302 first = 0
304 first = 0
303 @users = []
305 @users = []
304 raw.each do |r|
306 raw.each do |r|
305 if last != r.user.login
307 if last != r.user.login
306 count = 1
308 count = 1
307 last = r.user.login
309 last = r.user.login
308 first = r
310 first = r
309 else
311 else
310 @users << first if count == 1
312 @users << first if count == 1
311 @users << r
313 @users << r
312 count += 1
314 count += 1
313 end
315 end
314 end
316 end
315
317
316 #IP with multiple user
318 #IP with multiple user
317 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
319 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
318 last,count = 0,0
320 last,count = 0,0
319 first = 0
321 first = 0
320 @ip = []
322 @ip = []
321 raw.each do |r|
323 raw.each do |r|
322 if last != r.ip_address
324 if last != r.ip_address
323 count = 1
325 count = 1
324 last = r.ip_address
326 last = r.ip_address
325 first = r
327 first = r
326 else
328 else
327 @ip << first if count == 1
329 @ip << first if count == 1
328 @ip << r
330 @ip << r
329 count += 1
331 count += 1
330 end
332 end
331 end
333 end
332 end
334 end
333
335
334 def cheat_report
336 def cheat_report
335 date_and_time = '%Y-%m-%d %H:%M'
337 date_and_time = '%Y-%m-%d %H:%M'
336 begin
338 begin
337 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
339 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
338 @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)
340 @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)
339 rescue
341 rescue
340 @since_time = Time.zone.now.ago( 90.minutes)
342 @since_time = Time.zone.now.ago( 90.minutes)
341 end
343 end
342 begin
344 begin
343 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
345 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
344 @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)
346 @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)
345 rescue
347 rescue
346 @until_time = Time.zone.now
348 @until_time = Time.zone.now
347 end
349 end
348
350
349 #multi login
351 #multi login
350 @ml = Login.joins(:user).where("logins.created_at >= ? and logins.created_at <= ?",@since_time,@until_time).select('users.login,count(distinct ip_address) as count,users.full_name').group("users.id").having("count > 1")
352 @ml = Login.joins(:user).where("logins.created_at >= ? and logins.created_at <= ?",@since_time,@until_time).select('users.login,count(distinct ip_address) as count,users.full_name').group("users.id").having("count > 1")
351
353
352 st = <<-SQL
354 st = <<-SQL
353 SELECT l2.*
355 SELECT l2.*
354 FROM logins l2 INNER JOIN
356 FROM logins l2 INNER JOIN
355 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
357 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
356 FROM logins l
358 FROM logins l
357 INNER JOIN users u ON l.user_id = u.id
359 INNER JOIN users u ON l.user_id = u.id
358 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
360 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
359 GROUP BY u.id
361 GROUP BY u.id
360 HAVING count > 1
362 HAVING count > 1
361 ) ml ON l2.user_id = ml.id
363 ) ml ON l2.user_id = ml.id
362 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
364 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
363 UNION
365 UNION
364 SELECT l2.*
366 SELECT l2.*
365 FROM logins l2 INNER JOIN
367 FROM logins l2 INNER JOIN
366 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
368 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
367 FROM logins l
369 FROM logins l
368 INNER JOIN users u ON l.user_id = u.id
370 INNER JOIN users u ON l.user_id = u.id
369 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
371 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
370 GROUP BY l.ip_address
372 GROUP BY l.ip_address
371 HAVING count > 1
373 HAVING count > 1
372 ) ml on ml.ip_address = l2.ip_address
374 ) ml on ml.ip_address = l2.ip_address
373 INNER JOIN users u ON l2.user_id = u.id
375 INNER JOIN users u ON l2.user_id = u.id
374 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
376 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
375 ORDER BY ip_address,created_at
377 ORDER BY ip_address,created_at
376 SQL
378 SQL
377 @mld = Login.find_by_sql(st)
379 @mld = Login.find_by_sql(st)
378
380
379 st = <<-SQL
381 st = <<-SQL
380 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
382 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
381 FROM submissions s INNER JOIN
383 FROM submissions s INNER JOIN
382 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
384 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
383 FROM logins l
385 FROM logins l
384 INNER JOIN users u ON l.user_id = u.id
386 INNER JOIN users u ON l.user_id = u.id
385 WHERE l.created_at >= ? and l.created_at <= ?
387 WHERE l.created_at >= ? and l.created_at <= ?
386 GROUP BY u.id
388 GROUP BY u.id
387 HAVING count > 1
389 HAVING count > 1
388 ) ml ON s.user_id = ml.id
390 ) ml ON s.user_id = ml.id
389 WHERE s.submitted_at >= ? and s.submitted_at <= ?
391 WHERE s.submitted_at >= ? and s.submitted_at <= ?
390 UNION
392 UNION
391 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
393 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
392 FROM submissions s INNER JOIN
394 FROM submissions s INNER JOIN
393 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
395 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
394 FROM logins l
396 FROM logins l
395 INNER JOIN users u ON l.user_id = u.id
397 INNER JOIN users u ON l.user_id = u.id
396 WHERE l.created_at >= ? and l.created_at <= ?
398 WHERE l.created_at >= ? and l.created_at <= ?
397 GROUP BY l.ip_address
399 GROUP BY l.ip_address
398 HAVING count > 1
400 HAVING count > 1
399 ) ml on ml.ip_address = s.ip_address
401 ) ml on ml.ip_address = s.ip_address
400 WHERE s.submitted_at >= ? and s.submitted_at <= ?
402 WHERE s.submitted_at >= ? and s.submitted_at <= ?
401 ORDER BY ip_address,submitted_at
403 ORDER BY ip_address,submitted_at
402 SQL
404 SQL
403 @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time,
405 @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time,
404 @since_time,@until_time,
406 @since_time,@until_time,
405 @since_time,@until_time,
407 @since_time,@until_time,
406 @since_time,@until_time])
408 @since_time,@until_time])
407
409
408 end
410 end
409
411
410 def cheat_scruntinize
412 def cheat_scruntinize
411 #convert date & time
413 #convert date & time
412 date_and_time = '%Y-%m-%d %H:%M'
414 date_and_time = '%Y-%m-%d %H:%M'
413 begin
415 begin
414 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
416 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
415 @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)
417 @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)
416 rescue
418 rescue
417 @since_time = Time.zone.now.ago( 90.minutes)
419 @since_time = Time.zone.now.ago( 90.minutes)
418 end
420 end
419 begin
421 begin
420 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
422 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
421 @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)
423 @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)
422 rescue
424 rescue
423 @until_time = Time.zone.now
425 @until_time = Time.zone.now
424 end
426 end
425
427
426 #convert sid
428 #convert sid
427 @sid = params[:SID].split(/[,\s]/) if params[:SID]
429 @sid = params[:SID].split(/[,\s]/) if params[:SID]
428 unless @sid and @sid.size > 0
430 unless @sid and @sid.size > 0
429 return
431 return
430 redirect_to actoin: :cheat_scruntinize
432 redirect_to actoin: :cheat_scruntinize
431 flash[:notice] = 'Please enter at least 1 student id'
433 flash[:notice] = 'Please enter at least 1 student id'
432 end
434 end
433 mark = Array.new(@sid.size,'?')
435 mark = Array.new(@sid.size,'?')
434 condition = "(u.login = " + mark.join(' OR u.login = ') + ')'
436 condition = "(u.login = " + mark.join(' OR u.login = ') + ')'
435
437
436 @st = <<-SQL
438 @st = <<-SQL
437 SELECT l.created_at as submitted_at ,-1 as id,u.login,u.full_name,l.ip_address,"" as problem_id,"" as points,l.user_id
439 SELECT l.created_at as submitted_at ,-1 as id,u.login,u.full_name,l.ip_address,"" as problem_id,"" as points,l.user_id
438 FROM logins l INNER JOIN users u on l.user_id = u.id
440 FROM logins l INNER JOIN users u on l.user_id = u.id
439 WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
441 WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
@@ -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