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

r748:ff7f37009e5e - - 3 files changed: 15 inserted, 7 deleted

@@ -1,369 +1,369
1 1 require 'digest/sha1'
2 2 require 'net/pop'
3 3 require 'net/https'
4 4 require 'net/http'
5 5 require 'json'
6 6
7 7 class User < ActiveRecord::Base
8 8
9 9 has_and_belongs_to_many :roles
10 10
11 11 #has_and_belongs_to_many :groups
12 12 has_many :groups_users, class_name: GroupUser
13 13 has_many :groups, :through => :groups_users
14 14
15 - has_many :test_requests, -> {order(submitted_at: DESC)}
15 + has_many :test_requests, -> {order(submitted_at: :desc)}
16 16
17 - has_many :messages, -> { order(created_at: DESC) },
17 + has_many :messages, -> { order(created_at: :desc) },
18 18 :class_name => "Message",
19 19 :foreign_key => "sender_id"
20 20
21 - has_many :replied_messages, -> { order(created_at: DESC) },
21 + has_many :replied_messages, -> { order(created_at: :desc) },
22 22 :class_name => "Message",
23 23 :foreign_key => "receiver_id"
24 24
25 25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
26 26
27 27 belongs_to :site
28 28 belongs_to :country
29 29
30 30 has_and_belongs_to_many :contests, -> { order(:name); uniq}
31 31
32 32 scope :activated_users, -> {where activated: true}
33 33
34 34 validates_presence_of :login
35 35 validates_uniqueness_of :login
36 36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
37 37 validates_length_of :login, :within => 3..30
38 38
39 39 validates_presence_of :full_name
40 40 validates_length_of :full_name, :minimum => 1
41 41
42 42 validates_presence_of :password, :if => :password_required?
43 43 validates_length_of :password, :within => 4..20, :if => :password_required?
44 44 validates_confirmation_of :password, :if => :password_required?
45 45
46 46 validates_format_of :email,
47 47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
48 48 :if => :email_validation?
49 49 validate :uniqueness_of_email_from_activated_users,
50 50 :if => :email_validation?
51 51 validate :enough_time_interval_between_same_email_registrations,
52 52 :if => :email_validation?
53 53
54 54 # these are for ytopc
55 55 # disable for now
56 56 #validates_presence_of :province
57 57
58 58 attr_accessor :password
59 59
60 60 before_save :encrypt_new_password
61 61 before_save :assign_default_site
62 62 before_save :assign_default_contest
63 63
64 64 # this is for will_paginate
65 65 cattr_reader :per_page
66 66 @@per_page = 50
67 67
68 68 def self.authenticate(login, password)
69 69 user = find_by_login(login)
70 70 if user
71 71 return user if user.authenticated?(password)
72 72 end
73 73 end
74 74
75 75 def authenticated?(password)
76 76 if self.activated
77 77 hashed_password == User.encrypt(password,self.salt)
78 78 else
79 79 false
80 80 end
81 81 end
82 82
83 83 def admin?
84 84 self.roles.detect {|r| r.name == 'admin' }
85 85 end
86 86
87 87 def email_for_editing
88 88 if self.email==nil
89 89 "(unknown)"
90 90 elsif self.email==''
91 91 "(blank)"
92 92 else
93 93 self.email
94 94 end
95 95 end
96 96
97 97 def email_for_editing=(e)
98 98 self.email=e
99 99 end
100 100
101 101 def alias_for_editing
102 102 if self.alias==nil
103 103 "(unknown)"
104 104 elsif self.alias==''
105 105 "(blank)"
106 106 else
107 107 self.alias
108 108 end
109 109 end
110 110
111 111 def alias_for_editing=(e)
112 112 self.alias=e
113 113 end
114 114
115 115 def activation_key
116 116 if self.hashed_password==nil
117 117 encrypt_new_password
118 118 end
119 119 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
120 120 end
121 121
122 122 def verify_activation_key(key)
123 123 key == activation_key
124 124 end
125 125
126 126 def self.random_password(length=5)
127 127 chars = 'abcdefghjkmnopqrstuvwxyz'
128 128 password = ''
129 129 length.times { password << chars[rand(chars.length - 1)] }
130 130 password
131 131 end
132 132
133 133 def self.find_non_admin_with_prefix(prefix='')
134 134 users = User.all
135 135 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
136 136 end
137 137
138 138 # Contest information
139 139
140 140 def self.find_users_with_no_contest()
141 141 users = User.all
142 142 return users.find_all { |u| u.contests.length == 0 }
143 143 end
144 144
145 145
146 146 def contest_time_left
147 147 if GraderConfiguration.contest_mode?
148 148 return nil if site==nil
149 149 return site.time_left
150 150 elsif GraderConfiguration.indv_contest_mode?
151 151 time_limit = GraderConfiguration.contest_time_limit
152 152 if time_limit == nil
153 153 return nil
154 154 end
155 155 if contest_stat==nil or contest_stat.started_at==nil
156 156 return (Time.now.gmtime + time_limit) - Time.now.gmtime
157 157 else
158 158 finish_time = contest_stat.started_at + time_limit
159 159 current_time = Time.now.gmtime
160 160 if current_time > finish_time
161 161 return 0
162 162 else
163 163 return finish_time - current_time
164 164 end
165 165 end
166 166 else
167 167 return nil
168 168 end
169 169 end
170 170
171 171 def contest_finished?
172 172 if GraderConfiguration.contest_mode?
173 173 return false if site==nil
174 174 return site.finished?
175 175 elsif GraderConfiguration.indv_contest_mode?
176 176 return false if self.contest_stat(true)==nil
177 177 return contest_time_left == 0
178 178 else
179 179 return false
180 180 end
181 181 end
182 182
183 183 def contest_started?
184 184 if GraderConfiguration.indv_contest_mode?
185 185 stat = self.contest_stat
186 186 return ((stat != nil) and (stat.started_at != nil))
187 187 elsif GraderConfiguration.contest_mode?
188 188 return true if site==nil
189 189 return site.started
190 190 else
191 191 return true
192 192 end
193 193 end
194 194
195 195 def update_start_time
196 196 stat = self.contest_stat
197 197 if stat.nil? or stat.started_at.nil?
198 198 stat ||= UserContestStat.new(:user => self)
199 199 stat.started_at = Time.now.gmtime
200 200 stat.save
201 201 end
202 202 end
203 203
204 204 def problem_in_user_contests?(problem)
205 205 problem_contests = problem.contests.all
206 206
207 207 if problem_contests.length == 0 # this is public contest
208 208 return true
209 209 end
210 210
211 211 contests.each do |contest|
212 212 if problem_contests.find {|c| c.id == contest.id }
213 213 return true
214 214 end
215 215 end
216 216 return false
217 217 end
218 218
219 219 def available_problems_group_by_contests
220 220 contest_problems = []
221 221 pin = {}
222 222 contests.enabled.each do |contest|
223 223 available_problems = contest.problems.available
224 224 contest_problems << {
225 225 :contest => contest,
226 226 :problems => available_problems
227 227 }
228 228 available_problems.each {|p| pin[p.id] = true}
229 229 end
230 230 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
231 231 contest_problems << {
232 232 :contest => nil,
233 233 :problems => other_avaiable_problems
234 234 }
235 235 return contest_problems
236 236 end
237 237
238 238 def solve_all_available_problems?
239 239 available_problems.each do |p|
240 240 u = self
241 241 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
242 242 return false if !p or !sub or sub.points < p.full_score
243 243 end
244 244 return true
245 245 end
246 246
247 247 #get a list of available problem
248 248 def available_problems
249 249 if not GraderConfiguration.multicontests?
250 250 if GraderConfiguration.use_problem_group?
251 251 return available_problems_in_group
252 252 else
253 253 return Problem.available_problems
254 254 end
255 255 else
256 256 contest_problems = []
257 257 pin = {}
258 258 contests.enabled.each do |contest|
259 259 contest.problems.available.each do |problem|
260 260 if not pin.has_key? problem.id
261 261 contest_problems << problem
262 262 end
263 263 pin[problem.id] = true
264 264 end
265 265 end
266 266 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
267 267 return contest_problems + other_avaiable_problems
268 268 end
269 269 end
270 270
271 271 def available_problems_in_group
272 272 problem = []
273 273 self.groups.each do |group|
274 274 group.problems.where(available: true).each { |p| problem << p }
275 275 end
276 276 problem.uniq!
277 277 if problem
278 278 problem.sort! do |a,b|
279 279 case
280 280 when a.date_added < b.date_added
281 281 1
282 282 when a.date_added > b.date_added
283 283 -1
284 284 else
285 285 a.name <=> b.name
286 286 end
287 287 end
288 288 return problem
289 289 else
290 290 return []
291 291 end
292 292 end
293 293
294 294 def can_view_problem?(problem)
295 295 return true if admin?
296 296 return available_problems.include? problem
297 297 end
298 298
299 299 def self.clear_last_login
300 300 User.update_all(:last_ip => nil)
301 301 end
302 302
303 303 protected
304 304 def encrypt_new_password
305 305 return if password.blank?
306 306 self.salt = (10+rand(90)).to_s
307 307 self.hashed_password = User.encrypt(self.password,self.salt)
308 308 end
309 309
310 310 def assign_default_site
311 311 # have to catch error when migrating (because self.site is not available).
312 312 begin
313 313 if self.site==nil
314 314 self.site = Site.find_by_name('default')
315 315 if self.site==nil
316 316 self.site = Site.find(1) # when 'default has be renamed'
317 317 end
318 318 end
319 319 rescue
320 320 end
321 321 end
322 322
323 323 def assign_default_contest
324 324 # have to catch error when migrating (because self.site is not available).
325 325 begin
326 326 if self.contests.length == 0
327 327 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
328 328 if default_contest
329 329 self.contests = [default_contest]
330 330 end
331 331 end
332 332 rescue
333 333 end
334 334 end
335 335
336 336 def password_required?
337 337 self.hashed_password.blank? || !self.password.blank?
338 338 end
339 339
340 340 def self.encrypt(string,salt)
341 341 Digest::SHA1.hexdigest(salt + string)
342 342 end
343 343
344 344 def uniqueness_of_email_from_activated_users
345 345 user = User.activated_users.find_by_email(self.email)
346 346 if user and (user.login != self.login)
347 347 self.errors.add(:base,"Email has already been taken")
348 348 end
349 349 end
350 350
351 351 def enough_time_interval_between_same_email_registrations
352 352 return if !self.new_record?
353 353 return if self.activated
354 354 open_user = User.find_by_email(self.email,
355 355 :order => 'created_at DESC')
356 356 if open_user and open_user.created_at and
357 357 (open_user.created_at > Time.now.gmtime - 5.minutes)
358 358 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
359 359 end
360 360 end
361 361
362 362 def email_validation?
363 363 begin
364 364 return VALIDATE_USER_EMAILS
365 365 rescue
366 366 return false
367 367 end
368 368 end
369 369 end
@@ -1,106 +1,106
1 1 %h1 Users
2 2
3 3 .panel.panel-primary
4 4 .panel-title.panel-heading
5 5 Quick Add
6 6 .panel-body
7 7 = form_tag( {method: 'post'}, {class: 'form-inline'}) do
8 8 .form-group
9 9 = label_tag 'user_login', 'Login'
10 10 = text_field 'user', 'login', :size => 10,class: 'form-control'
11 11 .form-group
12 12 = label_tag 'user_full_name', 'Full Name'
13 13 = text_field 'user', 'full_name', :size => 10,class: 'form-control'
14 14 .form-group
15 15 = label_tag 'user_password', 'Password'
16 16 = text_field 'user', 'password', :size => 10,class: 'form-control'
17 17 .form-group
18 18 = label_tag 'user_password_confirmation', 'Confirm'
19 19 = text_field 'user', 'password_confirmation', :size => 10,class: 'form-control'
20 20 .form-group
21 21 = label_tag 'user_email', 'email'
22 22 = text_field 'user', 'email', :size => 10,class: 'form-control'
23 23 =submit_tag "Create", class: 'btn btn-primary'
24 24
25 25 .panel.panel-primary
26 26 .panel-title.panel-heading
27 27 Import from site management
28 28 .panel-body
29 29 = form_tag({:action => 'import'}, :multipart => true,class: 'form form-inline') do
30 30 .form-group
31 31 = label_tag :file, 'File:'
32 32 .input-group
33 33 %span.input-group-btn
34 34 %span.btn.btn-default.btn-file
35 35 Browse
36 36 = file_field_tag 'file'
37 37 = text_field_tag '' , nil, {readonly: true, class: 'form-control'}
38 38 = submit_tag 'Submit', class: 'btn btn-default'
39 39
40 40
41 41 %p
42 42 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
43 43 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
44 - = link_to 'Bulk Manage', bulk_manage_user_admin_path , { class: 'btn btn-default btn-info'}
44 + = link_to 'Bulk Manage', { action: :bulk_manage} , { class: 'btn btn-default btn-info'}
45 45 = link_to 'View administrators',{ :action => 'admin'}, { class: 'btn btn-default '}
46 46 = link_to 'Random passwords',{ :action => 'random_all_passwords'}, { class: 'btn btn-default '}
47 47 = link_to 'View active users',{ :action => 'active'}, { class: 'btn btn-default '}
48 48 = link_to 'Mass mailing',{ :action => 'mass_mailing'}, { class: 'btn btn-default '}
49 49
50 50 - if GraderConfiguration.multicontests?
51 51 %br/
52 52 %b Multi-contest:
53 53 = link_to '[Manage bulk users in contests]', :action => 'contest_management'
54 54 View users in:
55 55 - @contests.each do |contest|
56 56 = link_to "[#{contest.name}]", :action => 'contests', :id => contest.id
57 57 = link_to "[no contest]", :action => 'contests', :id => 'none'
58 58
59 59 -# Total #{@user_count} users |
60 60 -# - if !@paginated
61 61 -# Display all users.
62 62 -# \#{link_to '[show in pages]', :action => 'index', :page => '1'}
63 63 -# - else
64 64 -# Display in pages.
65 65 -# \#{link_to '[display all]', :action => 'index', :page => 'all'} |
66 66 -# \#{will_paginate @users, :container => false}
67 67
68 68
69 69 %table.table.table-hover.table-condense.datatable
70 70 %thead
71 71 %th Login
72 72 %th Full name
73 73 %th email
74 74 %th Remark
75 75 %th
76 76 Activated
77 77 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'User has already confirmed the email?' } [?]
78 78 %th
79 79 Enabled
80 80 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'Allow the user to login?' } [?]
81 81 %th Last IP
82 82 %th
83 83 %th
84 84 %th
85 85 %th
86 86 - for user in @users
87 87 %tr
88 88 %td= link_to user.login, stat_user_path(user)
89 89 %td= user.full_name
90 90 %td= user.email
91 91 %td= user.remark
92 92 %td= toggle_button(user.activated?, toggle_activate_user_path(user),"toggle_activate_user_#{user.id}")
93 93 %td= toggle_button(user.enabled?, toggle_enable_user_path(user),"toggle_enable_user_#{user.id}")
94 94 %td= user.last_ip
95 95 %td= link_to 'Clear IP', {:action => 'clear_last_ip', :id => user, :page=>params[:page]}, :confirm => 'This will reset last logging in ip of the user, are you sure?', class: 'btn btn-default btn-xs btn-block'
96 96 %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-default btn-xs btn-block'
97 97 %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-default btn-xs btn-block'
98 - %td= link_to 'Destroy', user_admin_destroy_path(user), data: {confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-danger btn-xs btn-block'
98 + %td= link_to 'Destroy', {action: :destroy, id: user}, data: {confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-danger btn-xs btn-block'
99 99 %br/
100 100 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
101 101 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
102 102
103 103 :javascript
104 104 $('.datatable').DataTable({
105 105 'pageLength': 50
106 106 });
@@ -1,158 +1,166
1 1 CafeGrader::Application.routes.draw do
2 2 resources :tags
3 3 get "sources/direct_edit"
4 4
5 5 root :to => 'main#login'
6 6
7 7 #logins
8 8 match 'login/login', to: 'login#login', via: [:get,:post]
9 9
10 10
11 11 resources :contests
12 12
13 13 resources :sites
14 14
15 15 resources :test
16 16
17 17 resources :messages do
18 18 collection do
19 19 get 'console'
20 20 end
21 21 end
22 22
23 23 resources :announcements do
24 24 member do
25 25 get 'toggle','toggle_front'
26 26 end
27 27 end
28 28
29 29 resources :problems do
30 30 member do
31 31 get 'toggle'
32 32 get 'toggle_test'
33 33 get 'toggle_view_testcase'
34 34 get 'stat'
35 35 end
36 36 collection do
37 37 get 'turn_all_off'
38 38 get 'turn_all_on'
39 39 get 'import'
40 40 get 'manage'
41 41 end
42 42 end
43 43
44 44 resources :groups do
45 45 member do
46 46 post 'add_user', to: 'groups#add_user', as: 'add_user'
47 47 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
48 48 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
49 49 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
50 50 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
51 51 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
52 52 end
53 53 collection do
54 54
55 55 end
56 56 end
57 57
58 58 resources :testcases, only: [] do
59 59 member do
60 60 get 'download_input'
61 61 get 'download_sol'
62 62 end
63 63 collection do
64 64 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
65 65 end
66 66 end
67 67
68 68 resources :grader_configuration, controller: 'configurations'
69 69
70 70 resources :users do
71 71 member do
72 72 get 'toggle_activate', 'toggle_enable'
73 73 get 'stat'
74 74 end
75 75 end
76 76
77 77 resources :submissions do
78 78 member do
79 79 get 'download'
80 80 get 'compiler_msg'
81 81 get 'rejudge'
82 82 end
83 83 collection do
84 84 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
85 85 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
86 86 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
87 87 end
88 88 end
89 89
90 90
91 91 #user admin
92 92 resources :user_admin do
93 93 collection do
94 - get 'bulk_manage', as: 'bulk_manage_user_admin'
95 - delete ':id', to: 'user_admin#destroy', as: 'user_admin_destroy'
94 + get 'bulk_manage'
96 95 get 'user_stat'
96 + get 'import'
97 + get 'new_list'
98 + get 'admin'
99 + get 'random_all_passwords'
100 + get 'active'
101 + get 'mass_mailing'
102 + end
103 + member do
104 + get 'clear_last_ip'
97 105 end
98 106 end
99 107
100 108 resources :contest_management, only: [:index] do
101 109 collection do
102 110 get 'user_stat'
103 111 get 'clear_stat'
104 112 get 'clear_all_stat'
105 113 end
106 114 end
107 115
108 116 #get 'user_admin', to: 'user_admin#index'
109 117 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
110 118 #post 'user_admin', to: 'user_admin#create'
111 119 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
112 120
113 121 #singular resource
114 122 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
115 123 #report
116 124 resource :report, only: [], controller: 'report' do
117 125 get 'login'
118 126 get 'multiple_login'
119 127 get 'problem_hof/:id', action: 'problem_hof'
120 128 get 'current_score'
121 129 get 'max_score'
122 130 post 'show_max_score'
123 131 end
124 132 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
125 133 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
126 134 #get "report/login"
127 135 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
128 136 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
129 137
130 138 resource :main, only: [], controller: 'main' do
131 139 get 'list'
132 140 get 'submission(/:id)', action: 'submission', as: 'main_submission'
133 141 post 'submit'
134 142 get 'announcements'
135 143 get 'help'
136 144 end
137 145 #main
138 146 #get "main/list"
139 147 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
140 148 #post 'main/submit', to: 'main#submit'
141 149 #get 'main/announcements', to: 'main#announcements'
142 150
143 151
144 152 #
145 153 get 'tasks/view/:file.:ext' => 'tasks#view'
146 154 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
147 155 get 'heartbeat/:id/edit' => 'heartbeat#edit'
148 156
149 157 #grader
150 158 get 'graders/list', to: 'graders#list', as: 'grader_list'
151 159
152 160
153 161 # See how all your routes lay out with "rake routes"
154 162
155 163 # This is a legacy wild controller route that's not recommended for RESTful applications.
156 164 # Note: This route will make all actions in every controller accessible via GET requests.
157 165 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
158 166 end
You need to be logged in to leave comments. Login now