]> git.openstreetmap.org Git - rails.git/blobdiff - app/controllers/amf_controller.rb
Allow the API to be taken offline completely as well as being put into
[rails.git] / app / controllers / amf_controller.rb
index b318e3eefc060a87dd837197c266ba083996bc80..ea32acec8ddbcb788c8755df1dec42143156096d 100644 (file)
@@ -1,6 +1,9 @@
 class AmfController < ApplicationController
   require 'stringio'
 
+  session :off
+  before_filter :check_write_availability
+
   # to log:
   # RAILS_DEFAULT_LOGGER.error("Args: #{args[0]}, #{args[1]}, #{args[2]}, #{args[3]}")
 
@@ -40,6 +43,8 @@ class AmfController < ApplicationController
                  when 'putway';                results[index]=putdata(index,putway(args))
                  when 'deleteway';             results[index]=putdata(index,deleteway(args))
                  when 'makeway';               results[index]=putdata(index,makeway(args))
+                 when 'putpoi';                results[index]=putdata(index,putpoi(args))
+                 when 'getpoi';                results[index]=putdata(index,getpoi(args))
       end
     end
 
@@ -68,8 +73,8 @@ class AmfController < ApplicationController
 
   def getpresets
     presets={}
-    presetmenus={}; presetmenus['point']=[]; presetmenus['way']=[]
-    presetnames={}; presetnames['point']={}; presetnames['way']={}
+    presetmenus={}; presetmenus['point']=[]; presetmenus['way']=[]; presetmenus['POI']=[]
+    presetnames={}; presetnames['point']={}; presetnames['way']={}; presetnames['POI']={}
     presettype=''
     presetcategory=''
 
@@ -94,8 +99,8 @@ unclassified road: highway=unclassified,name=(type road name)
 
 way/footway
 footpath: highway=footway,foot=yes
-bridleway: highway=bridleway,foot=yes,horse=yes,bicycle=yes
-byway: highway=byway,foot=yes,horse=yes,bicycle=yes,motorcar=yes
+bridleway: highway=bridleway,foot=yes
+byway: highway=unsurfaced,foot=yes
 permissive path: highway=footway,foot=permissive
 
 way/cycleway
@@ -120,6 +125,10 @@ preserved railway: railway=preserved
 disused railway tracks: railway=disused
 course of old railway: railway=abandoned
 
+way/natural
+lake: landuse=water
+forest: landuse=forest
+
 point/road
 mini roundabout: highway=mini_roundabout
 traffic lights: highway=traffic_signals
@@ -144,6 +153,35 @@ point/railway
 station: railway=station
 viaduct: railway=viaduct
 level crossing: railway=crossing
+
+point/natural
+peak: point=peak
+
+POI/road
+car park: amenity=parking
+petrol station: amenity=fuel
+
+POI/cycleway
+bike park: amenity=bicycle_parking
+
+POI/place
+city: place=city,name=(type name here),is_in=(type region or county)
+town: place=town,name=(type name here),is_in=(type region or county)
+suburb: place=suburb,name=(type name here),is_in=(type region or county)
+village: place=village,name=(type name here),is_in=(type region or county)
+hamlet: place=hamlet,name=(type name here),is_in=(type region or county)
+
+POI/tourism
+attraction: tourism=attraction,amenity=,religion=,denomination=
+church: tourism=,amenity=place_of_worship,name=(type name here),religion=christian,denomination=(type denomination here)
+hotel: tourism=hotel,amenity=,religion=,denomination=
+other religious: tourism=,amenity=place_of_worship,name=(type name here),religion=(type religion),denomination=
+post box: amenity=post_box,tourism=,name=,religion=,denomination=
+post office: amenity=post_office,tourism=,name=,religion=,denomination=
+pub: tourism=,amenity=pub,name=(type name here),religion=,denomination=
+
+POI/natural
+peak: point=peak
 EOF
 
     StringIO.open(txt) do |file|
@@ -177,6 +215,9 @@ EOF
     ymin = args[1].to_f-0.01
     xmax = args[2].to_f+0.01
     ymax = args[3].to_f+0.01
+       baselong    = args[4]
+       basey       = args[5]
+       masterscale = args[6]
 
     RAILS_DEFAULT_LOGGER.info("  Message: whichways, bbox=#{xmin},#{ymin},#{xmax},#{ymax}")
 
@@ -192,7 +233,7 @@ EOF
 
        ways = waylist.collect {|a| a.wayid.to_i } # get an array of way id's
 
