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: 105 inserted, 71 deleted

@@ -1,112 +1,111
1 class SubmissionsController < ApplicationController
1 class SubmissionsController < ApplicationController
2 before_action :check_valid_login
2 before_action :check_valid_login
3 before_action :submission_authorization, only: [:show, :download, :edit]
3 before_action :submission_authorization, only: [:show, :download, :edit]
4 before_action :admin_authorization, only: [:rejudge]
4 before_action :admin_authorization, only: [:rejudge]
5
5
6 # GET /submissions
6 # GET /submissions
7 # GET /submissions.json
7 # GET /submissions.json
8 # Show problem selection and user's submission of that problem
8 # Show problem selection and user's submission of that problem
9 def index
9 def index
10 @user = @current_user
10 @user = @current_user
11 @problems = @user.available_problems
11 @problems = @user.available_problems
12
12
13 if params[:problem_id]==nil
13 if params[:problem_id]==nil
14 @problem = nil
14 @problem = nil
15 @submissions = nil
15 @submissions = nil
16 else
16 else
17 @problem = Problem.find_by_id(params[:problem_id])
17 @problem = Problem.find_by_id(params[:problem_id])
18 if (@problem == nil) or (not @problem.available)
18 if (@problem == nil) or (not @problem.available)
19 redirect_to list_main_path
19 redirect_to list_main_path
20 flash[:error] = 'Authorization error: You have no right to view submissions for this problem'
20 flash[:error] = 'Authorization error: You have no right to view submissions for this problem'
21 return
21 return
22 end
22 end
23 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
23 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
24 end
24 end
25 end
25 end
26
26
27 # GET /submissions/1
27 # GET /submissions/1
28 # GET /submissions/1.json
28 # GET /submissions/1.json
29 def show
29 def show
30 @submission = Submission.find(params[:id])
30 @submission = Submission.find(params[:id])
31
31
32 #log the viewing
32 #log the viewing
33 user = User.find(session[:user_id])
33 user = User.find(session[:user_id])
34 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
34 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
35
35
36 @task = @submission.task
36 @task = @submission.task
37 end
37 end
38
38
39 def download
39 def download
40 @submission = Submission.find(params[:id])
40 @submission = Submission.find(params[:id])
41 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
41 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
42 end
42 end
43
43
44 def compiler_msg
44 def compiler_msg
45 @submission = Submission.find(params[:id])
45 @submission = Submission.find(params[:id])
46 respond_to do |format|
46 respond_to do |format|
47 format.js
47 format.js
48 end
48 end
49 end
49 end
50
50
51 #on-site new submission on specific problem
51 #on-site new submission on specific problem
52 def direct_edit_problem
52 def direct_edit_problem
53 @problem = Problem.find(params[:problem_id])
53 @problem = Problem.find(params[:problem_id])
54 unless @current_user.can_view_problem?(@problem)
54 unless @current_user.can_view_problem?(@problem)
55 unauthorized_redirect
55 unauthorized_redirect
56 return
56 return
57 end
57 end
58 @source = ''
58 @source = ''
59 if (params[:view_latest])
59 if (params[:view_latest])
60 sub = Submission.find_last_by_user_and_problem(@current_user.id,@problem.id)
60 sub = Submission.find_last_by_user_and_problem(@current_user.id,@problem.id)
61 @source = @submission.source.to_s if @submission and @submission.source
61 @source = @submission.source.to_s if @submission and @submission.source
62 end
62 end
63 render 'edit'
63 render 'edit'
64 end
64 end
65
65
66 # GET /submissions/1/edit
66 # GET /submissions/1/edit
67 def edit
67 def edit
68 @submission = Submission.find(params[:id])
68 @submission = Submission.find(params[:id])
69 @source = @submission.source.to_s
69 @source = @submission.source.to_s
70 @problem = @submission.problem
70 @problem = @submission.problem
71 @lang_id = @submission.language.id
71 @lang_id = @submission.language.id
72 end
72 end
73
73
74
74
75 def get_latest_submission_status
75 def get_latest_submission_status
76 @problem = Problem.find(params[:pid])
76 @problem = Problem.find(params[:pid])
77 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
77 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
78 respond_to do |format|
78 respond_to do |format|
79 format.js
79 format.js
80 end
80 end
81 end
81 end
82
82
83 # GET /submissions/:id/rejudge
83 # GET /submissions/:id/rejudge
84 def rejudge
84 def rejudge
85 @submission = Submission.find(params[:id])
85 @submission = Submission.find(params[:id])
86 @task = @submission.task
86 @task = @submission.task
87 @task.status_inqueue! if @task
87 @task.status_inqueue! if @task
88 respond_to do |format|
88 respond_to do |format|
89 format.js
89 format.js
90 end
90 end
91 end
91 end
92
92
93 protected
93 protected
94
94
95 def submission_authorization
95 def submission_authorization
96 #admin always has privileged
96 #admin always has privileged
97 - if @current_user.admin?
97 + return true if @current_user.admin?
98 - return true
98 + return true if @current_user.has_role?('TA') && (['show','download'].include? action_name)
99 - end
100
99
101 sub = Submission.find(params[:id])
100 sub = Submission.find(params[:id])
102 if @current_user.available_problems.include? sub.problem
101 if @current_user.available_problems.include? sub.problem
103 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
102 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
104 end
103 end
105
104
106 #default to NO
105 #default to NO
107 unauthorized_redirect
106 unauthorized_redirect
108 return false
107 return false
109 end
108 end
110
109
111
110
112 end
111 end
@@ -166,414 +166,411
166 if params[:commit] == 'download csv'
166 if params[:commit] == 'download csv'
167 @problems = Problem.all
167 @problems = Problem.all
168 else
168 else
169 @problems = Problem.available_problems
169 @problems = Problem.available_problems
170 end
170 end
171 @users = User.includes(:contests, :contest_stat).where(enabled: true)
171 @users = User.includes(:contests, :contest_stat).where(enabled: true)
172 @scorearray = Array.new
172 @scorearray = Array.new
173 @users.each do |u|
173 @users.each do |u|
174 ustat = Array.new
174 ustat = Array.new
175 ustat[0] = u
175 ustat[0] = u
176 @problems.each do |p|
176 @problems.each do |p|
177 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
177 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
178 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
178 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
179 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
179 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
180 else
180 else
181 ustat << [0,false]
181 ustat << [0,false]
182 end
182 end
183 end
183 end
184 @scorearray << ustat
184 @scorearray << ustat
185 end
185 end
186 if params[:commit] == 'download csv' then
186 if params[:commit] == 'download csv' then
187 csv = gen_csv_from_scorearray(@scorearray,@problems)
187 csv = gen_csv_from_scorearray(@scorearray,@problems)
188 send_data csv, filename: 'last_score.csv'
188 send_data csv, filename: 'last_score.csv'
189 else
189 else
190 render template: 'user_admin/user_stat'
190 render template: 'user_admin/user_stat'
191 end
191 end
192 end
192 end
193
193
194 def user_stat_max
194 def user_stat_max
195 if params[:commit] == 'download csv'
195 if params[:commit] == 'download csv'
196 @problems = Problem.all
196 @problems = Problem.all
197 else
197 else
198 @problems = Problem.available_problems
198 @problems = Problem.available_problems
199 end
199 end
200 @users = User.includes(:contests).includes(:contest_stat).all
200 @users = User.includes(:contests).includes(:contest_stat).all
201 @scorearray = Array.new
201 @scorearray = Array.new
202 #set up range from param
202 #set up range from param
203 since_id = params.fetch(:since_id, 0).to_i
203 since_id = params.fetch(:since_id, 0).to_i
204 until_id = params.fetch(:until_id, 0).to_i
204 until_id = params.fetch(:until_id, 0).to_i
205 @users.each do |u|
205 @users.each do |u|
206 ustat = Array.new
206 ustat = Array.new
207 ustat[0] = u
207 ustat[0] = u
208 @problems.each do |p|
208 @problems.each do |p|
209 max_points = 0
209 max_points = 0
210 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
210 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
211 max_points = sub.points if sub and sub.points and (sub.points > max_points)
211 max_points = sub.points if sub and sub.points and (sub.points > max_points)
212 end
212 end
213 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
213 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
214 end
214 end
215 @scorearray << ustat
215 @scorearray << ustat
216 end
216 end
217
217
218 if params[:commit] == 'download csv' then
218 if params[:commit] == 'download csv' then
219 csv = gen_csv_from_scorearray(@scorearray,@problems)
219 csv = gen_csv_from_scorearray(@scorearray,@problems)
220 send_data csv, filename: 'max_score.csv'
220 send_data csv, filename: 'max_score.csv'
221 else
221 else
222 render template: 'user_admin/user_stat'
222 render template: 'user_admin/user_stat'
223 end
223 end
224 end
224 end
225
225
226 def import
226 def import
227 if params[:file]==''
227 if params[:file]==''
228 flash[:notice] = 'Error importing no file'
228 flash[:notice] = 'Error importing no file'
229 redirect_to :action => 'index' and return
229 redirect_to :action => 'index' and return
230 end
230 end
231 import_from_file(params[:file])
231 import_from_file(params[:file])
232 end
232 end
233
233
234 def random_all_passwords
234 def random_all_passwords
235 users = User.all
235 users = User.all
236 @prefix = params[:prefix] || ''
236 @prefix = params[:prefix] || ''
237 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
237 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
238 @changed = false
238 @changed = false
239 if params[:commit] == 'Go ahead'
239 if params[:commit] == 'Go ahead'
240 @non_admin_users.each do |user|
240 @non_admin_users.each do |user|
241 password = random_password
241 password = random_password
242 user.password = password
242 user.password = password
243 user.password_confirmation = password
243 user.password_confirmation = password
244 user.save
244 user.save
245 end
245 end
246 @changed = true
246 @changed = true
247 end
247 end
248 end
248 end
249
249
250 # contest management
250 # contest management
251
251
252 def contests
252 def contests
253 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
253 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
254 @contests = Contest.enabled
254 @contests = Contest.enabled
255 end
255 end
256
256
257 def assign_from_list
257 def assign_from_list
258 contest_id = params[:users_contest_id]
258 contest_id = params[:users_contest_id]
259 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
259 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
260 contest = Contest.find(params[:new_contest][:id])
260 contest = Contest.find(params[:new_contest][:id])
261 if !contest
261 if !contest
262 flash[:notice] = 'Error: no contest'
262 flash[:notice] = 'Error: no contest'
263 redirect_to :action => 'contests', :id =>contest_id
263 redirect_to :action => 'contests', :id =>contest_id
264 end
264 end
265
265
266 note = []
266 note = []
267 users.each do |u|
267 users.each do |u|
268 u.contests = [contest]
268 u.contests = [contest]
269 note << u.login
269 note << u.login
270 end
270 end
271 flash[:notice] = 'User(s) ' + note.join(', ') +
271 flash[:notice] = 'User(s) ' + note.join(', ') +
272 " were successfully reassigned to #{contest.title}."
272 " were successfully reassigned to #{contest.title}."
273 redirect_to :action => 'contests', :id =>contest.id
273 redirect_to :action => 'contests', :id =>contest.id
274 end
274 end
275
275
276 def add_to_contest
276 def add_to_contest
277 user = User.find(params[:id])
277 user = User.find(params[:id])
278 contest = Contest.find(params[:contest_id])
278 contest = Contest.find(params[:contest_id])
279 if user and contest
279 if user and contest
280 user.contests << contest
280 user.contests << contest
281 end
281 end
282 redirect_to :action => 'index'
282 redirect_to :action => 'index'
283 end
283 end
284
284
285 def remove_from_contest
285 def remove_from_contest
286 user = User.find(params[:id])
286 user = User.find(params[:id])
287 contest = Contest.find(params[:contest_id])
287 contest = Contest.find(params[:contest_id])
288 if user and contest
288 if user and contest
289 user.contests.delete(contest)
289 user.contests.delete(contest)
290 end
290 end
291 redirect_to :action => 'index'
291 redirect_to :action => 'index'
292 end
292 end
293
293
294 def contest_management
294 def contest_management
295 end
295 end
296
296
297 def manage_contest
297 def manage_contest
298 contest = Contest.find(params[:contest][:id])
298 contest = Contest.find(params[:contest][:id])
299 if !contest
299 if !contest
300 flash[:notice] = 'You did not choose the contest.'
300 flash[:notice] = 'You did not choose the contest.'
301 redirect_to :action => 'contest_management' and return
301 redirect_to :action => 'contest_management' and return
302 end
302 end
303
303
304 operation = params[:operation]
304 operation = params[:operation]
305
305
306 if not ['add','remove','assign'].include? operation
306 if not ['add','remove','assign'].include? operation
307 flash[:notice] = 'You did not choose the operation to perform.'
307 flash[:notice] = 'You did not choose the operation to perform.'
308 redirect_to :action => 'contest_management' and return
308 redirect_to :action => 'contest_management' and return
309 end
309 end
310
310
311 lines = params[:login_list]
311 lines = params[:login_list]
312 if !lines or lines.blank?
312 if !lines or lines.blank?
313 flash[:notice] = 'You entered an empty list.'
313 flash[:notice] = 'You entered an empty list.'
314 redirect_to :action => 'contest_management' and return
314 redirect_to :action => 'contest_management' and return
315 end
315 end
316
316
317 note = []
317 note = []
318 users = []
318 users = []
319 lines.split("\n").each do |line|
319 lines.split("\n").each do |line|
320 user = User.find_by_login(line.chomp)
320 user = User.find_by_login(line.chomp)
321 if user
321 if user
322 if operation=='add'
322 if operation=='add'
323 if ! user.contests.include? contest
323 if ! user.contests.include? contest
324 user.contests << contest
324 user.contests << contest
325 end
325 end
326 elsif operation=='remove'
326 elsif operation=='remove'
327 user.contests.delete(contest)
327 user.contests.delete(contest)
328 else
328 else
329 user.contests = [contest]
329 user.contests = [contest]
330 end
330 end
331
331
332 if params[:reset_timer]
332 if params[:reset_timer]
333 user.contest_stat.forced_logout = true
333 user.contest_stat.forced_logout = true
334 user.contest_stat.reset_timer_and_save
334 user.contest_stat.reset_timer_and_save
335 end
335 end
336
336
337 if params[:notification_emails]
337 if params[:notification_emails]
338 send_contest_update_notification_email(user, contest)
338 send_contest_update_notification_email(user, contest)
339 end
339 end
340
340
341 note << user.login
341 note << user.login
342 users << user
342 users << user
343 end
343 end
344 end
344 end
345
345
346 if params[:reset_timer]
346 if params[:reset_timer]
347 logout_users(users)
347 logout_users(users)
348 end
348 end
349
349
350 flash[:notice] = 'User(s) ' + note.join(', ') +
350 flash[:notice] = 'User(s) ' + note.join(', ') +
351 ' were successfully modified. '
351 ' were successfully modified. '
352 redirect_to :action => 'contest_management'
352 redirect_to :action => 'contest_management'
353 end
353 end
354
354
355 # admin management
355 # admin management
356
356
357 def admin
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 end
360 end
360
361
361 - def grant_admin
362 + def modify_role
362 - login = params[:login]
363 + user = User.find_by_login(params[:login])
363 - user = User.find_by_login(login)
364 + role = Role.find_by_name(params[:role])
364 - if user!=nil
365 + unless user && role
365 - admin_role = Role.find_by_name('admin')
366 + flash[:error] = 'Unknown user or role'
366 - user.roles << admin_role
367 + redirect_to admin_user_admin_index_path
367 - else
368 + return
368 - flash[:notice] = 'Unknown user'
369 end
369 end
370 - flash[:notice] = 'User added as admins'
370 + if params[:commit] == 'Grant'
371 - redirect_to :action => 'admin'
371 + #grant role
372 - end
372 + user.roles << role
373 -
373 + flash[:notice] = "User '#{user.login}' has been granted the role '#{role.name}'"
374 - def revoke_admin
374 + else
375 - user = User.find(params[:id])
375 + #revoke role
376 - if user==nil
376 + if user.login == 'root' && role.name == 'admin'
377 - flash[:notice] = 'Unknown user'
377 + flash[:error] = 'You cannot revoke admisnistrator permission from root.'
378 - redirect_to :action => 'admin' and return
378 + redirect_to admin_user_admin_index_path
379 - elsif user.login == 'root'
379 + return
380 - flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
380 + end
381 - redirect_to :action => 'admin' and return
381 + user.roles.delete(role)
382 + flash[:notice] = "The role '#{role.name}' has been revoked from User '#{user.login}'"
382 end
383 end
383 -
384 + redirect_to admin_user_admin_index_path
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'
388 end
385 end
389
386
390 # mass mailing
387 # mass mailing
391
388
392 def mass_mailing
389 def mass_mailing
393 end
390 end
394
391
395 def bulk_mail
392 def bulk_mail
396 lines = params[:login_list]
393 lines = params[:login_list]
397 if !lines or lines.blank?
394 if !lines or lines.blank?
398 flash[:notice] = 'You entered an empty list.'
395 flash[:notice] = 'You entered an empty list.'
399 redirect_to :action => 'mass_mailing' and return
396 redirect_to :action => 'mass_mailing' and return
400 end
397 end
401
398
402 mail_subject = params[:subject]
399 mail_subject = params[:subject]
403 if !mail_subject or mail_subject.blank?
400 if !mail_subject or mail_subject.blank?
404 flash[:notice] = 'You entered an empty mail subject.'
401 flash[:notice] = 'You entered an empty mail subject.'
405 redirect_to :action => 'mass_mailing' and return
402 redirect_to :action => 'mass_mailing' and return
406 end
403 end
407
404
408 mail_body = params[:email_body]
405 mail_body = params[:email_body]
409 if !mail_body or mail_body.blank?
406 if !mail_body or mail_body.blank?
410 flash[:notice] = 'You entered an empty mail body.'
407 flash[:notice] = 'You entered an empty mail body.'
411 redirect_to :action => 'mass_mailing' and return
408 redirect_to :action => 'mass_mailing' and return
412 end
409 end
413
410
414 note = []
411 note = []
415 users = []
412 users = []
416 lines.split("\n").each do |line|
413 lines.split("\n").each do |line|
417 user = User.find_by_login(line.chomp)
414 user = User.find_by_login(line.chomp)
418 if user
415 if user
419 send_mail(user.email, mail_subject, mail_body)
416 send_mail(user.email, mail_subject, mail_body)
420 note << user.login
417 note << user.login
421 end
418 end
422 end
419 end
423
420
424 flash[:notice] = 'User(s) ' + note.join(', ') +
421 flash[:notice] = 'User(s) ' + note.join(', ') +
425 ' were successfully modified. '
422 ' were successfully modified. '
426 redirect_to :action => 'mass_mailing'
423 redirect_to :action => 'mass_mailing'
427 end
424 end
428
425
429 #bulk manage
426 #bulk manage
430 def bulk_manage
427 def bulk_manage
431
428
432 begin
429 begin
433 @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
430 @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
434 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
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 rescue Exception
432 rescue Exception
436 flash[:error] = 'Regular Expression is malformed'
433 flash[:error] = 'Regular Expression is malformed'
437 @users = nil
434 @users = nil
438 end
435 end
439
436
440 if params[:commit]
437 if params[:commit]
441 @action = {}
438 @action = {}
442 @action[:set_enable] = params[:enabled]
439 @action[:set_enable] = params[:enabled]
443 @action[:enabled] = params[:enable] == "1"
440 @action[:enabled] = params[:enable] == "1"
444 @action[:gen_password] = params[:gen_password]
441 @action[:gen_password] = params[:gen_password]
445 @action[:add_group] = params[:add_group]
442 @action[:add_group] = params[:add_group]
446 @action[:group_name] = params[:group_name]
443 @action[:group_name] = params[:group_name]
447 end
444 end
448
445
449 if params[:commit] == "Perform"
446 if params[:commit] == "Perform"
450 if @action[:set_enable]
447 if @action[:set_enable]
451 @users.update_all(enabled: @action[:enabled])
448 @users.update_all(enabled: @action[:enabled])
452 end
449 end
453 if @action[:gen_password]
450 if @action[:gen_password]
454 @users.each do |u|
451 @users.each do |u|
455 password = random_password
452 password = random_password
456 u.password = password
453 u.password = password
457 u.password_confirmation = password
454 u.password_confirmation = password
458 u.save
455 u.save
459 end
456 end
460 end
457 end
461 if @action[:add_group] and @action[:group_name]
458 if @action[:add_group] and @action[:group_name]
462 @group = Group.find(@action[:group_name])
459 @group = Group.find(@action[:group_name])
463 ok = []
460 ok = []
464 failed = []
461 failed = []
465 @users.each do |user|
462 @users.each do |user|
466 begin
463 begin
467 @group.users << user
464 @group.users << user
468 ok << user.login
465 ok << user.login
469 rescue => e
466 rescue => e
470 failed << user.login
467 failed << user.login
471 end
468 end
472 end
469 end
473 flash[:success] = "The following users are added to the 'group #{@group.name}': " + ok.join(', ') if ok.count > 0
470 flash[:success] = "The following users are added to the 'group #{@group.name}': " + ok.join(', ') if ok.count > 0
474 flash[:alert] = "The following users are already in the 'group #{@group.name}': " + failed.join(', ') if failed.count > 0
471 flash[:alert] = "The following users are already in the 'group #{@group.name}': " + failed.join(', ') if failed.count > 0
475 end
472 end
476 end
473 end
477 end
474 end
478
475
479 protected
476 protected
480
477
481 def random_password(length=5)
478 def random_password(length=5)
482 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
479 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
483 newpass = ""
480 newpass = ""
484 length.times { newpass << chars[rand(chars.size-1)] }
481 length.times { newpass << chars[rand(chars.size-1)] }
485 return newpass
482 return newpass
486 end
483 end
487
484
488 def import_from_file(f)
485 def import_from_file(f)
489 data_hash = YAML.load(f)
486 data_hash = YAML.load(f)
490 @import_log = ""
487 @import_log = ""
491
488
492 country_data = data_hash[:countries]
489 country_data = data_hash[:countries]
493 site_data = data_hash[:sites]
490 site_data = data_hash[:sites]
494 user_data = data_hash[:users]
491 user_data = data_hash[:users]
495
492
496 # import country
493 # import country
497 countries = {}
494 countries = {}
498 country_data.each_pair do |id,country|
495 country_data.each_pair do |id,country|
499 c = Country.find_by_name(country[:name])
496 c = Country.find_by_name(country[:name])
500 if c!=nil
497 if c!=nil
501 countries[id] = c
498 countries[id] = c
502 @import_log << "Found #{country[:name]}\n"
499 @import_log << "Found #{country[:name]}\n"
503 else
500 else
504 countries[id] = Country.new(:name => country[:name])
501 countries[id] = Country.new(:name => country[:name])
505 countries[id].save
502 countries[id].save
506 @import_log << "Created #{country[:name]}\n"
503 @import_log << "Created #{country[:name]}\n"
507 end
504 end
508 end
505 end
509
506
510 # import sites
507 # import sites
511 sites = {}
508 sites = {}
512 site_data.each_pair do |id,site|
509 site_data.each_pair do |id,site|
513 s = Site.find_by_name(site[:name])
510 s = Site.find_by_name(site[:name])
514 if s!=nil
511 if s!=nil
515 @import_log << "Found #{site[:name]}\n"
512 @import_log << "Found #{site[:name]}\n"
516 else
513 else
517 s = Site.new(:name => site[:name])
514 s = Site.new(:name => site[:name])
518 @import_log << "Created #{site[:name]}\n"
515 @import_log << "Created #{site[:name]}\n"
519 end
516 end
520 s.password = site[:password]
517 s.password = site[:password]
521 s.country = countries[site[:country_id]]
518 s.country = countries[site[:country_id]]
522 s.save
519 s.save
523 sites[id] = s
520 sites[id] = s
524 end
521 end
525
522
526 # import users
523 # import users
527 user_data.each_pair do |id,user|
524 user_data.each_pair do |id,user|
528 u = User.find_by_login(user[:login])
525 u = User.find_by_login(user[:login])
529 if u!=nil
526 if u!=nil
530 @import_log << "Found #{user[:login]}\n"
527 @import_log << "Found #{user[:login]}\n"
531 else
528 else
532 u = User.new(:login => user[:login])
529 u = User.new(:login => user[:login])
533 @import_log << "Created #{user[:login]}\n"
530 @import_log << "Created #{user[:login]}\n"
534 end
531 end
535 u.full_name = user[:name]
532 u.full_name = user[:name]
536 u.password = user[:password]
533 u.password = user[:password]
537 u.country = countries[user[:country_id]]
534 u.country = countries[user[:country_id]]
538 u.site = sites[user[:site_id]]
535 u.site = sites[user[:site_id]]
539 u.activated = true
536 u.activated = true
540 u.email = "empty-#{u.login}@none.com"
537 u.email = "empty-#{u.login}@none.com"
541 if not u.save
538 if not u.save
542 @import_log << "Errors\n"
539 @import_log << "Errors\n"
543 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
540 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
544 end
541 end
545 end
542 end
546
543
547 end
544 end
548
545
549 def logout_users(users)
546 def logout_users(users)
550 users.each do |user|
547 users.each do |user|
551 contest_stat = user.contest_stat(true)
548 contest_stat = user.contest_stat(true)
552 if contest_stat and !contest_stat.forced_logout
549 if contest_stat and !contest_stat.forced_logout
553 contest_stat.forced_logout = true
550 contest_stat.forced_logout = true
554 contest_stat.save
551 contest_stat.save
555 end
552 end
556 end
553 end
557 end
554 end
558
555
559 def send_contest_update_notification_email(user, contest)
556 def send_contest_update_notification_email(user, contest)
560 contest_title_name = GraderConfiguration['contest.name']
557 contest_title_name = GraderConfiguration['contest.name']
561 contest_name = contest.name
558 contest_name = contest.name
562 mail_subject = t('contest.notification.email_subject', {
559 mail_subject = t('contest.notification.email_subject', {
563 :contest_title_name => contest_title_name,
560 :contest_title_name => contest_title_name,
564 :contest_name => contest_name })
561 :contest_name => contest_name })
565 mail_body = t('contest.notification.email_body', {
562 mail_body = t('contest.notification.email_body', {
566 :full_name => user.full_name,
563 :full_name => user.full_name,
567 :contest_title_name => contest_title_name,
564 :contest_title_name => contest_title_name,
568 :contest_name => contest.name,
565 :contest_name => contest.name,
569 })
566 })
570
567
571 logger.info mail_body
568 logger.info mail_body
572 send_mail(user.email, mail_subject, mail_body)
569 send_mail(user.email, mail_subject, mail_body)
573 end
570 end
574
571
575 def find_contest_and_user_from_contest_id(id)
572 def find_contest_and_user_from_contest_id(id)
576 if id!='none'
573 if id!='none'
577 @contest = Contest.find(id)
574 @contest = Contest.find(id)
578 else
575 else
579 @contest = nil
576 @contest = nil
@@ -1,319 +1,323
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 require 'net/https'
3 require 'net/https'
4 require 'net/http'
4 require 'net/http'
5 require 'json'
5 require 'json'
6
6
7 class User < ActiveRecord::Base
7 class User < ActiveRecord::Base
8
8
9 has_and_belongs_to_many :roles
9 has_and_belongs_to_many :roles
10
10
11 #has_and_belongs_to_many :groups
11 #has_and_belongs_to_many :groups
12 has_many :groups_users, class_name: 'GroupUser'
12 has_many :groups_users, class_name: 'GroupUser'
13 has_many :groups, :through => :groups_users
13 has_many :groups, :through => :groups_users
14
14
15 has_many :test_requests, -> {order(submitted_at: :desc)}
15 has_many :test_requests, -> {order(submitted_at: :desc)}
16
16
17 has_many :messages, -> { order(created_at: :desc) },
17 has_many :messages, -> { order(created_at: :desc) },
18 :class_name => "Message",
18 :class_name => "Message",
19 :foreign_key => "sender_id"
19 :foreign_key => "sender_id"
20
20
21 has_many :replied_messages, -> { order(created_at: :desc) },
21 has_many :replied_messages, -> { order(created_at: :desc) },
22 :class_name => "Message",
22 :class_name => "Message",
23 :foreign_key => "receiver_id"
23 :foreign_key => "receiver_id"
24
24
25 has_many :logins
25 has_many :logins
26
26
27 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
27 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
28
28
29 belongs_to :site
29 belongs_to :site
30 belongs_to :country
30 belongs_to :country
31
31
32 has_and_belongs_to_many :contests, -> { order(:name)}
32 has_and_belongs_to_many :contests, -> { order(:name)}
33
33
34 scope :activated_users, -> {where activated: true}
34 scope :activated_users, -> {where activated: true}
35
35
36 validates_presence_of :login
36 validates_presence_of :login
37 validates_uniqueness_of :login
37 validates_uniqueness_of :login
38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
39 validates_length_of :login, :within => 3..30
39 validates_length_of :login, :within => 3..30
40
40
41 validates_presence_of :full_name
41 validates_presence_of :full_name
42 validates_length_of :full_name, :minimum => 1
42 validates_length_of :full_name, :minimum => 1
43
43
44 validates_presence_of :password, :if => :password_required?
44 validates_presence_of :password, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
47
47
48 validates_format_of :email,
48 validates_format_of :email,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
50 :if => :email_validation?
50 :if => :email_validation?
51 validate :uniqueness_of_email_from_activated_users,
51 validate :uniqueness_of_email_from_activated_users,
52 :if => :email_validation?
52 :if => :email_validation?
53 validate :enough_time_interval_between_same_email_registrations,
53 validate :enough_time_interval_between_same_email_registrations,
54 :if => :email_validation?
54 :if => :email_validation?
55
55
56 # these are for ytopc
56 # these are for ytopc
57 # disable for now
57 # disable for now
58 #validates_presence_of :province
58 #validates_presence_of :province
59
59
60 attr_accessor :password
60 attr_accessor :password
61
61
62 before_save :encrypt_new_password
62 before_save :encrypt_new_password
63 before_save :assign_default_site
63 before_save :assign_default_site
64 before_save :assign_default_contest
64 before_save :assign_default_contest
65
65
66 # this is for will_paginate
66 # this is for will_paginate
67 cattr_reader :per_page
67 cattr_reader :per_page
68 @@per_page = 50
68 @@per_page = 50
69
69
70 def self.authenticate(login, password)
70 def self.authenticate(login, password)
71 user = find_by_login(login)
71 user = find_by_login(login)
72 if user
72 if user
73 return user if user.authenticated?(password)
73 return user if user.authenticated?(password)
74 if user.authenticated_by_cucas?(password)
74 if user.authenticated_by_cucas?(password)
75 user.password = password
75 user.password = password
76 user.save
76 user.save
77 return user
77 return user
78 end
78 end
79 end
79 end
80 end
80 end
81
81
82
82
83 def authenticated?(password)
83 def authenticated?(password)
84 if self.activated
84 if self.activated
85 hashed_password == User.encrypt(password,self.salt)
85 hashed_password == User.encrypt(password,self.salt)
86 else
86 else
87 false
87 false
88 end
88 end
89 end
89 end
90
90
91 def authenticated_by_cucas?(password)
91 def authenticated_by_cucas?(password)
92 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
92 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
93 appid = '41508763e340d5858c00f8c1a0f5a2bb'
93 appid = '41508763e340d5858c00f8c1a0f5a2bb'
94 appsecret ='d9cbb5863091dbe186fded85722a1e31'
94 appsecret ='d9cbb5863091dbe186fded85722a1e31'
95 post_args = {
95 post_args = {
96 'appid' => appid,
96 'appid' => appid,
97 'appsecret' => appsecret,
97 'appsecret' => appsecret,
98 'username' => login,
98 'username' => login,
99 'password' => password
99 'password' => password
100 }
100 }
101
101
102 #simple call
102 #simple call
103 begin
103 begin
104 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
104 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
105 http.use_ssl = true
105 http.use_ssl = true
106 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
106 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
107 result = [ ]
107 result = [ ]
108 http.start do |http|
108 http.start do |http|
109 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
109 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
110 #req = Net::HTTP::Post.new('/appX/prod/?q=studentAuthenticate')
110 #req = Net::HTTP::Post.new('/appX/prod/?q=studentAuthenticate')
111 #req = Net::HTTP::Post.new('/app2/prod/api/?q=studentAuthenticate')
111 #req = Net::HTTP::Post.new('/app2/prod/api/?q=studentAuthenticate')
112 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
112 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
113 resp = http.request(req,param)
113 resp = http.request(req,param)
114 result = JSON.parse resp.body
114 result = JSON.parse resp.body
115 puts result
115 puts result
116 end
116 end
117 return true if result["type"] == "beanStudent"
117 return true if result["type"] == "beanStudent"
118 rescue => e
118 rescue => e
119 puts e
119 puts e
120 puts e.message
120 puts e.message
121 return false
121 return false
122 end
122 end
123 return false
123 return false
124 end
124 end
125
125
126 def admin?
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 end
132 end
129
133
130 def email_for_editing
134 def email_for_editing
131 if self.email==nil
135 if self.email==nil
132 "(unknown)"
136 "(unknown)"
133 elsif self.email==''
137 elsif self.email==''
134 "(blank)"
138 "(blank)"
135 else
139 else
136 self.email
140 self.email
137 end
141 end
138 end
142 end
139
143
140 def email_for_editing=(e)
144 def email_for_editing=(e)
141 self.email=e
145 self.email=e
142 end
146 end
143
147
144 def alias_for_editing
148 def alias_for_editing
145 if self.alias==nil
149 if self.alias==nil
146 "(unknown)"
150 "(unknown)"
147 elsif self.alias==''
151 elsif self.alias==''
148 "(blank)"
152 "(blank)"
149 else
153 else
150 self.alias
154 self.alias
151 end
155 end
152 end
156 end
153
157
154 def alias_for_editing=(e)
158 def alias_for_editing=(e)
155 self.alias=e
159 self.alias=e
156 end
160 end
157
161
158 def activation_key
162 def activation_key
159 if self.hashed_password==nil
163 if self.hashed_password==nil
160 encrypt_new_password
164 encrypt_new_password
161 end
165 end
162 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
166 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
163 end
167 end
164
168
165 def verify_activation_key(key)
169 def verify_activation_key(key)
166 key == activation_key
170 key == activation_key
167 end
171 end
168
172
169 def self.random_password(length=5)
173 def self.random_password(length=5)
170 chars = 'abcdefghjkmnopqrstuvwxyz'
174 chars = 'abcdefghjkmnopqrstuvwxyz'
171 password = ''
175 password = ''
172 length.times { password << chars[rand(chars.length - 1)] }
176 length.times { password << chars[rand(chars.length - 1)] }
173 password
177 password
174 end
178 end
175
179
176 def self.find_non_admin_with_prefix(prefix='')
180 def self.find_non_admin_with_prefix(prefix='')
177 users = User.all
181 users = User.all
178 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
182 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
179 end
183 end
180
184
181 # Contest information
185 # Contest information
182
186
183 def self.find_users_with_no_contest()
187 def self.find_users_with_no_contest()
184 users = User.all
188 users = User.all
185 return users.find_all { |u| u.contests.length == 0 }
189 return users.find_all { |u| u.contests.length == 0 }
186 end
190 end
187
191
188
192
189 def contest_time_left
193 def contest_time_left
190 if GraderConfiguration.contest_mode?
194 if GraderConfiguration.contest_mode?
191 return nil if site==nil
195 return nil if site==nil
192 return site.time_left
196 return site.time_left
193 elsif GraderConfiguration.indv_contest_mode?
197 elsif GraderConfiguration.indv_contest_mode?
194 time_limit = GraderConfiguration.contest_time_limit
198 time_limit = GraderConfiguration.contest_time_limit
195 if time_limit == nil
199 if time_limit == nil
196 return nil
200 return nil
197 end
201 end
198 if contest_stat==nil or contest_stat.started_at==nil
202 if contest_stat==nil or contest_stat.started_at==nil
199 return (Time.now.gmtime + time_limit) - Time.now.gmtime
203 return (Time.now.gmtime + time_limit) - Time.now.gmtime
200 else
204 else
201 finish_time = contest_stat.started_at + time_limit
205 finish_time = contest_stat.started_at + time_limit
202 current_time = Time.now.gmtime
206 current_time = Time.now.gmtime
203 if current_time > finish_time
207 if current_time > finish_time
204 return 0
208 return 0
205 else
209 else
206 return finish_time - current_time
210 return finish_time - current_time
207 end
211 end
208 end
212 end
209 else
213 else
210 return nil
214 return nil
211 end
215 end
212 end
216 end
213
217
214 def contest_finished?
218 def contest_finished?
215 if GraderConfiguration.contest_mode?
219 if GraderConfiguration.contest_mode?
216 return false if site==nil
220 return false if site==nil
217 return site.finished?
221 return site.finished?
218 elsif GraderConfiguration.indv_contest_mode?
222 elsif GraderConfiguration.indv_contest_mode?
219 return false if self.contest_stat==nil
223 return false if self.contest_stat==nil
220 return contest_time_left == 0
224 return contest_time_left == 0
221 else
225 else
222 return false
226 return false
223 end
227 end
224 end
228 end
225
229
226 def contest_started?
230 def contest_started?
227 if GraderConfiguration.indv_contest_mode?
231 if GraderConfiguration.indv_contest_mode?
228 stat = self.contest_stat
232 stat = self.contest_stat
229 return ((stat != nil) and (stat.started_at != nil))
233 return ((stat != nil) and (stat.started_at != nil))
230 elsif GraderConfiguration.contest_mode?
234 elsif GraderConfiguration.contest_mode?
231 return true if site==nil
235 return true if site==nil
232 return site.started
236 return site.started
233 else
237 else
234 return true
238 return true
235 end
239 end
236 end
240 end
237
241
238 def update_start_time
242 def update_start_time
239 stat = self.contest_stat
243 stat = self.contest_stat
240 if stat.nil? or stat.started_at.nil?
244 if stat.nil? or stat.started_at.nil?
241 stat ||= UserContestStat.new(:user => self)
245 stat ||= UserContestStat.new(:user => self)
242 stat.started_at = Time.now.gmtime
246 stat.started_at = Time.now.gmtime
243 stat.save
247 stat.save
244 end
248 end
245 end
249 end
246
250
247 def problem_in_user_contests?(problem)
251 def problem_in_user_contests?(problem)
248 problem_contests = problem.contests.all
252 problem_contests = problem.contests.all
249
253
250 if problem_contests.length == 0 # this is public contest
254 if problem_contests.length == 0 # this is public contest
251 return true
255 return true
252 end
256 end
253
257
254 contests.each do |contest|
258 contests.each do |contest|
255 if problem_contests.find {|c| c.id == contest.id }
259 if problem_contests.find {|c| c.id == contest.id }
256 return true
260 return true
257 end
261 end
258 end
262 end
259 return false
263 return false
260 end
264 end
261
265
262 def available_problems_group_by_contests
266 def available_problems_group_by_contests
263 contest_problems = []
267 contest_problems = []
264 pin = {}
268 pin = {}
265 contests.enabled.each do |contest|
269 contests.enabled.each do |contest|
266 available_problems = contest.problems.available
270 available_problems = contest.problems.available
267 contest_problems << {
271 contest_problems << {
268 :contest => contest,
272 :contest => contest,
269 :problems => available_problems
273 :problems => available_problems
270 }
274 }
271 available_problems.each {|p| pin[p.id] = true}
275 available_problems.each {|p| pin[p.id] = true}
272 end
276 end
273 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
277 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
274 contest_problems << {
278 contest_problems << {
275 :contest => nil,
279 :contest => nil,
276 :problems => other_avaiable_problems
280 :problems => other_avaiable_problems
277 }
281 }
278 return contest_problems
282 return contest_problems
279 end
283 end
280
284
281 def solve_all_available_problems?
285 def solve_all_available_problems?
282 available_problems.each do |p|
286 available_problems.each do |p|
283 u = self
287 u = self
284 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
288 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
285 return false if !p or !sub or sub.points < p.full_score
289 return false if !p or !sub or sub.points < p.full_score
286 end
290 end
287 return true
291 return true
288 end
292 end
289
293
290 #get a list of available problem
294 #get a list of available problem
291 def available_problems
295 def available_problems
292 # first, we check if this is normal mode
296 # first, we check if this is normal mode
293 if not GraderConfiguration.multicontests?
297 if not GraderConfiguration.multicontests?
294
298
295 #if this is a normal mode
299 #if this is a normal mode
296 #we show problem based on problem_group, if the config said so
300 #we show problem based on problem_group, if the config said so
297 if GraderConfiguration.use_problem_group?
301 if GraderConfiguration.use_problem_group?
298 return available_problems_in_group
302 return available_problems_in_group
299 else
303 else
300 return Problem.available_problems
304 return Problem.available_problems
301 end
305 end
302 else
306 else
303 #this is multi contest mode
307 #this is multi contest mode
304 contest_problems = []
308 contest_problems = []
305 pin = {}
309 pin = {}
306 contests.enabled.each do |contest|
310 contests.enabled.each do |contest|
307 contest.problems.available.each do |problem|
311 contest.problems.available.each do |problem|
308 if not pin.has_key? problem.id
312 if not pin.has_key? problem.id
309 contest_problems << problem
313 contest_problems << problem
310 end
314 end
311 pin[problem.id] = true
315 pin[problem.id] = true
312 end
316 end
313 end
317 end
314 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
318 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
315 return contest_problems + other_avaiable_problems
319 return contest_problems + other_avaiable_problems
316 end
320 end
317 end
321 end
318
322
319 # new feature, get list of available problem in all enabled group that the user belongs to
323 # new feature, get list of available problem in all enabled group that the user belongs to
@@ -1,96 +1,96
1 %header.navbar.navbar-default.navbar-fixed-top
1 %header.navbar.navbar-default.navbar-fixed-top
2 %nav
2 %nav
3 .container-fluid
3 .container-fluid
4 .navbar-header
4 .navbar-header
5 %button.navbar-toggle.collapsed{ data: {toggle: 'collapse', target: '#navbar-collapse'} }
5 %button.navbar-toggle.collapsed{ data: {toggle: 'collapse', target: '#navbar-collapse'} }
6 %span.sr-only Togggle Navigation
6 %span.sr-only Togggle Navigation
7 %span.icon-bar
7 %span.icon-bar
8 %span.icon-bar
8 %span.icon-bar
9 %span.icon-bar
9 %span.icon-bar
10 %a.navbar-brand{href: list_main_path}
10 %a.navbar-brand{href: list_main_path}
11 %span.glyphicon.glyphicon-home
11 %span.glyphicon.glyphicon-home
12 MAIN
12 MAIN
13 .collapse.navbar-collapse#navbar-collapse
13 .collapse.navbar-collapse#navbar-collapse
14 %ul.nav.navbar-nav
14 %ul.nav.navbar-nav
15 / submission
15 / submission
16 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
16 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
17 %li.dropdown
17 %li.dropdown
18 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
18 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
19 = "#{I18n.t 'menu.submissions'}"
19 = "#{I18n.t 'menu.submissions'}"
20 %span.caret
20 %span.caret
21 %ul.dropdown-menu
21 %ul.dropdown-menu
22 = add_menu("View", 'submissions', 'index')
22 = add_menu("View", 'submissions', 'index')
23 = add_menu("Self Test", 'test', 'index')
23 = add_menu("Self Test", 'test', 'index')
24 / hall of fame
24 / hall of fame
25 - if GraderConfiguration['right.user_hall_of_fame']
25 - if GraderConfiguration['right.user_hall_of_fame']
26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
27 / display MODE button (with countdown in contest mode)
27 / display MODE button (with countdown in contest mode)
28 - if GraderConfiguration.analysis_mode?
28 - if GraderConfiguration.analysis_mode?
29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
30 - elsif GraderConfiguration.time_limit_mode?
30 - elsif GraderConfiguration.time_limit_mode?
31 - if @current_user.contest_finished?
31 - if @current_user.contest_finished?
32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
33 - elsif !@current_user.contest_started?
33 - elsif !@current_user.contest_started?
34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
35 - else
35 - else
36 %div.navbar-btn.btn.btn-primary#countdown asdf
36 %div.navbar-btn.btn.btn-primary#countdown asdf
37 :javascript
37 :javascript
38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
39 / admin section
39 / admin section
40 - if (@current_user!=nil) and (session[:admin])
40 - if (@current_user!=nil) and (session[:admin])
41 / management
41 / management
42 %li.dropdown
42 %li.dropdown
43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
44 Manage
44 Manage
45 %span.caret
45 %span.caret
46 %ul.dropdown-menu
46 %ul.dropdown-menu
47 = add_menu( 'Announcements', 'announcements', 'index')
47 = add_menu( 'Announcements', 'announcements', 'index')
48 = add_menu( 'Problems', 'problems', 'index')
48 = add_menu( 'Problems', 'problems', 'index')
49 = add_menu( 'Tags', 'tags', 'index')
49 = add_menu( 'Tags', 'tags', 'index')
50 = add_menu( 'Users', 'user_admin', 'index')
50 = add_menu( 'Users', 'user_admin', 'index')
51 = add_menu( 'User Groups', 'groups', 'index')
51 = add_menu( 'User Groups', 'groups', 'index')
52 = add_menu( 'Graders', 'graders', 'list')
52 = add_menu( 'Graders', 'graders', 'list')
53 = add_menu( 'Message ', 'messages', 'console')
53 = add_menu( 'Message ', 'messages', 'console')
54 %li.divider{role: 'separator'}
54 %li.divider{role: 'separator'}
55 = add_menu( 'System config', 'configurations', 'index')
55 = add_menu( 'System config', 'configurations', 'index')
56 %li.divider{role: 'separator'}
56 %li.divider{role: 'separator'}
57 = add_menu( 'Sites', 'sites', 'index')
57 = add_menu( 'Sites', 'sites', 'index')
58 = add_menu( 'Contests', 'contest_management', 'index')
58 = add_menu( 'Contests', 'contest_management', 'index')
59 / report
59 / report
60 %li.dropdown
60 %li.dropdown
61 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
61 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
62 Report
62 Report
63 %span.caret
63 %span.caret
64 %ul.dropdown-menu
64 %ul.dropdown-menu
65 = add_menu( 'Current Score', 'report', 'current_score')
65 = add_menu( 'Current Score', 'report', 'current_score')
66 = add_menu( 'Score Report', 'report', 'max_score')
66 = add_menu( 'Score Report', 'report', 'max_score')
67 = add_menu( 'Submission Report', 'report', 'submission')
67 = add_menu( 'Submission Report', 'report', 'submission')
68 = add_menu( 'Login Report', 'report', 'login')
68 = add_menu( 'Login Report', 'report', 'login')
69 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
69 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
70 =link_to "#{ungraded} backlogs!",
70 =link_to "#{ungraded} backlogs!",
71 - grader_list_path,
71 + graders_list_path,
72 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
72 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
73
73
74 %ul.nav.navbar-nav.navbar-right
74 %ul.nav.navbar-nav.navbar-right
75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'index', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'index', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
77 - if GraderConfiguration['system.user_setting_enabled']
77 - if GraderConfiguration['system.user_setting_enabled']
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'}})
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 = 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'}})
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 - if (@current_user!=nil) and (session[:admin])
82 - if (@current_user!=nil) and (session[:admin])
83 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
83 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
84 .container-fluid
84 .container-fluid
85 .collapse.navbar-collapse
85 .collapse.navbar-collapse
86 %ul.nav.navbar-nav
86 %ul.nav.navbar-nav
87 = add_menu( '[Announcements]', 'announcements', 'index')
87 = add_menu( '[Announcements]', 'announcements', 'index')
88 = add_menu( '[Msg console]', 'messages', 'console')
88 = add_menu( '[Msg console]', 'messages', 'console')
89 = add_menu( '[Problems]', 'problems', 'index')
89 = add_menu( '[Problems]', 'problems', 'index')
90 = add_menu( '[Users]', 'user_admin', 'index')
90 = add_menu( '[Users]', 'user_admin', 'index')
91 = add_menu( '[Results]', 'user_admin', 'user_stat')
91 = add_menu( '[Results]', 'user_admin', 'user_stat')
92 = add_menu( '[Report]', 'report', 'multiple_login')
92 = add_menu( '[Report]', 'report', 'multiple_login')
93 = add_menu( '[Graders]', 'graders', 'list')
93 = add_menu( '[Graders]', 'graders', 'list')
94 = add_menu( '[Contests]', 'contest_management', 'index')
94 = add_menu( '[Contests]', 'contest_management', 'index')
95 = add_menu( '[Sites]', 'sites', 'index')
95 = add_menu( '[Sites]', 'sites', 'index')
96 = add_menu( '[System config]', 'configurations', 'index')
96 = add_menu( '[System config]', 'configurations', 'index')
@@ -1,59 +1,63
1 :css
1 :css
2 .fix-width {
2 .fix-width {
3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
4 }
4 }
5
5
6 %h1 Problem stat: #{@problem.name}
6 %h1 Problem stat: #{@problem.name}
7 %h2 Overview
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 %h2 Submissions Count
27 %h2 Submissions Count
24 = render partial: 'application/bar_graph', locals: { histogram: @histogram }
28 = render partial: 'application/bar_graph', locals: { histogram: @histogram }
25
29
26 %h2 Submissions
30 %h2 Submissions
27 - if @submissions and @submissions.count > 0
31 - if @submissions and @submissions.count > 0
28 %table#main_table.table.table-condensed.table-striped
32 %table#main_table.table.table-condensed.table-striped
29 %thead
33 %thead
30 %tr
34 %tr
31 %th ID
35 %th ID
32 %th Login
36 %th Login
33 %th Name
37 %th Name
34 %th Submitted_at
38 %th Submitted_at
35 %th language
39 %th language
36 %th Points
40 %th Points
37 %th comment
41 %th comment
38 %th IP
42 %th IP
39 %tbody
43 %tbody
40 - row_odd,curr = true,''
44 - row_odd,curr = true,''
41 - @submissions.each do |sub|
45 - @submissions.each do |sub|
42 - next unless sub.user
46 - next unless sub.user
43 - row_odd,curr = !row_odd, sub.user if curr != sub.user
47 - row_odd,curr = !row_odd, sub.user if curr != sub.user
44 %tr
48 %tr
45 %td= link_to sub.id, submission_path(sub)
49 %td= link_to sub.id, submission_path(sub)
46 %td= link_to sub.user.login, stat_user_path(sub.user)
50 %td= link_to sub.user.login, stat_user_path(sub.user)
47 %td= sub.user.full_name
51 %td= sub.user.full_name
48 %td{data: {order: sub.submitted_at}}= time_ago_in_words(sub.submitted_at) + " ago"
52 %td{data: {order: sub.submitted_at}}= time_ago_in_words(sub.submitted_at) + " ago"
49 %td= sub.language.name
53 %td= sub.language.name
50 %td= sub.points
54 %td= sub.points
51 %td.fix-width= sub.grader_comment
55 %td.fix-width= sub.grader_comment
52 %td= sub.ip_address
56 %td= sub.ip_address
53 - else
57 - else
54 No submission
58 No submission
55
59
56 :javascript
60 :javascript
57 $("#main_table").DataTable({
61 $("#main_table").DataTable({
58 paging: false
62 paging: false
59 });
63 });
@@ -1,25 +1,54
1 - %h1 Administrators
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'}
15 + %th #
16 + %th Login
17 + %th Full name
18 + %th
19 + - @admins.each_with_index do |user, i|
20 + %tr
21 + %td= i+1
22 + %td= user.login
23 + %td= user.full_name
24 + %td
25 + - if user.login!='root'
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')
2
51
3 - %table{:class => 'info'}
4 - %tr{:class => 'info-head'}
5 - %th #
6 - %th Login
7 - %th Full name
8 - %th
9 - - @admins.each_with_index do |user, i|
10 - %tr
11 - %td= i+1
12 - %td= user.login
13 - %td= user.full_name
14 - %td
15 - - if user.login!='root'
16 - = link_to '[revoke]', :action => 'revoke_admin', :id => user.id
17 - %hr
18 -
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 %hr/
53 %hr/
25 = link_to '[go back to index]', :action => 'index'
54 = link_to '[go back to index]', :action => 'index'
@@ -1,211 +1,211
1 Rails.application.routes.draw do
1 Rails.application.routes.draw do
2 resources :tags
2 resources :tags
3 get "sources/direct_edit"
3 get "sources/direct_edit"
4
4
5 root :to => 'main#login'
5 root :to => 'main#login'
6
6
7 #logins
7 #logins
8 match 'login/login', to: 'login#login', via: [:get,:post]
8 match 'login/login', to: 'login#login', via: [:get,:post]
9
9
10 resources :contests
10 resources :contests
11 resources :sites
11 resources :sites
12 resources :test
12 resources :test
13
13
14 resources :messages do
14 resources :messages do
15 member do
15 member do
16 get 'hide'
16 get 'hide'
17 post 'reply'
17 post 'reply'
18 end
18 end
19 collection do
19 collection do
20 get 'console'
20 get 'console'
21 get 'list_all'
21 get 'list_all'
22 end
22 end
23 end
23 end
24
24
25 resources :announcements do
25 resources :announcements do
26 member do
26 member do
27 get 'toggle','toggle_front'
27 get 'toggle','toggle_front'
28 end
28 end
29 end
29 end
30
30
31 resources :problems do
31 resources :problems do
32 member do
32 member do
33 get 'toggle'
33 get 'toggle'
34 get 'toggle_test'
34 get 'toggle_test'
35 get 'toggle_view_testcase'
35 get 'toggle_view_testcase'
36 get 'stat'
36 get 'stat'
37 end
37 end
38 collection do
38 collection do
39 get 'turn_all_off'
39 get 'turn_all_off'
40 get 'turn_all_on'
40 get 'turn_all_on'
41 get 'import'
41 get 'import'
42 get 'manage'
42 get 'manage'
43 get 'quick_create'
43 get 'quick_create'
44 post 'do_manage'
44 post 'do_manage'
45 post 'do_import'
45 post 'do_import'
46 end
46 end
47 end
47 end
48
48
49 resources :groups do
49 resources :groups do
50 member do
50 member do
51 post 'add_user', to: 'groups#add_user', as: 'add_user'
51 post 'add_user', to: 'groups#add_user', as: 'add_user'
52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
57 get 'toggle'
57 get 'toggle'
58 end
58 end
59 collection do
59 collection do
60
60
61 end
61 end
62 end
62 end
63
63
64 resources :testcases, only: [] do
64 resources :testcases, only: [] do
65 member do
65 member do
66 get 'download_input'
66 get 'download_input'
67 get 'download_sol'
67 get 'download_sol'
68 end
68 end
69 collection do
69 collection do
70 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
70 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
71 end
71 end
72 end
72 end
73
73
74 resources :grader_configuration, controller: 'configurations' do
74 resources :grader_configuration, controller: 'configurations' do
75 collection do
75 collection do
76 get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right'
76 get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right'
77 end
77 end
78 end
78 end
79
79
80 resources :users do
80 resources :users do
81 member do
81 member do
82 get 'toggle_activate', 'toggle_enable'
82 get 'toggle_activate', 'toggle_enable'
83 get 'stat'
83 get 'stat'
84 end
84 end
85 collection do
85 collection do
86 get 'profile'
86 get 'profile'
87 post 'chg_passwd'
87 post 'chg_passwd'
88 end
88 end
89 end
89 end
90
90
91 resources :submissions do
91 resources :submissions do
92 member do
92 member do
93 get 'download'
93 get 'download'
94 get 'compiler_msg'
94 get 'compiler_msg'
95 get 'rejudge'
95 get 'rejudge'
96 end
96 end
97 collection do
97 collection do
98 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
98 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
99 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
99 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
100 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
100 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
101 end
101 end
102 end
102 end
103
103
104
104
105 #user admin
105 #user admin
106 resources :user_admin do
106 resources :user_admin do
107 collection do
107 collection do
108 match 'bulk_manage', via: [:get, :post]
108 match 'bulk_manage', via: [:get, :post]
109 get 'bulk_mail'
109 get 'bulk_mail'
110 get 'user_stat'
110 get 'user_stat'
111 get 'import'
111 get 'import'
112 get 'new_list'
112 get 'new_list'
113 get 'admin'
113 get 'admin'
114 get 'active'
114 get 'active'
115 get 'mass_mailing'
115 get 'mass_mailing'
116 - get 'revoke_admin'
116 + match 'modify_role', via: [:get, :post]
117 - post 'grant_admin'
118 match 'create_from_list', via: [:get, :post]
117 match 'create_from_list', via: [:get, :post]
119 match 'random_all_passwords', via: [:get, :post]
118 match 'random_all_passwords', via: [:get, :post]
120 end
119 end
121 member do
120 member do
122 get 'clear_last_ip'
121 get 'clear_last_ip'
123 end
122 end
124 end
123 end
125
124
126 resources :contest_management, only: [:index] do
125 resources :contest_management, only: [:index] do
127 collection do
126 collection do
128 get 'user_stat'
127 get 'user_stat'
129 get 'clear_stat'
128 get 'clear_stat'
130 get 'clear_all_stat'
129 get 'clear_all_stat'
131 get 'change_contest_mode'
130 get 'change_contest_mode'
132 end
131 end
133 end
132 end
134
133
135 #get 'user_admin', to: 'user_admin#index'
134 #get 'user_admin', to: 'user_admin#index'
136 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
135 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
137 #post 'user_admin', to: 'user_admin#create'
136 #post 'user_admin', to: 'user_admin#create'
138 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
137 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
139
138
140 #singular resource
139 #singular resource
141 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
140 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
142 #report
141 #report
143 resource :report, only: [], controller: 'report' do
142 resource :report, only: [], controller: 'report' do
144 get 'login'
143 get 'login'
145 get 'multiple_login'
144 get 'multiple_login'
146 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
145 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
147 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
146 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
148 get 'max_score'
147 get 'max_score'
149 post 'show_max_score'
148 post 'show_max_score'
150 get 'stuck'
149 get 'stuck'
151 get 'cheat_report'
150 get 'cheat_report'
152 post 'cheat_report'
151 post 'cheat_report'
153 get 'cheat_scrutinize'
152 get 'cheat_scrutinize'
154 post 'cheat_scrutinize'
153 post 'cheat_scrutinize'
155 get 'submission'
154 get 'submission'
156 post 'submission_query'
155 post 'submission_query'
157 get 'login_stat'
156 get 'login_stat'
158 post 'login_stat'
157 post 'login_stat'
159 get 'login'
158 get 'login'
160 post 'login_summary_query'
159 post 'login_summary_query'
161 post 'login_detail_query'
160 post 'login_detail_query'
162 end
161 end
163 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
162 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
164 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
163 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
165 #get "report/login"
164 #get "report/login"
166 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
165 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
167 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
166 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
168
167
169 resource :main, only: [], controller: 'main' do
168 resource :main, only: [], controller: 'main' do
170 get 'login'
169 get 'login'
171 get 'logout'
170 get 'logout'
172 get 'list'
171 get 'list'
173 get 'submission(/:id)', action: 'submission', as: 'main_submission'
172 get 'submission(/:id)', action: 'submission', as: 'main_submission'
174 get 'announcements'
173 get 'announcements'
175 get 'help'
174 get 'help'
176 post 'submit'
175 post 'submit'
177 end
176 end
178 #main
177 #main
179 #get "main/list"
178 #get "main/list"
180 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
179 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
181 #post 'main/submit', to: 'main#submit'
180 #post 'main/submit', to: 'main#submit'
182 #get 'main/announcements', to: 'main#announcements'
181 #get 'main/announcements', to: 'main#announcements'
183
182
184
183
185 #
184 #
186 get 'tasks/view/:file.:ext' => 'tasks#view'
185 get 'tasks/view/:file.:ext' => 'tasks#view'
187 get 'tasks/download/:id/:file.:ext' => 'tasks#download', as: 'download_task'
186 get 'tasks/download/:id/:file.:ext' => 'tasks#download', as: 'download_task'
188 get 'heartbeat/:id/edit' => 'heartbeat#edit'
187 get 'heartbeat/:id/edit' => 'heartbeat#edit'
189
188
190 #grader
189 #grader
191 - get 'graders/list', to: 'graders#list', as: 'grader_list'
190 + #get 'graders/list', to: 'graders#list', as: 'grader_list'
192 namespace :graders do
191 namespace :graders do
193 get 'task/:id/:type', action: 'task', as: 'task'
192 get 'task/:id/:type', action: 'task', as: 'task'
194 get 'view/:id/:type', action: 'view', as: 'view'
193 get 'view/:id/:type', action: 'view', as: 'view'
195 get 'clear/:id', action: 'clear', as: 'clear'
194 get 'clear/:id', action: 'clear', as: 'clear'
196 - get 'stop'
197 - get 'stop_all'
198 - get 'clear_all'
199 - get 'clear_terminated'
200 get 'start_grading'
195 get 'start_grading'
201 get 'start_exam'
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 end
203 end
204
204
205
205
206 # See how all your routes lay out with "rake routes"
206 # See how all your routes lay out with "rake routes"
207
207
208 # This is a legacy wild controller route that's not recommended for RESTful applications.
208 # This is a legacy wild controller route that's not recommended for RESTful applications.
209 # Note: This route will make all actions in every controller accessible via GET requests.
209 # Note: This route will make all actions in every controller accessible via GET requests.
210 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
210 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
211 end
211 end
@@ -36,253 +36,254
36 :key => 'system.mode',
36 :key => 'system.mode',
37 :value_type => 'string',
37 :value_type => 'string',
38 :default_value => 'standard',
38 :default_value => 'standard',
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 },
40 },
41
41
42 {
42 {
43 :key => 'contest.name',
43 :key => 'contest.name',
44 :value_type => 'string',
44 :value_type => 'string',
45 :default_value => 'Grader',
45 :default_value => 'Grader',
46 :description => 'This name will be shown on the user header bar.'
46 :description => 'This name will be shown on the user header bar.'
47 },
47 },
48
48
49 {
49 {
50 :key => 'contest.multisites',
50 :key => 'contest.multisites',
51 :value_type => 'boolean',
51 :value_type => 'boolean',
52 :default_value => 'false',
52 :default_value => 'false',
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.'
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 #---------------------------- right --------------------------------
56 #---------------------------- right --------------------------------
57 {
57 {
58 :key => 'right.user_hall_of_fame',
58 :key => 'right.user_hall_of_fame',
59 :value_type => 'boolean',
59 :value_type => 'boolean',
60 :default_value => 'false',
60 :default_value => 'false',
61 :description => 'If true, any user can access hall of fame page.'
61 :description => 'If true, any user can access hall of fame page.'
62 },
62 },
63
63
64 {
64 {
65 :key => 'right.multiple_ip_login',
65 :key => 'right.multiple_ip_login',
66 :value_type => 'boolean',
66 :value_type => 'boolean',
67 :default_value => 'true',
67 :default_value => 'true',
68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
69 },
69 },
70
70
71 {
71 {
72 :key => 'right.user_view_submission',
72 :key => 'right.user_view_submission',
73 :value_type => 'boolean',
73 :value_type => 'boolean',
74 :default_value => 'false',
74 :default_value => 'false',
75 :description => 'If true, any user can view submissions of every one.'
75 :description => 'If true, any user can view submissions of every one.'
76 },
76 },
77
77
78 {
78 {
79 :key => 'right.bypass_agreement',
79 :key => 'right.bypass_agreement',
80 :value_type => 'boolean',
80 :value_type => 'boolean',
81 :default_value => 'true',
81 :default_value => 'true',
82 :description => 'When false, a user must accept usage agreement before login'
82 :description => 'When false, a user must accept usage agreement before login'
83 },
83 },
84
84
85 {
85 {
86 :key => 'right.heartbeat_response',
86 :key => 'right.heartbeat_response',
87 :value_type => 'string',
87 :value_type => 'string',
88 :default_value => 'OK',
88 :default_value => 'OK',
89 :description => 'Heart beat response text'
89 :description => 'Heart beat response text'
90 },
90 },
91
91
92 {
92 {
93 :key => 'right.heartbeat_response_full',
93 :key => 'right.heartbeat_response_full',
94 :value_type => 'string',
94 :value_type => 'string',
95 :default_value => 'OK',
95 :default_value => 'OK',
96 :description => 'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
96 :description => 'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
97 },
97 },
98
98
99 {
99 {
100 :key => 'right.view_testcase',
100 :key => 'right.view_testcase',
101 :value_type => 'boolean',
101 :value_type => 'boolean',
102 :default_value => 'false',
102 :default_value => 'false',
103 :description => 'If true, any user can view/download test data'
103 :description => 'If true, any user can view/download test data'
104 },
104 },
105
105
106 {
106 {
107 :key => 'system.online_registration',
107 :key => 'system.online_registration',
108 :value_type => 'boolean',
108 :value_type => 'boolean',
109 :default_value => 'false',
109 :default_value => 'false',
110 :description => 'This option enables online registration.'
110 :description => 'This option enables online registration.'
111 },
111 },
112
112
113 # If Configuration['system.online_registration'] is true, the
113 # If Configuration['system.online_registration'] is true, the
114 # system allows online registration, and will use these
114 # system allows online registration, and will use these
115 # information for sending confirmation emails.
115 # information for sending confirmation emails.
116 {
116 {
117 :key => 'system.online_registration.smtp',
117 :key => 'system.online_registration.smtp',
118 :value_type => 'string',
118 :value_type => 'string',
119 :default_value => 'smtp.somehost.com'
119 :default_value => 'smtp.somehost.com'
120 },
120 },
121
121
122 {
122 {
123 :key => 'system.online_registration.from',
123 :key => 'system.online_registration.from',
124 :value_type => 'string',
124 :value_type => 'string',
125 :default_value => 'your.email@address'
125 :default_value => 'your.email@address'
126 },
126 },
127
127
128 {
128 {
129 :key => 'system.admin_email',
129 :key => 'system.admin_email',
130 :value_type => 'string',
130 :value_type => 'string',
131 :default_value => 'admin@admin.email'
131 :default_value => 'admin@admin.email'
132 },
132 },
133
133
134 {
134 {
135 :key => 'system.user_setting_enabled',
135 :key => 'system.user_setting_enabled',
136 :value_type => 'boolean',
136 :value_type => 'boolean',
137 :default_value => 'true',
137 :default_value => 'true',
138 :description => 'If this option is true, users can change their settings'
138 :description => 'If this option is true, users can change their settings'
139 },
139 },
140
140
141 {
141 {
142 :key => 'system.user_setting_enabled',
142 :key => 'system.user_setting_enabled',
143 :value_type => 'boolean',
143 :value_type => 'boolean',
144 :default_value => 'true',
144 :default_value => 'true',
145 :description => 'If this option is true, users can change their settings'
145 :description => 'If this option is true, users can change their settings'
146 },
146 },
147
147
148 # If Configuration['contest.test_request.early_timeout'] is true
148 # If Configuration['contest.test_request.early_timeout'] is true
149 # the user will not be able to use test request at 30 minutes
149 # the user will not be able to use test request at 30 minutes
150 # before the contest ends.
150 # before the contest ends.
151 {
151 {
152 :key => 'contest.test_request.early_timeout',
152 :key => 'contest.test_request.early_timeout',
153 :value_type => 'boolean',
153 :value_type => 'boolean',
154 :default_value => 'false'
154 :default_value => 'false'
155 },
155 },
156
156
157 {
157 {
158 :key => 'system.multicontests',
158 :key => 'system.multicontests',
159 :value_type => 'boolean',
159 :value_type => 'boolean',
160 :default_value => 'false'
160 :default_value => 'false'
161 },
161 },
162
162
163 {
163 {
164 :key => 'contest.confirm_indv_contest_start',
164 :key => 'contest.confirm_indv_contest_start',
165 :value_type => 'boolean',
165 :value_type => 'boolean',
166 :default_value => 'false'
166 :default_value => 'false'
167 },
167 },
168
168
169 {
169 {
170 :key => 'contest.default_contest_name',
170 :key => 'contest.default_contest_name',
171 :value_type => 'string',
171 :value_type => 'string',
172 :default_value => 'none',
172 :default_value => 'none',
173 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
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 :key => 'system.use_problem_group',
177 :key => 'system.use_problem_group',
178 :value_type => 'boolean',
178 :value_type => 'boolean',
179 :default_value => 'false',
179 :default_value => 'false',
180 :description => "If true, available problem to the user will be only ones associated with the group of the user."
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 :key => 'right.whitelist_ignore',
185 :key => 'right.whitelist_ignore',
186 :value_type => 'boolean',
186 :value_type => 'boolean',
187 :default_value => 'true',
187 :default_value => 'true',
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."
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 :key => 'right.whitelist_ip',
192 :key => 'right.whitelist_ip',
193 :value_type => 'string',
193 :value_type => 'string',
194 :default_value => '0.0.0.0/0',
194 :default_value => '0.0.0.0/0',
195 :description => "list of whitelist ip, given in comma separated CIDR notation. For example '192.168.90.0/23, 192.168.1.23/32'"
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 def create_configuration_key(key,
201 def create_configuration_key(key,
202 value_type,
202 value_type,
203 default_value,
203 default_value,
204 description='')
204 description='')
205 conf = (GraderConfiguration.find_by_key(key) ||
205 conf = (GraderConfiguration.find_by_key(key) ||
206 GraderConfiguration.new(:key => key,
206 GraderConfiguration.new(:key => key,
207 :value_type => value_type,
207 :value_type => value_type,
208 :value => default_value))
208 :value => default_value))
209 conf.description = description
209 conf.description = description
210 conf.save
210 conf.save
211 end
211 end
212
212
213 def seed_config
213 def seed_config
214 CONFIGURATIONS.each do |conf|
214 CONFIGURATIONS.each do |conf|
215 if conf.has_key? :description
215 if conf.has_key? :description
216 desc = conf[:description]
216 desc = conf[:description]
217 else
217 else
218 desc = ''
218 desc = ''
219 end
219 end
220 create_configuration_key(conf[:key],
220 create_configuration_key(conf[:key],
221 conf[:value_type],
221 conf[:value_type],
222 conf[:default_value],
222 conf[:default_value],
223 desc)
223 desc)
224 end
224 end
225 end
225 end
226
226
227 def seed_roles
227 def seed_roles
228 + Role.find_or_create_by(name: 'TA')
228 return if Role.find_by_name('admin')
229 return if Role.find_by_name('admin')
229
230
230 role = Role.create(:name => 'admin')
231 role = Role.create(:name => 'admin')
231 user_admin_right = Right.create(:name => 'user_admin',
232 user_admin_right = Right.create(:name => 'user_admin',
232 :controller => 'user_admin',
233 :controller => 'user_admin',
233 :action => 'all')
234 :action => 'all')
234 problem_admin_right = Right.create(:name=> 'problem_admin',
235 problem_admin_right = Right.create(:name=> 'problem_admin',
235 :controller => 'problems',
236 :controller => 'problems',
236 :action => 'all')
237 :action => 'all')
237
238
238 graders_right = Right.create(:name => 'graders_admin',
239 graders_right = Right.create(:name => 'graders_admin',
239 :controller => 'graders',
240 :controller => 'graders',
240 :action => 'all')
241 :action => 'all')
241
242
242 role.rights << user_admin_right;
243 role.rights << user_admin_right;
243 role.rights << problem_admin_right;
244 role.rights << problem_admin_right;
244 role.rights << graders_right;
245 role.rights << graders_right;
245 role.save
246 role.save
246 end
247 end
247
248
248 def seed_root
249 def seed_root
249 return if User.find_by_login('root')
250 return if User.find_by_login('root')
250
251
251 root = User.new(:login => 'root',
252 root = User.new(:login => 'root',
252 :full_name => 'Administrator',
253 :full_name => 'Administrator',
253 :alias => 'root')
254 :alias => 'root')
254 root.password = 'ioionrails';
255 root.password = 'ioionrails';
255
256
256 class << root
257 class << root
257 public :encrypt_new_password
258 public :encrypt_new_password
258 def valid?(context=nil)
259 def valid?(context=nil)
259 true
260 true
260 end
261 end
261 end
262 end
262
263
263 root.encrypt_new_password
264 root.encrypt_new_password
264
265
265 root.roles << Role.find_by_name('admin')
266 root.roles << Role.find_by_name('admin')
266
267
267 root.activated = true
268 root.activated = true
268 root.save
269 root.save
269 end
270 end
270
271
271 def seed_users_and_roles
272 def seed_users_and_roles
272 seed_roles
273 seed_roles
273 seed_root
274 seed_root
274 end
275 end
275
276
276 def seed_more_languages
277 def seed_more_languages
277 #Language.delete_all
278 #Language.delete_all
278 Language.find_or_create_by( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
279 Language.find_or_create_by( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
279 Language.find_or_create_by( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
280 Language.find_or_create_by( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
280 Language.find_or_create_by( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
281 Language.find_or_create_by( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
281 Language.find_or_create_by( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
282 Language.find_or_create_by( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
282 Language.find_or_create_by( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
283 Language.find_or_create_by( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
283 Language.find_or_create_by( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
284 Language.find_or_create_by( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
284 end
285 end
285
286
286 seed_config
287 seed_config
287 seed_users_and_roles
288 seed_users_and_roles
288 seed_more_languages
289 seed_more_languages
You need to be logged in to leave comments. Login now