From 849397a33616f0802294047131fbca52b844ce51 Mon Sep 17 00:00:00 2001 From: Richard Fairhurst Date: Tue, 13 Nov 2007 09:26:04 +0000 Subject: [PATCH] 0.5a: further revisions to merged ways, API->SWF error handling --- app/controllers/amf_controller.rb | 65 ++++++++++++++++-------------- app/controllers/swf_controller.rb | 20 ++++----- public/potlatch/potlatch.swf | Bin 77424 -> 78456 bytes 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/app/controllers/amf_controller.rb b/app/controllers/amf_controller.rb index 3df6da6fa..bffff484e 100644 --- a/app/controllers/amf_controller.rb +++ b/app/controllers/amf_controller.rb @@ -12,9 +12,12 @@ class AmfController < ApplicationController # # Public domain. Set your tab width to 4 to read this document. :) # editions Systeme D / Richard Fairhurst 2004-2007 - + + # to trap errors (getway_old,putway,putpoi,deleteway only): + # return(-1,"message") <-- just puts up a dialogue + # return(-2,"message") <-- also asks the user to e-mail me # to log: - # RAILS_DEFAULT_LOGGER.error("Args: #{args[0]}, #{args[1]}, #{args[2]}, #{args[3]}") + # RAILS_DEFAULT_LOGGER.error("Args: #{args[0]}, #{args[1]}, #{args[2]}, #{args[3]}") # ==================================================================== # Main AMF handler @@ -215,7 +218,7 @@ EOF end } end - return [presets,presetmenus,presetnames] + [presets,presetmenus,presetnames] end # ----- whichways(left,bottom,right,top) @@ -253,7 +256,7 @@ EOF points = pointlist.collect {|a| [a['id'],long2coord(a['lng'].to_f,baselong,masterscale),lat2coord(a['lat'].to_f,basey,masterscale),tag2array(a['tags'])] } # get a list of node ids and their tags - return [ways,points] + [ways,points] end # ----- whichways_deleted(left,bottom,right,top) @@ -315,7 +318,7 @@ EOF def getway_old(args) RAILS_DEFAULT_LOGGER.info(" Message: getway_old (server is #{SERVER_URL})") - return if SERVER_URL=='www.openstreetmap.org' + if SERVER_URL=="www.openstreetmap.org" then return -1,"Revert is not currently enabled on the OpenStreetMap server." end objname,wayid,version,baselong,basey,masterscale=args wayid = wayid.to_i @@ -343,7 +346,7 @@ EOF attrlist.each {|a| attributes[a['k'].gsub(':','|')]=a['v'] } attributes['history']="Retrieved from v"+version.to_s - [objname,points,attributes,xmin,xmax,ymin,ymax,version] + [0,objname,points,attributes,xmin,xmax,ymin,ymax,version] end # ----- getway_history (way) @@ -372,28 +375,27 @@ EOF # returns current way ID, new way ID, hash of renumbered nodes, # xmin,xmax,ymin,ymax - # ** needs to be updated so that nodes with visible=0 (i.e. undeleted) - # no longer cause a problem - # best way to do this would be to know which version it was recovered from; - # then replace readwayquery with historic query. Line 506 would also need - # to check if visible had changed, and update if so - # (a side-effect is that merging/splitting ways will need to be forbidden - # for undeleted ways, I think) - def putway(args) RAILS_DEFAULT_LOGGER.info(" putway started") usertoken,originalway,points,attributes,oldversion,baselong,basey,masterscale=args uid=getuserid(usertoken) - return if !uid + if !uid then return -1,"You are not logged in, so the way could not be saved." end + RAILS_DEFAULT_LOGGER.info(" putway authenticated happily") - db_uqn='unin'+uid.to_s+originalway.to_i.abs.to_s+Time.new.to_i.to_s # temp uniquenodes table name, typically 51 chars - db_now='@now'+uid.to_s+originalway.to_i.abs.to_s+Time.new.to_i.to_s # 'now' variable name, typically 51 chars + db_uqn='unin'+(rand*100).to_i.to_s+uid.to_s+originalway.to_i.abs.to_s+Time.new.to_i.to_s # temp uniquenodes table name, typically 51 chars + db_now='@now'+(rand*100).to_i.to_s+uid.to_s+originalway.to_i.abs.to_s+Time.new.to_i.to_s # 'now' variable name, typically 51 chars ActiveRecord::Base.connection.execute("SET #{db_now}=NOW()") originalway=originalway.to_i oldversion=oldversion.to_i RAILS_DEFAULT_LOGGER.info(" Message: putway, id=#{originalway}") + # -- Temporary check for null IDs + + points.each do |a| + if a[2]==0 or a[2].nil? then return -2,"Server error - node with id 0 found in way #{originalway}." end + end + # -- 3. read original way into memory xc={}; yc={}; tagc={}; vc={} @@ -529,7 +531,7 @@ EOF if (insertsql !='') then ActiveRecord::Base.connection.insert("INSERT INTO way_tags (id,k,v,version) VALUES #{insertsql}" ) end if (currentsql!='') then ActiveRecord::Base.connection.insert("INSERT INTO current_way_tags (id,k,v) VALUES #{currentsql}") end - [originalway,way,renumberednodes,xmin,xmax,ymin,ymax] + [0,originalway,way,renumberednodes,xmin,xmax,ymin,ymax] end # ----- putpoi (user token, id, x,y,tag array,visible,baselong,basey,masterscale) @@ -540,8 +542,9 @@ EOF def putpoi(args) usertoken,id,x,y,tags,visible,baselong,basey,masterscale=args uid=getuserid(usertoken) - return if !uid - db_now='@now'+uid.to_s+id.to_i.abs.to_s+Time.new.to_i.to_s # 'now' variable name, typically 51 chars + if !uid then return -1,"You are not logged in, so the point could not be saved." end + + db_now='@now'+(rand*100).to_i.to_s+uid.to_s+id.to_i.abs.to_s+Time.new.to_i.to_s # 'now' variable name, typically 51 chars ActiveRecord::Base.connection.execute("SET #{db_now}=NOW()") id=id.to_i @@ -549,7 +552,7 @@ EOF if visible==0 then # if deleting, check node hasn't become part of a way inway=ActiveRecord::Base.connection.select_one("SELECT cw.id FROM current_ways cw,current_way_nodes cwn WHERE cw.id=cwn.id AND cw.visible=1 AND cwn.node_id=#{id} LIMIT 1") - unless inway.nil? then return [id,id] end # should really return an error + unless inway.nil? then return -1,"The point has since become part of a way, so you cannot save it as a POI." end deleteitemrelations(id,'node',uid,db_now) end @@ -568,7 +571,7 @@ EOF newid=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes (latitude,longitude,timestamp,user_id,visible,tags,tile) VALUES (#{lat},#{long},#{db_now},#{uid},#{visible},#{tagsql},#{tile})"); ActiveRecord::Base.connection.update("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags,tile) VALUES (#{newid},#{lat},#{long},#{db_now},#{uid},#{visible},#{tagsql},#{tile})"); end - [id,newid] + [0,id,newid] end # ----- getpoi (id,baselong,basey,masterscale) @@ -589,24 +592,24 @@ EOF # returns way ID only def deleteway(args) - usertoken,way,preserve=args + usertoken,way=args RAILS_DEFAULT_LOGGER.info(" Message: deleteway, id=#{way}") + uid=getuserid(usertoken) + if !uid then return -1,"You are not logged in, so the way could not be deleted." end - uid=getuserid(usertoken); if !uid then return end way=way.to_i - - db_uqn='unin'+uid.to_s+way.to_i.abs.to_s+Time.new.to_i.to_s # temp uniquenodes table name, typically 51 chars - db_now='@now'+uid.to_s+way.to_i.abs.to_s+Time.new.to_i.to_s # 'now' variable name, typically 51 chars + db_uqn='unin'+(rand*100).to_i.to_s+uid.to_s+way.to_i.abs.to_s+Time.new.to_i.to_s # temp uniquenodes table name, typically 51 chars + db_now='@now'+(rand*100).to_i.to_s+uid.to_s+way.to_i.abs.to_s+Time.new.to_i.to_s # 'now' variable name, typically 51 chars ActiveRecord::Base.connection.execute("SET #{db_now}=NOW()") # - delete any otherwise unused nodes createuniquenodes(way,db_uqn,[]) - unless (preserve.empty?) then - ActiveRecord::Base.connection.execute("DELETE FROM #{db_uqn} WHERE node_id IN ("+preserve.join(',')+")") - end +# unless (preserve.empty?) then +# ActiveRecord::Base.connection.execute("DELETE FROM #{db_uqn} WHERE node_id IN ("+preserve.join(',')+")") +# end sql=<<-EOF INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tile) @@ -633,7 +636,7 @@ EOF ActiveRecord::Base.connection.execute("DELETE FROM current_way_nodes WHERE id=#{way}") ActiveRecord::Base.connection.execute("DELETE FROM current_way_tags WHERE id=#{way}") deleteitemrelations(way,'way',uid,db_now) - way + [0,way] end diff --git a/app/controllers/swf_controller.rb b/app/controllers/swf_controller.rb index 18aa20774..47f692b08 100644 --- a/app/controllers/swf_controller.rb +++ b/app/controllers/swf_controller.rb @@ -46,16 +46,16 @@ class SwfController < ApplicationController lastfile='-1' if params['token'] - user=User.authenticate(:token => params[:token]) - sql="SELECT gps_points.latitude*0.0000001 AS lat,gps_points.longitude*0.0000001 AS lon,gpx_files.id AS fileid,UNIX_TIMESTAMP(gps_points.timestamp) AS ts "+ - " FROM gpx_files,gps_points "+ - "WHERE gpx_files.id=gpx_id "+ - " AND gpx_files.user_id=#{user.id} "+ - " AND "+OSM.sql_for_area(ymin,xmin,ymax,xmax,"gps_points.")+ - " AND (gps_points.timestamp IS NOT NULL) "+ - "ORDER BY fileid DESC,ts "+ - "LIMIT 10000" - else + user=User.authenticate(:token => params[:token]) + sql="SELECT gps_points.latitude*0.0000001 AS lat,gps_points.longitude*0.0000001 AS lon,gpx_files.id AS fileid,UNIX_TIMESTAMP(gps_points.timestamp) AS ts "+ + " FROM gpx_files,gps_points "+ + "WHERE gpx_files.id=gpx_id "+ + " AND gpx_files.user_id=#{user.id} "+ + " AND "+OSM.sql_for_area(ymin,xmin,ymax,xmax,"gps_points.")+ + " AND (gps_points.timestamp IS NOT NULL) "+ + "ORDER BY fileid DESC,ts "+ + "LIMIT 10000" + else sql="SELECT latitude*0.0000001 AS lat,longitude*0.0000001 AS lon,gpx_id AS fileid,UNIX_TIMESTAMP(timestamp) AS ts "+ " FROM gps_points "+ "WHERE "+OSM.sql_for_area(ymin,xmin,ymax,xmax,"gps_points.")+ diff --git a/public/potlatch/potlatch.swf b/public/potlatch/potlatch.swf index 4a0073e36820f5013e10dc9f2dabd290af594ba1..7d3178d02c463c705f3ada1f7f29dc777053aa39 100755 GIT binary patch delta 21332 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 VchM;NM69ceI*Z{ncJ~&~{SVJ?PDcO$ delta 20266 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 ImC}p