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_availability, :except => [:api_details, :api_data, :api_create]
8 before_filter :check_read_availability, :only => [:api_details, :api_data, :api_create]
10 # Counts and selects pages of GPX traces for various criteria (by user, tags, public etc.).
11 # target_user - if set, specifies the user to fetch traces for. if not set will fetch all traces
12 def list(target_user = nil, action = "list")
13 # from display name, pick up user id if one user's traces only
14 display_name = params[:display_name]
15 if target_user.nil? and !display_name.blank?
16 target_user = User.find(:first, :conditions => [ "visible = 1 and display_name = ?", display_name])
21 @title = "Public GPS traces"
22 elsif @user and @user == target_user
23 @title = "Your GPS traces"
25 @title = "Public GPS traces from #{target_user.display_name}"
28 @title += " tagged with #{params[:tag]}" if params[:tag]
31 # 1 - all traces, logged in = all public traces + all user's (i.e + all mine)
32 # 2 - all traces, not logged in = all public traces
33 # 3 - user's traces, logged in as same user = all user's traces
34 # 4 - user's traces, not logged in as that user = all user's public traces
35 if target_user.nil? # all traces
37 conditions = ["(gpx_files.public = 1 OR gpx_files.user_id = ?)", @user.id] #1
39 conditions = ["gpx_files.public = 1"] #2
42 if @user and @user == target_user
43 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)
45 conditions = ["gpx_files.public = 1 AND gpx_files.user_id = ?", target_user.id] #4
52 files = Tracetag.find_all_by_tag(params[:tag]).collect { |tt| tt.gpx_id }
53 conditions[0] += " AND gpx_files.id IN (#{files.join(',')})"
56 conditions[0] += " AND gpx_files.visible = 1"
58 @trace_pages, @traces = paginate(:traces,
59 :include => [:user, :tags],
60 :conditions => conditions,
61 :order => "gpx_files.timestamp DESC",
64 # put together SET of tags across traces, for related links
67 @traces.each do |trace|
68 trace.tags.reload if params[:tag] # if searched by tag, ActiveRecord won't bring back other tags, so do explicitly here
69 trace.tags.each do |tag|
70 tagset[tag.tag] = tag.tag
75 # final helper vars for view
77 @display_name = target_user.display_name if target_user
78 @all_tags = tagset.values
86 @trace = Trace.find(params[:id])
88 if @trace and @trace.visible? and
89 (@trace.public? or @trace.user == @user)
90 @title = "Viewing trace #{@trace.name}"
92 flash[:notice] = "Trace not found!"
93 redirect_to :controller => 'trace', :action => 'list'
95 rescue ActiveRecord::RecordNotFound
96 flash[:notice] = "Trace not found!"
97 redirect_to :controller => 'trace', :action => 'list'
101 logger.info(params[:trace][:gpx_file].class.name)
102 if params[:trace][:gpx_file].respond_to?(:read)
103 do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
104 params[:trace][:description], params[:trace][:public])
107 logger.info("id is #{@trace.id}")
108 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."
110 redirect_to :action => 'mine'
113 @trace = Trace.new({:name => "Dummy",
114 :tagstring => params[:trace][:tagstring],
115 :description => params[:trace][:description],
116 :public => params[:trace][:public],
117 :inserted => false, :user => @user,
118 :timestamp => Time.now})
120 @trace.errors.add(:gpx_file, "can't be blank")
125 trace = Trace.find(params[:id])
127 if trace.visible? and (trace.public? or (@user and @user == trace.user))
128 if request.format == Mime::XML
129 send_file(trace.xml_file, :filename => "#{trace.id}.xml", :type => Mime::XML.to_s, :disposition => 'attachment')
131 send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
134 render :nothing => true, :status => :not_found
136 rescue ActiveRecord::RecordNotFound
137 render :nothing => true, :status => :not_found
141 @trace = Trace.find(params[:id])
143 if @user and @trace.user == @user
145 @trace.description = params[:trace][:description]
146 @trace.tagstring = params[:trace][:tagstring]
148 redirect_to :action => 'view'
152 render :nothing => true, :status => :forbidden
154 rescue ActiveRecord::RecordNotFound
155 render :nothing => true, :status => :not_found
159 trace = Trace.find(params[:id])
161 if @user and trace.user == @user
162 if request.post? and trace.visible?
163 trace.visible = false
165 flash[:notice] = 'Track scheduled for deletion'
166 redirect_to :controller => 'traces', :action => 'mine'
168 render :nothing => true, :status => :bad_request
171 render :nothing => true, :status => :forbidden
173 rescue ActiveRecord::RecordNotFound
174 render :nothing => true, :status => :not_found
178 trace = Trace.find(params[:id])
180 if @user and trace.user == @user
181 if request.post? and !trace.public?
184 flash[:notice] = 'Track made public'
185 redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
187 render :nothing => true, :status => :bad_request
190 render :nothing => true, :status => :forbidden
192 rescue ActiveRecord::RecordNotFound
193 render :nothing => true, :status => :not_found
197 conditions = ["gpx_files.public = 1"]
199 if params[:display_name]
200 conditions[0] += " AND users.display_name = ?"
201 conditions << params[:display_name]
205 conditions[0] += " AND EXISTS (SELECT * FROM gpx_file_tags AS gft WHERE gft.gpx_id = gpx_files.id AND gft.tag = ?)"
206 conditions << params[:tag]
209 traces = Trace.find(:all, :include => :user, :conditions => conditions,
210 :order => "timestamp DESC", :limit => 20)
212 rss = OSM::GeoRSS.new
214 traces.each do |trace|
215 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)
218 render :text => rss.to_s, :content_type => "application/rss+xml"
222 trace = Trace.find(params[:id])
225 if trace.public? or (@user and @user == trace.user)
226 send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline')
228 render :nothing => true, :status => :forbidden
231 render :nothing => true, :status => :not_found
233 rescue ActiveRecord::RecordNotFound
234 render :nothing => true, :status => :not_found
238 trace = Trace.find(params[:id])
241 if trace.public? or (@user and @user == trace.user)
242 send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => 'image/gif', :disposition => 'inline')
244 render :nothing => true, :status => :forbidden
247 render :nothing => true, :status => :not_found
249 rescue ActiveRecord::RecordNotFound
250 render :nothing => true, :status => :not_found
254 trace = Trace.find(params[:id])
256 if trace.public? or trace.user == @user
257 render :text => trace.to_xml.to_s, :content_type => "text/xml"
259 render :nothing => true, :status => :forbidden
261 rescue ActiveRecord::RecordNotFound
262 render :nothing => true, :status => :not_found
266 trace = Trace.find(params[:id])
268 if trace.public? or trace.user == @user
269 send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
271 render :nothing => true, :status => :forbidden
273 rescue ActiveRecord::RecordNotFound
274 render :nothing => true, :status => :not_found
279 do_create(params[:file], params[:tags], params[:description], params[:public])
282 render :text => @trace.id.to_s, :content_type => "text/plain"
284 render :nothing => true, :status => :internal_server_error
286 render :nothing => true, :status => :bad_request
289 render :nothing => true, :status => :method_not_allowed
295 def do_create(file, tags, description, public)
296 # Sanitise the user's filename
297 name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, '_')
299 # Get a temporary filename...
300 filename = "/tmp/#{rand}"
302 # ...and save the uploaded file to that location
303 File.open(filename, "w") { |f| f.write(file.read) }
305 # Create the trace object, falsely marked as already
306 # inserted to stop the import daemon trying to load it
310 :description => description,
314 :timestamp => Time.now
317 # Save the trace object
319 # Rename the temporary file to the final name
320 FileUtils.mv(filename, @trace.trace_name)
322 # Clear the inserted flag to make the import daemon load the trace
323 @trace.inserted = false
326 # Remove the file as we have failed to update the database
327 FileUtils.rm_f(filename)