]> git.openstreetmap.org Git - rails.git/blob - app/controllers/api/tracepoints_controller.rb
Preload traces for the selected points
[rails.git] / app / controllers / api / tracepoints_controller.rb
1 module Api
2   class TracepointsController < ApiController
3     authorize_resource
4
5     before_action :check_api_readable
6     around_action :api_call_handle_error, :api_call_timeout
7
8     # Get an XML response containing a list of tracepoints that have been uploaded
9     # within the specified bounding box, and in the specified page.
10     def index
11       # retrieve the page number
12       page = params["page"].to_s.to_i
13
14       unless page >= 0
15         report_error("Page number must be greater than or equal to 0")
16         return
17       end
18
19       offset = page * Settings.tracepoints_per_page
20
21       # Figure out the bbox
22       # check boundary is sane and area within defined
23       # see /config/application.yml
24       begin
25         bbox = BoundingBox.from_bbox_params(params)
26         bbox.check_boundaries
27         bbox.check_size
28       rescue StandardError => e
29         report_error(e.message)
30         return
31       end
32
33       # get all the points
34       ordered_points = Tracepoint.bbox(bbox).joins(:trace).where(:gpx_files => { :visibility => %w[trackable identifiable] }).order("gpx_id DESC, trackid ASC, timestamp ASC")
35       unordered_points = Tracepoint.bbox(bbox).joins(:trace).where(:gpx_files => { :visibility => %w[public private] }).order("gps_points.latitude", "gps_points.longitude", "gps_points.timestamp")
36       points = ordered_points.union_all(unordered_points).offset(offset).limit(Settings.tracepoints_per_page).preload(:trace)
37
38       doc = XML::Document.new
39       doc.encoding = XML::Encoding::UTF_8
40       root = XML::Node.new "gpx"
41       root["version"] = "1.0"
42       root["creator"] = "OpenStreetMap.org"
43       root["xmlns"] = "http://www.topografix.com/GPX/1/0"
44
45       doc.root = root
46
47       # initialise these variables outside of the loop so that they
48       # stay in scope and don't get free'd up by the GC during the
49       # loop.
50       gpx_id = -1
51       trackid = -1
52       track = nil
53       trkseg = nil
54       anon_track = nil
55       anon_trkseg = nil
56       timestamps = false
57
58       points.each do |point|
59         if gpx_id != point.gpx_id
60           gpx_id = point.gpx_id
61           trackid = -1
62
63           if point.trace.trackable?
64             track = XML::Node.new "trk"
65             doc.root << track
66             timestamps = true
67
68             if point.trace.identifiable?
69               track << (XML::Node.new("name") << point.trace.name)
70               track << (XML::Node.new("desc") << point.trace.description)
71               track << (XML::Node.new("url") << url_for(:controller => "/traces", :action => "show", :display_name => point.trace.user.display_name, :id => point.trace.id))
72             end
73           else
74             # use the anonymous track segment if the user hasn't allowed
75             # their GPX points to be tracked.
76             timestamps = false
77             if anon_track.nil?
78               anon_track = XML::Node.new "trk"
79               doc.root << anon_track
80             end
81             track = anon_track
82           end
83         end
84
85         if trackid != point.trackid
86           if point.trace.trackable?
87             trkseg = XML::Node.new "trkseg"
88             track << trkseg
89             trackid = point.trackid
90           else
91             if anon_trkseg.nil?
92               anon_trkseg = XML::Node.new "trkseg"
93               anon_track << anon_trkseg
94             end
95             trkseg = anon_trkseg
96           end
97         end
98
99         trkseg << point.to_xml_node(timestamps)
100       end
101
102       response.headers["Content-Disposition"] = "attachment; filename=\"tracks.gpx\""
103
104       render :xml => doc.to_s
105     end
106   end
107 end