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:
Gabriel Ebner 2008-05-04 13:52:43 +00:00
parent 0499559f79
commit 3d6e1c67fb
8 changed files with 256 additions and 117 deletions

View file

@ -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

View file

@ -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 }

View file

@ -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
# #

View file

@ -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

View file

@ -56,39 +56,42 @@ class Node < GeoRecord
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

View file

@ -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()

View file

@ -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
# #

View file

@ -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+/