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

r753:9918c6e0c313 - - 6 files changed: 26 inserted, 17 deleted

@@ -1,304 +1,308
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
14
15 def show
15 def show
16 @problem = Problem.find(params[:id])
16 @problem = Problem.find(params[:id])
17 end
17 end
18
18
19 def new
19 def new
20 @problem = Problem.new
20 @problem = Problem.new
21 @description = nil
21 @description = nil
22 end
22 end
23
23
24 def create
24 def create
25 @problem = Problem.new(problem_params)
25 @problem = Problem.new(problem_params)
26 @description = Description.new(problem_params[:description])
26 @description = Description.new(problem_params[:description])
27 if @description.body!=''
27 if @description.body!=''
28 if !@description.save
28 if !@description.save
29 render :action => new and return
29 render :action => new and return
30 end
30 end
31 else
31 else
32 @description = nil
32 @description = nil
33 end
33 end
34 @problem.description = @description
34 @problem.description = @description
35 if @problem.save
35 if @problem.save
36 flash[:notice] = 'Problem was successfully created.'
36 flash[:notice] = 'Problem was successfully created.'
37 redirect_to action: :index
37 redirect_to action: :index
38 else
38 else
39 render :action => 'new'
39 render :action => 'new'
40 end
40 end
41 end
41 end
42
42
43 def quick_create
43 def quick_create
44 @problem = Problem.new(problem_params)
44 @problem = Problem.new(problem_params)
45 @problem.full_name = @problem.name if @problem.full_name == ''
45 @problem.full_name = @problem.name if @problem.full_name == ''
46 @problem.full_score = 100
46 @problem.full_score = 100
47 @problem.available = false
47 @problem.available = false
48 @problem.test_allowed = true
48 @problem.test_allowed = true
49 @problem.output_only = false
49 @problem.output_only = false
50 @problem.date_added = Time.new
50 @problem.date_added = Time.new
51 if @problem.save
51 if @problem.save
52 flash[:notice] = 'Problem was successfully created.'
52 flash[:notice] = 'Problem was successfully created.'
53 redirect_to action: :index
53 redirect_to action: :index
54 else
54 else
55 flash[:notice] = 'Error saving problem'
55 flash[:notice] = 'Error saving problem'
56 redirect_to action: :index
56 redirect_to action: :index
57 end
57 end
58 end
58 end
59
59
60 def edit
60 def edit
61 @problem = Problem.find(params[:id])
61 @problem = Problem.find(params[:id])
62 @description = @problem.description
62 @description = @problem.description
63 end
63 end
64
64
65 def update
65 def update
66 @problem = Problem.find(params[:id])
66 @problem = Problem.find(params[:id])
67 @description = @problem.description
67 @description = @problem.description
68 if @description.nil? and params[:description][:body]!=''
68 if @description.nil? and params[:description][:body]!=''
69 - @description = Description.new(params[:description])
69 + @description = Description.new(description_params)
70 if !@description.save
70 if !@description.save
71 flash[:notice] = 'Error saving description'
71 flash[:notice] = 'Error saving description'
72 render :action => 'edit' and return
72 render :action => 'edit' and return
73 end
73 end
74 @problem.description = @description
74 @problem.description = @description
75 elsif @description
75 elsif @description
76 - if !@description.update_attributes(params[:description])
76 + if !@description.update_attributes(description_params)
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 end
80 end
81 if params[:file] and params[:file].content_type != 'application/pdf'
81 if params[:file] and params[:file].content_type != 'application/pdf'
82 flash[:notice] = 'Error: Uploaded file is not PDF'
82 flash[:notice] = 'Error: Uploaded file is not PDF'
83 render :action => 'edit' and return
83 render :action => 'edit' and return
84 end
84 end
85 if @problem.update_attributes(problem_params)
85 if @problem.update_attributes(problem_params)
86 flash[:notice] = 'Problem was successfully updated.'
86 flash[:notice] = 'Problem was successfully updated.'
87 unless params[:file] == nil or params[:file] == ''
87 unless params[:file] == nil or params[:file] == ''
88 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
88 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
89 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
89 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
90 if not FileTest.exists? out_dirname
90 if not FileTest.exists? out_dirname
91 Dir.mkdir out_dirname
91 Dir.mkdir out_dirname
92 end
92 end
93
93
94 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
94 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
95 if FileTest.exists? out_filename
95 if FileTest.exists? out_filename
96 File.delete out_filename
96 File.delete out_filename
97 end
97 end
98
98
99 File.open(out_filename,"wb") do |file|
99 File.open(out_filename,"wb") do |file|
100 file.write(params[:file].read)
100 file.write(params[:file].read)
101 end
101 end
102 @problem.description_filename = "#{@problem.name}.pdf"
102 @problem.description_filename = "#{@problem.name}.pdf"
103 @problem.save
103 @problem.save
104 end
104 end
105 redirect_to :action => 'show', :id => @problem
105 redirect_to :action => 'show', :id => @problem
106 else
106 else
107 render :action => 'edit'
107 render :action => 'edit'
108 end
108 end
109 end
109 end
110
110
111 def destroy
111 def destroy
112 p = Problem.find(params[:id]).destroy
112 p = Problem.find(params[:id]).destroy
113 redirect_to action: :index
113 redirect_to action: :index
114 end
114 end
115
115
116 def toggle
116 def toggle
117 @problem = Problem.find(params[:id])
117 @problem = Problem.find(params[:id])
118 @problem.update_attributes(available: !(@problem.available) )
118 @problem.update_attributes(available: !(@problem.available) )
119 respond_to do |format|
119 respond_to do |format|
120 format.js { }
120 format.js { }
121 end
121 end
122 end
122 end
123
123
124 def toggle_test
124 def toggle_test
125 @problem = Problem.find(params[:id])
125 @problem = Problem.find(params[:id])
126 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
126 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
127 respond_to do |format|
127 respond_to do |format|
128 format.js { }
128 format.js { }
129 end
129 end
130 end
130 end
131
131
132 def toggle_view_testcase
132 def toggle_view_testcase
133 @problem = Problem.find(params[:id])
133 @problem = Problem.find(params[:id])
134 @problem.update_attributes(view_testcase: !(@problem.view_testcase?) )
134 @problem.update_attributes(view_testcase: !(@problem.view_testcase?) )
135 respond_to do |format|
135 respond_to do |format|
136 format.js { }
136 format.js { }
137 end
137 end
138 end
138 end
139
139
140 def turn_all_off
140 def turn_all_off
141 Problem.available.all.each do |problem|
141 Problem.available.all.each do |problem|
142 problem.available = false
142 problem.available = false
143 problem.save
143 problem.save
144 end
144 end
145 redirect_to action: :index
145 redirect_to action: :index
146 end
146 end
147
147
148 def turn_all_on
148 def turn_all_on
149 Problem.where.not(available: true).each do |problem|
149 Problem.where.not(available: true).each do |problem|
150 problem.available = true
150 problem.available = true
151 problem.save
151 problem.save
152 end
152 end
153 redirect_to action: :index
153 redirect_to action: :index
154 end
154 end
155
155
156 def stat
156 def stat
157 @problem = Problem.find(params[:id])
157 @problem = Problem.find(params[:id])
158 unless @problem.available or session[:admin]
158 unless @problem.available or session[:admin]
159 redirect_to :controller => 'main', :action => 'list'
159 redirect_to :controller => 'main', :action => 'list'
160 return
160 return
161 end
161 end
162 @submissions = Submission.includes(:user).includes(:language).where(problem_id: params[:id]).order(:user_id,:id)
162 @submissions = Submission.includes(:user).includes(:language).where(problem_id: params[:id]).order(:user_id,:id)
163
163
164 #stat summary
164 #stat summary
165 range =65
165 range =65
166 @histogram = { data: Array.new(range,0), summary: {} }
166 @histogram = { data: Array.new(range,0), summary: {} }
167 user = Hash.new(0)
167 user = Hash.new(0)
168 @submissions.find_each do |sub|
168 @submissions.find_each do |sub|
169 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
169 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
170 @histogram[:data][d.to_i] += 1 if d < range
170 @histogram[:data][d.to_i] += 1 if d < range
171 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
171 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
172 end
172 end
173 @histogram[:summary][:max] = [@histogram[:data].max,1].max
173 @histogram[:summary][:max] = [@histogram[:data].max,1].max
174
174
175 @summary = { attempt: user.count, solve: 0 }
175 @summary = { attempt: user.count, solve: 0 }
176 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
176 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
177 end
177 end
178
178
179 def manage
179 def manage
180 @problems = Problem.order(date_added: :desc)
180 @problems = Problem.order(date_added: :desc)
181 end
181 end
182
182
183 def do_manage
183 def do_manage
184 if params.has_key? 'change_date_added' and params[:date_added].strip.empty? == false
184 if params.has_key? 'change_date_added' and params[:date_added].strip.empty? == false
185 change_date_added
185 change_date_added
186 elsif params.has_key? 'add_to_contest'
186 elsif params.has_key? 'add_to_contest'
187 add_to_contest
187 add_to_contest
188 elsif params.has_key? 'enable_problem'
188 elsif params.has_key? 'enable_problem'
189 set_available(true)
189 set_available(true)
190 elsif params.has_key? 'disable_problem'
190 elsif params.has_key? 'disable_problem'
191 set_available(false)
191 set_available(false)
192 elsif params.has_key? 'add_group'
192 elsif params.has_key? 'add_group'
193 group = Group.find(params[:group_id])
193 group = Group.find(params[:group_id])
194 ok = []
194 ok = []
195 failed = []
195 failed = []
196 get_problems_from_params.each do |p|
196 get_problems_from_params.each do |p|
197 begin
197 begin
198 group.problems << p
198 group.problems << p
199 ok << p.full_name
199 ok << p.full_name
200 rescue => e
200 rescue => e
201 failed << p.full_name
201 failed << p.full_name
202 end
202 end
203 end
203 end
204 flash[:success] = "The following problems are added to the group #{group.name}: " + ok.join(', ') if ok.count > 0
204 flash[:success] = "The following problems are added to the group #{group.name}: " + ok.join(', ') if ok.count > 0
205 flash[:alert] = "The following problems are already in the group #{group.name}: " + failed.join(', ') if failed.count > 0
205 flash[:alert] = "The following problems are already in the group #{group.name}: " + failed.join(', ') if failed.count > 0
206 elsif params.has_key? 'add_tags'
206 elsif params.has_key? 'add_tags'
207 get_problems_from_params.each do |p|
207 get_problems_from_params.each do |p|
208 p.tag_ids += params[:tag_ids]
208 p.tag_ids += params[:tag_ids]
209 end
209 end
210 end
210 end
211
211
212 redirect_to :action => 'manage'
212 redirect_to :action => 'manage'
213 end
213 end
214
214
215 def import
215 def import
216 @allow_test_pair_import = allow_test_pair_import?
216 @allow_test_pair_import = allow_test_pair_import?
217 end
217 end
218
218
219 def do_import
219 def do_import
220 old_problem = Problem.find_by_name(params[:name])
220 old_problem = Problem.find_by_name(params[:name])
221 if !allow_test_pair_import? and params.has_key? :import_to_db
221 if !allow_test_pair_import? and params.has_key? :import_to_db
222 params.delete :import_to_db
222 params.delete :import_to_db
223 end
223 end
224 @problem, import_log = Problem.create_from_import_form_params(params,
224 @problem, import_log = Problem.create_from_import_form_params(params,
225 old_problem)
225 old_problem)
226
226
227 if !@problem.errors.empty?
227 if !@problem.errors.empty?
228 render :action => 'import' and return
228 render :action => 'import' and return
229 end
229 end
230
230
231 if old_problem!=nil
231 if old_problem!=nil
232 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
232 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
233 end
233 end
234 @log = import_log
234 @log = import_log
235 end
235 end
236
236
237 def remove_contest
237 def remove_contest
238 problem = Problem.find(params[:id])
238 problem = Problem.find(params[:id])
239 contest = Contest.find(params[:contest_id])
239 contest = Contest.find(params[:contest_id])
240 if problem!=nil and contest!=nil
240 if problem!=nil and contest!=nil
241 problem.contests.delete(contest)
241 problem.contests.delete(contest)
242 end
242 end
243 redirect_to :action => 'manage'
243 redirect_to :action => 'manage'
244 end
244 end
245
245
246 ##################################
246 ##################################
247 protected
247 protected
248
248
249 def allow_test_pair_import?
249 def allow_test_pair_import?
250 if defined? ALLOW_TEST_PAIR_IMPORT
250 if defined? ALLOW_TEST_PAIR_IMPORT
251 return ALLOW_TEST_PAIR_IMPORT
251 return ALLOW_TEST_PAIR_IMPORT
252 else
252 else
253 return false
253 return false
254 end
254 end
255 end
255 end
256
256
257 def change_date_added
257 def change_date_added
258 problems = get_problems_from_params
258 problems = get_problems_from_params
259 date = Date.parse(params[:date_added])
259 date = Date.parse(params[:date_added])
260 problems.each do |p|
260 problems.each do |p|
261 p.date_added = date
261 p.date_added = date
262 p.save
262 p.save
263 end
263 end
264 end
264 end
265
265
266 def add_to_contest
266 def add_to_contest
267 problems = get_problems_from_params
267 problems = get_problems_from_params
268 contest = Contest.find(params[:contest][:id])
268 contest = Contest.find(params[:contest][:id])
269 if contest!=nil and contest.enabled
269 if contest!=nil and contest.enabled
270 problems.each do |p|
270 problems.each do |p|
271 p.contests << contest
271 p.contests << contest
272 end
272 end
273 end
273 end
274 end
274 end
275
275
276 def set_available(avail)
276 def set_available(avail)
277 problems = get_problems_from_params
277 problems = get_problems_from_params
278 problems.each do |p|
278 problems.each do |p|
279 p.available = avail
279 p.available = avail
280 p.save
280 p.save
281 end
281 end
282 end
282 end
283
283
284 def get_problems_from_params
284 def get_problems_from_params
285 problems = []
285 problems = []
286 params.keys.each do |k|
286 params.keys.each do |k|
287 if k.index('prob-')==0
287 if k.index('prob-')==0
288 name, id, order = k.split('-')
288 name, id, order = k.split('-')
289 problems << Problem.find(id)
289 problems << Problem.find(id)
290 end
290 end
291 end
291 end
292 problems
292 problems
293 end
293 end
294
294
295 def get_problems_stat
295 def get_problems_stat
296 end
296 end
297
297
298 private
298 private
299
299
300 def problem_params
300 def problem_params
301 params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available, :test_allowed,:output_only, :url, :description, tag_ids:[])
301 params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available, :test_allowed,:output_only, :url, :description, tag_ids:[])
302 end
302 end
303
303
304 + def description_params
305 + params.require(:description).permit(:body, :markdown)
306 + end
307 +
304 end
308 end
@@ -1,368 +1,368
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 require 'net/https'
3 require 'net/https'
4 require 'net/http'
4 require 'net/http'
5 require 'json'
5 require 'json'
6
6
7 class User < ActiveRecord::Base
7 class User < ActiveRecord::Base
8
8
9 has_and_belongs_to_many :roles
9 has_and_belongs_to_many :roles
10
10
11 #has_and_belongs_to_many :groups
11 #has_and_belongs_to_many :groups
12 has_many :groups_users, class_name: 'GroupUser'
12 has_many :groups_users, class_name: 'GroupUser'
13 has_many :groups, :through => :groups_users
13 has_many :groups, :through => :groups_users
14
14
15 has_many :test_requests, -> {order(submitted_at: :desc)}
15 has_many :test_requests, -> {order(submitted_at: :desc)}
16
16
17 has_many :messages, -> { order(created_at: :desc) },
17 has_many :messages, -> { order(created_at: :desc) },
18 :class_name => "Message",
18 :class_name => "Message",
19 :foreign_key => "sender_id"
19 :foreign_key => "sender_id"
20
20
21 has_many :replied_messages, -> { order(created_at: :desc) },
21 has_many :replied_messages, -> { order(created_at: :desc) },
22 :class_name => "Message",
22 :class_name => "Message",
23 :foreign_key => "receiver_id"
23 :foreign_key => "receiver_id"
24
24
25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
26
26
27 belongs_to :site
27 belongs_to :site
28 belongs_to :country
28 belongs_to :country
29
29
30 - has_and_belongs_to_many :contests, -> { order(:name); uniq}
30 + has_and_belongs_to_many :contests, -> { order(:name)}
31
31
32 scope :activated_users, -> {where activated: true}
32 scope :activated_users, -> {where activated: true}
33
33
34 validates_presence_of :login
34 validates_presence_of :login
35 validates_uniqueness_of :login
35 validates_uniqueness_of :login
36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
37 validates_length_of :login, :within => 3..30
37 validates_length_of :login, :within => 3..30
38
38
39 validates_presence_of :full_name
39 validates_presence_of :full_name
40 validates_length_of :full_name, :minimum => 1
40 validates_length_of :full_name, :minimum => 1
41
41
42 validates_presence_of :password, :if => :password_required?
42 validates_presence_of :password, :if => :password_required?
43 validates_length_of :password, :within => 4..20, :if => :password_required?
43 validates_length_of :password, :within => 4..20, :if => :password_required?
44 validates_confirmation_of :password, :if => :password_required?
44 validates_confirmation_of :password, :if => :password_required?
45
45
46 validates_format_of :email,
46 validates_format_of :email,
47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
48 :if => :email_validation?
48 :if => :email_validation?
49 validate :uniqueness_of_email_from_activated_users,
49 validate :uniqueness_of_email_from_activated_users,
50 :if => :email_validation?
50 :if => :email_validation?
51 validate :enough_time_interval_between_same_email_registrations,
51 validate :enough_time_interval_between_same_email_registrations,
52 :if => :email_validation?
52 :if => :email_validation?
53
53
54 # these are for ytopc
54 # these are for ytopc
55 # disable for now
55 # disable for now
56 #validates_presence_of :province
56 #validates_presence_of :province
57
57
58 attr_accessor :password
58 attr_accessor :password
59
59
60 before_save :encrypt_new_password
60 before_save :encrypt_new_password
61 before_save :assign_default_site
61 before_save :assign_default_site
62 before_save :assign_default_contest
62 before_save :assign_default_contest
63
63
64 # this is for will_paginate
64 # this is for will_paginate
65 cattr_reader :per_page
65 cattr_reader :per_page
66 @@per_page = 50
66 @@per_page = 50
67
67
68 def self.authenticate(login, password)
68 def self.authenticate(login, password)
69 user = find_by_login(login)
69 user = find_by_login(login)
70 if user
70 if user
71 return user if user.authenticated?(password)
71 return user if user.authenticated?(password)
72 end
72 end
73 end
73 end
74
74
75 def authenticated?(password)
75 def authenticated?(password)
76 if self.activated
76 if self.activated
77 hashed_password == User.encrypt(password,self.salt)
77 hashed_password == User.encrypt(password,self.salt)
78 else
78 else
79 false
79 false
80 end
80 end
81 end
81 end
82
82
83 def admin?
83 def admin?
84 self.roles.detect {|r| r.name == 'admin' }
84 self.roles.detect {|r| r.name == 'admin' }
85 end
85 end
86
86
87 def email_for_editing
87 def email_for_editing
88 if self.email==nil
88 if self.email==nil
89 "(unknown)"
89 "(unknown)"
90 elsif self.email==''
90 elsif self.email==''
91 "(blank)"
91 "(blank)"
92 else
92 else
93 self.email
93 self.email
94 end
94 end
95 end
95 end
96
96
97 def email_for_editing=(e)
97 def email_for_editing=(e)
98 self.email=e
98 self.email=e
99 end
99 end
100
100
101 def alias_for_editing
101 def alias_for_editing
102 if self.alias==nil
102 if self.alias==nil
103 "(unknown)"
103 "(unknown)"
104 elsif self.alias==''
104 elsif self.alias==''
105 "(blank)"
105 "(blank)"
106 else
106 else
107 self.alias
107 self.alias
108 end
108 end
109 end
109 end
110
110
111 def alias_for_editing=(e)
111 def alias_for_editing=(e)
112 self.alias=e
112 self.alias=e
113 end
113 end
114
114
115 def activation_key
115 def activation_key
116 if self.hashed_password==nil
116 if self.hashed_password==nil
117 encrypt_new_password
117 encrypt_new_password
118 end
118 end
119 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
119 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
120 end
120 end
121
121
122 def verify_activation_key(key)
122 def verify_activation_key(key)
123 key == activation_key
123 key == activation_key
124 end
124 end
125
125
126 def self.random_password(length=5)
126 def self.random_password(length=5)
127 chars = 'abcdefghjkmnopqrstuvwxyz'
127 chars = 'abcdefghjkmnopqrstuvwxyz'
128 password = ''
128 password = ''
129 length.times { password << chars[rand(chars.length - 1)] }
129 length.times { password << chars[rand(chars.length - 1)] }
130 password
130 password
131 end
131 end
132
132
133 def self.find_non_admin_with_prefix(prefix='')
133 def self.find_non_admin_with_prefix(prefix='')
134 users = User.all
134 users = User.all
135 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
135 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
136 end
136 end
137
137
138 # Contest information
138 # Contest information
139
139
140 def self.find_users_with_no_contest()
140 def self.find_users_with_no_contest()
141 users = User.all
141 users = User.all
142 return users.find_all { |u| u.contests.length == 0 }
142 return users.find_all { |u| u.contests.length == 0 }
143 end
143 end
144
144
145
145
146 def contest_time_left
146 def contest_time_left
147 if GraderConfiguration.contest_mode?
147 if GraderConfiguration.contest_mode?
148 return nil if site==nil
148 return nil if site==nil
149 return site.time_left
149 return site.time_left
150 elsif GraderConfiguration.indv_contest_mode?
150 elsif GraderConfiguration.indv_contest_mode?
151 time_limit = GraderConfiguration.contest_time_limit
151 time_limit = GraderConfiguration.contest_time_limit
152 if time_limit == nil
152 if time_limit == nil
153 return nil
153 return nil
154 end
154 end
155 if contest_stat==nil or contest_stat.started_at==nil
155 if contest_stat==nil or contest_stat.started_at==nil
156 return (Time.now.gmtime + time_limit) - Time.now.gmtime
156 return (Time.now.gmtime + time_limit) - Time.now.gmtime
157 else
157 else
158 finish_time = contest_stat.started_at + time_limit
158 finish_time = contest_stat.started_at + time_limit
159 current_time = Time.now.gmtime
159 current_time = Time.now.gmtime
160 if current_time > finish_time
160 if current_time > finish_time
161 return 0
161 return 0
162 else
162 else
163 return finish_time - current_time
163 return finish_time - current_time
164 end
164 end
165 end
165 end
166 else
166 else
167 return nil
167 return nil
168 end
168 end
169 end
169 end
170
170
171 def contest_finished?
171 def contest_finished?
172 if GraderConfiguration.contest_mode?
172 if GraderConfiguration.contest_mode?
173 return false if site==nil
173 return false if site==nil
174 return site.finished?
174 return site.finished?
175 elsif GraderConfiguration.indv_contest_mode?
175 elsif GraderConfiguration.indv_contest_mode?
176 - return false if self.contest_stat(true)==nil
176 + return false if self.contest_stat==nil
177 return contest_time_left == 0
177 return contest_time_left == 0
178 else
178 else
179 return false
179 return false
180 end
180 end
181 end
181 end
182
182
183 def contest_started?
183 def contest_started?
184 if GraderConfiguration.indv_contest_mode?
184 if GraderConfiguration.indv_contest_mode?
185 stat = self.contest_stat
185 stat = self.contest_stat
186 return ((stat != nil) and (stat.started_at != nil))
186 return ((stat != nil) and (stat.started_at != nil))
187 elsif GraderConfiguration.contest_mode?
187 elsif GraderConfiguration.contest_mode?
188 return true if site==nil
188 return true if site==nil
189 return site.started
189 return site.started
190 else
190 else
191 return true
191 return true
192 end
192 end
193 end
193 end
194
194
195 def update_start_time
195 def update_start_time
196 stat = self.contest_stat
196 stat = self.contest_stat
197 if stat.nil? or stat.started_at.nil?
197 if stat.nil? or stat.started_at.nil?
198 stat ||= UserContestStat.new(:user => self)
198 stat ||= UserContestStat.new(:user => self)
199 stat.started_at = Time.now.gmtime
199 stat.started_at = Time.now.gmtime
200 stat.save
200 stat.save
201 end
201 end
202 end
202 end
203
203
204 def problem_in_user_contests?(problem)
204 def problem_in_user_contests?(problem)
205 problem_contests = problem.contests.all
205 problem_contests = problem.contests.all
206
206
207 if problem_contests.length == 0 # this is public contest
207 if problem_contests.length == 0 # this is public contest
208 return true
208 return true
209 end
209 end
210
210
211 contests.each do |contest|
211 contests.each do |contest|
212 if problem_contests.find {|c| c.id == contest.id }
212 if problem_contests.find {|c| c.id == contest.id }
213 return true
213 return true
214 end
214 end
215 end
215 end
216 return false
216 return false
217 end
217 end
218
218
219 def available_problems_group_by_contests
219 def available_problems_group_by_contests
220 contest_problems = []
220 contest_problems = []
221 pin = {}
221 pin = {}
222 contests.enabled.each do |contest|
222 contests.enabled.each do |contest|
223 available_problems = contest.problems.available
223 available_problems = contest.problems.available
224 contest_problems << {
224 contest_problems << {
225 :contest => contest,
225 :contest => contest,
226 :problems => available_problems
226 :problems => available_problems
227 }
227 }
228 available_problems.each {|p| pin[p.id] = true}
228 available_problems.each {|p| pin[p.id] = true}
229 end
229 end
230 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
230 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
231 contest_problems << {
231 contest_problems << {
232 :contest => nil,
232 :contest => nil,
233 :problems => other_avaiable_problems
233 :problems => other_avaiable_problems
234 }
234 }
235 return contest_problems
235 return contest_problems
236 end
236 end
237
237
238 def solve_all_available_problems?
238 def solve_all_available_problems?
239 available_problems.each do |p|
239 available_problems.each do |p|
240 u = self
240 u = self
241 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
241 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
242 return false if !p or !sub or sub.points < p.full_score
242 return false if !p or !sub or sub.points < p.full_score
243 end
243 end
244 return true
244 return true
245 end
245 end
246
246
247 #get a list of available problem
247 #get a list of available problem
248 def available_problems
248 def available_problems
249 if not GraderConfiguration.multicontests?
249 if not GraderConfiguration.multicontests?
250 if GraderConfiguration.use_problem_group?
250 if GraderConfiguration.use_problem_group?
251 return available_problems_in_group
251 return available_problems_in_group
252 else
252 else
253 return Problem.available_problems
253 return Problem.available_problems
254 end
254 end
255 else
255 else
256 contest_problems = []
256 contest_problems = []
257 pin = {}
257 pin = {}
258 contests.enabled.each do |contest|
258 contests.enabled.each do |contest|
259 contest.problems.available.each do |problem|
259 contest.problems.available.each do |problem|
260 if not pin.has_key? problem.id
260 if not pin.has_key? problem.id
261 contest_problems << problem
261 contest_problems << problem
262 end
262 end
263 pin[problem.id] = true
263 pin[problem.id] = true
264 end
264 end
265 end
265 end
266 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
266 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
267 return contest_problems + other_avaiable_problems
267 return contest_problems + other_avaiable_problems
268 end
268 end
269 end
269 end
270
270
271 def available_problems_in_group
271 def available_problems_in_group
272 problem = []
272 problem = []
273 self.groups.each do |group|
273 self.groups.each do |group|
274 group.problems.where(available: true).each { |p| problem << p }
274 group.problems.where(available: true).each { |p| problem << p }
275 end
275 end
276 problem.uniq!
276 problem.uniq!
277 if problem
277 if problem
278 problem.sort! do |a,b|
278 problem.sort! do |a,b|
279 case
279 case
280 when a.date_added < b.date_added
280 when a.date_added < b.date_added
281 1
281 1
282 when a.date_added > b.date_added
282 when a.date_added > b.date_added
283 -1
283 -1
284 else
284 else
285 a.name <=> b.name
285 a.name <=> b.name
286 end
286 end
287 end
287 end
288 return problem
288 return problem
289 else
289 else
290 return []
290 return []
291 end
291 end
292 end
292 end
293
293
294 def can_view_problem?(problem)
294 def can_view_problem?(problem)
295 return true if admin?
295 return true if admin?
296 return available_problems.include? problem
296 return available_problems.include? problem
297 end
297 end
298
298
299 def self.clear_last_login
299 def self.clear_last_login
300 User.update_all(:last_ip => nil)
300 User.update_all(:last_ip => nil)
301 end
301 end
302
302
303 protected
303 protected
304 def encrypt_new_password
304 def encrypt_new_password
305 return if password.blank?
305 return if password.blank?
306 self.salt = (10+rand(90)).to_s
306 self.salt = (10+rand(90)).to_s
307 self.hashed_password = User.encrypt(self.password,self.salt)
307 self.hashed_password = User.encrypt(self.password,self.salt)
308 end
308 end
309
309
310 def assign_default_site
310 def assign_default_site
311 # have to catch error when migrating (because self.site is not available).
311 # have to catch error when migrating (because self.site is not available).
312 begin
312 begin
313 if self.site==nil
313 if self.site==nil
314 self.site = Site.find_by_name('default')
314 self.site = Site.find_by_name('default')
315 if self.site==nil
315 if self.site==nil
316 self.site = Site.find(1) # when 'default has be renamed'
316 self.site = Site.find(1) # when 'default has be renamed'
317 end
317 end
318 end
318 end
319 rescue
319 rescue
320 end
320 end
321 end
321 end
322
322
323 def assign_default_contest
323 def assign_default_contest
324 # have to catch error when migrating (because self.site is not available).
324 # have to catch error when migrating (because self.site is not available).
325 begin
325 begin
326 if self.contests.length == 0
326 if self.contests.length == 0
327 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
327 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
328 if default_contest
328 if default_contest
329 self.contests = [default_contest]
329 self.contests = [default_contest]
330 end
330 end
331 end
331 end
332 rescue
332 rescue
333 end
333 end
334 end
334 end
335
335
336 def password_required?
336 def password_required?
337 self.hashed_password.blank? || !self.password.blank?
337 self.hashed_password.blank? || !self.password.blank?
338 end
338 end
339
339
340 def self.encrypt(string,salt)
340 def self.encrypt(string,salt)
341 Digest::SHA1.hexdigest(salt + string)
341 Digest::SHA1.hexdigest(salt + string)
342 end
342 end
343
343
344 def uniqueness_of_email_from_activated_users
344 def uniqueness_of_email_from_activated_users
345 user = User.activated_users.find_by_email(self.email)
345 user = User.activated_users.find_by_email(self.email)
346 if user and (user.login != self.login)
346 if user and (user.login != self.login)
347 self.errors.add(:base,"Email has already been taken")
347 self.errors.add(:base,"Email has already been taken")
348 end
348 end
349 end
349 end
350
350
351 def enough_time_interval_between_same_email_registrations
351 def enough_time_interval_between_same_email_registrations
352 return if !self.new_record?
352 return if !self.new_record?
353 return if self.activated
353 return if self.activated
354 open_user = User.find_by_email(self.email,
354 open_user = User.find_by_email(self.email,
355 :order => 'created_at DESC')
355 :order => 'created_at DESC')
356 if open_user and open_user.created_at and
356 if open_user and open_user.created_at and
357 (open_user.created_at > Time.now.gmtime - 5.minutes)
357 (open_user.created_at > Time.now.gmtime - 5.minutes)
358 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
358 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
359 end
359 end
360 end
360 end
361
361
362 def email_validation?
362 def email_validation?
363 begin
363 begin
364 return VALIDATE_USER_EMAILS
364 return VALIDATE_USER_EMAILS
365 rescue
365 rescue
366 return false
366 return false
367 end
367 end
368 end
368 end
@@ -1,71 +1,72
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3
3
4 %h1 Import problems
4 %h1 Import problems
5
5
6 %p= link_to '[Back to problem list]', problems_path
6 %p= link_to '[Back to problem list]', problems_path
7
7
8 - if @problem and @problem.errors
8 - if @problem and @problem.errors
9 =error_messages_for 'problem'
9 =error_messages_for 'problem'
10
10
11 - = form_tag({:action => 'do_import'}, :multipart => true) do
11 + = simple_form_for :problem, url: do_import_problems_path, :multipart => true do |f|
12 +
12 .submitbox
13 .submitbox
13 %table
14 %table
14 %tr
15 %tr
15 %td Name:
16 %td Name:
16 %td= text_field_tag 'name'
17 %td= text_field_tag 'name'
17 %tr
18 %tr
18 %td Full name:
19 %td Full name:
19 %td
20 %td
20 = text_field_tag 'full_name'
21 = text_field_tag 'full_name'
21 %span{:class => 'help'} Leave blank to use the same value as the name above.
22 %span{:class => 'help'} Leave blank to use the same value as the name above.
22 %tr
23 %tr
23 %td Testdata file:
24 %td Testdata file:
24 %td= file_field_tag 'file'
25 %td= file_field_tag 'file'
25 %tr
26 %tr
26 %td
27 %td
27 %td
28 %td
28 %span{:class => 'help'}
29 %span{:class => 'help'}
29 In .zip, .tgz, tar.gz, .tar format.
30 In .zip, .tgz, tar.gz, .tar format.
30 It should includes inputs (e.g., 1.in, 2a.in, 2b.in)
31 It should includes inputs (e.g., 1.in, 2a.in, 2b.in)
31 and solutions (e.g., 1.sol, 2a.sol, 2b.sol).
32 and solutions (e.g., 1.sol, 2a.sol, 2b.sol).
32 %br/
33 %br/
33 You may put task description in *.html for raw html
34 You may put task description in *.html for raw html
34 and *.md or *.markdown for markdown.
35 and *.md or *.markdown for markdown.
35 %br/
36 %br/
36 You may also put a pdf file for the task description
37 You may also put a pdf file for the task description
37 %tr
38 %tr
38 %td Checker:
39 %td Checker:
39 %td= select_tag 'checker', options_for_select([['Text checker','text'],['Float checker','float']], 'text')
40 %td= select_tag 'checker', options_for_select([['Text checker','text'],['Float checker','float']], 'text')
40 %tr
41 %tr
41 %td
42 %td
42 %td
43 %td
43 %span{:class => 'help'}
44 %span{:class => 'help'}
44 "Text" checker checks if the text (including numbers) is the same, ignoring any whitespace
45 "Text" checker checks if the text (including numbers) is the same, ignoring any whitespace
45 %br/
46 %br/
46 "Float" checker checks if all numbers is within EPSILON error using formula |a-b| < EPSILON * max(|a|,|b|)
47 "Float" checker checks if all numbers is within EPSILON error using formula |a-b| < EPSILON * max(|a|,|b|)
47
48
48 - if @allow_test_pair_import
49 - if @allow_test_pair_import
49 %tr
50 %tr
50 %td
51 %td
51 %td
52 %td
52 = check_box_tag 'import_to_db'
53 = check_box_tag 'import_to_db'
53 Import test data to database (for a test-pair task)
54 Import test data to database (for a test-pair task)
54 %tr
55 %tr
55 %td Time limit:
56 %td Time limit:
56 %td
57 %td
57 = text_field_tag 'time_limit'
58 = text_field_tag 'time_limit'
58 %span{:class => 'help'} In seconds. Leave blank to use 1 sec.
59 %span{:class => 'help'} In seconds. Leave blank to use 1 sec.
59 %tr
60 %tr
60 %td Memory limit:
61 %td Memory limit:
61 %td
62 %td
62 = text_field_tag 'memory_limit'
63 = text_field_tag 'memory_limit'
63 %span{:class => 'help'} In MB. Leave blank to use 32MB.
64 %span{:class => 'help'} In MB. Leave blank to use 32MB.
64 %tr
65 %tr
65 %td
66 %td
66 %td= submit_tag 'Import problem'
67 %td= submit_tag 'Import problem'
67
68
68 - if @log
69 - if @log
69 %h3 Import log
70 %h3 Import log
70 %pre.import-log
71 %pre.import-log
71 = @log
72 = @log
@@ -1,49 +1,49
1 %h1 Maximum score
1 %h1 Maximum score
2
2
3 - = form_tag report_show_max_score_path
3 + = form_tag show_max_score_report_path
4 .row
4 .row
5 .col-md-4
5 .col-md-4
6 .panel.panel-primary
6 .panel.panel-primary
7 .panel-heading
7 .panel-heading
8 Problems
8 Problems
9 .panel-body
9 .panel-body
10 %p
10 %p
11 Select problem(s) that we wish to know the score.
11 Select problem(s) that we wish to know the score.
12 = label_tag :problem_id, "Problems"
12 = label_tag :problem_id, "Problems"
13 = select_tag 'problem_id[]',
13 = select_tag 'problem_id[]',
14 options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
14 options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
15 { class: 'select2 form-control', multiple: "true" }
15 { class: 'select2 form-control', multiple: "true" }
16 .col-md-4
16 .col-md-4
17 .panel.panel-primary
17 .panel.panel-primary
18 .panel-heading
18 .panel-heading
19 Submission range
19 Submission range
20 .panel-body
20 .panel-body
21 %p
21 %p
22 Input minimum and maximum range of submission ID that should be included. A blank value for min and max means -1 and infinity, respectively.
22 Input minimum and maximum range of submission ID that should be included. A blank value for min and max means -1 and infinity, respectively.
23 .form-group
23 .form-group
24 = label_tag :from, "Min"
24 = label_tag :from, "Min"
25 = text_field_tag 'from_id', @since_id, class: "form-control"
25 = text_field_tag 'from_id', @since_id, class: "form-control"
26 .form-group
26 .form-group
27 = label_tag :from, "Max"
27 = label_tag :from, "Max"
28 = text_field_tag 'to_id', @until_id, class: "form-control"
28 = text_field_tag 'to_id', @until_id, class: "form-control"
29 .col-md-4
29 .col-md-4
30 .panel.panel-primary
30 .panel.panel-primary
31 .panel-heading
31 .panel-heading
32 Users
32 Users
33 .panel-body
33 .panel-body
34 .radio
34 .radio
35 %label
35 %label
36 = radio_button_tag 'users', 'all', (params[:users] == "all")
36 = radio_button_tag 'users', 'all', (params[:users] == "all")
37 All users
37 All users
38 .radio
38 .radio
39 %label
39 %label
40 = radio_button_tag 'users', 'enabled', (params[:users] == "enabled")
40 = radio_button_tag 'users', 'enabled', (params[:users] == "enabled")
41 Only enabled users
41 Only enabled users
42 .row
42 .row
43 .col-md-12
43 .col-md-12
44 = button_tag 'Show', class: "btn btn-primary btn-large", value: "show"
44 = button_tag 'Show', class: "btn btn-primary btn-large", value: "show"
45 = button_tag 'Download CSV', class: "btn btn-primary btn-large", value: "download"
45 = button_tag 'Download CSV', class: "btn btn-primary btn-large", value: "download"
46
46
47 - if @scorearray
47 - if @scorearray
48 %h2 Result
48 %h2 Result
49 =render "score_table"
49 =render "score_table"
@@ -1,256 +1,257
1 %h2 Live submit
1 %h2 Live submit
2 %br
2 %br
3
3
4 %textarea#text_sourcecode{style: "display:none"}~ @source
4 %textarea#text_sourcecode{style: "display:none"}~ @source
5 .container
5 .container
6 .row
6 .row
7 .col-md-12
7 .col-md-12
8 .alert.alert-info
8 .alert.alert-info
9 Write your code in the following box, choose language, and click submit button when finished
9 Write your code in the following box, choose language, and click submit button when finished
10 .row
10 .row
11 .col-md-8
11 .col-md-8
12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
13 .col-md-4
13 .col-md-4
14 - # submission form
14 - # submission form
15 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
15 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
16
16
17 = hidden_field_tag 'editor_text', @source
17 = hidden_field_tag 'editor_text', @source
18 = hidden_field_tag 'submission[problem_id]', @problem.id
18 = hidden_field_tag 'submission[problem_id]', @problem.id
19 .form-group
19 .form-group
20 = label_tag "Task:"
20 = label_tag "Task:"
21 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
21 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
22 .form-group
22 .form-group
23 = label_tag "Description:"
23 = label_tag "Description:"
24 = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem
24 = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem
25
25
26 .form-group
26 .form-group
27 = label_tag 'Language:'
27 = label_tag 'Language:'
28 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
28 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
29 .form-group
29 .form-group
30 .input-group
30 .input-group
31 %span.input-group-btn
31 %span.input-group-btn
32 %span.btn.btn-default.btn-file
32 %span.btn.btn-default.btn-file
33 Browse
33 Browse
34 = file_field_tag 'load_file'
34 = file_field_tag 'load_file'
35 = text_field_tag '' , nil, {readonly: true, class: 'form-control'}
35 = text_field_tag '' , nil, {readonly: true, class: 'form-control'}
36 .form-group
36 .form-group
37 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
37 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
38 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
38 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
39 - # latest submission status
39 - # latest submission status
40 .panel{class: (@submission && @submission.graded_at) ? "panel-info" : "panel-warning"}
40 .panel{class: (@submission && @submission.graded_at) ? "panel-info" : "panel-warning"}
41 .panel-heading
41 .panel-heading
42 Latest Submission Status
42 Latest Submission Status
43 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
43 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
44 .panel-body
44 .panel-body
45 %div#latest_status
45 %div#latest_status
46 - if @submission
46 - if @submission
47 = render :partial => 'submission_short',
47 = render :partial => 'submission_short',
48 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
48 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
49 .row
49 .row
50 .col-md-12
50 .col-md-12
51 %h2 Console
51 %h2 Console
52 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
52 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
53
53
54 - .modal.fade#compiler{tabindex: -1,role: 'dialog'}
54 + - if @submission
55 - .modal-dialog.modal-lg{role:'document'}
55 + .modal.fade#compiler{tabindex: -1,role: 'dialog'}
56 - .modal-content
56 + .modal-dialog.modal-lg{role:'document'}
57 - .modal-header
57 + .modal-content
58 - %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
58 + .modal-header
59 - %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
59 + %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
60 - %h4 Compiler message
60 + %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
61 - .modal-body
61 + %h4 Compiler message
62 - %pre#compiler_msg= @submission.compiler_message
62 + .modal-body
63 - .modal-footer
63 + %pre#compiler_msg= @submission.compiler_message
64 - %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
64 + .modal-footer
65 + %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
65
66
66 :javascript
67 :javascript
67 $(document).ready(function() {
68 $(document).ready(function() {
68 e = ace.edit("editor")
69 e = ace.edit("editor")
69 e.setValue($("#text_sourcecode").val());
70 e.setValue($("#text_sourcecode").val());
70 e.gotoLine(1);
71 e.gotoLine(1);
71 $("#language_id").trigger('change');
72 $("#language_id").trigger('change');
72
73
73 $("#load_file").on('change',function(evt) {
74 $("#load_file").on('change',function(evt) {
74 var file = evt.target.files[0];
75 var file = evt.target.files[0];
75 var reader = new FileReader();
76 var reader = new FileReader();
76 reader.onload = function(theFile) {
77 reader.onload = function(theFile) {
77 var e = ace.edit("editor")
78 var e = ace.edit("editor")
78 e.setValue(theFile.target.result);
79 e.setValue(theFile.target.result);
79 e.gotoLine(1);
80 e.gotoLine(1);
80 };
81 };
81 reader.readAsText(file)
82 reader.readAsText(file)
82 });
83 });
83
84
84 //brython();
85 //brython();
85 });
86 });
86
87
87
88
88
89
89
90
90
91
91 %script#__main__{type:'text/python3'}
92 %script#__main__{type:'text/python3'}
92 :plain
93 :plain
93 import sys
94 import sys
94 import traceback
95 import traceback
95
96
96 from browser import document as doc
97 from browser import document as doc
97 from browser import window, alert, console
98 from browser import window, alert, console
98
99
99 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
100 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
100 for supporting Python development. See www.python.org for more information."""
101 for supporting Python development. See www.python.org for more information."""
101
102
102 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
103 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
103 All Rights Reserved.
104 All Rights Reserved.
104
105
105 Copyright (c) 2001-2013 Python Software Foundation.
106 Copyright (c) 2001-2013 Python Software Foundation.
106 All Rights Reserved.
107 All Rights Reserved.
107
108
108 Copyright (c) 2000 BeOpen.com.
109 Copyright (c) 2000 BeOpen.com.
109 All Rights Reserved.
110 All Rights Reserved.
110
111
111 Copyright (c) 1995-2001 Corporation for National Research Initiatives.
112 Copyright (c) 1995-2001 Corporation for National Research Initiatives.
112 All Rights Reserved.
113 All Rights Reserved.
113
114
114 Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
115 Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
115 All Rights Reserved."""
116 All Rights Reserved."""
116
117
117 _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
118 _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
118 All rights reserved.
119 All rights reserved.
119
120
120 Redistribution and use in source and binary forms, with or without
121 Redistribution and use in source and binary forms, with or without
121 modification, are permitted provided that the following conditions are met:
122 modification, are permitted provided that the following conditions are met:
122
123
123 Redistributions of source code must retain the above copyright notice, this
124 Redistributions of source code must retain the above copyright notice, this
124 list of conditions and the following disclaimer. Redistributions in binary
125 list of conditions and the following disclaimer. Redistributions in binary
125 form must reproduce the above copyright notice, this list of conditions and
126 form must reproduce the above copyright notice, this list of conditions and
126 the following disclaimer in the documentation and/or other materials provided
127 the following disclaimer in the documentation and/or other materials provided
127 with the distribution.
128 with the distribution.
128 Neither the name of the <ORGANIZATION> nor the names of its contributors may
129 Neither the name of the <ORGANIZATION> nor the names of its contributors may
129 be used to endorse or promote products derived from this software without
130 be used to endorse or promote products derived from this software without
130 specific prior written permission.
131 specific prior written permission.
131
132
132 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
133 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
133 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
134 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
134 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
135 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
135 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
136 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
136 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
137 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
137 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
138 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
138 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
139 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
139 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
140 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
140 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
141 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
141 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
142 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
142 POSSIBILITY OF SUCH DAMAGE.
143 POSSIBILITY OF SUCH DAMAGE.
143 """
144 """
144
145
145 def credits():
146 def credits():
146 print(_credits)
147 print(_credits)
147 credits.__repr__ = lambda:_credits
148 credits.__repr__ = lambda:_credits
148
149
149 def copyright():
150 def copyright():
150 print(_copyright)
151 print(_copyright)
151 copyright.__repr__ = lambda:_copyright
152 copyright.__repr__ = lambda:_copyright
152
153
153 def license():
154 def license():
154 print(_license)
155 print(_license)
155 license.__repr__ = lambda:_license
156 license.__repr__ = lambda:_license
156
157
157 def write(data):
158 def write(data):
158 doc['console'].value += str(data)
159 doc['console'].value += str(data)
159
160
160
161
161 sys.stdout.write = sys.stderr.write = write
162 sys.stdout.write = sys.stderr.write = write
162 history = []
163 history = []
163 current = 0
164 current = 0
164 _status = "main" # or "block" if typing inside a block
165 _status = "main" # or "block" if typing inside a block
165
166
166 # execution namespace
167 # execution namespace
167 editor_ns = {'credits':credits,
168 editor_ns = {'credits':credits,
168 'copyright':copyright,
169 'copyright':copyright,
169 'license':license,
170 'license':license,
170 '__name__':'__main__'}
171 '__name__':'__main__'}
171
172
172 def cursorToEnd(*args):
173 def cursorToEnd(*args):
173 pos = len(doc['console'].value)
174 pos = len(doc['console'].value)
174 doc['console'].setSelectionRange(pos, pos)
175 doc['console'].setSelectionRange(pos, pos)
175 doc['console'].scrollTop = doc['console'].scrollHeight
176 doc['console'].scrollTop = doc['console'].scrollHeight
176
177
177 def get_col(area):
178 def get_col(area):
178 # returns the column num of cursor
179 # returns the column num of cursor
179 sel = doc['console'].selectionStart
180 sel = doc['console'].selectionStart
180 lines = doc['console'].value.split('\n')
181 lines = doc['console'].value.split('\n')
181 for line in lines[:-1]:
182 for line in lines[:-1]:
182 sel -= len(line) + 1
183 sel -= len(line) + 1
183 return sel
184 return sel
184
185
185
186
186 def myKeyPress(event):
187 def myKeyPress(event):
187 global _status, current
188 global _status, current
188 if event.keyCode == 9: # tab key
189 if event.keyCode == 9: # tab key
189 event.preventDefault()
190 event.preventDefault()
190 doc['console'].value += " "
191 doc['console'].value += " "
191 elif event.keyCode == 13: # return
192 elif event.keyCode == 13: # return
192 src = doc['console'].value
193 src = doc['console'].value
193 if _status == "main":
194 if _status == "main":
194 currentLine = src[src.rfind('>>>') + 4:]
195 currentLine = src[src.rfind('>>>') + 4:]
195 elif _status == "3string":
196 elif _status == "3string":
196 currentLine = src[src.rfind('>>>') + 4:]
197 currentLine = src[src.rfind('>>>') + 4:]
197 currentLine = currentLine.replace('\n... ', '\n')
198 currentLine = currentLine.replace('\n... ', '\n')
198 else:
199 else:
199 currentLine = src[src.rfind('...') + 4:]
200 currentLine = src[src.rfind('...') + 4:]
200 if _status == 'main' and not currentLine.strip():
201 if _status == 'main' and not currentLine.strip():
201 doc['console'].value += '\n>>> '
202 doc['console'].value += '\n>>> '
202 event.preventDefault()
203 event.preventDefault()
203 return
204 return
204 doc['console'].value += '\n'
205 doc['console'].value += '\n'
205 history.append(currentLine)
206 history.append(currentLine)
206 current = len(history)
207 current = len(history)
207 if _status == "main" or _status == "3string":
208 if _status == "main" or _status == "3string":
208 try:
209 try:
209 _ = editor_ns['_'] = eval(currentLine, editor_ns)
210 _ = editor_ns['_'] = eval(currentLine, editor_ns)
210 if _ is not None:
211 if _ is not None:
211 write(repr(_)+'\n')
212 write(repr(_)+'\n')
212 doc['console'].value += '>>> '
213 doc['console'].value += '>>> '
213 _status = "main"
214 _status = "main"
214 except IndentationError:
215 except IndentationError:
215 doc['console'].value += '... '
216 doc['console'].value += '... '
216 _status = "block"
217 _status = "block"
217 except SyntaxError as msg:
218 except SyntaxError as msg:
218 if str(msg) == 'invalid syntax : triple string end not found' or \
219 if str(msg) == 'invalid syntax : triple string end not found' or \
219 str(msg).startswith('Unbalanced bracket'):
220 str(msg).startswith('Unbalanced bracket'):
220 doc['console'].value += '... '
221 doc['console'].value += '... '
221 _status = "3string"
222 _status = "3string"
222 elif str(msg) == 'eval() argument must be an expression':
223 elif str(msg) == 'eval() argument must be an expression':
223 try:
224 try:
224 exec(currentLine, editor_ns)
225 exec(currentLine, editor_ns)
225 except:
226 except:
226 traceback.print_exc()
227 traceback.print_exc()
227 doc['console'].value += '>>> '
228 doc['console'].value += '>>> '
228 _status = "main"
229 _status = "main"
229 elif str(msg) == 'decorator expects function':
230 elif str(msg) == 'decorator expects function':
230 doc['console'].value += '... '
231 doc['console'].value += '... '
231 _status = "block"
232 _status = "block"
232 else:
233 else:
233 traceback.print_exc()
234 traceback.print_exc()
234 doc['console'].value += '>>> '
235 doc['console'].value += '>>> '
235 _status = "main"
236 _status = "main"
236 except:
237 except:
237 traceback.print_exc()
238 traceback.print_exc()
238 doc['console'].value += '>>> '
239 doc['console'].value += '>>> '
239 _status = "main"
240 _status = "main"
240 elif currentLine == "": # end of block
241 elif currentLine == "": # end of block
241 block = src[src.rfind('>>>') + 4:].splitlines()
242 block = src[src.rfind('>>>') + 4:].splitlines()
242 block = [block[0]] + [b[4:] for b in block[1:]]
243 block = [block[0]] + [b[4:] for b in block[1:]]
243 block_src = '\n'.join(block)
244 block_src = '\n'.join(block)
244 # status must be set before executing code in globals()
245 # status must be set before executing code in globals()
245 _status = "main"
246 _status = "main"
246 try:
247 try:
247 _ = exec(block_src, editor_ns)
248 _ = exec(block_src, editor_ns)
248 if _ is not None:
249 if _ is not None:
249 print(repr(_))
250 print(repr(_))
250 except:
251 except:
251 traceback.print_exc()
252 traceback.print_exc()
252 doc['console'].value += '>>> '
253 doc['console'].value += '>>> '
253 else:
254 else:
254 doc['console'].value += '... '
255 doc['console'].value += '... '
255
256
256 cursorToEnd()
257 cursorToEnd()
@@ -1,171 +1,174
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
10
11 resources :contests
11 resources :contests
12
12
13 resources :sites
13 resources :sites
14
14
15 resources :test
15 resources :test
16
16
17 resources :messages do
17 resources :messages do
18 collection do
18 collection do
19 get 'console'
19 get 'console'
20 end
20 end
21 end
21 end
22
22
23 resources :announcements do
23 resources :announcements do
24 member do
24 member do
25 get 'toggle','toggle_front'
25 get 'toggle','toggle_front'
26 end
26 end
27 end
27 end
28
28
29 resources :problems do
29 resources :problems do
30 member do
30 member do
31 get 'toggle'
31 get 'toggle'
32 get 'toggle_test'
32 get 'toggle_test'
33 get 'toggle_view_testcase'
33 get 'toggle_view_testcase'
34 get 'stat'
34 get 'stat'
35 end
35 end
36 collection do
36 collection do
37 get 'turn_all_off'
37 get 'turn_all_off'
38 get 'turn_all_on'
38 get 'turn_all_on'
39 get 'import'
39 get 'import'
40 get 'manage'
40 get 'manage'
41 get 'quick_create'
41 get 'quick_create'
42 post 'do_manage'
42 post 'do_manage'
43 + post 'do_import'
43 end
44 end
44 end
45 end
45
46
46 resources :groups do
47 resources :groups do
47 member do
48 member do
48 post 'add_user', to: 'groups#add_user', as: 'add_user'
49 post 'add_user', to: 'groups#add_user', as: 'add_user'
49 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
50 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
50 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
51 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
51 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
52 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
52 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
53 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
53 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
54 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
54 end
55 end
55 collection do
56 collection do
56
57
57 end
58 end
58 end
59 end
59
60
60 resources :testcases, only: [] do
61 resources :testcases, only: [] do
61 member do
62 member do
62 get 'download_input'
63 get 'download_input'
63 get 'download_sol'
64 get 'download_sol'
64 end
65 end
65 collection do
66 collection do
66 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
67 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
67 end
68 end
68 end
69 end
69
70
70 resources :grader_configuration, controller: 'configurations'
71 resources :grader_configuration, controller: 'configurations'
71
72
72 resources :users do
73 resources :users do
73 member do
74 member do
74 get 'toggle_activate', 'toggle_enable'
75 get 'toggle_activate', 'toggle_enable'
75 get 'stat'
76 get 'stat'
76 end
77 end
77 end
78 end
78
79
79 resources :submissions do
80 resources :submissions do
80 member do
81 member do
81 get 'download'
82 get 'download'
82 get 'compiler_msg'
83 get 'compiler_msg'
83 get 'rejudge'
84 get 'rejudge'
85 + get 'source'
84 end
86 end
85 collection do
87 collection do
86 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
88 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
87 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
89 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
88 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
90 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
89 end
91 end
90 end
92 end
91
93
92
94
93 #user admin
95 #user admin
94 resources :user_admin do
96 resources :user_admin do
95 collection do
97 collection do
96 match 'bulk_manage', via: [:get, :post]
98 match 'bulk_manage', via: [:get, :post]
97 get 'bulk_mail'
99 get 'bulk_mail'
98 get 'user_stat'
100 get 'user_stat'
99 get 'import'
101 get 'import'
100 get 'new_list'
102 get 'new_list'
101 get 'admin'
103 get 'admin'
102 get 'active'
104 get 'active'
103 get 'mass_mailing'
105 get 'mass_mailing'
104 post 'grant_admin'
106 post 'grant_admin'
105 match 'create_from_list', via: [:get, :post]
107 match 'create_from_list', via: [:get, :post]
106 match 'random_all_passwords', via: [:get, :post]
108 match 'random_all_passwords', via: [:get, :post]
107 end
109 end
108 member do
110 member do
109 get 'clear_last_ip'
111 get 'clear_last_ip'
110 end
112 end
111 end
113 end
112
114
113 resources :contest_management, only: [:index] do
115 resources :contest_management, only: [:index] do
114 collection do
116 collection do
115 get 'user_stat'
117 get 'user_stat'
116 get 'clear_stat'
118 get 'clear_stat'
117 get 'clear_all_stat'
119 get 'clear_all_stat'
120 + get 'change_contest_mode'
118 end
121 end
119 end
122 end
120
123
121 #get 'user_admin', to: 'user_admin#index'
124 #get 'user_admin', to: 'user_admin#index'
122 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
125 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
123 #post 'user_admin', to: 'user_admin#create'
126 #post 'user_admin', to: 'user_admin#create'
124 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
127 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
125
128
126 #singular resource
129 #singular resource
127 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
130 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
128 #report
131 #report
129 resource :report, only: [], controller: 'report' do
132 resource :report, only: [], controller: 'report' do
130 get 'login'
133 get 'login'
131 get 'multiple_login'
134 get 'multiple_login'
132 get 'problem_hof/:id', action: 'problem_hof'
135 get 'problem_hof/:id', action: 'problem_hof'
133 get 'current_score'
136 get 'current_score'
134 get 'max_score'
137 get 'max_score'
135 post 'show_max_score'
138 post 'show_max_score'
136 end
139 end
137 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
140 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
138 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
141 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
139 #get "report/login"
142 #get "report/login"
140 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
143 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
141 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
144 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
142
145
143 resource :main, only: [], controller: 'main' do
146 resource :main, only: [], controller: 'main' do
144 get 'list'
147 get 'list'
145 get 'submission(/:id)', action: 'submission', as: 'main_submission'
148 get 'submission(/:id)', action: 'submission', as: 'main_submission'
146 post 'submit'
149 post 'submit'
147 get 'announcements'
150 get 'announcements'
148 get 'help'
151 get 'help'
149 end
152 end
150 #main
153 #main
151 #get "main/list"
154 #get "main/list"
152 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
155 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
153 #post 'main/submit', to: 'main#submit'
156 #post 'main/submit', to: 'main#submit'
154 #get 'main/announcements', to: 'main#announcements'
157 #get 'main/announcements', to: 'main#announcements'
155
158
156
159
157 #
160 #
158 get 'tasks/view/:file.:ext' => 'tasks#view'
161 get 'tasks/view/:file.:ext' => 'tasks#view'
159 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
162 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
160 get 'heartbeat/:id/edit' => 'heartbeat#edit'
163 get 'heartbeat/:id/edit' => 'heartbeat#edit'
161
164
162 #grader
165 #grader
163 get 'graders/list', to: 'graders#list', as: 'grader_list'
166 get 'graders/list', to: 'graders#list', as: 'grader_list'
164
167
165
168
166 # See how all your routes lay out with "rake routes"
169 # See how all your routes lay out with "rake routes"
167
170
168 # This is a legacy wild controller route that's not recommended for RESTful applications.
171 # This is a legacy wild controller route that's not recommended for RESTful applications.
169 # Note: This route will make all actions in every controller accessible via GET requests.
172 # Note: This route will make all actions in every controller accessible via GET requests.
170 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
173 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
171 end
174 end
You need to be logged in to leave comments. Login now