# within the specified bounding box, and in the specified page.
def trackpoints
#retrieve the page number
- page = params['page'].to_i
- unless page
- page = 0;
- end
+ page = params['page'].to_s.to_i
unless page >= 0
report_error("Page number must be greater than or equal to 0")
end
# get all the points
- points = Tracepoint.find_by_area(min_lat, min_lon, max_lat, max_lon, :offset => offset, :limit => APP_CONFIG['tracepoints_per_page'], :order => "timestamp DESC" )
+ points = Tracepoint.find_by_area(min_lat, min_lon, max_lat, max_lon, :offset => offset, :limit => APP_CONFIG['tracepoints_per_page'], :order => "gpx_id DESC, trackid ASC, timestamp ASC" )
doc = XML::Document.new
doc.encoding = XML::Encoding::UTF_8
doc.root = root
- track = XML::Node.new 'trk'
- doc.root << track
-
- trkseg = XML::Node.new 'trkseg'
- track << trkseg
+ # initialise these variables outside of the loop so that they
+ # stay in scope and don't get free'd up by the GC during the
+ # loop.
+ gpx_id = -1
+ trackid = -1
+ track = nil
+ trkseg = nil
+ anon_track = nil
+ anon_trkseg = nil
+ gpx_file = nil
+ timestamps = false
points.each do |point|
- trkseg << point.to_xml_node()
+ if gpx_id != point.gpx_id
+ gpx_id = point.gpx_id
+ trackid = -1
+ gpx_file = Trace.find(gpx_id)
+
+ if gpx_file.trackable?
+ track = XML::Node.new 'trk'
+ doc.root << track
+ timestamps = true
+
+ if gpx_file.identifiable?
+ track << (XML::Node.new("name") << gpx_file.name)
+ track << (XML::Node.new("desc") << gpx_file.description)
+ track << (XML::Node.new("url") << url_for(:controller => 'trace', :action => 'view', :id => gpx_file.id))
+ end
+ else
+ # use the anonymous track segment if the user hasn't allowed
+ # their GPX points to be tracked.
+ timestamps = false
+ if anon_track.nil?
+ anon_track = XML::Node.new 'trk'
+ doc.root << anon_track
+ end
+ track = anon_track
+ end
+ end
+
+ if trackid != point.trackid
+ if gpx_file.trackable?
+ trkseg = XML::Node.new 'trkseg'
+ track << trkseg
+ trackid = point.trackid
+ else
+ if anon_trkseg.nil?
+ anon_trkseg = XML::Node.new 'trkseg'
+ anon_track << anon_trkseg
+ end
+ trkseg = anon_trkseg
+ end
+ end
+
+ trkseg << point.to_xml_node(timestamps)
end
response.headers["Content-Disposition"] = "attachment; filename=\"map.osm\""
before_filter :authorize_web
before_filter :set_locale
- before_filter :require_user, :only => [:mine, :create, :edit, :delete, :make_public]
+ before_filter :require_user, :only => [:mine, :create, :edit, :delete]
before_filter :authorize, :only => [:api_details, :api_data, :api_create]
before_filter :check_database_readable, :except => [:api_details, :api_data, :api_create]
- before_filter :check_database_writable, :only => [:create, :edit, :delete, :make_public]
+ before_filter :check_database_writable, :only => [:create, :edit, :delete]
before_filter :check_api_readable, :only => [:api_details, :api_data]
before_filter :check_api_writable, :only => [:api_create]
# 4 - user's traces, not logged in as that user = all user's public traces
if target_user.nil? # all traces
if @user
- conditions = ["(gpx_files.public = ? OR gpx_files.user_id = ?)", true, @user.id] #1
+ conditions = ["(gpx_files.visibility <> 'private' OR gpx_files.user_id = ?)", @user.id] #1
else
- conditions = ["gpx_files.public = ?", true] #2
+ conditions = ["gpx_files.visibility <> 'private'"] #2
end
else
if @user and @user == target_user
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)
else
- conditions = ["gpx_files.public = ? AND gpx_files.user_id = ?", true, target_user.id] #4
+ conditions = ["gpx_files.public <> 'private' AND gpx_files.user_id = ?", target_user.id] #4
end
end
def mine
# Load the preference of whether the user set the trace public the last time
@trace = Trace.new
- if @user.preferences.find(:first, :conditions => {:k => "gps.trace.public", :v => "default"}).nil?
- @trace.public = false
+ visibility = @user.preferences.find(:first, :conditions => {:k => "gps.trace.visibility"})
+ if visibility
+ @trace.visibility = visibility.v
+ elsif @user.preferences.find(:first, :conditions => {:k => "gps.trace.public", :v => "default"}).nil?
+ @trace.visibility = "private"
else
- @trace.public = true
+ @trace.visibility = "public"
end
list(@user, "mine")
end
logger.info(params[:trace][:gpx_file].class.name)
if params[:trace][:gpx_file].respond_to?(:read)
do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
- params[:trace][:description], params[:trace][:public])
+ params[:trace][:description], params[:trace][:visibility])
if @trace.id
logger.info("id is #{@trace.id}")
@trace = Trace.new({:name => "Dummy",
:tagstring => params[:trace][:tagstring],
:description => params[:trace][:description],
- :public => params[:trace][:public],
+ :visibility => params[:trace][:visibility],
:inserted => false, :user => @user,
:timestamp => Time.now.getutc})
@trace.valid?
if params[:trace]
@trace.description = params[:trace][:description]
@trace.tagstring = params[:trace][:tagstring]
+ @trace.visibility = params[:trace][:visibility]
if @trace.save
redirect_to :action => 'view'
end
render :nothing => true, :status => :not_found
end
- def make_public
- trace = Trace.find(params[:id])
-
- if @user and trace.user == @user
- if request.post? and !trace.public?
- trace.public = true
- trace.save
- flash[:notice] = t 'trace.make_public.made_public'
- redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
- else
- render :nothing => true, :status => :bad_request
- end
- else
- render :nothing => true, :status => :forbidden
- end
- rescue ActiveRecord::RecordNotFound
- render :nothing => true, :status => :not_found
- end
-
def georss
- conditions = ["gpx_files.public = ?", true]
+ conditions = ["gpx_files.visibility <> 'private'"]
if params[:display_name]
conditions[0] += " AND users.display_name = ?"
if trace.inserted?
if trace.public? or (@user and @user == trace.user)
- expires_in 7.days, :private => !trace.public, :public => trace.public
+ expires_in 7.days, :private => !trace.public?, :public => trace.public?
send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline')
else
render :nothing => true, :status => :forbidden
if trace.inserted?
if trace.public? or (@user and @user == trace.user)
- expires_in 7.days, :private => !trace.public, :public => trace.public
+ expires_in 7.days, :private => !trace.public?, :public => trace.public?
send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => 'image/gif', :disposition => 'inline')
else
render :nothing => true, :status => :forbidden
if request.post?
tags = params[:tags] || ""
description = params[:description] || ""
- pub = params[:public] || false
+ visibility = params[:visibility] || false
+
+ if params[:public] && !visibility
+ visibility = "public"
+ end
if params[:file].respond_to?(:read)
- do_create(params[:file], tags, description, pub)
+ do_create(params[:file], tags, description, visibility)
if @trace.id
render :text => @trace.id.to_s, :content_type => "text/plain"
private
- def do_create(file, tags, description, public)
+ def do_create(file, tags, description, visibility)
# Sanitise the user's filename
name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, '_')
:name => name,
:tagstring => tags,
:description => description,
- :public => public,
+ :visibility => visibility,
:inserted => true,
:user => @user,
:timestamp => Time.now.getutc
FileUtils.rm_f(filename)
end
- # Finally save whether the user marked the trace as being public
- if @trace.public?
- if @user.trace_public_default.nil?
- @user.preferences.create(:k => "gps.trace.public", :v => "default")
- end
+ # Finally save the user's preferred previacy level
+ if pref = @user.preferences.find(:first, :conditions => {:k => "gps.trace.visibility"})
+ pref.v = visibility
+ pref.save
else
- pref = @user.trace_public_default
- pref.destroy unless pref.nil?
+ @user.preferences.create(:k => "gps.trace.visibility", :v => visibility)
end
end
validates_length_of :name, :maximum => 255
validates_length_of :description, :maximum => 255
# validates_numericality_of :latitude, :longitude
- validates_inclusion_of :public, :inserted, :in => [ true, false]
-
+ validates_inclusion_of :inserted, :in => [ true, false ]
+ validates_inclusion_of :visibility, :in => ["private", "public", "trackable", "identifiable"]
+
belongs_to :user
has_many :tags, :class_name => 'Tracetag', :foreign_key => 'gpx_id', :dependent => :delete_all
has_many :points, :class_name => 'Tracepoint', :foreign_key => 'gpx_id', :dependent => :delete_all
end
def tagstring=(s)
- if s.include?','
+ if s.include? ','
self.tags = s.split(/\s*,\s*/).collect {|tag|
tt = Tracetag.new
tt.tag = tag
}
end
end
-
+
+ def public?
+ visibility == "public" || visibility == "identifiable"
+ end
+
+ def trackable?
+ visibility == "trackable" || visibility == "identifiable"
+ end
+
+ def identifiable?
+ visibility == "identifiable"
+ end
+
def large_picture= (data)
f = File.new(large_picture_name, "wb")
f.syswrite(data)
el1['lat'] = self.latitude.to_s
el1['lon'] = self.longitude.to_s
el1['user'] = self.user.display_name
- el1['public'] = self.public.to_s
+ el1['visibility'] = self.visibility
el1['pending'] = (!self.inserted).to_s
el1['timestamp'] = self.timestamp.xmlschema
return el1
belongs_to :trace, :foreign_key => 'gpx_id'
- def to_xml_node
+ def to_xml_node(print_timestamp = false)
el1 = XML::Node.new 'trkpt'
el1['lat'] = self.lat.to_s
el1['lon'] = self.lon.to_s
+ el1 << (XML::Node.new("time") << self.timestamp.xmlschema) if print_timestamp
return el1
end
end
return false
end
- def trace_public_default
- return self.preferences.find(:first, :conditions => {:k => "gps.trace.public", :v => "default"})
- end
-
def delete
self.active = false
self.display_name = "user_#{self.id}"
<tr><td align="right"><%= t'trace.trace_form.upload_gpx' %></td><td><%= f.file_field :gpx_file, :size => 50, :maxlength => 255 %></td></tr>
<tr><td align="right"><%= t'trace.trace_form.description' %></td><td><%= f.text_field :description, :size => 50, :maxlength => 255 %></td></tr>
<tr><td align="right"><%= t'trace.trace_form.tags' %></td><td><%= f.text_field :tagstring, :size => 50, :maxlength => 255 %> (<%= t'trace.trace_form.tags_help' %>)</td></tr>
- <tr><td align="right"><%= t'trace.trace_form.public' %></td><td><%= f.check_box :public %> <span class="minorNote">(<a href="<%= t'trace.trace_form.public_help_url' %>"><%= t'trace.trace_form.public_help' %></a>)</span></td></tr>
+ <tr><td align="right"><%= t'trace.trace_form.visibility' %></td><td><%= f.select :visibility, [[t('trace.visibility.private'),"private"],[t('trace.visibility.public'),"public"],[t('trace.visibility.trackable'),"trackable"],[t('trace.visibility.identifiable'),"identifiable"]] %> <span class="minorNote">(<a href="<%= t'trace.trace_form.visibility_help_url' %>"><%= t'trace.trace_form.visibility_help' %></a>)</span></td></tr>
<tr><td></td><td><%= submit_tag t('trace.trace_form.upload_button') %> | <a href="<%= t'trace.trace_form.help_url' %>"><%= t'trace.trace_form.help' %></a></td></tr>
</table>
<% end %>
<td><%= t'trace.edit.tags' %></td>
<td><%= f.text_field :tagstring, :size => 50 %> (<%= t'trace.edit.tags_help' %>)</td>
</tr>
+ <tr>
+ <td><%= t'trace.edit.visibility' %></td>
+ <td><%= f.select :visibility, [[t('trace.visibility.private'),"private"],[t('trace.visibility.public'),"public"],[t('trace.visibility.trackable'),"trackable"],[t('trace.visibility.identifiable'),"identifiable"]] %> (<a href="<%= t'trace.edit.visibility_help_url' %>"><%= t'trace.edit.visibility_help' %></a>)</td>
+ </tr>
</table>
<br /><br />
<% end %>
</td>
</tr>
+ <tr>
+ <td><%= t'trace.view.visibility' %></td>
+ <td><%= t"trace.visibility.#{@trace.visibility}" %></td>
+ </tr>
</table>
<br /><br />
<table>
<tr>
- <% unless @trace.public? %>
- <td><%= button_to t('trace.view.make_public'), :controller => 'trace', :action => 'make_public', :id => @trace.id %></td>
- <% end %>
<% if @trace.user == @user %>
<td><%= button_to t('trace.view.edit_track'), :controller => 'trace', :action => 'edit', :id => @trace.id %></td>
<% end %>
destination: "Destination access"
construction: "Roads under construction"
trace:
+ visibility:
+ private: "Private (only shared as anonymous, unordered points)"
+ public: "Public (shown in trace list and as anonymous, unordered points)"
+ trackable: "Trackable (only shared as anonymous, ordered points with timestamps)"
+ identifiable: "Identifiable (shown in trace list and as identifiable, ordered points with timestamps)"
create:
upload_trace: "Upload GPS Trace"
trace_uploaded: "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."
tags: "Tags:"
tags_help: "comma delimited"
save_button: "Save Changes"
+ visibility: "Visibility:"
+ visibility_help: "what does this mean?"
+ visibility_help_url: "http://wiki.openstreetmap.org/wiki/Visibility_of_GPS_traces"
no_such_user:
title: "No such user"
heading: "The user {{user}} does not exist"
description: "Description"
tags: "Tags"
tags_help: "comma delimited"
- public: "Public?"
- public_help: "what does this mean?"
- public_help_url: "http://wiki.openstreetmap.org/wiki/Visibility_of_GPS_traces"
+ visibility: "Visibility"
+ visibility_help: "what does this mean?"
+ visibility_help_url: "http://wiki.openstreetmap.org/wiki/Visibility_of_GPS_traces"
upload_button: "Upload"
help: "Help"
help_url: "http://wiki.openstreetmap.org/wiki/Upload"
description: "Description:"
tags: "Tags:"
none: "None"
- make_public: "Make this track public permanently"
edit_track: "Edit this track"
delete_track: "Delete this track"
trace_not_found: "Trace not found!"
+ visibility: "Visibility:"
trace_paging_nav:
showing: "Showing page"
of: "of"
map.connect '/trace/:id/data.:format', :controller => 'trace', :action => 'data'
map.connect '/trace/:id/edit', :controller => 'trace', :action => 'edit'
map.connect '/trace/:id/delete', :controller => 'trace', :action => 'delete'
- map.connect '/trace/:id/make_public', :controller => 'trace', :action => 'make_public'
map.connect '/user/:display_name/traces', :controller => 'trace', :action => 'list'
map.connect '/user/:display_name/traces/page/:page', :controller => 'trace', :action => 'list'
map.connect '/user/:display_name/traces/rss', :controller => 'trace', :action => 'georss'
--- /dev/null
+require 'lib/migrate'
+
+class AddMoreControlsToGpxFiles < ActiveRecord::Migration
+ def self.up
+ create_enumeration :gpx_visibility_enum, ["private", "public", "trackable", "identifiable"]
+ add_column :gpx_files, :visibility, :gpx_visibility_enum, :default => "public", :null => false
+ Trace.update_all("visibility = 'private'", { :public => false })
+ add_index :gpx_files, [:visible, :visibility], :name => "gpx_files_visible_visibility_idx"
+ remove_index :gpx_files, :name => "gpx_files_visible_public_idx"
+ remove_column :gpx_files, :public
+ end
+
+ def self.down
+ add_column :gpx_files, :public, :boolean, :default => true, :null => false
+ Trace.update_all("public = false", { :visibility => "private" })
+ add_index :gpx_files, [:visible, :public], :name => "gpx_files_visible_public_idx"
+ remove_index :gpx_files, :name => "gpx_files_visible_visibility_idx"
+ remove_column :gpx_files, :visibility
+ drop_enumeration :gpx_visibility_enum
+ end
+end
timestamp: "2008-10-01 10:10:10"
tile: <%= QuadTile.tile_for_point(1, 1) %>
+trackable_trace_1:
+ trackid: 1
+ latitude: <%= (51.510 * SCALE).to_i %>
+ longitude: <%= (-0.140 * SCALE).to_i %>
+ gpx_id: 3
+ timestamp: "2009-07-30 17:46:00"
+ tile: <%= QuadTile.tile_for_point(51.510, -0.140) %>
+
+trackable_trace_2:
+ trackid: 2
+ latitude: <%= (51.511 * SCALE).to_i %>
+ longitude: <%= (-0.141 * SCALE).to_i %>
+ gpx_id: 3
+ timestamp: "2009-07-30 17:47:00"
+ tile: <%= QuadTile.tile_for_point(51.511, -0.141) %>
+
+identifiable_trace_1:
+ trackid: 1
+ latitude: <%= (51.512 * SCALE).to_i %>
+ longitude: <%= (0.142 * SCALE).to_i %>
+ gpx_id: 4
+ timestamp: "2009-07-30 17:46:00"
+ tile: <%= QuadTile.tile_for_point(51.512, 0.142) %>
+
latitude: 1
longitude: 1
timestamp: "2008-10-29 10:10:10"
- public: true
+ visibility: "public"
description: This is a trace
inserted: true
latitude: 51.3
longitude: -0.56
timestamp: "2009-05-06 13:34:34"
- public: false
+ visibility: "private"
description: This is an anonymous trace
inserted: true
+
+trackable_trace_file:
+ id: 3
+ user_id: 2
+ visible: false
+ name: Trackable Trace.gpx
+ size: 123
+ latitude: 51.51
+ longitude: -0.14
+ timestamp: "2009-07-30 17:48:34"
+ visibility: "trackable"
+ description: This trace shows trksegs and timestamps, but no user details.
+ inserted: true
+
+identifiable_trace_file:
+ id: 4
+ user_id: 2
+ visible: false
+ name: Identifiable Trace.gpx
+ size: 123
+ latitude: 51.512
+ longitude: 0.142
+ timestamp: "2009-07-30 17:48:34"
+ visibility: "identifiable"
+ description: This trace shows trksegs, timestamps and user details.
+ inserted: true
def test_tracepoints
point = gpx_files(:public_trace_file)
- minlon = point.longitude-0.1
- minlat = point.latitude-0.1
- maxlon = point.longitude+0.1
- maxlat = point.latitude+0.1
+ minlon = point.longitude-0.001
+ minlat = point.latitude-0.001
+ maxlon = point.longitude+0.001
+ maxlat = point.latitude+0.001
bbox = "#{minlon},#{minlat},#{maxlon},#{maxlat}"
get :trackpoints, :bbox => bbox
#print @response.body
end
end
+ def test_tracepoints_trackable
+ point = gpx_files(:trackable_trace_file)
+ minlon = point.longitude-0.002
+ minlat = point.latitude-0.002
+ maxlon = point.longitude+0.002
+ maxlat = point.latitude+0.002
+ bbox = "#{minlon},#{minlat},#{maxlon},#{maxlat}"
+ get :trackpoints, :bbox => bbox
+ #print @response.body
+ assert_response :success
+ assert_select "gpx[version=1.0][creator=OpenStreetMap.org][xmlns=http://www.topografix.com/GPX/1/0/]:root", :count => 1 do
+ assert_select "trk", :count => 1 do
+ assert_select "trk > trkseg", :count => 2 do |trksegs|
+ trksegs.each do |trkseg|
+ assert_select trkseg, "trkpt", :count => 1 do |trkpt|
+ assert_select trkpt[0], "time", :count => 1
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def test_tracepoints_identifiable
+ point = gpx_files(:identifiable_trace_file)
+ minlon = point.longitude-0.002
+ minlat = point.latitude-0.002
+ maxlon = point.longitude+0.002
+ maxlat = point.latitude+0.002
+ bbox = "#{minlon},#{minlat},#{maxlon},#{maxlat}"
+ get :trackpoints, :bbox => bbox
+ #print @response.body
+ assert_response :success
+ assert_select "gpx[version=1.0][creator=OpenStreetMap.org][xmlns=http://www.topografix.com/GPX/1/0/]:root", :count => 1 do
+ assert_select "trk", :count => 1 do
+ assert_select "trk>name", :count => 1
+ assert_select "trk>desc", :count => 1
+ assert_select "trk>url", :count => 1
+ assert_select "trkseg", :count => 1 do
+ assert_select "trkpt", :count => 1 do
+ assert_select "time", :count => 1
+ end
+ end
+ end
+ end
+ end
+
def test_map_without_bbox
["trackpoints", "map"].each do |tq|
get tq
api_fixtures
def test_trace_count
- assert_equal 2, Trace.count
+ assert_equal 4, Trace.count
end
end
api_fixtures
def test_tracepoint_count
- assert_equal 1, Tracepoint.count
+ assert_equal 4, Tracepoint.count
end
end