From 0f2aa939d447dcf137309ac2ed80e0b23ee65c63 Mon Sep 17 00:00:00 2001 From: Anton Khorev Date: Sat, 1 Feb 2025 16:49:08 +0300 Subject: [PATCH 1/2] Map 'full' to api way show action --- app/abilities/api_ability.rb | 2 +- app/controllers/api/ways_controller.rb | 35 ++++++---------- app/views/api/ways/full.json.jbuilder | 6 --- app/views/api/ways/full.xml.builder | 6 --- app/views/api/ways/show.json.jbuilder | 1 + app/views/api/ways/show.xml.builder | 1 + config/routes.rb | 7 +++- test/controllers/api/ways_controller_test.rb | 44 +++++++++++++++++--- 8 files changed, 58 insertions(+), 44 deletions(-) delete mode 100644 app/views/api/ways/full.json.jbuilder delete mode 100644 app/views/api/ways/full.xml.builder diff --git a/app/abilities/api_ability.rb b/app/abilities/api_ability.rb index c74a4d0996..7ce3aa599b 100644 --- a/app/abilities/api_ability.rb +++ b/app/abilities/api_ability.rb @@ -16,7 +16,7 @@ def initialize(token) can :read, Tracepoint can :read, User can :read, Node - can [:read, :full, :ways_for_node], Way + can [:read, :ways_for_node], Way can [:read, :full, :relations_for_node, :relations_for_way, :relations_for_relation], Relation can [:history, :read], [OldNode, OldWay, OldRelation] can :read, UserBlock diff --git a/app/controllers/api/ways_controller.rb b/app/controllers/api/ways_controller.rb index 285ed46046..b1bc8d799b 100644 --- a/app/controllers/api/ways_controller.rb +++ b/app/controllers/api/ways_controller.rb @@ -26,12 +26,21 @@ def index end def show - @way = Way.find(params[:id]) + @way = Way + @way = @way.includes(:nodes => :node_tags) if params[:full] + @way = @way.find(params[:id]) - response.last_modified = @way.timestamp + response.last_modified = @way.timestamp unless params[:full] if @way.visible - # Render the result + if params[:full] + @nodes = [] + + @way.nodes.uniq.each do |node| + @nodes << node if node.visible + end + end + respond_to do |format| format.xml format.json @@ -72,26 +81,6 @@ def destroy end end - def full - @way = Way.includes(:nodes => :node_tags).find(params[:id]) - - if @way.visible - @nodes = [] - - @way.nodes.uniq.each do |node| - @nodes << node if node.visible - end - - # Render the result - respond_to do |format| - format.xml - format.json - end - else - head :gone - end - end - ## # returns all the ways which are currently using the node given in the # :id parameter. note that this used to return deleted ways as well, but diff --git a/app/views/api/ways/full.json.jbuilder b/app/views/api/ways/full.json.jbuilder deleted file mode 100644 index 1bd127dacf..0000000000 --- a/app/views/api/ways/full.json.jbuilder +++ /dev/null @@ -1,6 +0,0 @@ -json.partial! "api/root_attributes" - -json.elements do - json.array! @nodes, :partial => "/api/nodes/node", :as => :node - json.array! [@way], :partial => "/api/ways/way", :as => :way -end diff --git a/app/views/api/ways/full.xml.builder b/app/views/api/ways/full.xml.builder deleted file mode 100644 index 025291638c..0000000000 --- a/app/views/api/ways/full.xml.builder +++ /dev/null @@ -1,6 +0,0 @@ -xml.instruct! - -xml.osm(OSM::API.new.xml_root_attributes) do |osm| - osm << (render(@nodes) || "") - osm << (render(@way) || "") -end diff --git a/app/views/api/ways/show.json.jbuilder b/app/views/api/ways/show.json.jbuilder index 92e570d869..adf8beab2d 100644 --- a/app/views/api/ways/show.json.jbuilder +++ b/app/views/api/ways/show.json.jbuilder @@ -1,5 +1,6 @@ json.partial! "api/root_attributes" json.elements do + json.array! @nodes, :partial => "/api/nodes/node", :as => :node if @nodes json.array! [@way], :partial => "way", :as => :way end diff --git a/app/views/api/ways/show.xml.builder b/app/views/api/ways/show.xml.builder index d520a08444..72b22e7374 100644 --- a/app/views/api/ways/show.xml.builder +++ b/app/views/api/ways/show.xml.builder @@ -1,5 +1,6 @@ xml.instruct! xml.osm(OSM::API.new.xml_root_attributes) do |osm| + osm << (render(@nodes) || "") if @nodes osm << (render(@way) || "") end diff --git a/config/routes.rb b/config/routes.rb index b562ca9f4a..a7631849cc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,7 +37,6 @@ get "node/:id/:version" => "old_nodes#show", :as => :api_old_node, :id => /\d+/, :version => /\d+/ get "way/:id/history" => "old_ways#history", :as => :api_way_history, :id => /\d+/ - get "way/:id/full" => "ways#full", :as => :way_full, :id => /\d+/ get "way/:id/relations" => "relations#relations_for_way", :as => :way_relations, :id => /\d+/ post "way/:id/:version/redact" => "old_ways#redact", :as => :way_version_redact, :version => /\d+/, :id => /\d+/ get "way/:id/:version" => "old_ways#show", :as => :api_old_way, :id => /\d+/, :version => /\d+/ @@ -55,7 +54,11 @@ put "node/create" => "nodes#create", :as => nil resources :ways, :only => [:index, :create] - resources :ways, :path => "way", :id => /\d+/, :only => [:show, :update, :destroy] + resources :ways, :path => "way", :id => /\d+/, :only => [:show, :update, :destroy] do + member do + get :full, :action => :show, :full => true, :as => nil + end + end put "way/create" => "ways#create", :as => nil resources :relations, :only => [:index, :create] diff --git a/test/controllers/api/ways_controller_test.rb b/test/controllers/api/ways_controller_test.rb index 2ff5e6f29f..191f9a8203 100644 --- a/test/controllers/api/ways_controller_test.rb +++ b/test/controllers/api/ways_controller_test.rb @@ -27,11 +27,11 @@ def test_routes ) assert_routing( { :path => "/api/0.6/way/1/full", :method => :get }, - { :controller => "api/ways", :action => "full", :id => "1" } + { :controller => "api/ways", :action => "show", :full => true, :id => "1" } ) assert_routing( { :path => "/api/0.6/way/1/full.json", :method => :get }, - { :controller => "api/ways", :action => "full", :id => "1", :format => "json" } + { :controller => "api/ways", :action => "show", :full => true, :id => "1", :format => "json" } ) assert_routing( { :path => "/api/0.6/way/1", :method => :put }, @@ -136,10 +136,10 @@ def test_show_json ## # check the "full" mode - def test_full + def test_show_full way = create(:way_with_nodes, :nodes_count => 3) - get way_full_path(way) + get api_way_path(way, :full => true) assert_response :success @@ -154,10 +154,42 @@ def test_full end end - def test_full_deleted + def test_show_full_json + way = create(:way_with_nodes, :nodes_count => 3) + + get api_way_path(way, :full => true, :format => "json") + + assert_response :success + + # Check the way is correctly returned + js = ActiveSupport::JSON.decode(@response.body) + assert_not_nil js + assert_equal 4, js["elements"].count + js_ways = js["elements"].filter { |e| e["type"] == "way" } + assert_equal 1, js_ways.count + assert_equal way.id, js_ways[0]["id"] + assert_equal 1, js_ways[0]["version"] + + # check that each node in the way appears once in the output as a + # reference and as the node element. + js_nodes = js["elements"].filter { |e| e["type"] == "node" } + assert_equal 3, js_nodes.count + + way.nodes.each_with_index do |n, i| + assert_equal n.id, js_ways[0]["nodes"][i] + js_nodes_with_id = js_nodes.filter { |e| e["id"] == n.id } + assert_equal 1, js_nodes_with_id.count + assert_equal n.id, js_nodes_with_id[0]["id"] + assert_equal 1, js_nodes_with_id[0]["version"] + assert_equal n.lat, js_nodes_with_id[0]["lat"] + assert_equal n.lon, js_nodes_with_id[0]["lon"] + end + end + + def test_show_full_deleted way = create(:way, :deleted) - get way_full_path(way) + get api_way_path(way, :full => true) assert_response :gone end From 04c6d38649d0794eeb09e3b62e866efe6a9f95e2 Mon Sep 17 00:00:00 2001 From: Anton Khorev Date: Sat, 1 Feb 2025 17:48:49 +0300 Subject: [PATCH 2/2] Map 'full' to api relation show action --- app/abilities/api_ability.rb | 2 +- app/controllers/api/relations_controller.rb | 129 ++++++++---------- app/views/api/relations/full.json.jbuilder | 7 - app/views/api/relations/full.xml.builder | 7 - app/views/api/relations/show.json.jbuilder | 4 +- app/views/api/relations/show.xml.builder | 4 +- config/routes.rb | 7 +- .../api/relations_controller_test.rb | 38 +++++- 8 files changed, 101 insertions(+), 97 deletions(-) delete mode 100644 app/views/api/relations/full.json.jbuilder delete mode 100644 app/views/api/relations/full.xml.builder diff --git a/app/abilities/api_ability.rb b/app/abilities/api_ability.rb index 7ce3aa599b..97b461b1f6 100644 --- a/app/abilities/api_ability.rb +++ b/app/abilities/api_ability.rb @@ -17,7 +17,7 @@ def initialize(token) can :read, User can :read, Node can [:read, :ways_for_node], Way - can [:read, :full, :relations_for_node, :relations_for_way, :relations_for_relation], Relation + can [:read, :relations_for_node, :relations_for_way, :relations_for_relation], Relation can [:history, :read], [OldNode, OldWay, OldRelation] can :read, UserBlock diff --git a/app/controllers/api/relations_controller.rb b/app/controllers/api/relations_controller.rb index f712534f00..006b3e8a62 100644 --- a/app/controllers/api/relations_controller.rb +++ b/app/controllers/api/relations_controller.rb @@ -26,9 +26,64 @@ def index end def show - @relation = Relation.find(params[:id]) - response.last_modified = @relation.timestamp - if @relation.visible + relation = Relation.find(params[:id]) + + response.last_modified = relation.timestamp unless params[:full] + + @nodes = [] + @ways = [] + @relations = [] + + if relation.visible + if params[:full] + # with parameter :full + # returns representation of one relation object plus all its + # members, plus all nodes part of member ways + + # first find the ids of nodes, ways and relations referenced by this + # relation - note that we exclude this relation just in case. + + node_ids = relation.members.select { |m| m[0] == "Node" }.pluck(1) + way_ids = relation.members.select { |m| m[0] == "Way" }.pluck(1) + relation_ids = relation.members.select { |m| m[0] == "Relation" && m[1] != relation.id }.pluck(1) + + # next load the relations and the ways. + + relations = Relation.where(:id => relation_ids).includes(:relation_tags) + ways = Way.where(:id => way_ids).includes(:way_nodes, :way_tags) + + # now additionally collect nodes referenced by ways. Note how we + # recursively evaluate ways but NOT relations. + + way_node_ids = ways.collect do |way| + way.way_nodes.collect(&:node_id) + end + node_ids += way_node_ids.flatten + nodes = Node.where(:id => node_ids.uniq).includes(:node_tags) + + @nodes = [] + nodes.each do |node| + next unless node.visible? # should be unnecessary if data is consistent. + + @nodes << node + end + + ways.each do |way| + next unless way.visible? # should be unnecessary if data is consistent. + + @ways << way + end + + relations.each do |rel| + next unless rel.visible? # should be unnecessary if data is consistent. + + @relations << rel + end + end + + # finally add self + @relations << relation + # Render the result respond_to do |format| format.xml @@ -68,74 +123,6 @@ def destroy end end - # ----------------------------------------------------------------- - # full - # - # input parameters: id - # - # returns XML representation of one relation object plus all its - # members, plus all nodes part of member ways - # ----------------------------------------------------------------- - def full - relation = Relation.find(params[:id]) - - if relation.visible - - # first find the ids of nodes, ways and relations referenced by this - # relation - note that we exclude this relation just in case. - - node_ids = relation.members.select { |m| m[0] == "Node" }.pluck(1) - way_ids = relation.members.select { |m| m[0] == "Way" }.pluck(1) - relation_ids = relation.members.select { |m| m[0] == "Relation" && m[1] != relation.id }.pluck(1) - - # next load the relations and the ways. - - relations = Relation.where(:id => relation_ids).includes(:relation_tags) - ways = Way.where(:id => way_ids).includes(:way_nodes, :way_tags) - - # now additionally collect nodes referenced by ways. Note how we - # recursively evaluate ways but NOT relations. - - way_node_ids = ways.collect do |way| - way.way_nodes.collect(&:node_id) - end - node_ids += way_node_ids.flatten - nodes = Node.where(:id => node_ids.uniq).includes(:node_tags) - - @nodes = [] - nodes.each do |node| - next unless node.visible? # should be unnecessary if data is consistent. - - @nodes << node - end - - @ways = [] - ways.each do |way| - next unless way.visible? # should be unnecessary if data is consistent. - - @ways << way - end - - @relations = [] - relations.each do |rel| - next unless rel.visible? # should be unnecessary if data is consistent. - - @relations << rel - end - - # finally add self - @relations << relation - - # Render the result - respond_to do |format| - format.xml - format.json - end - else - head :gone - end - end - def relations_for_way relations_for_object("Way") end diff --git a/app/views/api/relations/full.json.jbuilder b/app/views/api/relations/full.json.jbuilder deleted file mode 100644 index 16331a89e6..0000000000 --- a/app/views/api/relations/full.json.jbuilder +++ /dev/null @@ -1,7 +0,0 @@ -json.partial! "api/root_attributes" - -json.elements do - json.array! @nodes, :partial => "/api/nodes/node", :as => :node - json.array! @ways, :partial => "/api/ways/way", :as => :way - json.array! @relations, :partial => "/api/relations/relation", :as => :relation -end diff --git a/app/views/api/relations/full.xml.builder b/app/views/api/relations/full.xml.builder deleted file mode 100644 index e23061727c..0000000000 --- a/app/views/api/relations/full.xml.builder +++ /dev/null @@ -1,7 +0,0 @@ -xml.instruct! - -xml.osm(OSM::API.new.xml_root_attributes) do |osm| - osm << (render(@nodes) || "") - osm << (render(@ways) || "") - osm << (render(@relations) || "") -end diff --git a/app/views/api/relations/show.json.jbuilder b/app/views/api/relations/show.json.jbuilder index e5da7cd3f4..16331a89e6 100644 --- a/app/views/api/relations/show.json.jbuilder +++ b/app/views/api/relations/show.json.jbuilder @@ -1,5 +1,7 @@ json.partial! "api/root_attributes" json.elements do - json.array! [@relation], :partial => "relation", :as => :relation + json.array! @nodes, :partial => "/api/nodes/node", :as => :node + json.array! @ways, :partial => "/api/ways/way", :as => :way + json.array! @relations, :partial => "/api/relations/relation", :as => :relation end diff --git a/app/views/api/relations/show.xml.builder b/app/views/api/relations/show.xml.builder index 555eb4db5f..e23061727c 100644 --- a/app/views/api/relations/show.xml.builder +++ b/app/views/api/relations/show.xml.builder @@ -1,5 +1,7 @@ xml.instruct! xml.osm(OSM::API.new.xml_root_attributes) do |osm| - osm << (render(@relation) || "") + osm << (render(@nodes) || "") + osm << (render(@ways) || "") + osm << (render(@relations) || "") end diff --git a/config/routes.rb b/config/routes.rb index a7631849cc..bc06e5f38e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -43,7 +43,6 @@ get "relation/:id/relations" => "relations#relations_for_relation", :as => :relation_relations, :id => /\d+/ get "relation/:id/history" => "old_relations#history", :as => :api_relation_history, :id => /\d+/ - get "relation/:id/full" => "relations#full", :as => :relation_full, :id => /\d+/ post "relation/:id/:version/redact" => "old_relations#redact", :as => :relation_version_redact, :version => /\d+/, :id => /\d+/ get "relation/:id/:version" => "old_relations#show", :as => :api_old_relation, :id => /\d+/, :version => /\d+/ end @@ -62,7 +61,11 @@ put "way/create" => "ways#create", :as => nil resources :relations, :only => [:index, :create] - resources :relations, :path => "relation", :id => /\d+/, :only => [:show, :update, :destroy] + resources :relations, :path => "relation", :id => /\d+/, :only => [:show, :update, :destroy] do + member do + get :full, :action => :show, :full => true, :as => nil + end + end put "relation/create" => "relations#create", :as => nil resource :map, :only => :show diff --git a/test/controllers/api/relations_controller_test.rb b/test/controllers/api/relations_controller_test.rb index 34953f7b7a..803a57acf5 100644 --- a/test/controllers/api/relations_controller_test.rb +++ b/test/controllers/api/relations_controller_test.rb @@ -27,11 +27,11 @@ def test_routes ) assert_routing( { :path => "/api/0.6/relation/1/full", :method => :get }, - { :controller => "api/relations", :action => "full", :id => "1" } + { :controller => "api/relations", :action => "show", :full => true, :id => "1" } ) assert_routing( { :path => "/api/0.6/relation/1/full.json", :method => :get }, - { :controller => "api/relations", :action => "full", :id => "1", :format => "json" } + { :controller => "api/relations", :action => "show", :full => true, :id => "1", :format => "json" } ) assert_routing( { :path => "/api/0.6/relation/1", :method => :put }, @@ -149,19 +149,19 @@ def test_show end def test_full_not_found - get relation_full_path(999999) + get api_relation_path(999999, :full => true) assert_response :not_found end def test_full_deleted - get relation_full_path(create(:relation, :deleted)) + get api_relation_path(create(:relation, :deleted), :full => true) assert_response :gone end def test_full_empty relation = create(:relation) - get relation_full_path(relation) + get api_relation_path(relation, :full => true) assert_response :success assert_dom "relation", :count => 1 do @@ -174,7 +174,7 @@ def test_full_with_node_member node = create(:node) create(:relation_member, :relation => relation, :member => node) - get relation_full_path(relation) + get api_relation_path(relation, :full => true) assert_response :success assert_dom "node", :count => 1 do @@ -190,7 +190,7 @@ def test_full_with_way_member way = create(:way_with_nodes) create(:relation_member, :relation => relation, :member => way) - get relation_full_path(relation) + get api_relation_path(relation, :full => true) assert_response :success assert_dom "node", :count => 1 do @@ -204,6 +204,30 @@ def test_full_with_way_member end end + def test_full_with_node_member_json + relation = create(:relation) + node = create(:node) + create(:relation_member, :relation => relation, :member => node) + + get api_relation_path(relation, :full => true, :format => "json") + + assert_response :success + js = ActiveSupport::JSON.decode(@response.body) + assert_not_nil js + assert_equal 2, js["elements"].count + + js_relations = js["elements"].filter { |e| e["type"] == "relation" } + assert_equal 1, js_relations.count + assert_equal relation.id, js_relations[0]["id"] + assert_equal 1, js_relations[0]["members"].count + assert_equal "node", js_relations[0]["members"][0]["type"] + assert_equal node.id, js_relations[0]["members"][0]["ref"] + + js_nodes = js["elements"].filter { |e| e["type"] == "node" } + assert_equal 1, js_nodes.count + assert_equal node.id, js_nodes[0]["id"] + end + ## # check that all relations containing a particular node, and no extra # relations, are returned from the relations_for_node call.