Description:
add download score as csv
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r449:c1892413ee46 - - 2 files changed: 58 inserted, 1 deleted

@@ -1,260 +1,283
1 + require 'csv'
2 +
1 3 class UserAdminController < ApplicationController
2 4
5 +
3 6 include MailHelperMethods
4 7
5 8 before_filter :admin_authorization
6 9
7 10 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
8 11 verify :method => :post, :only => [ :destroy,
9 12 :create, :create_from_list,
10 13 :update,
11 14 :manage_contest,
12 15 :bulk_mail
13 16 ],
14 17 :redirect_to => { :action => :list }
15 18
16 19 def index
17 20 list
18 21 render :action => 'list'
19 22 end
20 23
21 24 def list
22 25 @user_count = User.count
23 26 if params[:page] == 'all'
24 27 @users = User.all
25 28 @paginated = false
26 29 else
27 30 @users = User.paginate :page => params[:page]
28 31 @paginated = true
29 32 end
30 33 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
31 34 @contests = Contest.enabled
32 35 end
33 36
34 37 def active
35 38 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
36 39 @users = []
37 40 sessions.each do |session|
38 41 if session.data[:user_id]
39 42 @users << User.find(session.data[:user_id])
40 43 end
41 44 end
42 45 end
43 46
44 47 def show
45 48 @user = User.find(params[:id])
46 49 end
47 50
48 51 def new
49 52 @user = User.new
50 53 end
51 54
52 55 def create
53 56 @user = User.new(params[:user])
54 57 @user.activated = true
55 58 if @user.save
56 59 flash[:notice] = 'User was successfully created.'
57 60 redirect_to :action => 'list'
58 61 else
59 62 render :action => 'new'
60 63 end
61 64 end
62 65
63 66 def create_from_list
64 67 lines = params[:user_list]
65 68
66 69 note = []
67 70
68 71 lines.split("\n").each do |line|
69 72 items = line.chomp.split(',')
70 73 if items.length>=2
71 74 login = items[0]
72 75 full_name = items[1]
73 76
74 77 added_random_password = false
75 78 if items.length>=3
76 79 password = items[2].chomp(" ")
77 80 user_alias = (items.length>=4) ? items[3] : login
78 81 else
79 82 password = random_password
80 83 user_alias = (items.length>=4) ? items[3] : login
81 84 added_random_password = true
82 85 end
83 86
84 87 user = User.new({:login => login,
85 88 :full_name => full_name,
86 89 :password => password,
87 90 :password_confirmation => password,
88 91 :alias => user_alias})
89 92 user.activated = true
90 93 user.save
91 94
92 95 if added_random_password
93 96 note << "'#{login}' (+)"
94 97 else
95 98 note << login
96 99 end
97 100 end
98 101 end
99 102 flash[:notice] = 'User(s) ' + note.join(', ') +
100 103 ' were successfully created. ' +
101 104 '( (+) - created with random passwords.)'
102 105 redirect_to :action => 'list'
103 106 end
104 107
105 108 def edit
106 109 @user = User.find(params[:id])
107 110 end
108 111
109 112 def update
110 113 @user = User.find(params[:id])
111 114 if @user.update_attributes(params[:user])
112 115 flash[:notice] = 'User was successfully updated.'
113 116 redirect_to :action => 'show', :id => @user
114 117 else
115 118 render :action => 'edit'
116 119 end
117 120 end
118 121
119 122 def destroy
120 123 User.find(params[:id]).destroy
121 124 redirect_to :action => 'list'
122 125 end
123 126
124 127 def user_stat
128 + if params[:commit] == 'download csv'
129 + @problems = Problem.all
130 + else
125 131 @problems = Problem.find_available_problems
132 + end
126 133 @users = User.find(:all, :include => [:contests, :contest_stat])
127 134 @scorearray = Array.new
128 135 @users.each do |u|
129 136 ustat = Array.new
130 137 ustat[0] = u
131 138 @problems.each do |p|
132 139 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
133 140 if (sub!=nil) and (sub.points!=nil)
134 141 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
135 142 else
136 143 ustat << [0,false]
137 144 end
138 145 end
139 146 @scorearray << ustat
140 147 end
148 +
149 + if params[:commit] == 'download csv' then
150 + csv = gen_csv_from_scorearray(@scorearray,@problems)
151 + send_data csv, filename: 'last_score.csv'
152 + else
153 + render template: 'user_admin/user_stat'
154 + end
141 155 end
142 156
143 157 def user_stat_max
158 + if params[:commit] == 'download csv'
159 + @problems = Problem.all
160 + else
144 161 @problems = Problem.find_available_problems
162 + end
145 163 @users = User.find(:all, :include => [:contests, :contest_stat])
146 164 @scorearray = Array.new
147 165 #set up range from param
148 166 since_id = params.fetch(:since_id, 0).to_i
149 167 until_id = params.fetch(:until_id, 0).to_i
150 168 @users.each do |u|
151 169 ustat = Array.new
152 170 ustat[0] = u
153 171 @problems.each do |p|
154 172 max_points = 0
155 173 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
156 174 max_points = sub.points if sub and sub.points and (sub.points > max_points)
157 175 end
158 176 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
159 177 end
160 178 @scorearray << ustat
161 179 end
162 180
181 + if params[:commit] == 'download csv' then
182 + csv = gen_csv_from_scorearray(@scorearray,@problems)
183 + send_data csv, filename: 'max_score.csv'
184 + else
163 185 render template: 'user_admin/user_stat'
164 186 end
187 + end
165 188
166 189 def import
167 190 if params[:file]==''
168 191 flash[:notice] = 'Error importing no file'
169 192 redirect_to :action => 'list' and return
170 193 end
171 194 import_from_file(params[:file])
172 195 end
173 196
174 197 def random_all_passwords
175 198 users = User.find(:all)
176 199 @prefix = params[:prefix] || ''
177 200 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
178 201 @changed = false
179 202 if request.request_method == 'POST'
180 203 @non_admin_users.each do |user|
181 204 password = random_password
182 205 user.password = password
183 206 user.password_confirmation = password
184 207 user.save
185 208 end
186 209 @changed = true
187 210 end
188 211 end
189 212
190 213 # contest management
191 214
192 215 def contests
193 216 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
194 217 @contests = Contest.enabled
195 218 end
196 219
197 220 def assign_from_list
198 221 contest_id = params[:users_contest_id]
199 222 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
200 223 contest = Contest.find(params[:new_contest][:id])
201 224 if !contest
202 225 flash[:notice] = 'Error: no contest'
203 226 redirect_to :action => 'contests', :id =>contest_id
204 227 end
205 228
206 229 note = []
207 230 users.each do |u|
208 231 u.contests = [contest]
209 232 note << u.login
210 233 end
211 234 flash[:notice] = 'User(s) ' + note.join(', ') +
212 235 " were successfully reassigned to #{contest.title}."
213 236 redirect_to :action => 'contests', :id =>contest.id
214 237 end
215 238
216 239 def add_to_contest
217 240 user = User.find(params[:id])
218 241 contest = Contest.find(params[:contest_id])
219 242 if user and contest
220 243 user.contests << contest
221 244 end
222 245 redirect_to :action => 'list'
223 246 end
224 247
225 248 def remove_from_contest
226 249 user = User.find(params[:id])
227 250 contest = Contest.find(params[:contest_id])
228 251 if user and contest
229 252 user.contests.delete(contest)
230 253 end
231 254 redirect_to :action => 'list'
232 255 end
233 256
234 257 def contest_management
235 258 end
236 259
237 260 def manage_contest
238 261 contest = Contest.find(params[:contest][:id])
239 262 if !contest
240 263 flash[:notice] = 'You did not choose the contest.'
241 264 redirect_to :action => 'contest_management' and return
242 265 end
243 266
244 267 operation = params[:operation]
245 268
246 269 if not ['add','remove','assign'].include? operation
247 270 flash[:notice] = 'You did not choose the operation to perform.'
248 271 redirect_to :action => 'contest_management' and return
249 272 end
250 273
251 274 lines = params[:login_list]
252 275 if !lines or lines.blank?
253 276 flash[:notice] = 'You entered an empty list.'
254 277 redirect_to :action => 'contest_management' and return
255 278 end
256 279
257 280 note = []
258 281 users = []
259 282 lines.split("\n").each do |line|
260 283 user = User.find_by_login(line.chomp)
@@ -382,97 +405,128
382 405 country_data = data_hash[:countries]
383 406 site_data = data_hash[:sites]
384 407 user_data = data_hash[:users]
385 408
386 409 # import country
387 410 countries = {}
388 411 country_data.each_pair do |id,country|
389 412 c = Country.find_by_name(country[:name])
390 413 if c!=nil
391 414 countries[id] = c
392 415 @import_log << "Found #{country[:name]}\n"
393 416 else
394 417 countries[id] = Country.new(:name => country[:name])
395 418 countries[id].save
396 419 @import_log << "Created #{country[:name]}\n"
397 420 end
398 421 end
399 422
400 423 # import sites
401 424 sites = {}
402 425 site_data.each_pair do |id,site|
403 426 s = Site.find_by_name(site[:name])
404 427 if s!=nil
405 428 @import_log << "Found #{site[:name]}\n"
406 429 else
407 430 s = Site.new(:name => site[:name])
408 431 @import_log << "Created #{site[:name]}\n"
409 432 end
410 433 s.password = site[:password]
411 434 s.country = countries[site[:country_id]]
412 435 s.save
413 436 sites[id] = s
414 437 end
415 438
416 439 # import users
417 440 user_data.each_pair do |id,user|
418 441 u = User.find_by_login(user[:login])
419 442 if u!=nil
420 443 @import_log << "Found #{user[:login]}\n"
421 444 else
422 445 u = User.new(:login => user[:login])
423 446 @import_log << "Created #{user[:login]}\n"
424 447 end
425 448 u.full_name = user[:name]
426 449 u.password = user[:password]
427 450 u.country = countries[user[:country_id]]
428 451 u.site = sites[user[:site_id]]
429 452 u.activated = true
430 453 u.email = "empty-#{u.login}@none.com"
431 454 if not u.save
432 455 @import_log << "Errors\n"
433 456 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
434 457 end
435 458 end
436 459
437 460 end
438 461
439 462 def logout_users(users)
440 463 users.each do |user|
441 464 contest_stat = user.contest_stat(true)
442 465 if contest_stat and !contest_stat.forced_logout
443 466 contest_stat.forced_logout = true
444 467 contest_stat.save
445 468 end
446 469 end
447 470 end
448 471
449 472 def send_contest_update_notification_email(user, contest)
450 473 contest_title_name = GraderConfiguration['contest.name']
451 474 contest_name = contest.name
452 475 mail_subject = t('contest.notification.email_subject', {
453 476 :contest_title_name => contest_title_name,
454 477 :contest_name => contest_name })
455 478 mail_body = t('contest.notification.email_body', {
456 479 :full_name => user.full_name,
457 480 :contest_title_name => contest_title_name,
458 481 :contest_name => contest.name,
459 482 })
460 483
461 484 logger.info mail_body
462 485 send_mail(user.email, mail_subject, mail_body)
463 486 end
464 487
465 488 def find_contest_and_user_from_contest_id(id)
466 489 if id!='none'
467 490 @contest = Contest.find(id)
468 491 else
469 492 @contest = nil
470 493 end
471 494 if @contest
472 495 @users = @contest.users
473 496 else
474 497 @users = User.find_users_with_no_contest
475 498 end
476 499 return [@contest, @users]
477 500 end
501 +
502 + def gen_csv_from_scorearray(scorearray,problem)
503 + CSV.generate do |csv|
504 + #add header
505 + header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
506 + problem.each { |p| header << p.name }
507 + header += ['Total','Passed']
508 + csv << header
509 + #add data
510 + scorearray.each do |sc|
511 + total = num_passed = 0
512 + row = Array.new
513 + sc.each_index do |i|
514 + if i == 0
515 + row << sc[i].login
516 + row << sc[i].full_name
517 + row << sc[i].activated
518 + row << (sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no')
519 + row << sc[i].contests.collect {|c| c.name}.join(', ')
520 + else
521 + row << sc[i][0]
522 + total += sc[i][0]
523 + num_passed += 1 if sc[i][1]
478 524 end
525 + end
526 + row << total
527 + row << num_passed
528 + csv << row
529 + end
530 + end
531 + end
532 + end
@@ -1,54 +1,57
1 1 - content_for :header do
2 2 = javascript_include_tag 'new'
3 3 = stylesheet_link_tag 'tablesorter-theme.cafe'
4 4
5 5 %script{:type=>"text/javascript"}
6 6 $(function () {
7 7 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 8 $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 9 $('#my_table').tablesorter({widgets: ['zebra']});
10 10 });
11 11
12 12 %h1 User grading results
13 13 %h2= params[:action] == 'user_stat' ? "Show scores from latest submission" : "Show max scores in submission range"
14 14
15 15
16 16 - if @problem and @problem.errors
17 17 =error_messages_for 'problem'
18 18
19 19 = render partial: 'submission_range'
20 20
21 21 - if params[:action] == 'user_stat'
22 - = "latest score"
22 + %h3 Latest score
23 + = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat, commit: 'download csv'
23 24 - else
25 + %h3 Max score
24 26 = link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
27 + = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat_max, commit: 'download csv'
25 28
26 29 %table.tablesorter-cafe#my_table
27 30 %thead
28 31 %tr
29 32 %th User
30 33 %th Name
31 34 %th Activated?
32 35 %th Logged in
33 36 %th Contest(s)
34 37 - @problems.each do |p|
35 38 %th= p.name
36 39 %th Total
37 40 %th Passed
38 41 %tbody
39 42 - @scorearray.each do |sc|
40 43 %tr{class: cycle('info-even','info-odd')}
41 44 - total,num_passed = 0,0
42 45 - sc.each_index do |i|
43 46 - if i == 0
44 47 %td= link_to sc[i].login, controller: 'users', action: 'profile', id: sc[i]
45 48 %td= sc[i].full_name
46 49 %td= sc[i].activated
47 50 %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no'
48 51 %td= sc[i].contests.collect {|c| c.name}.join(', ')
49 52 - else
50 53 %td= sc[i][0]
51 54 - total += sc[i][0]
52 55 - num_passed += 1 if sc[i][1]
53 56 %td= total
54 57 %td= num_passed
You need to be logged in to leave comments. Login now