object, return 200 OK with an empty document if not matches are found rather than 400 Bad Request (for ways) or 404 Not Found (for relations).
212 lines
6.6 KiB
Ruby
212 lines
6.6 KiB
Ruby
class RelationController < ApplicationController
|
|
require 'xml/libxml'
|
|
|
|
session :off
|
|
before_filter :authorize, :only => [:create, :update, :delete]
|
|
before_filter :check_write_availability, :only => [:create, :update, :delete]
|
|
before_filter :check_read_availability, :except => [:create, :update, :delete]
|
|
after_filter :compress_output
|
|
|
|
def create
|
|
if request.put?
|
|
relation = Relation.from_xml(request.raw_post, true)
|
|
|
|
if relation
|
|
if !relation.preconditions_ok?
|
|
render :text => "", :status => :precondition_failed
|
|
else
|
|
relation.user_id = @user.id
|
|
relation.save_with_history!
|
|
|
|
render :text => relation.id.to_s, :content_type => "text/plain"
|
|
end
|
|
else
|
|
render :nothing => true, :status => :bad_request
|
|
end
|
|
else
|
|
render :nothing => true, :status => :method_not_allowed
|
|
end
|
|
end
|
|
|
|
def read
|
|
begin
|
|
relation = Relation.find(params[:id])
|
|
|
|
if relation.visible
|
|
render :text => relation.to_xml.to_s, :content_type => "text/xml"
|
|
else
|
|
render :text => "", :status => :gone
|
|
end
|
|
rescue ActiveRecord::RecordNotFound
|
|
render :nothing => true, :status => :not_found
|
|
rescue
|
|
render :nothing => true, :status => :internal_server_error
|
|
end
|
|
end
|
|
|
|
def update
|
|
begin
|
|
relation = Relation.find(params[:id])
|
|
new_relation = Relation.from_xml(request.raw_post)
|
|
|
|
if new_relation and new_relation.id == relation.id
|
|
if !new_relation.preconditions_ok?
|
|
render :text => "", :status => :precondition_failed
|
|
else
|
|
relation.user_id = @user.id
|
|
relation.tags = new_relation.tags
|
|
relation.members = new_relation.members
|
|
relation.visible = true
|
|
relation.save_with_history!
|
|
|
|
render :nothing => true
|
|
end
|
|
else
|
|
render :nothing => true, :status => :bad_request
|
|
end
|
|
rescue ActiveRecord::RecordNotFound
|
|
render :nothing => true, :status => :not_found
|
|
rescue
|
|
render :nothing => true, :status => :internal_server_error
|
|
end
|
|
end
|
|
|
|
def delete
|
|
#XXX check if member somewhere!
|
|
begin
|
|
relation = Relation.find(params[:id])
|
|
|
|
if relation.visible
|
|
if RelationMember.find(:first, :joins => "INNER JOIN current_relations ON current_relations.id=current_relation_members.id", :conditions => [ "visible = 1 AND member_type='relation' and member_id=?", params[:id]])
|
|
render :text => "", :status => :precondition_failed
|
|
else
|
|
relation.user_id = @user.id
|
|
relation.tags = []
|
|
relation.members = []
|
|
relation.visible = false
|
|
relation.save_with_history!
|
|
|
|
render :nothing => true
|
|
end
|
|
else
|
|
render :text => "", :status => :gone
|
|
end
|
|
rescue ActiveRecord::RecordNotFound
|
|
render :nothing => true, :status => :not_found
|
|
rescue
|
|
render :nothing => true, :status => :internal_server_error
|
|
end
|
|
end
|
|
|
|
# -----------------------------------------------------------------
|
|
# full
|
|
#
|
|
# input parameters: id
|
|
#
|
|
# returns XML representation of one relation object plus all its
|
|
# members, plus all nodes part of member ways
|
|
# -----------------------------------------------------------------
|
|
def full
|
|
begin
|
|
relation = Relation.find(params[:id])
|
|
|
|
if relation.visible
|
|
|
|
# first collect nodes, ways, and relations referenced by this relation.
|
|
|
|
ways = Way.find_by_sql("select w.* from current_ways w,current_relation_members rm where "+
|
|
"rm.member_type='way' and rm.member_id=w.id and rm.id=#{relation.id}");
|
|
nodes = Node.find_by_sql("select n.* from current_nodes n,current_relation_members rm where "+
|
|
"rm.member_type='node' and rm.member_id=n.id and rm.id=#{relation.id}");
|
|
# note query is built to exclude self just in case.
|
|
relations = Relation.find_by_sql("select r.* from current_relations r,current_relation_members rm where "+
|
|
"rm.member_type='relation' and rm.member_id=r.id and rm.id=#{relation.id} and r.id<>rm.id");
|
|
|
|
# now additionally collect nodes referenced by ways. Note how we recursively
|
|
# evaluate ways but NOT relations.
|
|
|
|
node_ids = nodes.collect {|node| node.id }
|
|
way_node_ids = ways.collect { |way|
|
|
way.way_nodes.collect { |way_node| way_node.node_id }
|
|
}
|
|
way_node_ids.flatten!
|
|
way_node_ids.uniq
|
|
way_node_ids -= node_ids
|
|
nodes += Node.find(way_node_ids)
|
|
|
|
# create XML.
|
|
doc = OSM::API.new.get_xml_doc
|
|
visible_nodes = {}
|
|
user_display_name_cache = {}
|
|
|
|
nodes.each do |node|
|
|
if node.visible? # should be unnecessary if data is consistent.
|
|
doc.root << node.to_xml_node(user_display_name_cache)
|
|
visible_nodes[node.id] = node
|
|
end
|
|
end
|
|
ways.each do |way|
|
|
if way.visible? # should be unnecessary if data is consistent.
|
|
doc.root << way.to_xml_node(visible_nodes, user_display_name_cache)
|
|
end
|
|
end
|
|
relations.each do |rel|
|
|
if rel.visible? # should be unnecessary if data is consistent.
|
|
doc.root << rel.to_xml_node(user_display_name_cache)
|
|
end
|
|
end
|
|
# finally add self and output
|
|
doc.root << relation.to_xml_node(user_display_name_cache)
|
|
render :text => doc.to_s, :content_type => "text/xml"
|
|
|
|
else
|
|
|
|
render :text => "", :status => :gone
|
|
end
|
|
|
|
rescue ActiveRecord::RecordNotFound
|
|
render :nothing => true, :status => :not_found
|
|
|
|
rescue
|
|
render :nothing => true, :status => :internal_server_error
|
|
end
|
|
end
|
|
|
|
def relations
|
|
ids = params['relations'].split(',').collect { |w| w.to_i }
|
|
|
|
if ids.length > 0
|
|
doc = OSM::API.new.get_xml_doc
|
|
|
|
Relation.find(ids).each do |relation|
|
|
doc.root << relation.to_xml_node
|
|
end
|
|
|
|
render :text => doc.to_s, :content_type => "text/xml"
|
|
else
|
|
render :nothing => true, :status => :bad_request
|
|
end
|
|
end
|
|
|
|
def relations_for_way
|
|
relations_for_object("way")
|
|
end
|
|
def relations_for_node
|
|
relations_for_object("node")
|
|
end
|
|
def relations_for_relation
|
|
relations_for_object("relation")
|
|
end
|
|
|
|
def relations_for_object(objtype)
|
|
relationids = RelationMember.find(:all, :conditions => ['member_type=? and member_id=?', objtype, params[:id]]).collect { |ws| ws.id }.uniq
|
|
|
|
doc = OSM::API.new.get_xml_doc
|
|
|
|
Relation.find(relationids).each do |relation|
|
|
doc.root << relation.to_xml_node
|
|
end
|
|
|
|
render :text => doc.to_s, :content_type => "text/xml"
|
|
end
|
|
end
|