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
@@ -38,64 +38,65
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
@@ -2,102 +2,107
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
@@ -78,97 +78,97
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
@@ -1,68 +1,67
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
@@ -88,108 +88,127
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
@@ -62,106 +62,101
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/>
@@ -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