1 class TraceController < ApplicationController
4 before_filter :authorize_web
5 before_filter :require_user, :only => [:mine, :edit, :delete, :make_public]
6 before_filter :authorize, :only => [:api_details, :api_data, :api_create]
7 before_filter :check_database_readable, :except => [:api_details, :api_data, :api_create]
8 before_filter :check_database_writable, :only => [:create, :edit, :delete, :make_public]
9 before_filter :check_api_readable, :only => [:api_details, :api_data]
10 before_filter :check_api_writable, :only => [:api_create]
12 # Counts and selects pages of GPX traces for various criteria (by user, tags, public etc.).
13 # target_user - if set, specifies the user to fetch traces for. if not set will fetch all traces
14 def list(target_user = nil, action = "list")
15 # from display name, pick up user id if one user's traces only
16 display_name = params[:display_name]
17 if target_user.nil? and !display_name.blank?
18 target_user = User.find(:first, :conditions => [ "visible = 1 and display_name = ?", display_name])
23 @title = "Public GPS traces"
24 elsif @user and @user == target_user
25 @title = "Your GPS traces"
27 @title = "Public GPS traces from #{target_user.display_name}"
30 @title += " tagged with #{params[:tag]}" if params[:tag]
33 # 1 - all traces, logged in = all public traces + all user's (i.e + all mine)
34 # 2 - all traces, not logged in = all public traces
35 # 3 - user's traces, logged in as same user = all user's traces
36 # 4 - user's traces, not logged in as that user = all user's public traces
37 if target_user.nil? # all traces
39 conditions = ["(gpx_files.public = 1 OR gpx_files.user_id = ?)", @user.id] #1
41 conditions = ["gpx_files.public = 1"] #2
44 if @user and @user == target_user
45 conditions = ["gpx_files.user_id = ?", @user.id] #3 (check vs user id, so no join + can't pick up non-public traces by changing name)
47 conditions = ["gpx_files.public = 1 AND gpx_files.user_id = ?", target_user.id] #4
54 files = Tracetag.find_all_by_tag(params[:tag]).collect { |tt| tt.gpx_id }
55 conditions[0] += " AND gpx_files.id IN (#{files.join(',')})"
58 conditions[0] += " AND gpx_files.visible = 1"
60 @trace_pages, @traces = paginate(:traces,
61 :include => [:user, :tags],
62 :conditions => conditions,
63 :order => "gpx_files.timestamp DESC",
66 # put together SET of tags across traces, for related links
69 @traces.each do |trace|
70 trace.tags.reload if params[:tag] # if searched by tag, ActiveRecord won't bring back other tags, so do explicitly here
71 trace.tags.each do |tag|
72 tagset[tag.tag] = tag.tag
77 # final helper vars for view
79 @display_name = target_user.display_name if target_user
80 @all_tags = tagset.values
88 @trace = Trace.find(params[:id])
90 if @trace and @trace.visible? and
91 (@trace.public? or @trace.user == @user)
92 @title = "Viewing trace #{@trace.name}"
94 flash[:notice] = "Trace not found!"
95 redirect_to :controller => 'trace', :action => 'list'
97 rescue ActiveRecord::RecordNotFound
98 flash[:notice] = "Trace not found!"
99 redirect_to :controller => 'trace', :action => 'list'
103 logger.info(params[:trace][:gpx_file].class.name)
104 if params[:trace][:gpx_file].respond_to?(:read)
105 do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
106 params[:trace][:description], params[:trace][:public])
109 logger.info("id is #{@trace.id}")
110 flash[:notice] = "Your GPX file has been uploaded and is awaiting insertion in to the database. This will usually happen within half an hour, and an email will be sent to you on completion."
112 redirect_to :action => 'mine'
115 @trace = Trace.new({:name => "Dummy",
116 :tagstring => params[:trace][:tagstring],
117 :description => params[:trace][:description],
118 :public => params[:trace][:public],
119 :inserted => false, :user => @user,
120 :timestamp => Time.now})
122 @trace.errors.add(:gpx_file, "can't be blank")
127 trace = Trace.find(params[:id])
129 if trace.visible? and (trace.public? or (@user and @user == trace.user))
130 if request.format == Mime::XML
131 send_file(trace.xml_file, :filename => "#{trace.id}.xml", :type => Mime::XML.to_s, :disposition => 'attachment')
133 send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
136 render :nothing => true, :status => :not_found
138 rescue ActiveRecord::RecordNotFound
139 render :nothing => true, :status => :not_found
143 @trace = Trace.find(params[:id])
145 if @user and @trace.user == @user
147 @trace.description = params[:trace][:description]
148 @trace.tagstring = params[:trace][:tagstring]
150 redirect_to :action => 'view'
154 render :nothing => true, :status => :forbidden
156 rescue ActiveRecord::RecordNotFound
157 render :nothing => true, :status => :not_found
161 trace = Trace.find(params[:id])
163 if @user and trace.user == @user
164 if request.post? and trace.visible?
165 trace.visible = false
167 flash[:notice] = 'Track scheduled for deletion'
168 redirect_to :controller => 'traces', :action => 'mine'
170 render :nothing => true, :status => :bad_request
173 render :nothing => true, :status => :forbidden
175 rescue ActiveRecord::RecordNotFound
176 render :nothing => true, :status => :not_found
180 trace = Trace.find(params[:id])
182 if @user and trace.user == @user
183 if request.post? and !trace.public?
186 flash[:notice] = 'Track made public'
187 redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
189 render :nothing => true, :status => :bad_request
192 render :nothing => true, :status => :forbidden
194 rescue ActiveRecord::RecordNotFound
195 render :nothing => true, :status => :not_found
199 conditions = ["gpx_files.public = 1"]
201 if params[:display_name]
202 conditions[0] += " AND users.display_name = ?"
203 conditions << params[:display_name]
207 conditions[0] += " AND EXISTS (SELECT * FROM gpx_file_tags AS gft WHERE gft.gpx_id = gpx_files.id AND gft.tag = ?)"
208 conditions << params[:tag]
211 traces = Trace.find(:all, :include => :user, :conditions => conditions,
212 :order => "timestamp DESC", :limit => 20)
214 rss = OSM::GeoRSS.new
216 traces.each do |trace|
217 rss.add(trace.latitude, trace.longitude, trace.name, trace.user.display_name, url_for({:controller => 'trace', :action => 'view', :id => trace.id, :display_name => trace.user.display_name}), "<img src='#{url_for({:controller => 'trace', :action => 'icon', :id => trace.id, :user_login => trace.user.display_name})}'> GPX file with #{trace.size} points from #{trace.user.display_name}", trace.timestamp)
220 render :text => rss.to_s, :content_type => "application/rss+xml"
224 trace = Trace.find(params[:id])
227 if trace.public? or (@user and @user == trace.user)
228 send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline')
230 render :nothing => true, :status => :forbidden
233 render :nothing => true, :status => :not_found
235 rescue ActiveRecord::RecordNotFound
236 render :nothing => true, :status => :not_found
240 trace = Trace.find(params[:id])
243 if trace.public? or (@user and @user == trace.user)
244 send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => 'image/gif', :disposition => 'inline')
246 render :nothing => true, :status => :forbidden
249 render :nothing => true, :status => :not_found
251 rescue ActiveRecord::RecordNotFound
252 render :nothing => true, :status => :not_found
256 trace = Trace.find(params[:id])
258 if trace.public? or trace.user == @user
259 render :text => trace.to_xml.to_s, :content_type => "text/xml"
261 render :nothing => true, :status => :forbidden
263 rescue ActiveRecord::RecordNotFound
264 render :nothing => true, :status => :not_found
268 trace = Trace.find(params[:id])
270 if trace.public? or trace.user == @user
271 send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
273 render :nothing => true, :status => :forbidden
275 rescue ActiveRecord::RecordNotFound
276 render :nothing => true, :status => :not_found
281 do_create(params[:file], params[:tags], params[:description], params[:public])
284 render :text => @trace.id.to_s, :content_type => "text/plain"
286 render :nothing => true, :status => :internal_server_error
288 render :nothing => true, :status => :bad_request
291 render :nothing => true, :status => :method_not_allowed
297 def do_create(file, tags, description, public)
298 # Sanitise the user's filename
299 name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, '_')
301 # Get a temporary filename...
302 filename = "/tmp/#{rand}"
304 # ...and save the uploaded file to that location
305 File.open(filename, "w") { |f| f.write(file.read) }
307 # Create the trace object, falsely marked as already
308 # inserted to stop the import daemon trying to load it
312 :description => description,
316 :timestamp => Time.now
319 # Save the trace object
321 # Rename the temporary file to the final name
322 FileUtils.mv(filename, @trace.trace_name)
324 # Clear the inserted flag to make the import daemon load the trace
325 @trace.inserted = false
328 # Remove the file as we have failed to update the database
329 FileUtils.rm_f(filename)