Description:
add authorization for show max score
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r595:ad86e593f5b0 - - 1 file changed: 1 inserted, 1 deleted

@@ -1,452 +1,452
1 1 class ReportController < ApplicationController
2 2
3 - before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize]
3 + before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score]
4 4
5 5 before_filter(only: [:problem_hof]) { |c|
6 6 return false unless authenticate
7 7
8 8 if GraderConfiguration["right.user_view_submission"]
9 9 return true;
10 10 end
11 11
12 12 admin_authorization
13 13 }
14 14
15 15 def max_score
16 16 end
17 17
18 18 def show_max_score
19 19 #process parameters
20 20 #problems
21 21 @problems = []
22 22 params[:problem_id].each do |id|
23 23 next unless id.strip != ""
24 24 @problems << Problem.find(id.to_i)
25 25 end
26 26
27 27 #users
28 28 @users = if params[:user] == "all" then
29 29 User.find(:all, :include => [:contests, :contest_stat])
30 30 else
31 31 User.includes(:contests).includes(:contest_stat).where(enabled: true)
32 32 end
33 33
34 34 #set up range from param
35 35 since_id = params.fetch(:min_id, 0).to_i
36 36 until_id = params.fetch(:max_id, 0).to_i
37 37
38 38 #get data
39 39 @scorearray = Array.new
40 40 @users.each do |u|
41 41 ustat = Array.new
42 42 ustat[0] = u
43 43 @problems.each do |p|
44 44 max_points = 0
45 45 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
46 46 max_points = sub.points if sub and sub.points and (sub.points > max_points)
47 47 end
48 48 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
49 49 end
50 50 @scorearray << ustat
51 51 end
52 52
53 53 if params[:commit] == 'download csv' then
54 54 csv = gen_csv_from_scorearray(@scorearray,@problems)
55 55 send_data csv, filename: 'max_score.csv'
56 56 else
57 57 #render template: 'user_admin/user_stat'
58 58 render 'max_score'
59 59 end
60 60
61 61 end
62 62
63 63 def score
64 64 if params[:commit] == 'download csv'
65 65 @problems = Problem.all
66 66 else
67 67 @problems = Problem.find_available_problems
68 68 end
69 69 @users = User.includes(:contests, :contest_stat).where(enabled: true) #find(:all, :include => [:contests, :contest_stat]).where(enabled: true)
70 70 @scorearray = Array.new
71 71 @users.each do |u|
72 72 ustat = Array.new
73 73 ustat[0] = u
74 74 @problems.each do |p|
75 75 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
76 76 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
77 77 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
78 78 else
79 79 ustat << [0,false]
80 80 end
81 81 end
82 82 @scorearray << ustat
83 83 end
84 84 if params[:commit] == 'download csv' then
85 85 csv = gen_csv_from_scorearray(@scorearray,@problems)
86 86 send_data csv, filename: 'last_score.csv'
87 87 else
88 88 render template: 'user_admin/user_stat'
89 89 end
90 90
91 91 end
92 92
93 93 def login_stat
94 94 @logins = Array.new
95 95
96 96 date_and_time = '%Y-%m-%d %H:%M'
97 97 begin
98 98 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
99 99 @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)
100 100 rescue
101 101 @since_time = DateTime.new(1000,1,1)
102 102 end
103 103 begin
104 104 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
105 105 @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)
106 106 rescue
107 107 @until_time = DateTime.new(3000,1,1)
108 108 end
109 109
110 110 User.all.each do |user|
111 111 @logins << { id: user.id,
112 112 login: user.login,
113 113 full_name: user.full_name,
114 114 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
115 115 user.id,@since_time,@until_time)
116 116 .count(:id),
117 117 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
118 118 user.id,@since_time,@until_time)
119 119 .minimum(:created_at),
120 120 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
121 121 user.id,@since_time,@until_time)
122 122 .maximum(:created_at),
123 123 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
124 124 user.id,@since_time,@until_time)
125 125 .select(:ip_address).uniq
126 126
127 127 }
128 128 end
129 129 end
130 130
131 131 def submission_stat
132 132
133 133 date_and_time = '%Y-%m-%d %H:%M'
134 134 begin
135 135 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
136 136 rescue
137 137 @since_time = DateTime.new(1000,1,1)
138 138 end
139 139 begin
140 140 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
141 141 rescue
142 142 @until_time = DateTime.new(3000,1,1)
143 143 end
144 144
145 145 @submissions = {}
146 146
147 147 User.find_each do |user|
148 148 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
149 149 end
150 150
151 151 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
152 152 if @submissions[s.user_id]
153 153 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
154 154 a = Problem.find_by_id(s.problem_id)
155 155 @submissions[s.user_id][:sub][s.problem_id] =
156 156 { prob_name: (a ? a.full_name : '(NULL)'),
157 157 sub_ids: [s.id] }
158 158 else
159 159 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
160 160 end
161 161 @submissions[s.user_id][:count] += 1
162 162 end
163 163 end
164 164 end
165 165
166 166 def problem_hof
167 167 # gen problem list
168 168 @user = User.find(session[:user_id])
169 169 @problems = @user.available_problems
170 170
171 171 # get selected problems or the default
172 172 if params[:id]
173 173 begin
174 174 @problem = Problem.available.find(params[:id])
175 175 rescue
176 176 redirect_to action: :problem_hof
177 177 flash[:notice] = 'Error: submissions for that problem are not viewable.'
178 178 return
179 179 end
180 180 end
181 181
182 182 return unless @problem
183 183
184 184 @by_lang = {} #aggregrate by language
185 185
186 186 range =65
187 187 @histogram = { data: Array.new(range,0), summary: {} }
188 188 @summary = {count: 0, solve: 0, attempt: 0}
189 189 user = Hash.new(0)
190 190 Submission.where(problem_id: @problem.id).find_each do |sub|
191 191 #histogram
192 192 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
193 193 @histogram[:data][d.to_i] += 1 if d < range
194 194
195 195 next unless sub.points
196 196 @summary[:count] += 1
197 197 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
198 198
199 199 lang = Language.find_by_id(sub.language_id)
200 200 next unless lang
201 201 next unless sub.points >= @problem.full_score
202 202
203 203 #initialize
204 204 unless @by_lang.has_key?(lang.pretty_name)
205 205 @by_lang[lang.pretty_name] = {
206 206 runtime: { avail: false, value: 2**30-1 },
207 207 memory: { avail: false, value: 2**30-1 },
208 208 length: { avail: false, value: 2**30-1 },
209 209 first: { avail: false, value: DateTime.new(3000,1,1) }
210 210 }
211 211 end
212 212
213 213 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
214 214 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
215 215 end
216 216
217 217 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
218 218 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
219 219 end
220 220
221 221 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
222 222 !sub.user.admin?
223 223 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
224 224 end
225 225
226 226 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
227 227 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
228 228 end
229 229 end
230 230
231 231 #process user_id
232 232 @by_lang.each do |lang,prop|
233 233 prop.each do |k,v|
234 234 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
235 235 end
236 236 end
237 237
238 238 #sum into best
239 239 if @by_lang and @by_lang.first
240 240 @best = @by_lang.first[1].clone
241 241 @by_lang.each do |lang,prop|
242 242 if @best[:runtime][:value] >= prop[:runtime][:value]
243 243 @best[:runtime] = prop[:runtime]
244 244 @best[:runtime][:lang] = lang
245 245 end
246 246 if @best[:memory][:value] >= prop[:memory][:value]
247 247 @best[:memory] = prop[:memory]
248 248 @best[:memory][:lang] = lang
249 249 end
250 250 if @best[:length][:value] >= prop[:length][:value]
251 251 @best[:length] = prop[:length]
252 252 @best[:length][:lang] = lang
253 253 end
254 254 if @best[:first][:value] >= prop[:first][:value]
255 255 @best[:first] = prop[:first]
256 256 @best[:first][:lang] = lang
257 257 end
258 258 end
259 259 end
260 260
261 261 @histogram[:summary][:max] = [@histogram[:data].max,1].max
262 262 @summary[:attempt] = user.count
263 263 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
264 264 end
265 265
266 266 def stuck #report struggling user,problem
267 267 # init
268 268 user,problem = nil
269 269 solve = true
270 270 tries = 0
271 271 @struggle = Array.new
272 272 record = {}
273 273 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
274 274 next unless sub.problem and sub.user
275 275 if user != sub.user_id or problem != sub.problem_id
276 276 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
277 277 record = {user: sub.user, problem: sub.problem}
278 278 user,problem = sub.user_id, sub.problem_id
279 279 solve = false
280 280 tries = 0
281 281 end
282 282 if sub.points >= sub.problem.full_score
283 283 solve = true
284 284 else
285 285 tries += 1
286 286 end
287 287 end
288 288 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
289 289 @struggle = @struggle[0..50]
290 290 end
291 291
292 292
293 293 def multiple_login
294 294 #user with multiple IP
295 295 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
296 296 last,count = 0,0
297 297 first = 0
298 298 @users = []
299 299 raw.each do |r|
300 300 if last != r.user.login
301 301 count = 1
302 302 last = r.user.login
303 303 first = r
304 304 else
305 305 @users << first if count == 1
306 306 @users << r
307 307 count += 1
308 308 end
309 309 end
310 310
311 311 #IP with multiple user
312 312 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
313 313 last,count = 0,0
314 314 first = 0
315 315 @ip = []
316 316 raw.each do |r|
317 317 if last != r.ip_address
318 318 count = 1
319 319 last = r.ip_address
320 320 first = r
321 321 else
322 322 @ip << first if count == 1
323 323 @ip << r
324 324 count += 1
325 325 end
326 326 end
327 327 end
328 328
329 329 def cheat_report
330 330 date_and_time = '%Y-%m-%d %H:%M'
331 331 begin
332 332 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
333 333 @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)
334 334 rescue
335 335 @since_time = Time.zone.now.ago( 90.minutes)
336 336 end
337 337 begin
338 338 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
339 339 @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)
340 340 rescue
341 341 @until_time = Time.zone.now
342 342 end
343 343
344 344 #multi login
345 345 @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")
346 346
347 347 st = <<-SQL
348 348 SELECT l2.*
349 349 FROM logins l2 INNER JOIN
350 350 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
351 351 FROM logins l
352 352 INNER JOIN users u ON l.user_id = u.id
353 353 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
354 354 GROUP BY u.id
355 355 HAVING count > 1
356 356 ) ml ON l2.user_id = ml.id
357 357 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
358 358 UNION
359 359 SELECT l2.*
360 360 FROM logins l2 INNER JOIN
361 361 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
362 362 FROM logins l
363 363 INNER JOIN users u ON l.user_id = u.id
364 364 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
365 365 GROUP BY l.ip_address
366 366 HAVING count > 1
367 367 ) ml on ml.ip_address = l2.ip_address
368 368 INNER JOIN users u ON l2.user_id = u.id
369 369 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
370 370 ORDER BY ip_address,created_at
371 371 SQL
372 372 @mld = Login.find_by_sql(st)
373 373
374 374 st = <<-SQL
375 375 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
376 376 FROM submissions s INNER JOIN
377 377 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
378 378 FROM logins l
379 379 INNER JOIN users u ON l.user_id = u.id
380 380 WHERE l.created_at >= ? and l.created_at <= ?
381 381 GROUP BY u.id
382 382 HAVING count > 1
383 383 ) ml ON s.user_id = ml.id
384 384 WHERE s.submitted_at >= ? and s.submitted_at <= ?
385 385 UNION
386 386 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
387 387 FROM submissions s INNER JOIN
388 388 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
389 389 FROM logins l
390 390 INNER JOIN users u ON l.user_id = u.id
391 391 WHERE l.created_at >= ? and l.created_at <= ?
392 392 GROUP BY l.ip_address
393 393 HAVING count > 1
394 394 ) ml on ml.ip_address = s.ip_address
395 395 WHERE s.submitted_at >= ? and s.submitted_at <= ?
396 396 ORDER BY ip_address,submitted_at
397 397 SQL
398 398 @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time,
399 399 @since_time,@until_time,
400 400 @since_time,@until_time,
401 401 @since_time,@until_time])
402 402
403 403 end
404 404
405 405 def cheat_scruntinize
406 406 #convert date & time
407 407 date_and_time = '%Y-%m-%d %H:%M'
408 408 begin
409 409 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
410 410 @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)
411 411 rescue
412 412 @since_time = Time.zone.now.ago( 90.minutes)
413 413 end
414 414 begin
415 415 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
416 416 @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)
417 417 rescue
418 418 @until_time = Time.zone.now
419 419 end
420 420
421 421 #convert sid
422 422 @sid = params[:SID].split(/[,\s]/) if params[:SID]
423 423 unless @sid and @sid.size > 0
424 424 return
425 425 redirect_to actoin: :cheat_scruntinize
426 426 flash[:notice] = 'Please enter at least 1 student id'
427 427 end
428 428 mark = Array.new(@sid.size,'?')
429 429 condition = "(u.login = " + mark.join(' OR u.login = ') + ')'
430 430
431 431 @st = <<-SQL
432 432 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
433 433 FROM logins l INNER JOIN users u on l.user_id = u.id
434 434 WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
435 435 UNION
436 436 SELECT s.submitted_at,s.id,u.login,u.full_name,s.ip_address,s.problem_id,s.points,s.user_id
437 437 FROM submissions s INNER JOIN users u ON s.user_id = u.id
438 438 WHERE s.submitted_at >= ? AND s.submitted_at <= ? AND #{condition}
439 439 ORDER BY submitted_at
440 440 SQL
441 441
442 442 p = [@st,@since_time,@until_time] + @sid + [@since_time,@until_time] + @sid
443 443 @logs = Submission.joins(:problem).find_by_sql(p)
444 444
445 445
446 446
447 447
448 448
449 449 end
450 450
451 451
452 452 end
You need to be logged in to leave comments. Login now