Description:
added contest problem access control
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r282:6dab27215603 - - 5 files changed: 77 inserted, 18 deleted

@@ -1,60 +1,75
1 class TasksController < ApplicationController
1 class TasksController < ApplicationController
2
2
3 before_filter :authenticate, :check_viewability
3 before_filter :authenticate, :check_viewability
4
4
5 def index
5 def index
6 redirect_to :action => 'list'
6 redirect_to :action => 'list'
7 end
7 end
8
8
9 def list
9 def list
10 @problems = Problem.find_available_problems
10 @problems = Problem.find_available_problems
11 - @user = User.find(session[:user_id])
12 end
11 end
13
12
13 + # this has contest-wide access control
14 def view
14 def view
15 base_name = params[:file]
15 base_name = params[:file]
16 - if !check_user_viewability(base_name)
16 + base_filename = File.basename("#{base_name}.#{params[:ext]}")
17 + filename = "#{Problem.download_file_basedir}/#{base_filename}"
18 +
19 + if !FileTest.exists?(filename)
17 redirect_to :action => 'index' and return
20 redirect_to :action => 'index' and return
18 end
21 end
19
22
20 - base_filename = File.basename("#{base_name}.#{params[:ext]}")
23 + send_file_to_user(filename, base_filename)
21 - filename = "#{Problem.download_file_basedir}/#{base_filename}"
24 + end
22
25
23 - if !check_user_viewability(base_name) or !FileTest.exists?(filename)
26 + # this has problem-level access control
27 + def download
28 + problem = Problem.find(params[:id])
29 + if !problem or !problem.available or !@user.can_view_problem? problem
24 redirect_to :action => 'index' and return
30 redirect_to :action => 'index' and return
25 end
31 end
26
32
33 + base_name = params[:file]
34 + base_filename = File.basename("#{base_name}.#{params[:ext]}")
35 + filename = "#{Problem.download_file_basedir}/#{params[:id]}/#{base_filename}"
36 + puts "SENDING: #{filename}"
37 +
38 + if !FileTest.exists?(filename)
39 + redirect_to :action => 'index' and return
40 + end
41 +
42 + puts "SENDING: #{filename}"
43 +
44 + send_file_to_user(filename, base_filename)
45 + end
46 +
47 + protected
48 +
49 + def send_file_to_user(filename, base_filename)
27 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
50 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
28 response.headers['Content-Type'] = "application/force-download"
51 response.headers['Content-Type'] = "application/force-download"
29 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
52 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
30 response.headers["X-Sendfile"] = filename
53 response.headers["X-Sendfile"] = filename
31 response.headers['Content-length'] = File.size(filename)
54 response.headers['Content-length'] = File.size(filename)
32 render :nothing => true
55 render :nothing => true
33 else
56 else
34 if params[:ext]=='pdf'
57 if params[:ext]=='pdf'
35 content_type = 'application/pdf'
58 content_type = 'application/pdf'
36 else
59 else
37 content_type = 'application/octet-stream'
60 content_type = 'application/octet-stream'
38 end
61 end
39
62
40 send_file filename, :stream => false, :filename => base_filename, :type => content_type
63 send_file filename, :stream => false, :filename => base_filename, :type => content_type
41 end
64 end
42 end
65 end
43
66
44 - protected
45 -
46 def check_viewability
67 def check_viewability
47 @user = User.find(session[:user_id])
68 @user = User.find(session[:user_id])
48 if @user==nil or !Configuration.show_tasks_to?(@user)
69 if @user==nil or !Configuration.show_tasks_to?(@user)
49 redirect_to :controller => 'main', :action => 'list'
70 redirect_to :controller => 'main', :action => 'list'
50 return false
71 return false
51 end
72 end
52 end
73 end
53
74
54 - def check_user_viewability(filename)
55 - # individual file access control shall be added here
56 - return false if not @user
57 - return Configuration.show_tasks_to?(@user)
58 - end
59 -
60 end
75 end
@@ -1,18 +1,19
1 module MainHelper
1 module MainHelper
2
2
3 def link_to_description_if_any(name, problem, options={})
3 def link_to_description_if_any(name, problem, options={})
4 if !problem.url.blank?
4 if !problem.url.blank?
5 return link_to name, problem.url, options
5 return link_to name, problem.url, options
6 elsif !problem.description_filename.blank?
6 elsif !problem.description_filename.blank?
7 basename, ext = problem.description_filename.split('.')
7 basename, ext = problem.description_filename.split('.')
8 options[:controller] = 'tasks'
8 options[:controller] = 'tasks'
9 - options[:action] = 'view'
9 + options[:action] = 'download'
10 + options[:id] = problem.id
10 options[:file] = basename
11 options[:file] = basename
11 options[:ext] = ext
12 options[:ext] = ext
12 return link_to name, options
13 return link_to name, options
13 else
14 else
14 return ''
15 return ''
15 end
16 end
16 end
17 end
17
18
18 end
19 end
@@ -173,24 +173,47
173 end
173 end
174 end
174 end
175
175
176 def update_start_time
176 def update_start_time
177 stat = self.contest_stat
177 stat = self.contest_stat
178 if stat == nil
178 if stat == nil
179 stat = UserContestStat.new(:user => self,
179 stat = UserContestStat.new(:user => self,
180 :started_at => Time.now.gmtime)
180 :started_at => Time.now.gmtime)
181 stat.save
181 stat.save
182 end
182 end
183 end
183 end
184
184
185 + def problem_in_user_contests?(problem)
186 + problem_contests = problem.contests.all
187 +
188 + if problem_contests.length == 0 # this is public contest
189 + return true
190 + end
191 +
192 + contests.each do |contest|
193 + if problem_contests.find {|c| c.id == contest.id }
194 + return true
195 + end
196 + end
197 + return false
198 + end
199 +
200 + def can_view_problem?(problem)
201 + if not Configuration.multicontests?
202 + return problem.available
203 + else
204 + return problem_in_user_contests? problem
205 + end
206 + end
207 +
185 protected
208 protected
186 def encrypt_new_password
209 def encrypt_new_password
187 return if password.blank?
210 return if password.blank?
188 self.salt = (10+rand(90)).to_s
211 self.salt = (10+rand(90)).to_s
189 self.hashed_password = User.encrypt(self.password,self.salt)
212 self.hashed_password = User.encrypt(self.password,self.salt)
190 end
213 end
191
214
192 def assign_default_site
215 def assign_default_site
193 # have to catch error when migrating (because self.site is not available).
216 # have to catch error when migrating (because self.site is not available).
194 begin
217 begin
195 if self.site==nil
218 if self.site==nil
196 self.site = Site.find_by_name('default')
219 self.site = Site.find_by_name('default')
@@ -14,17 +14,18
14 # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
14 # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
15 # This route can be invoked with purchase_url(:id => product.id)
15 # This route can be invoked with purchase_url(:id => product.id)
16
16
17 # You can have the root of your site routed by hooking up ''
17 # You can have the root of your site routed by hooking up ''
18 # -- just remember to delete public/index.html.
18 # -- just remember to delete public/index.html.
19 map.connect '', :controller => 'main', :action => 'login'
19 map.connect '', :controller => 'main', :action => 'login'
20
20
21 # Allow downloading Web Service WSDL as a file with an extension
21 # Allow downloading Web Service WSDL as a file with an extension
22 # instead of a file named 'wsdl'
22 # instead of a file named 'wsdl'
23 map.connect ':controller/service.wsdl', :action => 'wsdl'
23 map.connect ':controller/service.wsdl', :action => 'wsdl'
24
24
25 map.connect 'tasks/view/:file.:ext', :controller => 'tasks', :action => 'view'
25 map.connect 'tasks/view/:file.:ext', :controller => 'tasks', :action => 'view'
26 + map.connect 'tasks/download/:id/:file.:ext', :controller => 'tasks', :action => 'download'
26
27
27 # Install the default route as the lowest priority.
28 # Install the default route as the lowest priority.
28 map.connect ':controller/:action/:id.:format'
29 map.connect ':controller/:action/:id.:format'
29 map.connect ':controller/:action/:id'
30 map.connect ':controller/:action/:id'
30 end
31 end
@@ -42,28 +42,33
42
42
43 def self.long_ext(filename)
43 def self.long_ext(filename)
44 i = filename.index('.')
44 i = filename.index('.')
45 len = filename.length
45 len = filename.length
46 return filename.slice(i..len)
46 return filename.slice(i..len)
47 end
47 end
48
48
49 def extract(tempfile)
49 def extract(tempfile)
50 testdata_filename = save_testdata_file(tempfile)
50 testdata_filename = save_testdata_file(tempfile)
51 ext = TestdataImporter.long_ext(tempfile.original_filename)
51 ext = TestdataImporter.long_ext(tempfile.original_filename)
52
52
53 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
53 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
54 - begin
54 + if File.exists? extract_dir
55 - Dir.mkdir extract_dir
55 + backup_count = 0
56 - rescue Errno::EEXIST
56 + begin
57 + backup_count += 1
58 + backup_dirname = "#{extract_dir}.backup.#{backup_count}"
59 + end while File.exists? backup_dirname
60 + File.rename(extract_dir, backup_dirname)
57 end
61 end
62 + Dir.mkdir extract_dir
58
63
59 if ext=='.tar.gz' or ext=='.tgz'
64 if ext=='.tar.gz' or ext=='.tgz'
60 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
65 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
61 elsif ext=='.tar'
66 elsif ext=='.tar'
62 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
67 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
63 elsif ext=='.zip'
68 elsif ext=='.zip'
64 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
69 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
65 else
70 else
66 return nil
71 return nil
67 end
72 end
68
73
69 system(cmd)
74 system(cmd)
@@ -129,25 +134,39
129 description.body = open(filename).read
134 description.body = open(filename).read
130 description.save
135 description.save
131 @problem.description = description
136 @problem.description = description
132 @problem.save
137 @problem.save
133 return "\nProblem description imported from #{filename}."
138 return "\nProblem description imported from #{filename}."
134 else
139 else
135 return ''
140 return ''
136 end
141 end
137 end
142 end
138
143
139 def import_problem_pdf(dirname)
144 def import_problem_pdf(dirname)
140 pdf_files = Dir["#{dirname}/*.pdf"]
145 pdf_files = Dir["#{dirname}/*.pdf"]
146 + puts "CHECKING... #{dirname}"
141 if pdf_files.length != 0
147 if pdf_files.length != 0
148 + puts "HAS PDF FILE"
142 filename = pdf_files[0]
149 filename = pdf_files[0]
143 - out_filename = "#{Problem.download_file_basedir}/#{@problem.name}.pdf"
150 +
151 + @problem.save if not @problem.id
152 + out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
153 + if not FileTest.exists? out_dirname
154 + Dir.mkdir out_dirname
155 + end
156 +
157 + out_filename = "#{out_dirname}/#{@problem.name}.pdf"
158 +
159 + if FileTest.exists? out_filename
160 + File.delete out_filename
161 + end
162 +
144 File.rename(filename, out_filename)
163 File.rename(filename, out_filename)
145 @problem.description_filename = "#{@problem.name}.pdf"
164 @problem.description_filename = "#{@problem.name}.pdf"
146 @problem.save
165 @problem.save
147 return "\nProblem pdf imported from #{filename}."
166 return "\nProblem pdf imported from #{filename}."
148 else
167 else
149 return ""
168 return ""
150 end
169 end
151 end
170 end
152
171
153 end
172 end
You need to be logged in to leave comments. Login now