-       pointlist =ActiveRecord::Base.connection.select_all("SELECT current_nodes.id,current_nodes.tags "+
+       pointlist =ActiveRecord::Base.connection.select_all("SELECT current_nodes.id,latitude,longitude,current_nodes.tags "+
        "  FROM current_nodes "+
        "  LEFT OUTER JOIN current_segments cs1 ON cs1.node_a=current_nodes.id "+
        "  LEFT OUTER JOIN current_segments cs2 ON cs2.node_b=current_nodes.id "+
@@ -201,7 +242,7 @@ EOF
        "   AND cs1.id IS NULL AND cs2.id IS NULL "+
        "   AND current_nodes.visible=1")
 
-           points = pointlist.collect {|a| [a['id'],tag2array(a['tags'])]      } # get a list of node ids and their tags
+           points = pointlist.collect {|a| [a['id'],long2coord(a['longitude'].to_f,baselong,masterscale),lat2coord(a['latitude'].to_f,basey,masterscale),tag2array(a['tags'])] } # get a list of node ids and their tags
 
     return [ways,points]
   end
@@ -295,10 +336,14 @@ EOF
       # compare node
       if node<0
         # new node - create
-        newnode=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes (   latitude,longitude,timestamp,user_id,visible,tags) VALUES (           #{ys},#{xs},#{db_now},#{uid},1,#{tagsql})")
-                       ActiveRecord::Base.connection.insert("INSERT INTO nodes         (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{newnode},#{ys},#{xs},#{db_now},#{uid},1,#{tagsql})")
-        points[i][2]=newnode
-        renumberednodes[node.to_s]=newnode.to_s
+               if renumberednodes[node.to_s].nil?
+                       newnode=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes (   latitude,longitude,timestamp,user_id,visible,tags) VALUES (           #{ys},#{xs},#{db_now},#{uid},1,#{tagsql})")
+                                       ActiveRecord::Base.connection.insert("INSERT INTO nodes         (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{newnode},#{ys},#{xs},#{db_now},#{uid},1,#{tagsql})")
+                       points[i][2]=newnode
+                       renumberednodes[node.to_s]=newnode.to_s
+               else
+                       points[i][2]=renumberednodes[node.to_s].to_i
+               end
 
       elsif xc.has_key?(node)
         # old node from original way - update
@@ -424,6 +469,49 @@ EOF
     [originalway,way,renumberednodes,numberedsegments,xmin,xmax,ymin,ymax]
   end
 
+  # -----      putpoi (user token, id, x,y,tag array,visible,baselong,basey,masterscale)
+  #                    returns current id, new id
+  #                    if new: add new row to current_nodes and nodes
+  #                    if old: add new row to nodes, update current_nodes
+
+  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
+    ActiveRecord::Base.connection.execute("SET #{db_now}=NOW()")
+
+       id=id.to_i
+       visible=visible.to_i
+       x=coord2long(x.to_f,masterscale,baselong)
+       y=coord2lat(y.to_f,masterscale,basey)
+       tagsql="'"+sqlescape(array2tag(tags))+"'"
+       
+       if (id>0) then
+               ActiveRecord::Base.connection.insert("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{id},#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
+               ActiveRecord::Base.connection.update("UPDATE current_nodes SET latitude=#{y},longitude=#{x},timestamp=#{db_now},user_id=#{uid},visible=#{visible},tags=#{tagsql} WHERE id=#{id}");
+               newid=id
+       else
+               newid=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes (latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
+                         ActiveRecord::Base.connection.update("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{newid},#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
+       end
+       [id,newid]
+  end
+
+  # -----      getpoi (id,baselong,basey,masterscale)
+  #                    returns id,x,y,tag array
+  
+  def getpoi(args)
+       id,baselong,basey,masterscale=args; id=id.to_i
+       poi=ActiveRecord::Base.connection.select_one("SELECT latitude,longitude,tags "+
+               "FROM current_nodes WHERE visible=1 AND id=#{id}")
+       if poi.nil? then return [nil,nil,nil,''] end
+       [id,
+        long2coord(poi['longitude'].to_f,baselong,masterscale),
+        lat2coord(poi['latitude'].to_f,basey,masterscale),
+        tag2array(poi['tags'])]
+  end
+
   # -----      deleteway (user token, way)
   #                    returns way ID only
 
@@ -494,14 +582,21 @@ end
 #              returns way made from unwayed segments
 
 def makeway(args)
-       x,y,baselong,basey,masterscale=args
+       usertoken,x,y,baselong,basey,masterscale=args
+    uid=getuserid(usertoken)
+    return if !uid
+
        points=[]
+       toreverse=[]                            # segments to reverse
        nodesused={}                            # so we don't go over the same node twice
 
        # - find start point near x
        
        xc=coord2long(x,masterscale,baselong)
        yc=coord2lat(y,masterscale,basey)
+
+        RAILS_DEFAULT_LOGGER.info("  Message: makeway, xc=#{xc}, y=#{yc}")
+
        xs1=xc-0.001; xs2=xc+0.001
        ys1=yc-0.001; ys2=yc+0.001
        
@@ -515,9 +610,10 @@ def makeway(args)
                 WHERE (cn1.longitude BETWEEN #{xs1} AND #{xs2}) 
                   AND (cn1.latitude  BETWEEN #{ys1} AND #{ys2}) 
                   AND segment_id IS NULL 
+                   AND cs.visible=1
                   AND cn1.id=node_a AND cn1.visible=1 
                   AND cn2.id=node_b AND cn2.visible=1 
-      ORDER BY SQRT(POW(cn1.longitude-#{xc},2)+
+             ORDER BY SQRT(POW(cn1.longitude-#{xc},2)+
                                POW(cn1.latitude -#{yc},2)) 
         LIMIT 1
        EOF
@@ -533,23 +629,41 @@ def makeway(args)
        points<<[xs2,ys2,row['id2'].to_i,1,{},row['segid'].to_i]
        
        # - extend at start, then end
-       while (a,point,nodesused=findconnect(points[0][2],nodesused,'b',baselong,basey,masterscale))[0]
+       while (a,point,nodesused,toreverse=findconnect(points[0][2],nodesused,'b',toreverse,baselong,basey,masterscale))[0]
                points[0][5]=point[5]; point[5]=0       # segment leads to next node
                points.unshift(point)
                xmin=[point[0],xmin].min; xmax=[point[0],xmax].max
                ymin=[point[1],ymin].min; ymax=[point[1],ymax].max
        end
-       while (a,point,nodesused=findconnect(points[-1][2],nodesused,'a',baselong,basey,masterscale))[0]
+       while (a,point,nodesused,toreverse=findconnect(points[-1][2],nodesused,'a',toreverse,baselong,basey,masterscale))[0]
                points.push(point)
                xmin=[point[0],xmin].min; xmax=[point[0],xmax].max
                ymin=[point[1],ymin].min; ymax=[point[1],ymax].max
        end
        points[0][3]=0  # start with a move
 
+       # reverse segments in toreverse
+       if toreverse.length>0
+               sql=<<-EOF
+                       UPDATE current_segments c1, current_segments c2 
+                          SET c1.node_a=c2.node_b,c1.node_b=c2.node_a,
+                              c1.timestamp=NOW(),c1.user_id=#{uid} 
+                        WHERE c1.id=c2.id 
+                          AND c1.id IN (#{toreverse.join(',')})
+               EOF
+               ActiveRecord::Base.connection.update sql
+               sql=<<-EOF
+                       INSERT INTO segments 
+                  (SELECT * FROM current_segments 
+                    WHERE id IN (#{toreverse.join(',')}))
+               EOF
+               ActiveRecord::Base.connection.insert sql
+       end
+
        [points,xmin,xmax,ymin,ymax]
 end
 
-def findconnect(id,nodesused,lookfor,baselong,basey,masterscale)
+def findconnect(id,nodesused,lookfor,toreverse,baselong,basey,masterscale)
        # get all segments with 'id' as a point
        # (to look for both node_a and node_b, UNION is faster than node_a=id OR node_b=id)!
        sql=<<-EOF
@@ -560,6 +674,7 @@ def findconnect(id,nodesused,lookfor,baselong,basey,masterscale)
                       current_segments AS cs 
                       LEFT OUTER JOIN current_way_segments ON segment_id=cs.id 
                 WHERE segment_id IS NULL 
+                   AND cs.visible=1
                   AND cn1.id=node_a AND cn1.visible=1 
                   AND cn2.id=node_b AND cn2.visible=1 
                   AND node_a=#{id}
@@ -571,14 +686,15 @@ def findconnect(id,nodesused,lookfor,baselong,basey,masterscale)
                       current_segments AS cs 
                       LEFT OUTER JOIN current_way_segments ON segment_id=cs.id 
                 WHERE segment_id IS NULL 
+                   AND cs.visible=1
                   AND cn1.id=node_a AND cn1.visible=1 
                   AND cn2.id=node_b AND cn2.visible=1 
                   AND node_b=#{id}
        EOF
        connectlist=ActiveRecord::Base.connection.select_all sql
        
-       if lookfor=='b' then tocol='id1'; tolat='lat1'; tolon='lon1'; fromcol='id2'
-                                       else tocol='id2'; tolat='lat2'; tolon='lon2'; fromcol='id1'
+       if lookfor=='b' then tocol='id1'; tolat='lat1'; tolon='lon1'; fromcol='id2'; fromlat='lat2'; fromlon='lon2'
+                                       else tocol='id2'; tolat='lat2'; tolon='lon2'; fromcol='id1'; fromlat='lat1'; fromlon='lon1'
        end
        
        # eliminate those already in the hash
@@ -588,9 +704,13 @@ def findconnect(id,nodesused,lookfor,baselong,basey,masterscale)
                tonode=row[tocol].to_i
                fromnode=row[fromcol].to_i
                if id==tonode and !nodesused.has_key?(fromnode)
+                       # wrong way round; add, then add to 'segments to reverse' list
                        connex+=1
                        nodesused[fromnode]=true
+                       point=[long2coord(row[fromlon].to_f,baselong,masterscale),lat2coord(row[fromlat].to_f,basey,masterscale),fromnode,1,{},row['segid'].to_i]
+                       toreverse.push(row['segid'].to_i)
                elsif id==fromnode and !nodesused.has_key?(tonode)
+                       # right way round; just add
                        connex+=1
                        point=[long2coord(row[tolon].to_f,baselong,masterscale),lat2coord(row[tolat].to_f,basey,masterscale),tonode,1,{},row['segid'].to_i]
                        nodesused[tonode]=true
@@ -599,9 +719,9 @@ def findconnect(id,nodesused,lookfor,baselong,basey,masterscale)
        
        # if only one left, then add it; otherwise return false
        if connex!=1 or point.nil? then
-               return [false,[],nodesused]
+               return [false,[],nodesused,toreverse]
        else
-               return [true,point,nodesused]
+               return [true,point,nodesused,toreverse]
        end
 end
 
@@ -640,18 +760,33 @@ end
 def createuniquenodes(uqs_name,uqn_name)
        # Finds nodes which appear in uniquesegments but no other segments
        sql=<<-EOF
-               CREATE TEMPORARY TABLE #{uqn_name}
-                          SELECT DISTINCT node_id
-                             FROM (SELECT cn.id AS node_id
-                                                 FROM current_nodes AS cn,
-                                                      current_segments AS cs,
-                                                      #{uqs_name} AS us
-                                                WHERE cs.id=us.segment_id
-                                                  AND (cn.id=cs.node_a OR cn.id=cs.node_b)) AS n
-                                        LEFT JOIN current_segments AS cs2 ON node_id=cs2.node_a AND cs2.visible=1
-                                        LEFT JOIN current_segments AS cs3 ON node_id=cs3.node_b AND cs3.visible=1
-                                            WHERE cs2.node_a IS NULL
-                                              AND cs3.node_b IS NULL
+       CREATE TEMPORARY TABLE #{uqn_name}
+          SELECT DISTINCT node_id
+          FROM (SELECT cn.id AS node_id
+                FROM current_nodes AS cn,
+                     current_segments AS cs,
+                     #{uqs_name} AS us
+                WHERE cs.id=us.segment_id
+                  AND cn.id=cs.node_a) AS n
+          LEFT JOIN current_segments AS cs2 ON node_id=cs2.node_a AND cs2.visible=1
+          LEFT JOIN current_segments AS cs3 ON node_id=cs3.node_b AND cs3.visible=1
+          WHERE cs2.node_a IS NULL
+            AND cs3.node_b IS NULL
+       EOF
+       ActiveRecord::Base.connection.execute(sql)
+       sql=<<-EOF
+       INSERT INTO #{uqn_name}
+          SELECT DISTINCT node_id
+          FROM (SELECT cn.id AS node_id
+                FROM current_nodes AS cn,
+                     current_segments AS cs,
+                     #{uqs_name} AS us
+                WHERE cs.id=us.segment_id
+                  AND cn.id=cs.node_b) AS n
+          LEFT JOIN current_segments AS cs2 ON node_id=cs2.node_a AND cs2.visible=1
+          LEFT JOIN current_segments AS cs3 ON node_id=cs3.node_b AND cs3.visible=1
+          WHERE cs2.node_a IS NULL
+            AND cs3.node_b IS NULL
        EOF
        ActiveRecord::Base.connection.execute(sql)
 end
@@ -685,12 +820,13 @@ def array2tag(a)
 end
 
 def getuserid(token)
-  token=sqlescape(token)
-  if (token=~/^(.+)\+(.+)$/) then
-    return ActiveRecord::Base.connection.select_value("SELECT id FROM users WHERE active=1 AND email='#{$1}' AND pass_crypt=MD5('#{$2}')")
+  if (token =~ /^(.+)\+(.+)$/) then
+    user = User.authenticate(:username => $1, :password => $2)
   else
-    return ActiveRecord::Base.connection.select_value("SELECT id FROM users WHERE active=1 AND token='#{token}'")
+    user = User.authenticate(:token => token)
   end
+
+  return user ? user.id : nil;
 end