Description:
- remove inplace editor from view - add link to edit announcement directly - modify submission_short display button
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r598:db36298d10ca - - 4 files changed: 55 inserted, 22 deleted

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