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,29 +61,51 @@ 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])
res = delete_internal(node)
unless res
render :text => "", :status => :precondition_failed
else
render :text => "", :status => res
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
end
end
def delete_internal(node)
if node.visible 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 ]) 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 ])
render :text => "", :status => :precondition_failed 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]]) 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 return false
else else
node.user_id = @user.id node.user_id = @user.id
node.visible = 0 node.visible = 0
node.save_with_history! node.save_with_history!
render :nothing => true return :ok
end end
else else
render :text => "", :status => :gone return :gone
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
end end
end end

View file

@ -77,9 +77,23 @@ class RelationController < ApplicationController
begin begin
relation = Relation.find(params[:id]) relation = Relation.find(params[:id])
res = delete_internal(node)
unless res
render :text => "", :status => :precondition_failed
else
render :text => "", :status => res
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
end
end
def delete_internal(relation)
if relation.visible 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]]) 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 return false
else else
relation.user_id = @user.id relation.user_id = @user.id
relation.tags = [] relation.tags = []
@ -87,15 +101,10 @@ class RelationController < ApplicationController
relation.visible = false relation.visible = false
relation.save_with_history! relation.save_with_history!
render :nothing => true return :ok
end end
else else
render :text => "", :status => :gone return :gone
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
end end
end end

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,9 +56,17 @@ class Node < GeoRecord
p.string = xml p.string = xml
doc = p.parse doc = p.parse
doc.find('//osm/node').each do |pt|
return Node.from_xml_node(pt, create)
end
rescue
return nil
end
end
def self.from_xml_node(pt, create=false)
node = Node.new node = Node.new
doc.find('//osm/node').each do |pt|
node.lat = pt['lat'].to_f node.lat = pt['lat'].to_f
node.lon = pt['lon'].to_f node.lon = pt['lon'].to_f
@ -86,11 +94,6 @@ class Node < GeoRecord
node.add_tag_key_val(tag['k'],tag['v']) node.add_tag_key_val(tag['k'],tag['v'])
end end
end
rescue
node = nil
end
return node return node
end end

View file

@ -16,9 +16,19 @@ class Relation < ActiveRecord::Base
p.string = xml p.string = xml
doc = p.parse doc = p.parse
doc.find('//osm/relation').each do |pt|
relation = Relation.from_xml_node pt, create
end
rescue
relation = nil
end
return relation
end
def self.from_xml_node(pt, create=false)
relation = Relation.new relation = Relation.new
doc.find('//osm/relation').each do |pt|
if !create and pt['id'] != '0' if !create and pt['id'] != '0'
relation.id = pt['id'].to_i relation.id = pt['id'].to_i
end end
@ -39,10 +49,6 @@ class Relation < ActiveRecord::Base
pt.find('member').each do |member| pt.find('member').each do |member|
relation.add_member(member['type'], member['ref'], member['role']) relation.add_member(member['type'], member['ref'], member['role'])
end end
end
rescue
relation = nil
end
return relation return relation
end end

View file

@ -17,9 +17,19 @@ class Way < ActiveRecord::Base
p.string = xml p.string = xml
doc = p.parse doc = p.parse
doc.find('//osm/way').each do |pt|
way = Way.from_xml_node pt, create
end
rescue
way = nil
end
return way
end
def self.from_xml_node(pt, create=false)
way = Way.new way = Way.new
doc.find('//osm/way').each do |pt|
if !create and pt['id'] != '0' if !create and pt['id'] != '0'
way.id = pt['id'].to_i way.id = pt['id'].to_i
end end
@ -40,10 +50,6 @@ class Way < ActiveRecord::Base
pt.find('nd').each do |nd| pt.find('nd').each do |nd|
way.add_nd_num(nd['ref']) way.add_nd_num(nd['ref'])
end end
end
rescue
way = nil
end
return way return way
end end

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