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,212 +1,211
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
@@ -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