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

r836:36fbb20457ec - - 8 files changed: 94 inserted, 60 deleted

@@ -1,112 +1,111
1 1 class SubmissionsController < ApplicationController
2 2 before_action :check_valid_login
3 3 before_action :submission_authorization, only: [:show, :download, :edit]
4 4 before_action :admin_authorization, only: [:rejudge]
5 5
6 6 # GET /submissions
7 7 # GET /submissions.json
8 8 # Show problem selection and user's submission of that problem
9 9 def index
10 10 @user = @current_user
11 11 @problems = @user.available_problems
12 12
13 13 if params[:problem_id]==nil
14 14 @problem = nil
15 15 @submissions = nil
16 16 else
17 17 @problem = Problem.find_by_id(params[:problem_id])
18 18 if (@problem == nil) or (not @problem.available)
19 19 redirect_to list_main_path
20 20 flash[:error] = 'Authorization error: You have no right to view submissions for this problem'
21 21 return
22 22 end
23 23 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
24 24 end
25 25 end
26 26
27 27 # GET /submissions/1
28 28 # GET /submissions/1.json
29 29 def show
30 30 @submission = Submission.find(params[:id])
31 31
32 32 #log the viewing
33 33 user = User.find(session[:user_id])
34 34 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
35 35
36 36 @task = @submission.task
37 37 end
38 38
39 39 def download
40 40 @submission = Submission.find(params[:id])
41 41 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
42 42 end
43 43
44 44 def compiler_msg
45 45 @submission = Submission.find(params[:id])
46 46 respond_to do |format|
47 47 format.js
48 48 end
49 49 end
50 50
51 51 #on-site new submission on specific problem
52 52 def direct_edit_problem
53 53 @problem = Problem.find(params[:problem_id])
54 54 unless @current_user.can_view_problem?(@problem)
55 55 unauthorized_redirect
56 56 return
57 57 end
58 58 @source = ''
59 59 if (params[:view_latest])
60 60 sub = Submission.find_last_by_user_and_problem(@current_user.id,@problem.id)
61 61 @source = @submission.source.to_s if @submission and @submission.source
62 62 end
63 63 render 'edit'
64 64 end
65 65
66 66 # GET /submissions/1/edit
67 67 def edit
68 68 @submission = Submission.find(params[:id])
69 69 @source = @submission.source.to_s
70 70 @problem = @submission.problem
71 71 @lang_id = @submission.language.id
72 72 end
73 73
74 74
75 75 def get_latest_submission_status
76 76 @problem = Problem.find(params[:pid])
77 77 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
78 78 respond_to do |format|
79 79 format.js
80 80 end
81 81 end
82 82
83 83 # GET /submissions/:id/rejudge
84 84 def rejudge
85 85 @submission = Submission.find(params[:id])
86 86 @task = @submission.task
87 87 @task.status_inqueue! if @task
88 88 respond_to do |format|
89 89 format.js
90 90 end
91 91 end
92 92
93 93 protected
94 94
95 95 def submission_authorization
96 96 #admin always has privileged
97 - if @current_user.admin?
98 - return true
99 - end
97 + return true if @current_user.admin?
98 + return true if @current_user.has_role?('TA') && (['show','download'].include? action_name)
100 99
101 100 sub = Submission.find(params[:id])
102 101 if @current_user.available_problems.include? sub.problem
103 102 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
104 103 end
105 104
106 105 #default to NO
107 106 unauthorized_redirect
108 107 return false
109 108 end
110 109
111 110
112 111 end
@@ -262,222 +262,219
262 262 flash[:notice] = 'Error: no contest'
263 263 redirect_to :action => 'contests', :id =>contest_id
264 264 end
265 265
266 266 note = []
267 267 users.each do |u|
268 268 u.contests = [contest]
269 269 note << u.login
270 270 end
271 271 flash[:notice] = 'User(s) ' + note.join(', ') +
272 272 " were successfully reassigned to #{contest.title}."
273 273 redirect_to :action => 'contests', :id =>contest.id
274 274 end
275 275
276 276 def add_to_contest
277 277 user = User.find(params[:id])
278 278 contest = Contest.find(params[:contest_id])
279 279 if user and contest
280 280 user.contests << contest
281 281 end
282 282 redirect_to :action => 'index'
283 283 end
284 284
285 285 def remove_from_contest
286 286 user = User.find(params[:id])
287 287 contest = Contest.find(params[:contest_id])
288 288 if user and contest
289 289 user.contests.delete(contest)
290 290 end
291 291 redirect_to :action => 'index'
292 292 end
293 293
294 294 def contest_management
295 295 end
296 296
297 297 def manage_contest
298 298 contest = Contest.find(params[:contest][:id])
299 299 if !contest
300 300 flash[:notice] = 'You did not choose the contest.'
301 301 redirect_to :action => 'contest_management' and return
302 302 end
303 303
304 304 operation = params[:operation]
305 305
306 306 if not ['add','remove','assign'].include? operation
307 307 flash[:notice] = 'You did not choose the operation to perform.'
308 308 redirect_to :action => 'contest_management' and return
309 309 end
310 310
311 311 lines = params[:login_list]
312 312 if !lines or lines.blank?
313 313 flash[:notice] = 'You entered an empty list.'
314 314 redirect_to :action => 'contest_management' and return
315 315 end
316 316
317 317 note = []
318 318 users = []
319 319 lines.split("\n").each do |line|
320 320 user = User.find_by_login(line.chomp)
321 321 if user
322 322 if operation=='add'
323 323 if ! user.contests.include? contest
324 324 user.contests << contest
325 325 end
326 326 elsif operation=='remove'
327 327 user.contests.delete(contest)
328 328 else
329 329 user.contests = [contest]
330 330 end
331 331
332 332 if params[:reset_timer]
333 333 user.contest_stat.forced_logout = true
334 334 user.contest_stat.reset_timer_and_save
335 335 end
336 336
337 337 if params[:notification_emails]
338 338 send_contest_update_notification_email(user, contest)
339 339 end
340 340
341 341 note << user.login
342 342 users << user
343 343 end
344 344 end
345 345
346 346 if params[:reset_timer]
347 347 logout_users(users)
348 348 end
349 349
350 350 flash[:notice] = 'User(s) ' + note.join(', ') +
351 351 ' were successfully modified. '
352 352 redirect_to :action => 'contest_management'
353 353 end
354 354
355 355 # admin management
356 356
357 357 def admin
358 - @admins = User.all.find_all {|user| user.admin? }
358 + @admins = Role.where(name: 'admin').take.users
359 + @tas = Role.where(name: 'ta').take.users
359 360 end
360 361
361 - def grant_admin
362 - login = params[:login]
363 - user = User.find_by_login(login)
364 - if user!=nil
365 - admin_role = Role.find_by_name('admin')
366 - user.roles << admin_role
367 - else
368 - flash[:notice] = 'Unknown user'
369 - end
370 - flash[:notice] = 'User added as admins'
371 - redirect_to :action => 'admin'
362 + def modify_role
363 + user = User.find_by_login(params[:login])
364 + role = Role.find_by_name(params[:role])
365 + unless user && role
366 + flash[:error] = 'Unknown user or role'
367 + redirect_to admin_user_admin_index_path
368 + return
372 369 end
373 -
374 - def revoke_admin
375 - user = User.find(params[:id])
376 - if user==nil
377 - flash[:notice] = 'Unknown user'
378 - redirect_to :action => 'admin' and return
379 - elsif user.login == 'root'
380 - flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
381 - redirect_to :action => 'admin' and return
370 + if params[:commit] == 'Grant'
371 + #grant role
372 + user.roles << role
373 + flash[:notice] = "User '#{user.login}' has been granted the role '#{role.name}'"
374 + else
375 + #revoke role
376 + if user.login == 'root' && role.name == 'admin'
377 + flash[:error] = 'You cannot revoke admisnistrator permission from root.'
378 + redirect_to admin_user_admin_index_path
379 + return
382 380 end
383 -
384 - admin_role = Role.find_by_name('admin')
385 - user.roles.delete(admin_role)
386 - flash[:notice] = 'User permission revoked'
387 - redirect_to :action => 'admin'
381 + user.roles.delete(role)
382 + flash[:notice] = "The role '#{role.name}' has been revoked from User '#{user.login}'"
383 + end
384 + redirect_to admin_user_admin_index_path
388 385 end
389 386
390 387 # mass mailing
391 388
392 389 def mass_mailing
393 390 end
394 391
395 392 def bulk_mail
396 393 lines = params[:login_list]
397 394 if !lines or lines.blank?
398 395 flash[:notice] = 'You entered an empty list.'
399 396 redirect_to :action => 'mass_mailing' and return
400 397 end
401 398
402 399 mail_subject = params[:subject]
403 400 if !mail_subject or mail_subject.blank?
404 401 flash[:notice] = 'You entered an empty mail subject.'
405 402 redirect_to :action => 'mass_mailing' and return
406 403 end
407 404
408 405 mail_body = params[:email_body]
409 406 if !mail_body or mail_body.blank?
410 407 flash[:notice] = 'You entered an empty mail body.'
411 408 redirect_to :action => 'mass_mailing' and return
412 409 end
413 410
414 411 note = []
415 412 users = []
416 413 lines.split("\n").each do |line|
417 414 user = User.find_by_login(line.chomp)
418 415 if user
419 416 send_mail(user.email, mail_subject, mail_body)
420 417 note << user.login
421 418 end
422 419 end
423 420
424 421 flash[:notice] = 'User(s) ' + note.join(', ') +
425 422 ' were successfully modified. '
426 423 redirect_to :action => 'mass_mailing'
427 424 end
428 425
429 426 #bulk manage
430 427 def bulk_manage
431 428
432 429 begin
433 430 @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
434 431 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
435 432 rescue Exception
436 433 flash[:error] = 'Regular Expression is malformed'
437 434 @users = nil
438 435 end
439 436
440 437 if params[:commit]
441 438 @action = {}
442 439 @action[:set_enable] = params[:enabled]
443 440 @action[:enabled] = params[:enable] == "1"
444 441 @action[:gen_password] = params[:gen_password]
445 442 @action[:add_group] = params[:add_group]
446 443 @action[:group_name] = params[:group_name]
447 444 end
448 445
449 446 if params[:commit] == "Perform"
450 447 if @action[:set_enable]
451 448 @users.update_all(enabled: @action[:enabled])
452 449 end
453 450 if @action[:gen_password]
454 451 @users.each do |u|
455 452 password = random_password
456 453 u.password = password
457 454 u.password_confirmation = password
458 455 u.save
459 456 end
460 457 end
461 458 if @action[:add_group] and @action[:group_name]
462 459 @group = Group.find(@action[:group_name])
463 460 ok = []
464 461 failed = []
465 462 @users.each do |user|
466 463 begin
467 464 @group.users << user
468 465 ok << user.login
469 466 rescue => e
470 467 failed << user.login
471 468 end
472 469 end
473 470 flash[:success] = "The following users are added to the 'group #{@group.name}': " + ok.join(', ') if ok.count > 0
474 471 flash[:alert] = "The following users are already in the 'group #{@group.name}': " + failed.join(', ') if failed.count > 0
475 472 end
476 473 end
477 474 end
478 475
479 476 protected
480 477
481 478 def random_password(length=5)
482 479 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
483 480 newpass = ""
@@ -31,193 +31,197
31 31
32 32 has_and_belongs_to_many :contests, -> { order(:name)}
33 33
34 34 scope :activated_users, -> {where activated: true}
35 35
36 36 validates_presence_of :login
37 37 validates_uniqueness_of :login
38 38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
39 39 validates_length_of :login, :within => 3..30
40 40
41 41 validates_presence_of :full_name
42 42 validates_length_of :full_name, :minimum => 1
43 43
44 44 validates_presence_of :password, :if => :password_required?
45 45 validates_length_of :password, :within => 4..50, :if => :password_required?
46 46 validates_confirmation_of :password, :if => :password_required?
47 47
48 48 validates_format_of :email,
49 49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
50 50 :if => :email_validation?
51 51 validate :uniqueness_of_email_from_activated_users,
52 52 :if => :email_validation?
53 53 validate :enough_time_interval_between_same_email_registrations,
54 54 :if => :email_validation?
55 55
56 56 # these are for ytopc
57 57 # disable for now
58 58 #validates_presence_of :province
59 59
60 60 attr_accessor :password
61 61
62 62 before_save :encrypt_new_password
63 63 before_save :assign_default_site
64 64 before_save :assign_default_contest
65 65
66 66 # this is for will_paginate
67 67 cattr_reader :per_page
68 68 @@per_page = 50
69 69
70 70 def self.authenticate(login, password)
71 71 user = find_by_login(login)
72 72 if user
73 73 return user if user.authenticated?(password)
74 74 if user.authenticated_by_cucas?(password)
75 75 user.password = password
76 76 user.save
77 77 return user
78 78 end
79 79 end
80 80 end
81 81
82 82
83 83 def authenticated?(password)
84 84 if self.activated
85 85 hashed_password == User.encrypt(password,self.salt)
86 86 else
87 87 false
88 88 end
89 89 end
90 90
91 91 def authenticated_by_cucas?(password)
92 92 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
93 93 appid = '41508763e340d5858c00f8c1a0f5a2bb'
94 94 appsecret ='d9cbb5863091dbe186fded85722a1e31'
95 95 post_args = {
96 96 'appid' => appid,
97 97 'appsecret' => appsecret,
98 98 'username' => login,
99 99 'password' => password
100 100 }
101 101
102 102 #simple call
103 103 begin
104 104 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
105 105 http.use_ssl = true
106 106 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
107 107 result = [ ]
108 108 http.start do |http|
109 109 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
110 110 #req = Net::HTTP::Post.new('/appX/prod/?q=studentAuthenticate')
111 111 #req = Net::HTTP::Post.new('/app2/prod/api/?q=studentAuthenticate')
112 112 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
113 113 resp = http.request(req,param)
114 114 result = JSON.parse resp.body
115 115 puts result
116 116 end
117 117 return true if result["type"] == "beanStudent"
118 118 rescue => e
119 119 puts e
120 120 puts e.message
121 121 return false
122 122 end
123 123 return false
124 124 end
125 125
126 126 def admin?
127 - self.roles.where(name: 'admin').count > 0
127 + has_role?('admin')
128 + end
129 +
130 + def has_role?(role)
131 + self.roles.where(name: role).count > 0
128 132 end
129 133
130 134 def email_for_editing
131 135 if self.email==nil
132 136 "(unknown)"
133 137 elsif self.email==''
134 138 "(blank)"
135 139 else
136 140 self.email
137 141 end
138 142 end
139 143
140 144 def email_for_editing=(e)
141 145 self.email=e
142 146 end
143 147
144 148 def alias_for_editing
145 149 if self.alias==nil
146 150 "(unknown)"
147 151 elsif self.alias==''
148 152 "(blank)"
149 153 else
150 154 self.alias
151 155 end
152 156 end
153 157
154 158 def alias_for_editing=(e)
155 159 self.alias=e
156 160 end
157 161
158 162 def activation_key
159 163 if self.hashed_password==nil
160 164 encrypt_new_password
161 165 end
162 166 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
163 167 end
164 168
165 169 def verify_activation_key(key)
166 170 key == activation_key
167 171 end
168 172
169 173 def self.random_password(length=5)
170 174 chars = 'abcdefghjkmnopqrstuvwxyz'
171 175 password = ''
172 176 length.times { password << chars[rand(chars.length - 1)] }
173 177 password
174 178 end
175 179
176 180 def self.find_non_admin_with_prefix(prefix='')
177 181 users = User.all
178 182 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
179 183 end
180 184
181 185 # Contest information
182 186
183 187 def self.find_users_with_no_contest()
184 188 users = User.all
185 189 return users.find_all { |u| u.contests.length == 0 }
186 190 end
187 191
188 192
189 193 def contest_time_left
190 194 if GraderConfiguration.contest_mode?
191 195 return nil if site==nil
192 196 return site.time_left
193 197 elsif GraderConfiguration.indv_contest_mode?
194 198 time_limit = GraderConfiguration.contest_time_limit
195 199 if time_limit == nil
196 200 return nil
197 201 end
198 202 if contest_stat==nil or contest_stat.started_at==nil
199 203 return (Time.now.gmtime + time_limit) - Time.now.gmtime
200 204 else
201 205 finish_time = contest_stat.started_at + time_limit
202 206 current_time = Time.now.gmtime
203 207 if current_time > finish_time
204 208 return 0
205 209 else
206 210 return finish_time - current_time
207 211 end
208 212 end
209 213 else
210 214 return nil
211 215 end
212 216 end
213 217
214 218 def contest_finished?
215 219 if GraderConfiguration.contest_mode?
216 220 return false if site==nil
217 221 return site.finished?
218 222 elsif GraderConfiguration.indv_contest_mode?
219 223 return false if self.contest_stat==nil
220 224 return contest_time_left == 0
221 225 else
222 226 return false
223 227 end
@@ -1,96 +1,96
1 1 %header.navbar.navbar-default.navbar-fixed-top
2 2 %nav
3 3 .container-fluid
4 4 .navbar-header
5 5 %button.navbar-toggle.collapsed{ data: {toggle: 'collapse', target: '#navbar-collapse'} }
6 6 %span.sr-only Togggle Navigation
7 7 %span.icon-bar
8 8 %span.icon-bar
9 9 %span.icon-bar
10 10 %a.navbar-brand{href: list_main_path}
11 11 %span.glyphicon.glyphicon-home
12 12 MAIN
13 13 .collapse.navbar-collapse#navbar-collapse
14 14 %ul.nav.navbar-nav
15 15 / submission
16 16 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
17 17 %li.dropdown
18 18 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
19 19 = "#{I18n.t 'menu.submissions'}"
20 20 %span.caret
21 21 %ul.dropdown-menu
22 22 = add_menu("View", 'submissions', 'index')
23 23 = add_menu("Self Test", 'test', 'index')
24 24 / hall of fame
25 25 - if GraderConfiguration['right.user_hall_of_fame']
26 26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
27 27 / display MODE button (with countdown in contest mode)
28 28 - if GraderConfiguration.analysis_mode?
29 29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
30 30 - elsif GraderConfiguration.time_limit_mode?
31 31 - if @current_user.contest_finished?
32 32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
33 33 - elsif !@current_user.contest_started?
34 34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
35 35 - else
36 36 %div.navbar-btn.btn.btn-primary#countdown asdf
37 37 :javascript
38 38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
39 39 / admin section
40 40 - if (@current_user!=nil) and (session[:admin])
41 41 / management
42 42 %li.dropdown
43 43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
44 44 Manage
45 45 %span.caret
46 46 %ul.dropdown-menu
47 47 = add_menu( 'Announcements', 'announcements', 'index')
48 48 = add_menu( 'Problems', 'problems', 'index')
49 49 = add_menu( 'Tags', 'tags', 'index')
50 50 = add_menu( 'Users', 'user_admin', 'index')
51 51 = add_menu( 'User Groups', 'groups', 'index')
52 52 = add_menu( 'Graders', 'graders', 'list')
53 53 = add_menu( 'Message ', 'messages', 'console')
54 54 %li.divider{role: 'separator'}
55 55 = add_menu( 'System config', 'configurations', 'index')
56 56 %li.divider{role: 'separator'}
57 57 = add_menu( 'Sites', 'sites', 'index')
58 58 = add_menu( 'Contests', 'contest_management', 'index')
59 59 / report
60 60 %li.dropdown
61 61 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
62 62 Report
63 63 %span.caret
64 64 %ul.dropdown-menu
65 65 = add_menu( 'Current Score', 'report', 'current_score')
66 66 = add_menu( 'Score Report', 'report', 'max_score')
67 67 = add_menu( 'Submission Report', 'report', 'submission')
68 68 = add_menu( 'Login Report', 'report', 'login')
69 69 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
70 70 =link_to "#{ungraded} backlogs!",
71 - grader_list_path,
71 + graders_list_path,
72 72 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
73 73
74 74 %ul.nav.navbar-nav.navbar-right
75 75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
76 76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'index', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
77 77 - if GraderConfiguration['system.user_setting_enabled']
78 78 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog', id: 'user_profile')}".html_safe, 'users', 'profile', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
79 79 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
80 80
81 81 /
82 82 - if (@current_user!=nil) and (session[:admin])
83 83 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
84 84 .container-fluid
85 85 .collapse.navbar-collapse
86 86 %ul.nav.navbar-nav
87 87 = add_menu( '[Announcements]', 'announcements', 'index')
88 88 = add_menu( '[Msg console]', 'messages', 'console')
89 89 = add_menu( '[Problems]', 'problems', 'index')
90 90 = add_menu( '[Users]', 'user_admin', 'index')
91 91 = add_menu( '[Results]', 'user_admin', 'user_stat')
92 92 = add_menu( '[Report]', 'report', 'multiple_login')
93 93 = add_menu( '[Graders]', 'graders', 'list')
94 94 = add_menu( '[Contests]', 'contest_management', 'index')
95 95 = add_menu( '[Sites]', 'sites', 'index')
96 96 = add_menu( '[System config]', 'configurations', 'index')
@@ -1,59 +1,63
1 1 :css
2 2 .fix-width {
3 3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
4 4 }
5 5
6 6 %h1 Problem stat: #{@problem.name}
7 7 %h2 Overview
8 8
9 + .row
10 + .col-md-2
11 + %strong Name:
12 + .col-md-10
13 + = @problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1
14 + = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem
15 + .row
16 + .col-md-2.strong
17 + %strong Submissions:
18 + .col-md-10
19 + = @submissions.count
20 + .row
21 + .col-md-2.strong
22 + %strong Solved/Attemped User
23 + .col-md-10
24 + #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
9 25
10 - %table.info
11 - %thead
12 - %tr.info-head
13 - %th Stat
14 - %th Value
15 - %tbody
16 - %tr{class: cycle('info-even','info-odd')}
17 - %td Submissions
18 - %td= @submissions.count
19 - %tr{class: cycle('info-even','info-odd')}
20 - %td Solved/Attempted User
21 - %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
22 26
23 27 %h2 Submissions Count
24 28 = render partial: 'application/bar_graph', locals: { histogram: @histogram }
25 29
26 30 %h2 Submissions
27 31 - if @submissions and @submissions.count > 0
28 32 %table#main_table.table.table-condensed.table-striped
29 33 %thead
30 34 %tr
31 35 %th ID
32 36 %th Login
33 37 %th Name
34 38 %th Submitted_at
35 39 %th language
36 40 %th Points
37 41 %th comment
38 42 %th IP
39 43 %tbody
40 44 - row_odd,curr = true,''
41 45 - @submissions.each do |sub|
42 46 - next unless sub.user
43 47 - row_odd,curr = !row_odd, sub.user if curr != sub.user
44 48 %tr
45 49 %td= link_to sub.id, submission_path(sub)
46 50 %td= link_to sub.user.login, stat_user_path(sub.user)
47 51 %td= sub.user.full_name
48 52 %td{data: {order: sub.submitted_at}}= time_ago_in_words(sub.submitted_at) + " ago"
49 53 %td= sub.language.name
50 54 %td= sub.points
51 55 %td.fix-width= sub.grader_comment
52 56 %td= sub.ip_address
53 57 - else
54 58 No submission
55 59
56 60 :javascript
57 61 $("#main_table").DataTable({
58 62 paging: false
59 63 });
@@ -1,25 +1,54
1 - %h1 Administrators
2 -
3 - %table{:class => 'info'}
4 - %tr{:class => 'info-head'}
1 + %h1 Modify Role
2 + .row
3 + .col-md-6
4 + %h4 Administrators
5 + = form_tag modify_role_user_admin_index_path, method: 'post', class: 'form-inline' do
6 + = hidden_field_tag :role, 'admin'
7 + .form-group
8 + = label_tag :login, 'Grant admin role to:'
9 + = text_field_tag 'login',nil, class: 'form-control'
10 + .form-group
11 + = submit_tag 'Grant', class: 'btn btn-primary'
12 + %br
13 + %table.table.table-condense.table-hover.table-striped.table-bordered
14 + %thead{:class => 'info-head'}
5 15 %th #
6 16 %th Login
7 17 %th Full name
8 18 %th
9 19 - @admins.each_with_index do |user, i|
10 20 %tr
11 21 %td= i+1
12 22 %td= user.login
13 23 %td= user.full_name
14 24 %td
15 25 - if user.login!='root'
16 - = link_to '[revoke]', :action => 'revoke_admin', :id => user.id
17 - %hr
26 + = link_to '[revoke]', modify_role_user_admin_index_path( login: user.login, role: 'admin', commit: 'revoke')
27 + .col-md-6
28 + %h4 Teacher Assistants (TA)
29 + = form_tag modify_role_user_admin_index_path, method: 'post', class: 'form-inline' do
30 + = hidden_field_tag :role, 'TA'
31 + .form-group
32 + = label_tag :login, 'Grant TA role to:'
33 + = text_field_tag 'login',nil, class: 'form-control'
34 + .form-group
35 + = submit_tag 'Grant', class: 'btn btn-primary'
36 + %br
37 + %table.table.table-condense.table-hover.table-striped.table-bordered
38 + %thead{:class => 'info-head'}
39 + %th #
40 + %th Login
41 + %th Full name
42 + %th
43 + - @tas.each_with_index do |user, i|
44 + %tr
45 + %td= i+1
46 + %td= user.login
47 + %td= user.full_name
48 + %td
49 + - if user.login!='root'
50 + = link_to '[revoke]', modify_role_user_admin_index_path( login: user.login, role: 'TA', commit: 'revoke')
18 51
19 - = form_tag :action => 'grant_admin' do
20 - = label_tag :login, 'Grant admin permission to:'
21 - = text_field_tag 'login',nil, class: 'input-field'
22 - = submit_tag 'Grant', class: 'btn btn-primary'
23 52
24 53 %hr/
25 54 = link_to '[go back to index]', :action => 'index'
@@ -20,192 +20,192
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 - get 'revoke_admin'
117 - post 'grant_admin'
116 + match 'modify_role', via: [:get, :post]
118 117 match 'create_from_list', via: [:get, :post]
119 118 match 'random_all_passwords', via: [:get, :post]
120 119 end
121 120 member do
122 121 get 'clear_last_ip'
123 122 end
124 123 end
125 124
126 125 resources :contest_management, only: [:index] do
127 126 collection do
128 127 get 'user_stat'
129 128 get 'clear_stat'
130 129 get 'clear_all_stat'
131 130 get 'change_contest_mode'
132 131 end
133 132 end
134 133
135 134 #get 'user_admin', to: 'user_admin#index'
136 135 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
137 136 #post 'user_admin', to: 'user_admin#create'
138 137 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
139 138
140 139 #singular resource
141 140 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
142 141 #report
143 142 resource :report, only: [], controller: 'report' do
144 143 get 'login'
145 144 get 'multiple_login'
146 145 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
147 146 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
148 147 get 'max_score'
149 148 post 'show_max_score'
150 149 get 'stuck'
151 150 get 'cheat_report'
152 151 post 'cheat_report'
153 152 get 'cheat_scrutinize'
154 153 post 'cheat_scrutinize'
155 154 get 'submission'
156 155 post 'submission_query'
157 156 get 'login_stat'
158 157 post 'login_stat'
159 158 get 'login'
160 159 post 'login_summary_query'
161 160 post 'login_detail_query'
162 161 end
163 162 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
164 163 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
165 164 #get "report/login"
166 165 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
167 166 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
168 167
169 168 resource :main, only: [], controller: 'main' do
170 169 get 'login'
171 170 get 'logout'
172 171 get 'list'
173 172 get 'submission(/:id)', action: 'submission', as: 'main_submission'
174 173 get 'announcements'
175 174 get 'help'
176 175 post 'submit'
177 176 end
178 177 #main
179 178 #get "main/list"
180 179 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
181 180 #post 'main/submit', to: 'main#submit'
182 181 #get 'main/announcements', to: 'main#announcements'
183 182
184 183
185 184 #
186 185 get 'tasks/view/:file.:ext' => 'tasks#view'
187 186 get 'tasks/download/:id/:file.:ext' => 'tasks#download', as: 'download_task'
188 187 get 'heartbeat/:id/edit' => 'heartbeat#edit'
189 188
190 189 #grader
191 - get 'graders/list', to: 'graders#list', as: 'grader_list'
190 + #get 'graders/list', to: 'graders#list', as: 'grader_list'
192 191 namespace :graders do
193 192 get 'task/:id/:type', action: 'task', as: 'task'
194 193 get 'view/:id/:type', action: 'view', as: 'view'
195 194 get 'clear/:id', action: 'clear', as: 'clear'
196 - get 'stop'
197 - get 'stop_all'
198 - get 'clear_all'
199 - get 'clear_terminated'
200 195 get 'start_grading'
201 196 get 'start_exam'
197 + get 'clear_all'
198 + get 'stop_all'
202 199
200 + get 'stop'
201 + get 'clear_terminated'
202 + get 'list'
203 203 end
204 204
205 205
206 206 # See how all your routes lay out with "rake routes"
207 207
208 208 # This is a legacy wild controller route that's not recommended for RESTful applications.
209 209 # Note: This route will make all actions in every controller accessible via GET requests.
210 210 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
211 211 end
@@ -132,157 +132,158
132 132 },
133 133
134 134 {
135 135 :key => 'system.user_setting_enabled',
136 136 :value_type => 'boolean',
137 137 :default_value => 'true',
138 138 :description => 'If this option is true, users can change their settings'
139 139 },
140 140
141 141 {
142 142 :key => 'system.user_setting_enabled',
143 143 :value_type => 'boolean',
144 144 :default_value => 'true',
145 145 :description => 'If this option is true, users can change their settings'
146 146 },
147 147
148 148 # If Configuration['contest.test_request.early_timeout'] is true
149 149 # the user will not be able to use test request at 30 minutes
150 150 # before the contest ends.
151 151 {
152 152 :key => 'contest.test_request.early_timeout',
153 153 :value_type => 'boolean',
154 154 :default_value => 'false'
155 155 },
156 156
157 157 {
158 158 :key => 'system.multicontests',
159 159 :value_type => 'boolean',
160 160 :default_value => 'false'
161 161 },
162 162
163 163 {
164 164 :key => 'contest.confirm_indv_contest_start',
165 165 :value_type => 'boolean',
166 166 :default_value => 'false'
167 167 },
168 168
169 169 {
170 170 :key => 'contest.default_contest_name',
171 171 :value_type => 'string',
172 172 :default_value => 'none',
173 173 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
174 174 },
175 175
176 176 {
177 177 :key => 'system.use_problem_group',
178 178 :value_type => 'boolean',
179 179 :default_value => 'false',
180 180 :description => "If true, available problem to the user will be only ones associated with the group of the user."
181 181 },
182 182
183 183
184 184 {
185 185 :key => 'right.whitelist_ignore',
186 186 :value_type => 'boolean',
187 187 :default_value => 'true',
188 188 :description => "If true, no IP check against whitelist_ip is perform. However, when false, non-admin user must have their ip in 'whitelist_ip' to be able to login."
189 189 },
190 190
191 191 {
192 192 :key => 'right.whitelist_ip',
193 193 :value_type => 'string',
194 194 :default_value => '0.0.0.0/0',
195 195 :description => "list of whitelist ip, given in comma separated CIDR notation. For example '192.168.90.0/23, 192.168.1.23/32'"
196 196 },
197 197
198 198 ]
199 199
200 200
201 201 def create_configuration_key(key,
202 202 value_type,
203 203 default_value,
204 204 description='')
205 205 conf = (GraderConfiguration.find_by_key(key) ||
206 206 GraderConfiguration.new(:key => key,
207 207 :value_type => value_type,
208 208 :value => default_value))
209 209 conf.description = description
210 210 conf.save
211 211 end
212 212
213 213 def seed_config
214 214 CONFIGURATIONS.each do |conf|
215 215 if conf.has_key? :description
216 216 desc = conf[:description]
217 217 else
218 218 desc = ''
219 219 end
220 220 create_configuration_key(conf[:key],
221 221 conf[:value_type],
222 222 conf[:default_value],
223 223 desc)
224 224 end
225 225 end
226 226
227 227 def seed_roles
228 + Role.find_or_create_by(name: 'TA')
228 229 return if Role.find_by_name('admin')
229 230
230 231 role = Role.create(:name => 'admin')
231 232 user_admin_right = Right.create(:name => 'user_admin',
232 233 :controller => 'user_admin',
233 234 :action => 'all')
234 235 problem_admin_right = Right.create(:name=> 'problem_admin',
235 236 :controller => 'problems',
236 237 :action => 'all')
237 238
238 239 graders_right = Right.create(:name => 'graders_admin',
239 240 :controller => 'graders',
240 241 :action => 'all')
241 242
242 243 role.rights << user_admin_right;
243 244 role.rights << problem_admin_right;
244 245 role.rights << graders_right;
245 246 role.save
246 247 end
247 248
248 249 def seed_root
249 250 return if User.find_by_login('root')
250 251
251 252 root = User.new(:login => 'root',
252 253 :full_name => 'Administrator',
253 254 :alias => 'root')
254 255 root.password = 'ioionrails';
255 256
256 257 class << root
257 258 public :encrypt_new_password
258 259 def valid?(context=nil)
259 260 true
260 261 end
261 262 end
262 263
263 264 root.encrypt_new_password
264 265
265 266 root.roles << Role.find_by_name('admin')
266 267
267 268 root.activated = true
268 269 root.save
269 270 end
270 271
271 272 def seed_users_and_roles
272 273 seed_roles
273 274 seed_root
274 275 end
275 276
276 277 def seed_more_languages
277 278 #Language.delete_all
278 279 Language.find_or_create_by( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
279 280 Language.find_or_create_by( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
280 281 Language.find_or_create_by( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
281 282 Language.find_or_create_by( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
282 283 Language.find_or_create_by( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
283 284 Language.find_or_create_by( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
284 285 end
285 286
286 287 seed_config
287 288 seed_users_and_roles
288 289 seed_more_languages
You need to be logged in to leave comments. Login now