api06: Preliminary support for diff uploading. This will not return anything
useful and the code will need some heavy refactoring.
This commit is contained in:
parent
0499559f79
commit
3d6e1c67fb
8 changed files with 256 additions and 117 deletions
|
@ -3,9 +3,10 @@
|
||||||
class ChangesetController < ApplicationController
|
class ChangesetController < ApplicationController
|
||||||
require 'xml/libxml'
|
require 'xml/libxml'
|
||||||
|
|
||||||
before_filter :authorize, :only => [:create, :update, :delete]
|
before_filter :authorize, :only => [:create, :update, :delete, :upload]
|
||||||
before_filter :check_write_availability, :only => [:create, :update, :delete]
|
before_filter :check_write_availability, :only => [:create, :update, :delete, :upload]
|
||||||
before_filter :check_read_availability, :except => [:create, :update, :delete]
|
before_filter :check_read_availability, :except => [:create, :update, :delete, :upload]
|
||||||
|
after_filter :compress_output
|
||||||
|
|
||||||
# Create a changeset from XML.
|
# Create a changeset from XML.
|
||||||
def create
|
def create
|
||||||
|
@ -23,4 +24,91 @@ class ChangesetController < ApplicationController
|
||||||
render :nothing => true, :status => :method_not_allowed
|
render :nothing => true, :status => :method_not_allowed
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_prim(ids, prim, nd)
|
||||||
|
prim.version = 0
|
||||||
|
prim.user_id = @user.id
|
||||||
|
prim.visible = true
|
||||||
|
prim.save_with_history!
|
||||||
|
|
||||||
|
ids[nd['id'].to_i] = prim.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_way(w, node_ids)
|
||||||
|
w.nds.each { |nd|
|
||||||
|
new_id = node_ids[nd.node_id]
|
||||||
|
nd.node_id = new_id unless new_id.nil?
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_rel(r, ids)
|
||||||
|
r.members.each { |memb|
|
||||||
|
new_id = ids[memb.member_type][memb.member_id]
|
||||||
|
nd.member_id = new_id unless new_id.nil?
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload
|
||||||
|
if not request.put?
|
||||||
|
render :nothing => true, :status => :method_not_allowed
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# FIXME: this should really be done without loading the whole XML file
|
||||||
|
# into memory.
|
||||||
|
p = XML::Parser.new
|
||||||
|
p.string = request.raw_post
|
||||||
|
doc = p.parse
|
||||||
|
|
||||||
|
node_ids, way_ids, rel_ids = {}, {}, {}
|
||||||
|
ids = {"node"=>node_ids, "way"=>way_ids, "relation"=>rel_ids}
|
||||||
|
|
||||||
|
Changeset.transaction do
|
||||||
|
doc.find('//osm/create/node').each do |nd|
|
||||||
|
create_prim node_ids, Node.from_xml_node(nd, true), nd
|
||||||
|
end
|
||||||
|
doc.find('//osm/create/way').each do |nd|
|
||||||
|
way = Way.from_xml_node(nd, true)
|
||||||
|
raise OSM::APIPreconditionFailedError.new if !way.preconditions_ok?
|
||||||
|
create_prim way_ids, fix_way(way, node_ids), nd
|
||||||
|
end
|
||||||
|
doc.find('//osm/create/relation').each do |nd|
|
||||||
|
relation = Relation.from_xml_node(nd, true)
|
||||||
|
raise OSM::APIPreconditionFailedError.new if !way.preconditions_ok?
|
||||||
|
create_prim relation_ids, fix_rel(relation, ids), nd
|
||||||
|
end
|
||||||
|
|
||||||
|
doc.find('//osm/modify/node').each do |nd|
|
||||||
|
unless NodeController.update_internal nil, Node.from_xml_node(nd)
|
||||||
|
raise OSM::APIPreconditionFailedError.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
doc.find('//osm/modify/way').each do |nd|
|
||||||
|
unless WayController.update_internal nil, fix_way(Way.from_xml_node(nd), node_ids)
|
||||||
|
raise OSM::APIPreconditionFailedError.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
doc.find('//osm/modify/relation').each do |nd|
|
||||||
|
unless RelationController.update_internal nil, fix_rel(Relation.from_xml_node(nd), ids)
|
||||||
|
raise OSM::APIPreconditionFailedError.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
doc.find('//osm/delete/node').each do |nd|
|
||||||
|
unless NodeController.delete_internal nil, Node.from_xml_node(n)
|
||||||
|
raise OSM::APIPreconditionFailedError.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
doc.find('//osm/delete/way').each do |nd|
|
||||||
|
Way.from_xml_node(nd).delete_with_relations_and_history(@user)
|
||||||
|
end
|
||||||
|
doc.find('//osm/delete/relation').each do |nd|
|
||||||
|
unless RelationController.delete_internal nil, fix_rel(Relation.from_xml_node(nd), ids)
|
||||||
|
raise OSM::APIPreconditionFailedError.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
render :text => "Ok, Fine. Upload worked without errors.\n", :status => 200
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,13 +51,7 @@ class NodeController < ApplicationController
|
||||||
new_node = Node.from_xml(request.raw_post)
|
new_node = Node.from_xml(request.raw_post)
|
||||||
|
|
||||||
if new_node and new_node.id == node.id
|
if new_node and new_node.id == node.id
|
||||||
node.user_id = @user.id
|
update_internal node, new_node
|
||||||
node.latitude = new_node.latitude
|
|
||||||
node.longitude = new_node.longitude
|
|
||||||
node.tags = new_node.tags
|
|
||||||
node.visible = true
|
|
||||||
node.save_with_history!
|
|
||||||
|
|
||||||
render :nothing => true
|
render :nothing => true
|
||||||
else
|
else
|
||||||
render :nothing => true, :status => :bad_request
|
render :nothing => true, :status => :bad_request
|
||||||
|
@ -67,32 +61,54 @@ class NodeController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_internal(node, new_node)
|
||||||
|
node = Node.find(new_node.id) if node.nil?
|
||||||
|
|
||||||
|
node.user_id = @user.id
|
||||||
|
node.latitude = new_node.latitude
|
||||||
|
node.longitude = new_node.longitude
|
||||||
|
node.tags = new_node.tags
|
||||||
|
node.visible = true
|
||||||
|
node.save_with_history!
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
# Delete a node. Doesn't actually delete it, but retains its history in a wiki-like way.
|
# Delete a node. Doesn't actually delete it, but retains its history in a wiki-like way.
|
||||||
# FIXME remove all the fricking SQL
|
# FIXME remove all the fricking SQL
|
||||||
def delete
|
def delete
|
||||||
begin
|
begin
|
||||||
node = Node.find(params[:id])
|
node = Node.find(params[:id])
|
||||||
|
|
||||||
if node.visible
|
res = delete_internal(node)
|
||||||
if WayNode.find(:first, :joins => "INNER JOIN current_ways ON current_ways.id = current_way_nodes.id", :conditions => [ "current_ways.visible = 1 AND current_way_nodes.node_id = ?", node.id ])
|
unless res
|
||||||
render :text => "", :status => :precondition_failed
|
render :text => "", :status => :precondition_failed
|
||||||
elsif RelationMember.find(:first, :joins => "INNER JOIN current_relations ON current_relations.id=current_relation_members.id", :conditions => [ "visible = 1 AND member_type='node' and member_id=?", params[:id]])
|
|
||||||
render :text => "", :status => :precondition_failed
|
|
||||||
else
|
|
||||||
node.user_id = @user.id
|
|
||||||
node.visible = 0
|
|
||||||
node.save_with_history!
|
|
||||||
|
|
||||||
render :nothing => true
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
render :text => "", :status => :gone
|
render :text => "", :status => res
|
||||||
end
|
end
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render :nothing => true, :status => :not_found
|
render :nothing => true, :status => :not_found
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_internal(node)
|
||||||
|
if node.visible
|
||||||
|
if WayNode.find(:first, :joins => "INNER JOIN current_ways ON current_ways.id = current_way_nodes.id", :conditions => [ "current_ways.visible = 1 AND current_way_nodes.node_id = ?", node.id ])
|
||||||
|
return false
|
||||||
|
elsif RelationMember.find(:first, :joins => "INNER JOIN current_relations ON current_relations.id=current_relation_members.id", :conditions => [ "visible = 1 AND member_type='node' and member_id=?", params[:id]])
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
node.user_id = @user.id
|
||||||
|
node.visible = 0
|
||||||
|
node.save_with_history!
|
||||||
|
|
||||||
|
return :ok
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return :gone
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# WTF does this do?
|
# WTF does this do?
|
||||||
def nodes
|
def nodes
|
||||||
ids = params['nodes'].split(',').collect { |n| n.to_i }
|
ids = params['nodes'].split(',').collect { |n| n.to_i }
|
||||||
|
|
|
@ -77,20 +77,11 @@ class RelationController < ApplicationController
|
||||||
begin
|
begin
|
||||||
relation = Relation.find(params[:id])
|
relation = Relation.find(params[:id])
|
||||||
|
|
||||||
if relation.visible
|
res = delete_internal(node)
|
||||||
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]])
|
unless res
|
||||||
render :text => "", :status => :precondition_failed
|
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
|
else
|
||||||
render :text => "", :status => :gone
|
render :text => "", :status => res
|
||||||
end
|
end
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render :nothing => true, :status => :not_found
|
render :nothing => true, :status => :not_found
|
||||||
|
@ -99,6 +90,24 @@ class RelationController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_internal(relation)
|
||||||
|
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]])
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
relation.user_id = @user.id
|
||||||
|
relation.tags = []
|
||||||
|
relation.members = []
|
||||||
|
relation.visible = false
|
||||||
|
relation.save_with_history!
|
||||||
|
|
||||||
|
return :ok
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return :gone
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
# full
|
# full
|
||||||
#
|
#
|
||||||
|
|
|
@ -51,15 +51,9 @@ class WayController < ApplicationController
|
||||||
new_way = Way.from_xml(request.raw_post)
|
new_way = Way.from_xml(request.raw_post)
|
||||||
|
|
||||||
if new_way and new_way.id == way.id
|
if new_way and new_way.id == way.id
|
||||||
if !new_way.preconditions_ok?
|
unless update_internal(way, new_way)
|
||||||
render :text => "", :status => :precondition_failed
|
render :text => "", :status => :precondition_failed
|
||||||
else
|
else
|
||||||
way.user_id = @user.id
|
|
||||||
way.tags = new_way.tags
|
|
||||||
way.nds = new_way.nds
|
|
||||||
way.visible = true
|
|
||||||
way.save_with_history!
|
|
||||||
|
|
||||||
render :nothing => true
|
render :nothing => true
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -70,6 +64,22 @@ class WayController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_internal way, new_way
|
||||||
|
way = Way.find(new_way.id) if way.nil?
|
||||||
|
|
||||||
|
if !new_way.preconditions_ok?
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
way.user_id = @user.id
|
||||||
|
way.tags = new_way.tags
|
||||||
|
way.nds = new_way.nds
|
||||||
|
way.visible = true
|
||||||
|
way.save_with_history!
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This is the API call to delete a way
|
# This is the API call to delete a way
|
||||||
def delete
|
def delete
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -55,40 +55,43 @@ class Node < GeoRecord
|
||||||
p = XML::Parser.new
|
p = XML::Parser.new
|
||||||
p.string = xml
|
p.string = xml
|
||||||
doc = p.parse
|
doc = p.parse
|
||||||
|
|
||||||
node = Node.new
|
|
||||||
|
|
||||||
doc.find('//osm/node').each do |pt|
|
doc.find('//osm/node').each do |pt|
|
||||||
node.lat = pt['lat'].to_f
|
return Node.from_xml_node(pt, create)
|
||||||
node.lon = pt['lon'].to_f
|
|
||||||
|
|
||||||
return nil unless node.in_world?
|
|
||||||
|
|
||||||
unless create
|
|
||||||
if pt['id'] != '0'
|
|
||||||
node.id = pt['id'].to_i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
node.visible = pt['visible'] and pt['visible'] == 'true'
|
|
||||||
|
|
||||||
if create
|
|
||||||
node.timestamp = Time.now
|
|
||||||
else
|
|
||||||
if pt['timestamp']
|
|
||||||
node.timestamp = Time.parse(pt['timestamp'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
tags = []
|
|
||||||
|
|
||||||
pt.find('tag').each do |tag|
|
|
||||||
node.add_tag_key_val(tag['k'],tag['v'])
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
node = nil
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_xml_node(pt, create=false)
|
||||||
|
node = Node.new
|
||||||
|
|
||||||
|
node.lat = pt['lat'].to_f
|
||||||
|
node.lon = pt['lon'].to_f
|
||||||
|
|
||||||
|
return nil unless node.in_world?
|
||||||
|
|
||||||
|
unless create
|
||||||
|
if pt['id'] != '0'
|
||||||
|
node.id = pt['id'].to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
node.visible = pt['visible'] and pt['visible'] == 'true'
|
||||||
|
|
||||||
|
if create
|
||||||
|
node.timestamp = Time.now
|
||||||
|
else
|
||||||
|
if pt['timestamp']
|
||||||
|
node.timestamp = Time.parse(pt['timestamp'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tags = []
|
||||||
|
|
||||||
|
pt.find('tag').each do |tag|
|
||||||
|
node.add_tag_key_val(tag['k'],tag['v'])
|
||||||
end
|
end
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
|
|
@ -16,29 +16,8 @@ class Relation < ActiveRecord::Base
|
||||||
p.string = xml
|
p.string = xml
|
||||||
doc = p.parse
|
doc = p.parse
|
||||||
|
|
||||||
relation = Relation.new
|
|
||||||
|
|
||||||
doc.find('//osm/relation').each do |pt|
|
doc.find('//osm/relation').each do |pt|
|
||||||
if !create and pt['id'] != '0'
|
relation = Relation.from_xml_node pt, create
|
||||||
relation.id = pt['id'].to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
if create
|
|
||||||
relation.timestamp = Time.now
|
|
||||||
relation.visible = true
|
|
||||||
else
|
|
||||||
if pt['timestamp']
|
|
||||||
relation.timestamp = Time.parse(pt['timestamp'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
pt.find('tag').each do |tag|
|
|
||||||
relation.add_tag_keyval(tag['k'], tag['v'])
|
|
||||||
end
|
|
||||||
|
|
||||||
pt.find('member').each do |member|
|
|
||||||
relation.add_member(member['type'], member['ref'], member['role'])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
relation = nil
|
relation = nil
|
||||||
|
@ -47,6 +26,33 @@ class Relation < ActiveRecord::Base
|
||||||
return relation
|
return relation
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.from_xml_node(pt, create=false)
|
||||||
|
relation = Relation.new
|
||||||
|
|
||||||
|
if !create and pt['id'] != '0'
|
||||||
|
relation.id = pt['id'].to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
if create
|
||||||
|
relation.timestamp = Time.now
|
||||||
|
relation.visible = true
|
||||||
|
else
|
||||||
|
if pt['timestamp']
|
||||||
|
relation.timestamp = Time.parse(pt['timestamp'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pt.find('tag').each do |tag|
|
||||||
|
relation.add_tag_keyval(tag['k'], tag['v'])
|
||||||
|
end
|
||||||
|
|
||||||
|
pt.find('member').each do |member|
|
||||||
|
relation.add_member(member['type'], member['ref'], member['role'])
|
||||||
|
end
|
||||||
|
|
||||||
|
return relation
|
||||||
|
end
|
||||||
|
|
||||||
def to_xml
|
def to_xml
|
||||||
doc = OSM::API.new.get_xml_doc
|
doc = OSM::API.new.get_xml_doc
|
||||||
doc.root << to_xml_node()
|
doc.root << to_xml_node()
|
||||||
|
|
|
@ -17,29 +17,8 @@ class Way < ActiveRecord::Base
|
||||||
p.string = xml
|
p.string = xml
|
||||||
doc = p.parse
|
doc = p.parse
|
||||||
|
|
||||||
way = Way.new
|
|
||||||
|
|
||||||
doc.find('//osm/way').each do |pt|
|
doc.find('//osm/way').each do |pt|
|
||||||
if !create and pt['id'] != '0'
|
way = Way.from_xml_node pt, create
|
||||||
way.id = pt['id'].to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
if create
|
|
||||||
way.timestamp = Time.now
|
|
||||||
way.visible = true
|
|
||||||
else
|
|
||||||
if pt['timestamp']
|
|
||||||
way.timestamp = Time.parse(pt['timestamp'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
pt.find('tag').each do |tag|
|
|
||||||
way.add_tag_keyval(tag['k'], tag['v'])
|
|
||||||
end
|
|
||||||
|
|
||||||
pt.find('nd').each do |nd|
|
|
||||||
way.add_nd_num(nd['ref'])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
way = nil
|
way = nil
|
||||||
|
@ -48,6 +27,33 @@ class Way < ActiveRecord::Base
|
||||||
return way
|
return way
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.from_xml_node(pt, create=false)
|
||||||
|
way = Way.new
|
||||||
|
|
||||||
|
if !create and pt['id'] != '0'
|
||||||
|
way.id = pt['id'].to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
if create
|
||||||
|
way.timestamp = Time.now
|
||||||
|
way.visible = true
|
||||||
|
else
|
||||||
|
if pt['timestamp']
|
||||||
|
way.timestamp = Time.parse(pt['timestamp'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pt.find('tag').each do |tag|
|
||||||
|
way.add_tag_keyval(tag['k'], tag['v'])
|
||||||
|
end
|
||||||
|
|
||||||
|
pt.find('nd').each do |nd|
|
||||||
|
way.add_nd_num(nd['ref'])
|
||||||
|
end
|
||||||
|
|
||||||
|
return way
|
||||||
|
end
|
||||||
|
|
||||||
# Find a way given it's ID, and in a single SQL call also grab its nodes
|
# Find a way given it's ID, and in a single SQL call also grab its nodes
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ ActionController::Routing::Routes.draw do |map|
|
||||||
|
|
||||||
# API
|
# API
|
||||||
map.connect "api/#{API_VERSION}/changeset/create", :controller => 'changeset', :action => 'create'
|
map.connect "api/#{API_VERSION}/changeset/create", :controller => 'changeset', :action => 'create'
|
||||||
|
map.connect "api/#{API_VERSION}/changeset/upload", :controller => 'changeset', :action => 'upload'
|
||||||
|
|
||||||
map.connect "api/#{API_VERSION}/node/create", :controller => 'node', :action => 'create'
|
map.connect "api/#{API_VERSION}/node/create", :controller => 'node', :action => 'create'
|
||||||
map.connect "api/#{API_VERSION}/node/:id/ways", :controller => 'way', :action => 'ways_for_node', :id => /\d+/
|
map.connect "api/#{API_VERSION}/node/:id/ways", :controller => 'way', :action => 'ways_for_node', :id => /\d+/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue