Description:
update new list of users
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r808:8690f354dd15 - - 5 files changed: 111 inserted, 83 deleted

@@ -0,0 +1,5
1 + class AddIndexToTaskStatus < ActiveRecord::Migration[5.2]
2 + def change
3 + add_index :tasks, :status
4 + end
5 + end
@@ -1,236 +1,167
1 require 'csv'
1 require 'csv'
2
2
3 class UserAdminController < ApplicationController
3 class UserAdminController < ApplicationController
4
4
5 include MailHelperMethods
5 include MailHelperMethods
6
6
7 before_action :admin_authorization
7 before_action :admin_authorization
8
8
9 def index
9 def index
10 @user_count = User.count
10 @user_count = User.count
11 @users = User.all
11 @users = User.all
12 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
12 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
13 @contests = Contest.enabled
13 @contests = Contest.enabled
14 end
14 end
15
15
16 def active
16 def active
17 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
17 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
18 @users = []
18 @users = []
19 sessions.each do |session|
19 sessions.each do |session|
20 if session.data[:user_id]
20 if session.data[:user_id]
21 @users << User.find(session.data[:user_id])
21 @users << User.find(session.data[:user_id])
22 end
22 end
23 end
23 end
24 end
24 end
25
25
26 def show
26 def show
27 @user = User.find(params[:id])
27 @user = User.find(params[:id])
28 end
28 end
29
29
30 def new
30 def new
31 @user = User.new
31 @user = User.new
32 end
32 end
33
33
34 def create
34 def create
35 @user = User.new(user_params)
35 @user = User.new(user_params)
36 @user.activated = true
36 @user.activated = true
37 if @user.save
37 if @user.save
38 flash[:notice] = 'User was successfully created.'
38 flash[:notice] = 'User was successfully created.'
39 redirect_to :action => 'index'
39 redirect_to :action => 'index'
40 else
40 else
41 render :action => 'new'
41 render :action => 'new'
42 end
42 end
43 end
43 end
44
44
45 def clear_last_ip
45 def clear_last_ip
46 @user = User.find(params[:id])
46 @user = User.find(params[:id])
47 @user.last_ip = nil
47 @user.last_ip = nil
48 @user.save
48 @user.save
49 redirect_to action: 'index', page: params[:page]
49 redirect_to action: 'index', page: params[:page]
50 end
50 end
51
51
52 def create_from_list
52 def create_from_list
53 lines = params[:user_list]
53 lines = params[:user_list]
54
54
55 - note = []
56 - error_note = []
57 - error_msg = nil
58 - ok_user = []
59 -
60 - lines.split("\n").each do |line|
61 - #split with large limit, this will cause consecutive ',' to be result in a blank
62 - items = line.chomp.split(',',1000)
63 - if items.length>=2
64 - login = items[0]
65 - full_name = items[1]
66 - remark =''
67 - user_alias = ''
68 -
69 - added_random_password = false
70 - added_password = false
71 - if items.length >= 3
72 - if items[2].chomp(" ").length > 0
73 - password = items[2].chomp(" ")
74 - added_password = true
75 - end
76 - else
77 - password = random_password
78 - added_random_password=true;
79 - end
80 -
81 - if items.length>= 4 and items[3].chomp(" ").length > 0;
82 - user_alias = items[3].chomp(" ")
83 - else
84 - user_alias = login
85 - end
86 -
87
55
88 - has_remark = false
56 + res = User.create_from_list(lines)
89 - if items.length>=5
57 + error_logins = res[:error_logins]
90 - remark = items[4].strip;
58 + error_msg = res[:first_error]
91 - has_remark = true
59 + ok_user = res[:created_users]
92 - end
93
60
94 - user = User.find_by_login(login)
95 - if (user)
96 - user.full_name = full_name
97 - user.remark = remark if has_remark
98 - user.password = password if added_password || added_random_password
99 - else
100 - #create a random password if none are given
101 - password = random_password unless password
102 - user = User.new({:login => login,
103 - :full_name => full_name,
104 - :password => password,
105 - :password_confirmation => password,
106 - :alias => user_alias,
107 - :remark => remark})
108 - end
109 - user.activated = true
110 -
111 - if user.save
112 - if added_random_password
113 - note << "'#{login}' (+)"
114 - else
115 - note << login
116 - end
117 - ok_user << user
118 - else
119 - error_note << "'#{login}'"
120 - error_msg = user.errors.full_messages.to_sentence unless error_msg
121 - end
122 -
123 - end
124 - end
125
61
126 #add to group
62 #add to group
127 if params[:add_to_group]
63 if params[:add_to_group]
128 - group = Group.where(id: params[:group_id]).first
64 + group = Group.find_by(id: params[:group_id])&.add_users_skip_existing(ok_user)
129 - if group
130 - group.users << ok_user
131 - end
132 end
65 end
133
66
134 # show flash
67 # show flash
135 - if note.size > 0
68 + if ok_user.count > 0
136 - flash[:success] = 'User(s) ' + note.join(', ') +
69 + flash[:success] = "#{ok_user.count} user(s) was created or updated successfully"
137 - ' were successfully created. ' +
138 - '( (+) - created with random passwords.)'
139 end
70 end
140 - if error_note.size > 0
71 + if error_logins.size > 0
141 flash[:error] = "Following user(s) failed to be created: " + error_note.join(', ') + ". The error of the first failed one are: " + error_msg;
72 flash[:error] = "Following user(s) failed to be created: " + error_note.join(', ') + ". The error of the first failed one are: " + error_msg;
142 end
73 end
143 redirect_to :action => 'index'
74 redirect_to :action => 'index'
144 end
75 end
145
76
146 def edit
77 def edit
147 @user = User.find(params[:id])
78 @user = User.find(params[:id])
148 end
79 end
149
80
150 def update
81 def update
151 @user = User.find(params[:id])
82 @user = User.find(params[:id])
152 if @user.update_attributes(user_params)
83 if @user.update_attributes(user_params)
153 flash[:notice] = 'User was successfully updated.'
84 flash[:notice] = 'User was successfully updated.'
154 redirect_to :action => 'show', :id => @user
85 redirect_to :action => 'show', :id => @user
155 else
86 else
156 render :action => 'edit'
87 render :action => 'edit'
157 end
88 end
158 end
89 end
159
90
160 def destroy
91 def destroy
161 User.find(params[:id]).destroy
92 User.find(params[:id]).destroy
162 redirect_to :action => 'index'
93 redirect_to :action => 'index'
163 end
94 end
164
95
165 def user_stat
96 def user_stat
166 if params[:commit] == 'download csv'
97 if params[:commit] == 'download csv'
167 @problems = Problem.all
98 @problems = Problem.all
168 else
99 else
169 @problems = Problem.available_problems
100 @problems = Problem.available_problems
170 end
101 end
171 @users = User.includes(:contests, :contest_stat).where(enabled: true)
102 @users = User.includes(:contests, :contest_stat).where(enabled: true)
172 @scorearray = Array.new
103 @scorearray = Array.new
173 @users.each do |u|
104 @users.each do |u|
174 ustat = Array.new
105 ustat = Array.new
175 ustat[0] = u
106 ustat[0] = u
176 @problems.each do |p|
107 @problems.each do |p|
177 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
108 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
178 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
109 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
179 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
110 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
180 else
111 else
181 ustat << [0,false]
112 ustat << [0,false]
182 end
113 end
183 end
114 end
184 @scorearray << ustat
115 @scorearray << ustat
185 end
116 end
186 if params[:commit] == 'download csv' then
117 if params[:commit] == 'download csv' then
187 csv = gen_csv_from_scorearray(@scorearray,@problems)
118 csv = gen_csv_from_scorearray(@scorearray,@problems)
188 send_data csv, filename: 'last_score.csv'
119 send_data csv, filename: 'last_score.csv'
189 else
120 else
190 render template: 'user_admin/user_stat'
121 render template: 'user_admin/user_stat'
191 end
122 end
192 end
123 end
193
124
194 def user_stat_max
125 def user_stat_max
195 if params[:commit] == 'download csv'
126 if params[:commit] == 'download csv'
196 @problems = Problem.all
127 @problems = Problem.all
197 else
128 else
198 @problems = Problem.available_problems
129 @problems = Problem.available_problems
199 end
130 end
200 @users = User.includes(:contests).includes(:contest_stat).all
131 @users = User.includes(:contests).includes(:contest_stat).all
201 @scorearray = Array.new
132 @scorearray = Array.new
202 #set up range from param
133 #set up range from param
203 since_id = params.fetch(:since_id, 0).to_i
134 since_id = params.fetch(:since_id, 0).to_i
204 until_id = params.fetch(:until_id, 0).to_i
135 until_id = params.fetch(:until_id, 0).to_i
205 @users.each do |u|
136 @users.each do |u|
206 ustat = Array.new
137 ustat = Array.new
207 ustat[0] = u
138 ustat[0] = u
208 @problems.each do |p|
139 @problems.each do |p|
209 max_points = 0
140 max_points = 0
210 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
141 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
211 max_points = sub.points if sub and sub.points and (sub.points > max_points)
142 max_points = sub.points if sub and sub.points and (sub.points > max_points)
212 end
143 end
213 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
144 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
214 end
145 end
215 @scorearray << ustat
146 @scorearray << ustat
216 end
147 end
217
148
218 if params[:commit] == 'download csv' then
149 if params[:commit] == 'download csv' then
219 csv = gen_csv_from_scorearray(@scorearray,@problems)
150 csv = gen_csv_from_scorearray(@scorearray,@problems)
220 send_data csv, filename: 'max_score.csv'
151 send_data csv, filename: 'max_score.csv'
221 else
152 else
222 render template: 'user_admin/user_stat'
153 render template: 'user_admin/user_stat'
223 end
154 end
224 end
155 end
225
156
226 def import
157 def import
227 if params[:file]==''
158 if params[:file]==''
228 flash[:notice] = 'Error importing no file'
159 flash[:notice] = 'Error importing no file'
229 redirect_to :action => 'index' and return
160 redirect_to :action => 'index' and return
230 end
161 end
231 import_from_file(params[:file])
162 import_from_file(params[:file])
232 end
163 end
233
164
234 def random_all_passwords
165 def random_all_passwords
235 users = User.all
166 users = User.all
236 @prefix = params[:prefix] || ''
167 @prefix = params[:prefix] || ''
@@ -334,194 +265,199
334 user.contest_stat.reset_timer_and_save
265 user.contest_stat.reset_timer_and_save
335 end
266 end
336
267
337 if params[:notification_emails]
268 if params[:notification_emails]
338 send_contest_update_notification_email(user, contest)
269 send_contest_update_notification_email(user, contest)
339 end
270 end
340
271
341 note << user.login
272 note << user.login
342 users << user
273 users << user
343 end
274 end
344 end
275 end
345
276
346 if params[:reset_timer]
277 if params[:reset_timer]
347 logout_users(users)
278 logout_users(users)
348 end
279 end
349
280
350 flash[:notice] = 'User(s) ' + note.join(', ') +
281 flash[:notice] = 'User(s) ' + note.join(', ') +
351 ' were successfully modified. '
282 ' were successfully modified. '
352 redirect_to :action => 'contest_management'
283 redirect_to :action => 'contest_management'
353 end
284 end
354
285
355 # admin management
286 # admin management
356
287
357 def admin
288 def admin
358 @admins = Role.where(name: 'admin').take.users
289 @admins = Role.where(name: 'admin').take.users
359 @tas = Role.where(name: 'ta').take.users
290 @tas = Role.where(name: 'ta').take.users
360 end
291 end
361
292
362 def modify_role
293 def modify_role
363 user = User.find_by_login(params[:login])
294 user = User.find_by_login(params[:login])
364 role = Role.find_by_name(params[:role])
295 role = Role.find_by_name(params[:role])
365 unless user && role
296 unless user && role
366 flash[:error] = 'Unknown user or role'
297 flash[:error] = 'Unknown user or role'
367 redirect_to admin_user_admin_index_path
298 redirect_to admin_user_admin_index_path
368 return
299 return
369 end
300 end
370 if params[:commit] == 'Grant'
301 if params[:commit] == 'Grant'
371 #grant role
302 #grant role
372 user.roles << role
303 user.roles << role
373 flash[:notice] = "User '#{user.login}' has been granted the role '#{role.name}'"
304 flash[:notice] = "User '#{user.login}' has been granted the role '#{role.name}'"
374 else
305 else
375 #revoke role
306 #revoke role
376 if user.login == 'root' && role.name == 'admin'
307 if user.login == 'root' && role.name == 'admin'
377 flash[:error] = 'You cannot revoke admisnistrator permission from root.'
308 flash[:error] = 'You cannot revoke admisnistrator permission from root.'
378 redirect_to admin_user_admin_index_path
309 redirect_to admin_user_admin_index_path
379 return
310 return
380 end
311 end
381 user.roles.delete(role)
312 user.roles.delete(role)
382 flash[:notice] = "The role '#{role.name}' has been revoked from User '#{user.login}'"
313 flash[:notice] = "The role '#{role.name}' has been revoked from User '#{user.login}'"
383 end
314 end
384 redirect_to admin_user_admin_index_path
315 redirect_to admin_user_admin_index_path
385 end
316 end
386
317
387 # mass mailing
318 # mass mailing
388
319
389 def mass_mailing
320 def mass_mailing
390 end
321 end
391
322
392 def bulk_mail
323 def bulk_mail
393 lines = params[:login_list]
324 lines = params[:login_list]
394 if !lines or lines.blank?
325 if !lines or lines.blank?
395 flash[:notice] = 'You entered an empty list.'
326 flash[:notice] = 'You entered an empty list.'
396 redirect_to :action => 'mass_mailing' and return
327 redirect_to :action => 'mass_mailing' and return
397 end
328 end
398
329
399 mail_subject = params[:subject]
330 mail_subject = params[:subject]
400 if !mail_subject or mail_subject.blank?
331 if !mail_subject or mail_subject.blank?
401 flash[:notice] = 'You entered an empty mail subject.'
332 flash[:notice] = 'You entered an empty mail subject.'
402 redirect_to :action => 'mass_mailing' and return
333 redirect_to :action => 'mass_mailing' and return
403 end
334 end
404
335
405 mail_body = params[:email_body]
336 mail_body = params[:email_body]
406 if !mail_body or mail_body.blank?
337 if !mail_body or mail_body.blank?
407 flash[:notice] = 'You entered an empty mail body.'
338 flash[:notice] = 'You entered an empty mail body.'
408 redirect_to :action => 'mass_mailing' and return
339 redirect_to :action => 'mass_mailing' and return
409 end
340 end
410
341
411 note = []
342 note = []
412 users = []
343 users = []
413 lines.split("\n").each do |line|
344 lines.split("\n").each do |line|
414 user = User.find_by_login(line.chomp)
345 user = User.find_by_login(line.chomp)
415 if user
346 if user
416 send_mail(user.email, mail_subject, mail_body)
347 send_mail(user.email, mail_subject, mail_body)
417 note << user.login
348 note << user.login
418 end
349 end
419 end
350 end
420
351
421 flash[:notice] = 'User(s) ' + note.join(', ') +
352 flash[:notice] = 'User(s) ' + note.join(', ') +
422 ' were successfully modified. '
353 ' were successfully modified. '
423 redirect_to :action => 'mass_mailing'
354 redirect_to :action => 'mass_mailing'
424 end
355 end
425
356
426 #bulk manage
357 #bulk manage
427 def bulk_manage
358 def bulk_manage
428
359
429 begin
360 begin
430 - @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
361 + if params[:filter_group]
431 - @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
362 + @users = Group.find_by(id: params[:filter_group_id]).users
363 + else
364 + @users = User.all
365 + end
366 + @users = @users.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) unless params[:regex].blank?
367 + @users.count if @users #test the sql
432 rescue Exception
368 rescue Exception
433 flash[:error] = 'Regular Expression is malformed'
369 flash[:error] = 'Regular Expression is malformed'
434 @users = nil
370 @users = nil
435 end
371 end
436
372
437 if params[:commit]
373 if params[:commit]
438 @action = {}
374 @action = {}
439 @action[:set_enable] = params[:enabled]
375 @action[:set_enable] = params[:enabled]
440 @action[:enabled] = params[:enable] == "1"
376 @action[:enabled] = params[:enable] == "1"
441 @action[:gen_password] = params[:gen_password]
377 @action[:gen_password] = params[:gen_password]
442 @action[:add_group] = params[:add_group]
378 @action[:add_group] = params[:add_group]
443 @action[:group_name] = params[:group_name]
379 @action[:group_name] = params[:group_name]
444 end
380 end
445
381
446 if params[:commit] == "Perform"
382 if params[:commit] == "Perform"
447 if @action[:set_enable]
383 if @action[:set_enable]
448 @users.update_all(enabled: @action[:enabled])
384 @users.update_all(enabled: @action[:enabled])
449 end
385 end
450 if @action[:gen_password]
386 if @action[:gen_password]
451 @users.each do |u|
387 @users.each do |u|
452 password = random_password
388 password = random_password
453 u.password = password
389 u.password = password
454 u.password_confirmation = password
390 u.password_confirmation = password
455 u.save
391 u.save
456 end
392 end
457 end
393 end
458 if @action[:add_group] and @action[:group_name]
394 if @action[:add_group] and @action[:group_name]
459 @group = Group.find(@action[:group_name])
395 @group = Group.find(@action[:group_name])
460 ok = []
396 ok = []
461 failed = []
397 failed = []
462 @users.each do |user|
398 @users.each do |user|
463 begin
399 begin
464 @group.users << user
400 @group.users << user
465 ok << user.login
401 ok << user.login
466 rescue => e
402 rescue => e
467 failed << user.login
403 failed << user.login
468 end
404 end
469 end
405 end
470 flash[:success] = "The following users are added to the 'group #{@group.name}': " + ok.join(', ') if ok.count > 0
406 flash[:success] = "The following users are added to the 'group #{@group.name}': " + ok.join(', ') if ok.count > 0
471 flash[:alert] = "The following users are already in the 'group #{@group.name}': " + failed.join(', ') if failed.count > 0
407 flash[:alert] = "The following users are already in the 'group #{@group.name}': " + failed.join(', ') if failed.count > 0
472 end
408 end
473 end
409 end
474 end
410 end
475
411
476 protected
412 protected
477
413
478 def random_password(length=5)
414 def random_password(length=5)
479 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
415 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
480 newpass = ""
416 newpass = ""
481 length.times { newpass << chars[rand(chars.size-1)] }
417 length.times { newpass << chars[rand(chars.size-1)] }
482 return newpass
418 return newpass
483 end
419 end
484
420
485 def import_from_file(f)
421 def import_from_file(f)
486 data_hash = YAML.load(f)
422 data_hash = YAML.load(f)
487 @import_log = ""
423 @import_log = ""
488
424
489 country_data = data_hash[:countries]
425 country_data = data_hash[:countries]
490 site_data = data_hash[:sites]
426 site_data = data_hash[:sites]
491 user_data = data_hash[:users]
427 user_data = data_hash[:users]
492
428
493 # import country
429 # import country
494 countries = {}
430 countries = {}
495 country_data.each_pair do |id,country|
431 country_data.each_pair do |id,country|
496 c = Country.find_by_name(country[:name])
432 c = Country.find_by_name(country[:name])
497 if c!=nil
433 if c!=nil
498 countries[id] = c
434 countries[id] = c
499 @import_log << "Found #{country[:name]}\n"
435 @import_log << "Found #{country[:name]}\n"
500 else
436 else
501 countries[id] = Country.new(:name => country[:name])
437 countries[id] = Country.new(:name => country[:name])
502 countries[id].save
438 countries[id].save
503 @import_log << "Created #{country[:name]}\n"
439 @import_log << "Created #{country[:name]}\n"
504 end
440 end
505 end
441 end
506
442
507 # import sites
443 # import sites
508 sites = {}
444 sites = {}
509 site_data.each_pair do |id,site|
445 site_data.each_pair do |id,site|
510 s = Site.find_by_name(site[:name])
446 s = Site.find_by_name(site[:name])
511 if s!=nil
447 if s!=nil
512 @import_log << "Found #{site[:name]}\n"
448 @import_log << "Found #{site[:name]}\n"
513 else
449 else
514 s = Site.new(:name => site[:name])
450 s = Site.new(:name => site[:name])
515 @import_log << "Created #{site[:name]}\n"
451 @import_log << "Created #{site[:name]}\n"
516 end
452 end
517 s.password = site[:password]
453 s.password = site[:password]
518 s.country = countries[site[:country_id]]
454 s.country = countries[site[:country_id]]
519 s.save
455 s.save
520 sites[id] = s
456 sites[id] = s
521 end
457 end
522
458
523 # import users
459 # import users
524 user_data.each_pair do |id,user|
460 user_data.each_pair do |id,user|
525 u = User.find_by_login(user[:login])
461 u = User.find_by_login(user[:login])
526 if u!=nil
462 if u!=nil
527 @import_log << "Found #{user[:login]}\n"
463 @import_log << "Found #{user[:login]}\n"
@@ -1,13 +1,20
1 class Group < ActiveRecord::Base
1 class Group < ActiveRecord::Base
2 has_many :groups_problems, class_name: 'GroupProblem'
2 has_many :groups_problems, class_name: 'GroupProblem'
3 has_many :problems, :through => :groups_problems
3 has_many :problems, :through => :groups_problems
4
4
5 has_many :groups_users, class_name: 'GroupUser'
5 has_many :groups_users, class_name: 'GroupUser'
6 has_many :users, :through => :groups_users
6 has_many :users, :through => :groups_users
7
7
8 #has_and_belongs_to_many :problems
8 #has_and_belongs_to_many :problems
9 #has_and_belongs_to_many :users
9 #has_and_belongs_to_many :users
10
10
11 + def add_users_skip_existing(users_list)
12 + new_list = []
13 + users_list.each do |u|
14 + new_list << u unless users.include? u
15 + end
16 + users << new_list
17 + end
11
18
12 end
19 end
13
20
@@ -43,341 +43,415
43
43
44 validates_presence_of :password, :if => :password_required?
44 validates_presence_of :password, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
47
47
48 validates_format_of :email,
48 validates_format_of :email,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
50 :if => :email_validation?
50 :if => :email_validation?
51 validate :uniqueness_of_email_from_activated_users,
51 validate :uniqueness_of_email_from_activated_users,
52 :if => :email_validation?
52 :if => :email_validation?
53 validate :enough_time_interval_between_same_email_registrations,
53 validate :enough_time_interval_between_same_email_registrations,
54 :if => :email_validation?
54 :if => :email_validation?
55
55
56 # these are for ytopc
56 # these are for ytopc
57 # disable for now
57 # disable for now
58 #validates_presence_of :province
58 #validates_presence_of :province
59
59
60 attr_accessor :password
60 attr_accessor :password
61
61
62 before_save :encrypt_new_password
62 before_save :encrypt_new_password
63 before_save :assign_default_site
63 before_save :assign_default_site
64 before_save :assign_default_contest
64 before_save :assign_default_contest
65
65
66 # this is for will_paginate
66 # this is for will_paginate
67 cattr_reader :per_page
67 cattr_reader :per_page
68 @@per_page = 50
68 @@per_page = 50
69
69
70 def self.authenticate(login, password)
70 def self.authenticate(login, password)
71 user = find_by_login(login)
71 user = find_by_login(login)
72 if user
72 if user
73 return user if user.authenticated?(password)
73 return user if user.authenticated?(password)
74 end
74 end
75 end
75 end
76
76
77 def authenticated?(password)
77 def authenticated?(password)
78 if self.activated
78 if self.activated
79 hashed_password == User.encrypt(password,self.salt)
79 hashed_password == User.encrypt(password,self.salt)
80 else
80 else
81 false
81 false
82 end
82 end
83 end
83 end
84
84
85 def admin?
85 def admin?
86 has_role?('admin')
86 has_role?('admin')
87 end
87 end
88
88
89 def has_role?(role)
89 def has_role?(role)
90 self.roles.where(name: role).count > 0
90 self.roles.where(name: role).count > 0
91 end
91 end
92
92
93 def email_for_editing
93 def email_for_editing
94 if self.email==nil
94 if self.email==nil
95 "(unknown)"
95 "(unknown)"
96 elsif self.email==''
96 elsif self.email==''
97 "(blank)"
97 "(blank)"
98 else
98 else
99 self.email
99 self.email
100 end
100 end
101 end
101 end
102
102
103 def email_for_editing=(e)
103 def email_for_editing=(e)
104 self.email=e
104 self.email=e
105 end
105 end
106
106
107 def alias_for_editing
107 def alias_for_editing
108 if self.alias==nil
108 if self.alias==nil
109 "(unknown)"
109 "(unknown)"
110 elsif self.alias==''
110 elsif self.alias==''
111 "(blank)"
111 "(blank)"
112 else
112 else
113 self.alias
113 self.alias
114 end
114 end
115 end
115 end
116
116
117 def alias_for_editing=(e)
117 def alias_for_editing=(e)
118 self.alias=e
118 self.alias=e
119 end
119 end
120
120
121 def activation_key
121 def activation_key
122 if self.hashed_password==nil
122 if self.hashed_password==nil
123 encrypt_new_password
123 encrypt_new_password
124 end
124 end
125 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
125 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
126 end
126 end
127
127
128 def verify_activation_key(key)
128 def verify_activation_key(key)
129 key == activation_key
129 key == activation_key
130 end
130 end
131
131
132 def self.random_password(length=5)
132 def self.random_password(length=5)
133 chars = 'abcdefghjkmnopqrstuvwxyz'
133 chars = 'abcdefghjkmnopqrstuvwxyz'
134 password = ''
134 password = ''
135 length.times { password << chars[rand(chars.length - 1)] }
135 length.times { password << chars[rand(chars.length - 1)] }
136 password
136 password
137 end
137 end
138
138
139 - def self.find_non_admin_with_prefix(prefix='')
140 - users = User.all
141 - return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
142 - end
143
139
144 # Contest information
140 # Contest information
145
141
146 def self.find_users_with_no_contest()
142 def self.find_users_with_no_contest()
147 users = User.all
143 users = User.all
148 return users.find_all { |u| u.contests.length == 0 }
144 return users.find_all { |u| u.contests.length == 0 }
149 end
145 end
150
146
151
147
152 def contest_time_left
148 def contest_time_left
153 if GraderConfiguration.contest_mode?
149 if GraderConfiguration.contest_mode?
154 return nil if site==nil
150 return nil if site==nil
155 return site.time_left
151 return site.time_left
156 elsif GraderConfiguration.indv_contest_mode?
152 elsif GraderConfiguration.indv_contest_mode?
157 time_limit = GraderConfiguration.contest_time_limit
153 time_limit = GraderConfiguration.contest_time_limit
158 if time_limit == nil
154 if time_limit == nil
159 return nil
155 return nil
160 end
156 end
161 if contest_stat==nil or contest_stat.started_at==nil
157 if contest_stat==nil or contest_stat.started_at==nil
162 return (Time.now.gmtime + time_limit) - Time.now.gmtime
158 return (Time.now.gmtime + time_limit) - Time.now.gmtime
163 else
159 else
164 finish_time = contest_stat.started_at + time_limit
160 finish_time = contest_stat.started_at + time_limit
165 current_time = Time.now.gmtime
161 current_time = Time.now.gmtime
166 if current_time > finish_time
162 if current_time > finish_time
167 return 0
163 return 0
168 else
164 else
169 return finish_time - current_time
165 return finish_time - current_time
170 end
166 end
171 end
167 end
172 else
168 else
173 return nil
169 return nil
174 end
170 end
175 end
171 end
176
172
177 def contest_finished?
173 def contest_finished?
178 if GraderConfiguration.contest_mode?
174 if GraderConfiguration.contest_mode?
179 return false if site==nil
175 return false if site==nil
180 return site.finished?
176 return site.finished?
181 elsif GraderConfiguration.indv_contest_mode?
177 elsif GraderConfiguration.indv_contest_mode?
182 return false if self.contest_stat==nil
178 return false if self.contest_stat==nil
183 return contest_time_left == 0
179 return contest_time_left == 0
184 else
180 else
185 return false
181 return false
186 end
182 end
187 end
183 end
188
184
189 def contest_started?
185 def contest_started?
190 if GraderConfiguration.indv_contest_mode?
186 if GraderConfiguration.indv_contest_mode?
191 stat = self.contest_stat
187 stat = self.contest_stat
192 return ((stat != nil) and (stat.started_at != nil))
188 return ((stat != nil) and (stat.started_at != nil))
193 elsif GraderConfiguration.contest_mode?
189 elsif GraderConfiguration.contest_mode?
194 return true if site==nil
190 return true if site==nil
195 return site.started
191 return site.started
196 else
192 else
197 return true
193 return true
198 end
194 end
199 end
195 end
200
196
201 def update_start_time
197 def update_start_time
202 stat = self.contest_stat
198 stat = self.contest_stat
203 if stat.nil? or stat.started_at.nil?
199 if stat.nil? or stat.started_at.nil?
204 stat ||= UserContestStat.new(:user => self)
200 stat ||= UserContestStat.new(:user => self)
205 stat.started_at = Time.now.gmtime
201 stat.started_at = Time.now.gmtime
206 stat.save
202 stat.save
207 end
203 end
208 end
204 end
209
205
210 def problem_in_user_contests?(problem)
206 def problem_in_user_contests?(problem)
211 problem_contests = problem.contests.all
207 problem_contests = problem.contests.all
212
208
213 if problem_contests.length == 0 # this is public contest
209 if problem_contests.length == 0 # this is public contest
214 return true
210 return true
215 end
211 end
216
212
217 contests.each do |contest|
213 contests.each do |contest|
218 if problem_contests.find {|c| c.id == contest.id }
214 if problem_contests.find {|c| c.id == contest.id }
219 return true
215 return true
220 end
216 end
221 end
217 end
222 return false
218 return false
223 end
219 end
224
220
225 def available_problems_group_by_contests
221 def available_problems_group_by_contests
226 contest_problems = []
222 contest_problems = []
227 pin = {}
223 pin = {}
228 contests.enabled.each do |contest|
224 contests.enabled.each do |contest|
229 available_problems = contest.problems.available
225 available_problems = contest.problems.available
230 contest_problems << {
226 contest_problems << {
231 :contest => contest,
227 :contest => contest,
232 :problems => available_problems
228 :problems => available_problems
233 }
229 }
234 available_problems.each {|p| pin[p.id] = true}
230 available_problems.each {|p| pin[p.id] = true}
235 end
231 end
236 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
232 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
237 contest_problems << {
233 contest_problems << {
238 :contest => nil,
234 :contest => nil,
239 :problems => other_avaiable_problems
235 :problems => other_avaiable_problems
240 }
236 }
241 return contest_problems
237 return contest_problems
242 end
238 end
243
239
244 def solve_all_available_problems?
240 def solve_all_available_problems?
245 available_problems.each do |p|
241 available_problems.each do |p|
246 u = self
242 u = self
247 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
243 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
248 return false if !p or !sub or sub.points < p.full_score
244 return false if !p or !sub or sub.points < p.full_score
249 end
245 end
250 return true
246 return true
251 end
247 end
252
248
253 #get a list of available problem
249 #get a list of available problem
254 def available_problems
250 def available_problems
255 # first, we check if this is normal mode
251 # first, we check if this is normal mode
256 if not GraderConfiguration.multicontests?
252 if not GraderConfiguration.multicontests?
257
253
258 #if this is a normal mode
254 #if this is a normal mode
259 #we show problem based on problem_group, if the config said so
255 #we show problem based on problem_group, if the config said so
260 if GraderConfiguration.use_problem_group?
256 if GraderConfiguration.use_problem_group?
261 return available_problems_in_group
257 return available_problems_in_group
262 else
258 else
263 return Problem.available_problems
259 return Problem.available_problems
264 end
260 end
265 else
261 else
266 #this is multi contest mode
262 #this is multi contest mode
267 contest_problems = []
263 contest_problems = []
268 pin = {}
264 pin = {}
269 contests.enabled.each do |contest|
265 contests.enabled.each do |contest|
270 contest.problems.available.each do |problem|
266 contest.problems.available.each do |problem|
271 if not pin.has_key? problem.id
267 if not pin.has_key? problem.id
272 contest_problems << problem
268 contest_problems << problem
273 end
269 end
274 pin[problem.id] = true
270 pin[problem.id] = true
275 end
271 end
276 end
272 end
277 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
273 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
278 return contest_problems + other_avaiable_problems
274 return contest_problems + other_avaiable_problems
279 end
275 end
280 end
276 end
281
277
282 # new feature, get list of available problem in all enabled group that the user belongs to
278 # new feature, get list of available problem in all enabled group that the user belongs to
283 def available_problems_in_group
279 def available_problems_in_group
284 problem = []
280 problem = []
285 self.groups.where(enabled: true).each do |group|
281 self.groups.where(enabled: true).each do |group|
286 group.problems.where(available: true).each { |p| problem << p }
282 group.problems.where(available: true).each { |p| problem << p }
287 end
283 end
288 problem.uniq!
284 problem.uniq!
289 if problem
285 if problem
290 problem.sort! do |a,b|
286 problem.sort! do |a,b|
291 case
287 case
292 when a.date_added < b.date_added
288 when a.date_added < b.date_added
293 1
289 1
294 when a.date_added > b.date_added
290 when a.date_added > b.date_added
295 -1
291 -1
296 else
292 else
297 a.name <=> b.name
293 a.name <=> b.name
298 end
294 end
299 end
295 end
300 return problem
296 return problem
301 else
297 else
302 return []
298 return []
303 end
299 end
304 end
300 end
305
301
306 #check if the user has the right to view that problem
302 #check if the user has the right to view that problem
307 #this also consider group based problem policy
303 #this also consider group based problem policy
308 def can_view_problem?(problem)
304 def can_view_problem?(problem)
309 return true if admin?
305 return true if admin?
310 return available_problems.include? problem
306 return available_problems.include? problem
311 end
307 end
312
308
313 def self.clear_last_login
309 def self.clear_last_login
314 User.update_all(:last_ip => nil)
310 User.update_all(:last_ip => nil)
315 end
311 end
316
312
313 + #create multiple user, one per lines of input
314 + def self.create_from_list(lines)
315 + error_logins = []
316 + first_error = nil
317 + created_users = []
318 +
319 + lines.split("\n").each do |line|
320 + #split with large limit, this will cause consecutive ',' to be result in a blank
321 + items = line.chomp.split(',',1000)
322 + if items.length>=2
323 + login = items[0]
324 + full_name = items[1]
325 + remark =''
326 + user_alias = ''
327 +
328 + added_random_password = false
329 + added_password = false
330 +
331 + #given password?
332 + if items.length >= 3
333 + if items[2].chomp(" ").length > 0
334 + password = items[2].chomp(" ")
335 + added_password = true
336 + end
337 + else
338 + password = random_password
339 + added_random_password=true;
340 + end
341 +
342 + #given alias?
343 + if items.length>= 4 and items[3].chomp(" ").length > 0;
344 + user_alias = items[3].chomp(" ")
345 + else
346 + user_alias = login
347 + end
348 +
349 + #given remark?
350 + has_remark = false
351 + if items.length>=5
352 + remark = items[4].strip;
353 + has_remark = true
354 + end
355 +
356 + user = User.find_by_login(login)
357 + if (user)
358 + user.full_name = full_name
359 + user.remark = remark if has_remark
360 + user.password = password if added_password || added_random_password
361 + else
362 + #create a random password if none are given
363 + password = random_password unless password
364 + user = User.new({:login => login,
365 + :full_name => full_name,
366 + :password => password,
367 + :password_confirmation => password,
368 + :alias => user_alias,
369 + :remark => remark})
370 + end
371 + user.activated = true
372 +
373 + if user.save
374 + created_users << user
375 + else
376 + error_logins << "'#{login}'"
377 + first_error = user.errors.full_messages.to_sentence unless first_error
378 + end
379 + end
380 + end
381 +
382 + return {error_logins: error_logins, first_error: first_error, created_users: created_users}
383 +
384 + end
385 +
386 + def self.find_non_admin_with_prefix(prefix='')
387 + users = User.all
388 + return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
389 + end
390 +
317 protected
391 protected
318 def encrypt_new_password
392 def encrypt_new_password
319 return if password.blank?
393 return if password.blank?
320 self.salt = (10+rand(90)).to_s
394 self.salt = (10+rand(90)).to_s
321 self.hashed_password = User.encrypt(self.password,self.salt)
395 self.hashed_password = User.encrypt(self.password,self.salt)
322 end
396 end
323
397
324 def assign_default_site
398 def assign_default_site
325 # have to catch error when migrating (because self.site is not available).
399 # have to catch error when migrating (because self.site is not available).
326 begin
400 begin
327 if self.site==nil
401 if self.site==nil
328 self.site = Site.find_by_name('default')
402 self.site = Site.find_by_name('default')
329 if self.site==nil
403 if self.site==nil
330 self.site = Site.find(1) # when 'default has be renamed'
404 self.site = Site.find(1) # when 'default has be renamed'
331 end
405 end
332 end
406 end
333 rescue
407 rescue
334 end
408 end
335 end
409 end
336
410
337 def assign_default_contest
411 def assign_default_contest
338 # have to catch error when migrating (because self.site is not available).
412 # have to catch error when migrating (because self.site is not available).
339 begin
413 begin
340 if self.contests.length == 0
414 if self.contests.length == 0
341 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
415 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
342 if default_contest
416 if default_contest
343 self.contests = [default_contest]
417 self.contests = [default_contest]
344 end
418 end
345 end
419 end
346 rescue
420 rescue
347 end
421 end
348 end
422 end
349
423
350 def password_required?
424 def password_required?
351 self.hashed_password.blank? || !self.password.blank?
425 self.hashed_password.blank? || !self.password.blank?
352 end
426 end
353
427
354 def self.encrypt(string,salt)
428 def self.encrypt(string,salt)
355 Digest::SHA1.hexdigest(salt + string)
429 Digest::SHA1.hexdigest(salt + string)
356 end
430 end
357
431
358 def uniqueness_of_email_from_activated_users
432 def uniqueness_of_email_from_activated_users
359 user = User.activated_users.find_by_email(self.email)
433 user = User.activated_users.find_by_email(self.email)
360 if user and (user.login != self.login)
434 if user and (user.login != self.login)
361 self.errors.add(:base,"Email has already been taken")
435 self.errors.add(:base,"Email has already been taken")
362 end
436 end
363 end
437 end
364
438
365 def enough_time_interval_between_same_email_registrations
439 def enough_time_interval_between_same_email_registrations
366 return if !self.new_record?
440 return if !self.new_record?
367 return if self.activated
441 return if self.activated
368 open_user = User.find_by_email(self.email,
442 open_user = User.find_by_email(self.email,
369 :order => 'created_at DESC')
443 :order => 'created_at DESC')
370 if open_user and open_user.created_at and
444 if open_user and open_user.created_at and
371 (open_user.created_at > Time.now.gmtime - 5.minutes)
445 (open_user.created_at > Time.now.gmtime - 5.minutes)
372 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
446 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
373 end
447 end
374 end
448 end
375
449
376 def email_validation?
450 def email_validation?
377 begin
451 begin
378 return VALIDATE_USER_EMAILS
452 return VALIDATE_USER_EMAILS
379 rescue
453 rescue
380 return false
454 return false
381 end
455 end
382 end
456 end
383 end
457 end
@@ -1,86 +1,92
1 %h1 Bulk Manage User
1 %h1 Bulk Manage User
2
2
3 = form_tag bulk_manage_user_admin_index_path
3 = form_tag bulk_manage_user_admin_index_path
4 .row
4 .row
5 .col-md-6
5 .col-md-6
6 .panel.panel-primary
6 .panel.panel-primary
7 .panel-title.panel-heading
7 .panel-title.panel-heading
8 Filter User
8 Filter User
9 .panel-body
9 .panel-body
10 Filtering users whose login match the following MySQL regex
10 Filtering users whose login match the following MySQL regex
11 .form-group
11 .form-group
12 = label_tag "regex", 'Regex Pattern'
12 = label_tag "regex", 'Regex Pattern'
13 = text_field_tag "regex", params[:regex], class: 'form-control'
13 = text_field_tag "regex", params[:regex], class: 'form-control'
14 %p
14 %p
15 Example
15 Example
16 %ul
16 %ul
17 %li
17 %li
18 %code root
18 %code root
19 matches every user whose login contains "root"
19 matches every user whose login contains "root"
20 %li
20 %li
21 %code ^56
21 %code ^56
22 matches every user whose login starts with "56"
22 matches every user whose login starts with "56"
23 %li
23 %li
24 %code 21$
24 %code 21$
25 matches every user whose login ends with "21"
25 matches every user whose login ends with "21"
26 + .form-group
27 + .div.checkbox
28 + %label
29 + = check_box_tag :filter_group, 1, params[:filter_group] == '1'
30 + Apply to this group only
31 + = select_tag "filter_group_id", options_from_collection_for_select( Group.all, 'id','name',params[:filter_group_id]), id: 'group_name',class: 'select2'
26 .col-md-6
32 .col-md-6
27 .panel.panel-primary
33 .panel.panel-primary
28 .panel-title.panel-heading
34 .panel-title.panel-heading
29 Action
35 Action
30 .panel-body
36 .panel-body
31 .row.form-group
37 .row.form-group
32 .col-md-6
38 .col-md-6
33 %label.checkbox-inline
39 %label.checkbox-inline
34 = check_box_tag "enabled", true, params[:enabled]
40 = check_box_tag "enabled", true, params[:enabled]
35 Change "Enabled" to
41 Change "Enabled" to
36 .col-md-3
42 .col-md-3
37 %label.radio-inline
43 %label.radio-inline
38 = radio_button_tag "enable", 1, params[:enable] == '1', id: 'enable-yes'
44 = radio_button_tag "enable", 1, params[:enable] == '1', id: 'enable-yes'
39 Yes
45 Yes
40 .col-md-3
46 .col-md-3
41 %label.radio-inline
47 %label.radio-inline
42 = radio_button_tag "enable", 0, params[:enable] == '0', id: 'enable-no'
48 = radio_button_tag "enable", 0, params[:enable] == '0', id: 'enable-no'
43 No
49 No
44 .row.form-group
50 .row.form-group
45 .col-md-6
51 .col-md-6
46 %label.checkbox-inline
52 %label.checkbox-inline
47 = check_box_tag "gen_password", true, params[:gen_password]
53 = check_box_tag "gen_password", true, params[:gen_password]
48 Generate new random password
54 Generate new random password
49 .row.form-group
55 .row.form-group
50 .col-md-4
56 .col-md-4
51 %label.checkbox-inline
57 %label.checkbox-inline
52 = check_box_tag "add_group", true, params[:add_group]
58 = check_box_tag "add_group", true, params[:add_group]
53 Add users to group
59 Add users to group
54 %label.col-md-3.control-label.text-right Group name
60 %label.col-md-3.control-label.text-right Group name
55 .col-md-5
61 .col-md-5
56 = select_tag "group_name", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'form-control select2'
62 = select_tag "group_name", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'form-control select2'
57
63
58
64
59 .row
65 .row
60 .col-md-12
66 .col-md-12
61 = submit_tag "Preview Result", class: 'btn btn-default'
67 = submit_tag "Preview Result", class: 'btn btn-default'
62 - if @users
68 - if @users
63 .row
69 .row
64 .col-md-4
70 .col-md-4
65 - if @action
71 - if @action
66 %h2 Confirmation
72 %h2 Confirmation
67 - if @action[:set_enable]
73 - if @action[:set_enable]
68 .alert.alert-info The following users will be set #{(@action[:enabled] ? 'enable' : 'disable')}.
74 .alert.alert-info The following users will be set #{(@action[:enabled] ? 'enable' : 'disable')}.
69 - if @action[:gen_password]
75 - if @action[:gen_password]
70 .alert.alert-info The password of the following users will be randomly generated.
76 .alert.alert-info The password of the following users will be randomly generated.
71 .row
77 .row
72 .col-md-4
78 .col-md-4
73 = submit_tag "Perform", class: 'btn btn-primary'
79 = submit_tag "Perform", class: 'btn btn-primary'
74 .row
80 .row
75 .col-md-12
81 .col-md-12
76 The pattern matches #{@users.count} following users.
82 The pattern matches #{@users.count} following users.
77 %br
83 %br
78 - @users.each do |user|
84 - @users.each do |user|
79 = user.login
85 = user.login
80 = ' '
86 = ' '
81 = user.full_name
87 = user.full_name
82 = ' '
88 = ' '
83 = "(#{user.remark})" if user.remark
89 = "(#{user.remark})" if user.remark
84 %br
90 %br
85
91
86
92
You need to be logged in to leave comments. Login now