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

r308:c400f7405eee - - 3 files changed: 23 inserted, 1 deleted

@@ -1,249 +1,249
1 1 class UserAdminController < ApplicationController
2 2
3 3 include MailHelperMethods
4 4
5 5 before_filter :admin_authorization
6 6
7 7 def index
8 8 list
9 9 render :action => 'list'
10 10 end
11 11
12 12 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
13 13 verify :method => :post, :only => [ :destroy,
14 14 :create, :create_from_list,
15 15 :update ],
16 16 :redirect_to => { :action => :list }
17 17
18 18 def list
19 19 @user_count = User.count
20 20 if params[:page] == 'all'
21 21 @users = User.all
22 22 @paginated = false
23 23 else
24 24 @users = User.paginate :page => params[:page]
25 25 @paginated = true
26 26 end
27 27 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
28 28 @contests = Contest.enabled
29 29 end
30 30
31 31 def active
32 32 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
33 33 @users = []
34 34 sessions.each do |session|
35 35 if session.data[:user_id]
36 36 @users << User.find(session.data[:user_id])
37 37 end
38 38 end
39 39 end
40 40
41 41 def show
42 42 @user = User.find(params[:id])
43 43 end
44 44
45 45 def new
46 46 @user = User.new
47 47 end
48 48
49 49 def create
50 50 @user = User.new(params[:user])
51 51 @user.activated = true
52 52 if @user.save
53 53 flash[:notice] = 'User was successfully created.'
54 54 redirect_to :action => 'list'
55 55 else
56 56 render :action => 'new'
57 - end
57 + end
58 58 end
59 59
60 60 def create_from_list
61 61 lines = params[:user_list]
62 62
63 63 note = []
64 64
65 65 lines.split("\n").each do |line|
66 66 items = line.chomp.split(',')
67 67 if items.length>=2
68 68 login = items[0]
69 69 full_name = items[1]
70 70
71 71 added_random_password = false
72 72 if items.length>=3
73 73 password = items[2].chomp(" ")
74 74 user_alias = (items.length>=4) ? items[3] : login
75 75 else
76 76 password = random_password
77 77 user_alias = (items.length>=4) ? items[3] : login
78 78 added_random_password = true
79 79 end
80 80
81 81 user = User.new({:login => login,
82 82 :full_name => full_name,
83 83 :password => password,
84 84 :password_confirmation => password,
85 85 :alias => user_alias})
86 86 user.activated = true
87 87 user.save
88 88
89 89 if added_random_password
90 90 note << "'#{login}' (+)"
91 91 else
92 92 note << login
93 93 end
94 94 end
95 95 end
96 96 flash[:notice] = 'User(s) ' + note.join(', ') +
97 97 ' were successfully created. ' +
98 98 '( (+) - created with random passwords.)'
99 99 redirect_to :action => 'list'
100 100 end
101 101
102 102 def edit
103 103 @user = User.find(params[:id])
104 104 end
105 105
106 106 def update
107 107 @user = User.find(params[:id])
108 108 if @user.update_attributes(params[:user])
109 109 flash[:notice] = 'User was successfully updated.'
110 110 redirect_to :action => 'show', :id => @user
111 111 else
112 112 render :action => 'edit'
113 113 end
114 114 end
115 115
116 116 def destroy
117 117 User.find(params[:id]).destroy
118 118 redirect_to :action => 'list'
119 119 end
120 120
121 121 def user_stat
122 122 @problems = Problem.find_available_problems
123 123 @users = User.find(:all, :include => [:contests, :contest_stat])
124 124 @scorearray = Array.new
125 125 @users.each do |u|
126 126 ustat = Array.new
127 127 ustat[0] = u
128 128 @problems.each do |p|
129 129 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
130 130 if (sub!=nil) and (sub.points!=nil)
131 131 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
132 132 else
133 133 ustat << [0,false]
134 134 end
135 135 end
136 136 @scorearray << ustat
137 137 end
138 138 end
139 139
140 140 def import
141 141 if params[:file]==''
142 142 flash[:notice] = 'Error importing no file'
143 143 redirect_to :action => 'list' and return
144 144 end
145 145 import_from_file(params[:file])
146 146 end
147 147
148 148 def random_all_passwords
149 149 users = User.find(:all)
150 150 @prefix = params[:prefix] || ''
151 151 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
152 152 @changed = false
153 153 if request.request_method == :post
154 154 @non_admin_users.each do |user|
155 155 password = random_password
156 156 user.password = password
157 157 user.password_confirmation = password
158 158 user.save
159 159 end
160 160 @changed = true
161 161 end
162 162 end
163 163
164 164 # contest management
165 165
166 166 def contests
167 167 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
168 168 @contests = Contest.enabled
169 169 end
170 170
171 171 def assign_from_list
172 172 contest_id = params[:users_contest_id]
173 173 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
174 174 contest = Contest.find(params[:new_contest][:id])
175 175 if !contest
176 176 flash[:notice] = 'Error: no contest'
177 177 redirect_to :action => 'contests', :id =>contest_id
178 178 end
179 179
180 180 note = []
181 181 users.each do |u|
182 182 u.contests = [contest]
183 183 note << u.login
184 184 end
185 185 flash[:notice] = 'User(s) ' + note.join(', ') +
186 186 " were successfully reassigned to #{contest.title}."
187 187 redirect_to :action => 'contests', :id =>contest.id
188 188 end
189 189
190 190 def add_to_contest
191 191 user = User.find(params[:id])
192 192 contest = Contest.find(params[:contest_id])
193 193 if user and contest
194 194 user.contests << contest
195 195 end
196 196 redirect_to :action => 'list'
197 197 end
198 198
199 199 def remove_from_contest
200 200 user = User.find(params[:id])
201 201 contest = Contest.find(params[:contest_id])
202 202 if user and contest
203 203 user.contests.delete(contest)
204 204 end
205 205 redirect_to :action => 'list'
206 206 end
207 207
208 208 def contest_management
209 209 end
210 210
211 211 def manage_contest
212 212 contest = Contest.find(params[:contest][:id])
213 213 if !contest
214 214 flash[:notice] = 'You did not choose the contest.'
215 215 redirect_to :action => 'contest_management' and return
216 216 end
217 217
218 218 operation = params[:operation]
219 219
220 220 if not ['add','remove','assign'].include? operation
221 221 flash[:notice] = 'You did not choose the operation to perform.'
222 222 redirect_to :action => 'contest_management' and return
223 223 end
224 224
225 225 lines = params[:login_list]
226 226 if !lines or lines.blank?
227 227 flash[:notice] = 'You entered an empty list.'
228 228 redirect_to :action => 'contest_management' and return
229 229 end
230 230
231 231 note = []
232 232 users = []
233 233 lines.split("\n").each do |line|
234 234 user = User.find_by_login(line.chomp)
235 235 if user
236 236 if operation=='add'
237 237 if ! user.contests.include? contest
238 238 user.contests << contest
239 239 end
240 240 elsif operation=='remove'
241 241 user.contests.delete(contest)
242 242 else
243 243 user.contests = [contest]
244 244 end
245 245
246 246 if params[:reset_timer]
247 247 user.contest_stat.forced_logout = true
248 248 user.contest_stat.reset_timer_and_save
249 249 end
@@ -1,309 +1,323
1 1 require 'digest/sha1'
2 2
3 3 class User < ActiveRecord::Base
4 4
5 5 has_and_belongs_to_many :roles
6 6
7 7 has_many :test_requests, :order => "submitted_at DESC"
8 8
9 9 has_many :messages,
10 10 :class_name => "Message",
11 11 :foreign_key => "sender_id",
12 12 :order => 'created_at DESC'
13 13
14 14 has_many :replied_messages,
15 15 :class_name => "Message",
16 16 :foreign_key => "receiver_id",
17 17 :order => 'created_at DESC'
18 18
19 19 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
20 20
21 21 belongs_to :site
22 22 belongs_to :country
23 23
24 24 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
25 25
26 26 named_scope :activated_users, :conditions => {:activated => true}
27 27
28 28 validates_presence_of :login
29 29 validates_uniqueness_of :login
30 30 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
31 31 validates_length_of :login, :within => 3..30
32 32
33 33 validates_presence_of :full_name
34 34 validates_length_of :full_name, :minimum => 1
35 35
36 36 validates_presence_of :password, :if => :password_required?
37 37 validates_length_of :password, :within => 4..20, :if => :password_required?
38 38 validates_confirmation_of :password, :if => :password_required?
39 39
40 40 validates_format_of :email,
41 41 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
42 42 :if => :email_validation?
43 43 validate :uniqueness_of_email_from_activated_users,
44 44 :if => :email_validation?
45 45 validate :enough_time_interval_between_same_email_registrations,
46 46 :if => :email_validation?
47 47
48 48 # these are for ytopc
49 49 # disable for now
50 50 #validates_presence_of :province
51 51
52 52 attr_accessor :password
53 53
54 54 before_save :encrypt_new_password
55 55 before_save :assign_default_site
56 + before_save :assign_default_contest
56 57
57 58 # this is for will_paginate
58 59 cattr_reader :per_page
59 60 @@per_page = 50
60 61
61 62 def self.authenticate(login, password)
62 63 user = find_by_login(login)
63 64 return user if user && user.authenticated?(password)
64 65 end
65 66
66 67 def authenticated?(password)
67 68 if self.activated
68 69 hashed_password == User.encrypt(password,self.salt)
69 70 else
70 71 false
71 72 end
72 73 end
73 74
74 75 def admin?
75 76 self.roles.detect {|r| r.name == 'admin' }
76 77 end
77 78
78 79 def email_for_editing
79 80 if self.email==nil
80 81 "(unknown)"
81 82 elsif self.email==''
82 83 "(blank)"
83 84 else
84 85 self.email
85 86 end
86 87 end
87 88
88 89 def email_for_editing=(e)
89 90 self.email=e
90 91 end
91 92
92 93 def alias_for_editing
93 94 if self.alias==nil
94 95 "(unknown)"
95 96 elsif self.alias==''
96 97 "(blank)"
97 98 else
98 99 self.alias
99 100 end
100 101 end
101 102
102 103 def alias_for_editing=(e)
103 104 self.alias=e
104 105 end
105 106
106 107 def activation_key
107 108 if self.hashed_password==nil
108 109 encrypt_new_password
109 110 end
110 111 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
111 112 end
112 113
113 114 def verify_activation_key(key)
114 115 key == activation_key
115 116 end
116 117
117 118 def self.random_password(length=5)
118 119 chars = 'abcdefghjkmnopqrstuvwxyz'
119 120 password = ''
120 121 length.times { password << chars[rand(chars.length - 1)] }
121 122 password
122 123 end
123 124
124 125 def self.find_non_admin_with_prefix(prefix='')
125 126 users = User.find(:all)
126 127 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
127 128 end
128 129
129 130 # Contest information
130 131
131 132 def self.find_users_with_no_contest()
132 133 users = User.find(:all)
133 134 return users.find_all { |u| u.contests.length == 0 }
134 135 end
135 136
136 137
137 138 def contest_time_left
138 139 if Configuration.contest_mode?
139 140 return nil if site==nil
140 141 return site.time_left
141 142 elsif Configuration.indv_contest_mode?
142 143 time_limit = Configuration.contest_time_limit
143 144 if time_limit == nil
144 145 return nil
145 146 end
146 147 if contest_stat==nil or contest_stat.started_at==nil
147 148 return (Time.now.gmtime + time_limit) - Time.now.gmtime
148 149 else
149 150 finish_time = contest_stat.started_at + time_limit
150 151 current_time = Time.now.gmtime
151 152 if current_time > finish_time
152 153 return 0
153 154 else
154 155 return finish_time - current_time
155 156 end
156 157 end
157 158 else
158 159 return nil
159 160 end
160 161 end
161 162
162 163 def contest_finished?
163 164 if Configuration.contest_mode?
164 165 return false if site==nil
165 166 return site.finished?
166 167 elsif Configuration.indv_contest_mode?
167 168 return false if self.contest_stat(true)==nil
168 169 return contest_time_left == 0
169 170 else
170 171 return false
171 172 end
172 173 end
173 174
174 175 def contest_started?
175 176 if Configuration.indv_contest_mode?
176 177 stat = self.contest_stat
177 178 return ((stat != nil) and (stat.started_at != nil))
178 179 elsif Configuration.contest_mode?
179 180 return true if site==nil
180 181 return site.started
181 182 else
182 183 return true
183 184 end
184 185 end
185 186
186 187 def update_start_time
187 188 stat = self.contest_stat
188 189 if stat == nil or stat.started_at == nil
189 190 stat ||= UserContestStat.new(:user => self)
190 191 stat.started_at = Time.now.gmtime
191 192 stat.save
192 193 end
193 194 end
194 195
195 196 def problem_in_user_contests?(problem)
196 197 problem_contests = problem.contests.all
197 198
198 199 if problem_contests.length == 0 # this is public contest
199 200 return true
200 201 end
201 202
202 203 contests.each do |contest|
203 204 if problem_contests.find {|c| c.id == contest.id }
204 205 return true
205 206 end
206 207 end
207 208 return false
208 209 end
209 210
210 211 def available_problems_group_by_contests
211 212 contest_problems = []
212 213 pin = {}
213 214 contests.enabled.each do |contest|
214 215 available_problems = contest.problems.available
215 216 contest_problems << {
216 217 :contest => contest,
217 218 :problems => available_problems
218 219 }
219 220 available_problems.each {|p| pin[p.id] = true}
220 221 end
221 222 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
222 223 contest_problems << {
223 224 :contest => nil,
224 225 :problems => other_avaiable_problems
225 226 }
226 227 return contest_problems
227 228 end
228 229
229 230 def available_problems
230 231 if not Configuration.multicontests?
231 232 return Problem.find_available_problems
232 233 else
233 234 contest_problems = []
234 235 pin = {}
235 236 contests.enabled.each do |contest|
236 237 contest.problems.available.each do |problem|
237 238 if not pin.has_key? problem.id
238 239 contest_problems << problem
239 240 end
240 241 pin[problem.id] = true
241 242 end
242 243 end
243 244 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
244 245 return contest_problems + other_avaiable_problems
245 246 end
246 247 end
247 248
248 249 def can_view_problem?(problem)
249 250 if not Configuration.multicontests?
250 251 return problem.available
251 252 else
252 253 return problem_in_user_contests? problem
253 254 end
254 255 end
255 256
256 257 protected
257 258 def encrypt_new_password
258 259 return if password.blank?
259 260 self.salt = (10+rand(90)).to_s
260 261 self.hashed_password = User.encrypt(self.password,self.salt)
261 262 end
262 263
263 264 def assign_default_site
264 265 # have to catch error when migrating (because self.site is not available).
265 266 begin
266 267 if self.site==nil
267 268 self.site = Site.find_by_name('default')
268 269 if self.site==nil
269 270 self.site = Site.find(1) # when 'default has be renamed'
270 271 end
271 272 end
272 273 rescue
273 274 end
274 275 end
275 276
277 + def assign_default_contest
278 + # have to catch error when migrating (because self.site is not available).
279 + begin
280 + if self.contests.length == 0
281 + default_contest = Contest.find_by_name(Configuration['contest.default_contest_name'])
282 + if default_contest
283 + self.contests = [default_contest]
284 + end
285 + end
286 + rescue
287 + end
288 + end
289 +
276 290 def password_required?
277 291 self.hashed_password.blank? || !self.password.blank?
278 292 end
279 293
280 294 def self.encrypt(string,salt)
281 295 Digest::SHA1.hexdigest(salt + string)
282 296 end
283 297
284 298 def uniqueness_of_email_from_activated_users
285 299 user = User.activated_users.find_by_email(self.email)
286 300 if user and (user.login != self.login)
287 301 self.errors.add_to_base("Email has already been taken")
288 302 end
289 303 end
290 304
291 305 def enough_time_interval_between_same_email_registrations
292 306 return if !self.new_record?
293 307 return if self.activated
294 308 open_user = User.find_by_email(self.email,
295 309 :order => 'created_at DESC')
296 310 if open_user and open_user.created_at and
297 311 (open_user.created_at > Time.now.gmtime - 5.minutes)
298 312 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
299 313 end
300 314 end
301 315
302 316 def email_validation?
303 317 begin
304 318 return VALIDATE_USER_EMAILS
305 319 rescue
306 320 return false
307 321 end
308 322 end
309 323 end
@@ -1,190 +1,198
1 1 CONFIGURATIONS =
2 2 [
3 3 {
4 4 :key => 'system.single_user_mode',
5 5 :value_type => 'boolean',
6 6 :default_value => 'false',
7 7 :description => 'Only admins can log in to the system when running under single user mode.'
8 8 },
9 9
10 10 {
11 11 :key => 'ui.front.title',
12 12 :value_type => 'string',
13 13 :default_value => 'Grader'
14 14 },
15 15
16 16 {
17 17 :key => 'ui.front.welcome_message',
18 18 :value_type => 'string',
19 19 :default_value => 'Welcome!'
20 20 },
21 21
22 22 {
23 23 :key => 'ui.show_score',
24 24 :value_type => 'boolean',
25 25 :default_value => 'true'
26 26 },
27 27
28 28 {
29 29 :key => 'contest.time_limit',
30 30 :value_type => 'string',
31 31 :default_value => 'unlimited',
32 32 :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits. This config is CACHED. Restart the server before the change can take effect.'
33 33 },
34 34
35 35 {
36 36 :key => 'system.mode',
37 37 :value_type => 'string',
38 38 :default_value => 'standard',
39 39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 40 },
41 41
42 42 {
43 43 :key => 'contest.name',
44 44 :value_type => 'string',
45 45 :default_value => 'Grader',
46 46 :description => 'This name will be shown on the user header bar.'
47 47 },
48 48
49 49 {
50 50 :key => 'contest.multisites',
51 51 :value_type => 'boolean',
52 52 :default_value => 'false',
53 53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
54 54 },
55 55
56 56 {
57 57 :key => 'system.online_registration',
58 58 :value_type => 'boolean',
59 59 :default_value => 'false',
60 60 :description => 'This option enables online registration.'
61 61 },
62 62
63 63 # If Configuration['system.online_registration'] is true, the
64 64 # system allows online registration, and will use these
65 65 # information for sending confirmation emails.
66 66 {
67 67 :key => 'system.online_registration.smtp',
68 68 :value_type => 'string',
69 69 :default_value => 'smtp.somehost.com'
70 70 },
71 71
72 72 {
73 73 :key => 'system.online_registration.from',
74 74 :value_type => 'string',
75 75 :default_value => 'your.email@address'
76 76 },
77 77
78 78 {
79 79 :key => 'system.admin_email',
80 80 :value_type => 'string',
81 81 :default_value => 'admin@admin.email'
82 82 },
83 83
84 84 {
85 85 :key => 'system.user_setting_enabled',
86 86 :value_type => 'boolean',
87 87 :default_value => 'true',
88 88 :description => 'If this option is true, users can change their settings'
89 89 },
90 90
91 91 # If Configuration['contest.test_request.early_timeout'] is true
92 92 # the user will not be able to use test request at 30 minutes
93 93 # before the contest ends.
94 94 {
95 95 :key => 'contest.test_request.early_timeout',
96 96 :value_type => 'boolean',
97 97 :default_value => 'false'
98 98 },
99 99
100 100 {
101 101 :key => 'system.multicontests',
102 102 :value_type => 'boolean',
103 103 :default_value => 'false'
104 104 },
105 105
106 106 {
107 107 :key => 'contest.confirm_indv_contest_start',
108 108 :value_type => 'boolean',
109 109 :default_value => 'false'
110 + },
111 +
112 + {
113 + :key => 'contest.default_contest_name',
114 + :value_type => 'string',
115 + :default_value => 'none',
116 + :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
110 117 }
118 +
111 119 ]
112 120
113 121
114 122 def create_configuration_key(key,
115 123 value_type,
116 124 default_value,
117 125 description='')
118 126 conf = (Configuration.find_by_key(key) ||
119 127 Configuration.new(:key => key,
120 128 :value_type => value_type,
121 129 :value => default_value))
122 130 conf.description = description
123 131 conf.save
124 132 end
125 133
126 134 def seed_config
127 135 CONFIGURATIONS.each do |conf|
128 136 if conf.has_key? :description
129 137 desc = conf[:description]
130 138 else
131 139 desc = ''
132 140 end
133 141 create_configuration_key(conf[:key],
134 142 conf[:value_type],
135 143 conf[:default_value],
136 144 desc)
137 145 end
138 146 end
139 147
140 148 def seed_roles
141 149 return if Role.find_by_name('admin')
142 150
143 151 role = Role.create(:name => 'admin')
144 152 user_admin_right = Right.create(:name => 'user_admin',
145 153 :controller => 'user_admin',
146 154 :action => 'all')
147 155 problem_admin_right = Right.create(:name=> 'problem_admin',
148 156 :controller => 'problems',
149 157 :action => 'all')
150 158
151 159 graders_right = Right.create(:name => 'graders_admin',
152 160 :controller => 'graders',
153 161 :action => 'all')
154 162
155 163 role.rights << user_admin_right;
156 164 role.rights << problem_admin_right;
157 165 role.rights << graders_right;
158 166 role.save
159 167 end
160 168
161 169 def seed_root
162 170 return if User.find_by_login('root')
163 171
164 172 root = User.new(:login => 'root',
165 173 :full_name => 'Administrator',
166 174 :alias => 'root')
167 175 root.password = 'ioionrails';
168 176
169 177 class << root
170 178 public :encrypt_new_password
171 179 def valid?
172 180 true
173 181 end
174 182 end
175 183
176 184 root.encrypt_new_password
177 185
178 186 root.roles << Role.find_by_name('admin')
179 187
180 188 root.activated = true
181 189 root.save
182 190 end
183 191
184 192 def seed_users_and_roles
185 193 seed_roles
186 194 seed_root
187 195 end
188 196
189 197 seed_config
190 198 seed_users_and_roles
You need to be logged in to leave comments. Login now