Description:
* DRY the toggle button via application_helper.rb#toggle_button and _toggle_button.js.haml * bootrapize the user_admin * now considering user.enabled * tidy up route
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r562:ede66b5a6449 - - 15 files changed: 171 inserted, 52 deleted

@@ -0,0 +1,7
1 + :plain
2 + var t = $("#{button_id}");
3 + t.removeClass('btn-default');
4 + t.removeClass('btn-success');
5 + t.removeClass('btn-warning');
6 + t.addClass("btn-#{button_on ? 'success' : 'default'}");
7 + t.text("#{button_on ? 'Yes' : 'No'}");
@@ -0,0 +1,86
1 + %h1 Listing users
2 + .submitbox
3 + %b Quick add
4 + = form_tag :action => 'create' do
5 + %table{:border => "0"}
6 + %tr
7 + %td
8 + %label{:for => "user_login"} Login
9 + %td
10 + %label{:for => "user_full_name"} Full name
11 + %td
12 + %label{:for => "user_password"} Password
13 + %td
14 + %label{:for => "user_password_confirmation"} Confirm
15 + %td
16 + %label{:for => "user_email"} Email
17 + %tr
18 + %td= text_field 'user', 'login', :size => 10
19 + %td= text_field 'user', 'full_name', :size => 30
20 + %td= password_field 'user', 'password', :size => 10
21 + %td= password_field 'user', 'password_confirmation', :size => 10
22 + %td= email_field 'user', 'email', :size => 15
23 + %td= submit_tag "Create"
24 + %br/
25 + %b Import from site management
26 + = form_tag({:action => 'import'}, :multipart => true) do
27 + File: #{file_field_tag 'file'} #{submit_tag 'Import'}
28 + %br/
29 + %b What else:
30 + = link_to 'New user', {:action => 'new'}, { class: 'btn btn-default btn-sm'}
31 + = link_to 'New list of users',{ :action => 'new_list'}, { class: 'btn btn-default btn-sm'}
32 + = link_to 'View administrators',{ :action => 'admin'}, { class: 'btn btn-default btn-sm'}
33 + = link_to 'Random passwords',{ :action => 'random_all_passwords'}, { class: 'btn btn-default btn-sm'}
34 + = link_to 'View active users',{ :action => 'active'}, { class: 'btn btn-default btn-sm'}
35 + = link_to 'Mass mailing',{ :action => 'mass_mailing'}, { class: 'btn btn-default btn-sm'}
36 + - if GraderConfiguration.multicontests?
37 + %br/
38 + %b Multi-contest:
39 + = link_to '[Manage bulk users in contests]', :action => 'contest_management'
40 + View users in:
41 + - @contests.each do |contest|
42 + = link_to "[#{contest.name}]", :action => 'contests', :id => contest.id
43 + = link_to "[no contest]", :action => 'contests', :id => 'none'
44 + Total #{@user_count} users |
45 + - if !@paginated
46 + Display all users.
47 + \#{link_to '[show in pages]', :action => 'index', :page => '1'}
48 + - else
49 + Display in pages.
50 + \#{link_to '[display all]', :action => 'index', :page => 'all'} |
51 + \#{will_paginate @users, :container => false}
52 +
53 +
54 + %table.table.table-hover.table-condense
55 + %thead
56 + %th Login
57 + %th Full name
58 + %th email
59 + %th Remark
60 + %th
61 + Activated
62 + %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'User has already confirmed the email?' } [?]
63 + %th
64 + Enabled
65 + %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'Allow the user to login?' } [?]
66 + %th Last IP
67 + %th
68 + %th
69 + %th
70 + %th
71 + - for user in @users
72 + %tr
73 + %td= link_to user.login, controller: :users, :action => 'profile', :id => user
74 + %td= user.full_name
75 + %td= user.email
76 + %td= user.remark
77 + %td= toggle_button(user.activated?, toggle_activate_user_url(user),"toggle_activate_user_#{user.id}")
78 + %td= toggle_button(user.enabled?, toggle_enable_user_url(user),"toggle_enable_user_#{user.id}")
79 + %td= user.last_ip
80 + %td= link_to 'Clear IP', {:action => 'clear_last_ip', :id => user, :page=>params[:page]}, :confirm => 'This will reset last logging in ip of the user, are you sure?', class: 'btn btn-default btn-xs btn-block'
81 + %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-default btn-xs btn-block'
82 + %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-default btn-xs btn-block'
83 + %td= link_to 'Destroy', { :action => 'destroy', :id => user }, :confirm => 'Are you sure?', :method => :post, class: 'btn btn-danger btn-xs btn-block'
84 + %br/
85 + = link_to '[New user]', :action => 'new'
86 + = link_to '[New list of users]', :action => 'new_list'
@@ -1,14 +1,6
1 #js for announcement
1 #js for announcement
2 $ ->
2 $ ->
3 - $('.ajax-toggle').on 'click', (event) ->
4 - target = $(event.target)
5 - target.removeClass 'btn-default'
6 - target.removeClass 'btn-success'
7 - target.addClass 'btn-warning'
8 - target.text '...'
9 - return
10 -
11 $(document).ajaxError (event, jqxhr, settings, exception) ->
3 $(document).ajaxError (event, jqxhr, settings, exception) ->
12 if jqxhr.status
4 if jqxhr.status
13 alert 'We\'re sorry, but something went wrong (' + jqxhr.status + ')'
5 alert 'We\'re sorry, but something went wrong (' + jqxhr.status + ')'
14 return
6 return
@@ -1,35 +1,41
1 $(document).on 'change', '.btn-file :file', ->
1 $(document).on 'change', '.btn-file :file', ->
2 input = $(this)
2 input = $(this)
3 numFiles = if input.get(0).files then input.get(0).files.length else 1
3 numFiles = if input.get(0).files then input.get(0).files.length else 1
4 label = input.val().replace(/\\/g, '/').replace(/.*\//, '')
4 label = input.val().replace(/\\/g, '/').replace(/.*\//, '')
5 input.trigger 'fileselect', [
5 input.trigger 'fileselect', [
6 numFiles
6 numFiles
7 label
7 label
8 ]
8 ]
9 return
9 return
10
10
11
11
12 # document ready
12 # document ready
13
13
14 $ ->
14 $ ->
15 $(".select2").select2()
15 $(".select2").select2()
16 #$(".bootstrap-switch").bootstrapSwitch()
16 #$(".bootstrap-switch").bootstrapSwitch()
17 $(".bootstrap-toggle").bootstrapToggle()
17 $(".bootstrap-toggle").bootstrapToggle()
18 $('.btn-file :file').on 'fileselect', (event, numFiles, label) ->
18 $('.btn-file :file').on 'fileselect', (event, numFiles, label) ->
19 input = $(this).parents('.input-group').find(':text')
19 input = $(this).parents('.input-group').find(':text')
20 log = if numFiles > 1 then numFiles + ' files selected' else label
20 log = if numFiles > 1 then numFiles + ' files selected' else label
21 if input.length
21 if input.length
22 input.val log
22 input.val log
23 else
23 else
24 if log
24 if log
25 alert log
25 alert log
26 return
26 return
27 $(".go-button").on 'click', (event) ->
27 $(".go-button").on 'click', (event) ->
28 link = $(this).attr("data-source")
28 link = $(this).attr("data-source")
29 url = $(link).val()
29 url = $(link).val()
30 if url
30 if url
31 window.location.href = url
31 window.location.href = url
32 return
32 return
33 - return
33 + $('.ajax-toggle').on 'click', (event) ->
34 + target = $(event.target)
35 + target.removeClass 'btn-default'
36 + target.removeClass 'btn-success'
37 + target.addClass 'btn-warning'
38 + target.text '...'
39 + return
34
40
35 -
41 + return
@@ -1,101 +1,102
1 class AnnouncementsController < ApplicationController
1 class AnnouncementsController < ApplicationController
2
2
3 before_filter :admin_authorization
3 before_filter :admin_authorization
4
4
5 in_place_edit_for :announcement, :published
5 in_place_edit_for :announcement, :published
6
6
7 # GET /announcements
7 # GET /announcements
8 # GET /announcements.xml
8 # GET /announcements.xml
9 def index
9 def index
10 @announcements = Announcement.find(:all,
10 @announcements = Announcement.find(:all,
11 :order => "created_at DESC")
11 :order => "created_at DESC")
12
12
13 respond_to do |format|
13 respond_to do |format|
14 format.html # index.html.erb
14 format.html # index.html.erb
15 format.xml { render :xml => @announcements }
15 format.xml { render :xml => @announcements }
16 end
16 end
17 end
17 end
18
18
19 # GET /announcements/1
19 # GET /announcements/1
20 # GET /announcements/1.xml
20 # GET /announcements/1.xml
21 def show
21 def show
22 @announcement = Announcement.find(params[:id])
22 @announcement = Announcement.find(params[:id])
23
23
24 respond_to do |format|
24 respond_to do |format|
25 format.html # show.html.erb
25 format.html # show.html.erb
26 format.xml { render :xml => @announcement }
26 format.xml { render :xml => @announcement }
27 end
27 end
28 end
28 end
29
29
30 # GET /announcements/new
30 # GET /announcements/new
31 # GET /announcements/new.xml
31 # GET /announcements/new.xml
32 def new
32 def new
33 @announcement = Announcement.new
33 @announcement = Announcement.new
34
34
35 respond_to do |format|
35 respond_to do |format|
36 format.html # new.html.erb
36 format.html # new.html.erb
37 format.xml { render :xml => @announcement }
37 format.xml { render :xml => @announcement }
38 end
38 end
39 end
39 end
40
40
41 # GET /announcements/1/edit
41 # GET /announcements/1/edit
42 def edit
42 def edit
43 @announcement = Announcement.find(params[:id])
43 @announcement = Announcement.find(params[:id])
44 end
44 end
45
45
46 # POST /announcements
46 # POST /announcements
47 # POST /announcements.xml
47 # POST /announcements.xml
48 def create
48 def create
49 @announcement = Announcement.new(params[:announcement])
49 @announcement = Announcement.new(params[:announcement])
50
50
51 respond_to do |format|
51 respond_to do |format|
52 if @announcement.save
52 if @announcement.save
53 flash[:notice] = 'Announcement was successfully created.'
53 flash[:notice] = 'Announcement was successfully created.'
54 format.html { redirect_to(@announcement) }
54 format.html { redirect_to(@announcement) }
55 format.xml { render :xml => @announcement, :status => :created, :location => @announcement }
55 format.xml { render :xml => @announcement, :status => :created, :location => @announcement }
56 else
56 else
57 format.html { render :action => "new" }
57 format.html { render :action => "new" }
58 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
58 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
59 end
59 end
60 end
60 end
61 end
61 end
62
62
63 # PUT /announcements/1
63 # PUT /announcements/1
64 # PUT /announcements/1.xml
64 # PUT /announcements/1.xml
65 def update
65 def update
66 @announcement = Announcement.find(params[:id])
66 @announcement = Announcement.find(params[:id])
67
67
68 respond_to do |format|
68 respond_to do |format|
69 if @announcement.update_attributes(params[:announcement])
69 if @announcement.update_attributes(params[:announcement])
70 flash[:notice] = 'Announcement was successfully updated.'
70 flash[:notice] = 'Announcement was successfully updated.'
71 format.html { redirect_to(@announcement) }
71 format.html { redirect_to(@announcement) }
72 format.js {}
72 format.js {}
73 format.xml { head :ok }
73 format.xml { head :ok }
74 else
74 else
75 format.html { render :action => "edit" }
75 format.html { render :action => "edit" }
76 format.js {}
76 format.js {}
77 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
77 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
78 end
78 end
79 end
79 end
80 end
80 end
81
81
82 def toggle
82 def toggle
83 @announcement = Announcement.find(params[:id])
83 @announcement = Announcement.find(params[:id])
84 @announcement.update_attributes( published: !@announcement.published? )
84 @announcement.update_attributes( published: !@announcement.published? )
85 respond_to do |format|
85 respond_to do |format|
86 - format.js {}
86 + format.js { render partial: 'toggle_button',
87 + locals: {button_id: "#announcement_toggle_#{@announcement.id}",button_on: @announcement.published? } }
87 end
88 end
88 end
89 end
89
90
90 # DELETE /announcements/1
91 # DELETE /announcements/1
91 # DELETE /announcements/1.xml
92 # DELETE /announcements/1.xml
92 def destroy
93 def destroy
93 @announcement = Announcement.find(params[:id])
94 @announcement = Announcement.find(params[:id])
94 @announcement.destroy
95 @announcement.destroy
95
96
96 respond_to do |format|
97 respond_to do |format|
97 format.html { redirect_to(announcements_url) }
98 format.html { redirect_to(announcements_url) }
98 format.xml { head :ok }
99 format.xml { head :ok }
99 end
100 end
100 end
101 end
101 end
102 end
@@ -1,119 +1,124
1 class ApplicationController < ActionController::Base
1 class ApplicationController < ActionController::Base
2 protect_from_forgery
2 protect_from_forgery
3
3
4 before_filter :current_user
4 before_filter :current_user
5
5
6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
8
8
9 # Returns the current logged-in user (if any).
9 # Returns the current logged-in user (if any).
10 def current_user
10 def current_user
11 return nil unless session[:user_id]
11 return nil unless session[:user_id]
12 @current_user ||= User.find(session[:user_id])
12 @current_user ||= User.find(session[:user_id])
13 end
13 end
14
14
15 def admin_authorization
15 def admin_authorization
16 return false unless authenticate
16 return false unless authenticate
17 user = User.find(session[:user_id], :include => ['roles'])
17 user = User.find(session[:user_id], :include => ['roles'])
18 unless user.admin?
18 unless user.admin?
19 flash[:notice] = 'You are not authorized to view the page you requested'
19 flash[:notice] = 'You are not authorized to view the page you requested'
20 redirect_to :controller => 'main', :action => 'login' unless user.admin?
20 redirect_to :controller => 'main', :action => 'login' unless user.admin?
21 return false
21 return false
22 end
22 end
23 return true
23 return true
24 end
24 end
25
25
26 def authorization_by_roles(allowed_roles)
26 def authorization_by_roles(allowed_roles)
27 return false unless authenticate
27 return false unless authenticate
28 user = User.find(session[:user_id])
28 user = User.find(session[:user_id])
29 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
29 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
30 flash[:notice] = 'You are not authorized to view the page you requested'
30 flash[:notice] = 'You are not authorized to view the page you requested'
31 redirect_to :controller => 'main', :action => 'login'
31 redirect_to :controller => 'main', :action => 'login'
32 return false
32 return false
33 end
33 end
34 end
34 end
35
35
36 protected
36 protected
37
37
38 def authenticate
38 def authenticate
39 unless session[:user_id]
39 unless session[:user_id]
40 flash[:notice] = 'You need to login'
40 flash[:notice] = 'You need to login'
41 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
41 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
42 flash[:notice] = 'You need to login but you cannot log in at this time'
42 flash[:notice] = 'You need to login but you cannot log in at this time'
43 end
43 end
44 redirect_to :controller => 'main', :action => 'login'
44 redirect_to :controller => 'main', :action => 'login'
45 return false
45 return false
46 end
46 end
47
47
48 # check if run in single user mode
48 # check if run in single user mode
49 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
49 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
50 - user = User.find(session[:user_id])
50 + user = User.find_by_id(session[:user_id])
51 if user==nil or (not user.admin?)
51 if user==nil or (not user.admin?)
52 flash[:notice] = 'You cannot log in at this time'
52 flash[:notice] = 'You cannot log in at this time'
53 redirect_to :controller => 'main', :action => 'login'
53 redirect_to :controller => 'main', :action => 'login'
54 return false
54 return false
55 end
55 end
56 + unless user.enabled?
57 + flash[:notice] = 'Your account is disabled'
58 + redirect_to :controller => 'main', :action => 'login'
59 + return false
60 + end
56 return true
61 return true
57 end
62 end
58
63
59 if GraderConfiguration.multicontests?
64 if GraderConfiguration.multicontests?
60 user = User.find(session[:user_id])
65 user = User.find(session[:user_id])
61 return true if user.admin?
66 return true if user.admin?
62 begin
67 begin
63 if user.contest_stat(true).forced_logout
68 if user.contest_stat(true).forced_logout
64 flash[:notice] = 'You have been automatically logged out.'
69 flash[:notice] = 'You have been automatically logged out.'
65 redirect_to :controller => 'main', :action => 'index'
70 redirect_to :controller => 'main', :action => 'index'
66 end
71 end
67 rescue
72 rescue
68 end
73 end
69 end
74 end
70 return true
75 return true
71 end
76 end
72
77
73 def authenticate_by_ip_address
78 def authenticate_by_ip_address
74 #this assume that we have already authenticate normally
79 #this assume that we have already authenticate normally
75 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
80 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
76 user = User.find(session[:user_id])
81 user = User.find(session[:user_id])
77 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
82 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
78 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
83 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
79 redirect_to :controller => 'main', :action => 'login'
84 redirect_to :controller => 'main', :action => 'login'
80 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
85 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
81 return false
86 return false
82 end
87 end
83 unless user.last_ip
88 unless user.last_ip
84 user.last_ip = request.remote_ip
89 user.last_ip = request.remote_ip
85 user.save
90 user.save
86 end
91 end
87 end
92 end
88 return true
93 return true
89 end
94 end
90
95
91 def authorization
96 def authorization
92 return false unless authenticate
97 return false unless authenticate
93 user = User.find(session[:user_id])
98 user = User.find(session[:user_id])
94 unless user.roles.detect { |role|
99 unless user.roles.detect { |role|
95 role.rights.detect{ |right|
100 role.rights.detect{ |right|
96 right.controller == self.class.controller_name and
101 right.controller == self.class.controller_name and
97 (right.action == 'all' or right.action == action_name)
102 (right.action == 'all' or right.action == action_name)
98 }
103 }
99 }
104 }
100 flash[:notice] = 'You are not authorized to view the page you requested'
105 flash[:notice] = 'You are not authorized to view the page you requested'
101 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
106 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
102 redirect_to :controller => 'main', :action => 'login'
107 redirect_to :controller => 'main', :action => 'login'
103 return false
108 return false
104 end
109 end
105 end
110 end
106
111
107 def verify_time_limit
112 def verify_time_limit
108 return true if session[:user_id]==nil
113 return true if session[:user_id]==nil
109 user = User.find(session[:user_id], :include => :site)
114 user = User.find(session[:user_id], :include => :site)
110 return true if user==nil or user.site == nil
115 return true if user==nil or user.site == nil
111 if user.contest_finished?
116 if user.contest_finished?
112 flash[:notice] = 'Error: the contest you are participating is over.'
117 flash[:notice] = 'Error: the contest you are participating is over.'
113 redirect_to :back
118 redirect_to :back
114 return false
119 return false
115 end
120 end
116 return true
121 return true
117 end
122 end
118
123
119 end
124 end
@@ -1,274 +1,274
1 class ProblemsController < ApplicationController
1 class ProblemsController < ApplicationController
2
2
3 before_filter :authenticate, :authorization
3 before_filter :authenticate, :authorization
4
4
5 in_place_edit_for :problem, :name
5 in_place_edit_for :problem, :name
6 in_place_edit_for :problem, :full_name
6 in_place_edit_for :problem, :full_name
7 in_place_edit_for :problem, :full_score
7 in_place_edit_for :problem, :full_score
8
8
9 def index
9 def index
10 @problems = Problem.find(:all, :order => 'date_added DESC')
10 @problems = Problem.find(:all, :order => 'date_added DESC')
11 end
11 end
12
12
13 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
13 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
14 verify :method => :post, :only => [ :destroy,
14 verify :method => :post, :only => [ :destroy,
15 :create, :quick_create,
15 :create, :quick_create,
16 :do_manage,
16 :do_manage,
17 :do_import,
17 :do_import,
18 :update ],
18 :update ],
19 :redirect_to => { :action => :index }
19 :redirect_to => { :action => :index }
20
20
21 def show
21 def show
22 @problem = Problem.find(params[:id])
22 @problem = Problem.find(params[:id])
23 end
23 end
24
24
25 def new
25 def new
26 @problem = Problem.new
26 @problem = Problem.new
27 @description = nil
27 @description = nil
28 end
28 end
29
29
30 def create
30 def create
31 @problem = Problem.new(params[:problem])
31 @problem = Problem.new(params[:problem])
32 @description = Description.new(params[:description])
32 @description = Description.new(params[:description])
33 if @description.body!=''
33 if @description.body!=''
34 if !@description.save
34 if !@description.save
35 render :action => new and return
35 render :action => new and return
36 end
36 end
37 else
37 else
38 @description = nil
38 @description = nil
39 end
39 end
40 @problem.description = @description
40 @problem.description = @description
41 if @problem.save
41 if @problem.save
42 flash[:notice] = 'Problem was successfully created.'
42 flash[:notice] = 'Problem was successfully created.'
43 redirect_to action: :index
43 redirect_to action: :index
44 else
44 else
45 render :action => 'new'
45 render :action => 'new'
46 end
46 end
47 end
47 end
48
48
49 def quick_create
49 def quick_create
50 @problem = Problem.new(params[:problem])
50 @problem = Problem.new(params[:problem])
51 @problem.full_name = @problem.name if @problem.full_name == ''
51 @problem.full_name = @problem.name if @problem.full_name == ''
52 @problem.full_score = 100
52 @problem.full_score = 100
53 @problem.available = false
53 @problem.available = false
54 @problem.test_allowed = true
54 @problem.test_allowed = true
55 @problem.output_only = false
55 @problem.output_only = false
56 @problem.date_added = Time.new
56 @problem.date_added = Time.new
57 if @problem.save
57 if @problem.save
58 flash[:notice] = 'Problem was successfully created.'
58 flash[:notice] = 'Problem was successfully created.'
59 redirect_to action: :index
59 redirect_to action: :index
60 else
60 else
61 flash[:notice] = 'Error saving problem'
61 flash[:notice] = 'Error saving problem'
62 redirect_to action: :index
62 redirect_to action: :index
63 end
63 end
64 end
64 end
65
65
66 def edit
66 def edit
67 @problem = Problem.find(params[:id])
67 @problem = Problem.find(params[:id])
68 @description = @problem.description
68 @description = @problem.description
69 end
69 end
70
70
71 def update
71 def update
72 @problem = Problem.find(params[:id])
72 @problem = Problem.find(params[:id])
73 @description = @problem.description
73 @description = @problem.description
74 if @description == nil and params[:description][:body]!=''
74 if @description == nil and params[:description][:body]!=''
75 @description = Description.new(params[:description])
75 @description = Description.new(params[:description])
76 if !@description.save
76 if !@description.save
77 flash[:notice] = 'Error saving description'
77 flash[:notice] = 'Error saving description'
78 render :action => 'edit' and return
78 render :action => 'edit' and return
79 end
79 end
80 @problem.description = @description
80 @problem.description = @description
81 elsif @description!=nil
81 elsif @description!=nil
82 if !@description.update_attributes(params[:description])
82 if !@description.update_attributes(params[:description])
83 flash[:notice] = 'Error saving description'
83 flash[:notice] = 'Error saving description'
84 render :action => 'edit' and return
84 render :action => 'edit' and return
85 end
85 end
86 end
86 end
87 if params[:file] and params[:file].content_type != 'application/pdf'
87 if params[:file] and params[:file].content_type != 'application/pdf'
88 flash[:notice] = 'Error: Uploaded file is not PDF'
88 flash[:notice] = 'Error: Uploaded file is not PDF'
89 render :action => 'edit' and return
89 render :action => 'edit' and return
90 end
90 end
91 if @problem.update_attributes(params[:problem])
91 if @problem.update_attributes(params[:problem])
92 flash[:notice] = 'Problem was successfully updated.'
92 flash[:notice] = 'Problem was successfully updated.'
93 unless params[:file] == nil or params[:file] == ''
93 unless params[:file] == nil or params[:file] == ''
94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
96 if not FileTest.exists? out_dirname
96 if not FileTest.exists? out_dirname
97 Dir.mkdir out_dirname
97 Dir.mkdir out_dirname
98 end
98 end
99
99
100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
101 if FileTest.exists? out_filename
101 if FileTest.exists? out_filename
102 File.delete out_filename
102 File.delete out_filename
103 end
103 end
104
104
105 File.open(out_filename,"wb") do |file|
105 File.open(out_filename,"wb") do |file|
106 file.write(params[:file].read)
106 file.write(params[:file].read)
107 end
107 end
108 @problem.description_filename = "#{@problem.name}.pdf"
108 @problem.description_filename = "#{@problem.name}.pdf"
109 @problem.save
109 @problem.save
110 end
110 end
111 redirect_to :action => 'show', :id => @problem
111 redirect_to :action => 'show', :id => @problem
112 else
112 else
113 render :action => 'edit'
113 render :action => 'edit'
114 end
114 end
115 end
115 end
116
116
117 def destroy
117 def destroy
118 Problem.find(params[:id]).destroy
118 Problem.find(params[:id]).destroy
119 redirect_to action: :index
119 redirect_to action: :index
120 end
120 end
121
121
122 def toggle
122 def toggle
123 @problem = Problem.find(params[:id])
123 @problem = Problem.find(params[:id])
124 @problem.update_attributes(available: !(@problem.available) )
124 @problem.update_attributes(available: !(@problem.available) )
125 respond_to do |format|
125 respond_to do |format|
126 - format.js {}
126 + format.js { }
127 end
127 end
128 end
128 end
129
129
130 def turn_all_off
130 def turn_all_off
131 Problem.find(:all,
131 Problem.find(:all,
132 :conditions => "available = 1").each do |problem|
132 :conditions => "available = 1").each do |problem|
133 problem.available = false
133 problem.available = false
134 problem.save
134 problem.save
135 end
135 end
136 redirect_to action: :index
136 redirect_to action: :index
137 end
137 end
138
138
139 def turn_all_on
139 def turn_all_on
140 Problem.find(:all,
140 Problem.find(:all,
141 :conditions => "available = 0").each do |problem|
141 :conditions => "available = 0").each do |problem|
142 problem.available = true
142 problem.available = true
143 problem.save
143 problem.save
144 end
144 end
145 redirect_to action: :index
145 redirect_to action: :index
146 end
146 end
147
147
148 def stat
148 def stat
149 @problem = Problem.find(params[:id])
149 @problem = Problem.find(params[:id])
150 unless @problem.available or session[:admin]
150 unless @problem.available or session[:admin]
151 redirect_to :controller => 'main', :action => 'list'
151 redirect_to :controller => 'main', :action => 'list'
152 return
152 return
153 end
153 end
154 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
154 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
155
155
156 #stat summary
156 #stat summary
157 range =65
157 range =65
158 @histogram = { data: Array.new(range,0), summary: {} }
158 @histogram = { data: Array.new(range,0), summary: {} }
159 user = Hash.new(0)
159 user = Hash.new(0)
160 @submissions.find_each do |sub|
160 @submissions.find_each do |sub|
161 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
161 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
162 @histogram[:data][d.to_i] += 1 if d < range
162 @histogram[:data][d.to_i] += 1 if d < range
163 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
163 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
164 end
164 end
165 @histogram[:summary][:max] = [@histogram[:data].max,1].max
165 @histogram[:summary][:max] = [@histogram[:data].max,1].max
166
166
167 @summary = { attempt: user.count, solve: 0 }
167 @summary = { attempt: user.count, solve: 0 }
168 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
168 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
169 end
169 end
170
170
171 def manage
171 def manage
172 @problems = Problem.find(:all, :order => 'date_added DESC')
172 @problems = Problem.find(:all, :order => 'date_added DESC')
173 end
173 end
174
174
175 def do_manage
175 def do_manage
176 if params.has_key? 'change_date_added'
176 if params.has_key? 'change_date_added'
177 change_date_added
177 change_date_added
178 elsif params.has_key? 'add_to_contest'
178 elsif params.has_key? 'add_to_contest'
179 add_to_contest
179 add_to_contest
180 elsif params.has_key? 'enable_problem'
180 elsif params.has_key? 'enable_problem'
181 set_available(true)
181 set_available(true)
182 elsif params.has_key? 'disable_problem'
182 elsif params.has_key? 'disable_problem'
183 set_available(false)
183 set_available(false)
184 end
184 end
185 redirect_to :action => 'manage'
185 redirect_to :action => 'manage'
186 end
186 end
187
187
188 def import
188 def import
189 @allow_test_pair_import = allow_test_pair_import?
189 @allow_test_pair_import = allow_test_pair_import?
190 end
190 end
191
191
192 def do_import
192 def do_import
193 old_problem = Problem.find_by_name(params[:name])
193 old_problem = Problem.find_by_name(params[:name])
194 if !allow_test_pair_import? and params.has_key? :import_to_db
194 if !allow_test_pair_import? and params.has_key? :import_to_db
195 params.delete :import_to_db
195 params.delete :import_to_db
196 end
196 end
197 @problem, import_log = Problem.create_from_import_form_params(params,
197 @problem, import_log = Problem.create_from_import_form_params(params,
198 old_problem)
198 old_problem)
199
199
200 if !@problem.errors.empty?
200 if !@problem.errors.empty?
201 render :action => 'import' and return
201 render :action => 'import' and return
202 end
202 end
203
203
204 if old_problem!=nil
204 if old_problem!=nil
205 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
205 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
206 end
206 end
207 @log = import_log
207 @log = import_log
208 end
208 end
209
209
210 def remove_contest
210 def remove_contest
211 problem = Problem.find(params[:id])
211 problem = Problem.find(params[:id])
212 contest = Contest.find(params[:contest_id])
212 contest = Contest.find(params[:contest_id])
213 if problem!=nil and contest!=nil
213 if problem!=nil and contest!=nil
214 problem.contests.delete(contest)
214 problem.contests.delete(contest)
215 end
215 end
216 redirect_to :action => 'manage'
216 redirect_to :action => 'manage'
217 end
217 end
218
218
219 ##################################
219 ##################################
220 protected
220 protected
221
221
222 def allow_test_pair_import?
222 def allow_test_pair_import?
223 if defined? ALLOW_TEST_PAIR_IMPORT
223 if defined? ALLOW_TEST_PAIR_IMPORT
224 return ALLOW_TEST_PAIR_IMPORT
224 return ALLOW_TEST_PAIR_IMPORT
225 else
225 else
226 return false
226 return false
227 end
227 end
228 end
228 end
229
229
230 def change_date_added
230 def change_date_added
231 problems = get_problems_from_params
231 problems = get_problems_from_params
232 year = params[:date_added][:year].to_i
232 year = params[:date_added][:year].to_i
233 month = params[:date_added][:month].to_i
233 month = params[:date_added][:month].to_i
234 day = params[:date_added][:day].to_i
234 day = params[:date_added][:day].to_i
235 date = Date.new(year,month,day)
235 date = Date.new(year,month,day)
236 problems.each do |p|
236 problems.each do |p|
237 p.date_added = date
237 p.date_added = date
238 p.save
238 p.save
239 end
239 end
240 end
240 end
241
241
242 def add_to_contest
242 def add_to_contest
243 problems = get_problems_from_params
243 problems = get_problems_from_params
244 contest = Contest.find(params[:contest][:id])
244 contest = Contest.find(params[:contest][:id])
245 if contest!=nil and contest.enabled
245 if contest!=nil and contest.enabled
246 problems.each do |p|
246 problems.each do |p|
247 p.contests << contest
247 p.contests << contest
248 end
248 end
249 end
249 end
250 end
250 end
251
251
252 def set_available(avail)
252 def set_available(avail)
253 problems = get_problems_from_params
253 problems = get_problems_from_params
254 problems.each do |p|
254 problems.each do |p|
255 p.available = avail
255 p.available = avail
256 p.save
256 p.save
257 end
257 end
258 end
258 end
259
259
260 def get_problems_from_params
260 def get_problems_from_params
261 problems = []
261 problems = []
262 params.keys.each do |k|
262 params.keys.each do |k|
263 if k.index('prob-')==0
263 if k.index('prob-')==0
264 name, id, order = k.split('-')
264 name, id, order = k.split('-')
265 problems << Problem.find(id)
265 problems << Problem.find(id)
266 end
266 end
267 end
267 end
268 problems
268 problems
269 end
269 end
270
270
271 def get_problems_stat
271 def get_problems_stat
272 end
272 end
273
273
274 end
274 end
@@ -1,543 +1,542
1 require 'csv'
1 require 'csv'
2
2
3 class UserAdminController < ApplicationController
3 class UserAdminController < ApplicationController
4
4
5 include MailHelperMethods
5 include MailHelperMethods
6
6
7 before_filter :admin_authorization
7 before_filter :admin_authorization
8
8
9 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
9 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
10 verify :method => :post, :only => [ :destroy,
10 verify :method => :post, :only => [ :destroy,
11 :create, :create_from_list,
11 :create, :create_from_list,
12 :update,
12 :update,
13 :manage_contest,
13 :manage_contest,
14 :bulk_mail
14 :bulk_mail
15 ],
15 ],
16 :redirect_to => { :action => :list }
16 :redirect_to => { :action => :list }
17
17
18 def index
18 def index
19 list
19 list
20 - render :action => 'list'
21 end
20 end
22
21
23 def list
22 def list
24 @user_count = User.count
23 @user_count = User.count
25 if params[:page] == 'all'
24 if params[:page] == 'all'
26 @users = User.all
25 @users = User.all
27 @paginated = false
26 @paginated = false
28 else
27 else
29 @users = User.paginate :page => params[:page]
28 @users = User.paginate :page => params[:page]
30 @paginated = true
29 @paginated = true
31 end
30 end
32 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
31 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
33 @contests = Contest.enabled
32 @contests = Contest.enabled
34 end
33 end
35
34
36 def active
35 def active
37 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
36 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
38 @users = []
37 @users = []
39 sessions.each do |session|
38 sessions.each do |session|
40 if session.data[:user_id]
39 if session.data[:user_id]
41 @users << User.find(session.data[:user_id])
40 @users << User.find(session.data[:user_id])
42 end
41 end
43 end
42 end
44 end
43 end
45
44
46 def show
45 def show
47 @user = User.find(params[:id])
46 @user = User.find(params[:id])
48 end
47 end
49
48
50 def new
49 def new
51 @user = User.new
50 @user = User.new
52 end
51 end
53
52
54 def create
53 def create
55 @user = User.new(params[:user])
54 @user = User.new(params[:user])
56 @user.activated = true
55 @user.activated = true
57 if @user.save
56 if @user.save
58 flash[:notice] = 'User was successfully created.'
57 flash[:notice] = 'User was successfully created.'
59 redirect_to :action => 'list'
58 redirect_to :action => 'list'
60 else
59 else
61 render :action => 'new'
60 render :action => 'new'
62 end
61 end
63 end
62 end
64
63
65 def clear_last_ip
64 def clear_last_ip
66 @user = User.find(params[:id])
65 @user = User.find(params[:id])
67 @user.last_ip = nil
66 @user.last_ip = nil
68 @user.save
67 @user.save
69 redirect_to action: 'list', page: params[:page]
68 redirect_to action: 'list', page: params[:page]
70 end
69 end
71
70
72 def create_from_list
71 def create_from_list
73 lines = params[:user_list]
72 lines = params[:user_list]
74
73
75 note = []
74 note = []
76
75
77 lines.split("\n").each do |line|
76 lines.split("\n").each do |line|
78 items = line.chomp.split(',')
77 items = line.chomp.split(',')
79 if items.length>=2
78 if items.length>=2
80 login = items[0]
79 login = items[0]
81 full_name = items[1]
80 full_name = items[1]
82
81
83 added_random_password = false
82 added_random_password = false
84 if items.length>=3
83 if items.length>=3
85 password = items[2].chomp(" ")
84 password = items[2].chomp(" ")
86 user_alias = (items.length>=4) ? items[3] : login
85 user_alias = (items.length>=4) ? items[3] : login
87 else
86 else
88 password = random_password
87 password = random_password
89 user_alias = (items.length>=4) ? items[3] : login
88 user_alias = (items.length>=4) ? items[3] : login
90 added_random_password = true
89 added_random_password = true
91 end
90 end
92
91
93 user = User.find_by_login(login)
92 user = User.find_by_login(login)
94 if (user)
93 if (user)
95 user.full_name = full_name
94 user.full_name = full_name
96 user.password = password
95 user.password = password
97 else
96 else
98 user = User.new({:login => login,
97 user = User.new({:login => login,
99 :full_name => full_name,
98 :full_name => full_name,
100 :password => password,
99 :password => password,
101 :password_confirmation => password,
100 :password_confirmation => password,
102 :alias => user_alias})
101 :alias => user_alias})
103 end
102 end
104 user.activated = true
103 user.activated = true
105 user.save
104 user.save
106
105
107 if added_random_password
106 if added_random_password
108 note << "'#{login}' (+)"
107 note << "'#{login}' (+)"
109 else
108 else
110 note << login
109 note << login
111 end
110 end
112 end
111 end
113 end
112 end
114 flash[:notice] = 'User(s) ' + note.join(', ') +
113 flash[:notice] = 'User(s) ' + note.join(', ') +
115 ' were successfully created. ' +
114 ' were successfully created. ' +
116 '( (+) - created with random passwords.)'
115 '( (+) - created with random passwords.)'
117 redirect_to :action => 'list'
116 redirect_to :action => 'list'
118 end
117 end
119
118
120 def edit
119 def edit
121 @user = User.find(params[:id])
120 @user = User.find(params[:id])
122 end
121 end
123
122
124 def update
123 def update
125 @user = User.find(params[:id])
124 @user = User.find(params[:id])
126 if @user.update_attributes(params[:user])
125 if @user.update_attributes(params[:user])
127 flash[:notice] = 'User was successfully updated.'
126 flash[:notice] = 'User was successfully updated.'
128 redirect_to :action => 'show', :id => @user
127 redirect_to :action => 'show', :id => @user
129 else
128 else
130 render :action => 'edit'
129 render :action => 'edit'
131 end
130 end
132 end
131 end
133
132
134 def destroy
133 def destroy
135 User.find(params[:id]).destroy
134 User.find(params[:id]).destroy
136 redirect_to :action => 'list'
135 redirect_to :action => 'list'
137 end
136 end
138
137
139 def user_stat
138 def user_stat
140 if params[:commit] == 'download csv'
139 if params[:commit] == 'download csv'
141 @problems = Problem.all
140 @problems = Problem.all
142 else
141 else
143 @problems = Problem.find_available_problems
142 @problems = Problem.find_available_problems
144 end
143 end
145 @users = User.includes(:contests, :contest_stat).where(enabled: true) #find(:all, :include => [:contests, :contest_stat]).where(enabled: true)
144 @users = User.includes(:contests, :contest_stat).where(enabled: true) #find(:all, :include => [:contests, :contest_stat]).where(enabled: true)
146 @scorearray = Array.new
145 @scorearray = Array.new
147 @users.each do |u|
146 @users.each do |u|
148 ustat = Array.new
147 ustat = Array.new
149 ustat[0] = u
148 ustat[0] = u
150 @problems.each do |p|
149 @problems.each do |p|
151 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
150 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
152 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
151 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
153 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
152 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
154 else
153 else
155 ustat << [0,false]
154 ustat << [0,false]
156 end
155 end
157 end
156 end
158 @scorearray << ustat
157 @scorearray << ustat
159 end
158 end
160 if params[:commit] == 'download csv' then
159 if params[:commit] == 'download csv' then
161 csv = gen_csv_from_scorearray(@scorearray,@problems)
160 csv = gen_csv_from_scorearray(@scorearray,@problems)
162 send_data csv, filename: 'last_score.csv'
161 send_data csv, filename: 'last_score.csv'
163 else
162 else
164 render template: 'user_admin/user_stat'
163 render template: 'user_admin/user_stat'
165 end
164 end
166 end
165 end
167
166
168 def user_stat_max
167 def user_stat_max
169 if params[:commit] == 'download csv'
168 if params[:commit] == 'download csv'
170 @problems = Problem.all
169 @problems = Problem.all
171 else
170 else
172 @problems = Problem.find_available_problems
171 @problems = Problem.find_available_problems
173 end
172 end
174 @users = User.find(:all, :include => [:contests, :contest_stat])
173 @users = User.find(:all, :include => [:contests, :contest_stat])
175 @scorearray = Array.new
174 @scorearray = Array.new
176 #set up range from param
175 #set up range from param
177 since_id = params.fetch(:since_id, 0).to_i
176 since_id = params.fetch(:since_id, 0).to_i
178 until_id = params.fetch(:until_id, 0).to_i
177 until_id = params.fetch(:until_id, 0).to_i
179 @users.each do |u|
178 @users.each do |u|
180 ustat = Array.new
179 ustat = Array.new
181 ustat[0] = u
180 ustat[0] = u
182 @problems.each do |p|
181 @problems.each do |p|
183 max_points = 0
182 max_points = 0
184 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
183 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
185 max_points = sub.points if sub and sub.points and (sub.points > max_points)
184 max_points = sub.points if sub and sub.points and (sub.points > max_points)
186 end
185 end
187 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
186 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
188 end
187 end
189 @scorearray << ustat
188 @scorearray << ustat
190 end
189 end
191
190
192 if params[:commit] == 'download csv' then
191 if params[:commit] == 'download csv' then
193 csv = gen_csv_from_scorearray(@scorearray,@problems)
192 csv = gen_csv_from_scorearray(@scorearray,@problems)
194 send_data csv, filename: 'max_score.csv'
193 send_data csv, filename: 'max_score.csv'
195 else
194 else
196 render template: 'user_admin/user_stat'
195 render template: 'user_admin/user_stat'
197 end
196 end
198 end
197 end
199
198
200 def import
199 def import
201 if params[:file]==''
200 if params[:file]==''
202 flash[:notice] = 'Error importing no file'
201 flash[:notice] = 'Error importing no file'
203 redirect_to :action => 'list' and return
202 redirect_to :action => 'list' and return
204 end
203 end
205 import_from_file(params[:file])
204 import_from_file(params[:file])
206 end
205 end
207
206
208 def random_all_passwords
207 def random_all_passwords
209 users = User.find(:all)
208 users = User.find(:all)
210 @prefix = params[:prefix] || ''
209 @prefix = params[:prefix] || ''
211 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
210 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
212 @changed = false
211 @changed = false
213 if request.request_method == 'POST'
212 if request.request_method == 'POST'
214 @non_admin_users.each do |user|
213 @non_admin_users.each do |user|
215 password = random_password
214 password = random_password
216 user.password = password
215 user.password = password
217 user.password_confirmation = password
216 user.password_confirmation = password
218 user.save
217 user.save
219 end
218 end
220 @changed = true
219 @changed = true
221 end
220 end
222 end
221 end
223
222
224 # contest management
223 # contest management
225
224
226 def contests
225 def contests
227 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
226 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
228 @contests = Contest.enabled
227 @contests = Contest.enabled
229 end
228 end
230
229
231 def assign_from_list
230 def assign_from_list
232 contest_id = params[:users_contest_id]
231 contest_id = params[:users_contest_id]
233 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
232 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
234 contest = Contest.find(params[:new_contest][:id])
233 contest = Contest.find(params[:new_contest][:id])
235 if !contest
234 if !contest
236 flash[:notice] = 'Error: no contest'
235 flash[:notice] = 'Error: no contest'
237 redirect_to :action => 'contests', :id =>contest_id
236 redirect_to :action => 'contests', :id =>contest_id
238 end
237 end
239
238
240 note = []
239 note = []
241 users.each do |u|
240 users.each do |u|
242 u.contests = [contest]
241 u.contests = [contest]
243 note << u.login
242 note << u.login
244 end
243 end
245 flash[:notice] = 'User(s) ' + note.join(', ') +
244 flash[:notice] = 'User(s) ' + note.join(', ') +
246 " were successfully reassigned to #{contest.title}."
245 " were successfully reassigned to #{contest.title}."
247 redirect_to :action => 'contests', :id =>contest.id
246 redirect_to :action => 'contests', :id =>contest.id
248 end
247 end
249
248
250 def add_to_contest
249 def add_to_contest
251 user = User.find(params[:id])
250 user = User.find(params[:id])
252 contest = Contest.find(params[:contest_id])
251 contest = Contest.find(params[:contest_id])
253 if user and contest
252 if user and contest
254 user.contests << contest
253 user.contests << contest
255 end
254 end
256 redirect_to :action => 'list'
255 redirect_to :action => 'list'
257 end
256 end
258
257
259 def remove_from_contest
258 def remove_from_contest
260 user = User.find(params[:id])
259 user = User.find(params[:id])
261 contest = Contest.find(params[:contest_id])
260 contest = Contest.find(params[:contest_id])
262 if user and contest
261 if user and contest
263 user.contests.delete(contest)
262 user.contests.delete(contest)
264 end
263 end
265 redirect_to :action => 'list'
264 redirect_to :action => 'list'
266 end
265 end
267
266
268 def contest_management
267 def contest_management
269 end
268 end
270
269
271 def manage_contest
270 def manage_contest
272 contest = Contest.find(params[:contest][:id])
271 contest = Contest.find(params[:contest][:id])
273 if !contest
272 if !contest
274 flash[:notice] = 'You did not choose the contest.'
273 flash[:notice] = 'You did not choose the contest.'
275 redirect_to :action => 'contest_management' and return
274 redirect_to :action => 'contest_management' and return
276 end
275 end
277
276
278 operation = params[:operation]
277 operation = params[:operation]
279
278
280 if not ['add','remove','assign'].include? operation
279 if not ['add','remove','assign'].include? operation
281 flash[:notice] = 'You did not choose the operation to perform.'
280 flash[:notice] = 'You did not choose the operation to perform.'
282 redirect_to :action => 'contest_management' and return
281 redirect_to :action => 'contest_management' and return
283 end
282 end
284
283
285 lines = params[:login_list]
284 lines = params[:login_list]
286 if !lines or lines.blank?
285 if !lines or lines.blank?
287 flash[:notice] = 'You entered an empty list.'
286 flash[:notice] = 'You entered an empty list.'
288 redirect_to :action => 'contest_management' and return
287 redirect_to :action => 'contest_management' and return
289 end
288 end
290
289
291 note = []
290 note = []
292 users = []
291 users = []
293 lines.split("\n").each do |line|
292 lines.split("\n").each do |line|
294 user = User.find_by_login(line.chomp)
293 user = User.find_by_login(line.chomp)
295 if user
294 if user
296 if operation=='add'
295 if operation=='add'
297 if ! user.contests.include? contest
296 if ! user.contests.include? contest
298 user.contests << contest
297 user.contests << contest
299 end
298 end
300 elsif operation=='remove'
299 elsif operation=='remove'
301 user.contests.delete(contest)
300 user.contests.delete(contest)
302 else
301 else
303 user.contests = [contest]
302 user.contests = [contest]
304 end
303 end
305
304
306 if params[:reset_timer]
305 if params[:reset_timer]
307 user.contest_stat.forced_logout = true
306 user.contest_stat.forced_logout = true
308 user.contest_stat.reset_timer_and_save
307 user.contest_stat.reset_timer_and_save
309 end
308 end
310
309
311 if params[:notification_emails]
310 if params[:notification_emails]
312 send_contest_update_notification_email(user, contest)
311 send_contest_update_notification_email(user, contest)
313 end
312 end
314
313
315 note << user.login
314 note << user.login
316 users << user
315 users << user
317 end
316 end
318 end
317 end
319
318
320 if params[:reset_timer]
319 if params[:reset_timer]
321 logout_users(users)
320 logout_users(users)
322 end
321 end
323
322
324 flash[:notice] = 'User(s) ' + note.join(', ') +
323 flash[:notice] = 'User(s) ' + note.join(', ') +
325 ' were successfully modified. '
324 ' were successfully modified. '
326 redirect_to :action => 'contest_management'
325 redirect_to :action => 'contest_management'
327 end
326 end
328
327
329 # admin management
328 # admin management
330
329
331 def admin
330 def admin
332 @admins = User.find(:all).find_all {|user| user.admin? }
331 @admins = User.find(:all).find_all {|user| user.admin? }
333 end
332 end
334
333
335 def grant_admin
334 def grant_admin
336 login = params[:login]
335 login = params[:login]
337 user = User.find_by_login(login)
336 user = User.find_by_login(login)
338 if user!=nil
337 if user!=nil
339 admin_role = Role.find_by_name('admin')
338 admin_role = Role.find_by_name('admin')
340 user.roles << admin_role
339 user.roles << admin_role
341 else
340 else
342 flash[:notice] = 'Unknown user'
341 flash[:notice] = 'Unknown user'
343 end
342 end
344 flash[:notice] = 'User added as admins'
343 flash[:notice] = 'User added as admins'
345 redirect_to :action => 'admin'
344 redirect_to :action => 'admin'
346 end
345 end
347
346
348 def revoke_admin
347 def revoke_admin
349 user = User.find(params[:id])
348 user = User.find(params[:id])
350 if user==nil
349 if user==nil
351 flash[:notice] = 'Unknown user'
350 flash[:notice] = 'Unknown user'
352 redirect_to :action => 'admin' and return
351 redirect_to :action => 'admin' and return
353 elsif user.login == 'root'
352 elsif user.login == 'root'
354 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
353 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
355 redirect_to :action => 'admin' and return
354 redirect_to :action => 'admin' and return
356 end
355 end
357
356
358 admin_role = Role.find_by_name('admin')
357 admin_role = Role.find_by_name('admin')
359 user.roles.delete(admin_role)
358 user.roles.delete(admin_role)
360 flash[:notice] = 'User permission revoked'
359 flash[:notice] = 'User permission revoked'
361 redirect_to :action => 'admin'
360 redirect_to :action => 'admin'
362 end
361 end
363
362
364 # mass mailing
363 # mass mailing
365
364
366 def mass_mailing
365 def mass_mailing
367 end
366 end
368
367
369 def bulk_mail
368 def bulk_mail
370 lines = params[:login_list]
369 lines = params[:login_list]
371 if !lines or lines.blank?
370 if !lines or lines.blank?
372 flash[:notice] = 'You entered an empty list.'
371 flash[:notice] = 'You entered an empty list.'
373 redirect_to :action => 'mass_mailing' and return
372 redirect_to :action => 'mass_mailing' and return
374 end
373 end
375
374
376 mail_subject = params[:subject]
375 mail_subject = params[:subject]
377 if !mail_subject or mail_subject.blank?
376 if !mail_subject or mail_subject.blank?
378 flash[:notice] = 'You entered an empty mail subject.'
377 flash[:notice] = 'You entered an empty mail subject.'
379 redirect_to :action => 'mass_mailing' and return
378 redirect_to :action => 'mass_mailing' and return
380 end
379 end
381
380
382 mail_body = params[:email_body]
381 mail_body = params[:email_body]
383 if !mail_body or mail_body.blank?
382 if !mail_body or mail_body.blank?
384 flash[:notice] = 'You entered an empty mail body.'
383 flash[:notice] = 'You entered an empty mail body.'
385 redirect_to :action => 'mass_mailing' and return
384 redirect_to :action => 'mass_mailing' and return
386 end
385 end
387
386
388 note = []
387 note = []
389 users = []
388 users = []
390 lines.split("\n").each do |line|
389 lines.split("\n").each do |line|
391 user = User.find_by_login(line.chomp)
390 user = User.find_by_login(line.chomp)
392 if user
391 if user
393 send_mail(user.email, mail_subject, mail_body)
392 send_mail(user.email, mail_subject, mail_body)
394 note << user.login
393 note << user.login
395 end
394 end
396 end
395 end
397
396
398 flash[:notice] = 'User(s) ' + note.join(', ') +
397 flash[:notice] = 'User(s) ' + note.join(', ') +
399 ' were successfully modified. '
398 ' were successfully modified. '
400 redirect_to :action => 'mass_mailing'
399 redirect_to :action => 'mass_mailing'
401 end
400 end
402
401
403 protected
402 protected
404
403
405 def random_password(length=5)
404 def random_password(length=5)
406 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
405 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
407 newpass = ""
406 newpass = ""
408 length.times { newpass << chars[rand(chars.size-1)] }
407 length.times { newpass << chars[rand(chars.size-1)] }
409 return newpass
408 return newpass
410 end
409 end
411
410
412 def import_from_file(f)
411 def import_from_file(f)
413 data_hash = YAML.load(f)
412 data_hash = YAML.load(f)
414 @import_log = ""
413 @import_log = ""
415
414
416 country_data = data_hash[:countries]
415 country_data = data_hash[:countries]
417 site_data = data_hash[:sites]
416 site_data = data_hash[:sites]
418 user_data = data_hash[:users]
417 user_data = data_hash[:users]
419
418
420 # import country
419 # import country
421 countries = {}
420 countries = {}
422 country_data.each_pair do |id,country|
421 country_data.each_pair do |id,country|
423 c = Country.find_by_name(country[:name])
422 c = Country.find_by_name(country[:name])
424 if c!=nil
423 if c!=nil
425 countries[id] = c
424 countries[id] = c
426 @import_log << "Found #{country[:name]}\n"
425 @import_log << "Found #{country[:name]}\n"
427 else
426 else
428 countries[id] = Country.new(:name => country[:name])
427 countries[id] = Country.new(:name => country[:name])
429 countries[id].save
428 countries[id].save
430 @import_log << "Created #{country[:name]}\n"
429 @import_log << "Created #{country[:name]}\n"
431 end
430 end
432 end
431 end
433
432
434 # import sites
433 # import sites
435 sites = {}
434 sites = {}
436 site_data.each_pair do |id,site|
435 site_data.each_pair do |id,site|
437 s = Site.find_by_name(site[:name])
436 s = Site.find_by_name(site[:name])
438 if s!=nil
437 if s!=nil
439 @import_log << "Found #{site[:name]}\n"
438 @import_log << "Found #{site[:name]}\n"
440 else
439 else
441 s = Site.new(:name => site[:name])
440 s = Site.new(:name => site[:name])
442 @import_log << "Created #{site[:name]}\n"
441 @import_log << "Created #{site[:name]}\n"
443 end
442 end
444 s.password = site[:password]
443 s.password = site[:password]
445 s.country = countries[site[:country_id]]
444 s.country = countries[site[:country_id]]
446 s.save
445 s.save
447 sites[id] = s
446 sites[id] = s
448 end
447 end
449
448
450 # import users
449 # import users
451 user_data.each_pair do |id,user|
450 user_data.each_pair do |id,user|
452 u = User.find_by_login(user[:login])
451 u = User.find_by_login(user[:login])
453 if u!=nil
452 if u!=nil
454 @import_log << "Found #{user[:login]}\n"
453 @import_log << "Found #{user[:login]}\n"
455 else
454 else
456 u = User.new(:login => user[:login])
455 u = User.new(:login => user[:login])
457 @import_log << "Created #{user[:login]}\n"
456 @import_log << "Created #{user[:login]}\n"
458 end
457 end
459 u.full_name = user[:name]
458 u.full_name = user[:name]
460 u.password = user[:password]
459 u.password = user[:password]
461 u.country = countries[user[:country_id]]
460 u.country = countries[user[:country_id]]
462 u.site = sites[user[:site_id]]
461 u.site = sites[user[:site_id]]
463 u.activated = true
462 u.activated = true
464 u.email = "empty-#{u.login}@none.com"
463 u.email = "empty-#{u.login}@none.com"
465 if not u.save
464 if not u.save
466 @import_log << "Errors\n"
465 @import_log << "Errors\n"
467 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
466 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
468 end
467 end
469 end
468 end
470
469
471 end
470 end
472
471
473 def logout_users(users)
472 def logout_users(users)
474 users.each do |user|
473 users.each do |user|
475 contest_stat = user.contest_stat(true)
474 contest_stat = user.contest_stat(true)
476 if contest_stat and !contest_stat.forced_logout
475 if contest_stat and !contest_stat.forced_logout
477 contest_stat.forced_logout = true
476 contest_stat.forced_logout = true
478 contest_stat.save
477 contest_stat.save
479 end
478 end
480 end
479 end
481 end
480 end
482
481
483 def send_contest_update_notification_email(user, contest)
482 def send_contest_update_notification_email(user, contest)
484 contest_title_name = GraderConfiguration['contest.name']
483 contest_title_name = GraderConfiguration['contest.name']
485 contest_name = contest.name
484 contest_name = contest.name
486 mail_subject = t('contest.notification.email_subject', {
485 mail_subject = t('contest.notification.email_subject', {
487 :contest_title_name => contest_title_name,
486 :contest_title_name => contest_title_name,
488 :contest_name => contest_name })
487 :contest_name => contest_name })
489 mail_body = t('contest.notification.email_body', {
488 mail_body = t('contest.notification.email_body', {
490 :full_name => user.full_name,
489 :full_name => user.full_name,
491 :contest_title_name => contest_title_name,
490 :contest_title_name => contest_title_name,
492 :contest_name => contest.name,
491 :contest_name => contest.name,
493 })
492 })
494
493
495 logger.info mail_body
494 logger.info mail_body
496 send_mail(user.email, mail_subject, mail_body)
495 send_mail(user.email, mail_subject, mail_body)
497 end
496 end
498
497
499 def find_contest_and_user_from_contest_id(id)
498 def find_contest_and_user_from_contest_id(id)
500 if id!='none'
499 if id!='none'
501 @contest = Contest.find(id)
500 @contest = Contest.find(id)
502 else
501 else
503 @contest = nil
502 @contest = nil
504 end
503 end
505 if @contest
504 if @contest
506 @users = @contest.users
505 @users = @contest.users
507 else
506 else
508 @users = User.find_users_with_no_contest
507 @users = User.find_users_with_no_contest
509 end
508 end
510 return [@contest, @users]
509 return [@contest, @users]
511 end
510 end
512
511
513 def gen_csv_from_scorearray(scorearray,problem)
512 def gen_csv_from_scorearray(scorearray,problem)
514 CSV.generate do |csv|
513 CSV.generate do |csv|
515 #add header
514 #add header
516 header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
515 header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
517 problem.each { |p| header << p.name }
516 problem.each { |p| header << p.name }
518 header += ['Total','Passed']
517 header += ['Total','Passed']
519 csv << header
518 csv << header
520 #add data
519 #add data
521 scorearray.each do |sc|
520 scorearray.each do |sc|
522 total = num_passed = 0
521 total = num_passed = 0
523 row = Array.new
522 row = Array.new
524 sc.each_index do |i|
523 sc.each_index do |i|
525 if i == 0
524 if i == 0
526 row << sc[i].login
525 row << sc[i].login
527 row << sc[i].full_name
526 row << sc[i].full_name
528 row << sc[i].activated
527 row << sc[i].activated
529 row << (sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no')
528 row << (sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no')
530 row << sc[i].contests.collect {|c| c.name}.join(', ')
529 row << sc[i].contests.collect {|c| c.name}.join(', ')
531 else
530 else
532 row << sc[i][0]
531 row << sc[i][0]
533 total += sc[i][0]
532 total += sc[i][0]
534 num_passed += 1 if sc[i][1]
533 num_passed += 1 if sc[i][1]
535 end
534 end
536 end
535 end
537 row << total
536 row << total
538 row << num_passed
537 row << num_passed
539 csv << row
538 csv << row
540 end
539 end
541 end
540 end
542 end
541 end
543 end
542 end
@@ -1,195 +1,214
1 require 'net/smtp'
1 require 'net/smtp'
2
2
3 class UsersController < ApplicationController
3 class UsersController < ApplicationController
4
4
5 include MailHelperMethods
5 include MailHelperMethods
6
6
7 before_filter :authenticate, :except => [:new,
7 before_filter :authenticate, :except => [:new,
8 :register,
8 :register,
9 :confirm,
9 :confirm,
10 :forget,
10 :forget,
11 :retrieve_password]
11 :retrieve_password]
12
12
13 before_filter :verify_online_registration, :only => [:new,
13 before_filter :verify_online_registration, :only => [:new,
14 :register,
14 :register,
15 :forget,
15 :forget,
16 :retrieve_password]
16 :retrieve_password]
17 before_filter :authenticate, :profile_authorization, only: [:profile]
17 before_filter :authenticate, :profile_authorization, only: [:profile]
18
18
19 verify :method => :post, :only => [:chg_passwd],
19 verify :method => :post, :only => [:chg_passwd],
20 :redirect_to => { :action => :index }
20 :redirect_to => { :action => :index }
21
21
22 #in_place_edit_for :user, :alias_for_editing
22 #in_place_edit_for :user, :alias_for_editing
23 #in_place_edit_for :user, :email_for_editing
23 #in_place_edit_for :user, :email_for_editing
24
24
25 def index
25 def index
26 if !GraderConfiguration['system.user_setting_enabled']
26 if !GraderConfiguration['system.user_setting_enabled']
27 redirect_to :controller => 'main', :action => 'list'
27 redirect_to :controller => 'main', :action => 'list'
28 else
28 else
29 @user = User.find(session[:user_id])
29 @user = User.find(session[:user_id])
30 end
30 end
31 end
31 end
32
32
33 def chg_passwd
33 def chg_passwd
34 user = User.find(session[:user_id])
34 user = User.find(session[:user_id])
35 user.password = params[:passwd]
35 user.password = params[:passwd]
36 user.password_confirmation = params[:passwd_verify]
36 user.password_confirmation = params[:passwd_verify]
37 if user.save
37 if user.save
38 flash[:notice] = 'password changed'
38 flash[:notice] = 'password changed'
39 else
39 else
40 flash[:notice] = 'Error: password changing failed'
40 flash[:notice] = 'Error: password changing failed'
41 end
41 end
42 redirect_to :action => 'index'
42 redirect_to :action => 'index'
43 end
43 end
44
44
45 def new
45 def new
46 @user = User.new
46 @user = User.new
47 render :action => 'new', :layout => 'empty'
47 render :action => 'new', :layout => 'empty'
48 end
48 end
49
49
50 def register
50 def register
51 if(params[:cancel])
51 if(params[:cancel])
52 redirect_to :controller => 'main', :action => 'login'
52 redirect_to :controller => 'main', :action => 'login'
53 return
53 return
54 end
54 end
55 @user = User.new(params[:user])
55 @user = User.new(params[:user])
56 @user.password_confirmation = @user.password = User.random_password
56 @user.password_confirmation = @user.password = User.random_password
57 @user.activated = false
57 @user.activated = false
58 if (@user.valid?) and (@user.save)
58 if (@user.valid?) and (@user.save)
59 if send_confirmation_email(@user)
59 if send_confirmation_email(@user)
60 render :action => 'new_splash', :layout => 'empty'
60 render :action => 'new_splash', :layout => 'empty'
61 else
61 else
62 @admin_email = GraderConfiguration['system.admin_email']
62 @admin_email = GraderConfiguration['system.admin_email']
63 render :action => 'email_error', :layout => 'empty'
63 render :action => 'email_error', :layout => 'empty'
64 end
64 end
65 else
65 else
66 @user.errors.add(:base,"Email cannot be blank") if @user.email==''
66 @user.errors.add(:base,"Email cannot be blank") if @user.email==''
67 render :action => 'new', :layout => 'empty'
67 render :action => 'new', :layout => 'empty'
68 end
68 end
69 end
69 end
70
70
71 def confirm
71 def confirm
72 login = params[:login]
72 login = params[:login]
73 key = params[:activation]
73 key = params[:activation]
74 @user = User.find_by_login(login)
74 @user = User.find_by_login(login)
75 if (@user) and (@user.verify_activation_key(key))
75 if (@user) and (@user.verify_activation_key(key))
76 if @user.valid? # check uniquenss of email
76 if @user.valid? # check uniquenss of email
77 @user.activated = true
77 @user.activated = true
78 @user.save
78 @user.save
79 @result = :successful
79 @result = :successful
80 else
80 else
81 @result = :email_used
81 @result = :email_used
82 end
82 end
83 else
83 else
84 @result = :failed
84 @result = :failed
85 end
85 end
86 render :action => 'confirm', :layout => 'empty'
86 render :action => 'confirm', :layout => 'empty'
87 end
87 end
88
88
89 def forget
89 def forget
90 render :action => 'forget', :layout => 'empty'
90 render :action => 'forget', :layout => 'empty'
91 end
91 end
92
92
93 def retrieve_password
93 def retrieve_password
94 email = params[:email]
94 email = params[:email]
95 user = User.find_by_email(email)
95 user = User.find_by_email(email)
96 if user
96 if user
97 last_updated_time = user.updated_at || user.created_at || (Time.now.gmtime - 1.hour)
97 last_updated_time = user.updated_at || user.created_at || (Time.now.gmtime - 1.hour)
98 if last_updated_time > Time.now.gmtime - 5.minutes
98 if last_updated_time > Time.now.gmtime - 5.minutes
99 flash[:notice] = 'The account has recently created or new password has recently been requested. Please wait for 5 minutes'
99 flash[:notice] = 'The account has recently created or new password has recently been requested. Please wait for 5 minutes'
100 else
100 else
101 user.password = user.password_confirmation = User.random_password
101 user.password = user.password_confirmation = User.random_password
102 user.save
102 user.save
103 send_new_password_email(user)
103 send_new_password_email(user)
104 flash[:notice] = 'New password has been mailed to you.'
104 flash[:notice] = 'New password has been mailed to you.'
105 end
105 end
106 else
106 else
107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
108 end
108 end
109 redirect_to :action => 'forget'
109 redirect_to :action => 'forget'
110 end
110 end
111
111
112 def profile
112 def profile
113 @user = User.find(params[:id])
113 @user = User.find(params[:id])
114 @submission = Submission.includes(:problem).where(user_id: params[:id])
114 @submission = Submission.includes(:problem).where(user_id: params[:id])
115
115
116 range = 120
116 range = 120
117 @histogram = { data: Array.new(range,0), summary: {} }
117 @histogram = { data: Array.new(range,0), summary: {} }
118 @summary = {count: 0, solve: 0, attempt: 0}
118 @summary = {count: 0, solve: 0, attempt: 0}
119 problem = Hash.new(0)
119 problem = Hash.new(0)
120
120
121 @submission.find_each do |sub|
121 @submission.find_each do |sub|
122 #histogram
122 #histogram
123 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
123 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
124 @histogram[:data][d.to_i] += 1 if d < range
124 @histogram[:data][d.to_i] += 1 if d < range
125
125
126 @summary[:count] += 1
126 @summary[:count] += 1
127 next unless sub.problem
127 next unless sub.problem
128 problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max
128 problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max
129 end
129 end
130
130
131 @histogram[:summary][:max] = [@histogram[:data].max,1].max
131 @histogram[:summary][:max] = [@histogram[:data].max,1].max
132 @summary[:attempt] = problem.count
132 @summary[:attempt] = problem.count
133 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
133 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
134 end
134 end
135
135
136 + def toggle_activate
137 + @user = User.find(params[:id])
138 + @user.update_attributes( activated: !@user.activated? )
139 + respond_to do |format|
140 + format.js { render partial: 'toggle_button',
141 + locals: {button_id: "#toggle_activate_user_#{@user.id}",button_on: @user.activated? } }
142 + end
143 + end
144 +
145 + def toggle_enable
146 + @user = User.find(params[:id])
147 + @user.update_attributes( enabled: !@user.enabled? )
148 + respond_to do |format|
149 + format.js { render partial: 'toggle_button',
150 + locals: {button_id: "#toggle_enable_user_#{@user.id}",button_on: @user.enabled? } }
151 + end
152 + end
153 +
136 protected
154 protected
137
155
138 def verify_online_registration
156 def verify_online_registration
139 if !GraderConfiguration['system.online_registration']
157 if !GraderConfiguration['system.online_registration']
140 redirect_to :controller => 'main', :action => 'login'
158 redirect_to :controller => 'main', :action => 'login'
141 end
159 end
142 end
160 end
143
161
144 def send_confirmation_email(user)
162 def send_confirmation_email(user)
145 contest_name = GraderConfiguration['contest.name']
163 contest_name = GraderConfiguration['contest.name']
146 activation_url = url_for(:action => 'confirm',
164 activation_url = url_for(:action => 'confirm',
147 :login => user.login,
165 :login => user.login,
148 :activation => user.activation_key)
166 :activation => user.activation_key)
149 home_url = url_for(:controller => 'main', :action => 'index')
167 home_url = url_for(:controller => 'main', :action => 'index')
150 mail_subject = "[#{contest_name}] Confirmation"
168 mail_subject = "[#{contest_name}] Confirmation"
151 mail_body = t('registration.email_body', {
169 mail_body = t('registration.email_body', {
152 :full_name => user.full_name,
170 :full_name => user.full_name,
153 :contest_name => contest_name,
171 :contest_name => contest_name,
154 :login => user.login,
172 :login => user.login,
155 :password => user.password,
173 :password => user.password,
156 :activation_url => activation_url,
174 :activation_url => activation_url,
157 :admin_email => GraderConfiguration['system.admin_email']
175 :admin_email => GraderConfiguration['system.admin_email']
158 })
176 })
159
177
160 logger.info mail_body
178 logger.info mail_body
161
179
162 send_mail(user.email, mail_subject, mail_body)
180 send_mail(user.email, mail_subject, mail_body)
163 end
181 end
164
182
165 def send_new_password_email(user)
183 def send_new_password_email(user)
166 contest_name = GraderConfiguration['contest.name']
184 contest_name = GraderConfiguration['contest.name']
167 mail_subject = "[#{contest_name}] Password recovery"
185 mail_subject = "[#{contest_name}] Password recovery"
168 mail_body = t('registration.password_retrieval.email_body', {
186 mail_body = t('registration.password_retrieval.email_body', {
169 :full_name => user.full_name,
187 :full_name => user.full_name,
170 :contest_name => contest_name,
188 :contest_name => contest_name,
171 :login => user.login,
189 :login => user.login,
172 :password => user.password,
190 :password => user.password,
173 :admin_email => GraderConfiguration['system.admin_email']
191 :admin_email => GraderConfiguration['system.admin_email']
174 })
192 })
175
193
176 logger.info mail_body
194 logger.info mail_body
177
195
178 send_mail(user.email, mail_subject, mail_body)
196 send_mail(user.email, mail_subject, mail_body)
179 end
197 end
180
198
181 # allow viewing of regular user profile only when options allow so
199 # allow viewing of regular user profile only when options allow so
182 # only admins can view admins profile
200 # only admins can view admins profile
183 def profile_authorization
201 def profile_authorization
184 #if view admins' profile, allow only admin
202 #if view admins' profile, allow only admin
185 return false unless(params[:id])
203 return false unless(params[:id])
186 user = User.find(params[:id])
204 user = User.find(params[:id])
187 return false unless user
205 return false unless user
188 return admin_authorization if user.admin?
206 return admin_authorization if user.admin?
189 return true if GraderConfiguration["right.user_view_submission"]
207 return true if GraderConfiguration["right.user_view_submission"]
190
208
191 #finally, we allow only admin
209 #finally, we allow only admin
192 admin_authorization
210 admin_authorization
193 end
211 end
194
212
213 +
195 end
214 end
@@ -1,182 +1,177
1 # Methods added to this helper will be available to all templates in the application.
1 # Methods added to this helper will be available to all templates in the application.
2 module ApplicationHelper
2 module ApplicationHelper
3
3
4 def navbar_user_header
4 def navbar_user_header
5 left_menu = ''
5 left_menu = ''
6 right_menu = ''
6 right_menu = ''
7 user = User.find(session[:user_id])
7 user = User.find(session[:user_id])
8
8
9 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
9 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
10 left_menu << add_menu("#{I18n.t 'menu.tasks'}", 'tasks', 'list')
10 left_menu << add_menu("#{I18n.t 'menu.tasks'}", 'tasks', 'list')
11 left_menu << add_menu("#{I18n.t 'menu.submissions'}", 'main', 'submission')
11 left_menu << add_menu("#{I18n.t 'menu.submissions'}", 'main', 'submission')
12 left_menu << add_menu("#{I18n.t 'menu.test'}", 'test', 'index')
12 left_menu << add_menu("#{I18n.t 'menu.test'}", 'test', 'index')
13 end
13 end
14
14
15 if GraderConfiguration['right.user_hall_of_fame']
15 if GraderConfiguration['right.user_hall_of_fame']
16 left_menu << add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
16 left_menu << add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
17 end
17 end
18
18
19 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
19 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
20 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
20 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
21 if GraderConfiguration['system.user_setting_enabled']
21 if GraderConfiguration['system.user_setting_enabled']
22 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
22 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
23 end
23 end
24 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
24 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
25
25
26
26
27 result = content_tag(:ul,left_menu.html_safe,class: 'nav navbar-nav') + content_tag(:ul,right_menu.html_safe,class: 'nav navbar-nav navbar-right')
27 result = content_tag(:ul,left_menu.html_safe,class: 'nav navbar-nav') + content_tag(:ul,right_menu.html_safe,class: 'nav navbar-nav navbar-right')
28 end
28 end
29
29
30 def add_menu(title, controller, action,html_option = {})
30 def add_menu(title, controller, action,html_option = {})
31 link_option = {controller: controller, action: action}
31 link_option = {controller: controller, action: action}
32 html_option[:class] = (html_option[:class] || '') + " active" if current_page?(link_option)
32 html_option[:class] = (html_option[:class] || '') + " active" if current_page?(link_option)
33 content_tag(:li, link_to(title,link_option),html_option)
33 content_tag(:li, link_to(title,link_option),html_option)
34 end
34 end
35
35
36 def user_header
36 def user_header
37 menu_items = ''
37 menu_items = ''
38 user = User.find(session[:user_id])
38 user = User.find(session[:user_id])
39
39
40 if (user!=nil) and (session[:admin])
40 if (user!=nil) and (session[:admin])
41 # admin menu
41 # admin menu
42 menu_items << "<b>Administrative task:</b> "
42 menu_items << "<b>Administrative task:</b> "
43 append_to menu_items, '[Announcements]', 'announcements', 'index'
43 append_to menu_items, '[Announcements]', 'announcements', 'index'
44 append_to menu_items, '[Msg console]', 'messages', 'console'
44 append_to menu_items, '[Msg console]', 'messages', 'console'
45 append_to menu_items, '[Problems]', 'problems', 'index'
45 append_to menu_items, '[Problems]', 'problems', 'index'
46 append_to menu_items, '[Users]', 'user_admin', 'index'
46 append_to menu_items, '[Users]', 'user_admin', 'index'
47 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
47 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
48 append_to menu_items, '[Report]', 'report', 'multiple_login'
48 append_to menu_items, '[Report]', 'report', 'multiple_login'
49 append_to menu_items, '[Graders]', 'graders', 'list'
49 append_to menu_items, '[Graders]', 'graders', 'list'
50 append_to menu_items, '[Contests]', 'contest_management', 'index'
50 append_to menu_items, '[Contests]', 'contest_management', 'index'
51 append_to menu_items, '[Sites]', 'sites', 'index'
51 append_to menu_items, '[Sites]', 'sites', 'index'
52 append_to menu_items, '[System config]', 'configurations', 'index'
52 append_to menu_items, '[System config]', 'configurations', 'index'
53 menu_items << "<br/>"
53 menu_items << "<br/>"
54 end
54 end
55
55
56 # main page
56 # main page
57 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
57 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
58 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
58 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
59
59
60 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
60 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
61 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
61 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
62 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
62 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
63 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
63 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
64 end
64 end
65
65
66 if GraderConfiguration['right.user_hall_of_fame']
66 if GraderConfiguration['right.user_hall_of_fame']
67 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
67 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
68 end
68 end
69 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
69 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
70
70
71 if GraderConfiguration['system.user_setting_enabled']
71 if GraderConfiguration['system.user_setting_enabled']
72 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
72 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
73 end
73 end
74 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
74 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
75
75
76 menu_items.html_safe
76 menu_items.html_safe
77 end
77 end
78
78
79 def append_to(option,label, controller, action)
79 def append_to(option,label, controller, action)
80 option << ' ' if option!=''
80 option << ' ' if option!=''
81 option << link_to_unless_current(label,
81 option << link_to_unless_current(label,
82 :controller => controller,
82 :controller => controller,
83 :action => action)
83 :action => action)
84 end
84 end
85
85
86 def format_short_time(time)
86 def format_short_time(time)
87 now = Time.now.gmtime
87 now = Time.now.gmtime
88 st = ''
88 st = ''
89 if (time.yday != now.yday) or
89 if (time.yday != now.yday) or
90 (time.year != now.year)
90 (time.year != now.year)
91 st = time.strftime("%x ")
91 st = time.strftime("%x ")
92 end
92 end
93 st + time.strftime("%X")
93 st + time.strftime("%X")
94 end
94 end
95
95
96 def format_short_duration(duration)
96 def format_short_duration(duration)
97 return '' if duration==nil
97 return '' if duration==nil
98 d = duration.to_f
98 d = duration.to_f
99 return Time.at(d).gmtime.strftime("%X")
99 return Time.at(d).gmtime.strftime("%X")
100 end
100 end
101
101
102 def read_textfile(fname,max_size=2048)
102 def read_textfile(fname,max_size=2048)
103 begin
103 begin
104 File.open(fname).read(max_size)
104 File.open(fname).read(max_size)
105 rescue
105 rescue
106 nil
106 nil
107 end
107 end
108 end
108 end
109
109
110 - def problem_select(problems, options = {})
110 + def toggle_button(on,toggle_url,id)
111 - prefix = options[:with_specific_in_header] ? [[(t 'main.specified_in_header'),'-1']] : []
111 + link_to (on ? "Yes" : "No"), toggle_url,
112 - selected = options[:selected] || (options[:with_specific_in_header] ? -1 : nil)
112 + {class: "btn btn-block btn-xs btn-#{on ? 'success' : 'default'} ajax-toggle",
113 - puts "selected = #{selected} hehe"
113 + id: id,
114 - html_options = {class: 'select2 form-control'}
114 + data: {remote: true, method: 'get'}}
115 - html_options[:id] = options[:id]if options[:id]
116 - select 'submission',
117 - 'problem_id', prefix + problems.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},
118 - (selected ? { selected: "#{selected}"} : {} ),
119 - html_options
120 end
115 end
121
116
122 def user_title_bar(user)
117 def user_title_bar(user)
123 header = ''
118 header = ''
124 time_left = ''
119 time_left = ''
125
120
126 #
121 #
127 # if the contest is over
122 # if the contest is over
128 if GraderConfiguration.time_limit_mode?
123 if GraderConfiguration.time_limit_mode?
129 if user.contest_finished?
124 if user.contest_finished?
130 header = <<CONTEST_OVER
125 header = <<CONTEST_OVER
131 <tr><td colspan="2" align="center">
126 <tr><td colspan="2" align="center">
132 <span class="contest-over-msg">THE CONTEST IS OVER</span>
127 <span class="contest-over-msg">THE CONTEST IS OVER</span>
133 </td></tr>
128 </td></tr>
134 CONTEST_OVER
129 CONTEST_OVER
135 end
130 end
136 if !user.contest_started?
131 if !user.contest_started?
137 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
132 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
138 else
133 else
139 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
134 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
140 " #{format_short_duration(user.contest_time_left)}"
135 " #{format_short_duration(user.contest_time_left)}"
141 end
136 end
142 end
137 end
143
138
144 #
139 #
145 # if the contest is in the anaysis mode
140 # if the contest is in the anaysis mode
146 if GraderConfiguration.analysis_mode?
141 if GraderConfiguration.analysis_mode?
147 header = <<ANALYSISMODE
142 header = <<ANALYSISMODE
148 <tr><td colspan="2" align="center">
143 <tr><td colspan="2" align="center">
149 <span class="contest-over-msg">ANALYSIS MODE</span>
144 <span class="contest-over-msg">ANALYSIS MODE</span>
150 </td></tr>
145 </td></tr>
151 ANALYSISMODE
146 ANALYSISMODE
152 end
147 end
153
148
154 contest_name = GraderConfiguration['contest.name']
149 contest_name = GraderConfiguration['contest.name']
155
150
156 #
151 #
157 # build real title bar
152 # build real title bar
158 result = <<TITLEBAR
153 result = <<TITLEBAR
159 <div class="title">
154 <div class="title">
160 <table>
155 <table>
161 #{header}
156 #{header}
162 <tr>
157 <tr>
163 <td class="left-col">
158 <td class="left-col">
164 #{user.full_name}<br/>
159 #{user.full_name}<br/>
165 #{t 'title_bar.current_time'} #{format_short_time(Time.zone.now)}
160 #{t 'title_bar.current_time'} #{format_short_time(Time.zone.now)}
166 #{time_left}
161 #{time_left}
167 <br/>
162 <br/>
168 </td>
163 </td>
169 <td class="right-col">#{contest_name}</td>
164 <td class="right-col">#{contest_name}</td>
170 </tr>
165 </tr>
171 </table>
166 </table>
172 </div>
167 </div>
173 TITLEBAR
168 TITLEBAR
174 result.html_safe
169 result.html_safe
175 end
170 end
176
171
177 def markdown(text)
172 def markdown(text)
178 markdown = RDiscount.new(text)
173 markdown = RDiscount.new(text)
179 markdown.to_html.html_safe
174 markdown.to_html.html_safe
180 end
175 end
181
176
182 end
177 end
@@ -1,37 +1,36
1 %h1 Listing announcements
1 %h1 Listing announcements
2
2
3 = link_to '+ Add announcement', new_announcement_path, class: 'btn btn-success'
3 = link_to '+ Add announcement', new_announcement_path, class: 'btn btn-success'
4 %br
4 %br
5 %br
5 %br
6
6
7 %table.table.table-striped
7 %table.table.table-striped
8 %tr
8 %tr
9 %th Updated
9 %th Updated
10 %th Announcement
10 %th Announcement
11 %th Author
11 %th Author
12 %th Published
12 %th Published
13 %th
13 %th
14 %th
14 %th
15 - for announcement in @announcements
15 - for announcement in @announcements
16 %tr
16 %tr
17 - @announcement = announcement
17 - @announcement = announcement
18 %td= time_ago_in_words announcement.updated_at
18 %td= time_ago_in_words announcement.updated_at
19 %td
19 %td
20 - if !announcement.title.blank?
20 - if !announcement.title.blank?
21 %b Title:
21 %b Title:
22 = h announcement.title
22 = h announcement.title
23 %br/
23 %br/
24 - if !announcement.notes.blank?
24 - if !announcement.notes.blank?
25 %b
25 %b
26 Notes: #{h announcement.notes}
26 Notes: #{h announcement.notes}
27 %br/
27 %br/
28 = h announcement.body
28 = h announcement.body
29 %td= h announcement.author
29 %td= h announcement.author
30 - // %td= check_box_tag :published, 1, announcement.published, { class: 'bootstrap-toggle', id: "published-#{announcement.id}", data: {remote: true, method: 'PUT', url: url_for(controller: :announcements, action: :toggle, id: announcement), size: 'small', toggle: 'toggle' } }
30 + %td= toggle_button(announcement.published?, toggle_announcement_url(@announcement), "announcement_toggle_#{@announcement.id}")
31 - // <td><haml_loud> in_place_editor_field :announcement, :published, {}, :rows => 1 </haml_loud></td>
31 + //%td= link_to (announcement.published? ? "Yes" : "No"), url_for(controller: :announcements, action: :toggle, id: announcement), { class: "btn btn-block btn-sm btn-#{(announcement.published? ? 'success' : 'default')} ajax-toggle", id: "published-#{announcement.id}", data: {remote: true, method: 'post' } }
32 - %td= link_to (announcement.published? ? "Yes" : "No"), url_for(controller: :announcements, action: :toggle, id: announcement), { class: "btn btn-block btn-sm btn-#{(announcement.published? ? 'success' : 'default')} ajax-toggle", id: "published-#{announcement.id}", data: {remote: true, method: 'post' } }
33 %td= link_to 'Edit', edit_announcement_path(announcement), class: 'btn btn-block btn-sm btn-info'
32 %td= link_to 'Edit', edit_announcement_path(announcement), class: 'btn btn-block btn-sm btn-info'
34 %td= link_to 'Destroy', announcement, :confirm => 'Are you sure?', :method => :delete, class: "btn btn-block btn-sm btn-danger"
33 %td= link_to 'Destroy', announcement, :confirm => 'Are you sure?', :method => :delete, class: "btn btn-block btn-sm btn-danger"
35 %br
34 %br
36
35
37 = link_to '+ Add announcement', new_announcement_path, class: 'btn btn-success'
36 = link_to '+ Add announcement', new_announcement_path, class: 'btn btn-success'
@@ -1,46 +1,47
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3 %h1 Listing problems
3 %h1 Listing problems
4 %p
4 %p
5 = link_to 'New problem', new_problem_path, class: 'btn btn-default btn-sm'
5 = link_to 'New problem', new_problem_path, class: 'btn btn-default btn-sm'
6 = link_to 'Manage problems', { action: 'manage'}, class: 'btn btn-default btn-sm'
6 = link_to 'Manage problems', { action: 'manage'}, class: 'btn btn-default btn-sm'
7 = link_to 'Import problems', {:action => 'import'}, class: 'btn btn-default btn-sm'
7 = link_to 'Import problems', {:action => 'import'}, class: 'btn btn-default btn-sm'
8 = link_to 'Turn off all problems', {:action => 'turn_all_off'}, class: 'btn btn-default btn-sm'
8 = link_to 'Turn off all problems', {:action => 'turn_all_off'}, class: 'btn btn-default btn-sm'
9 = link_to 'Turn on all problems', {:action => 'turn_all_on'}, class: 'btn btn-default btn-sm'
9 = link_to 'Turn on all problems', {:action => 'turn_all_on'}, class: 'btn btn-default btn-sm'
10 .submitbox
10 .submitbox
11 = form_tag :action => 'quick_create' do
11 = form_tag :action => 'quick_create' do
12 %b Quick New:
12 %b Quick New:
13 %label{:for => "problem_name"} Name
13 %label{:for => "problem_name"} Name
14 = text_field 'problem', 'name'
14 = text_field 'problem', 'name'
15 |
15 |
16 %label{:for => "problem_full_name"} Full name
16 %label{:for => "problem_full_name"} Full name
17 = text_field 'problem', 'full_name'
17 = text_field 'problem', 'full_name'
18 = submit_tag "Create"
18 = submit_tag "Create"
19 - %table.table.table-condensed.table-hover
19 + %table.table.table-condense.table-hover
20 %thead
20 %thead
21 %th Name
21 %th Name
22 %th Full name
22 %th Full name
23 %th Full score
23 %th Full score
24 %th Date added
24 %th Date added
25 %th Avail?
25 %th Avail?
26 %th Test?
26 %th Test?
27 - if GraderConfiguration.multicontests?
27 - if GraderConfiguration.multicontests?
28 %th Contests
28 %th Contests
29 - for problem in @problems
29 - for problem in @problems
30 %tr{:class => "#{(problem.available) ? "success" : "danger"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"}
30 %tr{:class => "#{(problem.available) ? "success" : "danger"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"}
31 - @problem=problem
31 - @problem=problem
32 %td= in_place_editor_field :problem, :name, {}, :rows=>1
32 %td= in_place_editor_field :problem, :name, {}, :rows=>1
33 %td= in_place_editor_field :problem, :full_name, {}, :rows=>1
33 %td= in_place_editor_field :problem, :full_name, {}, :rows=>1
34 %td= in_place_editor_field :problem, :full_score, {}, :rows=>1
34 %td= in_place_editor_field :problem, :full_score, {}, :rows=>1
35 %td= problem.date_added
35 %td= problem.date_added
36 - %td{}= link_to (@problem.available? ? "Yes" : "No"), url_for(controller: :problems, action: :toggle, id: @problem), { class: "btn btn-block btn-sm btn-#{(@problem.available? ? 'success' : 'default')} ajax-toggle", id: "prob-#{@problem.id}-avail", data: {remote: true, method: 'post' } }
36 + %td= toggle_button(@problem.available?, url_for(controller: :problems, action: :toggle, id: @problem), "problem-avail-#{@problem.id}")
37 + //%td{}= link_to (@problem.available? ? "Yes" : "No"), url_for(controller: :problems, action: :toggle, id: @problem), { class: "btn btn-block btn-sm btn-#{(@problem.available? ? 'success' : 'default')} ajax-toggle", id: "problem-avail-#{@problem.id}", data: {remote: true, method: 'post' } }
37 %td= problem.test_allowed
38 %td= problem.test_allowed
38 - if GraderConfiguration.multicontests?
39 - if GraderConfiguration.multicontests?
39 %td
40 %td
40 = problem.contests.collect { |c| c.name }.join(', ')
41 = problem.contests.collect { |c| c.name }.join(', ')
41 - %td= link_to 'Stat', {:action => 'stat', :id => problem.id}, class: 'btn btn-primary btn-sm'
42 + %td= link_to 'Stat', {:action => 'stat', :id => problem.id}, class: 'btn btn-info btn-xs btn-block'
42 - %td= link_to 'Show', {:action => 'show', :id => problem}, class: 'btn btn-primary btn-sm'
43 + %td= link_to 'Show', {:action => 'show', :id => problem}, class: 'btn btn-info btn-xs btn-block'
43 - %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-primary btn-sm'
44 + %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-info btn-xs btn-block'
44 - %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :post, class: 'btn btn-danger btn-sm'
45 + %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :post, class: 'btn btn-danger btn-xs btn-block'
45 %br/
46 %br/
46 = link_to '[New problem]', :action => 'new'
47 = link_to '[New problem]', :action => 'new'
@@ -1,12 +1,8
1 + = render partial: 'toggle_button',
2 + locals: {button_id: "#problem-avail-#{@problem.id}",button_on: @problem.available }
1 :plain
3 :plain
2 - b = $("#prob-#{@problem.id}-avail");
3 - b.removeClass('btn-default');
4 - b.removeClass('btn-success');
5 - b.removeClass('btn-warning');
6 - b.addClass("btn-#{@problem.available? ? 'success' : 'default'}");
7 - b.text("#{@problem.available? ? 'Yes' : 'No'}");
8 r = $("#prob-#{@problem.id}");
4 r = $("#prob-#{@problem.id}");
9 r.removeClass('success');
5 r.removeClass('success');
10 r.removeClass('danger');
6 r.removeClass('danger');
11 r.addClass("#{@problem.available? ? 'success' : 'danger'}");
7 r.addClass("#{@problem.available? ? 'success' : 'danger'}");
12
8
@@ -1,33 +1,54
1 CafeGrader::Application.routes.draw do
1 CafeGrader::Application.routes.draw do
2 root :to => 'main#login'
2 root :to => 'main#login'
3
3
4 - get "report/login"
5
4
6 resources :contests
5 resources :contests
7
6
8 - resources :announcements
9 - match 'announcements/toggle/:id' => 'announcements#toggle'
10 -
11 resources :sites
7 resources :sites
12
8
13 - resources :problem
9 + resources :announcements do
10 + member do
11 + get 'toggle'
12 + end
13 + end
14 +
15 +
16 + resources :problems do
17 + member do
18 + get 'toggle'
19 + end
20 + collection do
21 + get 'turn_all_off'
22 + get 'turn_all_on'
23 + get 'import'
24 + get 'manage'
25 + end
26 + end
14
27
15 resources :grader_configuration, controller: 'configurations'
28 resources :grader_configuration, controller: 'configurations'
16
29
30 + resources :users do
31 + member do
32 + get 'toggle_activate', 'toggle_enable'
33 + end
34 + end
35 +
36 +
17 match 'tasks/view/:file.:ext' => 'tasks#view'
37 match 'tasks/view/:file.:ext' => 'tasks#view'
18 match 'tasks/download/:id/:file.:ext' => 'tasks#download'
38 match 'tasks/download/:id/:file.:ext' => 'tasks#download'
19 match 'heartbeat/:id/edit' => 'heartbeat#edit'
39 match 'heartbeat/:id/edit' => 'heartbeat#edit'
20
40
21 #main
41 #main
22 get "main/list"
42 get "main/list"
23 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
43 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
24
44
25 #report
45 #report
26 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
46 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
47 + get "report/login"
27
48
28 # See how all your routes lay out with "rake routes"
49 # See how all your routes lay out with "rake routes"
29
50
30 # This is a legacy wild controller route that's not recommended for RESTful applications.
51 # This is a legacy wild controller route that's not recommended for RESTful applications.
31 # Note: This route will make all actions in every controller accessible via GET requests.
52 # Note: This route will make all actions in every controller accessible via GET requests.
32 match ':controller(/:action(/:id))(.:format)'
53 match ':controller(/:action(/:id))(.:format)'
33 end
54 end
deleted file
You need to be logged in to leave comments. Login now