X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/4de6006567ccff573277c9fcfbf9cb3d6bb83a63..b38684e59eef299e82f5858fe1e14f6cf2aaa10a:/app/controllers/amf_controller.rb diff --git a/app/controllers/amf_controller.rb b/app/controllers/amf_controller.rb index 900439721..f11700718 100644 --- a/app/controllers/amf_controller.rb +++ b/app/controllers/amf_controller.rb @@ -26,6 +26,7 @@ # Any method that returns a status code (0 for ok) can also send: # return(-1,"message") <-- just puts up a dialogue # return(-2,"message") <-- also asks the user to e-mail me +# return(-3,'type',id) <-- version conflict # # To write to the Rails log, use logger.info("message"). @@ -42,6 +43,7 @@ class AmfController < ApplicationController session :off before_filter :check_api_writable + around_filter :api_call_timeout, :only => [:amf_read] # Main AMF handlers: process the raw AMF string (using AMF library) and # calls each action (private method) accordingly. @@ -71,7 +73,7 @@ class AmfController < ApplicationController index=AMF.getstring(req) # | get index in response sequence bytes=AMF.getlong(req) # | get total size in bytes args=AMF.getvalue(req) # | get response (probably an array) - logger.info("Executing AMF #{message}:#{index}") + logger.info("Executing AMF #{message}(#{args.join(',')}):#{index}") case message when 'getpresets'; results[index]=AMF.putdata(index,getpresets()) @@ -88,7 +90,7 @@ class AmfController < ApplicationController when 'getpoi'; results[index]=AMF.putdata(index,getpoi(*args)) end end - logger.info("encoding AMF results") + logger.info("Encoding AMF results") sendresponse(results) else render :nothing => true, :status => :method_not_allowed @@ -132,7 +134,7 @@ class AmfController < ApplicationController when 'startchangeset'; results[index]=AMF.putdata(index,startchangeset(*args)) end end - logger.info("encoding AMF results") + logger.info("Encoding AMF results") sendresponse(results) else render :nothing => true, :status => :method_not_allowed @@ -197,7 +199,7 @@ class AmfController < ApplicationController enlarge = [(xmax-xmin)/8,0.01].min xmin -= enlarge; ymin -= enlarge xmax += enlarge; ymax += enlarge - + # check boundary is sane and area within defined # see /config/application.yml check_boundaries(xmin, ymin, xmax, ymax) @@ -227,6 +229,8 @@ class AmfController < ApplicationController [0, ways, points, relations] + rescue OSM::APITimeoutError => err + [-1,"Sorry - I can't get the map for that area. The server said: #{err}"] rescue Exception => err [-2,"Sorry - I can't get the map for that area. The server said: #{err}"] end @@ -362,7 +366,7 @@ class AmfController < ApplicationController waycreated=revdates[0] revdates.uniq! revdates.sort! - revdates.reverse! + revdates.reverse! # Remove any dates (from nodes) before first revision date of way revdates.delete_if { |d| d ex return [-1, "The changeset #{ex.changeset.id} was closed at #{ex.changeset.closed_at}."] rescue OSM::APIVersionMismatchError => ex - # Really need to check to see whether this is a server load issue, and the - # last version was in the same changeset, or belongs to the same user, then - # we can return something different return [-3, "Sorry, someone else has changed this relation since you started editing. Please click the 'Edit' tab to reload the area. The server said: #{ex}"] rescue OSM::APIAlreadyDeletedError => ex return [-1, "The relation has already been deleted."] @@ -542,7 +545,8 @@ class AmfController < ApplicationController # 4. way ID # 5. list of nodes in way # 6. hash of way tags - # 7. array of nodes to change (each one is [lon,lat,id,version,tags]) + # 7. array of nodes to change (each one is [lon,lat,id,version,tags]), + # 8. hash of nodes to delete (id->version). # # Returns: # 0. '0' (code for success), @@ -552,7 +556,7 @@ class AmfController < ApplicationController # 4. way version, # 5. hash of node versions (node=>version) - def putway(renumberednodes, usertoken, changeset_id, wayversion, originalway, pointlist, attributes, nodes) #:doc: + def putway(renumberednodes, usertoken, changeset_id, wayversion, originalway, pointlist, attributes, nodes, deletednodes) #:doc: # -- Initialise @@ -561,22 +565,13 @@ class AmfController < ApplicationController if pointlist.length < 2 then return -2,"Server error - way is only #{points.length} points long." end originalway = originalway.to_i - pointlist.collect! {|a| a.to_i } + pointlist.collect! {|a| a.to_i } way=nil # this is returned, so scope it outside the transaction nodeversions = {} Way.transaction do - # -- Get unique nodes - - if originalway <= 0 - uniques = [] - else - way = Way.find(originalway) - uniques = way.unshared_node_ids - end - - #-- Update each changed node + # -- Update each changed node nodes.each do |a| lon = a[0].to_f @@ -602,6 +597,7 @@ class AmfController < ApplicationController else # We're updating an existing node previous=Node.find(id) + node.id=id previous.update_from(node, user) nodeversions[previous.id] = previous.version end @@ -609,9 +605,9 @@ class AmfController < ApplicationController # -- Save revised way - pointlist.collect! {|a| - renumberednodes[a] ? renumberednodes[a]:a - } # renumber nodes + pointlist.collect! {|a| + renumberednodes[a] ? renumberednodes[a]:a + } # renumber nodes new_way = Way.new new_way.tags = attributes new_way.nds = pointlist @@ -620,31 +616,36 @@ class AmfController < ApplicationController if originalway <= 0 new_way.create_with_history(user) way=new_way # so we can get way.id and way.version - elsif way.tags!=attributes or way.nds!=pointlist or !way.visible? - way.update_from(new_way, user) + else + way = Way.find(originalway) + if way.tags!=attributes or way.nds!=pointlist or !way.visible? + new_way.id=originalway + way.update_from(new_way, user) + end end - # -- Delete any unique nodes no longer used + # -- Delete unwanted nodes - uniques=uniques-pointlist - uniques.each do |n| - node = Node.find(n) - deleteitemrelations(user, changeset_id, id, 'Node', node.version) + deletednodes.each do |id,v| + node = Node.find(id.to_i) new_node = Node.new new_node.changeset_id = changeset_id - new_node.version = node.version - node.delete_with_history!(new_node, user) + new_node.version = v.to_i + new_node.id = id.to_i + begin + node.delete_with_history!(new_node, user) + rescue OSM::APIPreconditionFailedError => ex + # We don't do anything here as the node is being used elsewhere + # and we don't want to delete it + end end end # transaction - [0, originalway, way.id, renumberednodes, way.version, nodeversions] + [0, originalway, way.id, renumberednodes, way.version, nodeversions, deletednodes] rescue OSM::APIChangesetAlreadyClosedError => ex return [-2, "Sorry, your changeset #{ex.changeset.id} has been closed (at #{ex.changeset.closed_at})."] rescue OSM::APIVersionMismatchError => ex - # Really need to check to see whether this is a server load issue, and the - # last version was in the same changeset, or belongs to the same user, then - # we can return something different return [-3, "Sorry, someone else has changed this way since you started editing. Click the 'Edit' tab to reload the area. The server said: #{ex}"] rescue OSM::APITooManyWayNodesError => ex return [-1, "You have tried to upload a really long way with #{ex.provided} points: only #{ex.max} are allowed."] @@ -692,12 +693,15 @@ class AmfController < ApplicationController new_node.create_with_history(user) elsif visible # We're updating the node + new_node.id=id node.update_from(new_node, user) else # We're deleting the node + new_node.id=id node.delete_with_history!(new_node, user) end - end # transaction + + end # transaction if id <= 0 return [0, id, new_node.id, new_node.version] @@ -707,9 +711,6 @@ class AmfController < ApplicationController rescue OSM::APIChangesetAlreadyClosedError => ex return [-1, "The changeset #{ex.changeset.id} was closed at #{ex.changeset.closed_at}"] rescue OSM::APIVersionMismatchError => ex - # Really need to check to see whether this is a server load issue, and the - # last version was in the same changeset, or belongs to the same user, then - # we can return something different return [-3, "Sorry, someone else has changed this point since you started editing. Please click the 'Edit' tab to reload the area. The server said: #{ex}"] rescue OSM::APIAlreadyDeletedError => ex return [-1, "The point has already been deleted"] @@ -747,7 +748,7 @@ class AmfController < ApplicationController # of the nodes have been changed by someone else then, there is a problem! # Returns 0 (success), unchanged way id. - def deleteway(usertoken, changeset_id, way_id, way_version, node_id_version) #:doc: + def deleteway(usertoken, changeset_id, way_id, way_version, deletednodes) #:doc: user = getuser(usertoken) unless user then return -1,"You are not logged in, so the way could not be deleted." end @@ -755,29 +756,31 @@ class AmfController < ApplicationController # Need a transaction so that if one item fails to delete, the whole delete fails. Way.transaction do - # delete the way + # -- Delete the way + old_way = Way.find(way_id) - u = old_way.unshared_node_ids delete_way = Way.new delete_way.version = way_version delete_way.changeset_id = changeset_id + delete_way.id = way_id old_way.delete_with_history!(delete_way, user) - u.each do |node_id| - # delete the node - node = Node.find(node_id) - delete_node = Node.new - delete_node.changeset_id = changeset_id - if node_id_version[node_id.to_s] - delete_node.version = node_id_version[node_id.to_s] - else - # in case the node wasn't passed (i.e. if it was previously removed - # from the way in Potlatch) - deleteitemrelations(user, changeset_id, node_id, 'Node', node.version) - delete_node.version = node.version - end - node.delete_with_history!(delete_node, user) + # -- Delete unwanted nodes + + deletednodes.each do |id,v| + node = Node.find(id.to_i) + new_node = Node.new + new_node.changeset_id = changeset_id + new_node.version = v.to_i + new_node.id = id.to_i + begin + node.delete_with_history!(new_node, user) + rescue OSM::APIPreconditionFailedError => ex + # We don't do anything with the exception as the node is in use + # elsewhere and we don't want to delete it + end end + end # transaction [0, way_id] rescue OSM::APIChangesetAlreadyClosedError => ex @@ -798,28 +801,6 @@ class AmfController < ApplicationController # ==================================================================== # Support functions - # Remove a node or way from all relations - # This is only used by putway and deleteway when deleting nodes removed - # from a way (because Potlatch itself doesn't keep track of these - - # possible FIXME). - - def deleteitemrelations(user, changeset_id, objid, type, version) #:doc: - relations = RelationMember.find(:all, - :conditions => ['member_type = ? and member_id = ?', type.classify, objid], - :include => :relation).collect { |rm| rm.relation }.uniq - - relations.each do |rel| - rel.members.delete_if { |x| x[0] == type and x[1] == objid } - new_rel = Relation.new - new_rel.tags = rel.tags - new_rel.visible = rel.visible - new_rel.version = rel.version - new_rel.members = rel.members - new_rel.changeset_id = changeset_id - rel.update_from(new_rel, user) - end - end - # Authenticate token # (can also be of form user:pass) # When we are writing to the api, we need the actual user model,