Description:
fix display bugs in corrent score
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r782:97cd56a5f1d8 - - 3 files changed: 5 inserted, 4 deleted

@@ -84,443 +84,444
84 @scorearray = Array.new
84 @scorearray = Array.new
85 @users.each do |u|
85 @users.each do |u|
86 ustat = Array.new
86 ustat = Array.new
87 ustat[0] = u
87 ustat[0] = u
88 @problems.each do |p|
88 @problems.each do |p|
89 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
89 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
90 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
90 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
91 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
91 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
92 else
92 else
93 ustat << [0,false]
93 ustat << [0,false]
94 end
94 end
95 end
95 end
96 @scorearray << ustat
96 @scorearray << ustat
97 end
97 end
98 if params[:commit] == 'download csv' then
98 if params[:commit] == 'download csv' then
99 csv = gen_csv_from_scorearray(@scorearray,@problems)
99 csv = gen_csv_from_scorearray(@scorearray,@problems)
100 send_data csv, filename: 'last_score.csv'
100 send_data csv, filename: 'last_score.csv'
101 else
101 else
102 render template: 'user_admin/user_stat'
102 render template: 'user_admin/user_stat'
103 end
103 end
104
104
105 end
105 end
106
106
107 def login_stat
107 def login_stat
108 @logins = Array.new
108 @logins = Array.new
109
109
110 date_and_time = '%Y-%m-%d %H:%M'
110 date_and_time = '%Y-%m-%d %H:%M'
111 begin
111 begin
112 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
112 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
113 @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)
113 @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)
114 rescue
114 rescue
115 @since_time = DateTime.new(1000,1,1)
115 @since_time = DateTime.new(1000,1,1)
116 end
116 end
117 begin
117 begin
118 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
118 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
119 @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)
119 @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)
120 rescue
120 rescue
121 @until_time = DateTime.new(3000,1,1)
121 @until_time = DateTime.new(3000,1,1)
122 end
122 end
123
123
124 User.all.each do |user|
124 User.all.each do |user|
125 @logins << { id: user.id,
125 @logins << { id: user.id,
126 login: user.login,
126 login: user.login,
127 full_name: user.full_name,
127 full_name: user.full_name,
128 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
128 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
129 user.id,@since_time,@until_time)
129 user.id,@since_time,@until_time)
130 .count(:id),
130 .count(:id),
131 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
131 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
132 user.id,@since_time,@until_time)
132 user.id,@since_time,@until_time)
133 .minimum(:created_at),
133 .minimum(:created_at),
134 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
134 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
135 user.id,@since_time,@until_time)
135 user.id,@since_time,@until_time)
136 .maximum(:created_at),
136 .maximum(:created_at),
137 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
137 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
138 user.id,@since_time,@until_time)
138 user.id,@since_time,@until_time)
139 .select(:ip_address).uniq
139 .select(:ip_address).uniq
140
140
141 }
141 }
142 end
142 end
143 end
143 end
144
144
145 def submission_stat
145 def submission_stat
146
146
147 date_and_time = '%Y-%m-%d %H:%M'
147 date_and_time = '%Y-%m-%d %H:%M'
148 begin
148 begin
149 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
149 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
150 rescue
150 rescue
151 @since_time = DateTime.new(1000,1,1)
151 @since_time = DateTime.new(1000,1,1)
152 end
152 end
153 begin
153 begin
154 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
154 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
155 rescue
155 rescue
156 @until_time = DateTime.new(3000,1,1)
156 @until_time = DateTime.new(3000,1,1)
157 end
157 end
158
158
159 @submissions = {}
159 @submissions = {}
160
160
161 User.find_each do |user|
161 User.find_each do |user|
162 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
162 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
163 end
163 end
164
164
165 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
165 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
166 if @submissions[s.user_id]
166 if @submissions[s.user_id]
167 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
167 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
168 a = Problem.find_by_id(s.problem_id)
168 a = Problem.find_by_id(s.problem_id)
169 @submissions[s.user_id][:sub][s.problem_id] =
169 @submissions[s.user_id][:sub][s.problem_id] =
170 { prob_name: (a ? a.full_name : '(NULL)'),
170 { prob_name: (a ? a.full_name : '(NULL)'),
171 sub_ids: [s.id] }
171 sub_ids: [s.id] }
172 else
172 else
173 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
173 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
174 end
174 end
175 @submissions[s.user_id][:count] += 1
175 @submissions[s.user_id][:count] += 1
176 end
176 end
177 end
177 end
178 end
178 end
179
179
180 def problem_hof
180 def problem_hof
181 # gen problem list
181 # gen problem list
182 @user = User.find(session[:user_id])
182 @user = User.find(session[:user_id])
183 @problems = @user.available_problems
183 @problems = @user.available_problems
184
184
185 # get selected problems or the default
185 # get selected problems or the default
186 if params[:id]
186 if params[:id]
187 begin
187 begin
188 @problem = Problem.available.find(params[:id])
188 @problem = Problem.available.find(params[:id])
189 rescue
189 rescue
190 redirect_to action: :problem_hof
190 redirect_to action: :problem_hof
191 flash[:notice] = 'Error: submissions for that problem are not viewable.'
191 flash[:notice] = 'Error: submissions for that problem are not viewable.'
192 return
192 return
193 end
193 end
194 end
194 end
195
195
196 return unless @problem
196 return unless @problem
197
197
198 @by_lang = {} #aggregrate by language
198 @by_lang = {} #aggregrate by language
199
199
200 range =65
200 range =65
201 @histogram = { data: Array.new(range,0), summary: {} }
201 @histogram = { data: Array.new(range,0), summary: {} }
202 @summary = {count: 0, solve: 0, attempt: 0}
202 @summary = {count: 0, solve: 0, attempt: 0}
203 user = Hash.new(0)
203 user = Hash.new(0)
204 Submission.where(problem_id: @problem.id).find_each do |sub|
204 Submission.where(problem_id: @problem.id).find_each do |sub|
205 #histogram
205 #histogram
206 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
206 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
207 @histogram[:data][d.to_i] += 1 if d < range
207 @histogram[:data][d.to_i] += 1 if d < range
208
208
209 next unless sub.points
209 next unless sub.points
210 @summary[:count] += 1
210 @summary[:count] += 1
211 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
211 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
212
212
213 lang = Language.find_by_id(sub.language_id)
213 lang = Language.find_by_id(sub.language_id)
214 next unless lang
214 next unless lang
215 next unless sub.points >= @problem.full_score
215 next unless sub.points >= @problem.full_score
216
216
217 #initialize
217 #initialize
218 unless @by_lang.has_key?(lang.pretty_name)
218 unless @by_lang.has_key?(lang.pretty_name)
219 @by_lang[lang.pretty_name] = {
219 @by_lang[lang.pretty_name] = {
220 runtime: { avail: false, value: 2**30-1 },
220 runtime: { avail: false, value: 2**30-1 },
221 memory: { avail: false, value: 2**30-1 },
221 memory: { avail: false, value: 2**30-1 },
222 length: { avail: false, value: 2**30-1 },
222 length: { avail: false, value: 2**30-1 },
223 first: { avail: false, value: DateTime.new(3000,1,1) }
223 first: { avail: false, value: DateTime.new(3000,1,1) }
224 }
224 }
225 end
225 end
226
226
227 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
227 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
228 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
228 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
229 end
229 end
230
230
231 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
231 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
232 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
232 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
233 end
233 end
234
234
235 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and sub.user and
235 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and sub.user and
236 !sub.user.admin?
236 !sub.user.admin?
237 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
237 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
238 end
238 end
239
239
240 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
240 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
241 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
241 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
242 end
242 end
243 end
243 end
244
244
245 #process user_id
245 #process user_id
246 @by_lang.each do |lang,prop|
246 @by_lang.each do |lang,prop|
247 prop.each do |k,v|
247 prop.each do |k,v|
248 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
248 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
249 end
249 end
250 end
250 end
251
251
252 #sum into best
252 #sum into best
253 if @by_lang and @by_lang.first
253 if @by_lang and @by_lang.first
254 @best = @by_lang.first[1].clone
254 @best = @by_lang.first[1].clone
255 @by_lang.each do |lang,prop|
255 @by_lang.each do |lang,prop|
256 if @best[:runtime][:value] >= prop[:runtime][:value]
256 if @best[:runtime][:value] >= prop[:runtime][:value]
257 @best[:runtime] = prop[:runtime]
257 @best[:runtime] = prop[:runtime]
258 @best[:runtime][:lang] = lang
258 @best[:runtime][:lang] = lang
259 end
259 end
260 if @best[:memory][:value] >= prop[:memory][:value]
260 if @best[:memory][:value] >= prop[:memory][:value]
261 @best[:memory] = prop[:memory]
261 @best[:memory] = prop[:memory]
262 @best[:memory][:lang] = lang
262 @best[:memory][:lang] = lang
263 end
263 end
264 if @best[:length][:value] >= prop[:length][:value]
264 if @best[:length][:value] >= prop[:length][:value]
265 @best[:length] = prop[:length]
265 @best[:length] = prop[:length]
266 @best[:length][:lang] = lang
266 @best[:length][:lang] = lang
267 end
267 end
268 if @best[:first][:value] >= prop[:first][:value]
268 if @best[:first][:value] >= prop[:first][:value]
269 @best[:first] = prop[:first]
269 @best[:first] = prop[:first]
270 @best[:first][:lang] = lang
270 @best[:first][:lang] = lang
271 end
271 end
272 end
272 end
273 end
273 end
274
274
275 @histogram[:summary][:max] = [@histogram[:data].max,1].max
275 @histogram[:summary][:max] = [@histogram[:data].max,1].max
276 @summary[:attempt] = user.count
276 @summary[:attempt] = user.count
277 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
277 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
278 end
278 end
279
279
280 def stuck #report struggling user,problem
280 def stuck #report struggling user,problem
281 # init
281 # init
282 user,problem = nil
282 user,problem = nil
283 solve = true
283 solve = true
284 tries = 0
284 tries = 0
285 @struggle = Array.new
285 @struggle = Array.new
286 record = {}
286 record = {}
287 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
287 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
288 next unless sub.problem and sub.user
288 next unless sub.problem and sub.user
289 if user != sub.user_id or problem != sub.problem_id
289 if user != sub.user_id or problem != sub.problem_id
290 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
290 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
291 record = {user: sub.user, problem: sub.problem}
291 record = {user: sub.user, problem: sub.problem}
292 user,problem = sub.user_id, sub.problem_id
292 user,problem = sub.user_id, sub.problem_id
293 solve = false
293 solve = false
294 tries = 0
294 tries = 0
295 end
295 end
296 if sub.points >= sub.problem.full_score
296 if sub.points >= sub.problem.full_score
297 solve = true
297 solve = true
298 else
298 else
299 tries += 1
299 tries += 1
300 end
300 end
301 end
301 end
302 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
302 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
303 @struggle = @struggle[0..50]
303 @struggle = @struggle[0..50]
304 end
304 end
305
305
306
306
307 def multiple_login
307 def multiple_login
308 #user with multiple IP
308 #user with multiple IP
309 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
309 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
310 last,count = 0,0
310 last,count = 0,0
311 first = 0
311 first = 0
312 @users = []
312 @users = []
313 raw.each do |r|
313 raw.each do |r|
314 if last != r.user.login
314 if last != r.user.login
315 count = 1
315 count = 1
316 last = r.user.login
316 last = r.user.login
317 first = r
317 first = r
318 else
318 else
319 @users << first if count == 1
319 @users << first if count == 1
320 @users << r
320 @users << r
321 count += 1
321 count += 1
322 end
322 end
323 end
323 end
324
324
325 #IP with multiple user
325 #IP with multiple user
326 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
326 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
327 last,count = 0,0
327 last,count = 0,0
328 first = 0
328 first = 0
329 @ip = []
329 @ip = []
330 raw.each do |r|
330 raw.each do |r|
331 if last != r.ip_address
331 if last != r.ip_address
332 count = 1
332 count = 1
333 last = r.ip_address
333 last = r.ip_address
334 first = r
334 first = r
335 else
335 else
336 @ip << first if count == 1
336 @ip << first if count == 1
337 @ip << r
337 @ip << r
338 count += 1
338 count += 1
339 end
339 end
340 end
340 end
341 end
341 end
342
342
343 def cheat_report
343 def cheat_report
344 date_and_time = '%Y-%m-%d %H:%M'
344 date_and_time = '%Y-%m-%d %H:%M'
345 begin
345 begin
346 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
346 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
347 @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)
347 @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)
348 rescue
348 rescue
349 @since_time = Time.zone.now.ago( 90.minutes)
349 @since_time = Time.zone.now.ago( 90.minutes)
350 end
350 end
351 begin
351 begin
352 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
352 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
353 @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)
353 @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)
354 rescue
354 rescue
355 @until_time = Time.zone.now
355 @until_time = Time.zone.now
356 end
356 end
357
357
358 #multi login
358 #multi login
359 @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")
359 @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")
360
360
361 st = <<-SQL
361 st = <<-SQL
362 SELECT l2.*
362 SELECT l2.*
363 FROM logins l2 INNER JOIN
363 FROM logins l2 INNER JOIN
364 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
364 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
365 FROM logins l
365 FROM logins l
366 INNER JOIN users u ON l.user_id = u.id
366 INNER JOIN users u ON l.user_id = u.id
367 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
367 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
368 GROUP BY u.id
368 GROUP BY u.id
369 HAVING count > 1
369 HAVING count > 1
370 ) ml ON l2.user_id = ml.id
370 ) ml ON l2.user_id = ml.id
371 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
371 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
372 UNION
372 UNION
373 SELECT l2.*
373 SELECT l2.*
374 FROM logins l2 INNER JOIN
374 FROM logins l2 INNER JOIN
375 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
375 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
376 FROM logins l
376 FROM logins l
377 INNER JOIN users u ON l.user_id = u.id
377 INNER JOIN users u ON l.user_id = u.id
378 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
378 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
379 GROUP BY l.ip_address
379 GROUP BY l.ip_address
380 HAVING count > 1
380 HAVING count > 1
381 ) ml on ml.ip_address = l2.ip_address
381 ) ml on ml.ip_address = l2.ip_address
382 INNER JOIN users u ON l2.user_id = u.id
382 INNER JOIN users u ON l2.user_id = u.id
383 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
383 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
384 ORDER BY ip_address,created_at
384 ORDER BY ip_address,created_at
385 SQL
385 SQL
386 @mld = Login.find_by_sql(st)
386 @mld = Login.find_by_sql(st)
387
387
388 st = <<-SQL
388 st = <<-SQL
389 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
389 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
390 FROM submissions s INNER JOIN
390 FROM submissions s INNER JOIN
391 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
391 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
392 FROM logins l
392 FROM logins l
393 INNER JOIN users u ON l.user_id = u.id
393 INNER JOIN users u ON l.user_id = u.id
394 WHERE l.created_at >= ? and l.created_at <= ?
394 WHERE l.created_at >= ? and l.created_at <= ?
395 GROUP BY u.id
395 GROUP BY u.id
396 HAVING count > 1
396 HAVING count > 1
397 ) ml ON s.user_id = ml.id
397 ) ml ON s.user_id = ml.id
398 WHERE s.submitted_at >= ? and s.submitted_at <= ?
398 WHERE s.submitted_at >= ? and s.submitted_at <= ?
399 UNION
399 UNION
400 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
400 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
401 FROM submissions s INNER JOIN
401 FROM submissions s INNER JOIN
402 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
402 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
403 FROM logins l
403 FROM logins l
404 INNER JOIN users u ON l.user_id = u.id
404 INNER JOIN users u ON l.user_id = u.id
405 WHERE l.created_at >= ? and l.created_at <= ?
405 WHERE l.created_at >= ? and l.created_at <= ?
406 GROUP BY l.ip_address
406 GROUP BY l.ip_address
407 HAVING count > 1
407 HAVING count > 1
408 ) ml on ml.ip_address = s.ip_address
408 ) ml on ml.ip_address = s.ip_address
409 WHERE s.submitted_at >= ? and s.submitted_at <= ?
409 WHERE s.submitted_at >= ? and s.submitted_at <= ?
410 ORDER BY ip_address,submitted_at
410 ORDER BY ip_address,submitted_at
411 SQL
411 SQL
412 @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time,
412 @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time,
413 @since_time,@until_time,
413 @since_time,@until_time,
414 @since_time,@until_time,
414 @since_time,@until_time,
415 @since_time,@until_time])
415 @since_time,@until_time])
416
416
417 end
417 end
418
418
419 def cheat_scruntinize
419 def cheat_scruntinize
420 #convert date & time
420 #convert date & time
421 date_and_time = '%Y-%m-%d %H:%M'
421 date_and_time = '%Y-%m-%d %H:%M'
422 begin
422 begin
423 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
423 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
424 @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)
424 @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)
425 rescue
425 rescue
426 @since_time = Time.zone.now.ago( 90.minutes)
426 @since_time = Time.zone.now.ago( 90.minutes)
427 end
427 end
428 begin
428 begin
429 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
429 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
430 @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)
430 @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)
431 rescue
431 rescue
432 @until_time = Time.zone.now
432 @until_time = Time.zone.now
433 end
433 end
434
434
435 #convert sid
435 #convert sid
436 @sid = params[:SID].split(/[,\s]/) if params[:SID]
436 @sid = params[:SID].split(/[,\s]/) if params[:SID]
437 unless @sid and @sid.size > 0
437 unless @sid and @sid.size > 0
438 return
438 return
439 redirect_to actoin: :cheat_scruntinize
439 redirect_to actoin: :cheat_scruntinize
440 flash[:notice] = 'Please enter at least 1 student id'
440 flash[:notice] = 'Please enter at least 1 student id'
441 end
441 end
442 mark = Array.new(@sid.size,'?')
442 mark = Array.new(@sid.size,'?')
443 condition = "(u.login = " + mark.join(' OR u.login = ') + ')'
443 condition = "(u.login = " + mark.join(' OR u.login = ') + ')'
444
444
445 @st = <<-SQL
445 @st = <<-SQL
446 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
446 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
447 FROM logins l INNER JOIN users u on l.user_id = u.id
447 FROM logins l INNER JOIN users u on l.user_id = u.id
448 WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
448 WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
449 UNION
449 UNION
450 SELECT s.submitted_at,s.id,u.login,u.full_name,s.ip_address,s.problem_id,s.points,s.user_id
450 SELECT s.submitted_at,s.id,u.login,u.full_name,s.ip_address,s.problem_id,s.points,s.user_id
451 FROM submissions s INNER JOIN users u ON s.user_id = u.id
451 FROM submissions s INNER JOIN users u ON s.user_id = u.id
452 WHERE s.submitted_at >= ? AND s.submitted_at <= ? AND #{condition}
452 WHERE s.submitted_at >= ? AND s.submitted_at <= ? AND #{condition}
453 ORDER BY submitted_at
453 ORDER BY submitted_at
454 SQL
454 SQL
455
455
456 p = [@st,@since_time,@until_time] + @sid + [@since_time,@until_time] + @sid
456 p = [@st,@since_time,@until_time] + @sid + [@since_time,@until_time] + @sid
457 @logs = Submission.joins(:problem).find_by_sql(p)
457 @logs = Submission.joins(:problem).find_by_sql(p)
458
458
459
459
460
460
461
461
462
462
463 end
463 end
464
464
465 protected
465 protected
466
466
467 def calculate_max_score(problems, users,since_id,until_id, get_last_score = false)
467 def calculate_max_score(problems, users,since_id,until_id, get_last_score = false)
468 + #score[i] = user #i's user stat where i is the index (not id)
468 scorearray = Array.new
469 scorearray = Array.new
469 users.each do |u|
470 users.each do |u|
470 ustat = Array.new
471 ustat = Array.new
471 ustat[0] = u
472 ustat[0] = u
472 problems.each do |p|
473 problems.each do |p|
473 unless get_last_score
474 unless get_last_score
474 #get max score
475 #get max score
475 max_points = 0
476 max_points = 0
476 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
477 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
477 max_points = sub.points if sub and sub.points and (sub.points > max_points)
478 max_points = sub.points if sub and sub.points and (sub.points > max_points)
478 end
479 end
479 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
480 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
480 else
481 else
481 #get latest score
482 #get latest score
482 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
483 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
483 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
484 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
484 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
485 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
485 else
486 else
486 ustat << [0,false]
487 ustat << [0,false]
487 end
488 end
488 end
489 end
489 end
490 end
490 scorearray << ustat
491 scorearray << ustat
491 end
492 end
492 return scorearray
493 return scorearray
493 end
494 end
494
495
495 def gen_csv_from_scorearray(scorearray,problem)
496 def gen_csv_from_scorearray(scorearray,problem)
496 CSV.generate do |csv|
497 CSV.generate do |csv|
497 #add header
498 #add header
498 header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
499 header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
499 problem.each { |p| header << p.name }
500 problem.each { |p| header << p.name }
500 header += ['Total','Passed']
501 header += ['Total','Passed']
501 csv << header
502 csv << header
502 #add data
503 #add data
503 scorearray.each do |sc|
504 scorearray.each do |sc|
504 total = num_passed = 0
505 total = num_passed = 0
505 row = Array.new
506 row = Array.new
506 sc.each_index do |i|
507 sc.each_index do |i|
507 if i == 0
508 if i == 0
508 row << sc[i].login
509 row << sc[i].login
509 row << sc[i].full_name
510 row << sc[i].full_name
510 row << sc[i].activated
511 row << sc[i].activated
511 row << (sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no')
512 row << (sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no')
512 row << sc[i].contests.collect {|c| c.name}.join(', ')
513 row << sc[i].contests.collect {|c| c.name}.join(', ')
513 else
514 else
514 row << sc[i][0]
515 row << sc[i][0]
515 total += sc[i][0]
516 total += sc[i][0]
516 num_passed += 1 if sc[i][1]
517 num_passed += 1 if sc[i][1]
517 end
518 end
518 end
519 end
519 row << total
520 row << total
520 row << num_passed
521 row << num_passed
521 csv << row
522 csv << row
522 end
523 end
523 end
524 end
524 end
525 end
525
526
526 end
527 end
@@ -1,69 +1,69
1 %table.table.sortable.table-striped.table-bordered.table-condensed
1 %table.table.sortable.table-striped.table-bordered.table-condensed
2 %thead
2 %thead
3 %tr
3 %tr
4 %th Login
4 %th Login
5 %th Name
5 %th Name
6 / %th Activated?
6 / %th Activated?
7 / %th Logged_in
7 / %th Logged_in
8 / %th Contest(s)
8 / %th Contest(s)
9 %th Remark
9 %th Remark
10 - @problems.each do |p|
10 - @problems.each do |p|
11 %th.text-right= p.name.gsub('_',' ')
11 %th.text-right= p.name.gsub('_',' ')
12 %th.text-right Total
12 %th.text-right Total
13 %th.text-right Passed
13 %th.text-right Passed
14 %tbody
14 %tbody
15 - - sum = Array.new(@scorearray[0].count,0)
15 + - sum = Array.new(@problems.count,0)
16 - - nonzero = Array.new(@scorearray[0].count,0)
16 + - nonzero = Array.new(@problems.count,0)
17 - - full = Array.new(@scorearray[0].count,0)
17 + - full = Array.new(@problems.count,0)
18 - @scorearray.each do |sc|
18 - @scorearray.each do |sc|
19 %tr
19 %tr
20 - total,num_passed = 0,0
20 - total,num_passed = 0,0
21 - sc.each_index do |i|
21 - sc.each_index do |i|
22 - if i == 0
22 - if i == 0
23 %td= link_to sc[i].login, stat_user_path(sc[i])
23 %td= link_to sc[i].login, stat_user_path(sc[i])
24 %td= sc[i].full_name
24 %td= sc[i].full_name
25 / %td= sc[i].activated
25 / %td= sc[i].activated
26 / %td= sc[i].try(:contest_stat).try(:started_at) ? 'yes' : 'no'
26 / %td= sc[i].try(:contest_stat).try(:started_at) ? 'yes' : 'no'
27 / %td= sc[i].contests.collect {|c| c.name}.join(', ')
27 / %td= sc[i].contests.collect {|c| c.name}.join(', ')
28 %td= sc[i].remark
28 %td= sc[i].remark
29 - else
29 - else
30 %td.text-right= sc[i][0]
30 %td.text-right= sc[i][0]
31 - total += sc[i][0]
31 - total += sc[i][0]
32 - num_passed += 1 if sc[i][1]
32 - num_passed += 1 if sc[i][1]
33 - sum[i] += sc[i][0]
33 - sum[i] += sc[i][0]
34 - nonzero[i] += 1 if sc[i][0] > 0
34 - nonzero[i] += 1 if sc[i][0] > 0
35 - full[i] += 1 if sc[i][1]
35 - full[i] += 1 if sc[i][1]
36 %td.text-right= total
36 %td.text-right= total
37 %td.text-right= num_passed
37 %td.text-right= num_passed
38 %tfoot
38 %tfoot
39 %tr
39 %tr
40 %td Summation
40 %td Summation
41 %td
41 %td
42 %td
42 %td
43 - sum.each.with_index do |s,i|
43 - sum.each.with_index do |s,i|
44 - next if i == 0
44 - next if i == 0
45 %td.text-right= number_with_delimiter(s)
45 %td.text-right= number_with_delimiter(s)
46 %td
46 %td
47 %td
47 %td
48 %tr
48 %tr
49 %td partial solver
49 %td partial solver
50 %td
50 %td
51 %td
51 %td
52 - nonzero.each.with_index do |s,i|
52 - nonzero.each.with_index do |s,i|
53 - next if i == 0
53 - next if i == 0
54 %td.text-right= number_with_delimiter(s)
54 %td.text-right= number_with_delimiter(s)
55 %td
55 %td
56 %td
56 %td
57 %tr
57 %tr
58 %td Full solver
58 %td Full solver
59 %td
59 %td
60 %td
60 %td
61 - full.each.with_index do |s,i|
61 - full.each.with_index do |s,i|
62 - next if i == 0
62 - next if i == 0
63 %td.text-right= number_with_delimiter(s)
63 %td.text-right= number_with_delimiter(s)
64 %td
64 %td
65 %td
65 %td
66
66
67
67
68 :javascript
68 :javascript
69 $.bootstrapSortable(true,'reversed')
69 $.bootstrapSortable(true,'reversed')
@@ -1,11 +1,11
1 .container-fluid
1 .container-fluid
2 %h1 Current Score
2 %h1 Current Score
3 = form_tag current_score_report_path, method: 'get' do
3 = form_tag current_score_report_path, method: 'get' do
4 Show only users from this group
4 Show only users from this group
5 - = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
5 + = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_id]), id: 'group_name',class: 'select2', style: 'width: 20em';
6 = submit_tag 'Apply',class: 'btn btn-default'
6 = submit_tag 'Apply',class: 'btn btn-default'
7
7
8 %br
8 %br
9
9
10
10
11 = render "score_table"
11 = render "score_table"
You need to be logged in to leave comments. Login now