Description:
Merge pull request #23 from nattee/master some bug fix
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r768:f22301d0d070 - - 7 files changed: 12 inserted, 5 deleted

@@ -0,0 +1,5
1 + class ChangeSubmissionSourceSize < ActiveRecord::Migration
2 + def change
3 + change_column :submissions, :source, :text, :limit => 1.megabyte
4 + end
5 + end
@@ -1,310 +1,310
1 class ProblemsController < ApplicationController
1 class ProblemsController < ApplicationController
2
2
3 before_action :authenticate, :authorization
3 before_action :authenticate, :authorization
4 before_action :testcase_authorization, only: [:show_testcase]
4 before_action :testcase_authorization, only: [:show_testcase]
5
5
6 in_place_edit_for :problem, :name
6 in_place_edit_for :problem, :name
7 in_place_edit_for :problem, :full_name
7 in_place_edit_for :problem, :full_name
8 in_place_edit_for :problem, :full_score
8 in_place_edit_for :problem, :full_score
9
9
10 def index
10 def index
11 @problems = Problem.order(date_added: :desc)
11 @problems = Problem.order(date_added: :desc)
12 end
12 end
13
13
14 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
14 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
15 verify :method => :post, :only => [ :create, :quick_create,
15 verify :method => :post, :only => [ :create, :quick_create,
16 :do_manage,
16 :do_manage,
17 :do_import,
17 :do_import,
18 ],
18 ],
19 :redirect_to => { :action => :index }
19 :redirect_to => { :action => :index }
20
20
21 def show
21 def show
22 @problem = Problem.find(params[:id])
22 @problem = Problem.find(params[:id])
23 end
23 end
24
24
25 def new
25 def new
26 @problem = Problem.new
26 @problem = Problem.new
27 @description = nil
27 @description = nil
28 end
28 end
29
29
30 def create
30 def create
31 @problem = Problem.new(problem_params)
31 @problem = Problem.new(problem_params)
32 @description = Description.new(params[:description])
32 @description = Description.new(params[:description])
33 if @description.body!=''
33 if @description.body!=''
34 if !@description.save
34 if !@description.save
35 render :action => new and return
35 render :action => new and return
36 end
36 end
37 else
37 else
38 @description = nil
38 @description = nil
39 end
39 end
40 @problem.description = @description
40 @problem.description = @description
41 if @problem.save
41 if @problem.save
42 flash[:notice] = 'Problem was successfully created.'
42 flash[:notice] = 'Problem was successfully created.'
43 redirect_to action: :index
43 redirect_to action: :index
44 else
44 else
45 render :action => 'new'
45 render :action => 'new'
46 end
46 end
47 end
47 end
48
48
49 def quick_create
49 def quick_create
50 @problem = Problem.new(problem_params)
50 @problem = Problem.new(problem_params)
51 @problem.full_name = @problem.name if @problem.full_name == ''
51 @problem.full_name = @problem.name if @problem.full_name == ''
52 @problem.full_score = 100
52 @problem.full_score = 100
53 @problem.available = false
53 @problem.available = false
54 @problem.test_allowed = true
54 @problem.test_allowed = true
55 @problem.output_only = false
55 @problem.output_only = false
56 @problem.date_added = Time.new
56 @problem.date_added = Time.new
57 if @problem.save
57 if @problem.save
58 flash[:notice] = 'Problem was successfully created.'
58 flash[:notice] = 'Problem was successfully created.'
59 redirect_to action: :index
59 redirect_to action: :index
60 else
60 else
61 flash[:notice] = 'Error saving problem'
61 flash[:notice] = 'Error saving problem'
62 redirect_to action: :index
62 redirect_to action: :index
63 end
63 end
64 end
64 end
65
65
66 def edit
66 def edit
67 @problem = Problem.find(params[:id])
67 @problem = Problem.find(params[:id])
68 @description = @problem.description
68 @description = @problem.description
69 end
69 end
70
70
71 def update
71 def update
72 @problem = Problem.find(params[:id])
72 @problem = Problem.find(params[:id])
73 @description = @problem.description
73 @description = @problem.description
74 if @description.nil? and params[:description][:body]!=''
74 if @description.nil? and params[:description][:body]!=''
75 @description = Description.new(params[:description])
75 @description = Description.new(params[:description])
76 if !@description.save
76 if !@description.save
77 flash[:notice] = 'Error saving description'
77 flash[:notice] = 'Error saving description'
78 render :action => 'edit' and return
78 render :action => 'edit' and return
79 end
79 end
80 @problem.description = @description
80 @problem.description = @description
81 elsif @description
81 elsif @description
82 if !@description.update_attributes(params[:description])
82 if !@description.update_attributes(params[:description])
83 flash[:notice] = 'Error saving description'
83 flash[:notice] = 'Error saving description'
84 render :action => 'edit' and return
84 render :action => 'edit' and return
85 end
85 end
86 end
86 end
87 if params[:file] and params[:file].content_type != 'application/pdf'
87 if params[:file] and params[:file].content_type != 'application/pdf'
88 flash[:notice] = 'Error: Uploaded file is not PDF'
88 flash[:notice] = 'Error: Uploaded file is not PDF'
89 render :action => 'edit' and return
89 render :action => 'edit' and return
90 end
90 end
91 if @problem.update_attributes(problem_params)
91 if @problem.update_attributes(problem_params)
92 flash[:notice] = 'Problem was successfully updated.'
92 flash[:notice] = 'Problem was successfully updated.'
93 unless params[:file] == nil or params[:file] == ''
93 unless params[:file] == nil or params[:file] == ''
94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
96 if not FileTest.exists? out_dirname
96 if not FileTest.exists? out_dirname
97 Dir.mkdir out_dirname
97 Dir.mkdir out_dirname
98 end
98 end
99
99
100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
101 if FileTest.exists? out_filename
101 if FileTest.exists? out_filename
102 File.delete out_filename
102 File.delete out_filename
103 end
103 end
104
104
105 File.open(out_filename,"wb") do |file|
105 File.open(out_filename,"wb") do |file|
106 file.write(params[:file].read)
106 file.write(params[:file].read)
107 end
107 end
108 @problem.description_filename = "#{@problem.name}.pdf"
108 @problem.description_filename = "#{@problem.name}.pdf"
109 @problem.save
109 @problem.save
110 end
110 end
111 redirect_to :action => 'show', :id => @problem
111 redirect_to :action => 'show', :id => @problem
112 else
112 else
113 render :action => 'edit'
113 render :action => 'edit'
114 end
114 end
115 end
115 end
116
116
117 def destroy
117 def destroy
118 p = Problem.find(params[:id]).destroy
118 p = Problem.find(params[:id]).destroy
119 redirect_to action: :index
119 redirect_to action: :index
120 end
120 end
121
121
122 def toggle
122 def toggle
123 @problem = Problem.find(params[:id])
123 @problem = Problem.find(params[:id])
124 @problem.update_attributes(available: !(@problem.available) )
124 @problem.update_attributes(available: !(@problem.available) )
125 respond_to do |format|
125 respond_to do |format|
126 format.js { }
126 format.js { }
127 end
127 end
128 end
128 end
129
129
130 def toggle_test
130 def toggle_test
131 @problem = Problem.find(params[:id])
131 @problem = Problem.find(params[:id])
132 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
132 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
133 respond_to do |format|
133 respond_to do |format|
134 format.js { }
134 format.js { }
135 end
135 end
136 end
136 end
137
137
138 def toggle_view_testcase
138 def toggle_view_testcase
139 @problem = Problem.find(params[:id])
139 @problem = Problem.find(params[:id])
140 @problem.update_attributes(view_testcase: !(@problem.view_testcase?) )
140 @problem.update_attributes(view_testcase: !(@problem.view_testcase?) )
141 respond_to do |format|
141 respond_to do |format|
142 format.js { }
142 format.js { }
143 end
143 end
144 end
144 end
145
145
146 def turn_all_off
146 def turn_all_off
147 Problem.available.all.each do |problem|
147 Problem.available.all.each do |problem|
148 problem.available = false
148 problem.available = false
149 problem.save
149 problem.save
150 end
150 end
151 redirect_to action: :index
151 redirect_to action: :index
152 end
152 end
153
153
154 def turn_all_on
154 def turn_all_on
155 Problem.where.not(available: true).each do |problem|
155 Problem.where.not(available: true).each do |problem|
156 problem.available = true
156 problem.available = true
157 problem.save
157 problem.save
158 end
158 end
159 redirect_to action: :index
159 redirect_to action: :index
160 end
160 end
161
161
162 def stat
162 def stat
163 @problem = Problem.find(params[:id])
163 @problem = Problem.find(params[:id])
164 unless @problem.available or session[:admin]
164 unless @problem.available or session[:admin]
165 redirect_to :controller => 'main', :action => 'list'
165 redirect_to :controller => 'main', :action => 'list'
166 return
166 return
167 end
167 end
168 @submissions = Submission.includes(:user).includes(:language).where(problem_id: params[:id]).order(:user_id,:id)
168 @submissions = Submission.includes(:user).includes(:language).where(problem_id: params[:id]).order(:user_id,:id)
169
169
170 #stat summary
170 #stat summary
171 range =65
171 range =65
172 @histogram = { data: Array.new(range,0), summary: {} }
172 @histogram = { data: Array.new(range,0), summary: {} }
173 user = Hash.new(0)
173 user = Hash.new(0)
174 @submissions.find_each do |sub|
174 @submissions.find_each do |sub|
175 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
175 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
176 @histogram[:data][d.to_i] += 1 if d < range
176 @histogram[:data][d.to_i] += 1 if d < range
177 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
177 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
178 end
178 end
179 @histogram[:summary][:max] = [@histogram[:data].max,1].max
179 @histogram[:summary][:max] = [@histogram[:data].max,1].max
180
180
181 @summary = { attempt: user.count, solve: 0 }
181 @summary = { attempt: user.count, solve: 0 }
182 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
182 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
183 end
183 end
184
184
185 def manage
185 def manage
186 @problems = Problem.order(date_added: :desc)
186 @problems = Problem.order(date_added: :desc)
187 end
187 end
188
188
189 def do_manage
189 def do_manage
190 - if params.has_key? 'change_date_added'
190 + if params.has_key? 'change_date_added' and params[:date_added].strip.empty? == false
191 change_date_added
191 change_date_added
192 elsif params.has_key? 'add_to_contest'
192 elsif params.has_key? 'add_to_contest'
193 add_to_contest
193 add_to_contest
194 elsif params.has_key? 'enable_problem'
194 elsif params.has_key? 'enable_problem'
195 set_available(true)
195 set_available(true)
196 elsif params.has_key? 'disable_problem'
196 elsif params.has_key? 'disable_problem'
197 set_available(false)
197 set_available(false)
198 elsif params.has_key? 'add_group'
198 elsif params.has_key? 'add_group'
199 group = Group.find(params[:group_id])
199 group = Group.find(params[:group_id])
200 ok = []
200 ok = []
201 failed = []
201 failed = []
202 get_problems_from_params.each do |p|
202 get_problems_from_params.each do |p|
203 begin
203 begin
204 group.problems << p
204 group.problems << p
205 ok << p.full_name
205 ok << p.full_name
206 rescue => e
206 rescue => e
207 failed << p.full_name
207 failed << p.full_name
208 end
208 end
209 end
209 end
210 flash[:success] = "The following problems are added to the group #{group.name}: " + ok.join(', ') if ok.count > 0
210 flash[:success] = "The following problems are added to the group #{group.name}: " + ok.join(', ') if ok.count > 0
211 flash[:alert] = "The following problems are already in the group #{group.name}: " + failed.join(', ') if failed.count > 0
211 flash[:alert] = "The following problems are already in the group #{group.name}: " + failed.join(', ') if failed.count > 0
212 elsif params.has_key? 'add_tags'
212 elsif params.has_key? 'add_tags'
213 get_problems_from_params.each do |p|
213 get_problems_from_params.each do |p|
214 p.tag_ids += params[:tag_ids]
214 p.tag_ids += params[:tag_ids]
215 end
215 end
216 end
216 end
217
217
218 redirect_to :action => 'manage'
218 redirect_to :action => 'manage'
219 end
219 end
220
220
221 def import
221 def import
222 @allow_test_pair_import = allow_test_pair_import?
222 @allow_test_pair_import = allow_test_pair_import?
223 end
223 end
224
224
225 def do_import
225 def do_import
226 old_problem = Problem.find_by_name(params[:name])
226 old_problem = Problem.find_by_name(params[:name])
227 if !allow_test_pair_import? and params.has_key? :import_to_db
227 if !allow_test_pair_import? and params.has_key? :import_to_db
228 params.delete :import_to_db
228 params.delete :import_to_db
229 end
229 end
230 @problem, import_log = Problem.create_from_import_form_params(params,
230 @problem, import_log = Problem.create_from_import_form_params(params,
231 old_problem)
231 old_problem)
232
232
233 if !@problem.errors.empty?
233 if !@problem.errors.empty?
234 render :action => 'import' and return
234 render :action => 'import' and return
235 end
235 end
236
236
237 if old_problem!=nil
237 if old_problem!=nil
238 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
238 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
239 end
239 end
240 @log = import_log
240 @log = import_log
241 end
241 end
242
242
243 def remove_contest
243 def remove_contest
244 problem = Problem.find(params[:id])
244 problem = Problem.find(params[:id])
245 contest = Contest.find(params[:contest_id])
245 contest = Contest.find(params[:contest_id])
246 if problem!=nil and contest!=nil
246 if problem!=nil and contest!=nil
247 problem.contests.delete(contest)
247 problem.contests.delete(contest)
248 end
248 end
249 redirect_to :action => 'manage'
249 redirect_to :action => 'manage'
250 end
250 end
251
251
252 ##################################
252 ##################################
253 protected
253 protected
254
254
255 def allow_test_pair_import?
255 def allow_test_pair_import?
256 if defined? ALLOW_TEST_PAIR_IMPORT
256 if defined? ALLOW_TEST_PAIR_IMPORT
257 return ALLOW_TEST_PAIR_IMPORT
257 return ALLOW_TEST_PAIR_IMPORT
258 else
258 else
259 return false
259 return false
260 end
260 end
261 end
261 end
262
262
263 def change_date_added
263 def change_date_added
264 problems = get_problems_from_params
264 problems = get_problems_from_params
265 date = Date.parse(params[:date_added])
265 date = Date.parse(params[:date_added])
266 problems.each do |p|
266 problems.each do |p|
267 p.date_added = date
267 p.date_added = date
268 p.save
268 p.save
269 end
269 end
270 end
270 end
271
271
272 def add_to_contest
272 def add_to_contest
273 problems = get_problems_from_params
273 problems = get_problems_from_params
274 contest = Contest.find(params[:contest][:id])
274 contest = Contest.find(params[:contest][:id])
275 if contest!=nil and contest.enabled
275 if contest!=nil and contest.enabled
276 problems.each do |p|
276 problems.each do |p|
277 p.contests << contest
277 p.contests << contest
278 end
278 end
279 end
279 end
280 end
280 end
281
281
282 def set_available(avail)
282 def set_available(avail)
283 problems = get_problems_from_params
283 problems = get_problems_from_params
284 problems.each do |p|
284 problems.each do |p|
285 p.available = avail
285 p.available = avail
286 p.save
286 p.save
287 end
287 end
288 end
288 end
289
289
290 def get_problems_from_params
290 def get_problems_from_params
291 problems = []
291 problems = []
292 params.keys.each do |k|
292 params.keys.each do |k|
293 if k.index('prob-')==0
293 if k.index('prob-')==0
294 name, id, order = k.split('-')
294 name, id, order = k.split('-')
295 problems << Problem.find(id)
295 problems << Problem.find(id)
296 end
296 end
297 end
297 end
298 problems
298 problems
299 end
299 end
300
300
301 def get_problems_stat
301 def get_problems_stat
302 end
302 end
303
303
304 private
304 private
305
305
306 def problem_params
306 def problem_params
307 params.require(:problem).permit(:name, :full_name, :full_score, :date_added, :available, :test_allowed,:output_only, :url, :description, tag_ids:[])
307 params.require(:problem).permit(:name, :full_name, :full_score, :date_added, :available, :test_allowed,:output_only, :url, :description, tag_ids:[])
308 end
308 end
309
309
310 end
310 end
@@ -1,238 +1,238
1 require 'csv'
1 require 'csv'
2
2
3 class ReportController < ApplicationController
3 class ReportController < ApplicationController
4
4
5 before_filter :authenticate
5 before_filter :authenticate
6
6
7 before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score, :current_score]
7 before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score, :current_score]
8
8
9 before_filter(only: [:problem_hof]) { |c|
9 before_filter(only: [:problem_hof]) { |c|
10 return false unless authenticate
10 return false unless authenticate
11
11
12 admin_authorization unless GraderConfiguration["right.user_view_submission"]
12 admin_authorization unless GraderConfiguration["right.user_view_submission"]
13 }
13 }
14
14
15 def max_score
15 def max_score
16 end
16 end
17
17
18 def current_score
18 def current_score
19 @problems = Problem.available_problems
19 @problems = Problem.available_problems
20 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
20 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
21 @scorearray = calculate_max_score(@problems, @users,0,0,true)
21 @scorearray = calculate_max_score(@problems, @users,0,0,true)
22
22
23 #rencer accordingly
23 #rencer accordingly
24 if params[:button] == 'download' then
24 if params[:button] == 'download' then
25 csv = gen_csv_from_scorearray(@scorearray,@problems)
25 csv = gen_csv_from_scorearray(@scorearray,@problems)
26 send_data csv, filename: 'max_score.csv'
26 send_data csv, filename: 'max_score.csv'
27 else
27 else
28 #render template: 'user_admin/user_stat'
28 #render template: 'user_admin/user_stat'
29 render 'current_score'
29 render 'current_score'
30 end
30 end
31 end
31 end
32
32
33 def show_max_score
33 def show_max_score
34 #process parameters
34 #process parameters
35 #problems
35 #problems
36 @problems = []
36 @problems = []
37 if params[:problem_id]
37 if params[:problem_id]
38 params[:problem_id].each do |id|
38 params[:problem_id].each do |id|
39 next unless id.strip != ""
39 next unless id.strip != ""
40 pid = Problem.find_by_id(id.to_i)
40 pid = Problem.find_by_id(id.to_i)
41 @problems << pid if pid
41 @problems << pid if pid
42 end
42 end
43 end
43 end
44
44
45 #users
45 #users
46 - @users = if params[:user] == "all" then
46 + @users = if params[:users] == "all" then
47 User.includes(:contests).includes(:contest_stat)
47 User.includes(:contests).includes(:contest_stat)
48 else
48 else
49 User.includes(:contests).includes(:contest_stat).where(enabled: true)
49 User.includes(:contests).includes(:contest_stat).where(enabled: true)
50 end
50 end
51
51
52 #set up range from param
52 #set up range from param
53 @since_id = params.fetch(:from_id, 0).to_i
53 @since_id = params.fetch(:from_id, 0).to_i
54 @until_id = params.fetch(:to_id, 0).to_i
54 @until_id = params.fetch(:to_id, 0).to_i
55 @since_id = nil if @since_id == 0
55 @since_id = nil if @since_id == 0
56 @until_id = nil if @until_id == 0
56 @until_id = nil if @until_id == 0
57
57
58 #calculate the routine
58 #calculate the routine
59 @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
59 @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
60
60
61 #rencer accordingly
61 #rencer accordingly
62 if params[:button] == 'download' then
62 if params[:button] == 'download' then
63 csv = gen_csv_from_scorearray(@scorearray,@problems)
63 csv = gen_csv_from_scorearray(@scorearray,@problems)
64 send_data csv, filename: 'max_score.csv'
64 send_data csv, filename: 'max_score.csv'
65 else
65 else
66 #render template: 'user_admin/user_stat'
66 #render template: 'user_admin/user_stat'
67 render 'max_score'
67 render 'max_score'
68 end
68 end
69
69
70 end
70 end
71
71
72 def score
72 def score
73 if params[:commit] == 'download csv'
73 if params[:commit] == 'download csv'
74 @problems = Problem.all
74 @problems = Problem.all
75 else
75 else
76 @problems = Problem.available_problems
76 @problems = Problem.available_problems
77 end
77 end
78 @users = User.includes(:contests, :contest_stat).where(enabled: true)
78 @users = User.includes(:contests, :contest_stat).where(enabled: true)
79 @scorearray = Array.new
79 @scorearray = Array.new
80 @users.each do |u|
80 @users.each do |u|
81 ustat = Array.new
81 ustat = Array.new
82 ustat[0] = u
82 ustat[0] = u
83 @problems.each do |p|
83 @problems.each do |p|
84 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
84 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
85 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
85 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
86 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
86 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
87 else
87 else
88 ustat << [0,false]
88 ustat << [0,false]
89 end
89 end
90 end
90 end
91 @scorearray << ustat
91 @scorearray << ustat
92 end
92 end
93 if params[:commit] == 'download csv' then
93 if params[:commit] == 'download csv' then
94 csv = gen_csv_from_scorearray(@scorearray,@problems)
94 csv = gen_csv_from_scorearray(@scorearray,@problems)
95 send_data csv, filename: 'last_score.csv'
95 send_data csv, filename: 'last_score.csv'
96 else
96 else
97 render template: 'user_admin/user_stat'
97 render template: 'user_admin/user_stat'
98 end
98 end
99
99
100 end
100 end
101
101
102 def login_stat
102 def login_stat
103 @logins = Array.new
103 @logins = Array.new
104
104
105 date_and_time = '%Y-%m-%d %H:%M'
105 date_and_time = '%Y-%m-%d %H:%M'
106 begin
106 begin
107 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
107 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
108 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
108 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
109 rescue
109 rescue
110 @since_time = DateTime.new(1000,1,1)
110 @since_time = DateTime.new(1000,1,1)
111 end
111 end
112 begin
112 begin
113 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
113 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
114 @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
114 @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
115 rescue
115 rescue
116 @until_time = DateTime.new(3000,1,1)
116 @until_time = DateTime.new(3000,1,1)
117 end
117 end
118
118
119 User.all.each do |user|
119 User.all.each do |user|
120 @logins << { id: user.id,
120 @logins << { id: user.id,
121 login: user.login,
121 login: user.login,
122 full_name: user.full_name,
122 full_name: user.full_name,
123 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
123 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
124 user.id,@since_time,@until_time)
124 user.id,@since_time,@until_time)
125 .count(:id),
125 .count(:id),
126 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
126 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
127 user.id,@since_time,@until_time)
127 user.id,@since_time,@until_time)
128 .minimum(:created_at),
128 .minimum(:created_at),
129 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
129 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
130 user.id,@since_time,@until_time)
130 user.id,@since_time,@until_time)
131 .maximum(:created_at),
131 .maximum(:created_at),
132 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
132 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
133 user.id,@since_time,@until_time)
133 user.id,@since_time,@until_time)
134 .select(:ip_address).uniq
134 .select(:ip_address).uniq
135
135
136 }
136 }
137 end
137 end
138 end
138 end
139
139
140 def submission_stat
140 def submission_stat
141
141
142 date_and_time = '%Y-%m-%d %H:%M'
142 date_and_time = '%Y-%m-%d %H:%M'
143 begin
143 begin
144 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
144 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
145 rescue
145 rescue
146 @since_time = DateTime.new(1000,1,1)
146 @since_time = DateTime.new(1000,1,1)
147 end
147 end
148 begin
148 begin
149 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
149 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
150 rescue
150 rescue
151 @until_time = DateTime.new(3000,1,1)
151 @until_time = DateTime.new(3000,1,1)
152 end
152 end
153
153
154 @submissions = {}
154 @submissions = {}
155
155
156 User.find_each do |user|
156 User.find_each do |user|
157 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
157 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
158 end
158 end
159
159
160 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
160 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
161 if @submissions[s.user_id]
161 if @submissions[s.user_id]
162 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
162 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
163 a = Problem.find_by_id(s.problem_id)
163 a = Problem.find_by_id(s.problem_id)
164 @submissions[s.user_id][:sub][s.problem_id] =
164 @submissions[s.user_id][:sub][s.problem_id] =
165 { prob_name: (a ? a.full_name : '(NULL)'),
165 { prob_name: (a ? a.full_name : '(NULL)'),
166 sub_ids: [s.id] }
166 sub_ids: [s.id] }
167 else
167 else
168 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
168 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
169 end
169 end
170 @submissions[s.user_id][:count] += 1
170 @submissions[s.user_id][:count] += 1
171 end
171 end
172 end
172 end
173 end
173 end
174
174
175 def problem_hof
175 def problem_hof
176 # gen problem list
176 # gen problem list
177 @user = User.find(session[:user_id])
177 @user = User.find(session[:user_id])
178 @problems = @user.available_problems
178 @problems = @user.available_problems
179
179
180 # get selected problems or the default
180 # get selected problems or the default
181 if params[:id]
181 if params[:id]
182 begin
182 begin
183 @problem = Problem.available.find(params[:id])
183 @problem = Problem.available.find(params[:id])
184 rescue
184 rescue
185 redirect_to action: :problem_hof
185 redirect_to action: :problem_hof
186 flash[:notice] = 'Error: submissions for that problem are not viewable.'
186 flash[:notice] = 'Error: submissions for that problem are not viewable.'
187 return
187 return
188 end
188 end
189 end
189 end
190
190
191 return unless @problem
191 return unless @problem
192
192
193 @by_lang = {} #aggregrate by language
193 @by_lang = {} #aggregrate by language
194
194
195 range =65
195 range =65
196 @histogram = { data: Array.new(range,0), summary: {} }
196 @histogram = { data: Array.new(range,0), summary: {} }
197 @summary = {count: 0, solve: 0, attempt: 0}
197 @summary = {count: 0, solve: 0, attempt: 0}
198 user = Hash.new(0)
198 user = Hash.new(0)
199 Submission.where(problem_id: @problem.id).find_each do |sub|
199 Submission.where(problem_id: @problem.id).find_each do |sub|
200 #histogram
200 #histogram
201 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
201 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
202 @histogram[:data][d.to_i] += 1 if d < range
202 @histogram[:data][d.to_i] += 1 if d < range
203
203
204 next unless sub.points
204 next unless sub.points
205 @summary[:count] += 1
205 @summary[:count] += 1
206 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
206 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
207
207
208 lang = Language.find_by_id(sub.language_id)
208 lang = Language.find_by_id(sub.language_id)
209 next unless lang
209 next unless lang
210 next unless sub.points >= @problem.full_score
210 next unless sub.points >= @problem.full_score
211
211
212 #initialize
212 #initialize
213 unless @by_lang.has_key?(lang.pretty_name)
213 unless @by_lang.has_key?(lang.pretty_name)
214 @by_lang[lang.pretty_name] = {
214 @by_lang[lang.pretty_name] = {
215 runtime: { avail: false, value: 2**30-1 },
215 runtime: { avail: false, value: 2**30-1 },
216 memory: { avail: false, value: 2**30-1 },
216 memory: { avail: false, value: 2**30-1 },
217 length: { avail: false, value: 2**30-1 },
217 length: { avail: false, value: 2**30-1 },
218 first: { avail: false, value: DateTime.new(3000,1,1) }
218 first: { avail: false, value: DateTime.new(3000,1,1) }
219 }
219 }
220 end
220 end
221
221
222 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
222 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
223 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
223 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
224 end
224 end
225
225
226 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
226 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
227 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
227 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
228 end
228 end
229
229
230 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and sub.user and
230 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and sub.user and
231 !sub.user.admin?
231 !sub.user.admin?
232 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
232 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
233 end
233 end
234
234
235 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
235 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
236 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
236 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
237 end
237 end
238 end
238 end
@@ -1,166 +1,166
1 class Submission < ActiveRecord::Base
1 class Submission < ActiveRecord::Base
2
2
3 belongs_to :language
3 belongs_to :language
4 belongs_to :problem
4 belongs_to :problem
5 belongs_to :user
5 belongs_to :user
6
6
7 before_validation :assign_problem
7 before_validation :assign_problem
8 before_validation :assign_language
8 before_validation :assign_language
9
9
10 validates_presence_of :source
10 validates_presence_of :source
11 - validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'too long'
11 + validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'code too long, the limit is 100,000 bytes'
12 validates_length_of :source, :minimum => 1, :allow_blank => true, :message => 'too short'
12 validates_length_of :source, :minimum => 1, :allow_blank => true, :message => 'too short'
13 validate :must_have_valid_problem
13 validate :must_have_valid_problem
14 validate :must_specify_language
14 validate :must_specify_language
15
15
16 has_one :task
16 has_one :task
17
17
18 before_save :assign_latest_number_if_new_recond
18 before_save :assign_latest_number_if_new_recond
19
19
20 def self.find_last_by_user_and_problem(user_id, problem_id)
20 def self.find_last_by_user_and_problem(user_id, problem_id)
21 where("user_id = ? AND problem_id = ?",user_id,problem_id).last
21 where("user_id = ? AND problem_id = ?",user_id,problem_id).last
22 end
22 end
23
23
24 def self.find_all_last_by_problem(problem_id)
24 def self.find_all_last_by_problem(problem_id)
25 # need to put in SQL command, maybe there's a better way
25 # need to put in SQL command, maybe there's a better way
26 Submission.includes(:user).find_by_sql("SELECT * FROM submissions " +
26 Submission.includes(:user).find_by_sql("SELECT * FROM submissions " +
27 "WHERE id = " +
27 "WHERE id = " +
28 "(SELECT MAX(id) FROM submissions AS subs " +
28 "(SELECT MAX(id) FROM submissions AS subs " +
29 "WHERE subs.user_id = submissions.user_id AND " +
29 "WHERE subs.user_id = submissions.user_id AND " +
30 "problem_id = " + problem_id.to_s + " " +
30 "problem_id = " + problem_id.to_s + " " +
31 "GROUP BY user_id) " +
31 "GROUP BY user_id) " +
32 "ORDER BY user_id")
32 "ORDER BY user_id")
33 end
33 end
34
34
35 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
35 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
36 records = Submission.where(problem_id: problem_id,user_id: user_id)
36 records = Submission.where(problem_id: problem_id,user_id: user_id)
37 records = records.where('id >= ?',since_id) if since_id and since_id > 0
37 records = records.where('id >= ?',since_id) if since_id and since_id > 0
38 records = records.where('id <= ?',until_id) if until_id and until_id > 0
38 records = records.where('id <= ?',until_id) if until_id and until_id > 0
39 records.all
39 records.all
40 end
40 end
41
41
42 def self.find_last_for_all_available_problems(user_id)
42 def self.find_last_for_all_available_problems(user_id)
43 submissions = Array.new
43 submissions = Array.new
44 problems = Problem.available_problems
44 problems = Problem.available_problems
45 problems.each do |problem|
45 problems.each do |problem|
46 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
46 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
47 submissions << sub if sub!=nil
47 submissions << sub if sub!=nil
48 end
48 end
49 submissions
49 submissions
50 end
50 end
51
51
52 def self.find_by_user_problem_number(user_id, problem_id, number)
52 def self.find_by_user_problem_number(user_id, problem_id, number)
53 where("user_id = ? AND problem_id = ? AND number = ?",user_id,problem_id,number).first
53 where("user_id = ? AND problem_id = ? AND number = ?",user_id,problem_id,number).first
54 end
54 end
55
55
56 def self.find_all_by_user_problem(user_id, problem_id)
56 def self.find_all_by_user_problem(user_id, problem_id)
57 where("user_id = ? AND problem_id = ?",user_id,problem_id)
57 where("user_id = ? AND problem_id = ?",user_id,problem_id)
58 end
58 end
59
59
60 def download_filename
60 def download_filename
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 self.language = Submission.find_language_in_source(self.source,
130 self.language = Submission.find_language_in_source(self.source,
131 self.source_filename)
131 self.source_filename)
132 end
132 end
133
133
134 # validation codes
134 # validation codes
135 def must_specify_language
135 def must_specify_language
136 return if self.source==nil
136 return if self.source==nil
137
137
138 # for output_only tasks
138 # for output_only tasks
139 return if self.problem!=nil and self.problem.output_only
139 return if self.problem!=nil and self.problem.output_only
140
140
141 if self.language==nil
141 if self.language==nil
142 errors.add('source',"Cannot detect language. Did you submit a correct source file?") unless self.language!=nil
142 errors.add('source',"Cannot detect language. Did you submit a correct source file?") unless self.language!=nil
143 end
143 end
144 end
144 end
145
145
146 def must_have_valid_problem
146 def must_have_valid_problem
147 return if self.source==nil
147 return if self.source==nil
148 if self.problem==nil
148 if self.problem==nil
149 errors.add('problem',"must be specified.")
149 errors.add('problem',"must be specified.")
150 else
150 else
151 #admin always have right
151 #admin always have right
152 return if self.user.admin?
152 return if self.user.admin?
153
153
154 #check if user has the right to submit the problem
154 #check if user has the right to submit the problem
155 errors.add('problem',"must be valid.") if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
155 errors.add('problem',"must be valid.") if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
156 end
156 end
157 end
157 end
158
158
159 # callbacks
159 # callbacks
160 def assign_latest_number_if_new_recond
160 def assign_latest_number_if_new_recond
161 return if !self.new_record?
161 return if !self.new_record?
162 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
162 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
163 self.number = (latest==nil) ? 1 : latest.number + 1;
163 self.number = (latest==nil) ? 1 : latest.number + 1;
164 end
164 end
165
165
166 end
166 end
@@ -1,118 +1,119
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3 = javascript_include_tag 'local_jquery'
3 = javascript_include_tag 'local_jquery'
4
4
5 :javascript
5 :javascript
6 $(document).ready( function() {
6 $(document).ready( function() {
7 function shiftclick(start,stop,value) {
7 function shiftclick(start,stop,value) {
8 $('tr input').each( function(id,input) {
8 $('tr input').each( function(id,input) {
9 var $input=$(input);
9 var $input=$(input);
10 var iid=parseInt($input.attr('id').split('-')[2]);
10 var iid=parseInt($input.attr('id').split('-')[2]);
11 if(iid>=start&&iid<=stop){
11 if(iid>=start&&iid<=stop){
12 $input.prop('checked',value)
12 $input.prop('checked',value)
13 }
13 }
14 });
14 });
15 }
15 }
16
16
17 $('tr input').click( function(e) {
17 $('tr input').click( function(e) {
18 if (e.shiftKey) {
18 if (e.shiftKey) {
19 stop = parseInt($(this).attr('id').split('-')[2]);
19 stop = parseInt($(this).attr('id').split('-')[2]);
20 var orig_stop = stop
20 var orig_stop = stop
21 if (typeof start !== 'undefined') {
21 if (typeof start !== 'undefined') {
22 if (start > stop) {
22 if (start > stop) {
23 var tmp = start;
23 var tmp = start;
24 start = stop;
24 start = stop;
25 stop = tmp;
25 stop = tmp;
26 }
26 }
27 shiftclick(start,stop,$(this).is(':checked') )
27 shiftclick(start,stop,$(this).is(':checked') )
28 }
28 }
29 start = orig_stop
29 start = orig_stop
30 } else {
30 } else {
31 start = parseInt($(this).attr('id').split('-')[2]);
31 start = parseInt($(this).attr('id').split('-')[2]);
32 }
32 }
33 });
33 });
34 });
34 });
35
35
36
36
37 %h1 Manage problems
37 %h1 Manage problems
38
38
39 %p= link_to '[Back to problem list]', problems_path
39 %p= link_to '[Back to problem list]', problems_path
40
40
41 = form_tag :action=>'do_manage' do
41 = form_tag :action=>'do_manage' do
42 .panel.panel-primary
42 .panel.panel-primary
43 .panel-heading
43 .panel-heading
44 Action
44 Action
45 .panel-body
45 .panel-body
46 .submit-box
46 .submit-box
47 What do you want to do to the selected problem?
47 What do you want to do to the selected problem?
48 %br/
48 %br/
49 (You can shift-click to select a range of problems)
49 (You can shift-click to select a range of problems)
50 %ul.form-inline
50 %ul.form-inline
51 %li
51 %li
52 Change "Date added" to
52 Change "Date added" to
53 .input-group.date
53 .input-group.date
54 = text_field_tag :date_added, class: 'form-control'
54 = text_field_tag :date_added, class: 'form-control'
55 %span.input-group-addon
55 %span.input-group-addon
56 %span.glyphicon.glyphicon-calendar
56 %span.glyphicon.glyphicon-calendar
57 -# = select_date Date.current, :prefix => 'date_added'
57 -# = select_date Date.current, :prefix => 'date_added'
58 &nbsp;&nbsp;&nbsp;
58 &nbsp;&nbsp;&nbsp;
59 = submit_tag 'Change', :name => 'change_date_added', class: 'btn btn-primary btn-sm'
59 = submit_tag 'Change', :name => 'change_date_added', class: 'btn btn-primary btn-sm'
60 %li
60 %li
61 Set "Available" to
61 Set "Available" to
62 = submit_tag 'True', :name => 'enable_problem', class: 'btn btn-primary btn-sm'
62 = submit_tag 'True', :name => 'enable_problem', class: 'btn btn-primary btn-sm'
63 = submit_tag 'False', :name => 'disable_problem', class: 'btn btn-primary btn-sm'
63 = submit_tag 'False', :name => 'disable_problem', class: 'btn btn-primary btn-sm'
64
64
65 - if GraderConfiguration.multicontests?
65 - if GraderConfiguration.multicontests?
66 %li
66 %li
67 Add selected problems to contest
67 Add selected problems to contest
68 = select("contest","id",Contest.all.collect {|c| [c.title, c.id]})
68 = select("contest","id",Contest.all.collect {|c| [c.title, c.id]})
69 = submit_tag 'Add', :name => 'add_to_contest', class: 'btn btn-primary btn-sm'
69 = submit_tag 'Add', :name => 'add_to_contest', class: 'btn btn-primary btn-sm'
70 %li
70 %li
71 Add selected problems to user group
71 Add selected problems to user group
72 = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
72 = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
73 = submit_tag 'Add', name: 'add_group', class: 'btn btn-primary'
73 = submit_tag 'Add', name: 'add_group', class: 'btn btn-primary'
74 %li
74 %li
75 Add the following tags to the selected problems
75 Add the following tags to the selected problems
76 = select_tag "tag_ids", options_from_collection_for_select( Tag.all, 'id','name'), id: 'tags_name',class: 'select2', multiple: true, data: {placeholder: 'Select tags by clicking', width: "200px"}
76 = select_tag "tag_ids", options_from_collection_for_select( Tag.all, 'id','name'), id: 'tags_name',class: 'select2', multiple: true, data: {placeholder: 'Select tags by clicking', width: "200px"}
77 = submit_tag 'Add', name: 'add_tags', class: 'btn btn-primary'
77 = submit_tag 'Add', name: 'add_tags', class: 'btn btn-primary'
78
78
79 %table.table.table-hover.datatable
79 %table.table.table-hover.datatable
80 %thead
80 %thead
81 %tr{style: "text-align: left;"}
81 %tr{style: "text-align: left;"}
82 %th= check_box_tag 'select_all'
82 %th= check_box_tag 'select_all'
83 %th Name
83 %th Name
84 %th Full name
84 %th Full name
85 %th Tags
85 %th Tags
86 %th Available
86 %th Available
87 %th Date added
87 %th Date added
88 - if GraderConfiguration.multicontests?
88 - if GraderConfiguration.multicontests?
89 %th Contests
89 %th Contests
90
90
91 %tbody
91 %tbody
92 - num = 0
92 - num = 0
93 - for problem in @problems
93 - for problem in @problems
94 - num += 1
94 - num += 1
95 %tr{:id => "row-prob-#{problem.id}", :name=> "prob-#{problem.id}"}
95 %tr{:id => "row-prob-#{problem.id}", :name=> "prob-#{problem.id}"}
96 %td= check_box_tag "prob-#{problem.id}-#{num}"
96 %td= check_box_tag "prob-#{problem.id}-#{num}"
97 %td= problem.name
97 %td= problem.name
98 %td= problem.full_name
98 %td= problem.full_name
99 %td
99 %td
100 - problem.tags.each do |t|
100 - problem.tags.each do |t|
101 %span.label.label-default= t.name
101 %span.label.label-default= t.name
102 %td= problem.available
102 %td= problem.available
103 %td= problem.date_added
103 %td= problem.date_added
104 - if GraderConfiguration.multicontests?
104 - if GraderConfiguration.multicontests?
105 %td
105 %td
106 - problem.contests.each do |contest|
106 - problem.contests.each do |contest|
107 = "(#{contest.name} [#{link_to 'x', :action => 'remove_contest', :id => problem.id, :contest_id => contest.id }])"
107 = "(#{contest.name} [#{link_to 'x', :action => 'remove_contest', :id => problem.id, :contest_id => contest.id }])"
108
108
109 :javascript
109 :javascript
110 $('.input-group.date').datetimepicker({
110 $('.input-group.date').datetimepicker({
111 format: 'DD/MMM/YYYY',
111 format: 'DD/MMM/YYYY',
112 showTodayButton: true,
112 showTodayButton: true,
113 + locale: 'en',
113 widgetPositioning: {horizontal: 'auto', vertical: 'bottom'},
114 widgetPositioning: {horizontal: 'auto', vertical: 'bottom'},
114
115
115 });
116 });
116 $('.datatable').DataTable({
117 $('.datatable').DataTable({
117 paging: false
118 paging: false
118 });
119 });
@@ -1,36 +1,37
1 %h1 Editing site
1 %h1 Editing site
2 = error_messages_for :site
2 = error_messages_for :site
3 = form_for(@site) do |f|
3 = form_for(@site) do |f|
4 .row
4 .row
5 .col-md-4
5 .col-md-4
6 .form-group.field
6 .form-group.field
7 = f.label :name, "Name"
7 = f.label :name, "Name"
8 = f.text_field :name, class: 'form-control'
8 = f.text_field :name, class: 'form-control'
9 .form-group.field
9 .form-group.field
10 = f.label :password, "Password"
10 = f.label :password, "Password"
11 = f.text_field :password, class: 'form-control'
11 = f.text_field :password, class: 'form-control'
12 .form-group.field
12 .form-group.field
13 = f.label :started, "Started"
13 = f.label :started, "Started"
14 = f.check_box :started, class: 'form-control'
14 = f.check_box :started, class: 'form-control'
15 .form-group.field
15 .form-group.field
16 = f.label :start_time, "Start time"
16 = f.label :start_time, "Start time"
17 -# = f.datetime_select :start_time, :include_blank => true
17 -# = f.datetime_select :start_time, :include_blank => true
18 .input-group.date
18 .input-group.date
19 = f.text_field :start_time, class:'form-control' , value: (@site.start_time ? @site.start_time.strftime('%d/%b/%Y %H:%M') : '')
19 = f.text_field :start_time, class:'form-control' , value: (@site.start_time ? @site.start_time.strftime('%d/%b/%Y %H:%M') : '')
20 %span.input-group-addon
20 %span.input-group-addon
21 %span.glyphicon.glyphicon-calendar
21 %span.glyphicon.glyphicon-calendar
22 .actions
22 .actions
23 = f.submit "Update", class: 'btn btn-primary'
23 = f.submit "Update", class: 'btn btn-primary'
24 .col-md-8
24 .col-md-8
25
25
26 = link_to 'Show', @site
26 = link_to 'Show', @site
27 |
27 |
28 = link_to 'Back', sites_path
28 = link_to 'Back', sites_path
29
29
30
30
31 :javascript
31 :javascript
32 $('.input-group.date').datetimepicker({
32 $('.input-group.date').datetimepicker({
33 format: 'DD/MMM/YYYY HH:mm',
33 format: 'DD/MMM/YYYY HH:mm',
34 + locale: 'en',
34 showTodayButton: true,
35 showTodayButton: true,
35 });
36 });
36
37
@@ -1,321 +1,321
1 # encoding: UTF-8
1 # encoding: UTF-8
2 # This file is auto-generated from the current state of the database. Instead
2 # This file is auto-generated from the current state of the database. Instead
3 # of editing this file, please use the migrations feature of Active Record to
3 # of editing this file, please use the migrations feature of Active Record to
4 # incrementally modify your database, and then regenerate this schema definition.
4 # incrementally modify your database, and then regenerate this schema definition.
5 #
5 #
6 # Note that this schema.rb definition is the authoritative source for your
6 # Note that this schema.rb definition is the authoritative source for your
7 # database schema. If you need to create the application database on another
7 # database schema. If you need to create the application database on another
8 # system, you should be using db:schema:load, not running all the migrations
8 # system, you should be using db:schema:load, not running all the migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 #
11 #
12 # It's strongly recommended that you check this file into your version control system.
12 # It's strongly recommended that you check this file into your version control system.
13
13
14 - ActiveRecord::Schema.define(version: 20170914150742) do
14 + ActiveRecord::Schema.define(version: 20180612102327) do
15
15
16 create_table "announcements", force: :cascade do |t|
16 create_table "announcements", force: :cascade do |t|
17 t.string "author", limit: 255
17 t.string "author", limit: 255
18 t.text "body", limit: 65535
18 t.text "body", limit: 65535
19 t.boolean "published"
19 t.boolean "published"
20 t.datetime "created_at", null: false
20 t.datetime "created_at", null: false
21 t.datetime "updated_at", null: false
21 t.datetime "updated_at", null: false
22 t.boolean "frontpage", default: false
22 t.boolean "frontpage", default: false
23 t.boolean "contest_only", default: false
23 t.boolean "contest_only", default: false
24 t.string "title", limit: 255
24 t.string "title", limit: 255
25 t.string "notes", limit: 255
25 t.string "notes", limit: 255
26 end
26 end
27
27
28 create_table "contests", force: :cascade do |t|
28 create_table "contests", force: :cascade do |t|
29 t.string "title", limit: 255
29 t.string "title", limit: 255
30 t.boolean "enabled"
30 t.boolean "enabled"
31 t.datetime "created_at", null: false
31 t.datetime "created_at", null: false
32 t.datetime "updated_at", null: false
32 t.datetime "updated_at", null: false
33 t.string "name", limit: 255
33 t.string "name", limit: 255
34 end
34 end
35
35
36 create_table "contests_problems", id: false, force: :cascade do |t|
36 create_table "contests_problems", id: false, force: :cascade do |t|
37 t.integer "contest_id", limit: 4
37 t.integer "contest_id", limit: 4
38 t.integer "problem_id", limit: 4
38 t.integer "problem_id", limit: 4
39 end
39 end
40
40
41 create_table "contests_users", id: false, force: :cascade do |t|
41 create_table "contests_users", id: false, force: :cascade do |t|
42 t.integer "contest_id", limit: 4
42 t.integer "contest_id", limit: 4
43 t.integer "user_id", limit: 4
43 t.integer "user_id", limit: 4
44 end
44 end
45
45
46 create_table "countries", force: :cascade do |t|
46 create_table "countries", force: :cascade do |t|
47 t.string "name", limit: 255
47 t.string "name", limit: 255
48 t.datetime "created_at", null: false
48 t.datetime "created_at", null: false
49 t.datetime "updated_at", null: false
49 t.datetime "updated_at", null: false
50 end
50 end
51
51
52 create_table "descriptions", force: :cascade do |t|
52 create_table "descriptions", force: :cascade do |t|
53 t.text "body", limit: 65535
53 t.text "body", limit: 65535
54 t.boolean "markdowned"
54 t.boolean "markdowned"
55 t.datetime "created_at", null: false
55 t.datetime "created_at", null: false
56 t.datetime "updated_at", null: false
56 t.datetime "updated_at", null: false
57 end
57 end
58
58
59 create_table "grader_configurations", force: :cascade do |t|
59 create_table "grader_configurations", force: :cascade do |t|
60 t.string "key", limit: 255
60 t.string "key", limit: 255
61 t.string "value_type", limit: 255
61 t.string "value_type", limit: 255
62 t.string "value", limit: 255
62 t.string "value", limit: 255
63 t.datetime "created_at", null: false
63 t.datetime "created_at", null: false
64 t.datetime "updated_at", null: false
64 t.datetime "updated_at", null: false
65 t.text "description", limit: 65535
65 t.text "description", limit: 65535
66 end
66 end
67
67
68 create_table "grader_processes", force: :cascade do |t|
68 create_table "grader_processes", force: :cascade do |t|
69 t.string "host", limit: 255
69 t.string "host", limit: 255
70 t.integer "pid", limit: 4
70 t.integer "pid", limit: 4
71 t.string "mode", limit: 255
71 t.string "mode", limit: 255
72 t.boolean "active"
72 t.boolean "active"
73 t.datetime "created_at", null: false
73 t.datetime "created_at", null: false
74 t.datetime "updated_at", null: false
74 t.datetime "updated_at", null: false
75 t.integer "task_id", limit: 4
75 t.integer "task_id", limit: 4
76 t.string "task_type", limit: 255
76 t.string "task_type", limit: 255
77 t.boolean "terminated"
77 t.boolean "terminated"
78 end
78 end
79
79
80 add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid", using: :btree
80 add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid", using: :btree
81
81
82 create_table "groups", force: :cascade do |t|
82 create_table "groups", force: :cascade do |t|
83 t.string "name", limit: 255
83 t.string "name", limit: 255
84 t.string "description", limit: 255
84 t.string "description", limit: 255
85 end
85 end
86
86
87 create_table "groups_problems", id: false, force: :cascade do |t|
87 create_table "groups_problems", id: false, force: :cascade do |t|
88 t.integer "problem_id", limit: 4, null: false
88 t.integer "problem_id", limit: 4, null: false
89 t.integer "group_id", limit: 4, null: false
89 t.integer "group_id", limit: 4, null: false
90 end
90 end
91
91
92 add_index "groups_problems", ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id", using: :btree
92 add_index "groups_problems", ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id", using: :btree
93
93
94 create_table "groups_users", id: false, force: :cascade do |t|
94 create_table "groups_users", id: false, force: :cascade do |t|
95 t.integer "group_id", limit: 4, null: false
95 t.integer "group_id", limit: 4, null: false
96 t.integer "user_id", limit: 4, null: false
96 t.integer "user_id", limit: 4, null: false
97 end
97 end
98
98
99 add_index "groups_users", ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id", using: :btree
99 add_index "groups_users", ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id", using: :btree
100
100
101 create_table "heart_beats", force: :cascade do |t|
101 create_table "heart_beats", force: :cascade do |t|
102 t.integer "user_id", limit: 4
102 t.integer "user_id", limit: 4
103 t.string "ip_address", limit: 255
103 t.string "ip_address", limit: 255
104 t.datetime "created_at", null: false
104 t.datetime "created_at", null: false
105 t.datetime "updated_at", null: false
105 t.datetime "updated_at", null: false
106 t.string "status", limit: 255
106 t.string "status", limit: 255
107 end
107 end
108
108
109 add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at", using: :btree
109 add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at", using: :btree
110
110
111 create_table "languages", force: :cascade do |t|
111 create_table "languages", force: :cascade do |t|
112 t.string "name", limit: 10
112 t.string "name", limit: 10
113 t.string "pretty_name", limit: 255
113 t.string "pretty_name", limit: 255
114 t.string "ext", limit: 10
114 t.string "ext", limit: 10
115 t.string "common_ext", limit: 255
115 t.string "common_ext", limit: 255
116 end
116 end
117
117
118 create_table "logins", force: :cascade do |t|
118 create_table "logins", force: :cascade do |t|
119 t.integer "user_id", limit: 4
119 t.integer "user_id", limit: 4
120 t.string "ip_address", limit: 255
120 t.string "ip_address", limit: 255
121 t.datetime "created_at", null: false
121 t.datetime "created_at", null: false
122 t.datetime "updated_at", null: false
122 t.datetime "updated_at", null: false
123 end
123 end
124
124
125 create_table "messages", force: :cascade do |t|
125 create_table "messages", force: :cascade do |t|
126 t.integer "sender_id", limit: 4
126 t.integer "sender_id", limit: 4
127 t.integer "receiver_id", limit: 4
127 t.integer "receiver_id", limit: 4
128 t.integer "replying_message_id", limit: 4
128 t.integer "replying_message_id", limit: 4
129 t.text "body", limit: 65535
129 t.text "body", limit: 65535
130 t.boolean "replied"
130 t.boolean "replied"
131 t.datetime "created_at", null: false
131 t.datetime "created_at", null: false
132 t.datetime "updated_at", null: false
132 t.datetime "updated_at", null: false
133 end
133 end
134
134
135 create_table "problems", force: :cascade do |t|
135 create_table "problems", force: :cascade do |t|
136 t.string "name", limit: 30
136 t.string "name", limit: 30
137 t.string "full_name", limit: 255
137 t.string "full_name", limit: 255
138 t.integer "full_score", limit: 4
138 t.integer "full_score", limit: 4
139 t.date "date_added"
139 t.date "date_added"
140 t.boolean "available"
140 t.boolean "available"
141 t.string "url", limit: 255
141 t.string "url", limit: 255
142 t.integer "description_id", limit: 4
142 t.integer "description_id", limit: 4
143 t.boolean "test_allowed"
143 t.boolean "test_allowed"
144 t.boolean "output_only"
144 t.boolean "output_only"
145 t.string "description_filename", limit: 255
145 t.string "description_filename", limit: 255
146 t.boolean "view_testcase"
146 t.boolean "view_testcase"
147 end
147 end
148
148
149 create_table "problems_tags", force: :cascade do |t|
149 create_table "problems_tags", force: :cascade do |t|
150 t.integer "problem_id", limit: 4
150 t.integer "problem_id", limit: 4
151 t.integer "tag_id", limit: 4
151 t.integer "tag_id", limit: 4
152 end
152 end
153
153
154 add_index "problems_tags", ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true, using: :btree
154 add_index "problems_tags", ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true, using: :btree
155 add_index "problems_tags", ["problem_id"], name: "index_problems_tags_on_problem_id", using: :btree
155 add_index "problems_tags", ["problem_id"], name: "index_problems_tags_on_problem_id", using: :btree
156 add_index "problems_tags", ["tag_id"], name: "index_problems_tags_on_tag_id", using: :btree
156 add_index "problems_tags", ["tag_id"], name: "index_problems_tags_on_tag_id", using: :btree
157
157
158 create_table "rights", force: :cascade do |t|
158 create_table "rights", force: :cascade do |t|
159 t.string "name", limit: 255
159 t.string "name", limit: 255
160 t.string "controller", limit: 255
160 t.string "controller", limit: 255
161 t.string "action", limit: 255
161 t.string "action", limit: 255
162 end
162 end
163
163
164 create_table "rights_roles", id: false, force: :cascade do |t|
164 create_table "rights_roles", id: false, force: :cascade do |t|
165 t.integer "right_id", limit: 4
165 t.integer "right_id", limit: 4
166 t.integer "role_id", limit: 4
166 t.integer "role_id", limit: 4
167 end
167 end
168
168
169 add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree
169 add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree
170
170
171 create_table "roles", force: :cascade do |t|
171 create_table "roles", force: :cascade do |t|
172 t.string "name", limit: 255
172 t.string "name", limit: 255
173 end
173 end
174
174
175 create_table "roles_users", id: false, force: :cascade do |t|
175 create_table "roles_users", id: false, force: :cascade do |t|
176 t.integer "role_id", limit: 4
176 t.integer "role_id", limit: 4
177 t.integer "user_id", limit: 4
177 t.integer "user_id", limit: 4
178 end
178 end
179
179
180 add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree
180 add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree
181
181
182 create_table "sessions", force: :cascade do |t|
182 create_table "sessions", force: :cascade do |t|
183 t.string "session_id", limit: 255
183 t.string "session_id", limit: 255
184 t.text "data", limit: 65535
184 t.text "data", limit: 65535
185 t.datetime "updated_at"
185 t.datetime "updated_at"
186 end
186 end
187
187
188 add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree
188 add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree
189 add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree
189 add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree
190
190
191 create_table "sites", force: :cascade do |t|
191 create_table "sites", force: :cascade do |t|
192 t.string "name", limit: 255
192 t.string "name", limit: 255
193 t.boolean "started"
193 t.boolean "started"
194 t.datetime "start_time"
194 t.datetime "start_time"
195 t.datetime "created_at", null: false
195 t.datetime "created_at", null: false
196 t.datetime "updated_at", null: false
196 t.datetime "updated_at", null: false
197 t.integer "country_id", limit: 4
197 t.integer "country_id", limit: 4
198 t.string "password", limit: 255
198 t.string "password", limit: 255
199 end
199 end
200
200
201 create_table "submission_view_logs", force: :cascade do |t|
201 create_table "submission_view_logs", force: :cascade do |t|
202 t.integer "user_id", limit: 4
202 t.integer "user_id", limit: 4
203 t.integer "submission_id", limit: 4
203 t.integer "submission_id", limit: 4
204 t.datetime "created_at", null: false
204 t.datetime "created_at", null: false
205 t.datetime "updated_at", null: false
205 t.datetime "updated_at", null: false
206 end
206 end
207
207
208 create_table "submissions", force: :cascade do |t|
208 create_table "submissions", force: :cascade do |t|
209 t.integer "user_id", limit: 4
209 t.integer "user_id", limit: 4
210 t.integer "problem_id", limit: 4
210 t.integer "problem_id", limit: 4
211 t.integer "language_id", limit: 4
211 t.integer "language_id", limit: 4
212 - t.text "source", limit: 65535
212 + t.text "source", limit: 16777215
213 t.binary "binary", limit: 65535
213 t.binary "binary", limit: 65535
214 t.datetime "submitted_at"
214 t.datetime "submitted_at"
215 t.datetime "compiled_at"
215 t.datetime "compiled_at"
216 t.text "compiler_message", limit: 65535
216 t.text "compiler_message", limit: 65535
217 t.datetime "graded_at"
217 t.datetime "graded_at"
218 t.integer "points", limit: 4
218 t.integer "points", limit: 4
219 t.text "grader_comment", limit: 65535
219 t.text "grader_comment", limit: 65535
220 t.integer "number", limit: 4
220 t.integer "number", limit: 4
221 t.string "source_filename", limit: 255
221 t.string "source_filename", limit: 255
222 t.float "max_runtime", limit: 24
222 t.float "max_runtime", limit: 24
223 t.integer "peak_memory", limit: 4
223 t.integer "peak_memory", limit: 4
224 t.integer "effective_code_length", limit: 4
224 t.integer "effective_code_length", limit: 4
225 t.string "ip_address", limit: 255
225 t.string "ip_address", limit: 255
226 end
226 end
227
227
228 add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree
228 add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree
229 add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree
229 add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree
230
230
231 create_table "tags", force: :cascade do |t|
231 create_table "tags", force: :cascade do |t|
232 t.string "name", limit: 255, null: false
232 t.string "name", limit: 255, null: false
233 t.text "description", limit: 65535
233 t.text "description", limit: 65535
234 t.boolean "public"
234 t.boolean "public"
235 t.datetime "created_at", null: false
235 t.datetime "created_at", null: false
236 t.datetime "updated_at", null: false
236 t.datetime "updated_at", null: false
237 end
237 end
238
238
239 create_table "tasks", force: :cascade do |t|
239 create_table "tasks", force: :cascade do |t|
240 t.integer "submission_id", limit: 4
240 t.integer "submission_id", limit: 4
241 t.datetime "created_at"
241 t.datetime "created_at"
242 t.integer "status", limit: 4
242 t.integer "status", limit: 4
243 t.datetime "updated_at"
243 t.datetime "updated_at"
244 end
244 end
245
245
246 add_index "tasks", ["submission_id"], name: "index_tasks_on_submission_id", using: :btree
246 add_index "tasks", ["submission_id"], name: "index_tasks_on_submission_id", using: :btree
247
247
248 create_table "test_pairs", force: :cascade do |t|
248 create_table "test_pairs", force: :cascade do |t|
249 t.integer "problem_id", limit: 4
249 t.integer "problem_id", limit: 4
250 t.text "input", limit: 16777215
250 t.text "input", limit: 16777215
251 t.text "solution", limit: 16777215
251 t.text "solution", limit: 16777215
252 t.datetime "created_at", null: false
252 t.datetime "created_at", null: false
253 t.datetime "updated_at", null: false
253 t.datetime "updated_at", null: false
254 end
254 end
255
255
256 create_table "test_requests", force: :cascade do |t|
256 create_table "test_requests", force: :cascade do |t|
257 t.integer "user_id", limit: 4
257 t.integer "user_id", limit: 4
258 t.integer "problem_id", limit: 4
258 t.integer "problem_id", limit: 4
259 t.integer "submission_id", limit: 4
259 t.integer "submission_id", limit: 4
260 t.string "input_file_name", limit: 255
260 t.string "input_file_name", limit: 255
261 t.string "output_file_name", limit: 255
261 t.string "output_file_name", limit: 255
262 t.string "running_stat", limit: 255
262 t.string "running_stat", limit: 255
263 t.integer "status", limit: 4
263 t.integer "status", limit: 4
264 t.datetime "updated_at", null: false
264 t.datetime "updated_at", null: false
265 t.datetime "submitted_at"
265 t.datetime "submitted_at"
266 t.datetime "compiled_at"
266 t.datetime "compiled_at"
267 t.text "compiler_message", limit: 65535
267 t.text "compiler_message", limit: 65535
268 t.datetime "graded_at"
268 t.datetime "graded_at"
269 t.string "grader_comment", limit: 255
269 t.string "grader_comment", limit: 255
270 t.datetime "created_at", null: false
270 t.datetime "created_at", null: false
271 t.float "running_time", limit: 24
271 t.float "running_time", limit: 24
272 t.string "exit_status", limit: 255
272 t.string "exit_status", limit: 255
273 t.integer "memory_usage", limit: 4
273 t.integer "memory_usage", limit: 4
274 end
274 end
275
275
276 add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree
276 add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree
277
277
278 create_table "testcases", force: :cascade do |t|
278 create_table "testcases", force: :cascade do |t|
279 t.integer "problem_id", limit: 4
279 t.integer "problem_id", limit: 4
280 t.integer "num", limit: 4
280 t.integer "num", limit: 4
281 t.integer "group", limit: 4
281 t.integer "group", limit: 4
282 t.integer "score", limit: 4
282 t.integer "score", limit: 4
283 t.text "input", limit: 4294967295
283 t.text "input", limit: 4294967295
284 t.text "sol", limit: 4294967295
284 t.text "sol", limit: 4294967295
285 t.datetime "created_at"
285 t.datetime "created_at"
286 t.datetime "updated_at"
286 t.datetime "updated_at"
287 end
287 end
288
288
289 add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree
289 add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree
290
290
291 create_table "user_contest_stats", force: :cascade do |t|
291 create_table "user_contest_stats", force: :cascade do |t|
292 t.integer "user_id", limit: 4
292 t.integer "user_id", limit: 4
293 t.datetime "started_at"
293 t.datetime "started_at"
294 t.datetime "created_at", null: false
294 t.datetime "created_at", null: false
295 t.datetime "updated_at", null: false
295 t.datetime "updated_at", null: false
296 t.boolean "forced_logout"
296 t.boolean "forced_logout"
297 end
297 end
298
298
299 create_table "users", force: :cascade do |t|
299 create_table "users", force: :cascade do |t|
300 t.string "login", limit: 50
300 t.string "login", limit: 50
301 t.string "full_name", limit: 255
301 t.string "full_name", limit: 255
302 t.string "hashed_password", limit: 255
302 t.string "hashed_password", limit: 255
303 t.string "salt", limit: 5
303 t.string "salt", limit: 5
304 t.string "alias", limit: 255
304 t.string "alias", limit: 255
305 t.string "email", limit: 255
305 t.string "email", limit: 255
306 t.integer "site_id", limit: 4
306 t.integer "site_id", limit: 4
307 t.integer "country_id", limit: 4
307 t.integer "country_id", limit: 4
308 t.boolean "activated", default: false
308 t.boolean "activated", default: false
309 t.datetime "created_at"
309 t.datetime "created_at"
310 t.datetime "updated_at"
310 t.datetime "updated_at"
311 t.boolean "enabled", default: true
311 t.boolean "enabled", default: true
312 t.string "remark", limit: 255
312 t.string "remark", limit: 255
313 t.string "last_ip", limit: 255
313 t.string "last_ip", limit: 255
314 t.string "section", limit: 255
314 t.string "section", limit: 255
315 end
315 end
316
316
317 add_index "users", ["login"], name: "index_users_on_login", unique: true, using: :btree
317 add_index "users", ["login"], name: "index_users_on_login", unique: true, using: :btree
318
318
319 add_foreign_key "problems_tags", "problems"
319 add_foreign_key "problems_tags", "problems"
320 add_foreign_key "problems_tags", "tags"
320 add_foreign_key "problems_tags", "tags"
321 end
321 end
You need to be logged in to leave comments. Login now