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

r801:33c0929c92ed - - 23 files changed: 180 inserted, 96 deleted

@@ -0,0 +1,8
1 + = render partial: 'toggle_button',
2 + locals: {button_id: "#group-enabled-#{@group.id}",button_on: @group.enabled }
3 + :plain
4 + r = $("#group-#{@group.id}");
5 + r.removeClass('success');
6 + r.removeClass('danger');
7 + r.addClass("#{@group.enabled? ? 'success' : 'danger'}");
8 +
@@ -0,0 +1,5
1 + class AddEnabledToGroup < ActiveRecord::Migration[5.2]
2 + def change
3 + add_column :groups, :enabled, :boolean, default: true
4 + end
5 + end
@@ -107,98 +107,99
107 def authenticate_by_ip_address
107 def authenticate_by_ip_address
108 #this assume that we have already authenticate normally
108 #this assume that we have already authenticate normally
109 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
109 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
110 user = User.find(session[:user_id])
110 user = User.find(session[:user_id])
111 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
111 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
112 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
112 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
113 redirect_to :controller => 'main', :action => 'login'
113 redirect_to :controller => 'main', :action => 'login'
114 return false
114 return false
115 end
115 end
116 unless user.last_ip
116 unless user.last_ip
117 user.last_ip = request.remote_ip
117 user.last_ip = request.remote_ip
118 user.save
118 user.save
119 end
119 end
120 end
120 end
121 return true
121 return true
122 end
122 end
123
123
124 def authorization
124 def authorization
125 return false unless check_valid_login
125 return false unless check_valid_login
126 user = User.find(session[:user_id])
126 user = User.find(session[:user_id])
127 unless user.roles.detect { |role|
127 unless user.roles.detect { |role|
128 role.rights.detect{ |right|
128 role.rights.detect{ |right|
129 right.controller == self.class.controller_name and
129 right.controller == self.class.controller_name and
130 (right.action == 'all' || right.action == action_name)
130 (right.action == 'all' || right.action == action_name)
131 }
131 }
132 }
132 }
133 flash[:notice] = 'You are not authorized to view the page you requested'
133 flash[:notice] = 'You are not authorized to view the page you requested'
134 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
134 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
135 redirect_to :controller => 'main', :action => 'login'
135 redirect_to :controller => 'main', :action => 'login'
136 return false
136 return false
137 end
137 end
138 end
138 end
139
139
140 def verify_time_limit
140 def verify_time_limit
141 return true if session[:user_id]==nil
141 return true if session[:user_id]==nil
142 user = User.find(session[:user_id], :include => :site)
142 user = User.find(session[:user_id], :include => :site)
143 return true if user==nil || user.site == nil
143 return true if user==nil || user.site == nil
144 if user.contest_finished?
144 if user.contest_finished?
145 flash[:notice] = 'Error: the contest you are participating is over.'
145 flash[:notice] = 'Error: the contest you are participating is over.'
146 redirect_to :back
146 redirect_to :back
147 return false
147 return false
148 end
148 end
149 return true
149 return true
150 end
150 end
151
151
152 def is_request_ip_allowed?
152 def is_request_ip_allowed?
153 unless GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
153 unless GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
154 user_ip = IPAddr.new(request.remote_ip)
154 user_ip = IPAddr.new(request.remote_ip)
155 + allowed = GraderConfiguration[WHITELIST_IP_CONF_KEY] || ''
155
156
156 - GraderConfiguration[WHITELIST_IP_CONF_KEY].delete(' ').split(',').each do |ips|
157 + allowed.delete(' ').split(',').each do |ips|
157 allow_ips = IPAddr.new(ips)
158 allow_ips = IPAddr.new(ips)
158 if allow_ips.include?(user_ip)
159 if allow_ips.include?(user_ip)
159 return true
160 return true
160 end
161 end
161 end
162 end
162 return false
163 return false
163 end
164 end
164 return true
165 return true
165 end
166 end
166
167
167 #function for datatable ajax query
168 #function for datatable ajax query
168 #return record,total_count,filter_count
169 #return record,total_count,filter_count
169 def process_query_record(record,
170 def process_query_record(record,
170 total_count: nil,
171 total_count: nil,
171 select: '',
172 select: '',
172 global_search: [],
173 global_search: [],
173 no_search: false,
174 no_search: false,
174 force_order: '',
175 force_order: '',
175 date_filter: '', date_param_since: 'date_since',date_param_until: 'date_until',
176 date_filter: '', date_param_since: 'date_since',date_param_until: 'date_until',
176 hard_limit: nil)
177 hard_limit: nil)
177 arel_table = record.model.arel_table
178 arel_table = record.model.arel_table
178
179
179 if !no_search && params['search']
180 if !no_search && params['search']
180 global_value = record.model.sanitize_sql(params['search']['value'].strip.downcase)
181 global_value = record.model.sanitize_sql(params['search']['value'].strip.downcase)
181 if !global_value.blank?
182 if !global_value.blank?
182 global_value.split.each do |value|
183 global_value.split.each do |value|
183 global_where = global_search.map{|f| "LOWER(#{f}) like '%#{value}%'"}.join(' OR ')
184 global_where = global_search.map{|f| "LOWER(#{f}) like '%#{value}%'"}.join(' OR ')
184 record = record.where(global_where)
185 record = record.where(global_where)
185 end
186 end
186 end
187 end
187
188
188 params['columns'].each do |i, col|
189 params['columns'].each do |i, col|
189 if !col['search']['value'].blank?
190 if !col['search']['value'].blank?
190 record = record.where(arel_table[col['name']].lower.matches("%#{col['search']['value'].strip.downcase}%"))
191 record = record.where(arel_table[col['name']].lower.matches("%#{col['search']['value'].strip.downcase}%"))
191 end
192 end
192 end
193 end
193 end
194 end
194
195
195 if !date_filter.blank?
196 if !date_filter.blank?
196 param_since = params[date_param_since]
197 param_since = params[date_param_since]
197 param_until = params[date_param_until]
198 param_until = params[date_param_until]
198 date_since = Time.zone.parse( param_since ) || Time.new(1,1,1) rescue Time.new(1,1,1)
199 date_since = Time.zone.parse( param_since ) || Time.new(1,1,1) rescue Time.new(1,1,1)
199 date_until = Time.zone.parse( param_until ) || Time.zone.now() rescue Time.zone.now()
200 date_until = Time.zone.parse( param_until ) || Time.zone.now() rescue Time.zone.now()
200 date_range = date_since..(date_until.end_of_day)
201 date_range = date_since..(date_until.end_of_day)
201 record = record.where(date_filter.to_sym => date_range)
202 record = record.where(date_filter.to_sym => date_range)
202 end
203 end
203
204
204 if force_order.blank?
205 if force_order.blank?
@@ -1,104 +1,110
1 class GroupsController < ApplicationController
1 class GroupsController < ApplicationController
2 before_action :set_group, only: [:show, :edit, :update, :destroy,
2 before_action :set_group, only: [:show, :edit, :update, :destroy,
3 :add_user, :remove_user,:remove_all_user,
3 :add_user, :remove_user,:remove_all_user,
4 :add_problem, :remove_problem,:remove_all_problem,
4 :add_problem, :remove_problem,:remove_all_problem,
5 + :toggle,
5 ]
6 ]
6 before_action :admin_authorization
7 before_action :admin_authorization
7
8
8 # GET /groups
9 # GET /groups
9 def index
10 def index
10 @groups = Group.all
11 @groups = Group.all
11 end
12 end
12
13
13 # GET /groups/1
14 # GET /groups/1
14 def show
15 def show
15 end
16 end
16
17
17 # GET /groups/new
18 # GET /groups/new
18 def new
19 def new
19 @group = Group.new
20 @group = Group.new
20 end
21 end
21
22
22 # GET /groups/1/edit
23 # GET /groups/1/edit
23 def edit
24 def edit
24 end
25 end
25
26
26 # POST /groups
27 # POST /groups
27 def create
28 def create
28 @group = Group.new(group_params)
29 @group = Group.new(group_params)
29
30
30 if @group.save
31 if @group.save
31 redirect_to @group, notice: 'Group was successfully created.'
32 redirect_to @group, notice: 'Group was successfully created.'
32 else
33 else
33 render :new
34 render :new
34 end
35 end
35 end
36 end
36
37
37 # PATCH/PUT /groups/1
38 # PATCH/PUT /groups/1
38 def update
39 def update
39 if @group.update(group_params)
40 if @group.update(group_params)
40 redirect_to @group, notice: 'Group was successfully updated.'
41 redirect_to @group, notice: 'Group was successfully updated.'
41 else
42 else
42 render :edit
43 render :edit
43 end
44 end
44 end
45 end
45
46
46 # DELETE /groups/1
47 # DELETE /groups/1
47 def destroy
48 def destroy
48 @group.destroy
49 @group.destroy
49 redirect_to groups_url, notice: 'Group was successfully destroyed.'
50 redirect_to groups_url, notice: 'Group was successfully destroyed.'
50 end
51 end
51
52
53 + def toggle
54 + @group.enabled = @group.enabled? ? false : true
55 + @group.save
56 + end
57 +
52 def remove_user
58 def remove_user
53 user = User.find(params[:user_id])
59 user = User.find(params[:user_id])
54 @group.users.delete(user)
60 @group.users.delete(user)
55 redirect_to group_path(@group), flash: {success: "User #{user.login} was removed from the group #{@group.name}"}
61 redirect_to group_path(@group), flash: {success: "User #{user.login} was removed from the group #{@group.name}"}
56 end
62 end
57
63
58 def remove_all_user
64 def remove_all_user
59 @group.users.clear
65 @group.users.clear
60 redirect_to group_path(@group), alert: 'All users removed'
66 redirect_to group_path(@group), alert: 'All users removed'
61 end
67 end
62
68
63 def remove_all_problem
69 def remove_all_problem
64 @group.problems.clear
70 @group.problems.clear
65 redirect_to group_path(@group), alert: 'All problems removed'
71 redirect_to group_path(@group), alert: 'All problems removed'
66 end
72 end
67
73
68 def add_user
74 def add_user
69 user = User.find(params[:user_id])
75 user = User.find(params[:user_id])
70 begin
76 begin
71 @group.users << user
77 @group.users << user
72 redirect_to group_path(@group), flash: { success: "User #{user.login} was add to the group #{@group.name}"}
78 redirect_to group_path(@group), flash: { success: "User #{user.login} was add to the group #{@group.name}"}
73 rescue => e
79 rescue => e
74 redirect_to group_path(@group), alert: e.message
80 redirect_to group_path(@group), alert: e.message
75 end
81 end
76 end
82 end
77
83
78 def remove_problem
84 def remove_problem
79 problem = Problem.find(params[:problem_id])
85 problem = Problem.find(params[:problem_id])
80 @group.problems.delete(problem)
86 @group.problems.delete(problem)
81 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was removed from the group #{@group.name}" }
87 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was removed from the group #{@group.name}" }
82 end
88 end
83
89
84 def add_problem
90 def add_problem
85 problem = Problem.find(params[:problem_id])
91 problem = Problem.find(params[:problem_id])
86 begin
92 begin
87 @group.problems << problem
93 @group.problems << problem
88 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was add to the group #{@group.name}" }
94 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was add to the group #{@group.name}" }
89 rescue => e
95 rescue => e
90 redirect_to group_path(@group), alert: e.message
96 redirect_to group_path(@group), alert: e.message
91 end
97 end
92 end
98 end
93
99
94 private
100 private
95 # Use callbacks to share common setup or constraints between actions.
101 # Use callbacks to share common setup or constraints between actions.
96 def set_group
102 def set_group
97 @group = Group.find(params[:id])
103 @group = Group.find(params[:id])
98 end
104 end
99
105
100 # Only allow a trusted parameter "white list" through.
106 # Only allow a trusted parameter "white list" through.
101 def group_params
107 def group_params
102 - params.require(:group).permit(:name, :description)
108 + params.require(:group).permit(:name, :description, :enabled)
103 end
109 end
104 end
110 end
@@ -1,112 +1,111
1 class SubmissionsController < ApplicationController
1 class SubmissionsController < ApplicationController
2 before_action :check_valid_login
2 before_action :check_valid_login
3 before_action :submission_authorization, only: [:show, :download, :edit]
3 before_action :submission_authorization, only: [:show, :download, :edit]
4 before_action :admin_authorization, only: [:rejudge]
4 before_action :admin_authorization, only: [:rejudge]
5
5
6 # GET /submissions
6 # GET /submissions
7 # GET /submissions.json
7 # GET /submissions.json
8 # Show problem selection and user's submission of that problem
8 # Show problem selection and user's submission of that problem
9 def index
9 def index
10 @user = @current_user
10 @user = @current_user
11 @problems = @user.available_problems
11 @problems = @user.available_problems
12
12
13 if params[:problem_id]==nil
13 if params[:problem_id]==nil
14 @problem = nil
14 @problem = nil
15 @submissions = nil
15 @submissions = nil
16 else
16 else
17 @problem = Problem.find_by_id(params[:problem_id])
17 @problem = Problem.find_by_id(params[:problem_id])
18 if (@problem == nil) or (not @problem.available)
18 if (@problem == nil) or (not @problem.available)
19 - redirect_to main_list_path
19 + redirect_to list_main_path
20 - flash[:notice] = 'Error: submissions for that problem are not viewable.'
20 + flash[:error] = 'Authorization error: You have no right to view submissions for this problem'
21 return
21 return
22 end
22 end
23 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
23 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
24 end
24 end
25 end
25 end
26
26
27 # GET /submissions/1
27 # GET /submissions/1
28 # GET /submissions/1.json
28 # GET /submissions/1.json
29 def show
29 def show
30 @submission = Submission.find(params[:id])
30 @submission = Submission.find(params[:id])
31
31
32 #log the viewing
32 #log the viewing
33 user = User.find(session[:user_id])
33 user = User.find(session[:user_id])
34 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
34 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
35
35
36 @task = @submission.task
36 @task = @submission.task
37 end
37 end
38
38
39 def download
39 def download
40 @submission = Submission.find(params[:id])
40 @submission = Submission.find(params[:id])
41 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
41 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
42 end
42 end
43
43
44 def compiler_msg
44 def compiler_msg
45 @submission = Submission.find(params[:id])
45 @submission = Submission.find(params[:id])
46 respond_to do |format|
46 respond_to do |format|
47 format.js
47 format.js
48 end
48 end
49 end
49 end
50
50
51 #on-site new submission on specific problem
51 #on-site new submission on specific problem
52 def direct_edit_problem
52 def direct_edit_problem
53 @problem = Problem.find(params[:problem_id])
53 @problem = Problem.find(params[:problem_id])
54 unless @current_user.can_view_problem?(@problem)
54 unless @current_user.can_view_problem?(@problem)
55 unauthorized_redirect
55 unauthorized_redirect
56 return
56 return
57 end
57 end
58 @source = ''
58 @source = ''
59 if (params[:view_latest])
59 if (params[:view_latest])
60 sub = Submission.find_last_by_user_and_problem(@current_user.id,@problem.id)
60 sub = Submission.find_last_by_user_and_problem(@current_user.id,@problem.id)
61 @source = @submission.source.to_s if @submission and @submission.source
61 @source = @submission.source.to_s if @submission and @submission.source
62 end
62 end
63 render 'edit'
63 render 'edit'
64 end
64 end
65
65
66 # GET /submissions/1/edit
66 # GET /submissions/1/edit
67 def edit
67 def edit
68 @submission = Submission.find(params[:id])
68 @submission = Submission.find(params[:id])
69 @source = @submission.source.to_s
69 @source = @submission.source.to_s
70 @problem = @submission.problem
70 @problem = @submission.problem
71 @lang_id = @submission.language.id
71 @lang_id = @submission.language.id
72 end
72 end
73
73
74
74
75 def get_latest_submission_status
75 def get_latest_submission_status
76 @problem = Problem.find(params[:pid])
76 @problem = Problem.find(params[:pid])
77 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
77 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
78 respond_to do |format|
78 respond_to do |format|
79 format.js
79 format.js
80 end
80 end
81 end
81 end
82
82
83 # GET /submissions/:id/rejudge
83 # GET /submissions/:id/rejudge
84 def rejudge
84 def rejudge
85 @submission = Submission.find(params[:id])
85 @submission = Submission.find(params[:id])
86 @task = @submission.task
86 @task = @submission.task
87 @task.status_inqueue! if @task
87 @task.status_inqueue! if @task
88 respond_to do |format|
88 respond_to do |format|
89 format.js
89 format.js
90 end
90 end
91 end
91 end
92
92
93 protected
93 protected
94
94
95 def submission_authorization
95 def submission_authorization
96 #admin always has privileged
96 #admin always has privileged
97 - if @current_user.admin?
97 + return true if @current_user.admin?
98 - return true
98 + return true if @current_user.has_role?('TA') && (['show','download'].include? action_name)
99 - end
100
99
101 sub = Submission.find(params[:id])
100 sub = Submission.find(params[:id])
102 if @current_user.available_problems.include? sub.problem
101 if @current_user.available_problems.include? sub.problem
103 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
102 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
104 end
103 end
105
104
106 #default to NO
105 #default to NO
107 unauthorized_redirect
106 unauthorized_redirect
108 return false
107 return false
109 end
108 end
110
109
111
110
112 end
111 end
@@ -1,74 +1,76
1 class TasksController < ApplicationController
1 class TasksController < ApplicationController
2
2
3 before_action :check_valid_login, :check_viewability
3 before_action :check_valid_login, :check_viewability
4
4
5 def index
5 def index
6 redirect_to :action => 'list'
6 redirect_to :action => 'list'
7 end
7 end
8
8
9 def list
9 def list
10 @problems = @user.available_problems
10 @problems = @user.available_problems
11 end
11 end
12
12
13 # this has contest-wide access control
13 # this has contest-wide access control
14 def view
14 def view
15 base_name = params[:file]
15 base_name = params[:file]
16 base_filename = File.basename("#{base_name}.#{params[:ext]}")
16 base_filename = File.basename("#{base_name}.#{params[:ext]}")
17 filename = "#{Problem.download_file_basedir}/#{base_filename}"
17 filename = "#{Problem.download_file_basedir}/#{base_filename}"
18
18
19 if !FileTest.exists?(filename)
19 if !FileTest.exists?(filename)
20 redirect_to :action => 'index' and return
20 redirect_to :action => 'index' and return
21 end
21 end
22
22
23 send_file_to_user(filename, base_filename)
23 send_file_to_user(filename, base_filename)
24 end
24 end
25
25
26 # this has problem-level access control
26 # this has problem-level access control
27 def download
27 def download
28 problem = Problem.find(params[:id])
28 problem = Problem.find(params[:id])
29 unless @current_user.can_view_problem? problem
29 unless @current_user.can_view_problem? problem
30 - flash[:notice] = 'You are not authorized to access this file'
30 + flash[:error] = 'You are not authorized to access this file'
31 - redirect_to :action => 'index' and return
31 + redirect_to list_main_path
32 + return
32 end
33 end
33
34
34 base_name = params[:file]
35 base_name = params[:file]
35 base_filename = File.basename("#{base_name}.#{params[:ext]}")
36 base_filename = File.basename("#{base_name}.#{params[:ext]}")
36 filename = "#{Problem.download_file_basedir}/#{params[:id]}/#{base_filename}"
37 filename = "#{Problem.download_file_basedir}/#{params[:id]}/#{base_filename}"
37
38
38 if !FileTest.exists?(filename)
39 if !FileTest.exists?(filename)
39 flash[:notice] = 'File does not exists'
40 flash[:notice] = 'File does not exists'
40 - redirect_to :action => 'index' and return
41 + redirect_to list_main_path
42 + return
41 end
43 end
42
44
43 send_file_to_user(filename, base_filename)
45 send_file_to_user(filename, base_filename)
44 end
46 end
45
47
46 protected
48 protected
47
49
48 def send_file_to_user(filename, base_filename)
50 def send_file_to_user(filename, base_filename)
49 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
51 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
50 response.headers['Content-Type'] = "application/force-download"
52 response.headers['Content-Type'] = "application/force-download"
51 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
53 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
52 response.headers["X-Sendfile"] = filename
54 response.headers["X-Sendfile"] = filename
53 response.headers['Content-length'] = File.size(filename)
55 response.headers['Content-length'] = File.size(filename)
54 render :nothing => true
56 render :nothing => true
55 else
57 else
56 if params[:ext]=='pdf'
58 if params[:ext]=='pdf'
57 content_type = 'application/pdf'
59 content_type = 'application/pdf'
58 else
60 else
59 content_type = 'application/octet-stream'
61 content_type = 'application/octet-stream'
60 end
62 end
61
63
62 send_file filename, :stream => false, :disposition => 'inline', :filename => base_filename, :type => content_type
64 send_file filename, :stream => false, :disposition => 'inline', :filename => base_filename, :type => content_type
63 end
65 end
64 end
66 end
65
67
66 def check_viewability
68 def check_viewability
67 @user = User.find(session[:user_id])
69 @user = User.find(session[:user_id])
68 if @user==nil or !GraderConfiguration.show_tasks_to?(@user)
70 if @user==nil or !GraderConfiguration.show_tasks_to?(@user)
69 redirect_to :controller => 'main', :action => 'list'
71 redirect_to :controller => 'main', :action => 'list'
70 return false
72 return false
71 end
73 end
72 end
74 end
73
75
74 end
76 end
@@ -13,127 +13,137
13 @contests = Contest.enabled
13 @contests = Contest.enabled
14 end
14 end
15
15
16 def active
16 def active
17 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
17 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
18 @users = []
18 @users = []
19 sessions.each do |session|
19 sessions.each do |session|
20 if session.data[:user_id]
20 if session.data[:user_id]
21 @users << User.find(session.data[:user_id])
21 @users << User.find(session.data[:user_id])
22 end
22 end
23 end
23 end
24 end
24 end
25
25
26 def show
26 def show
27 @user = User.find(params[:id])
27 @user = User.find(params[:id])
28 end
28 end
29
29
30 def new
30 def new
31 @user = User.new
31 @user = User.new
32 end
32 end
33
33
34 def create
34 def create
35 @user = User.new(user_params)
35 @user = User.new(user_params)
36 @user.activated = true
36 @user.activated = true
37 if @user.save
37 if @user.save
38 flash[:notice] = 'User was successfully created.'
38 flash[:notice] = 'User was successfully created.'
39 redirect_to :action => 'index'
39 redirect_to :action => 'index'
40 else
40 else
41 render :action => 'new'
41 render :action => 'new'
42 end
42 end
43 end
43 end
44
44
45 def clear_last_ip
45 def clear_last_ip
46 @user = User.find(params[:id])
46 @user = User.find(params[:id])
47 @user.last_ip = nil
47 @user.last_ip = nil
48 @user.save
48 @user.save
49 redirect_to action: 'index', page: params[:page]
49 redirect_to action: 'index', page: params[:page]
50 end
50 end
51
51
52 def create_from_list
52 def create_from_list
53 lines = params[:user_list]
53 lines = params[:user_list]
54
54
55 note = []
55 note = []
56 error_note = []
56 error_note = []
57 error_msg = nil
57 error_msg = nil
58 ok_user = []
58 ok_user = []
59
59
60 lines.split("\n").each do |line|
60 lines.split("\n").each do |line|
61 - items = line.chomp.split(',')
61 + #split with large limit, this will cause consecutive ',' to be result in a blank
62 + items = line.chomp.split(',',1000)
62 if items.length>=2
63 if items.length>=2
63 login = items[0]
64 login = items[0]
64 full_name = items[1]
65 full_name = items[1]
65 remark =''
66 remark =''
66 user_alias = ''
67 user_alias = ''
67
68
68 added_random_password = false
69 added_random_password = false
69 - if items.length >= 3 and items[2].chomp(" ").length > 0;
70 + added_password = false
71 + if items.length >= 3
72 + if items[2].chomp(" ").length > 0
70 password = items[2].chomp(" ")
73 password = items[2].chomp(" ")
74 + added_password = true
75 + end
71 else
76 else
72 password = random_password
77 password = random_password
73 added_random_password=true;
78 added_random_password=true;
74 end
79 end
75
80
76 if items.length>= 4 and items[3].chomp(" ").length > 0;
81 if items.length>= 4 and items[3].chomp(" ").length > 0;
77 user_alias = items[3].chomp(" ")
82 user_alias = items[3].chomp(" ")
78 else
83 else
79 user_alias = login
84 user_alias = login
80 end
85 end
81
86
87 +
88 + has_remark = false
82 if items.length>=5
89 if items.length>=5
83 remark = items[4].strip;
90 remark = items[4].strip;
91 + has_remark = true
84 end
92 end
85
93
86 user = User.find_by_login(login)
94 user = User.find_by_login(login)
87 if (user)
95 if (user)
88 user.full_name = full_name
96 user.full_name = full_name
89 - user.password = password
97 + user.remark = remark if has_remark
90 - user.remark = remark
98 + user.password = password if added_password || added_random_password
91 else
99 else
100 + #create a random password if none are given
101 + password = random_password unless password
92 user = User.new({:login => login,
102 user = User.new({:login => login,
93 :full_name => full_name,
103 :full_name => full_name,
94 :password => password,
104 :password => password,
95 :password_confirmation => password,
105 :password_confirmation => password,
96 :alias => user_alias,
106 :alias => user_alias,
97 :remark => remark})
107 :remark => remark})
98 end
108 end
99 user.activated = true
109 user.activated = true
100
110
101 if user.save
111 if user.save
102 if added_random_password
112 if added_random_password
103 note << "'#{login}' (+)"
113 note << "'#{login}' (+)"
104 else
114 else
105 note << login
115 note << login
106 end
116 end
107 ok_user << user
117 ok_user << user
108 else
118 else
109 error_note << "'#{login}'"
119 error_note << "'#{login}'"
110 error_msg = user.errors.full_messages.to_sentence unless error_msg
120 error_msg = user.errors.full_messages.to_sentence unless error_msg
111 end
121 end
112
122
113 end
123 end
114 end
124 end
115
125
116 #add to group
126 #add to group
117 if params[:add_to_group]
127 if params[:add_to_group]
118 group = Group.where(id: params[:group_id]).first
128 group = Group.where(id: params[:group_id]).first
119 if group
129 if group
120 group.users << ok_user
130 group.users << ok_user
121 end
131 end
122 end
132 end
123
133
124 # show flash
134 # show flash
125 if note.size > 0
135 if note.size > 0
126 flash[:success] = 'User(s) ' + note.join(', ') +
136 flash[:success] = 'User(s) ' + note.join(', ') +
127 ' were successfully created. ' +
137 ' were successfully created. ' +
128 '( (+) - created with random passwords.)'
138 '( (+) - created with random passwords.)'
129 end
139 end
130 if error_note.size > 0
140 if error_note.size > 0
131 flash[:error] = "Following user(s) failed to be created: " + error_note.join(', ') + ". The error of the first failed one are: " + error_msg;
141 flash[:error] = "Following user(s) failed to be created: " + error_note.join(', ') + ". The error of the first failed one are: " + error_msg;
132 end
142 end
133 redirect_to :action => 'index'
143 redirect_to :action => 'index'
134 end
144 end
135
145
136 def edit
146 def edit
137 @user = User.find(params[:id])
147 @user = User.find(params[:id])
138 end
148 end
139
149
@@ -300,126 +310,123
300
310
301 lines = params[:login_list]
311 lines = params[:login_list]
302 if !lines or lines.blank?
312 if !lines or lines.blank?
303 flash[:notice] = 'You entered an empty list.'
313 flash[:notice] = 'You entered an empty list.'
304 redirect_to :action => 'contest_management' and return
314 redirect_to :action => 'contest_management' and return
305 end
315 end
306
316
307 note = []
317 note = []
308 users = []
318 users = []
309 lines.split("\n").each do |line|
319 lines.split("\n").each do |line|
310 user = User.find_by_login(line.chomp)
320 user = User.find_by_login(line.chomp)
311 if user
321 if user
312 if operation=='add'
322 if operation=='add'
313 if ! user.contests.include? contest
323 if ! user.contests.include? contest
314 user.contests << contest
324 user.contests << contest
315 end
325 end
316 elsif operation=='remove'
326 elsif operation=='remove'
317 user.contests.delete(contest)
327 user.contests.delete(contest)
318 else
328 else
319 user.contests = [contest]
329 user.contests = [contest]
320 end
330 end
321
331
322 if params[:reset_timer]
332 if params[:reset_timer]
323 user.contest_stat.forced_logout = true
333 user.contest_stat.forced_logout = true
324 user.contest_stat.reset_timer_and_save
334 user.contest_stat.reset_timer_and_save
325 end
335 end
326
336
327 if params[:notification_emails]
337 if params[:notification_emails]
328 send_contest_update_notification_email(user, contest)
338 send_contest_update_notification_email(user, contest)
329 end
339 end
330
340
331 note << user.login
341 note << user.login
332 users << user
342 users << user
333 end
343 end
334 end
344 end
335
345
336 if params[:reset_timer]
346 if params[:reset_timer]
337 logout_users(users)
347 logout_users(users)
338 end
348 end
339
349
340 flash[:notice] = 'User(s) ' + note.join(', ') +
350 flash[:notice] = 'User(s) ' + note.join(', ') +
341 ' were successfully modified. '
351 ' were successfully modified. '
342 redirect_to :action => 'contest_management'
352 redirect_to :action => 'contest_management'
343 end
353 end
344
354
345 # admin management
355 # admin management
346
356
347 def admin
357 def admin
348 - @admins = User.all.find_all {|user| user.admin? }
358 + @admins = Role.where(name: 'admin').take.users
359 + @tas = Role.where(name: 'ta').take.users
349 end
360 end
350
361
351 - def grant_admin
362 + def modify_role
352 - login = params[:login]
363 + user = User.find_by_login(params[:login])
353 - user = User.find_by_login(login)
364 + role = Role.find_by_name(params[:role])
354 - if user!=nil
365 + unless user && role
355 - admin_role = Role.find_by_name('admin')
366 + flash[:error] = 'Unknown user or role'
356 - user.roles << admin_role
367 + redirect_to admin_user_admin_index_path
357 - else
368 + return
358 - flash[:notice] = 'Unknown user'
359 - end
360 - flash[:notice] = 'User added as admins'
361 - redirect_to :action => 'admin'
362 end
369 end
363 -
370 + if params[:commit] == 'Grant'
364 - def revoke_admin
371 + #grant role
365 - user = User.find(params[:id])
372 + user.roles << role
366 - if user==nil
373 + flash[:notice] = "User '#{user.login}' has been granted the role '#{role.name}'"
367 - flash[:notice] = 'Unknown user'
374 + else
368 - redirect_to :action => 'admin' and return
375 + #revoke role
369 - elsif user.login == 'root'
376 + if user.login == 'root' && role.name == 'admin'
370 - flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
377 + flash[:error] = 'You cannot revoke admisnistrator permission from root.'
371 - redirect_to :action => 'admin' and return
378 + redirect_to admin_user_admin_index_path
379 + return
372 end
380 end
373 -
381 + user.roles.delete(role)
374 - admin_role = Role.find_by_name('admin')
382 + flash[:notice] = "The role '#{role.name}' has been revoked from User '#{user.login}'"
375 - user.roles.delete(admin_role)
383 + end
376 - flash[:notice] = 'User permission revoked'
384 + redirect_to admin_user_admin_index_path
377 - redirect_to :action => 'admin'
378 end
385 end
379
386
380 # mass mailing
387 # mass mailing
381
388
382 def mass_mailing
389 def mass_mailing
383 end
390 end
384
391
385 def bulk_mail
392 def bulk_mail
386 lines = params[:login_list]
393 lines = params[:login_list]
387 if !lines or lines.blank?
394 if !lines or lines.blank?
388 flash[:notice] = 'You entered an empty list.'
395 flash[:notice] = 'You entered an empty list.'
389 redirect_to :action => 'mass_mailing' and return
396 redirect_to :action => 'mass_mailing' and return
390 end
397 end
391
398
392 mail_subject = params[:subject]
399 mail_subject = params[:subject]
393 if !mail_subject or mail_subject.blank?
400 if !mail_subject or mail_subject.blank?
394 flash[:notice] = 'You entered an empty mail subject.'
401 flash[:notice] = 'You entered an empty mail subject.'
395 redirect_to :action => 'mass_mailing' and return
402 redirect_to :action => 'mass_mailing' and return
396 end
403 end
397
404
398 mail_body = params[:email_body]
405 mail_body = params[:email_body]
399 if !mail_body or mail_body.blank?
406 if !mail_body or mail_body.blank?
400 flash[:notice] = 'You entered an empty mail body.'
407 flash[:notice] = 'You entered an empty mail body.'
401 redirect_to :action => 'mass_mailing' and return
408 redirect_to :action => 'mass_mailing' and return
402 end
409 end
403
410
404 note = []
411 note = []
405 users = []
412 users = []
406 lines.split("\n").each do |line|
413 lines.split("\n").each do |line|
407 user = User.find_by_login(line.chomp)
414 user = User.find_by_login(line.chomp)
408 if user
415 if user
409 send_mail(user.email, mail_subject, mail_body)
416 send_mail(user.email, mail_subject, mail_body)
410 note << user.login
417 note << user.login
411 end
418 end
412 end
419 end
413
420
414 flash[:notice] = 'User(s) ' + note.join(', ') +
421 flash[:notice] = 'User(s) ' + note.join(', ') +
415 ' were successfully modified. '
422 ' were successfully modified. '
416 redirect_to :action => 'mass_mailing'
423 redirect_to :action => 'mass_mailing'
417 end
424 end
418
425
419 #bulk manage
426 #bulk manage
420 def bulk_manage
427 def bulk_manage
421
428
422 begin
429 begin
423 @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
430 @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
424 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
431 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
425 rescue Exception
432 rescue Exception
@@ -68,157 +68,155
68 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
68 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
69 end
69 end
70 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
70 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
71
71
72 if GraderConfiguration['system.user_setting_enabled']
72 if GraderConfiguration['system.user_setting_enabled']
73 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
73 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
74 end
74 end
75 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
75 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
76
76
77 menu_items.html_safe
77 menu_items.html_safe
78 end
78 end
79
79
80 def append_to(option,label, controller, action)
80 def append_to(option,label, controller, action)
81 option << ' ' if option!=''
81 option << ' ' if option!=''
82 option << link_to_unless_current(label,
82 option << link_to_unless_current(label,
83 :controller => controller,
83 :controller => controller,
84 :action => action)
84 :action => action)
85 end
85 end
86
86
87 def format_short_time(time)
87 def format_short_time(time)
88 now = Time.zone.now
88 now = Time.zone.now
89 st = ''
89 st = ''
90 if (time.yday != now.yday) or (time.year != now.year)
90 if (time.yday != now.yday) or (time.year != now.year)
91 st = time.strftime("%d/%m/%y ")
91 st = time.strftime("%d/%m/%y ")
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 format_full_time_ago(time)
102 def format_full_time_ago(time)
103 st = time_ago_in_words(time) + ' ago (' + format_short_time(time) + ')'
103 st = time_ago_in_words(time) + ' ago (' + format_short_time(time) + ')'
104 end
104 end
105
105
106 def read_textfile(fname,max_size=2048)
106 def read_textfile(fname,max_size=2048)
107 begin
107 begin
108 File.open(fname).read(max_size)
108 File.open(fname).read(max_size)
109 rescue
109 rescue
110 nil
110 nil
111 end
111 end
112 end
112 end
113
113
114 def toggle_button(on,toggle_url,id, option={})
114 def toggle_button(on,toggle_url,id, option={})
115 btn_size = option[:size] || 'btn-xs'
115 btn_size = option[:size] || 'btn-xs'
116 + btn_block = option[:block] || 'btn-block'
116 link_to (on ? "Yes" : "No"), toggle_url,
117 link_to (on ? "Yes" : "No"), toggle_url,
117 - {class: "btn btn-block #{btn_size} btn-#{on ? 'success' : 'default'} ajax-toggle",
118 + {class: "btn #{btn_block} #{btn_size} btn-#{on ? 'success' : 'default'} ajax-toggle",
118 id: id,
119 id: id,
119 data: {remote: true, method: 'get'}}
120 data: {remote: true, method: 'get'}}
120 end
121 end
121
122
122 def get_ace_mode(language)
123 def get_ace_mode(language)
123 # return ace mode string from Language
124 # return ace mode string from Language
124
125
125 case language.pretty_name
126 case language.pretty_name
126 when 'Pascal'
127 when 'Pascal'
127 'ace/mode/pascal'
128 'ace/mode/pascal'
128 when 'C++','C'
129 when 'C++','C'
129 'ace/mode/c_cpp'
130 'ace/mode/c_cpp'
130 when 'Ruby'
131 when 'Ruby'
131 'ace/mode/ruby'
132 'ace/mode/ruby'
132 when 'Python'
133 when 'Python'
133 'ace/mode/python'
134 'ace/mode/python'
134 when 'Java'
135 when 'Java'
135 'ace/mode/java'
136 'ace/mode/java'
136 else
137 else
137 'ace/mode/c_cpp'
138 'ace/mode/c_cpp'
138 end
139 end
139 end
140 end
140
141
141
142
142 def user_title_bar(user)
143 def user_title_bar(user)
143 header = ''
144 header = ''
144 time_left = ''
145 time_left = ''
145
146
146 #
147 #
147 # if the contest is over
148 # if the contest is over
148 if GraderConfiguration.time_limit_mode?
149 if GraderConfiguration.time_limit_mode?
149 if user.contest_finished?
150 if user.contest_finished?
150 header = <<CONTEST_OVER
151 header = <<CONTEST_OVER
151 <tr><td colspan="2" align="center">
152 <tr><td colspan="2" align="center">
152 <span class="contest-over-msg">THE CONTEST IS OVER</span>
153 <span class="contest-over-msg">THE CONTEST IS OVER</span>
153 </td></tr>
154 </td></tr>
154 CONTEST_OVER
155 CONTEST_OVER
155 end
156 end
156 if !user.contest_started?
157 if !user.contest_started?
157 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
158 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
158 else
159 else
159 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
160 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
160 " #{format_short_duration(user.contest_time_left)}"
161 " #{format_short_duration(user.contest_time_left)}"
161 end
162 end
162 end
163 end
163
164
164 #
165 #
165 # if the contest is in the anaysis mode
166 # if the contest is in the anaysis mode
166 if GraderConfiguration.analysis_mode?
167 if GraderConfiguration.analysis_mode?
167 header = <<ANALYSISMODE
168 header = <<ANALYSISMODE
168 <tr><td colspan="2" align="center">
169 <tr><td colspan="2" align="center">
169 <span class="contest-over-msg">ANALYSIS MODE</span>
170 <span class="contest-over-msg">ANALYSIS MODE</span>
170 </td></tr>
171 </td></tr>
171 ANALYSISMODE
172 ANALYSISMODE
172 end
173 end
173
174
174 contest_name = GraderConfiguration['contest.name']
175 contest_name = GraderConfiguration['contest.name']
175
176
176 #
177 #
177 # build real title bar
178 # build real title bar
178 result = <<TITLEBAR
179 result = <<TITLEBAR
179 <div class="title">
180 <div class="title">
180 <table>
181 <table>
181 #{header}
182 #{header}
182 <tr>
183 <tr>
183 <td class="left-col">
184 <td class="left-col">
184 - #{user.full_name}<br/>
185 - #{t 'title_bar.current_time'} #{format_short_time(Time.zone.now)}
186 - #{time_left}
187 <br/>
185 <br/>
188 </td>
186 </td>
189 <td class="right-col">#{contest_name}</td>
187 <td class="right-col">#{contest_name}</td>
190 </tr>
188 </tr>
191 </table>
189 </table>
192 </div>
190 </div>
193 TITLEBAR
191 TITLEBAR
194 result.html_safe
192 result.html_safe
195 end
193 end
196
194
197 def markdown(text)
195 def markdown(text)
198 markdown = RDiscount.new(text)
196 markdown = RDiscount.new(text)
199 markdown.to_html.html_safe
197 markdown.to_html.html_safe
200 end
198 end
201
199
202
200
203 BOOTSTRAP_FLASH_MSG = {
201 BOOTSTRAP_FLASH_MSG = {
204 success: 'alert-success',
202 success: 'alert-success',
205 error: 'alert-danger',
203 error: 'alert-danger',
206 alert: 'alert-danger',
204 alert: 'alert-danger',
207 notice: 'alert-info'
205 notice: 'alert-info'
208 }
206 }
209
207
210 def bootstrap_class_for(flash_type)
208 def bootstrap_class_for(flash_type)
211 BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s)
209 BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s)
212 end
210 end
213
211
214 def flash_messages
212 def flash_messages
215 flash.each do |msg_type, message|
213 flash.each do |msg_type, message|
216 concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do
214 concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do
217 concat content_tag(:button, 'x', class: "close", data: { dismiss: 'alert' })
215 concat content_tag(:button, 'x', class: "close", data: { dismiss: 'alert' })
218 concat message
216 concat message
219 end)
217 end)
220 end
218 end
221 nil
219 nil
222 end
220 end
223
221
224 end
222 end
@@ -1,20 +1,14
1 module MainHelper
1 module MainHelper
2
2
3 - def link_to_description_if_any(name, problem, options={})
3 + def link_to_description_if_any(name, problem)
4 if !problem.url.blank?
4 if !problem.url.blank?
5 - return link_to name, problem.url, options
5 + return link_to name, problem.url
6 elsif !problem.description_filename.blank?
6 elsif !problem.description_filename.blank?
7 - #build a link to a problem (via task controller)
8 basename, ext = problem.description_filename.split('.')
7 basename, ext = problem.description_filename.split('.')
9 - options[:controller] = 'tasks'
8 + return link_to name, download_task_path(problem.id,basename,ext), target: '_blank'
10 - options[:action] = 'download'
11 - options[:id] = problem.id
12 - options[:file] = basename
13 - options[:ext] = ext
14 - return link_to name, options
15 else
9 else
16 return ''
10 return ''
17 end
11 end
18 end
12 end
19
13
20 end
14 end
@@ -109,60 +109,60
109 return Problem.find_by_name(source_filename.split('.').first)
109 return Problem.find_by_name(source_filename.split('.').first)
110 else
110 else
111 return nil
111 return nil
112 end
112 end
113 end
113 end
114 end
114 end
115
115
116 def assign_problem
116 def assign_problem
117 if self.problem_id!=-1
117 if self.problem_id!=-1
118 begin
118 begin
119 self.problem = Problem.find(self.problem_id)
119 self.problem = Problem.find(self.problem_id)
120 rescue ActiveRecord::RecordNotFound
120 rescue ActiveRecord::RecordNotFound
121 self.problem = nil
121 self.problem = nil
122 end
122 end
123 else
123 else
124 self.problem = Submission.find_problem_in_source(self.source,
124 self.problem = Submission.find_problem_in_source(self.source,
125 self.source_filename)
125 self.source_filename)
126 end
126 end
127 end
127 end
128
128
129 def assign_language
129 def assign_language
130 if self.language == nil
130 if self.language == nil
131 self.language = Submission.find_language_in_source(self.source,
131 self.language = Submission.find_language_in_source(self.source,
132 self.source_filename)
132 self.source_filename)
133 end
133 end
134 end
134 end
135
135
136 # validation codes
136 # validation codes
137 def must_specify_language
137 def must_specify_language
138 return if self.source==nil
138 return if self.source==nil
139
139
140 # for output_only tasks
140 # for output_only tasks
141 return if self.problem!=nil and self.problem.output_only
141 return if self.problem!=nil and self.problem.output_only
142
142
143 if self.language == nil
143 if self.language == nil
144 errors.add('source',"Cannot detect language. Did you submit a correct source file?")
144 errors.add('source',"Cannot detect language. Did you submit a correct source file?")
145 end
145 end
146 end
146 end
147
147
148 def must_have_valid_problem
148 def must_have_valid_problem
149 return if self.source==nil
149 return if self.source==nil
150 if self.problem==nil
150 if self.problem==nil
151 errors.add('problem',"must be specified.")
151 errors.add('problem',"must be specified.")
152 else
152 else
153 #admin always have right
153 #admin always have right
154 return if self.user.admin?
154 return if self.user.admin?
155
155
156 #check if user has the right to submit the problem
156 #check if user has the right to submit the problem
157 - errors.add('problem',"must be valid.") if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
157 + errors[:base] << "Authorization error: you have no right to submit to this problem" if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
158 end
158 end
159 end
159 end
160
160
161 # callbacks
161 # callbacks
162 def assign_latest_number_if_new_recond
162 def assign_latest_number_if_new_recond
163 return if !self.new_record?
163 return if !self.new_record?
164 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
164 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
165 self.number = (latest==nil) ? 1 : latest.number + 1;
165 self.number = (latest==nil) ? 1 : latest.number + 1;
166 end
166 end
167
167
168 end
168 end
@@ -38,97 +38,101
38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
39 validates_length_of :login, :within => 3..30
39 validates_length_of :login, :within => 3..30
40
40
41 validates_presence_of :full_name
41 validates_presence_of :full_name
42 validates_length_of :full_name, :minimum => 1
42 validates_length_of :full_name, :minimum => 1
43
43
44 validates_presence_of :password, :if => :password_required?
44 validates_presence_of :password, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
47
47
48 validates_format_of :email,
48 validates_format_of :email,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
50 :if => :email_validation?
50 :if => :email_validation?
51 validate :uniqueness_of_email_from_activated_users,
51 validate :uniqueness_of_email_from_activated_users,
52 :if => :email_validation?
52 :if => :email_validation?
53 validate :enough_time_interval_between_same_email_registrations,
53 validate :enough_time_interval_between_same_email_registrations,
54 :if => :email_validation?
54 :if => :email_validation?
55
55
56 # these are for ytopc
56 # these are for ytopc
57 # disable for now
57 # disable for now
58 #validates_presence_of :province
58 #validates_presence_of :province
59
59
60 attr_accessor :password
60 attr_accessor :password
61
61
62 before_save :encrypt_new_password
62 before_save :encrypt_new_password
63 before_save :assign_default_site
63 before_save :assign_default_site
64 before_save :assign_default_contest
64 before_save :assign_default_contest
65
65
66 # this is for will_paginate
66 # this is for will_paginate
67 cattr_reader :per_page
67 cattr_reader :per_page
68 @@per_page = 50
68 @@per_page = 50
69
69
70 def self.authenticate(login, password)
70 def self.authenticate(login, password)
71 user = find_by_login(login)
71 user = find_by_login(login)
72 if user
72 if user
73 return user if user.authenticated?(password)
73 return user if user.authenticated?(password)
74 end
74 end
75 end
75 end
76
76
77 def authenticated?(password)
77 def authenticated?(password)
78 if self.activated
78 if self.activated
79 hashed_password == User.encrypt(password,self.salt)
79 hashed_password == User.encrypt(password,self.salt)
80 else
80 else
81 false
81 false
82 end
82 end
83 end
83 end
84
84
85 def admin?
85 def admin?
86 - self.roles.where(name: 'admin').count > 0
86 + has_role?('admin')
87 + end
88 +
89 + def has_role?(role)
90 + self.roles.where(name: role).count > 0
87 end
91 end
88
92
89 def email_for_editing
93 def email_for_editing
90 if self.email==nil
94 if self.email==nil
91 "(unknown)"
95 "(unknown)"
92 elsif self.email==''
96 elsif self.email==''
93 "(blank)"
97 "(blank)"
94 else
98 else
95 self.email
99 self.email
96 end
100 end
97 end
101 end
98
102
99 def email_for_editing=(e)
103 def email_for_editing=(e)
100 self.email=e
104 self.email=e
101 end
105 end
102
106
103 def alias_for_editing
107 def alias_for_editing
104 if self.alias==nil
108 if self.alias==nil
105 "(unknown)"
109 "(unknown)"
106 elsif self.alias==''
110 elsif self.alias==''
107 "(blank)"
111 "(blank)"
108 else
112 else
109 self.alias
113 self.alias
110 end
114 end
111 end
115 end
112
116
113 def alias_for_editing=(e)
117 def alias_for_editing=(e)
114 self.alias=e
118 self.alias=e
115 end
119 end
116
120
117 def activation_key
121 def activation_key
118 if self.hashed_password==nil
122 if self.hashed_password==nil
119 encrypt_new_password
123 encrypt_new_password
120 end
124 end
121 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
125 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
122 end
126 end
123
127
124 def verify_activation_key(key)
128 def verify_activation_key(key)
125 key == activation_key
129 key == activation_key
126 end
130 end
127
131
128 def self.random_password(length=5)
132 def self.random_password(length=5)
129 chars = 'abcdefghjkmnopqrstuvwxyz'
133 chars = 'abcdefghjkmnopqrstuvwxyz'
130 password = ''
134 password = ''
131 length.times { password << chars[rand(chars.length - 1)] }
135 length.times { password << chars[rand(chars.length - 1)] }
132 password
136 password
133 end
137 end
134
138
@@ -230,119 +234,122
230 available_problems.each {|p| pin[p.id] = true}
234 available_problems.each {|p| pin[p.id] = true}
231 end
235 end
232 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
236 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
233 contest_problems << {
237 contest_problems << {
234 :contest => nil,
238 :contest => nil,
235 :problems => other_avaiable_problems
239 :problems => other_avaiable_problems
236 }
240 }
237 return contest_problems
241 return contest_problems
238 end
242 end
239
243
240 def solve_all_available_problems?
244 def solve_all_available_problems?
241 available_problems.each do |p|
245 available_problems.each do |p|
242 u = self
246 u = self
243 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
247 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
244 return false if !p or !sub or sub.points < p.full_score
248 return false if !p or !sub or sub.points < p.full_score
245 end
249 end
246 return true
250 return true
247 end
251 end
248
252
249 #get a list of available problem
253 #get a list of available problem
250 def available_problems
254 def available_problems
251 # first, we check if this is normal mode
255 # first, we check if this is normal mode
252 if not GraderConfiguration.multicontests?
256 if not GraderConfiguration.multicontests?
253
257
254 #if this is a normal mode
258 #if this is a normal mode
255 #we show problem based on problem_group, if the config said so
259 #we show problem based on problem_group, if the config said so
256 if GraderConfiguration.use_problem_group?
260 if GraderConfiguration.use_problem_group?
257 return available_problems_in_group
261 return available_problems_in_group
258 else
262 else
259 return Problem.available_problems
263 return Problem.available_problems
260 end
264 end
261 else
265 else
262 #this is multi contest mode
266 #this is multi contest mode
263 contest_problems = []
267 contest_problems = []
264 pin = {}
268 pin = {}
265 contests.enabled.each do |contest|
269 contests.enabled.each do |contest|
266 contest.problems.available.each do |problem|
270 contest.problems.available.each do |problem|
267 if not pin.has_key? problem.id
271 if not pin.has_key? problem.id
268 contest_problems << problem
272 contest_problems << problem
269 end
273 end
270 pin[problem.id] = true
274 pin[problem.id] = true
271 end
275 end
272 end
276 end
273 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
277 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
274 return contest_problems + other_avaiable_problems
278 return contest_problems + other_avaiable_problems
275 end
279 end
276 end
280 end
277
281
282 + # new feature, get list of available problem in all enabled group that the user belongs to
278 def available_problems_in_group
283 def available_problems_in_group
279 problem = []
284 problem = []
280 - self.groups.each do |group|
285 + self.groups.where(enabled: true).each do |group|
281 group.problems.where(available: true).each { |p| problem << p }
286 group.problems.where(available: true).each { |p| problem << p }
282 end
287 end
283 problem.uniq!
288 problem.uniq!
284 if problem
289 if problem
285 problem.sort! do |a,b|
290 problem.sort! do |a,b|
286 case
291 case
287 when a.date_added < b.date_added
292 when a.date_added < b.date_added
288 1
293 1
289 when a.date_added > b.date_added
294 when a.date_added > b.date_added
290 -1
295 -1
291 else
296 else
292 a.name <=> b.name
297 a.name <=> b.name
293 end
298 end
294 end
299 end
295 return problem
300 return problem
296 else
301 else
297 return []
302 return []
298 end
303 end
299 end
304 end
300
305
306 + #check if the user has the right to view that problem
307 + #this also consider group based problem policy
301 def can_view_problem?(problem)
308 def can_view_problem?(problem)
302 return true if admin?
309 return true if admin?
303 return available_problems.include? problem
310 return available_problems.include? problem
304 end
311 end
305
312
306 def self.clear_last_login
313 def self.clear_last_login
307 User.update_all(:last_ip => nil)
314 User.update_all(:last_ip => nil)
308 end
315 end
309
316
310 protected
317 protected
311 def encrypt_new_password
318 def encrypt_new_password
312 return if password.blank?
319 return if password.blank?
313 self.salt = (10+rand(90)).to_s
320 self.salt = (10+rand(90)).to_s
314 self.hashed_password = User.encrypt(self.password,self.salt)
321 self.hashed_password = User.encrypt(self.password,self.salt)
315 end
322 end
316
323
317 def assign_default_site
324 def assign_default_site
318 # have to catch error when migrating (because self.site is not available).
325 # have to catch error when migrating (because self.site is not available).
319 begin
326 begin
320 if self.site==nil
327 if self.site==nil
321 self.site = Site.find_by_name('default')
328 self.site = Site.find_by_name('default')
322 if self.site==nil
329 if self.site==nil
323 self.site = Site.find(1) # when 'default has be renamed'
330 self.site = Site.find(1) # when 'default has be renamed'
324 end
331 end
325 end
332 end
326 rescue
333 rescue
327 end
334 end
328 end
335 end
329
336
330 def assign_default_contest
337 def assign_default_contest
331 # have to catch error when migrating (because self.site is not available).
338 # have to catch error when migrating (because self.site is not available).
332 begin
339 begin
333 if self.contests.length == 0
340 if self.contests.length == 0
334 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
341 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
335 if default_contest
342 if default_contest
336 self.contests = [default_contest]
343 self.contests = [default_contest]
337 end
344 end
338 end
345 end
339 rescue
346 rescue
340 end
347 end
341 end
348 end
342
349
343 def password_required?
350 def password_required?
344 self.hashed_password.blank? || !self.password.blank?
351 self.hashed_password.blank? || !self.password.blank?
345 end
352 end
346
353
347 def self.encrypt(string,salt)
354 def self.encrypt(string,salt)
348 Digest::SHA1.hexdigest(salt + string)
355 Digest::SHA1.hexdigest(salt + string)
@@ -1,26 +1,26
1
1
2 %tr
2 %tr
3 %td{:align => "center"}
3 %td{:align => "center"}
4 = submission.number
4 = submission.number
5 %td.text-right
5 %td.text-right
6 = link_to "##{submission.id}", submission_path(submission.id)
6 = link_to "##{submission.id}", submission_path(submission.id)
7 %td
7 %td
8 = l submission.submitted_at, format: :long
8 = l submission.submitted_at, format: :long
9 = "( #{time_ago_in_words(submission.submitted_at)} ago)"
9 = "( #{time_ago_in_words(submission.submitted_at)} ago)"
10 %td
10 %td
11 = submission.source_filename
11 = submission.source_filename
12 = " (#{submission.language.pretty_name}) "
12 = " (#{submission.language.pretty_name}) "
13 - = link_to('[load]',{:action => 'source', :id => submission.id})
13 + = link_to '[load]', download_submission_path(submission)
14 %td
14 %td
15 - if submission.graded_at
15 - if submission.graded_at
16 = "Graded at #{format_short_time(submission.graded_at)}."
16 = "Graded at #{format_short_time(submission.graded_at)}."
17 %br/
17 %br/
18 = "Score: #{(submission.points*100/submission.problem.full_score).to_i} " if GraderConfiguration['ui.show_score']
18 = "Score: #{(submission.points*100/submission.problem.full_score).to_i} " if GraderConfiguration['ui.show_score']
19 = " ["
19 = " ["
20 %tt
20 %tt
21 = submission.grader_comment
21 = submission.grader_comment
22 = "]"
22 = "]"
23 %td
23 %td
24 = render :partial => 'compiler_message', :locals => {:compiler_message => submission.compiler_message }
24 = render :partial => 'compiler_message', :locals => {:compiler_message => submission.compiler_message }
25 %td
25 %td
26 = link_to 'Edit', edit_submission_path(submission.id), class: 'btn btn-success'
26 = link_to 'Edit', edit_submission_path(submission.id), class: 'btn btn-success'
@@ -1,64 +1,64
1 - content_for :head do
1 - content_for :head do
2 <meta http-equiv ="refresh" content="60"/>
2 <meta http-equiv ="refresh" content="60"/>
3
3
4 %h1 Grader information
4 %h1 Grader information
5
5
6 %p
6 %p
7 = link_to 'Refresh', { :action => 'list' }, class: 'btn btn-info'
7 = link_to 'Refresh', { :action => 'list' }, class: 'btn btn-info'
8
8
9 .panel.panel-primary
9 .panel.panel-primary
10 .panel-heading
10 .panel-heading
11 Grader control:
11 Grader control:
12 .panel-body
12 .panel-body
13 - =link_to 'Start Graders in grading env', { action: 'start_grading'}, class: 'btn btn-default', method: 'post'
13 + =link_to 'Start Graders in grading env', { action: 'start_grading'}, class: 'btn btn-default'
14 - =link_to 'Start Graders in exam env', { action: 'start_exam'}, class: 'btn btn-default', method: 'post'
14 + =link_to 'Start Graders in exam env', { action: 'start_exam'}, class: 'btn btn-default'
15 - =link_to 'Stop all running Graders', { action: 'stop_all'}, class: 'btn btn-default', method: 'post'
15 + =link_to 'Stop all running Graders', { action: 'stop_all'}, class: 'btn btn-default'
16 - =link_to 'Clear all data', { action: 'clear_all'}, class: 'btn btn-default', method: 'post'
16 + =link_to 'Clear all data', { action: 'clear_all'}, class: 'btn btn-default'
17
17
18 .row
18 .row
19 .col-md-6
19 .col-md-6
20 - if @last_task
20 - if @last_task
21 Last task:
21 Last task:
22 = link_to "#{@last_task.id}", :action => 'view', :id => @last_task.id, :type => 'Task'
22 = link_to "#{@last_task.id}", :action => 'view', :id => @last_task.id, :type => 'Task'
23
23
24 %br/
24 %br/
25
25
26 - if @last_test_request
26 - if @last_test_request
27 Last test_request:
27 Last test_request:
28 = link_to "#{@last_test_request.id}", :action => 'view', :id => @last_test_request.id, :type => 'TestRequest'
28 = link_to "#{@last_test_request.id}", :action => 'view', :id => @last_test_request.id, :type => 'TestRequest'
29
29
30 %h2 Current graders
30 %h2 Current graders
31
31
32 = render :partial => 'grader_list', :locals => {:grader_list => @grader_processes}
32 = render :partial => 'grader_list', :locals => {:grader_list => @grader_processes}
33
33
34 %h2 Stalled graders
34 %h2 Stalled graders
35
35
36 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
36 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
37
37
38 %h2 Terminated graders
38 %h2 Terminated graders
39
39
40 %p= link_to 'Clear data for terminated graders', { action: 'clear_terminated'}, class: 'btn btn-default', method: 'post'
40 %p= link_to 'Clear data for terminated graders', { action: 'clear_terminated'}, class: 'btn btn-default', method: 'post'
41
41
42 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
42 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
43 .col-md-6
43 .col-md-6
44 %h2 Last 20 submissions
44 %h2 Last 20 submissions
45 %table.table.table-striped.table-condensed
45 %table.table.table-striped.table-condensed
46 %thead
46 %thead
47 %th ID
47 %th ID
48 %th User
48 %th User
49 %th Problem
49 %th Problem
50 %th Submitted
50 %th Submitted
51 %th Graded
51 %th Graded
52 %th Result
52 %th Result
53 %tbody
53 %tbody
54 - @submission.each do |sub|
54 - @submission.each do |sub|
55 %tr.inactive
55 %tr.inactive
56 %td= link_to sub.id, submission_path(sub.id)
56 %td= link_to sub.id, submission_path(sub.id)
57 %td= ("" unless sub.user) || link_to(sub.try(:user).try(:full_name), stat_user_path(sub.user.id))
57 %td= ("" unless sub.user) || link_to(sub.try(:user).try(:full_name), stat_user_path(sub.user.id))
58 %td= ("" unless sub.problem) || link_to(sub.try(:problem).try(:full_name), stat_problem_path(sub.problem.id))
58 %td= ("" unless sub.problem) || link_to(sub.try(:problem).try(:full_name), stat_problem_path(sub.problem.id))
59 %td= "#{time_ago_in_words(sub.submitted_at)} ago"
59 %td= "#{time_ago_in_words(sub.submitted_at)} ago"
60 %td= sub.graded_at ? "#{time_ago_in_words(sub.graded_at)} ago" : " "
60 %td= sub.graded_at ? "#{time_ago_in_words(sub.graded_at)} ago" : " "
61 %td= sub.grader_comment
61 %td= sub.grader_comment
62 %h2 Ungraded submission
62 %h2 Ungraded submission
63 %table.table.table-striped.table-condensed
63 %table.table.table-striped.table-condensed
64 %thead
64 %thead
@@ -1,16 +1,27
1 = form_for @group do |f|
1 = form_for @group do |f|
2 - if @group.errors.any?
2 - if @group.errors.any?
3 #error_explanation
3 #error_explanation
4 %h2= "#{pluralize(@group.errors.count, "error")} prohibited this group from being saved:"
4 %h2= "#{pluralize(@group.errors.count, "error")} prohibited this group from being saved:"
5 %ul
5 %ul
6 - @group.errors.full_messages.each do |msg|
6 - @group.errors.full_messages.each do |msg|
7 %li= msg
7 %li= msg
8 -
8 + .row
9 + .col-md-6
9 .form-group.field
10 .form-group.field
10 = f.label :name
11 = f.label :name
11 = f.text_field :name, class: 'form-control'
12 = f.text_field :name, class: 'form-control'
13 + .row
14 + .col-md-6
12 .form-group.field
15 .form-group.field
13 = f.label :description
16 = f.label :description
14 = f.text_field :description, class: 'form-control'
17 = f.text_field :description, class: 'form-control'
18 + .row
19 + .col-md-6
20 + .checkbox
21 + = f.label :enabled do
22 + = f.check_box :enabled
23 + Enabled
24 + .row
25 + .col-md-6
15 .form-group.actions
26 .form-group.actions
16 = f.submit 'Save', class: 'btn btn-primary'
27 = f.submit 'Save', class: 'btn btn-primary'
@@ -1,22 +1,24
1 %h1 Groups
1 %h1 Groups
2
2
3 %p
3 %p
4 = link_to 'New Group', new_group_path, class: 'btn btn-primary'
4 = link_to 'New Group', new_group_path, class: 'btn btn-primary'
5 %table.table.table-hover
5 %table.table.table-hover
6 %thead
6 %thead
7 %tr
7 %tr
8 %th Name
8 %th Name
9 %th Description
9 %th Description
10 + %th Enabled?
10 %th
11 %th
11 %th
12 %th
12
13
13 %tbody
14 %tbody
14 - @groups.each do |group|
15 - @groups.each do |group|
15 - %tr
16 + %tr{:class => "#{(group.enabled?) ? "success" : "danger"}", id: "group-#{group.id}"}
16 %td= group.name
17 %td= group.name
17 %td= group.description
18 %td= group.description
19 + %td= toggle_button(group.enabled?, toggle_group_path(group), "group-enabled-#{group.id}", size: ' ', block: ' ')
18 %td= link_to 'View', group, class: 'btn btn-default'
20 %td= link_to 'View', group, class: 'btn btn-default'
19 %td= link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger'
21 %td= link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger'
20
22
21 %br
23 %br
22
24
@@ -23,74 +23,74
23 = add_menu("Self Test", 'test', 'index')
23 = add_menu("Self Test", 'test', 'index')
24 / hall of fame
24 / hall of fame
25 - if GraderConfiguration['right.user_hall_of_fame']
25 - if GraderConfiguration['right.user_hall_of_fame']
26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
27 / display MODE button (with countdown in contest mode)
27 / display MODE button (with countdown in contest mode)
28 - if GraderConfiguration.analysis_mode?
28 - if GraderConfiguration.analysis_mode?
29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
30 - elsif GraderConfiguration.time_limit_mode?
30 - elsif GraderConfiguration.time_limit_mode?
31 - if @current_user.contest_finished?
31 - if @current_user.contest_finished?
32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
33 - elsif !@current_user.contest_started?
33 - elsif !@current_user.contest_started?
34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
35 - else
35 - else
36 %div.navbar-btn.btn.btn-primary#countdown asdf
36 %div.navbar-btn.btn.btn-primary#countdown asdf
37 :javascript
37 :javascript
38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
39 / admin section
39 / admin section
40 - if (@current_user!=nil) and (session[:admin])
40 - if (@current_user!=nil) and (session[:admin])
41 / management
41 / management
42 %li.dropdown
42 %li.dropdown
43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
44 Manage
44 Manage
45 %span.caret
45 %span.caret
46 %ul.dropdown-menu
46 %ul.dropdown-menu
47 = add_menu( 'Announcements', 'announcements', 'index')
47 = add_menu( 'Announcements', 'announcements', 'index')
48 = add_menu( 'Problems', 'problems', 'index')
48 = add_menu( 'Problems', 'problems', 'index')
49 = add_menu( 'Tags', 'tags', 'index')
49 = add_menu( 'Tags', 'tags', 'index')
50 = add_menu( 'Users', 'user_admin', 'index')
50 = add_menu( 'Users', 'user_admin', 'index')
51 = add_menu( 'User Groups', 'groups', 'index')
51 = add_menu( 'User Groups', 'groups', 'index')
52 = add_menu( 'Graders', 'graders', 'list')
52 = add_menu( 'Graders', 'graders', 'list')
53 = add_menu( 'Message ', 'messages', 'console')
53 = add_menu( 'Message ', 'messages', 'console')
54 %li.divider{role: 'separator'}
54 %li.divider{role: 'separator'}
55 = add_menu( 'System config', 'configurations', 'index')
55 = add_menu( 'System config', 'configurations', 'index')
56 %li.divider{role: 'separator'}
56 %li.divider{role: 'separator'}
57 = add_menu( 'Sites', 'sites', 'index')
57 = add_menu( 'Sites', 'sites', 'index')
58 = add_menu( 'Contests', 'contest_management', 'index')
58 = add_menu( 'Contests', 'contest_management', 'index')
59 / report
59 / report
60 %li.dropdown
60 %li.dropdown
61 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
61 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
62 Report
62 Report
63 %span.caret
63 %span.caret
64 %ul.dropdown-menu
64 %ul.dropdown-menu
65 = add_menu( 'Current Score', 'report', 'current_score')
65 = add_menu( 'Current Score', 'report', 'current_score')
66 = add_menu( 'Score Report', 'report', 'max_score')
66 = add_menu( 'Score Report', 'report', 'max_score')
67 = add_menu( 'Submission Report', 'report', 'submission')
67 = add_menu( 'Submission Report', 'report', 'submission')
68 = add_menu( 'Login Report', 'report', 'login')
68 = add_menu( 'Login Report', 'report', 'login')
69 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
69 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
70 =link_to "#{ungraded} backlogs!",
70 =link_to "#{ungraded} backlogs!",
71 - grader_list_path,
71 + graders_list_path,
72 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
72 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
73
73
74 %ul.nav.navbar-nav.navbar-right
74 %ul.nav.navbar-nav.navbar-right
75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'index', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'index', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
77 - if GraderConfiguration['system.user_setting_enabled']
77 - if GraderConfiguration['system.user_setting_enabled']
78 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog', id: 'user_profile')}".html_safe, 'users', 'profile', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
78 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog', id: 'user_profile')}".html_safe, 'users', 'profile', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
79 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
79 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
80
80
81 /
81 /
82 - if (@current_user!=nil) and (session[:admin])
82 - if (@current_user!=nil) and (session[:admin])
83 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
83 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
84 .container-fluid
84 .container-fluid
85 .collapse.navbar-collapse
85 .collapse.navbar-collapse
86 %ul.nav.navbar-nav
86 %ul.nav.navbar-nav
87 = add_menu( '[Announcements]', 'announcements', 'index')
87 = add_menu( '[Announcements]', 'announcements', 'index')
88 = add_menu( '[Msg console]', 'messages', 'console')
88 = add_menu( '[Msg console]', 'messages', 'console')
89 = add_menu( '[Problems]', 'problems', 'index')
89 = add_menu( '[Problems]', 'problems', 'index')
90 = add_menu( '[Users]', 'user_admin', 'index')
90 = add_menu( '[Users]', 'user_admin', 'index')
91 = add_menu( '[Results]', 'user_admin', 'user_stat')
91 = add_menu( '[Results]', 'user_admin', 'user_stat')
92 = add_menu( '[Report]', 'report', 'multiple_login')
92 = add_menu( '[Report]', 'report', 'multiple_login')
93 = add_menu( '[Graders]', 'graders', 'list')
93 = add_menu( '[Graders]', 'graders', 'list')
94 = add_menu( '[Contests]', 'contest_management', 'index')
94 = add_menu( '[Contests]', 'contest_management', 'index')
95 = add_menu( '[Sites]', 'sites', 'index')
95 = add_menu( '[Sites]', 'sites', 'index')
96 = add_menu( '[System config]', 'configurations', 'index')
96 = add_menu( '[System config]', 'configurations', 'index')
@@ -1,47 +1,47
1 = user_title_bar(@user)
1 = user_title_bar(@user)
2
2
3 .announcementbox
3 .announcementbox
4 %span{:class => 'title'}
4 %span{:class => 'title'}
5 =raw t 'help.how_to_submit'
5 =raw t 'help.how_to_submit'
6 .announcement
6 .announcement
7 %p
7 %p
8 =raw t 'help.must_specify_language'
8 =raw t 'help.must_specify_language'
9
9
10 %p
10 %p
11 =raw t 'help.list_available_language'
11 =raw t 'help.list_available_language'
12
12
13 %table{:border => '1'}
13 %table{:border => '1'}
14 %tr
14 %tr
15 %th{:width => '150px'} C
15 %th{:width => '150px'} C
16 %th{:width => '150px'} C++
16 %th{:width => '150px'} C++
17 %th{:width => '150px'} Pascal
17 %th{:width => '150px'} Pascal
18 %tr
18 %tr
19 %td=raw "<tt>/*<br/>LANG: C<br/>*/</tt>"
19 %td=raw "<tt>/*<br/>LANG: C<br/>*/</tt>"
20 %td=raw "<tt>/*<br/>LANG: C++<br/>*/</tt>"
20 %td=raw "<tt>/*<br/>LANG: C++<br/>*/</tt>"
21 %td=raw "<tt>{<br/>LANG: Pascal<br/>}</tt>"
21 %td=raw "<tt>{<br/>LANG: Pascal<br/>}</tt>"
22
22
23 %p
23 %p
24 =raw t 'help.accept_only_language_specified'
24 =raw t 'help.accept_only_language_specified'
25
25
26 %p
26 %p
27 =raw t 'help.specifying_task'
27 =raw t 'help.specifying_task'
28
28
29 %p
29 %p
30 =raw t 'help.example_cpp'
30 =raw t 'help.example_cpp'
31
31
32 %table{:border => '1'}
32 %table{:border => '1'}
33 %tr
33 %tr
34 %td{:width => '300px'}
34 %td{:width => '300px'}
35 %tt <tt>/*<br/>LANG: C++<br/>TASK: mobiles<br/>*/</tt>
35 %tt <tt>/*<br/>LANG: C++<br/>TASK: mobiles<br/>*/</tt>
36
36
37 %p
37 %p
38 =raw t 'help.example_pas'
38 =raw t 'help.example_pas'
39
39
40 %table{:border => '1'}
40 %table{:border => '1'}
41 %tr
41 %tr
42 %td{:width => '300px'}
42 %td{:width => '300px'}
43 %tt <tt>{<br/>LANG: Pascal<br/>TASK: mobiles<br/>}</tt>
43 %tt <tt>{<br/>LANG: Pascal<br/>TASK: mobiles<br/>}</tt>
44
44
45 %p
45 %p
46 - = raw(t('help.ask_questions_at_messages',:message_link_name => (t 'menu.messages'),:url => url_for(:controller => 'messages', :action => 'list')))
46 + = raw(t('help.ask_questions_at_messages',:message_link_name => (t 'menu.messages'),url: messages_path ))
47
47
@@ -1,59 +1,63
1 :css
1 :css
2 .fix-width {
2 .fix-width {
3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
4 }
4 }
5
5
6 %h1 Problem stat: #{@problem.name}
6 %h1 Problem stat: #{@problem.name}
7 %h2 Overview
7 %h2 Overview
8
8
9 + .row
10 + .col-md-2
11 + %strong Name:
12 + .col-md-10
13 + = @problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1
14 + = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem
15 + .row
16 + .col-md-2.strong
17 + %strong Submissions:
18 + .col-md-10
19 + = @submissions.count
20 + .row
21 + .col-md-2.strong
22 + %strong Solved/Attemped User
23 + .col-md-10
24 + #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
9
25
10 - %table.info
11 - %thead
12 - %tr.info-head
13 - %th Stat
14 - %th Value
15 - %tbody
16 - %tr{class: cycle('info-even','info-odd')}
17 - %td Submissions
18 - %td= @submissions.count
19 - %tr{class: cycle('info-even','info-odd')}
20 - %td Solved/Attempted User
21 - %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
22
26
23 %h2 Submissions Count
27 %h2 Submissions Count
24 = render partial: 'application/bar_graph', locals: { histogram: @histogram }
28 = render partial: 'application/bar_graph', locals: { histogram: @histogram }
25
29
26 %h2 Submissions
30 %h2 Submissions
27 - if @submissions and @submissions.count > 0
31 - if @submissions and @submissions.count > 0
28 %table#main_table.table.table-condensed.table-striped
32 %table#main_table.table.table-condensed.table-striped
29 %thead
33 %thead
30 %tr
34 %tr
31 %th ID
35 %th ID
32 %th Login
36 %th Login
33 %th Name
37 %th Name
34 %th Submitted_at
38 %th Submitted_at
35 %th language
39 %th language
36 %th Points
40 %th Points
37 %th comment
41 %th comment
38 %th IP
42 %th IP
39 %tbody
43 %tbody
40 - row_odd,curr = true,''
44 - row_odd,curr = true,''
41 - @submissions.each do |sub|
45 - @submissions.each do |sub|
42 - next unless sub.user
46 - next unless sub.user
43 - row_odd,curr = !row_odd, sub.user if curr != sub.user
47 - row_odd,curr = !row_odd, sub.user if curr != sub.user
44 %tr
48 %tr
45 %td= link_to sub.id, submission_path(sub)
49 %td= link_to sub.id, submission_path(sub)
46 %td= link_to sub.user.login, stat_user_path(sub.user)
50 %td= link_to sub.user.login, stat_user_path(sub.user)
47 %td= sub.user.full_name
51 %td= sub.user.full_name
48 %td{data: {order: sub.submitted_at}}= time_ago_in_words(sub.submitted_at) + " ago"
52 %td{data: {order: sub.submitted_at}}= time_ago_in_words(sub.submitted_at) + " ago"
49 %td= sub.language.name
53 %td= sub.language.name
50 %td= sub.points
54 %td= sub.points
51 %td.fix-width= sub.grader_comment
55 %td.fix-width= sub.grader_comment
52 %td= sub.ip_address
56 %td= sub.ip_address
53 - else
57 - else
54 No submission
58 No submission
55
59
56 :javascript
60 :javascript
57 $("#main_table").DataTable({
61 $("#main_table").DataTable({
58 paging: false
62 paging: false
59 });
63 });
@@ -1,92 +1,93
1 %h1= "Submission: #{@submission.id}"
1 %h1= "Submission: #{@submission.id}"
2
2
3 %textarea#data{style: "display:none;"}
3 %textarea#data{style: "display:none;"}
4 :preserve
4 :preserve
5 #{@submission.source}
5 #{@submission.source}
6
6
7 //%div.highlight{:style => "border: 1px solid black;"}
7 //%div.highlight{:style => "border: 1px solid black;"}
8 //=@formatted_code.html_safe
8 //=@formatted_code.html_safe
9
9
10
10
11 .containter
11 .containter
12 .row
12 .row
13 .col-md-7
13 .col-md-7
14 %h2 Source Code
14 %h2 Source Code
15 .col-md-5
15 .col-md-5
16 %h2 Stat
16 %h2 Stat
17 .row
17 .row
18 .col-md-7
18 .col-md-7
19 %div#editor{ style: "font-size: 14px; height: 400px; border-radius:5px;" }
19 %div#editor{ style: "font-size: 14px; height: 400px; border-radius:5px;" }
20 :javascript
20 :javascript
21 e = ace.edit("editor")
21 e = ace.edit("editor")
22 e.setOptions({ maxLines: Infinity })
22 e.setOptions({ maxLines: Infinity })
23 e.setValue($("#data").text())
23 e.setValue($("#data").text())
24 e.gotoLine(1)
24 e.gotoLine(1)
25 e.getSession().setMode("#{get_ace_mode(@submission.language)}")
25 e.getSession().setMode("#{get_ace_mode(@submission.language)}")
26 e.setReadOnly(true)
26 e.setReadOnly(true)
27 .col-md-5
27 .col-md-5
28 %table.table.table-striped
28 %table.table.table-striped
29 %tr
29 %tr
30 %td.text-right
30 %td.text-right
31 %strong User
31 %strong User
32 %td
32 %td
33 - if @submission.user
33 - if @submission.user
34 = link_to "#{@submission.user.login}", stat_user_path(@submission.user)
34 = link_to "#{@submission.user.login}", stat_user_path(@submission.user)
35 = @submission.user.full_name
35 = @submission.user.full_name
36 - else
36 - else
37 = "(n/a)"
37 = "(n/a)"
38 %tr
38 %tr
39 %td.text-right
39 %td.text-right
40 %strong Task
40 %strong Task
41 %td
41 %td
42 - if @submission.problem!=nil
42 - if @submission.problem!=nil
43 = link_to "[#{@submission.problem.name}]", stat_problem_path(@submission.problem)
43 = link_to "[#{@submission.problem.name}]", stat_problem_path(@submission.problem)
44 = @submission.problem.full_name
44 = @submission.problem.full_name
45 + = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @submission.problem
45 - else
46 - else
46 = "(n/a)"
47 = "(n/a)"
47 %tr
48 %tr
48 %td.text-right
49 %td.text-right
49 %strong Tries
50 %strong Tries
50 %td= @submission.number
51 %td= @submission.number
51 %tr
52 %tr
52 %td.text-right
53 %td.text-right
53 %strong Language
54 %strong Language
54 %td= @submission.language.pretty_name
55 %td= @submission.language.pretty_name
55 %tr
56 %tr
56 %td.text-right
57 %td.text-right
57 %strong Submitted
58 %strong Submitted
58 %td #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
59 %td #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
59 %tr
60 %tr
60 %td.text-right
61 %td.text-right
61 %strong Graded
62 %strong Graded
62 - if @submission.graded_at
63 - if @submission.graded_at
63 %td #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
64 %td #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
64 - else
65 - else
65 %td -
66 %td -
66 %tr
67 %tr
67 %td.text-right
68 %td.text-right
68 %strong Points
69 %strong Points
69 %td #{@submission.points}/#{@submission.try(:problem).try(:full_score)}
70 %td #{@submission.points}/#{@submission.try(:problem).try(:full_score)}
70 %tr
71 %tr
71 %td.text-right
72 %td.text-right
72 %strong Comment
73 %strong Comment
73 %td #{@submission.grader_comment}
74 %td #{@submission.grader_comment}
74 %tr
75 %tr
75 %td.text-right
76 %td.text-right
76 %strong Runtime (s)
77 %strong Runtime (s)
77 %td #{@submission.max_runtime}
78 %td #{@submission.max_runtime}
78 %tr
79 %tr
79 %td.text-right
80 %td.text-right
80 %strong Memory (kb)
81 %strong Memory (kb)
81 %td #{@submission.peak_memory}
82 %td #{@submission.peak_memory}
82 %tr
83 %tr
83 %td.text-right
84 %td.text-right
84 %strong Compiler result
85 %strong Compiler result
85 %td
86 %td
86 %button.btn.btn-info.btn-xs{type: 'button', data: {toggle: 'modal', target: '#compiler'}}
87 %button.btn.btn-info.btn-xs{type: 'button', data: {toggle: 'modal', target: '#compiler'}}
87 view
88 view
88 - if session[:admin]
89 - if session[:admin]
89 %tr
90 %tr
90 %td.text-right
91 %td.text-right
91 %strong IP
92 %strong IP
92 %td #{@submission.ip_address}
93 %td #{@submission.ip_address}
@@ -1,25 +1,54
1 - %h1 Administrators
1 + %h1 Modify Role
2 -
2 + .row
3 - %table{:class => 'info'}
3 + .col-md-6
4 - %tr{:class => 'info-head'}
4 + %h4 Administrators
5 + = form_tag modify_role_user_admin_index_path, method: 'post', class: 'form-inline' do
6 + = hidden_field_tag :role, 'admin'
7 + .form-group
8 + = label_tag :login, 'Grant admin role to:'
9 + = text_field_tag 'login',nil, class: 'form-control'
10 + .form-group
11 + = submit_tag 'Grant', class: 'btn btn-primary'
12 + %br
13 + %table.table.table-condense.table-hover.table-striped.table-bordered
14 + %thead{:class => 'info-head'}
5 %th #
15 %th #
6 %th Login
16 %th Login
7 %th Full name
17 %th Full name
8 %th
18 %th
9 - @admins.each_with_index do |user, i|
19 - @admins.each_with_index do |user, i|
10 %tr
20 %tr
11 %td= i+1
21 %td= i+1
12 %td= user.login
22 %td= user.login
13 %td= user.full_name
23 %td= user.full_name
14 %td
24 %td
15 - if user.login!='root'
25 - if user.login!='root'
16 - = link_to '[revoke]', :action => 'revoke_admin', :id => user.id
26 + = link_to '[revoke]', modify_role_user_admin_index_path( login: user.login, role: 'admin', commit: 'revoke')
17 - %hr
27 + .col-md-6
28 + %h4 Teacher Assistants (TA)
29 + = form_tag modify_role_user_admin_index_path, method: 'post', class: 'form-inline' do
30 + = hidden_field_tag :role, 'TA'
31 + .form-group
32 + = label_tag :login, 'Grant TA role to:'
33 + = text_field_tag 'login',nil, class: 'form-control'
34 + .form-group
35 + = submit_tag 'Grant', class: 'btn btn-primary'
36 + %br
37 + %table.table.table-condense.table-hover.table-striped.table-bordered
38 + %thead{:class => 'info-head'}
39 + %th #
40 + %th Login
41 + %th Full name
42 + %th
43 + - @tas.each_with_index do |user, i|
44 + %tr
45 + %td= i+1
46 + %td= user.login
47 + %td= user.full_name
48 + %td
49 + - if user.login!='root'
50 + = link_to '[revoke]', modify_role_user_admin_index_path( login: user.login, role: 'TA', commit: 'revoke')
18
51
19 - = form_tag :action => 'grant_admin' do
20 - = label_tag :login, 'Grant admin permission to:'
21 - = text_field_tag 'login',nil, class: 'input-field'
22 - = submit_tag 'Grant', class: 'btn btn-primary'
23
52
24 %hr/
53 %hr/
25 = link_to '[go back to index]', :action => 'index'
54 = link_to '[go back to index]', :action => 'index'
@@ -1,45 +1,54
1 .container-fluid
1 .container-fluid
2 .row
2 .row
3 .col-md-6
3 .col-md-6
4 %h1 Adding list of users
4 %h1 Adding list of users
5 .row
5 .row
6 .col-md-6
6 .col-md-6
7 .panel.panel-default
7 .panel.panel-default
8 .panel-heading
8 .panel-heading
9 .panel-title Info
9 .panel-title Info
10 .panel-body
10 .panel-body
11 %ul
11 %ul
12 %li
12 %li
13 List of user information in this format:
13 List of user information in this format:
14 %tt user_id,name(,passwd(,alias(,remark)))
14 %tt user_id,name(,passwd(,alias(,remark)))
15 %li
15 %li
16 Note that
16 Note that
17 %tt passwd, alias
17 %tt passwd, alias
18 and
18 and
19 %tt remark
19 %tt remark
20 is optional.
20 is optional.
21 %li
21 %li
22 When
22 When
23 %tt passwd
23 %tt passwd
24 or
24 or
25 %tt alias
25 %tt alias
26 is empty, the original value will be used instead.
26 is empty, the original value will be used instead.
27 %li
27 %li
28 If the users with the same user_id already exists, existing information will be overwritten.
28 If the users with the same user_id already exists, existing information will be overwritten.
29 + Example:
30 + %ol
31 + %li
32 + %pre user1,Somchai Jaidee
33 + will create (or update) a user with login "user1" and setting the fullname to "Somchai Jaidee", also setting a random password.
34 + %li
35 + %pre user1,Somchai Jaidee,
36 + will create (or update) a user with login "user1" and and setting the fullname "Somchai Jaidee". No change is made to the password unless this is a new user. If this is a new user, a random password will be generated.
37 +
29
38
30 .row
39 .row
31 .col-md-6
40 .col-md-6
32 = form_tag :action => 'create_from_list' do
41 = form_tag :action => 'create_from_list' do
33 .form-group
42 .form-group
34 = submit_tag 'Create following users',class: 'btn btn-success'
43 = submit_tag 'Create following users',class: 'btn btn-success'
35 .form-group
44 .form-group
36 .div.checkbox
45 .div.checkbox
37 %label
46 %label
38 = check_box_tag :add_to_group
47 = check_box_tag :add_to_group
39 Also add these users to the following group
48 Also add these users to the following group
40 = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
49 = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
41 .form-group
50 .form-group
42 = text_area_tag 'user_list', nil, :rows => 50, :cols => 80
51 = text_area_tag 'user_list', nil, :rows => 50, :cols => 80
43 .col-md-6
52 .col-md-6
44
53
45
54
@@ -9,203 +9,203
9
9
10 resources :contests
10 resources :contests
11 resources :sites
11 resources :sites
12 resources :test
12 resources :test
13
13
14 resources :messages do
14 resources :messages do
15 member do
15 member do
16 get 'hide'
16 get 'hide'
17 post 'reply'
17 post 'reply'
18 end
18 end
19 collection do
19 collection do
20 get 'console'
20 get 'console'
21 get 'list_all'
21 get 'list_all'
22 end
22 end
23 end
23 end
24
24
25 resources :announcements do
25 resources :announcements do
26 member do
26 member do
27 get 'toggle','toggle_front'
27 get 'toggle','toggle_front'
28 end
28 end
29 end
29 end
30
30
31 resources :problems do
31 resources :problems do
32 member do
32 member do
33 get 'toggle'
33 get 'toggle'
34 get 'toggle_test'
34 get 'toggle_test'
35 get 'toggle_view_testcase'
35 get 'toggle_view_testcase'
36 get 'stat'
36 get 'stat'
37 end
37 end
38 collection do
38 collection do
39 get 'turn_all_off'
39 get 'turn_all_off'
40 get 'turn_all_on'
40 get 'turn_all_on'
41 get 'import'
41 get 'import'
42 get 'manage'
42 get 'manage'
43 get 'quick_create'
43 get 'quick_create'
44 post 'do_manage'
44 post 'do_manage'
45 post 'do_import'
45 post 'do_import'
46 end
46 end
47 end
47 end
48
48
49 resources :groups do
49 resources :groups do
50 member do
50 member do
51 post 'add_user', to: 'groups#add_user', as: 'add_user'
51 post 'add_user', to: 'groups#add_user', as: 'add_user'
52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
57 + get 'toggle'
57 end
58 end
58 collection do
59 collection do
59
60
60 end
61 end
61 end
62 end
62
63
63 resources :testcases, only: [] do
64 resources :testcases, only: [] do
64 member do
65 member do
65 get 'download_input'
66 get 'download_input'
66 get 'download_sol'
67 get 'download_sol'
67 end
68 end
68 collection do
69 collection do
69 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
70 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
70 end
71 end
71 end
72 end
72
73
73 resources :grader_configuration, controller: 'configurations' do
74 resources :grader_configuration, controller: 'configurations' do
74 collection do
75 collection do
75 get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right'
76 get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right'
76 end
77 end
77 end
78 end
78
79
79 resources :users do
80 resources :users do
80 member do
81 member do
81 get 'toggle_activate', 'toggle_enable'
82 get 'toggle_activate', 'toggle_enable'
82 get 'stat'
83 get 'stat'
83 end
84 end
84 collection do
85 collection do
85 get 'profile'
86 get 'profile'
86 post 'chg_passwd'
87 post 'chg_passwd'
87 end
88 end
88 end
89 end
89
90
90 resources :submissions do
91 resources :submissions do
91 member do
92 member do
92 get 'download'
93 get 'download'
93 get 'compiler_msg'
94 get 'compiler_msg'
94 get 'rejudge'
95 get 'rejudge'
95 - get 'source'
96 end
96 end
97 collection do
97 collection do
98 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
98 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
99 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
99 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
100 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
100 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
101 end
101 end
102 end
102 end
103
103
104
104
105 #user admin
105 #user admin
106 resources :user_admin do
106 resources :user_admin do
107 collection do
107 collection do
108 match 'bulk_manage', via: [:get, :post]
108 match 'bulk_manage', via: [:get, :post]
109 get 'bulk_mail'
109 get 'bulk_mail'
110 get 'user_stat'
110 get 'user_stat'
111 get 'import'
111 get 'import'
112 get 'new_list'
112 get 'new_list'
113 get 'admin'
113 get 'admin'
114 get 'active'
114 get 'active'
115 get 'mass_mailing'
115 get 'mass_mailing'
116 - get 'revoke_admin'
116 + match 'modify_role', via: [:get, :post]
117 - post 'grant_admin'
118 match 'create_from_list', via: [:get, :post]
117 match 'create_from_list', via: [:get, :post]
119 match 'random_all_passwords', via: [:get, :post]
118 match 'random_all_passwords', via: [:get, :post]
120 end
119 end
121 member do
120 member do
122 get 'clear_last_ip'
121 get 'clear_last_ip'
123 end
122 end
124 end
123 end
125
124
126 resources :contest_management, only: [:index] do
125 resources :contest_management, only: [:index] do
127 collection do
126 collection do
128 get 'user_stat'
127 get 'user_stat'
129 get 'clear_stat'
128 get 'clear_stat'
130 get 'clear_all_stat'
129 get 'clear_all_stat'
131 get 'change_contest_mode'
130 get 'change_contest_mode'
132 end
131 end
133 end
132 end
134
133
135 #get 'user_admin', to: 'user_admin#index'
134 #get 'user_admin', to: 'user_admin#index'
136 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
135 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
137 #post 'user_admin', to: 'user_admin#create'
136 #post 'user_admin', to: 'user_admin#create'
138 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
137 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
139
138
140 #singular resource
139 #singular resource
141 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
140 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
142 #report
141 #report
143 resource :report, only: [], controller: 'report' do
142 resource :report, only: [], controller: 'report' do
144 get 'login'
143 get 'login'
145 get 'multiple_login'
144 get 'multiple_login'
146 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
145 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
147 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
146 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
148 get 'max_score'
147 get 'max_score'
149 post 'show_max_score'
148 post 'show_max_score'
150 get 'stuck'
149 get 'stuck'
151 get 'cheat_report'
150 get 'cheat_report'
152 post 'cheat_report'
151 post 'cheat_report'
153 get 'cheat_scrutinize'
152 get 'cheat_scrutinize'
154 post 'cheat_scrutinize'
153 post 'cheat_scrutinize'
155 get 'submission'
154 get 'submission'
156 post 'submission_query'
155 post 'submission_query'
157 get 'login_stat'
156 get 'login_stat'
158 post 'login_stat'
157 post 'login_stat'
159 get 'login'
158 get 'login'
160 post 'login_summary_query'
159 post 'login_summary_query'
161 post 'login_detail_query'
160 post 'login_detail_query'
162 end
161 end
163 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
162 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
164 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
163 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
165 #get "report/login"
164 #get "report/login"
166 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
165 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
167 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
166 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
168
167
169 resource :main, only: [], controller: 'main' do
168 resource :main, only: [], controller: 'main' do
170 get 'login'
169 get 'login'
171 get 'logout'
170 get 'logout'
172 get 'list'
171 get 'list'
173 get 'submission(/:id)', action: 'submission', as: 'main_submission'
172 get 'submission(/:id)', action: 'submission', as: 'main_submission'
174 get 'announcements'
173 get 'announcements'
175 get 'help'
174 get 'help'
176 post 'submit'
175 post 'submit'
177 end
176 end
178 #main
177 #main
179 #get "main/list"
178 #get "main/list"
180 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
179 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
181 #post 'main/submit', to: 'main#submit'
180 #post 'main/submit', to: 'main#submit'
182 #get 'main/announcements', to: 'main#announcements'
181 #get 'main/announcements', to: 'main#announcements'
183
182
184
183
185 #
184 #
186 get 'tasks/view/:file.:ext' => 'tasks#view'
185 get 'tasks/view/:file.:ext' => 'tasks#view'
187 - get 'tasks/download/:id/:file.:ext' => 'tasks#download'
186 + get 'tasks/download/:id/:file.:ext' => 'tasks#download', as: 'download_task'
188 get 'heartbeat/:id/edit' => 'heartbeat#edit'
187 get 'heartbeat/:id/edit' => 'heartbeat#edit'
189
188
190 #grader
189 #grader
191 - get 'graders/list', to: 'graders#list', as: 'grader_list'
190 + #get 'graders/list', to: 'graders#list', as: 'grader_list'
192 namespace :graders do
191 namespace :graders do
193 get 'task/:id/:type', action: 'task', as: 'task'
192 get 'task/:id/:type', action: 'task', as: 'task'
194 get 'view/:id/:type', action: 'view', as: 'view'
193 get 'view/:id/:type', action: 'view', as: 'view'
195 get 'clear/:id', action: 'clear', as: 'clear'
194 get 'clear/:id', action: 'clear', as: 'clear'
196 - get 'stop'
197 - get 'stop_all'
198 - get 'clear_all'
199 - get 'clear_terminated'
200 get 'start_grading'
195 get 'start_grading'
201 get 'start_exam'
196 get 'start_exam'
197 + get 'clear_all'
198 + get 'stop_all'
202
199
200 + get 'stop'
201 + get 'clear_terminated'
202 + get 'list'
203 end
203 end
204
204
205
205
206 # See how all your routes lay out with "rake routes"
206 # See how all your routes lay out with "rake routes"
207
207
208 # This is a legacy wild controller route that's not recommended for RESTful applications.
208 # This is a legacy wild controller route that's not recommended for RESTful applications.
209 # Note: This route will make all actions in every controller accessible via GET requests.
209 # Note: This route will make all actions in every controller accessible via GET requests.
210 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
210 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
211 end
211 end
@@ -180,96 +180,97
180 :description => "If true, available problem to the user will be only ones associated with the group of the user."
180 :description => "If true, available problem to the user will be only ones associated with the group of the user."
181 },
181 },
182
182
183
183
184 {
184 {
185 :key => 'right.whitelist_ignore',
185 :key => 'right.whitelist_ignore',
186 :value_type => 'boolean',
186 :value_type => 'boolean',
187 :default_value => 'true',
187 :default_value => 'true',
188 :description => "If true, no IP check against whitelist_ip is perform. However, when false, non-admin user must have their ip in 'whitelist_ip' to be able to login."
188 :description => "If true, no IP check against whitelist_ip is perform. However, when false, non-admin user must have their ip in 'whitelist_ip' to be able to login."
189 },
189 },
190
190
191 {
191 {
192 :key => 'right.whitelist_ip',
192 :key => 'right.whitelist_ip',
193 :value_type => 'string',
193 :value_type => 'string',
194 :default_value => '0.0.0.0/0',
194 :default_value => '0.0.0.0/0',
195 :description => "list of whitelist ip, given in comma separated CIDR notation. For example '192.168.90.0/23, 192.168.1.23/32'"
195 :description => "list of whitelist ip, given in comma separated CIDR notation. For example '192.168.90.0/23, 192.168.1.23/32'"
196 },
196 },
197
197
198 ]
198 ]
199
199
200
200
201 def create_configuration_key(key,
201 def create_configuration_key(key,
202 value_type,
202 value_type,
203 default_value,
203 default_value,
204 description='')
204 description='')
205 conf = (GraderConfiguration.find_by_key(key) ||
205 conf = (GraderConfiguration.find_by_key(key) ||
206 GraderConfiguration.new(:key => key,
206 GraderConfiguration.new(:key => key,
207 :value_type => value_type,
207 :value_type => value_type,
208 :value => default_value))
208 :value => default_value))
209 conf.description = description
209 conf.description = description
210 conf.save
210 conf.save
211 end
211 end
212
212
213 def seed_config
213 def seed_config
214 CONFIGURATIONS.each do |conf|
214 CONFIGURATIONS.each do |conf|
215 if conf.has_key? :description
215 if conf.has_key? :description
216 desc = conf[:description]
216 desc = conf[:description]
217 else
217 else
218 desc = ''
218 desc = ''
219 end
219 end
220 create_configuration_key(conf[:key],
220 create_configuration_key(conf[:key],
221 conf[:value_type],
221 conf[:value_type],
222 conf[:default_value],
222 conf[:default_value],
223 desc)
223 desc)
224 end
224 end
225 end
225 end
226
226
227 def seed_roles
227 def seed_roles
228 + Role.find_or_create_by(name: 'TA')
228 return if Role.find_by_name('admin')
229 return if Role.find_by_name('admin')
229
230
230 role = Role.create(:name => 'admin')
231 role = Role.create(:name => 'admin')
231 user_admin_right = Right.create(:name => 'user_admin',
232 user_admin_right = Right.create(:name => 'user_admin',
232 :controller => 'user_admin',
233 :controller => 'user_admin',
233 :action => 'all')
234 :action => 'all')
234 problem_admin_right = Right.create(:name=> 'problem_admin',
235 problem_admin_right = Right.create(:name=> 'problem_admin',
235 :controller => 'problems',
236 :controller => 'problems',
236 :action => 'all')
237 :action => 'all')
237
238
238 graders_right = Right.create(:name => 'graders_admin',
239 graders_right = Right.create(:name => 'graders_admin',
239 :controller => 'graders',
240 :controller => 'graders',
240 :action => 'all')
241 :action => 'all')
241
242
242 role.rights << user_admin_right;
243 role.rights << user_admin_right;
243 role.rights << problem_admin_right;
244 role.rights << problem_admin_right;
244 role.rights << graders_right;
245 role.rights << graders_right;
245 role.save
246 role.save
246 end
247 end
247
248
248 def seed_root
249 def seed_root
249 return if User.find_by_login('root')
250 return if User.find_by_login('root')
250
251
251 root = User.new(:login => 'root',
252 root = User.new(:login => 'root',
252 :full_name => 'Administrator',
253 :full_name => 'Administrator',
253 :alias => 'root')
254 :alias => 'root')
254 root.password = 'ioionrails';
255 root.password = 'ioionrails';
255
256
256 class << root
257 class << root
257 public :encrypt_new_password
258 public :encrypt_new_password
258 def valid?(context=nil)
259 def valid?(context=nil)
259 true
260 true
260 end
261 end
261 end
262 end
262
263
263 root.encrypt_new_password
264 root.encrypt_new_password
264
265
265 root.roles << Role.find_by_name('admin')
266 root.roles << Role.find_by_name('admin')
266
267
267 root.activated = true
268 root.activated = true
268 root.save
269 root.save
269 end
270 end
270
271
271 def seed_users_and_roles
272 def seed_users_and_roles
272 seed_roles
273 seed_roles
273 seed_root
274 seed_root
274 end
275 end
275
276
You need to be logged in to leave comments. Login now