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

r834:825a2986c8ea - - 20 files changed: 150 inserted, 99 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
@@ -59,109 +59,110
59 #check if logged in
59 #check if logged in
60 unless session[:user_id]
60 unless session[:user_id]
61 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
61 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
62 unauthorized_redirect('You need to login but you cannot log in at this time')
62 unauthorized_redirect('You need to login but you cannot log in at this time')
63 else
63 else
64 unauthorized_redirect('You need to login')
64 unauthorized_redirect('You need to login')
65 end
65 end
66 return false
66 return false
67 end
67 end
68
68
69 # check if run in single user mode
69 # check if run in single user mode
70 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
70 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
71 if @current_user==nil || (!@current_user.admin?)
71 if @current_user==nil || (!@current_user.admin?)
72 unauthorized_redirect('You cannot log in at this time')
72 unauthorized_redirect('You cannot log in at this time')
73 return false
73 return false
74 end
74 end
75 end
75 end
76
76
77 # check if the user is enabled
77 # check if the user is enabled
78 unless @current_user.enabled? || @current_user.admin?
78 unless @current_user.enabled? || @current_user.admin?
79 unauthorized_redirect 'Your account is disabled'
79 unauthorized_redirect 'Your account is disabled'
80 return false
80 return false
81 end
81 end
82
82
83 # check if user ip is allowed
83 # check if user ip is allowed
84 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
84 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
85 unless is_request_ip_allowed?
85 unless is_request_ip_allowed?
86 unauthorized_redirect 'Your IP is not allowed to login at this time.'
86 unauthorized_redirect 'Your IP is not allowed to login at this time.'
87 return false
87 return false
88 end
88 end
89 end
89 end
90
90
91 if GraderConfiguration.multicontests?
91 if GraderConfiguration.multicontests?
92 return true if @current_user.admin?
92 return true if @current_user.admin?
93 begin
93 begin
94 if @current_user.contest_stat(true).forced_logout
94 if @current_user.contest_stat(true).forced_logout
95 flash[:notice] = 'You have been automatically logged out.'
95 flash[:notice] = 'You have been automatically logged out.'
96 redirect_to :controller => 'main', :action => 'index'
96 redirect_to :controller => 'main', :action => 'index'
97 end
97 end
98 rescue
98 rescue
99 end
99 end
100 end
100 end
101 return true
101 return true
102 end
102 end
103
103
104 #redirect to root (and also force logout)
104 #redirect to root (and also force logout)
105 #if the user use different ip from the previous connection
105 #if the user use different ip from the previous connection
106 # only applicable when MULTIPLE_IP_LOGIN options is false only
106 # only applicable when MULTIPLE_IP_LOGIN options is false only
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 end
168 end
@@ -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
@@ -95,193 +95,193
95
95
96 def source
96 def source
97 submission = Submission.find(params[:id])
97 submission = Submission.find(params[:id])
98 if ((submission.user_id == session[:user_id]) and
98 if ((submission.user_id == session[:user_id]) and
99 (submission.problem != nil) and
99 (submission.problem != nil) and
100 (submission.problem.available))
100 (submission.problem.available))
101 send_data(submission.source,
101 send_data(submission.source,
102 {:filename => submission.download_filename,
102 {:filename => submission.download_filename,
103 :type => 'text/plain'})
103 :type => 'text/plain'})
104 else
104 else
105 flash[:notice] = 'Error viewing source'
105 flash[:notice] = 'Error viewing source'
106 redirect_to :action => 'list'
106 redirect_to :action => 'list'
107 end
107 end
108 end
108 end
109
109
110 def compiler_msg
110 def compiler_msg
111 @submission = Submission.find(params[:id])
111 @submission = Submission.find(params[:id])
112 if @submission.user_id == session[:user_id]
112 if @submission.user_id == session[:user_id]
113 render :action => 'compiler_msg', :layout => 'empty'
113 render :action => 'compiler_msg', :layout => 'empty'
114 else
114 else
115 flash[:notice] = 'Error viewing source'
115 flash[:notice] = 'Error viewing source'
116 redirect_to :action => 'list'
116 redirect_to :action => 'list'
117 end
117 end
118 end
118 end
119
119
120 def result
120 def result
121 if !GraderConfiguration.show_grading_result
121 if !GraderConfiguration.show_grading_result
122 redirect_to :action => 'list' and return
122 redirect_to :action => 'list' and return
123 end
123 end
124 @user = User.find(session[:user_id])
124 @user = User.find(session[:user_id])
125 @submission = Submission.find(params[:id])
125 @submission = Submission.find(params[:id])
126 if @submission.user!=@user
126 if @submission.user!=@user
127 flash[:notice] = 'You are not allowed to view result of other users.'
127 flash[:notice] = 'You are not allowed to view result of other users.'
128 redirect_to :action => 'list' and return
128 redirect_to :action => 'list' and return
129 end
129 end
130 prepare_grading_result(@submission)
130 prepare_grading_result(@submission)
131 end
131 end
132
132
133 def load_output
133 def load_output
134 if !GraderConfiguration.show_grading_result or params[:num]==nil
134 if !GraderConfiguration.show_grading_result or params[:num]==nil
135 redirect_to :action => 'list' and return
135 redirect_to :action => 'list' and return
136 end
136 end
137 @user = User.find(session[:user_id])
137 @user = User.find(session[:user_id])
138 @submission = Submission.find(params[:id])
138 @submission = Submission.find(params[:id])
139 if @submission.user!=@user
139 if @submission.user!=@user
140 flash[:notice] = 'You are not allowed to view result of other users.'
140 flash[:notice] = 'You are not allowed to view result of other users.'
141 redirect_to :action => 'list' and return
141 redirect_to :action => 'list' and return
142 end
142 end
143 case_num = params[:num].to_i
143 case_num = params[:num].to_i
144 out_filename = output_filename(@user.login,
144 out_filename = output_filename(@user.login,
145 @submission.problem.name,
145 @submission.problem.name,
146 @submission.id,
146 @submission.id,
147 case_num)
147 case_num)
148 if !FileTest.exists?(out_filename)
148 if !FileTest.exists?(out_filename)
149 flash[:notice] = 'Output not found.'
149 flash[:notice] = 'Output not found.'
150 redirect_to :action => 'list' and return
150 redirect_to :action => 'list' and return
151 end
151 end
152
152
153 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
153 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
154 response.headers['Content-Type'] = "application/force-download"
154 response.headers['Content-Type'] = "application/force-download"
155 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
155 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
156 response.headers["X-Sendfile"] = out_filename
156 response.headers["X-Sendfile"] = out_filename
157 response.headers['Content-length'] = File.size(out_filename)
157 response.headers['Content-length'] = File.size(out_filename)
158 render :nothing => true
158 render :nothing => true
159 else
159 else
160 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
160 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
161 end
161 end
162 end
162 end
163
163
164 def error
164 def error
165 @user = User.find(session[:user_id])
165 @user = User.find(session[:user_id])
166 end
166 end
167
167
168 # announcement refreshing and hiding methods
168 # announcement refreshing and hiding methods
169
169
170 def announcements
170 def announcements
171 if params.has_key? 'recent'
171 if params.has_key? 'recent'
172 prepare_announcements(params[:recent])
172 prepare_announcements(params[:recent])
173 else
173 else
174 prepare_announcements
174 prepare_announcements
175 end
175 end
176 render(:partial => 'announcement',
176 render(:partial => 'announcement',
177 :collection => @announcements,
177 :collection => @announcements,
178 :locals => {:announcement_effect => true})
178 :locals => {:announcement_effect => true})
179 end
179 end
180
180
181 def confirm_contest_start
181 def confirm_contest_start
182 user = User.find(session[:user_id])
182 user = User.find(session[:user_id])
183 if request.method == 'POST'
183 if request.method == 'POST'
184 user.update_start_time
184 user.update_start_time
185 redirect_to :action => 'list'
185 redirect_to :action => 'list'
186 else
186 else
187 @contests = user.contests
187 @contests = user.contests
188 @user = user
188 @user = user
189 end
189 end
190 end
190 end
191 -
191 +
192 protected
192 protected
193
193
194 def prepare_announcements(recent=nil)
194 def prepare_announcements(recent=nil)
195 if GraderConfiguration.show_tasks_to?(@user)
195 if GraderConfiguration.show_tasks_to?(@user)
196 @announcements = Announcement.published(true)
196 @announcements = Announcement.published(true)
197 else
197 else
198 @announcements = Announcement.published
198 @announcements = Announcement.published
199 end
199 end
200 if recent!=nil
200 if recent!=nil
201 recent_id = recent.to_i
201 recent_id = recent.to_i
202 @announcements = @announcements.find_all { |a| a.id > recent_id }
202 @announcements = @announcements.find_all { |a| a.id > recent_id }
203 end
203 end
204 end
204 end
205
205
206 def prepare_list_information
206 def prepare_list_information
207 @user = User.find(session[:user_id])
207 @user = User.find(session[:user_id])
208 if not GraderConfiguration.multicontests?
208 if not GraderConfiguration.multicontests?
209 @problems = @user.available_problems
209 @problems = @user.available_problems
210 else
210 else
211 @contest_problems = @user.available_problems_group_by_contests
211 @contest_problems = @user.available_problems_group_by_contests
212 @problems = @user.available_problems
212 @problems = @user.available_problems
213 end
213 end
214 @prob_submissions = {}
214 @prob_submissions = {}
215 @problems.each do |p|
215 @problems.each do |p|
216 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
216 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
217 if sub!=nil
217 if sub!=nil
218 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
218 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
219 else
219 else
220 @prob_submissions[p.id] = { :count => 0, :submission => nil }
220 @prob_submissions[p.id] = { :count => 0, :submission => nil }
221 end
221 end
222 end
222 end
223 prepare_announcements
223 prepare_announcements
224 end
224 end
225
225
226 def check_viewability
226 def check_viewability
227 @user = User.find(session[:user_id])
227 @user = User.find(session[:user_id])
228 if (!GraderConfiguration.show_tasks_to?(@user)) and
228 if (!GraderConfiguration.show_tasks_to?(@user)) and
229 ((action_name=='submission') or (action_name=='submit'))
229 ((action_name=='submission') or (action_name=='submit'))
230 redirect_to :action => 'list' and return
230 redirect_to :action => 'list' and return
231 end
231 end
232 end
232 end
233
233
234 def prepare_grading_result(submission)
234 def prepare_grading_result(submission)
235 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
235 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
236 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
236 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
237 else
237 else
238 # guess task info from problem.full_score
238 # guess task info from problem.full_score
239 cases = submission.problem.full_score / 10
239 cases = submission.problem.full_score / 10
240 grading_info = {
240 grading_info = {
241 'testruns' => cases,
241 'testruns' => cases,
242 'testcases' => cases
242 'testcases' => cases
243 }
243 }
244 end
244 end
245 @test_runs = []
245 @test_runs = []
246 if grading_info['testruns'].is_a? Integer
246 if grading_info['testruns'].is_a? Integer
247 trun_count = grading_info['testruns']
247 trun_count = grading_info['testruns']
248 trun_count.times do |i|
248 trun_count.times do |i|
249 @test_runs << [ read_grading_result(@user.login,
249 @test_runs << [ read_grading_result(@user.login,
250 submission.problem.name,
250 submission.problem.name,
251 submission.id,
251 submission.id,
252 i+1) ]
252 i+1) ]
253 end
253 end
254 else
254 else
255 grading_info['testruns'].keys.sort.each do |num|
255 grading_info['testruns'].keys.sort.each do |num|
256 run = []
256 run = []
257 testrun = grading_info['testruns'][num]
257 testrun = grading_info['testruns'][num]
258 testrun.each do |c|
258 testrun.each do |c|
259 run << read_grading_result(@user.login,
259 run << read_grading_result(@user.login,
260 submission.problem.name,
260 submission.problem.name,
261 submission.id,
261 submission.id,
262 c)
262 c)
263 end
263 end
264 @test_runs << run
264 @test_runs << run
265 end
265 end
266 end
266 end
267 end
267 end
268
268
269 def grading_result_dir(user_name, problem_name, submission_id, case_num)
269 def grading_result_dir(user_name, problem_name, submission_id, case_num)
270 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
270 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
271 end
271 end
272
272
273 def output_filename(user_name, problem_name, submission_id, case_num)
273 def output_filename(user_name, problem_name, submission_id, case_num)
274 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
274 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
275 return "#{dir}/output.txt"
275 return "#{dir}/output.txt"
276 end
276 end
277
277
278 def read_grading_result(user_name, problem_name, submission_id, case_num)
278 def read_grading_result(user_name, problem_name, submission_id, case_num)
279 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
279 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
280 result_file_name = "#{dir}/result"
280 result_file_name = "#{dir}/result"
281 if !FileTest.exists?(result_file_name)
281 if !FileTest.exists?(result_file_name)
282 return {:num => case_num, :msg => 'program did not run'}
282 return {:num => case_num, :msg => 'program did not run'}
283 else
283 else
284 results = File.open(result_file_name).readlines
284 results = File.open(result_file_name).readlines
285 run_stat = extract_running_stat(results)
285 run_stat = extract_running_stat(results)
286 output_filename = "#{dir}/output.txt"
286 output_filename = "#{dir}/output.txt"
287 if FileTest.exists?(output_filename)
287 if FileTest.exists?(output_filename)
@@ -1,112 +1,112
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 if @current_user.admin?
98 return true
98 return true
99 end
99 end
100
100
101 sub = Submission.find(params[:id])
101 sub = Submission.find(params[:id])
102 if @current_user.available_problems.include? sub.problem
102 if @current_user.available_problems.include? sub.problem
103 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
103 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
104 end
104 end
105
105
106 #default to NO
106 #default to NO
107 unauthorized_redirect
107 unauthorized_redirect
108 return false
108 return false
109 end
109 end
110
110
111
111
112 end
112 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
@@ -1,194 +1,204
1 require 'csv'
1 require 'csv'
2
2
3 class UserAdminController < ApplicationController
3 class UserAdminController < ApplicationController
4
4
5 include MailHelperMethods
5 include MailHelperMethods
6
6
7 before_action :admin_authorization
7 before_action :admin_authorization
8
8
9 def index
9 def index
10 @user_count = User.count
10 @user_count = User.count
11 if params[:page] == 'all'
11 if params[:page] == 'all'
12 @users = User.all
12 @users = User.all
13 @paginated = false
13 @paginated = false
14 else
14 else
15 @users = User.paginate :page => params[:page]
15 @users = User.paginate :page => params[:page]
16 @paginated = true
16 @paginated = true
17 end
17 end
18 @users = User.all
18 @users = User.all
19 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
19 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
20 @contests = Contest.enabled
20 @contests = Contest.enabled
21 end
21 end
22
22
23 def active
23 def active
24 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
24 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
25 @users = []
25 @users = []
26 sessions.each do |session|
26 sessions.each do |session|
27 if session.data[:user_id]
27 if session.data[:user_id]
28 @users << User.find(session.data[:user_id])
28 @users << User.find(session.data[:user_id])
29 end
29 end
30 end
30 end
31 end
31 end
32
32
33 def show
33 def show
34 @user = User.find(params[:id])
34 @user = User.find(params[:id])
35 end
35 end
36
36
37 def new
37 def new
38 @user = User.new
38 @user = User.new
39 end
39 end
40
40
41 def create
41 def create
42 @user = User.new(user_params)
42 @user = User.new(user_params)
43 @user.activated = true
43 @user.activated = true
44 if @user.save
44 if @user.save
45 flash[:notice] = 'User was successfully created.'
45 flash[:notice] = 'User was successfully created.'
46 redirect_to :action => 'index'
46 redirect_to :action => 'index'
47 else
47 else
48 render :action => 'new'
48 render :action => 'new'
49 end
49 end
50 end
50 end
51
51
52 def clear_last_ip
52 def clear_last_ip
53 @user = User.find(params[:id])
53 @user = User.find(params[:id])
54 @user.last_ip = nil
54 @user.last_ip = nil
55 @user.save
55 @user.save
56 redirect_to action: 'index', page: params[:page]
56 redirect_to action: 'index', page: params[:page]
57 end
57 end
58
58
59 def create_from_list
59 def create_from_list
60 lines = params[:user_list]
60 lines = params[:user_list]
61
61
62 note = []
62 note = []
63 error_note = []
63 error_note = []
64 error_msg = nil
64 error_msg = nil
65 ok_user = []
65 ok_user = []
66
66
67 lines.split("\n").each do |line|
67 lines.split("\n").each do |line|
68 - items = line.chomp.split(',')
68 + #split with large limit, this will cause consecutive ',' to be result in a blank
69 + items = line.chomp.split(',',1000)
69 if items.length>=2
70 if items.length>=2
70 login = items[0]
71 login = items[0]
71 full_name = items[1]
72 full_name = items[1]
72 remark =''
73 remark =''
73 user_alias = ''
74 user_alias = ''
74
75
75 added_random_password = false
76 added_random_password = false
76 - if items.length >= 3 and items[2].chomp(" ").length > 0;
77 + added_password = false
77 - password = items[2].chomp(" ")
78 + if items.length >= 3
79 + if items[2].chomp(" ").length > 0
80 + password = items[2].chomp(" ")
81 + added_password = true
82 + end
78 else
83 else
79 password = random_password
84 password = random_password
80 added_random_password=true;
85 added_random_password=true;
81 end
86 end
82
87
83 if items.length>= 4 and items[3].chomp(" ").length > 0;
88 if items.length>= 4 and items[3].chomp(" ").length > 0;
84 user_alias = items[3].chomp(" ")
89 user_alias = items[3].chomp(" ")
85 else
90 else
86 user_alias = login
91 user_alias = login
87 end
92 end
88
93
94 +
95 + has_remark = false
89 if items.length>=5
96 if items.length>=5
90 remark = items[4].strip;
97 remark = items[4].strip;
98 + has_remark = true
91 end
99 end
92
100
93 user = User.find_by_login(login)
101 user = User.find_by_login(login)
94 if (user)
102 if (user)
95 user.full_name = full_name
103 user.full_name = full_name
96 - user.password = password
104 + user.remark = remark if has_remark
97 - user.remark = remark
105 + user.password = password if added_password || added_random_password
98 else
106 else
107 + #create a random password if none are given
108 + password = random_password unless password
99 user = User.new({:login => login,
109 user = User.new({:login => login,
100 :full_name => full_name,
110 :full_name => full_name,
101 :password => password,
111 :password => password,
102 :password_confirmation => password,
112 :password_confirmation => password,
103 :alias => user_alias,
113 :alias => user_alias,
104 :remark => remark})
114 :remark => remark})
105 end
115 end
106 user.activated = true
116 user.activated = true
107
117
108 if user.save
118 if user.save
109 if added_random_password
119 if added_random_password
110 note << "'#{login}' (+)"
120 note << "'#{login}' (+)"
111 else
121 else
112 note << login
122 note << login
113 end
123 end
114 ok_user << user
124 ok_user << user
115 else
125 else
116 error_note << "'#{login}'"
126 error_note << "'#{login}'"
117 error_msg = user.errors.full_messages.to_sentence unless error_msg
127 error_msg = user.errors.full_messages.to_sentence unless error_msg
118 end
128 end
119
129
120 end
130 end
121 end
131 end
122
132
123 #add to group
133 #add to group
124 if params[:add_to_group]
134 if params[:add_to_group]
125 group = Group.where(id: params[:group_id]).first
135 group = Group.where(id: params[:group_id]).first
126 if group
136 if group
127 group.users << ok_user
137 group.users << ok_user
128 end
138 end
129 end
139 end
130
140
131 # show flash
141 # show flash
132 if note.size > 0
142 if note.size > 0
133 flash[:success] = 'User(s) ' + note.join(', ') +
143 flash[:success] = 'User(s) ' + note.join(', ') +
134 ' were successfully created. ' +
144 ' were successfully created. ' +
135 '( (+) - created with random passwords.)'
145 '( (+) - created with random passwords.)'
136 end
146 end
137 if error_note.size > 0
147 if error_note.size > 0
138 flash[:error] = "Following user(s) failed to be created: " + error_note.join(', ') + ". The error of the first failed one are: " + error_msg;
148 flash[:error] = "Following user(s) failed to be created: " + error_note.join(', ') + ". The error of the first failed one are: " + error_msg;
139 end
149 end
140 redirect_to :action => 'index'
150 redirect_to :action => 'index'
141 end
151 end
142
152
143 def edit
153 def edit
144 @user = User.find(params[:id])
154 @user = User.find(params[:id])
145 end
155 end
146
156
147 def update
157 def update
148 @user = User.find(params[:id])
158 @user = User.find(params[:id])
149 if @user.update_attributes(user_params)
159 if @user.update_attributes(user_params)
150 flash[:notice] = 'User was successfully updated.'
160 flash[:notice] = 'User was successfully updated.'
151 redirect_to :action => 'show', :id => @user
161 redirect_to :action => 'show', :id => @user
152 else
162 else
153 render :action => 'edit'
163 render :action => 'edit'
154 end
164 end
155 end
165 end
156
166
157 def destroy
167 def destroy
158 User.find(params[:id]).destroy
168 User.find(params[:id]).destroy
159 redirect_to :action => 'index'
169 redirect_to :action => 'index'
160 end
170 end
161
171
162 def user_stat
172 def user_stat
163 if params[:commit] == 'download csv'
173 if params[:commit] == 'download csv'
164 @problems = Problem.all
174 @problems = Problem.all
165 else
175 else
166 @problems = Problem.available_problems
176 @problems = Problem.available_problems
167 end
177 end
168 @users = User.includes(:contests, :contest_stat).where(enabled: true)
178 @users = User.includes(:contests, :contest_stat).where(enabled: true)
169 @scorearray = Array.new
179 @scorearray = Array.new
170 @users.each do |u|
180 @users.each do |u|
171 ustat = Array.new
181 ustat = Array.new
172 ustat[0] = u
182 ustat[0] = u
173 @problems.each do |p|
183 @problems.each do |p|
174 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
184 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
175 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
185 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
176 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
186 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
177 else
187 else
178 ustat << [0,false]
188 ustat << [0,false]
179 end
189 end
180 end
190 end
181 @scorearray << ustat
191 @scorearray << ustat
182 end
192 end
183 if params[:commit] == 'download csv' then
193 if params[:commit] == 'download csv' then
184 csv = gen_csv_from_scorearray(@scorearray,@problems)
194 csv = gen_csv_from_scorearray(@scorearray,@problems)
185 send_data csv, filename: 'last_score.csv'
195 send_data csv, filename: 'last_score.csv'
186 else
196 else
187 render template: 'user_admin/user_stat'
197 render template: 'user_admin/user_stat'
188 end
198 end
189 end
199 end
190
200
191 def user_stat_max
201 def user_stat_max
192 if params[:commit] == 'download csv'
202 if params[:commit] == 'download csv'
193 @problems = Problem.all
203 @problems = Problem.all
194 else
204 else
@@ -20,205 +20,203
20 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
20 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
21 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
21 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
22 if GraderConfiguration['system.user_setting_enabled']
22 if GraderConfiguration['system.user_setting_enabled']
23 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
23 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
24 end
24 end
25 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
25 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
26
26
27
27
28 result = content_tag(:ul,left_menu.html_safe,class: 'nav navbar-nav') + content_tag(:ul,right_menu.html_safe,class: 'nav navbar-nav navbar-right')
28 result = content_tag(:ul,left_menu.html_safe,class: 'nav navbar-nav') + content_tag(:ul,right_menu.html_safe,class: 'nav navbar-nav navbar-right')
29 end
29 end
30
30
31 def add_menu(title, controller, action, html_option = {})
31 def add_menu(title, controller, action, html_option = {})
32 link_option = {controller: controller, action: action}
32 link_option = {controller: controller, action: action}
33 html_option[:class] = (html_option[:class] || '') + " active" if current_page?(link_option)
33 html_option[:class] = (html_option[:class] || '') + " active" if current_page?(link_option)
34 content_tag(:li, link_to(title,link_option),html_option)
34 content_tag(:li, link_to(title,link_option),html_option)
35 end
35 end
36
36
37 def user_header
37 def user_header
38 menu_items = ''
38 menu_items = ''
39 user = User.find(session[:user_id])
39 user = User.find(session[:user_id])
40
40
41 if (user!=nil) and (session[:admin])
41 if (user!=nil) and (session[:admin])
42 # admin menu
42 # admin menu
43 menu_items << "<b>Administrative task:</b> "
43 menu_items << "<b>Administrative task:</b> "
44 append_to menu_items, '[Announcements]', 'announcements', 'index'
44 append_to menu_items, '[Announcements]', 'announcements', 'index'
45 append_to menu_items, '[Msg console]', 'messages', 'console'
45 append_to menu_items, '[Msg console]', 'messages', 'console'
46 append_to menu_items, '[Problems]', 'problems', 'index'
46 append_to menu_items, '[Problems]', 'problems', 'index'
47 append_to menu_items, '[Users]', 'user_admin', 'index'
47 append_to menu_items, '[Users]', 'user_admin', 'index'
48 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
48 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
49 append_to menu_items, '[Report]', 'report', 'multiple_login'
49 append_to menu_items, '[Report]', 'report', 'multiple_login'
50 append_to menu_items, '[Graders]', 'graders', 'list'
50 append_to menu_items, '[Graders]', 'graders', 'list'
51 append_to menu_items, '[Contests]', 'contest_management', 'index'
51 append_to menu_items, '[Contests]', 'contest_management', 'index'
52 append_to menu_items, '[Sites]', 'sites', 'index'
52 append_to menu_items, '[Sites]', 'sites', 'index'
53 append_to menu_items, '[System config]', 'configurations', 'index'
53 append_to menu_items, '[System config]', 'configurations', 'index'
54 menu_items << "<br/>"
54 menu_items << "<br/>"
55 end
55 end
56
56
57 # main page
57 # main page
58 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
58 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
59 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
59 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
60
60
61 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
61 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
62 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
62 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
63 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
63 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
64 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
64 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
65 end
65 end
66
66
67 if GraderConfiguration['right.user_hall_of_fame']
67 if GraderConfiguration['right.user_hall_of_fame']
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
@@ -61,108 +61,108
61 if self.problem.output_only
61 if self.problem.output_only
62 return self.source_filename
62 return self.source_filename
63 else
63 else
64 timestamp = self.submitted_at.localtime.strftime("%H%M%S")
64 timestamp = self.submitted_at.localtime.strftime("%H%M%S")
65 return "#{self.problem.name}-#{timestamp}.#{self.language.ext}"
65 return "#{self.problem.name}-#{timestamp}.#{self.language.ext}"
66 end
66 end
67 end
67 end
68
68
69 protected
69 protected
70
70
71 def self.find_option_in_source(option, source)
71 def self.find_option_in_source(option, source)
72 if source==nil
72 if source==nil
73 return nil
73 return nil
74 end
74 end
75 i = 0
75 i = 0
76 source.each_line do |s|
76 source.each_line do |s|
77 if s =~ option
77 if s =~ option
78 words = s.split
78 words = s.split
79 return words[1]
79 return words[1]
80 end
80 end
81 i = i + 1
81 i = i + 1
82 if i==10
82 if i==10
83 return nil
83 return nil
84 end
84 end
85 end
85 end
86 return nil
86 return nil
87 end
87 end
88
88
89 def self.find_language_in_source(source, source_filename="")
89 def self.find_language_in_source(source, source_filename="")
90 langopt = find_option_in_source(/^LANG:/,source)
90 langopt = find_option_in_source(/^LANG:/,source)
91 if langopt
91 if langopt
92 return (Language.find_by_name(langopt) ||
92 return (Language.find_by_name(langopt) ||
93 Language.find_by_pretty_name(langopt))
93 Language.find_by_pretty_name(langopt))
94 else
94 else
95 if source_filename
95 if source_filename
96 return Language.find_by_extension(source_filename.split('.').last)
96 return Language.find_by_extension(source_filename.split('.').last)
97 else
97 else
98 return nil
98 return nil
99 end
99 end
100 end
100 end
101 end
101 end
102
102
103 def self.find_problem_in_source(source, source_filename="")
103 def self.find_problem_in_source(source, source_filename="")
104 prob_opt = find_option_in_source(/^TASK:/,source)
104 prob_opt = find_option_in_source(/^TASK:/,source)
105 if problem = Problem.find_by_name(prob_opt)
105 if problem = Problem.find_by_name(prob_opt)
106 return problem
106 return problem
107 else
107 else
108 if source_filename
108 if source_filename
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
@@ -223,195 +223,198
223 end
223 end
224 end
224 end
225
225
226 def contest_started?
226 def contest_started?
227 if GraderConfiguration.indv_contest_mode?
227 if GraderConfiguration.indv_contest_mode?
228 stat = self.contest_stat
228 stat = self.contest_stat
229 return ((stat != nil) and (stat.started_at != nil))
229 return ((stat != nil) and (stat.started_at != nil))
230 elsif GraderConfiguration.contest_mode?
230 elsif GraderConfiguration.contest_mode?
231 return true if site==nil
231 return true if site==nil
232 return site.started
232 return site.started
233 else
233 else
234 return true
234 return true
235 end
235 end
236 end
236 end
237
237
238 def update_start_time
238 def update_start_time
239 stat = self.contest_stat
239 stat = self.contest_stat
240 if stat.nil? or stat.started_at.nil?
240 if stat.nil? or stat.started_at.nil?
241 stat ||= UserContestStat.new(:user => self)
241 stat ||= UserContestStat.new(:user => self)
242 stat.started_at = Time.now.gmtime
242 stat.started_at = Time.now.gmtime
243 stat.save
243 stat.save
244 end
244 end
245 end
245 end
246
246
247 def problem_in_user_contests?(problem)
247 def problem_in_user_contests?(problem)
248 problem_contests = problem.contests.all
248 problem_contests = problem.contests.all
249
249
250 if problem_contests.length == 0 # this is public contest
250 if problem_contests.length == 0 # this is public contest
251 return true
251 return true
252 end
252 end
253
253
254 contests.each do |contest|
254 contests.each do |contest|
255 if problem_contests.find {|c| c.id == contest.id }
255 if problem_contests.find {|c| c.id == contest.id }
256 return true
256 return true
257 end
257 end
258 end
258 end
259 return false
259 return false
260 end
260 end
261
261
262 def available_problems_group_by_contests
262 def available_problems_group_by_contests
263 contest_problems = []
263 contest_problems = []
264 pin = {}
264 pin = {}
265 contests.enabled.each do |contest|
265 contests.enabled.each do |contest|
266 available_problems = contest.problems.available
266 available_problems = contest.problems.available
267 contest_problems << {
267 contest_problems << {
268 :contest => contest,
268 :contest => contest,
269 :problems => available_problems
269 :problems => available_problems
270 }
270 }
271 available_problems.each {|p| pin[p.id] = true}
271 available_problems.each {|p| pin[p.id] = true}
272 end
272 end
273 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
273 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
274 contest_problems << {
274 contest_problems << {
275 :contest => nil,
275 :contest => nil,
276 :problems => other_avaiable_problems
276 :problems => other_avaiable_problems
277 }
277 }
278 return contest_problems
278 return contest_problems
279 end
279 end
280
280
281 def solve_all_available_problems?
281 def solve_all_available_problems?
282 available_problems.each do |p|
282 available_problems.each do |p|
283 u = self
283 u = self
284 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
284 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
285 return false if !p or !sub or sub.points < p.full_score
285 return false if !p or !sub or sub.points < p.full_score
286 end
286 end
287 return true
287 return true
288 end
288 end
289
289
290 #get a list of available problem
290 #get a list of available problem
291 def available_problems
291 def available_problems
292 # first, we check if this is normal mode
292 # first, we check if this is normal mode
293 if not GraderConfiguration.multicontests?
293 if not GraderConfiguration.multicontests?
294
294
295 #if this is a normal mode
295 #if this is a normal mode
296 #we show problem based on problem_group, if the config said so
296 #we show problem based on problem_group, if the config said so
297 if GraderConfiguration.use_problem_group?
297 if GraderConfiguration.use_problem_group?
298 return available_problems_in_group
298 return available_problems_in_group
299 else
299 else
300 return Problem.available_problems
300 return Problem.available_problems
301 end
301 end
302 else
302 else
303 #this is multi contest mode
303 #this is multi contest mode
304 contest_problems = []
304 contest_problems = []
305 pin = {}
305 pin = {}
306 contests.enabled.each do |contest|
306 contests.enabled.each do |contest|
307 contest.problems.available.each do |problem|
307 contest.problems.available.each do |problem|
308 if not pin.has_key? problem.id
308 if not pin.has_key? problem.id
309 contest_problems << problem
309 contest_problems << problem
310 end
310 end
311 pin[problem.id] = true
311 pin[problem.id] = true
312 end
312 end
313 end
313 end
314 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
314 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
315 return contest_problems + other_avaiable_problems
315 return contest_problems + other_avaiable_problems
316 end
316 end
317 end
317 end
318
318
319 + # new feature, get list of available problem in all enabled group that the user belongs to
319 def available_problems_in_group
320 def available_problems_in_group
320 problem = []
321 problem = []
321 - self.groups.each do |group|
322 + self.groups.where(enabled: true).each do |group|
322 group.problems.where(available: true).each { |p| problem << p }
323 group.problems.where(available: true).each { |p| problem << p }
323 end
324 end
324 problem.uniq!
325 problem.uniq!
325 if problem
326 if problem
326 problem.sort! do |a,b|
327 problem.sort! do |a,b|
327 case
328 case
328 when a.date_added < b.date_added
329 when a.date_added < b.date_added
329 1
330 1
330 when a.date_added > b.date_added
331 when a.date_added > b.date_added
331 -1
332 -1
332 else
333 else
333 a.name <=> b.name
334 a.name <=> b.name
334 end
335 end
335 end
336 end
336 return problem
337 return problem
337 else
338 else
338 return []
339 return []
339 end
340 end
340 end
341 end
341
342
343 + #check if the user has the right to view that problem
344 + #this also consider group based problem policy
342 def can_view_problem?(problem)
345 def can_view_problem?(problem)
343 return true if admin?
346 return true if admin?
344 return available_problems.include? problem
347 return available_problems.include? problem
345 end
348 end
346
349
347 def self.clear_last_login
350 def self.clear_last_login
348 User.update_all(:last_ip => nil)
351 User.update_all(:last_ip => nil)
349 end
352 end
350
353
351 protected
354 protected
352 def encrypt_new_password
355 def encrypt_new_password
353 return if password.blank?
356 return if password.blank?
354 self.salt = (10+rand(90)).to_s
357 self.salt = (10+rand(90)).to_s
355 self.hashed_password = User.encrypt(self.password,self.salt)
358 self.hashed_password = User.encrypt(self.password,self.salt)
356 end
359 end
357
360
358 def assign_default_site
361 def assign_default_site
359 # have to catch error when migrating (because self.site is not available).
362 # have to catch error when migrating (because self.site is not available).
360 begin
363 begin
361 if self.site==nil
364 if self.site==nil
362 self.site = Site.find_by_name('default')
365 self.site = Site.find_by_name('default')
363 if self.site==nil
366 if self.site==nil
364 self.site = Site.find(1) # when 'default has be renamed'
367 self.site = Site.find(1) # when 'default has be renamed'
365 end
368 end
366 end
369 end
367 rescue
370 rescue
368 end
371 end
369 end
372 end
370
373
371 def assign_default_contest
374 def assign_default_contest
372 # have to catch error when migrating (because self.site is not available).
375 # have to catch error when migrating (because self.site is not available).
373 begin
376 begin
374 if self.contests.length == 0
377 if self.contests.length == 0
375 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
378 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
376 if default_contest
379 if default_contest
377 self.contests = [default_contest]
380 self.contests = [default_contest]
378 end
381 end
379 end
382 end
380 rescue
383 rescue
381 end
384 end
382 end
385 end
383
386
384 def password_required?
387 def password_required?
385 self.hashed_password.blank? || !self.password.blank?
388 self.hashed_password.blank? || !self.password.blank?
386 end
389 end
387
390
388 def self.encrypt(string,salt)
391 def self.encrypt(string,salt)
389 Digest::SHA1.hexdigest(salt + string)
392 Digest::SHA1.hexdigest(salt + string)
390 end
393 end
391
394
392 def uniqueness_of_email_from_activated_users
395 def uniqueness_of_email_from_activated_users
393 user = User.activated_users.find_by_email(self.email)
396 user = User.activated_users.find_by_email(self.email)
394 if user and (user.login != self.login)
397 if user and (user.login != self.login)
395 self.errors.add(:base,"Email has already been taken")
398 self.errors.add(:base,"Email has already been taken")
396 end
399 end
397 end
400 end
398
401
399 def enough_time_interval_between_same_email_registrations
402 def enough_time_interval_between_same_email_registrations
400 return if !self.new_record?
403 return if !self.new_record?
401 return if self.activated
404 return if self.activated
402 open_user = User.find_by_email(self.email,
405 open_user = User.find_by_email(self.email,
403 :order => 'created_at DESC')
406 :order => 'created_at DESC')
404 if open_user and open_user.created_at and
407 if open_user and open_user.created_at and
405 (open_user.created_at > Time.now.gmtime - 5.minutes)
408 (open_user.created_at > Time.now.gmtime - 5.minutes)
406 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
409 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
407 end
410 end
408 end
411 end
409
412
410 def email_validation?
413 def email_validation?
411 begin
414 begin
412 return VALIDATE_USER_EMAILS
415 return VALIDATE_USER_EMAILS
413 rescue
416 rescue
414 return false
417 return false
415 end
418 end
416 end
419 end
417 end
420 end
@@ -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,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 - .form-group.field
9 + .col-md-6
10 - = f.label :name
10 + .form-group.field
11 - = f.text_field :name, class: 'form-control'
11 + = f.label :name
12 - .form-group.field
12 + = f.text_field :name, class: 'form-control'
13 - = f.label :description
13 + .row
14 - = f.text_field :description, class: 'form-control'
14 + .col-md-6
15 - .form-group.actions
15 + .form-group.field
16 - = f.submit 'Save', class: 'btn btn-primary'
16 + = f.label :description
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
26 + .form-group.actions
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
@@ -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,112 +1,113
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}
93 %tr
94 %tr
94 %td.text-right
95 %td.text-right
95 %strong Grading Task Status
96 %strong Grading Task Status
96 %td
97 %td
97 = @task.status_str if @task
98 = @task.status_str if @task
98 - if session[:admin]
99 - if session[:admin]
99 = link_to "rejudge", rejudge_submission_path, data: {remote: true}, class: 'btn btn-info btn-xs'
100 = link_to "rejudge", rejudge_submission_path, data: {remote: true}, class: 'btn btn-info btn-xs'
100
101
101
102
102 .modal.fade#compiler{tabindex: -1,role: 'dialog'}
103 .modal.fade#compiler{tabindex: -1,role: 'dialog'}
103 .modal-dialog.modal-lg{role:'document'}
104 .modal-dialog.modal-lg{role:'document'}
104 .modal-content
105 .modal-content
105 .modal-header
106 .modal-header
106 %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
107 %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
107 %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
108 %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
108 %h4 Compiler message
109 %h4 Compiler message
109 .modal-body
110 .modal-body
110 %pre#compiler_msg= @submission.compiler_message
111 %pre#compiler_msg= @submission.compiler_message
111 .modal-footer
112 .modal-footer
112 %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
113 %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
@@ -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
@@ -1,204 +1,204
1 Rails.application.routes.draw do
1 Rails.application.routes.draw do
2 resources :tags
2 resources :tags
3 get "sources/direct_edit"
3 get "sources/direct_edit"
4
4
5 root :to => 'main#login'
5 root :to => 'main#login'
6
6
7 #logins
7 #logins
8 match 'login/login', to: 'login#login', via: [:get,:post]
8 match 'login/login', to: 'login#login', via: [:get,:post]
9
9
10 resources :contests
10 resources :contests
11 resources :sites
11 resources :sites
12 resources :test
12 resources :test
13
13
14 resources :messages do
14 resources :messages do
15 member do
15 member do
16 get 'hide'
16 get 'hide'
17 post 'reply'
17 post 'reply'
18 end
18 end
19 collection do
19 collection do
20 get 'console'
20 get 'console'
21 get 'list_all'
21 get 'list_all'
22 end
22 end
23 end
23 end
24
24
25 resources :announcements do
25 resources :announcements do
26 member do
26 member do
27 get 'toggle','toggle_front'
27 get 'toggle','toggle_front'
28 end
28 end
29 end
29 end
30
30
31 resources :problems do
31 resources :problems do
32 member do
32 member do
33 get 'toggle'
33 get 'toggle'
34 get 'toggle_test'
34 get 'toggle_test'
35 get 'toggle_view_testcase'
35 get 'toggle_view_testcase'
36 get 'stat'
36 get 'stat'
37 end
37 end
38 collection do
38 collection do
39 get 'turn_all_off'
39 get 'turn_all_off'
40 get 'turn_all_on'
40 get 'turn_all_on'
41 get 'import'
41 get 'import'
42 get 'manage'
42 get 'manage'
43 get 'quick_create'
43 get 'quick_create'
44 post 'do_manage'
44 post 'do_manage'
45 post 'do_import'
45 post 'do_import'
46 end
46 end
47 end
47 end
48
48
49 resources :groups do
49 resources :groups do
50 member do
50 member do
51 post 'add_user', to: 'groups#add_user', as: 'add_user'
51 post 'add_user', to: 'groups#add_user', as: 'add_user'
52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
57 + get 'toggle'
57 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 get 'revoke_admin'
117 post 'grant_admin'
117 post 'grant_admin'
118 match 'create_from_list', via: [:get, :post]
118 match 'create_from_list', via: [:get, :post]
119 match 'random_all_passwords', via: [:get, :post]
119 match 'random_all_passwords', via: [:get, :post]
120 end
120 end
121 member do
121 member do
122 get 'clear_last_ip'
122 get 'clear_last_ip'
123 end
123 end
124 end
124 end
125
125
126 resources :contest_management, only: [:index] do
126 resources :contest_management, only: [:index] do
127 collection do
127 collection do
128 get 'user_stat'
128 get 'user_stat'
129 get 'clear_stat'
129 get 'clear_stat'
130 get 'clear_all_stat'
130 get 'clear_all_stat'
131 get 'change_contest_mode'
131 get 'change_contest_mode'
132 end
132 end
133 end
133 end
134
134
135 #get 'user_admin', to: 'user_admin#index'
135 #get 'user_admin', to: 'user_admin#index'
136 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
136 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
137 #post 'user_admin', to: 'user_admin#create'
137 #post 'user_admin', to: 'user_admin#create'
138 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
138 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
139
139
140 #singular resource
140 #singular resource
141 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
141 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
142 #report
142 #report
143 resource :report, only: [], controller: 'report' do
143 resource :report, only: [], controller: 'report' do
144 get 'login'
144 get 'login'
145 get 'multiple_login'
145 get 'multiple_login'
146 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
146 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
147 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
147 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
148 get 'max_score'
148 get 'max_score'
149 post 'show_max_score'
149 post 'show_max_score'
150 get 'stuck'
150 get 'stuck'
151 get 'cheat_report'
151 get 'cheat_report'
152 post 'cheat_report'
152 post 'cheat_report'
153 get 'cheat_scruntinize'
153 get 'cheat_scruntinize'
154 post 'cheat_scruntinize'
154 post 'cheat_scruntinize'
155 end
155 end
156 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
156 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
157 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
157 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
158 #get "report/login"
158 #get "report/login"
159 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
159 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
160 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
160 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
161
161
162 resource :main, only: [], controller: 'main' do
162 resource :main, only: [], controller: 'main' do
163 get 'login'
163 get 'login'
164 get 'logout'
164 get 'logout'
165 get 'list'
165 get 'list'
166 get 'submission(/:id)', action: 'submission', as: 'main_submission'
166 get 'submission(/:id)', action: 'submission', as: 'main_submission'
167 get 'announcements'
167 get 'announcements'
168 get 'help'
168 get 'help'
169 post 'submit'
169 post 'submit'
170 end
170 end
171 #main
171 #main
172 #get "main/list"
172 #get "main/list"
173 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
173 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
174 #post 'main/submit', to: 'main#submit'
174 #post 'main/submit', to: 'main#submit'
175 #get 'main/announcements', to: 'main#announcements'
175 #get 'main/announcements', to: 'main#announcements'
176
176
177
177
178 #
178 #
179 get 'tasks/view/:file.:ext' => 'tasks#view'
179 get 'tasks/view/:file.:ext' => 'tasks#view'
180 - get 'tasks/download/:id/:file.:ext' => 'tasks#download'
180 + get 'tasks/download/:id/:file.:ext' => 'tasks#download', as: 'download_task'
181 get 'heartbeat/:id/edit' => 'heartbeat#edit'
181 get 'heartbeat/:id/edit' => 'heartbeat#edit'
182
182
183 #grader
183 #grader
184 get 'graders/list', to: 'graders#list', as: 'grader_list'
184 get 'graders/list', to: 'graders#list', as: 'grader_list'
185 namespace :graders do
185 namespace :graders do
186 get 'task/:id/:type', action: 'task', as: 'task'
186 get 'task/:id/:type', action: 'task', as: 'task'
187 get 'view/:id/:type', action: 'view', as: 'view'
187 get 'view/:id/:type', action: 'view', as: 'view'
188 get 'clear/:id', action: 'clear', as: 'clear'
188 get 'clear/:id', action: 'clear', as: 'clear'
189 get 'stop'
189 get 'stop'
190 get 'stop_all'
190 get 'stop_all'
191 get 'clear_all'
191 get 'clear_all'
192 get 'clear_terminated'
192 get 'clear_terminated'
193 get 'start_grading'
193 get 'start_grading'
194 get 'start_exam'
194 get 'start_exam'
195
195
196 end
196 end
197
197
198
198
199 # See how all your routes lay out with "rake routes"
199 # See how all your routes lay out with "rake routes"
200
200
201 # This is a legacy wild controller route that's not recommended for RESTful applications.
201 # This is a legacy wild controller route that's not recommended for RESTful applications.
202 # Note: This route will make all actions in every controller accessible via GET requests.
202 # Note: This route will make all actions in every controller accessible via GET requests.
203 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
203 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
204 end
204 end
@@ -1,307 +1,308
1 # This file is auto-generated from the current state of the database. Instead
1 # This file is auto-generated from the current state of the database. Instead
2 # of editing this file, please use the migrations feature of Active Record to
2 # of editing this file, please use the migrations feature of Active Record to
3 # incrementally modify your database, and then regenerate this schema definition.
3 # incrementally modify your database, and then regenerate this schema definition.
4 #
4 #
5 # Note that this schema.rb definition is the authoritative source for your
5 # Note that this schema.rb definition is the authoritative source for your
6 # database schema. If you need to create the application database on another
6 # database schema. If you need to create the application database on another
7 # system, you should be using db:schema:load, not running all the migrations
7 # system, you should be using db:schema:load, not running all the migrations
8 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 #
10 #
11 # It's strongly recommended that you check this file into your version control system.
11 # It's strongly recommended that you check this file into your version control system.
12
12
13 - ActiveRecord::Schema.define(version: 2018_06_12_102327) do
13 + ActiveRecord::Schema.define(version: 2020_08_13_083020) do
14
14
15 - create_table "announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
15 + create_table "announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
16 t.string "author"
16 t.string "author"
17 t.text "body"
17 t.text "body"
18 t.boolean "published"
18 t.boolean "published"
19 - t.datetime "created_at"
19 + t.datetime "created_at", null: false
20 - t.datetime "updated_at"
20 + t.datetime "updated_at", null: false
21 t.boolean "frontpage", default: false
21 t.boolean "frontpage", default: false
22 t.boolean "contest_only", default: false
22 t.boolean "contest_only", default: false
23 t.string "title"
23 t.string "title"
24 t.string "notes"
24 t.string "notes"
25 end
25 end
26
26
27 - create_table "contests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
27 + create_table "contests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
28 t.string "title"
28 t.string "title"
29 t.boolean "enabled"
29 t.boolean "enabled"
30 - t.datetime "created_at"
30 + t.datetime "created_at", null: false
31 - t.datetime "updated_at"
31 + t.datetime "updated_at", null: false
32 t.string "name"
32 t.string "name"
33 end
33 end
34
34
35 - create_table "contests_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
35 + create_table "contests_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
36 t.integer "contest_id"
36 t.integer "contest_id"
37 t.integer "problem_id"
37 t.integer "problem_id"
38 end
38 end
39
39
40 - create_table "contests_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
40 + create_table "contests_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
41 t.integer "contest_id"
41 t.integer "contest_id"
42 t.integer "user_id"
42 t.integer "user_id"
43 end
43 end
44
44
45 - create_table "countries", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
45 + create_table "countries", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
46 t.string "name"
46 t.string "name"
47 - t.datetime "created_at"
47 + t.datetime "created_at", null: false
48 - t.datetime "updated_at"
48 + t.datetime "updated_at", null: false
49 end
49 end
50
50
51 - create_table "descriptions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
51 + create_table "descriptions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
52 t.text "body"
52 t.text "body"
53 t.boolean "markdowned"
53 t.boolean "markdowned"
54 - t.datetime "created_at"
54 + t.datetime "created_at", null: false
55 - t.datetime "updated_at"
55 + t.datetime "updated_at", null: false
56 end
56 end
57
57
58 - create_table "grader_configurations", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
58 + create_table "grader_configurations", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
59 t.string "key"
59 t.string "key"
60 t.string "value_type"
60 t.string "value_type"
61 t.string "value"
61 t.string "value"
62 - t.datetime "created_at"
62 + t.datetime "created_at", null: false
63 - t.datetime "updated_at"
63 + t.datetime "updated_at", null: false
64 t.text "description"
64 t.text "description"
65 end
65 end
66
66
67 - create_table "grader_processes", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
67 + create_table "grader_processes", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
68 t.string "host"
68 t.string "host"
69 t.integer "pid"
69 t.integer "pid"
70 t.string "mode"
70 t.string "mode"
71 t.boolean "active"
71 t.boolean "active"
72 - t.datetime "created_at"
72 + t.datetime "created_at", null: false
73 - t.datetime "updated_at"
73 + t.datetime "updated_at", null: false
74 t.integer "task_id"
74 t.integer "task_id"
75 t.string "task_type"
75 t.string "task_type"
76 t.boolean "terminated"
76 t.boolean "terminated"
77 - t.index ["host", "pid"], name: "index_grader_processes_on_host_and_pid"
77 + t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
78 end
78 end
79
79
80 create_table "groups", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
80 create_table "groups", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
81 t.string "name"
81 t.string "name"
82 t.string "description"
82 t.string "description"
83 + t.boolean "enabled", default: true
83 end
84 end
84
85
85 create_table "groups_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
86 create_table "groups_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
86 t.integer "problem_id", null: false
87 t.integer "problem_id", null: false
87 t.integer "group_id", null: false
88 t.integer "group_id", null: false
88 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
89 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
89 end
90 end
90
91
91 create_table "groups_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
92 create_table "groups_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
92 t.integer "group_id", null: false
93 t.integer "group_id", null: false
93 t.integer "user_id", null: false
94 t.integer "user_id", null: false
94 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
95 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
95 end
96 end
96
97
97 - create_table "heart_beats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
98 + create_table "heart_beats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
98 t.integer "user_id"
99 t.integer "user_id"
99 t.string "ip_address"
100 t.string "ip_address"
100 - t.datetime "created_at"
101 + t.datetime "created_at", null: false
101 - t.datetime "updated_at"
102 + t.datetime "updated_at", null: false
102 t.string "status"
103 t.string "status"
103 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
104 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
104 end
105 end
105
106
106 - create_table "languages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
107 + create_table "languages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
107 t.string "name", limit: 10
108 t.string "name", limit: 10
108 t.string "pretty_name"
109 t.string "pretty_name"
109 t.string "ext", limit: 10
110 t.string "ext", limit: 10
110 t.string "common_ext"
111 t.string "common_ext"
111 end
112 end
112
113
113 - create_table "logins", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
114 + create_table "logins", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
114 t.integer "user_id"
115 t.integer "user_id"
115 t.string "ip_address"
116 t.string "ip_address"
116 - t.datetime "created_at"
117 + t.datetime "created_at", null: false
117 - t.datetime "updated_at"
118 + t.datetime "updated_at", null: false
118 end
119 end
119
120
120 - create_table "messages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
121 + create_table "messages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
121 t.integer "sender_id"
122 t.integer "sender_id"
122 t.integer "receiver_id"
123 t.integer "receiver_id"
123 t.integer "replying_message_id"
124 t.integer "replying_message_id"
124 t.text "body"
125 t.text "body"
125 t.boolean "replied"
126 t.boolean "replied"
126 - t.datetime "created_at"
127 + t.datetime "created_at", null: false
127 - t.datetime "updated_at"
128 + t.datetime "updated_at", null: false
128 end
129 end
129
130
130 - create_table "problems", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
131 + create_table "problems", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
131 t.string "name", limit: 30
132 t.string "name", limit: 30
132 t.string "full_name"
133 t.string "full_name"
133 t.integer "full_score"
134 t.integer "full_score"
134 t.date "date_added"
135 t.date "date_added"
135 t.boolean "available"
136 t.boolean "available"
136 t.string "url"
137 t.string "url"
137 t.integer "description_id"
138 t.integer "description_id"
138 t.boolean "test_allowed"
139 t.boolean "test_allowed"
139 t.boolean "output_only"
140 t.boolean "output_only"
140 t.string "description_filename"
141 t.string "description_filename"
141 t.boolean "view_testcase"
142 t.boolean "view_testcase"
142 end
143 end
143
144
144 create_table "problems_tags", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
145 create_table "problems_tags", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
145 t.integer "problem_id"
146 t.integer "problem_id"
146 t.integer "tag_id"
147 t.integer "tag_id"
147 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
148 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
148 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
149 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
149 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
150 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
150 end
151 end
151
152
152 - create_table "rights", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
153 + create_table "rights", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
153 t.string "name"
154 t.string "name"
154 t.string "controller"
155 t.string "controller"
155 t.string "action"
156 t.string "action"
156 end
157 end
157
158
158 - create_table "rights_roles", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
159 + create_table "rights_roles", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
159 t.integer "right_id"
160 t.integer "right_id"
160 t.integer "role_id"
161 t.integer "role_id"
161 t.index ["role_id"], name: "index_rights_roles_on_role_id"
162 t.index ["role_id"], name: "index_rights_roles_on_role_id"
162 end
163 end
163
164
164 - create_table "roles", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
165 + create_table "roles", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
165 t.string "name"
166 t.string "name"
166 end
167 end
167
168
168 - create_table "roles_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
169 + create_table "roles_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
169 t.integer "role_id"
170 t.integer "role_id"
170 t.integer "user_id"
171 t.integer "user_id"
171 t.index ["user_id"], name: "index_roles_users_on_user_id"
172 t.index ["user_id"], name: "index_roles_users_on_user_id"
172 end
173 end
173
174
174 - create_table "sessions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
175 + create_table "sessions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
175 t.string "session_id"
176 t.string "session_id"
176 t.text "data"
177 t.text "data"
177 t.datetime "updated_at"
178 t.datetime "updated_at"
178 t.index ["session_id"], name: "index_sessions_on_session_id"
179 t.index ["session_id"], name: "index_sessions_on_session_id"
179 t.index ["updated_at"], name: "index_sessions_on_updated_at"
180 t.index ["updated_at"], name: "index_sessions_on_updated_at"
180 end
181 end
181
182
182 - create_table "sites", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
183 + create_table "sites", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
183 t.string "name"
184 t.string "name"
184 t.boolean "started"
185 t.boolean "started"
185 t.datetime "start_time"
186 t.datetime "start_time"
186 - t.datetime "created_at"
187 + t.datetime "created_at", null: false
187 - t.datetime "updated_at"
188 + t.datetime "updated_at", null: false
188 t.integer "country_id"
189 t.integer "country_id"
189 t.string "password"
190 t.string "password"
190 end
191 end
191
192
192 - create_table "submission_view_logs", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
193 + create_table "submission_view_logs", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
193 t.integer "user_id"
194 t.integer "user_id"
194 t.integer "submission_id"
195 t.integer "submission_id"
195 - t.datetime "created_at"
196 + t.datetime "created_at", null: false
196 - t.datetime "updated_at"
197 + t.datetime "updated_at", null: false
197 end
198 end
198
199
199 - create_table "submissions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
200 + create_table "submissions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
200 t.integer "user_id"
201 t.integer "user_id"
201 t.integer "problem_id"
202 t.integer "problem_id"
202 t.integer "language_id"
203 t.integer "language_id"
203 t.text "source", limit: 16777215
204 t.text "source", limit: 16777215
204 t.binary "binary"
205 t.binary "binary"
205 t.datetime "submitted_at"
206 t.datetime "submitted_at"
206 t.datetime "compiled_at"
207 t.datetime "compiled_at"
207 t.text "compiler_message"
208 t.text "compiler_message"
208 t.datetime "graded_at"
209 t.datetime "graded_at"
209 t.integer "points"
210 t.integer "points"
210 t.text "grader_comment"
211 t.text "grader_comment"
211 t.integer "number"
212 t.integer "number"
212 t.string "source_filename"
213 t.string "source_filename"
213 t.float "max_runtime"
214 t.float "max_runtime"
214 t.integer "peak_memory"
215 t.integer "peak_memory"
215 t.integer "effective_code_length"
216 t.integer "effective_code_length"
216 t.string "ip_address"
217 t.string "ip_address"
217 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
218 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
218 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
219 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
219 end
220 end
220
221
221 create_table "tags", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
222 create_table "tags", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
222 t.string "name", null: false
223 t.string "name", null: false
223 t.text "description"
224 t.text "description"
224 t.boolean "public"
225 t.boolean "public"
225 t.datetime "created_at", null: false
226 t.datetime "created_at", null: false
226 t.datetime "updated_at", null: false
227 t.datetime "updated_at", null: false
227 end
228 end
228
229
229 - create_table "tasks", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
230 + create_table "tasks", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
230 t.integer "submission_id"
231 t.integer "submission_id"
231 t.datetime "created_at"
232 t.datetime "created_at"
232 t.integer "status"
233 t.integer "status"
233 t.datetime "updated_at"
234 t.datetime "updated_at"
234 t.index ["submission_id"], name: "index_tasks_on_submission_id"
235 t.index ["submission_id"], name: "index_tasks_on_submission_id"
235 end
236 end
236
237
237 - create_table "test_pairs", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
238 + create_table "test_pairs", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
238 t.integer "problem_id"
239 t.integer "problem_id"
239 t.text "input", limit: 16777215
240 t.text "input", limit: 16777215
240 t.text "solution", limit: 16777215
241 t.text "solution", limit: 16777215
241 - t.datetime "created_at"
242 + t.datetime "created_at", null: false
242 - t.datetime "updated_at"
243 + t.datetime "updated_at", null: false
243 end
244 end
244
245
245 - create_table "test_requests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
246 + create_table "test_requests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
246 t.integer "user_id"
247 t.integer "user_id"
247 t.integer "problem_id"
248 t.integer "problem_id"
248 t.integer "submission_id"
249 t.integer "submission_id"
249 t.string "input_file_name"
250 t.string "input_file_name"
250 t.string "output_file_name"
251 t.string "output_file_name"
251 t.string "running_stat"
252 t.string "running_stat"
252 t.integer "status"
253 t.integer "status"
253 - t.datetime "updated_at"
254 + t.datetime "updated_at", null: false
254 t.datetime "submitted_at"
255 t.datetime "submitted_at"
255 t.datetime "compiled_at"
256 t.datetime "compiled_at"
256 t.text "compiler_message"
257 t.text "compiler_message"
257 t.datetime "graded_at"
258 t.datetime "graded_at"
258 t.string "grader_comment"
259 t.string "grader_comment"
259 - t.datetime "created_at"
260 + t.datetime "created_at", null: false
260 t.float "running_time"
261 t.float "running_time"
261 t.string "exit_status"
262 t.string "exit_status"
262 t.integer "memory_usage"
263 t.integer "memory_usage"
263 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
264 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
264 end
265 end
265
266
266 create_table "testcases", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
267 create_table "testcases", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
267 t.integer "problem_id"
268 t.integer "problem_id"
268 t.integer "num"
269 t.integer "num"
269 t.integer "group"
270 t.integer "group"
270 t.integer "score"
271 t.integer "score"
271 t.text "input", limit: 4294967295
272 t.text "input", limit: 4294967295
272 t.text "sol", limit: 4294967295
273 t.text "sol", limit: 4294967295
273 t.datetime "created_at"
274 t.datetime "created_at"
274 t.datetime "updated_at"
275 t.datetime "updated_at"
275 t.index ["problem_id"], name: "index_testcases_on_problem_id"
276 t.index ["problem_id"], name: "index_testcases_on_problem_id"
276 end
277 end
277
278
278 - create_table "user_contest_stats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
279 + create_table "user_contest_stats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
279 t.integer "user_id"
280 t.integer "user_id"
280 t.datetime "started_at"
281 t.datetime "started_at"
281 - t.datetime "created_at"
282 + t.datetime "created_at", null: false
282 - t.datetime "updated_at"
283 + t.datetime "updated_at", null: false
283 t.boolean "forced_logout"
284 t.boolean "forced_logout"
284 end
285 end
285
286
286 - create_table "users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
287 + create_table "users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
287 t.string "login", limit: 50
288 t.string "login", limit: 50
288 t.string "full_name"
289 t.string "full_name"
289 t.string "hashed_password"
290 t.string "hashed_password"
290 t.string "salt", limit: 5
291 t.string "salt", limit: 5
291 t.string "alias"
292 t.string "alias"
292 t.string "email"
293 t.string "email"
293 t.integer "site_id"
294 t.integer "site_id"
294 t.integer "country_id"
295 t.integer "country_id"
295 t.boolean "activated", default: false
296 t.boolean "activated", default: false
296 t.datetime "created_at"
297 t.datetime "created_at"
297 t.datetime "updated_at"
298 t.datetime "updated_at"
298 - t.string "section"
299 t.boolean "enabled", default: true
299 t.boolean "enabled", default: true
300 t.string "remark"
300 t.string "remark"
301 t.string "last_ip"
301 t.string "last_ip"
302 + t.string "section"
302 t.index ["login"], name: "index_users_on_login", unique: true
303 t.index ["login"], name: "index_users_on_login", unique: true
303 end
304 end
304
305
305 add_foreign_key "problems_tags", "problems"
306 add_foreign_key "problems_tags", "problems"
306 add_foreign_key "problems_tags", "tags"
307 add_foreign_key "problems_tags", "tags"
307 end
308 end
You need to be logged in to leave comments. Login now