1 class TraceController < ApplicationController
4 before_filter :authorize_web
5 before_filter :require_user, :only => [:mine, :create, :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 = ? and display_name = ?", true, 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 = ? OR gpx_files.user_id = ?)", true, @user.id] #1
41 conditions = ["gpx_files.public = ?", true] #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 = ? AND gpx_files.user_id = ?", true, 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 = ?"
61 @trace_pages, @traces = paginate(:traces,
62 :include => [:user, :tags],
63 :conditions => conditions,
64 :order => "gpx_files.timestamp DESC",
67 # put together SET of tags across traces, for related links
70 @traces.each do |trace|
71 trace.tags.reload if params[:tag] # if searched by tag, ActiveRecord won't bring back other tags, so do explicitly here
72 trace.tags.each do |tag|
73 tagset[tag.tag] = tag.tag
78 # final helper vars for view
80 @display_name = target_user.display_name if target_user
81 @all_tags = tagset.values
89 @trace = Trace.find(params[:id])
91 if @trace and @trace.visible? and
92 (@trace.public? or @trace.user == @user)
93 @title = "Viewing trace #{@trace.name}"
95 flash[:notice] = "Trace not found!"
96 redirect_to :controller => 'trace', :action => 'list'
98 rescue ActiveRecord::RecordNotFound
99 flash[:notice] = "Trace not found!"
100 redirect_to :controller => 'trace', :action => 'list'
105 logger.info(params[:trace][:gpx_file].class.name)
106 if params[:trace][:gpx_file].respond_to?(:read)
107 do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
108 params[:trace][:description], params[:trace][:public])
111 logger.info("id is #{@trace.id}")
112 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."
114 redirect_to :action => 'mine'
117 @trace = Trace.new({:name => "Dummy",
118 :tagstring => params[:trace][:tagstring],
119 :description => params[:trace][:description],
120 :public => params[:trace][:public],
121 :inserted => false, :user => @user,
122 :timestamp => Time.now.getutc})
124 @trace.errors.add(:gpx_file, "can't be blank")
130 trace = Trace.find(params[:id])
132 if trace.visible? and (trace.public? or (@user and @user == trace.user))
133 if request.format == Mime::XML
134 send_file(trace.xml_file, :filename => "#{trace.id}.xml", :type => Mime::XML.to_s, :disposition => 'attachment')
136 send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
139 render :nothing => true, :status => :not_found
141 rescue ActiveRecord::RecordNotFound
142 render :nothing => true, :status => :not_found
146 @trace = Trace.find(params[:id])
148 if @user and @trace.user == @user
150 @trace.description = params[:trace][:description]
151 @trace.tagstring = params[:trace][:tagstring]
153 redirect_to :action => 'view'
157 render :nothing => true, :status => :forbidden
159 rescue ActiveRecord::RecordNotFound
160 render :nothing => true, :status => :not_found
164 trace = Trace.find(params[:id])
166 if @user and trace.user == @user
167 if request.post? and trace.visible?
168 trace.visible = false
170 flash[:notice] = 'Track scheduled for deletion'
171 redirect_to :controller => 'traces', :action => 'mine'
173 render :nothing => true, :status => :bad_request
176 render :nothing => true, :status => :forbidden
178 rescue ActiveRecord::RecordNotFound
179 render :nothing => true, :status => :not_found
183 trace = Trace.find(params[:id])
185 if @user and trace.user == @user
186 if request.post? and !trace.public?
189 flash[:notice] = 'Track made public'
190 redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
192 render :nothing => true, :status => :bad_request
195 render :nothing => true, :status => :forbidden
197 rescue ActiveRecord::RecordNotFound
198 render :nothing => true, :status => :not_found
202 conditions = ["gpx_files.public = ?", true]
204 if params[:display_name]
205 conditions[0] += " AND users.display_name = ?"
206 conditions << params[:display_name]
210 conditions[0] += " AND EXISTS (SELECT * FROM gpx_file_tags AS gft WHERE gft.gpx_id = gpx_files.id AND gft.tag = ?)"
211 conditions << params[:tag]
214 traces = Trace.find(:all, :include => :user, :conditions => conditions,
215 :order => "timestamp DESC", :limit => 20)
217 rss = OSM::GeoRSS.new
219 traces.each do |trace|
220 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)
223 render :text => rss.to_s, :content_type => "application/rss+xml"
227 trace = Trace.find(params[:id])
230 if trace.public? or (@user and @user == trace.user)
231 send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline')
233 render :nothing => true, :status => :forbidden
236 render :nothing => true, :status => :not_found
238 rescue ActiveRecord::RecordNotFound
239 render :nothing => true, :status => :not_found
243 trace = Trace.find(params[:id])
246 if trace.public? or (@user and @user == trace.user)
247 send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => 'image/gif', :disposition => 'inline')
249 render :nothing => true, :status => :forbidden
252 render :nothing => true, :status => :not_found
254 rescue ActiveRecord::RecordNotFound
255 render :nothing => true, :status => :not_found
259 trace = Trace.find(params[:id])
261 if trace.public? or trace.user == @user
262 render :text => trace.to_xml.to_s, :content_type => "text/xml"
264 render :nothing => true, :status => :forbidden
266 rescue ActiveRecord::RecordNotFound
267 render :nothing => true, :status => :not_found
271 trace = Trace.find(params[:id])
273 if trace.public? or trace.user == @user
274 send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
276 render :nothing => true, :status => :forbidden
278 rescue ActiveRecord::RecordNotFound
279 render :nothing => true, :status => :not_found
284 tags = params[:tags] || ""
285 description = params[:description] || ""
286 pub = params[:public] || false
288 if params[:file].respond_to?(:read)
289 do_create(params[:file], tags, description, pub)
292 render :text => @trace.id.to_s, :content_type => "text/plain"
294 render :nothing => true, :status => :internal_server_error
296 render :nothing => true, :status => :bad_request
299 render :nothing => true, :status => :bad_request
302 render :nothing => true, :status => :method_not_allowed
308 def do_create(file, tags, description, public)
309 # Sanitise the user's filename
310 name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, '_')
312 # Get a temporary filename...
313 filename = "/tmp/#{rand}"
315 # ...and save the uploaded file to that location
316 File.open(filename, "w") { |f| f.write(file.read) }
318 # Create the trace object, falsely marked as already
319 # inserted to stop the import daemon trying to load it
323 :description => description,
327 :timestamp => Time.now.getutc
330 # Save the trace object
332 # Rename the temporary file to the final name
333 FileUtils.mv(filename, @trace.trace_name)
335 # Clear the inserted flag to make the import daemon load the trace
336 @trace.inserted = false
339 # Remove the file as we have failed to update the database
340 FileUtils.rm_f(filename)
343 # Finally save whether the user marked the trace as being public
345 if @user.trace_public_default.nil?
346 @user.preferences.create(:k => "gps.trace.public", :v => "default")
349 pref = @user.trace_public_default
350 pref.destroy unless pref.nil?