Added a query method for querying bounding boxes, times and users of changesets. Needs (much) more testing.
This commit is contained in:
parent
748a7a0a03
commit
b875d14b7c
6 changed files with 148 additions and 20 deletions
|
@ -6,9 +6,12 @@ class ChangesetController < ApplicationController
|
||||||
|
|
||||||
before_filter :authorize, :only => [:create, :update, :delete, :upload, :include]
|
before_filter :authorize, :only => [:create, :update, :delete, :upload, :include]
|
||||||
before_filter :check_write_availability, :only => [:create, :update, :delete, :upload, :include]
|
before_filter :check_write_availability, :only => [:create, :update, :delete, :upload, :include]
|
||||||
before_filter :check_read_availability, :except => [:create, :update, :delete, :upload, :download]
|
before_filter :check_read_availability, :except => [:create, :update, :delete, :upload, :download, :query]
|
||||||
after_filter :compress_output
|
after_filter :compress_output
|
||||||
|
|
||||||
|
# Help methods for checking boundary sanity and area size
|
||||||
|
include MapBoundary
|
||||||
|
|
||||||
# Create a changeset from XML.
|
# Create a changeset from XML.
|
||||||
def create
|
def create
|
||||||
if request.put?
|
if request.put?
|
||||||
|
@ -224,4 +227,104 @@ class ChangesetController < ApplicationController
|
||||||
render ex.render_opts
|
render ex.render_opts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# query changesets by bounding box, time, user or open/closed status.
|
||||||
|
def query
|
||||||
|
# create the conditions that the user asked for. some or all of
|
||||||
|
# these may be nil.
|
||||||
|
conditions = conditions_bbox(params['bbox'])
|
||||||
|
cond_merge conditions, conditions_user(params['user'])
|
||||||
|
cond_merge conditions, conditions_time(params['time'])
|
||||||
|
cond_merge conditions, conditions_open(params['open'])
|
||||||
|
|
||||||
|
# create the results document
|
||||||
|
results = OSM::API.new.get_xml_doc
|
||||||
|
|
||||||
|
# add all matching changesets to the XML results document
|
||||||
|
Changeset.find(:all,
|
||||||
|
:conditions => conditions,
|
||||||
|
:limit => 100,
|
||||||
|
:order => 'created_at desc').each do |cs|
|
||||||
|
results.root << cs.to_xml_node
|
||||||
|
end
|
||||||
|
|
||||||
|
render :text => results.to_s, :content_type => "text/xml"
|
||||||
|
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render :nothing => true, :status => :not_found
|
||||||
|
rescue OSM::APIError => ex
|
||||||
|
render ex.render_opts
|
||||||
|
rescue String => s
|
||||||
|
render :text => s, :content_type => "text/plain", :status => :bad_request
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# merge two conditions
|
||||||
|
def cond_merge(a, b)
|
||||||
|
if a and b
|
||||||
|
a_str = a.shift
|
||||||
|
b_str = b.shift
|
||||||
|
return [ a_str + " and " + b_str ] + a + b
|
||||||
|
elsif a
|
||||||
|
return a
|
||||||
|
else b
|
||||||
|
return b
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# if a bounding box was specified then parse it and do some sanity
|
||||||
|
# checks. this is mostly the same as the map call, but without the
|
||||||
|
# area restriction.
|
||||||
|
def conditions_bbox(bbox)
|
||||||
|
unless bbox.nil?
|
||||||
|
raise "Bounding box should be min_lon,min_lat,max_lon,max_lat" unless bbox.count(',') == 3
|
||||||
|
bbox = sanitise_boundaries(bbox.split(/,/))
|
||||||
|
raise "Minimum longitude should be less than maximum." unless bbox[0] <= bbox[2]
|
||||||
|
raise "Minimum latitude should be less than maximum." unless bbox[1] <= bbox[3]
|
||||||
|
return ['min_lon < ? and max_lon > ? and min_lat < ? and max_lat > ?',
|
||||||
|
bbox[2] * SCALE, bbox[0] * SCALE, bbox[3]* SCALE, bbox[1] * SCALE]
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# restrict changesets to those by a particular user
|
||||||
|
def conditions_user(user)
|
||||||
|
unless user.nil?
|
||||||
|
u = User.find(user.to_i)
|
||||||
|
raise OSM::APINotFoundError unless u.data_public?
|
||||||
|
return ['user_id = ?', u.id]
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# restrict changes to those during a particular time period
|
||||||
|
def conditions_time(time)
|
||||||
|
unless time.nil?
|
||||||
|
# if there is a range, i.e: comma separated, then the first is
|
||||||
|
# low, second is high - same as with bounding boxes.
|
||||||
|
if time.count(',') == 1
|
||||||
|
from, to = time.split(/,/).collect { |t| Date.parse(t) }
|
||||||
|
return ['created_at > ? and created_at < ?', from, to]
|
||||||
|
else
|
||||||
|
# if there is no comma, assume its a lower limit on time
|
||||||
|
return ['created_at > ?', Date.parse(time)]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
rescue ArgumentError => ex
|
||||||
|
raise ex.message.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# restrict changes to those which are open
|
||||||
|
def conditions_open(open)
|
||||||
|
return open.nil? ? nil : ['open = ?', true]
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,7 +83,7 @@ class Node < ActiveRecord::Base
|
||||||
|
|
||||||
# version must be present unless creating
|
# version must be present unless creating
|
||||||
return nil unless create or not pt['version'].nil?
|
return nil unless create or not pt['version'].nil?
|
||||||
node.version = pt['version'].to_i
|
node.version = create ? 0 : pt['version'].to_i
|
||||||
|
|
||||||
unless create
|
unless create
|
||||||
if pt['id'] != '0'
|
if pt['id'] != '0'
|
||||||
|
|
17
test/fixtures/changesets.yml
vendored
17
test/fixtures/changesets.yml
vendored
|
@ -1,9 +1,17 @@
|
||||||
|
# FIXME! all of these changesets need their bounding boxes set correctly!
|
||||||
|
#
|
||||||
|
<% SCALE = 10000000 unless defined?(SCALE) %>
|
||||||
|
|
||||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||||
normal_user_first_change:
|
normal_user_first_change:
|
||||||
id: 1
|
id: 1
|
||||||
user_id: 1
|
user_id: 1
|
||||||
created_at: "2007-01-01 00:00:00"
|
created_at: "2007-01-01 00:00:00"
|
||||||
open: true
|
open: true
|
||||||
|
min_lon: <%= 1 * SCALE %>
|
||||||
|
min_lat: <%= 1 * SCALE %>
|
||||||
|
max_lon: <%= 5 * SCALE %>
|
||||||
|
max_lat: <%= 5 * SCALE %>
|
||||||
|
|
||||||
second_user_first_change:
|
second_user_first_change:
|
||||||
id: 2
|
id: 2
|
||||||
|
@ -22,3 +30,12 @@ normal_user_version_change:
|
||||||
user_id: 1
|
user_id: 1
|
||||||
created_at: "2008-01-01 00:00:00"
|
created_at: "2008-01-01 00:00:00"
|
||||||
open: true
|
open: true
|
||||||
|
|
||||||
|
# changeset to contain all the invalid stuff that is in the
|
||||||
|
# fixtures (nodes outside the world, etc...)
|
||||||
|
invalid_changeset:
|
||||||
|
id: 5
|
||||||
|
user_id: 0
|
||||||
|
created_at: "2008-01-01 00:00:00"
|
||||||
|
open: false
|
||||||
|
|
18
test/fixtures/current_nodes.yml
vendored
18
test/fixtures/current_nodes.yml
vendored
|
@ -55,7 +55,7 @@ node_too_far_north:
|
||||||
id: 6
|
id: 6
|
||||||
latitude: <%= 90.01*SCALE %>
|
latitude: <%= 90.01*SCALE %>
|
||||||
longitude: <%= 6*SCALE %>
|
longitude: <%= 6*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(90.01,6) %>
|
tile: <%= QuadTile.tile_for_point(90.01,6) %>
|
||||||
|
@ -65,7 +65,7 @@ node_north_limit:
|
||||||
id: 11
|
id: 11
|
||||||
latitude: <%= 90*SCALE %>
|
latitude: <%= 90*SCALE %>
|
||||||
longitude: <%= 11*SCALE %>
|
longitude: <%= 11*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(90,11) %>
|
tile: <%= QuadTile.tile_for_point(90,11) %>
|
||||||
|
@ -75,7 +75,7 @@ node_too_far_south:
|
||||||
id: 7
|
id: 7
|
||||||
latitude: <%= -90.01*SCALE %>
|
latitude: <%= -90.01*SCALE %>
|
||||||
longitude: <%= 7*SCALE %>
|
longitude: <%= 7*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(-90.01,7) %>
|
tile: <%= QuadTile.tile_for_point(-90.01,7) %>
|
||||||
|
@ -85,7 +85,7 @@ node_south_limit:
|
||||||
id: 12
|
id: 12
|
||||||
latitude: <%= -90*SCALE %>
|
latitude: <%= -90*SCALE %>
|
||||||
longitude: <%= 12*SCALE %>
|
longitude: <%= 12*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(-90,12) %>
|
tile: <%= QuadTile.tile_for_point(-90,12) %>
|
||||||
|
@ -95,7 +95,7 @@ node_too_far_west:
|
||||||
id: 8
|
id: 8
|
||||||
latitude: <%= 8*SCALE %>
|
latitude: <%= 8*SCALE %>
|
||||||
longitude: <%= -180.01*SCALE %>
|
longitude: <%= -180.01*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(8,-180.01) %>
|
tile: <%= QuadTile.tile_for_point(8,-180.01) %>
|
||||||
|
@ -105,7 +105,7 @@ node_west_limit:
|
||||||
id: 13
|
id: 13
|
||||||
latitude: <%= 13*SCALE %>
|
latitude: <%= 13*SCALE %>
|
||||||
longitude: <%= -180*SCALE %>
|
longitude: <%= -180*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(13,-180) %>
|
tile: <%= QuadTile.tile_for_point(13,-180) %>
|
||||||
|
@ -115,7 +115,7 @@ node_too_far_east:
|
||||||
id: 9
|
id: 9
|
||||||
latitude: <%= 9*SCALE %>
|
latitude: <%= 9*SCALE %>
|
||||||
longitude: <%= 180.01*SCALE %>
|
longitude: <%= 180.01*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(9,180.01) %>
|
tile: <%= QuadTile.tile_for_point(9,180.01) %>
|
||||||
|
@ -125,7 +125,7 @@ node_east_limit:
|
||||||
id: 14
|
id: 14
|
||||||
latitude: <%= 14*SCALE %>
|
latitude: <%= 14*SCALE %>
|
||||||
longitude: <%= 180*SCALE %>
|
longitude: <%= 180*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(14,180) %>
|
tile: <%= QuadTile.tile_for_point(14,180) %>
|
||||||
|
@ -135,7 +135,7 @@ node_totally_wrong:
|
||||||
id: 10
|
id: 10
|
||||||
latitude: <%= 200*SCALE %>
|
latitude: <%= 200*SCALE %>
|
||||||
longitude: <%= 200*SCALE %>
|
longitude: <%= 200*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(200,200) %>
|
tile: <%= QuadTile.tile_for_point(200,200) %>
|
||||||
|
|
18
test/fixtures/nodes.yml
vendored
18
test/fixtures/nodes.yml
vendored
|
@ -55,7 +55,7 @@ node_too_far_north:
|
||||||
id: 6
|
id: 6
|
||||||
latitude: <%= 90.01*SCALE %>
|
latitude: <%= 90.01*SCALE %>
|
||||||
longitude: <%= 6*SCALE %>
|
longitude: <%= 6*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(90.01,6) %>
|
tile: <%= QuadTile.tile_for_point(90.01,6) %>
|
||||||
|
@ -65,7 +65,7 @@ node_north_limit:
|
||||||
id: 11
|
id: 11
|
||||||
latitude: <%= 90*SCALE %>
|
latitude: <%= 90*SCALE %>
|
||||||
longitude: <%= 11*SCALE %>
|
longitude: <%= 11*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(90,11) %>
|
tile: <%= QuadTile.tile_for_point(90,11) %>
|
||||||
|
@ -75,7 +75,7 @@ node_too_far_south:
|
||||||
id: 7
|
id: 7
|
||||||
latitude: <%= -90.01*SCALE %>
|
latitude: <%= -90.01*SCALE %>
|
||||||
longitude: <%= 7*SCALE %>
|
longitude: <%= 7*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(-90.01,7) %>
|
tile: <%= QuadTile.tile_for_point(-90.01,7) %>
|
||||||
|
@ -85,7 +85,7 @@ node_south_limit:
|
||||||
id: 12
|
id: 12
|
||||||
latitude: <%= -90*SCALE %>
|
latitude: <%= -90*SCALE %>
|
||||||
longitude: <%= 12*SCALE %>
|
longitude: <%= 12*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(-90,12) %>
|
tile: <%= QuadTile.tile_for_point(-90,12) %>
|
||||||
|
@ -95,7 +95,7 @@ node_too_far_west:
|
||||||
id: 8
|
id: 8
|
||||||
latitude: <%= 8*SCALE %>
|
latitude: <%= 8*SCALE %>
|
||||||
longitude: <%= -180.01*SCALE %>
|
longitude: <%= -180.01*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(8,-180.01) %>
|
tile: <%= QuadTile.tile_for_point(8,-180.01) %>
|
||||||
|
@ -105,7 +105,7 @@ node_west_limit:
|
||||||
id: 13
|
id: 13
|
||||||
latitude: <%= 13*SCALE %>
|
latitude: <%= 13*SCALE %>
|
||||||
longitude: <%= -180*SCALE %>
|
longitude: <%= -180*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(13,-180) %>
|
tile: <%= QuadTile.tile_for_point(13,-180) %>
|
||||||
|
@ -115,7 +115,7 @@ node_too_far_east:
|
||||||
id: 9
|
id: 9
|
||||||
latitude: <%= 9*SCALE %>
|
latitude: <%= 9*SCALE %>
|
||||||
longitude: <%= 180.01*SCALE %>
|
longitude: <%= 180.01*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(9,180.01) %>
|
tile: <%= QuadTile.tile_for_point(9,180.01) %>
|
||||||
|
@ -125,7 +125,7 @@ node_east_limit:
|
||||||
id: 14
|
id: 14
|
||||||
latitude: <%= 14*SCALE %>
|
latitude: <%= 14*SCALE %>
|
||||||
longitude: <%= 180*SCALE %>
|
longitude: <%= 180*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(14,180) %>
|
tile: <%= QuadTile.tile_for_point(14,180) %>
|
||||||
|
@ -135,7 +135,7 @@ node_totally_wrong:
|
||||||
id: 10
|
id: 10
|
||||||
latitude: <%= 200*SCALE %>
|
latitude: <%= 200*SCALE %>
|
||||||
longitude: <%= 200*SCALE %>
|
longitude: <%= 200*SCALE %>
|
||||||
changeset_id: 1
|
changeset_id: 5
|
||||||
visible: true
|
visible: true
|
||||||
version: 1
|
version: 1
|
||||||
tile: <%= QuadTile.tile_for_point(200,200) %>
|
tile: <%= QuadTile.tile_for_point(200,200) %>
|
||||||
|
|
|
@ -576,6 +576,14 @@ EOF
|
||||||
check_after_include(changeset_id, -2, 5, [-2, -1, 4, 5])
|
check_after_include(changeset_id, -2, 5, [-2, -1, 4, 5])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# check searching for changesets by bbox
|
||||||
|
def test_changeset_by_bbox
|
||||||
|
get :query, :bbox => "-10,-10, 10, 10"
|
||||||
|
assert_response :success, "can't get changesets in bbox"
|
||||||
|
# FIXME: write the actual test bit after fixing the fixtures!
|
||||||
|
end
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
# utility functions
|
# utility functions
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue