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

r798:46ce575fc051 - - 6 files changed: 29 inserted, 18 deleted

@@ -1,482 +1,492
1 1 require 'csv'
2 2
3 3 class UserAdminController < ApplicationController
4 4
5 5 include MailHelperMethods
6 6
7 7 before_action :admin_authorization
8 8
9 9 def index
10 10 @user_count = User.count
11 11 if params[:page] == 'all'
12 12 @users = User.all
13 13 @paginated = false
14 14 else
15 15 @users = User.paginate :page => params[:page]
16 16 @paginated = true
17 17 end
18 18 @users = User.all
19 19 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
20 20 @contests = Contest.enabled
21 21 end
22 22
23 23 def active
24 24 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
25 25 @users = []
26 26 sessions.each do |session|
27 27 if session.data[:user_id]
28 28 @users << User.find(session.data[:user_id])
29 29 end
30 30 end
31 31 end
32 32
33 33 def show
34 34 @user = User.find(params[:id])
35 35 end
36 36
37 37 def new
38 38 @user = User.new
39 39 end
40 40
41 41 def create
42 42 @user = User.new(user_params)
43 43 @user.activated = true
44 44 if @user.save
45 45 flash[:notice] = 'User was successfully created.'
46 46 redirect_to :action => 'index'
47 47 else
48 48 render :action => 'new'
49 49 end
50 50 end
51 51
52 52 def clear_last_ip
53 53 @user = User.find(params[:id])
54 54 @user.last_ip = nil
55 55 @user.save
56 56 redirect_to action: 'index', page: params[:page]
57 57 end
58 58
59 59 def create_from_list
60 60 lines = params[:user_list]
61 61
62 62 note = []
63 63 error_note = []
64 64 error_msg = nil
65 65 ok_user = []
66 66
67 67 lines.split("\n").each do |line|
68 - items = line.chomp.split(',')
68 + #split with large limit, this will cause consecutive ',' to be result in a blank
69 + items = line.chomp.split(',',1000)
69 70 if items.length>=2
70 71 login = items[0]
71 72 full_name = items[1]
72 73 remark =''
73 74 user_alias = ''
74 75
75 76 added_random_password = false
76 - if items.length >= 3 and items[2].chomp(" ").length > 0;
77 - password = items[2].chomp(" ")
77 + added_password = false
78 + if items.length >= 3
79 + if items[2].chomp(" ").length > 0
80 + password = items[2].chomp(" ")
81 + added_password = true
82 + end
78 83 else
79 84 password = random_password
80 85 added_random_password=true;
81 86 end
82 87
83 88 if items.length>= 4 and items[3].chomp(" ").length > 0;
84 89 user_alias = items[3].chomp(" ")
85 90 else
86 91 user_alias = login
87 92 end
88 93
94 +
95 + has_remark = false
89 96 if items.length>=5
90 97 remark = items[4].strip;
98 + has_remark = true
91 99 end
92 100
93 101 user = User.find_by_login(login)
94 102 if (user)
95 103 user.full_name = full_name
96 - user.password = password
97 - user.remark = remark
104 + user.remark = remark if has_remark
105 + user.password = password if added_password || added_random_password
98 106 else
107 + #create a random password if none are given
108 + password = random_password unless password
99 109 user = User.new({:login => login,
100 110 :full_name => full_name,
101 111 :password => password,
102 112 :password_confirmation => password,
103 113 :alias => user_alias,
104 114 :remark => remark})
105 115 end
106 116 user.activated = true
107 117
108 118 if user.save
109 119 if added_random_password
110 120 note << "'#{login}' (+)"
111 121 else
112 122 note << login
113 123 end
114 124 ok_user << user
115 125 else
116 126 error_note << "'#{login}'"
117 127 error_msg = user.errors.full_messages.to_sentence unless error_msg
118 128 end
119 129
120 130 end
121 131 end
122 132
123 133 #add to group
124 134 if params[:add_to_group]
125 135 group = Group.where(id: params[:group_id]).first
126 136 if group
127 137 group.users << ok_user
128 138 end
129 139 end
130 140
131 141 # show flash
132 142 if note.size > 0
133 143 flash[:success] = 'User(s) ' + note.join(', ') +
134 144 ' were successfully created. ' +
135 145 '( (+) - created with random passwords.)'
136 146 end
137 147 if error_note.size > 0
138 148 flash[:error] = "Following user(s) failed to be created: " + error_note.join(', ') + ". The error of the first failed one are: " + error_msg;
139 149 end
140 150 redirect_to :action => 'index'
141 151 end
142 152
143 153 def edit
144 154 @user = User.find(params[:id])
145 155 end
146 156
147 157 def update
148 158 @user = User.find(params[:id])
149 159 if @user.update_attributes(user_params)
150 160 flash[:notice] = 'User was successfully updated.'
151 161 redirect_to :action => 'show', :id => @user
152 162 else
153 163 render :action => 'edit'
154 164 end
155 165 end
156 166
157 167 def destroy
158 168 User.find(params[:id]).destroy
159 169 redirect_to :action => 'index'
160 170 end
161 171
162 172 def user_stat
163 173 if params[:commit] == 'download csv'
164 174 @problems = Problem.all
165 175 else
166 176 @problems = Problem.available_problems
167 177 end
168 178 @users = User.includes(:contests, :contest_stat).where(enabled: true)
169 179 @scorearray = Array.new
170 180 @users.each do |u|
171 181 ustat = Array.new
172 182 ustat[0] = u
173 183 @problems.each do |p|
174 184 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
175 185 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
176 186 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
177 187 else
178 188 ustat << [0,false]
179 189 end
180 190 end
181 191 @scorearray << ustat
182 192 end
183 193 if params[:commit] == 'download csv' then
184 194 csv = gen_csv_from_scorearray(@scorearray,@problems)
185 195 send_data csv, filename: 'last_score.csv'
186 196 else
187 197 render template: 'user_admin/user_stat'
188 198 end
189 199 end
190 200
191 201 def user_stat_max
192 202 if params[:commit] == 'download csv'
193 203 @problems = Problem.all
194 204 else
195 205 @problems = Problem.available_problems
196 206 end
197 207 @users = User.includes(:contests).includes(:contest_stat).all
198 208 @scorearray = Array.new
199 209 #set up range from param
200 210 since_id = params.fetch(:since_id, 0).to_i
201 211 until_id = params.fetch(:until_id, 0).to_i
202 212 @users.each do |u|
203 213 ustat = Array.new
204 214 ustat[0] = u
205 215 @problems.each do |p|
206 216 max_points = 0
207 217 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
208 218 max_points = sub.points if sub and sub.points and (sub.points > max_points)
209 219 end
210 220 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
211 221 end
212 222 @scorearray << ustat
213 223 end
214 224
215 225 if params[:commit] == 'download csv' then
216 226 csv = gen_csv_from_scorearray(@scorearray,@problems)
217 227 send_data csv, filename: 'max_score.csv'
218 228 else
219 229 render template: 'user_admin/user_stat'
220 230 end
221 231 end
222 232
223 233 def import
224 234 if params[:file]==''
225 235 flash[:notice] = 'Error importing no file'
226 236 redirect_to :action => 'index' and return
227 237 end
228 238 import_from_file(params[:file])
229 239 end
230 240
231 241 def random_all_passwords
232 242 users = User.all
233 243 @prefix = params[:prefix] || ''
234 244 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
235 245 @changed = false
236 246 if params[:commit] == 'Go ahead'
237 247 @non_admin_users.each do |user|
238 248 password = random_password
239 249 user.password = password
240 250 user.password_confirmation = password
241 251 user.save
242 252 end
243 253 @changed = true
244 254 end
245 255 end
246 256
247 257 # contest management
248 258
249 259 def contests
250 260 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
251 261 @contests = Contest.enabled
252 262 end
253 263
254 264 def assign_from_list
255 265 contest_id = params[:users_contest_id]
256 266 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
257 267 contest = Contest.find(params[:new_contest][:id])
258 268 if !contest
259 269 flash[:notice] = 'Error: no contest'
260 270 redirect_to :action => 'contests', :id =>contest_id
261 271 end
262 272
263 273 note = []
264 274 users.each do |u|
265 275 u.contests = [contest]
266 276 note << u.login
267 277 end
268 278 flash[:notice] = 'User(s) ' + note.join(', ') +
269 279 " were successfully reassigned to #{contest.title}."
270 280 redirect_to :action => 'contests', :id =>contest.id
271 281 end
272 282
273 283 def add_to_contest
274 284 user = User.find(params[:id])
275 285 contest = Contest.find(params[:contest_id])
276 286 if user and contest
277 287 user.contests << contest
278 288 end
279 289 redirect_to :action => 'index'
280 290 end
281 291
282 292 def remove_from_contest
283 293 user = User.find(params[:id])
284 294 contest = Contest.find(params[:contest_id])
285 295 if user and contest
286 296 user.contests.delete(contest)
287 297 end
288 298 redirect_to :action => 'index'
289 299 end
290 300
291 301 def contest_management
292 302 end
293 303
294 304 def manage_contest
295 305 contest = Contest.find(params[:contest][:id])
296 306 if !contest
297 307 flash[:notice] = 'You did not choose the contest.'
298 308 redirect_to :action => 'contest_management' and return
299 309 end
300 310
301 311 operation = params[:operation]
302 312
303 313 if not ['add','remove','assign'].include? operation
304 314 flash[:notice] = 'You did not choose the operation to perform.'
305 315 redirect_to :action => 'contest_management' and return
306 316 end
307 317
308 318 lines = params[:login_list]
309 319 if !lines or lines.blank?
310 320 flash[:notice] = 'You entered an empty list.'
311 321 redirect_to :action => 'contest_management' and return
312 322 end
313 323
314 324 note = []
315 325 users = []
316 326 lines.split("\n").each do |line|
317 327 user = User.find_by_login(line.chomp)
318 328 if user
319 329 if operation=='add'
320 330 if ! user.contests.include? contest
321 331 user.contests << contest
322 332 end
323 333 elsif operation=='remove'
324 334 user.contests.delete(contest)
325 335 else
326 336 user.contests = [contest]
327 337 end
328 338
329 339 if params[:reset_timer]
330 340 user.contest_stat.forced_logout = true
331 341 user.contest_stat.reset_timer_and_save
332 342 end
333 343
334 344 if params[:notification_emails]
335 345 send_contest_update_notification_email(user, contest)
336 346 end
337 347
338 348 note << user.login
339 349 users << user
340 350 end
341 351 end
342 352
343 353 if params[:reset_timer]
344 354 logout_users(users)
345 355 end
346 356
347 357 flash[:notice] = 'User(s) ' + note.join(', ') +
348 358 ' were successfully modified. '
349 359 redirect_to :action => 'contest_management'
350 360 end
351 361
352 362 # admin management
353 363
354 364 def admin
355 365 @admins = User.all.find_all {|user| user.admin? }
356 366 end
357 367
358 368 def grant_admin
359 369 login = params[:login]
360 370 user = User.find_by_login(login)
361 371 if user!=nil
362 372 admin_role = Role.find_by_name('admin')
363 373 user.roles << admin_role
364 374 else
365 375 flash[:notice] = 'Unknown user'
366 376 end
367 377 flash[:notice] = 'User added as admins'
368 378 redirect_to :action => 'admin'
369 379 end
370 380
371 381 def revoke_admin
372 382 user = User.find(params[:id])
373 383 if user==nil
374 384 flash[:notice] = 'Unknown user'
375 385 redirect_to :action => 'admin' and return
376 386 elsif user.login == 'root'
377 387 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
378 388 redirect_to :action => 'admin' and return
379 389 end
380 390
381 391 admin_role = Role.find_by_name('admin')
382 392 user.roles.delete(admin_role)
383 393 flash[:notice] = 'User permission revoked'
384 394 redirect_to :action => 'admin'
385 395 end
386 396
387 397 # mass mailing
388 398
389 399 def mass_mailing
390 400 end
391 401
392 402 def bulk_mail
393 403 lines = params[:login_list]
394 404 if !lines or lines.blank?
395 405 flash[:notice] = 'You entered an empty list.'
396 406 redirect_to :action => 'mass_mailing' and return
397 407 end
398 408
399 409 mail_subject = params[:subject]
400 410 if !mail_subject or mail_subject.blank?
401 411 flash[:notice] = 'You entered an empty mail subject.'
402 412 redirect_to :action => 'mass_mailing' and return
403 413 end
404 414
405 415 mail_body = params[:email_body]
406 416 if !mail_body or mail_body.blank?
407 417 flash[:notice] = 'You entered an empty mail body.'
408 418 redirect_to :action => 'mass_mailing' and return
409 419 end
410 420
411 421 note = []
412 422 users = []
413 423 lines.split("\n").each do |line|
414 424 user = User.find_by_login(line.chomp)
415 425 if user
416 426 send_mail(user.email, mail_subject, mail_body)
417 427 note << user.login
418 428 end
419 429 end
420 430
421 431 flash[:notice] = 'User(s) ' + note.join(', ') +
422 432 ' were successfully modified. '
423 433 redirect_to :action => 'mass_mailing'
424 434 end
425 435
426 436 #bulk manage
427 437 def bulk_manage
428 438
429 439 begin
430 440 @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
431 441 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
432 442 rescue Exception
433 443 flash[:error] = 'Regular Expression is malformed'
434 444 @users = nil
435 445 end
436 446
437 447 if params[:commit]
438 448 @action = {}
439 449 @action[:set_enable] = params[:enabled]
440 450 @action[:enabled] = params[:enable] == "1"
441 451 @action[:gen_password] = params[:gen_password]
442 452 @action[:add_group] = params[:add_group]
443 453 @action[:group_name] = params[:group_name]
444 454 end
445 455
446 456 if params[:commit] == "Perform"
447 457 if @action[:set_enable]
448 458 @users.update_all(enabled: @action[:enabled])
449 459 end
450 460 if @action[:gen_password]
451 461 @users.each do |u|
452 462 password = random_password
453 463 u.password = password
454 464 u.password_confirmation = password
455 465 u.save
456 466 end
457 467 end
458 468 if @action[:add_group] and @action[:group_name]
459 469 @group = Group.find(@action[:group_name])
460 470 ok = []
461 471 failed = []
462 472 @users.each do |user|
463 473 begin
464 474 @group.users << user
465 475 ok << user.login
466 476 rescue => e
467 477 failed << user.login
468 478 end
469 479 end
470 480 flash[:success] = "The following users are added to the 'group #{@group.name}': " + ok.join(', ') if ok.count > 0
471 481 flash[:alert] = "The following users are already in the 'group #{@group.name}': " + failed.join(', ') if failed.count > 0
472 482 end
473 483 end
474 484 end
475 485
476 486 protected
477 487
478 488 def random_password(length=5)
479 489 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
480 490 newpass = ""
481 491 length.times { newpass << chars[rand(chars.size-1)] }
482 492 return newpass
@@ -1,225 +1,222
1 1 # Methods added to this helper will be available to all templates in the application.
2 2 module ApplicationHelper
3 3
4 4 #new bootstrap header
5 5 def navbar_user_header
6 6 left_menu = ''
7 7 right_menu = ''
8 8 user = User.find(session[:user_id])
9 9
10 10 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
11 11 left_menu << add_menu("#{I18n.t 'menu.tasks'}", 'tasks', 'list')
12 12 left_menu << add_menu("#{I18n.t 'menu.submissions'}", 'main', 'submission')
13 13 left_menu << add_menu("#{I18n.t 'menu.test'}", 'test', 'index')
14 14 end
15 15
16 16 if GraderConfiguration['right.user_hall_of_fame']
17 17 left_menu << add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
18 18 end
19 19
20 20 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
21 21 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
22 22 if GraderConfiguration['system.user_setting_enabled']
23 23 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
24 24 end
25 25 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
26 26
27 27
28 28 result = content_tag(:ul,left_menu.html_safe,class: 'nav navbar-nav') + content_tag(:ul,right_menu.html_safe,class: 'nav navbar-nav navbar-right')
29 29 end
30 30
31 31 def add_menu(title, controller, action, html_option = {})
32 32 link_option = {controller: controller, action: action}
33 33 html_option[:class] = (html_option[:class] || '') + " active" if current_page?(link_option)
34 34 content_tag(:li, link_to(title,link_option),html_option)
35 35 end
36 36
37 37 def user_header
38 38 menu_items = ''
39 39 user = User.find(session[:user_id])
40 40
41 41 if (user!=nil) and (session[:admin])
42 42 # admin menu
43 43 menu_items << "<b>Administrative task:</b> "
44 44 append_to menu_items, '[Announcements]', 'announcements', 'index'
45 45 append_to menu_items, '[Msg console]', 'messages', 'console'
46 46 append_to menu_items, '[Problems]', 'problems', 'index'
47 47 append_to menu_items, '[Users]', 'user_admin', 'index'
48 48 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
49 49 append_to menu_items, '[Report]', 'report', 'multiple_login'
50 50 append_to menu_items, '[Graders]', 'graders', 'list'
51 51 append_to menu_items, '[Contests]', 'contest_management', 'index'
52 52 append_to menu_items, '[Sites]', 'sites', 'index'
53 53 append_to menu_items, '[System config]', 'configurations', 'index'
54 54 menu_items << "<br/>"
55 55 end
56 56
57 57 # main page
58 58 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
59 59 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
60 60
61 61 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
62 62 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
63 63 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
64 64 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
65 65 end
66 66
67 67 if GraderConfiguration['right.user_hall_of_fame']
68 68 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
69 69 end
70 70 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
71 71
72 72 if GraderConfiguration['system.user_setting_enabled']
73 73 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
74 74 end
75 75 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
76 76
77 77 menu_items.html_safe
78 78 end
79 79
80 80 def append_to(option,label, controller, action)
81 81 option << ' ' if option!=''
82 82 option << link_to_unless_current(label,
83 83 :controller => controller,
84 84 :action => action)
85 85 end
86 86
87 87 def format_short_time(time)
88 88 now = Time.zone.now
89 89 st = ''
90 90 if (time.yday != now.yday) or (time.year != now.year)
91 91 st = time.strftime("%d/%m/%y ")
92 92 end
93 93 st + time.strftime("%X")
94 94 end
95 95
96 96 def format_short_duration(duration)
97 97 return '' if duration==nil
98 98 d = duration.to_f
99 99 return Time.at(d).gmtime.strftime("%X")
100 100 end
101 101
102 102 def format_full_time_ago(time)
103 103 st = time_ago_in_words(time) + ' ago (' + format_short_time(time) + ')'
104 104 end
105 105
106 106 def read_textfile(fname,max_size=2048)
107 107 begin
108 108 File.open(fname).read(max_size)
109 109 rescue
110 110 nil
111 111 end
112 112 end
113 113
114 114 def toggle_button(on,toggle_url,id, option={})
115 115 btn_size = option[:size] || 'btn-xs'
116 116 btn_block = option[:block] || 'btn-block'
117 117 link_to (on ? "Yes" : "No"), toggle_url,
118 118 {class: "btn #{btn_block} #{btn_size} btn-#{on ? 'success' : 'default'} ajax-toggle",
119 119 id: id,
120 120 data: {remote: true, method: 'get'}}
121 121 end
122 122
123 123 def get_ace_mode(language)
124 124 # return ace mode string from Language
125 125
126 126 case language.pretty_name
127 127 when 'Pascal'
128 128 'ace/mode/pascal'
129 129 when 'C++','C'
130 130 'ace/mode/c_cpp'
131 131 when 'Ruby'
132 132 'ace/mode/ruby'
133 133 when 'Python'
134 134 'ace/mode/python'
135 135 when 'Java'
136 136 'ace/mode/java'
137 137 else
138 138 'ace/mode/c_cpp'
139 139 end
140 140 end
141 141
142 142
143 143 def user_title_bar(user)
144 144 header = ''
145 145 time_left = ''
146 146
147 147 #
148 148 # if the contest is over
149 149 if GraderConfiguration.time_limit_mode?
150 150 if user.contest_finished?
151 151 header = <<CONTEST_OVER
152 152 <tr><td colspan="2" align="center">
153 153 <span class="contest-over-msg">THE CONTEST IS OVER</span>
154 154 </td></tr>
155 155 CONTEST_OVER
156 156 end
157 157 if !user.contest_started?
158 158 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
159 159 else
160 160 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
161 161 " #{format_short_duration(user.contest_time_left)}"
162 162 end
163 163 end
164 164
165 165 #
166 166 # if the contest is in the anaysis mode
167 167 if GraderConfiguration.analysis_mode?
168 168 header = <<ANALYSISMODE
169 169 <tr><td colspan="2" align="center">
170 170 <span class="contest-over-msg">ANALYSIS MODE</span>
171 171 </td></tr>
172 172 ANALYSISMODE
173 173 end
174 174
175 175 contest_name = GraderConfiguration['contest.name']
176 176
177 177 #
178 178 # build real title bar
179 179 result = <<TITLEBAR
180 180 <div class="title">
181 181 <table>
182 182 #{header}
183 183 <tr>
184 184 <td class="left-col">
185 - #{user.full_name}<br/>
186 - #{t 'title_bar.current_time'} #{format_short_time(Time.zone.now)}
187 - #{time_left}
188 185 <br/>
189 186 </td>
190 187 <td class="right-col">#{contest_name}</td>
191 188 </tr>
192 189 </table>
193 190 </div>
194 191 TITLEBAR
195 192 result.html_safe
196 193 end
197 194
198 195 def markdown(text)
199 196 markdown = RDiscount.new(text)
200 197 markdown.to_html.html_safe
201 198 end
202 199
203 200
204 201 BOOTSTRAP_FLASH_MSG = {
205 202 success: 'alert-success',
206 203 error: 'alert-danger',
207 204 alert: 'alert-danger',
208 205 notice: 'alert-info'
209 206 }
210 207
211 208 def bootstrap_class_for(flash_type)
212 209 BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s)
213 210 end
214 211
215 212 def flash_messages
216 213 flash.each do |msg_type, message|
217 214 concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do
218 215 concat content_tag(:button, 'x', class: "close", data: { dismiss: 'alert' })
219 216 concat message
220 217 end)
221 218 end
222 219 nil
223 220 end
224 221
225 222 end
@@ -1,20 +1,14
1 1 module MainHelper
2 2
3 - def link_to_description_if_any(name, problem, options={})
3 + def link_to_description_if_any(name, problem)
4 4 if !problem.url.blank?
5 - return link_to name, problem.url, options
5 + return link_to name, problem.url
6 6 elsif !problem.description_filename.blank?
7 - #build a link to a problem (via task controller)
8 7 basename, ext = problem.description_filename.split('.')
9 - options[:controller] = 'tasks'
10 - options[:action] = 'download'
11 - options[:id] = problem.id
12 - options[:file] = basename
13 - options[:ext] = ext
14 - return link_to name, options
8 + return link_to name, download_task_path(problem.id,basename,ext), target: '_blank'
15 9 else
16 10 return ''
17 11 end
18 12 end
19 13
20 14 end
@@ -1,112 +1,113
1 1 %h1= "Submission: #{@submission.id}"
2 2
3 3 %textarea#data{style: "display:none;"}
4 4 :preserve
5 5 #{@submission.source}
6 6
7 7 //%div.highlight{:style => "border: 1px solid black;"}
8 8 //=@formatted_code.html_safe
9 9
10 10
11 11 .containter
12 12 .row
13 13 .col-md-7
14 14 %h2 Source Code
15 15 .col-md-5
16 16 %h2 Stat
17 17 .row
18 18 .col-md-7
19 19 %div#editor{ style: "font-size: 14px; height: 400px; border-radius:5px;" }
20 20 :javascript
21 21 e = ace.edit("editor")
22 22 e.setOptions({ maxLines: Infinity })
23 23 e.setValue($("#data").text())
24 24 e.gotoLine(1)
25 25 e.getSession().setMode("#{get_ace_mode(@submission.language)}")
26 26 e.setReadOnly(true)
27 27 .col-md-5
28 28 %table.table.table-striped
29 29 %tr
30 30 %td.text-right
31 31 %strong User
32 32 %td
33 33 - if @submission.user
34 34 = link_to "#{@submission.user.login}", stat_user_path(@submission.user)
35 35 = @submission.user.full_name
36 36 - else
37 37 = "(n/a)"
38 38 %tr
39 39 %td.text-right
40 40 %strong Task
41 41 %td
42 42 - if @submission.problem!=nil
43 43 = link_to "[#{@submission.problem.name}]", stat_problem_path(@submission.problem)
44 44 = @submission.problem.full_name
45 + = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @submission.problem
45 46 - else
46 47 = "(n/a)"
47 48 %tr
48 49 %td.text-right
49 50 %strong Tries
50 51 %td= @submission.number
51 52 %tr
52 53 %td.text-right
53 54 %strong Language
54 55 %td= @submission.language.pretty_name
55 56 %tr
56 57 %td.text-right
57 58 %strong Submitted
58 59 %td #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
59 60 %tr
60 61 %td.text-right
61 62 %strong Graded
62 63 - if @submission.graded_at
63 64 %td #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
64 65 - else
65 66 %td -
66 67 %tr
67 68 %td.text-right
68 69 %strong Points
69 70 %td #{@submission.points}/#{@submission.try(:problem).try(:full_score)}
70 71 %tr
71 72 %td.text-right
72 73 %strong Comment
73 74 %td #{@submission.grader_comment}
74 75 %tr
75 76 %td.text-right
76 77 %strong Runtime (s)
77 78 %td #{@submission.max_runtime}
78 79 %tr
79 80 %td.text-right
80 81 %strong Memory (kb)
81 82 %td #{@submission.peak_memory}
82 83 %tr
83 84 %td.text-right
84 85 %strong Compiler result
85 86 %td
86 87 %button.btn.btn-info.btn-xs{type: 'button', data: {toggle: 'modal', target: '#compiler'}}
87 88 view
88 89 - if session[:admin]
89 90 %tr
90 91 %td.text-right
91 92 %strong IP
92 93 %td #{@submission.ip_address}
93 94 %tr
94 95 %td.text-right
95 96 %strong Grading Task Status
96 97 %td
97 98 = @task.status_str if @task
98 99 - if session[:admin]
99 100 = link_to "rejudge", rejudge_submission_path, data: {remote: true}, class: 'btn btn-info btn-xs'
100 101
101 102
102 103 .modal.fade#compiler{tabindex: -1,role: 'dialog'}
103 104 .modal-dialog.modal-lg{role:'document'}
104 105 .modal-content
105 106 .modal-header
106 107 %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
107 108 %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
108 109 %h4 Compiler message
109 110 .modal-body
110 111 %pre#compiler_msg= @submission.compiler_message
111 112 .modal-footer
112 113 %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
@@ -1,45 +1,54
1 1 .container-fluid
2 2 .row
3 3 .col-md-6
4 4 %h1 Adding list of users
5 5 .row
6 6 .col-md-6
7 7 .panel.panel-default
8 8 .panel-heading
9 9 .panel-title Info
10 10 .panel-body
11 11 %ul
12 12 %li
13 13 List of user information in this format:
14 14 %tt user_id,name(,passwd(,alias(,remark)))
15 15 %li
16 16 Note that
17 17 %tt passwd, alias
18 18 and
19 19 %tt remark
20 20 is optional.
21 21 %li
22 22 When
23 23 %tt passwd
24 24 or
25 25 %tt alias
26 26 is empty, the original value will be used instead.
27 27 %li
28 28 If the users with the same user_id already exists, existing information will be overwritten.
29 + Example:
30 + %ol
31 + %li
32 + %pre user1,Somchai Jaidee
33 + will create (or update) a user with login "user1" and setting the fullname to "Somchai Jaidee", also setting a random password.
34 + %li
35 + %pre user1,Somchai Jaidee,
36 + will create (or update) a user with login "user1" and and setting the fullname "Somchai Jaidee". No change is made to the password unless this is a new user. If this is a new user, a random password will be generated.
37 +
29 38
30 39 .row
31 40 .col-md-6
32 41 = form_tag :action => 'create_from_list' do
33 42 .form-group
34 43 = submit_tag 'Create following users',class: 'btn btn-success'
35 44 .form-group
36 45 .div.checkbox
37 46 %label
38 47 = check_box_tag :add_to_group
39 48 Also add these users to the following group
40 49 = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
41 50 .form-group
42 51 = text_area_tag 'user_list', nil, :rows => 50, :cols => 80
43 52 .col-md-6
44 53
45 54
@@ -1,204 +1,204
1 1 Rails.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 resources :contests
11 11 resources :sites
12 12 resources :test
13 13
14 14 resources :messages do
15 15 member do
16 16 get 'hide'
17 17 post 'reply'
18 18 end
19 19 collection do
20 20 get 'console'
21 21 get 'list_all'
22 22 end
23 23 end
24 24
25 25 resources :announcements do
26 26 member do
27 27 get 'toggle','toggle_front'
28 28 end
29 29 end
30 30
31 31 resources :problems do
32 32 member do
33 33 get 'toggle'
34 34 get 'toggle_test'
35 35 get 'toggle_view_testcase'
36 36 get 'stat'
37 37 end
38 38 collection do
39 39 get 'turn_all_off'
40 40 get 'turn_all_on'
41 41 get 'import'
42 42 get 'manage'
43 43 get 'quick_create'
44 44 post 'do_manage'
45 45 post 'do_import'
46 46 end
47 47 end
48 48
49 49 resources :groups do
50 50 member do
51 51 post 'add_user', to: 'groups#add_user', as: 'add_user'
52 52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
53 53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
54 54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
55 55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
56 56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
57 57 get 'toggle'
58 58 end
59 59 collection do
60 60
61 61 end
62 62 end
63 63
64 64 resources :testcases, only: [] do
65 65 member do
66 66 get 'download_input'
67 67 get 'download_sol'
68 68 end
69 69 collection do
70 70 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
71 71 end
72 72 end
73 73
74 74 resources :grader_configuration, controller: 'configurations' do
75 75 collection do
76 76 get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right'
77 77 end
78 78 end
79 79
80 80 resources :users do
81 81 member do
82 82 get 'toggle_activate', 'toggle_enable'
83 83 get 'stat'
84 84 end
85 85 collection do
86 86 get 'profile'
87 87 post 'chg_passwd'
88 88 end
89 89 end
90 90
91 91 resources :submissions do
92 92 member do
93 93 get 'download'
94 94 get 'compiler_msg'
95 95 get 'rejudge'
96 96 end
97 97 collection do
98 98 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
99 99 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
100 100 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
101 101 end
102 102 end
103 103
104 104
105 105 #user admin
106 106 resources :user_admin do
107 107 collection do
108 108 match 'bulk_manage', via: [:get, :post]
109 109 get 'bulk_mail'
110 110 get 'user_stat'
111 111 get 'import'
112 112 get 'new_list'
113 113 get 'admin'
114 114 get 'active'
115 115 get 'mass_mailing'
116 116 get 'revoke_admin'
117 117 post 'grant_admin'
118 118 match 'create_from_list', via: [:get, :post]
119 119 match 'random_all_passwords', via: [:get, :post]
120 120 end
121 121 member do
122 122 get 'clear_last_ip'
123 123 end
124 124 end
125 125
126 126 resources :contest_management, only: [:index] do
127 127 collection do
128 128 get 'user_stat'
129 129 get 'clear_stat'
130 130 get 'clear_all_stat'
131 131 get 'change_contest_mode'
132 132 end
133 133 end
134 134
135 135 #get 'user_admin', to: 'user_admin#index'
136 136 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
137 137 #post 'user_admin', to: 'user_admin#create'
138 138 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
139 139
140 140 #singular resource
141 141 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
142 142 #report
143 143 resource :report, only: [], controller: 'report' do
144 144 get 'login'
145 145 get 'multiple_login'
146 146 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
147 147 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
148 148 get 'max_score'
149 149 post 'show_max_score'
150 150 get 'stuck'
151 151 get 'cheat_report'
152 152 post 'cheat_report'
153 153 get 'cheat_scruntinize'
154 154 post 'cheat_scruntinize'
155 155 end
156 156 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
157 157 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
158 158 #get "report/login"
159 159 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
160 160 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
161 161
162 162 resource :main, only: [], controller: 'main' do
163 163 get 'login'
164 164 get 'logout'
165 165 get 'list'
166 166 get 'submission(/:id)', action: 'submission', as: 'main_submission'
167 167 get 'announcements'
168 168 get 'help'
169 169 post 'submit'
170 170 end
171 171 #main
172 172 #get "main/list"
173 173 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
174 174 #post 'main/submit', to: 'main#submit'
175 175 #get 'main/announcements', to: 'main#announcements'
176 176
177 177
178 178 #
179 179 get 'tasks/view/:file.:ext' => 'tasks#view'
180 - get 'tasks/download/:id/:file.:ext' => 'tasks#download'
180 + get 'tasks/download/:id/:file.:ext' => 'tasks#download', as: 'download_task'
181 181 get 'heartbeat/:id/edit' => 'heartbeat#edit'
182 182
183 183 #grader
184 184 get 'graders/list', to: 'graders#list', as: 'grader_list'
185 185 namespace :graders do
186 186 get 'task/:id/:type', action: 'task', as: 'task'
187 187 get 'view/:id/:type', action: 'view', as: 'view'
188 188 get 'clear/:id', action: 'clear', as: 'clear'
189 189 get 'stop'
190 190 get 'stop_all'
191 191 get 'clear_all'
192 192 get 'clear_terminated'
193 193 get 'start_grading'
194 194 get 'start_exam'
195 195
196 196 end
197 197
198 198
199 199 # See how all your routes lay out with "rake routes"
200 200
201 201 # This is a legacy wild controller route that's not recommended for RESTful applications.
202 202 # Note: This route will make all actions in every controller accessible via GET requests.
203 203 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
204 204 end
You need to be logged in to leave comments. Login now