Added a query method for querying bounding boxes, times and users of changesets. Needs (much) more testing.

This commit is contained in:
Matt Amos 2008-11-07 18:24:34 +00:00
parent 748a7a0a03
commit b875d14b7c
6 changed files with 148 additions and 20 deletions

View file

@ -6,9 +6,12 @@ class ChangesetController < ApplicationController
before_filter :authorize, :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
# Help methods for checking boundary sanity and area size
include MapBoundary
# Create a changeset from XML.
def create
if request.put?
@ -224,4 +227,104 @@ class ChangesetController < ApplicationController
render ex.render_opts
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

View file

@ -83,7 +83,7 @@ class Node < ActiveRecord::Base
# version must be present unless creating
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
if pt['id'] != '0'

View file

@ -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
normal_user_first_change:
id: 1
user_id: 1
created_at: "2007-01-01 00:00:00"
open: true
min_lon: <%= 1 * SCALE %>
min_lat: <%= 1 * SCALE %>
max_lon: <%= 5 * SCALE %>
max_lat: <%= 5 * SCALE %>
second_user_first_change:
id: 2
@ -22,3 +30,12 @@ normal_user_version_change:
user_id: 1
created_at: "2008-01-01 00:00:00"
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

View file

@ -55,7 +55,7 @@ node_too_far_north:
id: 6
latitude: <%= 90.01*SCALE %>
longitude: <%= 6*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(90.01,6) %>
@ -65,7 +65,7 @@ node_north_limit:
id: 11
latitude: <%= 90*SCALE %>
longitude: <%= 11*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(90,11) %>
@ -75,7 +75,7 @@ node_too_far_south:
id: 7
latitude: <%= -90.01*SCALE %>
longitude: <%= 7*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(-90.01,7) %>
@ -85,7 +85,7 @@ node_south_limit:
id: 12
latitude: <%= -90*SCALE %>
longitude: <%= 12*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(-90,12) %>
@ -95,7 +95,7 @@ node_too_far_west:
id: 8
latitude: <%= 8*SCALE %>
longitude: <%= -180.01*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(8,-180.01) %>
@ -105,7 +105,7 @@ node_west_limit:
id: 13
latitude: <%= 13*SCALE %>
longitude: <%= -180*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(13,-180) %>
@ -115,7 +115,7 @@ node_too_far_east:
id: 9
latitude: <%= 9*SCALE %>
longitude: <%= 180.01*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(9,180.01) %>
@ -125,7 +125,7 @@ node_east_limit:
id: 14
latitude: <%= 14*SCALE %>
longitude: <%= 180*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(14,180) %>
@ -135,7 +135,7 @@ node_totally_wrong:
id: 10
latitude: <%= 200*SCALE %>
longitude: <%= 200*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(200,200) %>

View file

@ -55,7 +55,7 @@ node_too_far_north:
id: 6
latitude: <%= 90.01*SCALE %>
longitude: <%= 6*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(90.01,6) %>
@ -65,7 +65,7 @@ node_north_limit:
id: 11
latitude: <%= 90*SCALE %>
longitude: <%= 11*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(90,11) %>
@ -75,7 +75,7 @@ node_too_far_south:
id: 7
latitude: <%= -90.01*SCALE %>
longitude: <%= 7*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(-90.01,7) %>
@ -85,7 +85,7 @@ node_south_limit:
id: 12
latitude: <%= -90*SCALE %>
longitude: <%= 12*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(-90,12) %>
@ -95,7 +95,7 @@ node_too_far_west:
id: 8
latitude: <%= 8*SCALE %>
longitude: <%= -180.01*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(8,-180.01) %>
@ -105,7 +105,7 @@ node_west_limit:
id: 13
latitude: <%= 13*SCALE %>
longitude: <%= -180*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(13,-180) %>
@ -115,7 +115,7 @@ node_too_far_east:
id: 9
latitude: <%= 9*SCALE %>
longitude: <%= 180.01*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(9,180.01) %>
@ -125,7 +125,7 @@ node_east_limit:
id: 14
latitude: <%= 14*SCALE %>
longitude: <%= 180*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(14,180) %>
@ -135,7 +135,7 @@ node_totally_wrong:
id: 10
latitude: <%= 200*SCALE %>
longitude: <%= 200*SCALE %>
changeset_id: 1
changeset_id: 5
visible: true
version: 1
tile: <%= QuadTile.tile_for_point(200,200) %>

View file

@ -576,6 +576,14 @@ EOF
check_after_include(changeset_id, -2, 5, [-2, -1, 4, 5])
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
#------------------------------------------------------------