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

r507:5af12f2a9a30 - - 2 files changed: 52 inserted, 20 deleted

@@ -1,99 +1,100
1 1 class ReportController < ApplicationController
2 2
3 - before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck]
3 + before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize]
4 +
4 5 before_filter(only: [:problem_hof]) { |c|
5 6 return false unless authenticate
6 7
7 8 if GraderConfiguration["right.user_view_submission"]
8 9 return true;
9 10 end
10 11
11 12 admin_authorization
12 13 }
13 14
14 15 def login_stat
15 16 @logins = Array.new
16 17
17 18 date_and_time = '%Y-%m-%d %H:%M'
18 19 begin
19 20 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
20 21 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
21 22 rescue
22 23 @since_time = DateTime.new(1000,1,1)
23 24 end
24 25 begin
25 26 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
26 27 @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
27 28 rescue
28 29 @until_time = DateTime.new(3000,1,1)
29 30 end
30 31
31 32 User.all.each do |user|
32 33 @logins << { id: user.id,
33 34 login: user.login,
34 35 full_name: user.full_name,
35 36 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
36 37 user.id,@since_time,@until_time)
37 38 .count(:id),
38 39 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
39 40 user.id,@since_time,@until_time)
40 41 .minimum(:created_at),
41 42 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
42 43 user.id,@since_time,@until_time)
43 44 .maximum(:created_at),
44 45 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
45 46 user.id,@since_time,@until_time)
46 47 .select(:ip_address).uniq
47 48
48 49 }
49 50 end
50 51 end
51 52
52 53 def submission_stat
53 54
54 55 date_and_time = '%Y-%m-%d %H:%M'
55 56 begin
56 57 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
57 58 rescue
58 59 @since_time = DateTime.new(1000,1,1)
59 60 end
60 61 begin
61 62 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
62 63 rescue
63 64 @until_time = DateTime.new(3000,1,1)
64 65 end
65 66
66 67 @submissions = {}
67 68
68 69 User.find_each do |user|
69 70 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
70 71 end
71 72
72 73 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
73 74 if @submissions[s.user_id]
74 75 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
75 76 a = nil
76 77 begin
77 78 a = Problem.find(s.problem_id)
78 79 rescue
79 80 a = nil
80 81 end
81 82 @submissions[s.user_id][:sub][s.problem_id] =
82 83 { prob_name: (a ? a.full_name : '(NULL)'),
83 84 sub_ids: [s.id] }
84 85 else
85 86 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
86 87 end
87 88 @submissions[s.user_id][:count] += 1
88 89 end
89 90 end
90 91 end
91 92
92 93 def problem_hof
93 94 # gen problem list
94 95 @user = User.find(session[:user_id])
95 96 @problems = @user.available_problems
96 97
97 98 # get selected problems or the default
98 99 if params[:id]
99 100 begin
@@ -165,184 +166,214
165 166 if @by_lang and @by_lang.first
166 167 @best = @by_lang.first[1].clone
167 168 @by_lang.each do |lang,prop|
168 169 if @best[:runtime][:value] >= prop[:runtime][:value]
169 170 @best[:runtime] = prop[:runtime]
170 171 @best[:runtime][:lang] = lang
171 172 end
172 173 if @best[:memory][:value] >= prop[:memory][:value]
173 174 @best[:memory] = prop[:memory]
174 175 @best[:memory][:lang] = lang
175 176 end
176 177 if @best[:length][:value] >= prop[:length][:value]
177 178 @best[:length] = prop[:length]
178 179 @best[:length][:lang] = lang
179 180 end
180 181 if @best[:first][:value] >= prop[:first][:value]
181 182 @best[:first] = prop[:first]
182 183 @best[:first][:lang] = lang
183 184 end
184 185 end
185 186 end
186 187
187 188 @histogram[:summary][:max] = [@histogram[:data].max,1].max
188 189 @summary[:attempt] = user.count
189 190 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
190 191 end
191 192
192 193 def stuck #report struggling user,problem
193 194 # init
194 195 user,problem = nil
195 196 solve = true
196 197 tries = 0
197 198 @struggle = Array.new
198 199 record = {}
199 200 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
200 201 next unless sub.problem and sub.user
201 202 if user != sub.user_id or problem != sub.problem_id
202 203 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
203 204 record = {user: sub.user, problem: sub.problem}
204 205 user,problem = sub.user_id, sub.problem_id
205 206 solve = false
206 207 tries = 0
207 208 end
208 209 if sub.points >= sub.problem.full_score
209 210 solve = true
210 211 else
211 212 tries += 1
212 213 end
213 214 end
214 215 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
215 216 @struggle = @struggle[0..50]
216 217 end
217 218
218 219
219 220 def multiple_login
220 221 #user with multiple IP
221 222 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
222 223 last,count = 0,0
223 224 first = 0
224 225 @users = []
225 226 raw.each do |r|
226 227 if last != r.user.login
227 228 count = 1
228 229 last = r.user.login
229 230 first = r
230 231 else
231 232 @users << first if count == 1
232 233 @users << r
233 234 count += 1
234 235 end
235 236 end
236 237
237 238 #IP with multiple user
238 239 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
239 240 last,count = 0,0
240 241 first = 0
241 242 @ip = []
242 243 raw.each do |r|
243 244 if last != r.ip_address
244 245 count = 1
245 246 last = r.ip_address
246 247 first = r
247 248 else
248 249 @ip << first if count == 1
249 250 @ip << r
250 251 count += 1
251 252 end
252 253 end
253 254 end
254 255
255 256 def cheat_report
256 257 date_and_time = '%Y-%m-%d %H:%M'
257 258 begin
258 259 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
259 260 @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)
260 261 rescue
261 - @since_time = Time.zone.now
262 + @since_time = Time.zone.now.ago( 90.minutes)
262 263 end
263 264 begin
264 265 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
265 266 @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)
266 267 rescue
267 - @until_time = Time.zone.now.ago( 90.minutes)
268 + @until_time = Time.zone.now
268 269 end
269 270
270 271 #multi login
271 272 @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")
272 273
273 274 st = <<-SQL
274 275 SELECT l2.*
275 276 FROM logins l2 INNER JOIN
276 277 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
277 278 FROM logins l
278 279 INNER JOIN users u ON l.user_id = u.id
279 280 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
280 281 GROUP BY u.id
281 282 HAVING count > 1
282 283 ) ml ON l2.user_id = ml.id
283 284 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
284 285 UNION
285 286 SELECT l2.*
286 287 FROM logins l2 INNER JOIN
287 288 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
288 289 FROM logins l
289 290 INNER JOIN users u ON l.user_id = u.id
290 291 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
291 292 GROUP BY l.ip_address
292 293 HAVING count > 1
293 294 ) ml on ml.ip_address = l2.ip_address
294 295 INNER JOIN users u ON l2.user_id = u.id
295 296 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
296 297 ORDER BY ip_address,created_at
297 298 SQL
298 299 @mld = Login.find_by_sql(st)
299 300
300 301 st = <<-SQL
301 302 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
302 303 FROM submissions s INNER JOIN
303 304 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
304 305 FROM logins l
305 306 INNER JOIN users u ON l.user_id = u.id
306 307 WHERE l.created_at >= ? and l.created_at <= ?
307 308 GROUP BY u.id
308 309 HAVING count > 1
309 310 ) ml ON s.user_id = ml.id
310 311 WHERE s.submitted_at >= ? and s.submitted_at <= ?
311 312 UNION
312 313 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
313 314 FROM submissions s INNER JOIN
314 315 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
315 316 FROM logins l
316 317 INNER JOIN users u ON l.user_id = u.id
317 318 WHERE l.created_at >= ? and l.created_at <= ?
318 319 GROUP BY l.ip_address
319 320 HAVING count > 1
320 321 ) ml on ml.ip_address = s.ip_address
321 322 WHERE s.submitted_at >= ? and s.submitted_at <= ?
322 323 ORDER BY ip_address,submitted_at
323 324 SQL
324 325 @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time,
325 326 @since_time,@until_time,
326 327 @since_time,@until_time,
327 328 @since_time,@until_time])
328 329
329 - # st =
330 - # " INNER JOIN" +
331 - # "(SELECT u.id,l.ip_address,COUNT(DISTINCT ip_address) as count " +
332 - # " FROM logins l INNER JOIN users u ON l.user_id = u.id "+
333 - # " WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}' " +
334 - # " GROUP BY u.id" +
335 - # " HAVING count > 1) ml "
336 - # #ml detail
337 - # @mld = Login.joins(st + "ON logins.user_id = ml.id").
338 - # where("logins.created_at >= ? and logins.created_at <= ?",@since_time,@until_time).
339 - # order("ip_address")
340 - #
341 - # #submissions
342 - # @subs = Submission.joins(:problem).joins(st + "ON submissions.user_id = ml.id").
343 - # where("submissions.submitted_at >= ? and submissions.submitted_at <= ?",@since_time,@until_time).
344 - # order("submissions.ip_address")
330 + end
331 +
332 + def cheat_scruntinize
333 + #convert date & time
334 + date_and_time = '%Y-%m-%d %H:%M'
335 + begin
336 + md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
337 + @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)
338 + rescue
339 + @since_time = Time.zone.now.ago( 90.minutes)
340 + end
341 + begin
342 + md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
343 + @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)
344 + rescue
345 + @until_time = Time.zone.now
346 + end
347 +
348 + #convert sid
349 + @sid = params[:SID].split(/[,\s]/) if params[:SID]
350 + unless @sid and @sid.size > 0
351 + return
352 + redirect_to actoin: :cheat_scruntinize
353 + flash[:notice] = 'Please enter at least 1 student id'
354 + end
355 + mark = Array.new(@sid.size,'?')
356 + condition = "(u.login = " + mark.join(' OR u.login = ') + ')'
357 +
358 + @st = <<-SQL
359 + 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
360 + FROM logins l INNER JOIN users u on l.user_id = u.id
361 + WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
362 + UNION
363 + SELECT s.submitted_at,s.id,u.login,u.full_name,s.ip_address,s.problem_id,s.points,s.user_id
364 + FROM submissions s INNER JOIN users u ON s.user_id = u.id
365 + WHERE s.submitted_at >= ? AND s.submitted_at <= ? AND #{condition}
366 + ORDER BY submitted_at
367 + SQL
368 +
369 + p = [@st,@since_time,@until_time] + @sid + [@since_time,@until_time] + @sid
370 + @logs = Submission.joins(:problem).find_by_sql(p)
371 +
372 +
373 +
374 +
375 +
345 376 end
346 377
347 378
348 379 end
@@ -1,8 +1,9
1 1
2 2 .task-menu
3 3 Reports
4 4 %br/
5 5 = link_to '[Hall of Fame]', :action => 'problem_hof'
6 6 = link_to '[Struggle]', :action => 'stuck'
7 - = link_to '[Login]', :action => 'login_stat'
7 + = link_to '[Cheat Detection]', :action => 'cheat_report'
8 + = link_to '[Cheat Detail]', :action => 'cheat_scruntinize'
8 9 = link_to '[Multiple Login]', :action => 'multiple_login'
You need to be logged in to leave comments. Login now