Merge remote-tracking branch 'upstream/pull/2204'
[rails.git] / app / controllers / api / search_controller.rb
1 module Api
2   class SearchController < ApiController
3     # Support searching for nodes, ways, or all
4     # Can search by tag k, v, or both (type->k,value->v)
5     # Can search by name (k=name,v=....)
6     authorize_resource :class => false
7
8     def search_all
9       do_search(true, true, true)
10     end
11
12     def search_ways
13       do_search(true, false, false)
14     end
15
16     def search_nodes
17       do_search(false, true, false)
18     end
19
20     def search_relations
21       do_search(false, false, true)
22     end
23
24     def do_search(do_ways, do_nodes, do_relations)
25       type = params["type"]
26       value = params["value"]
27       unless type || value
28         name = params["name"]
29         if name
30           type = "name"
31           value = name
32         end
33       end
34
35       if do_nodes
36         response.headers["Error"] = "Searching of nodes is currently unavailable"
37         head :service_unavailable
38         return false
39       end
40
41       unless value
42         response.headers["Error"] = "Searching for a key without value is currently unavailable"
43         head :service_unavailable
44         return false
45       end
46
47       # Matching for node tags table
48       if do_nodes
49         nodes = Node.joins(:node_tags)
50         nodes = nodes.where(:current_node_tags => { :k => type }) if type
51         nodes = nodes.where(:current_node_tags => { :v => value }) if value
52         nodes = nodes.limit(100)
53       else
54         nodes = []
55       end
56
57       # Matching for way tags table
58       if do_ways
59         ways = Way.joins(:way_tags)
60         ways = ways.where(:current_way_tags => { :k => type }) if type
61         ways = ways.where(:current_way_tags => { :v => value }) if value
62         ways = ways.limit(100)
63       else
64         ways = []
65       end
66
67       # Matching for relation tags table
68       if do_relations
69         relations = Relation.joins(:relation_tags)
70         relations = relations.where(:current_relation_tags => { :k => type }) if type
71         relations = relations.where(:current_relation_tags => { :v => value }) if value
72         relations = relations.limit(2000)
73       else
74         relations = []
75       end
76
77       # Fetch any node needed for our ways (only have matching nodes so far)
78       nodes += Node.find(ways.collect(&:nds).uniq)
79
80       # Print
81       visible_nodes = {}
82       changeset_cache = {}
83       user_display_name_cache = {}
84       doc = OSM::API.new.get_xml_doc
85       nodes.each do |node|
86         doc.root << node.to_xml_node(changeset_cache, user_display_name_cache)
87         visible_nodes[node.id] = node
88       end
89
90       ways.each do |way|
91         doc.root << way.to_xml_node(visible_nodes, changeset_cache, user_display_name_cache)
92       end
93
94       relations.each do |rel|
95         doc.root << rel.to_xml_node(changeset_cache, user_display_name_cache)
96       end
97
98       render :xml => doc.to_s
99     end
100   end
101 end