]> git.openstreetmap.org Git - rails.git/blob - app/controllers/api/relations_controller.rb
Enforce rate limit for API calls which make changes
[rails.git] / app / controllers / api / relations_controller.rb
1 module Api
2   class RelationsController < ApiController
3     require "xml/libxml"
4
5     before_action :check_api_writable, :only => [:create, :update, :delete]
6     before_action :check_api_readable, :except => [:create, :update, :delete]
7     before_action :authorize, :only => [:create, :update, :delete]
8
9     authorize_resource
10
11     before_action :require_public_data, :only => [:create, :update, :delete]
12     around_action :api_call_handle_error, :api_call_timeout
13
14     before_action :set_request_formats, :except => [:create, :update, :delete]
15     before_action :check_rate_limit, :only => [:create, :update, :delete]
16
17     def index
18       raise OSM::APIBadUserInput, "The parameter relations is required, and must be of the form relations=id[,id[,id...]]" unless params["relations"]
19
20       ids = params["relations"].split(",").collect(&:to_i)
21
22       raise OSM::APIBadUserInput, "No relations were given to search for" if ids.empty?
23
24       @relations = Relation.find(ids)
25
26       # Render the result
27       respond_to do |format|
28         format.xml
29         format.json
30       end
31     end
32
33     def show
34       @relation = Relation.find(params[:id])
35       response.last_modified = @relation.timestamp
36       if @relation.visible
37         # Render the result
38         respond_to do |format|
39           format.xml
40           format.json
41         end
42       else
43         head :gone
44       end
45     end
46
47     def create
48       assert_method :put
49
50       relation = Relation.from_xml(request.raw_post, :create => true)
51
52       # Assume that Relation.from_xml has thrown an exception if there is an error parsing the xml
53       relation.create_with_history current_user
54       render :plain => relation.id.to_s
55     end
56
57     def update
58       logger.debug request.raw_post
59
60       relation = Relation.find(params[:id])
61       new_relation = Relation.from_xml(request.raw_post)
62
63       raise OSM::APIBadUserInput, "The id in the url (#{relation.id}) is not the same as provided in the xml (#{new_relation.id})" unless new_relation && new_relation.id == relation.id
64
65       relation.update_from new_relation, current_user
66       render :plain => relation.version.to_s
67     end
68
69     def delete
70       relation = Relation.find(params[:id])
71       new_relation = Relation.from_xml(request.raw_post)
72       if new_relation && new_relation.id == relation.id
73         relation.delete_with_history!(new_relation, current_user)
74         render :plain => relation.version.to_s
75       else
76         head :bad_request
77       end
78     end
79
80     # -----------------------------------------------------------------
81     # full
82     #
83     # input parameters: id
84     #
85     # returns XML representation of one relation object plus all its
86     # members, plus all nodes part of member ways
87     # -----------------------------------------------------------------
88     def full
89       relation = Relation.find(params[:id])
90
91       if relation.visible
92
93         # first find the ids of nodes, ways and relations referenced by this
94         # relation - note that we exclude this relation just in case.
95
96         node_ids = relation.members.select { |m| m[0] == "Node" }.pluck(1)
97         way_ids = relation.members.select { |m| m[0] == "Way" }.pluck(1)
98         relation_ids = relation.members.select { |m| m[0] == "Relation" && m[1] != relation.id }.pluck(1)
99
100         # next load the relations and the ways.
101
102         relations = Relation.where(:id => relation_ids).includes(:relation_tags)
103         ways = Way.where(:id => way_ids).includes(:way_nodes, :way_tags)
104
105         # now additionally collect nodes referenced by ways. Note how we
106         # recursively evaluate ways but NOT relations.
107
108         way_node_ids = ways.collect do |way|
109           way.way_nodes.collect(&:node_id)
110         end
111         node_ids += way_node_ids.flatten
112         nodes = Node.where(:id => node_ids.uniq).includes(:node_tags)
113
114         visible_nodes = {}
115
116         @nodes = []
117         nodes.each do |node|
118           next unless node.visible? # should be unnecessary if data is consistent.
119
120           @nodes << node
121           visible_nodes[node.id] = node
122         end
123
124         @ways = []
125         ways.each do |way|
126           next unless way.visible? # should be unnecessary if data is consistent.
127
128           @ways << way
129         end
130
131         @relations = []
132         relations.each do |rel|
133           next unless rel.visible? # should be unnecessary if data is consistent.
134
135           @relations << rel
136         end
137
138         # finally add self
139         @relations << relation
140
141         # Render the result
142         respond_to do |format|
143           format.xml
144           format.json
145         end
146       else
147         head :gone
148       end
149     end
150
151     def relations_for_way
152       relations_for_object("Way")
153     end
154
155     def relations_for_node
156       relations_for_object("Node")
157     end
158
159     def relations_for_relation
160       relations_for_object("Relation")
161     end
162
163     private
164
165     def relations_for_object(objtype)
166       relationids = RelationMember.where(:member_type => objtype, :member_id => params[:id]).collect(&:relation_id).uniq
167
168       @relations = []
169
170       Relation.find(relationids).each do |relation|
171         @relations << relation if relation.visible
172       end
173
174       # Render the result
175       respond_to do |format|
176         format.xml
177         format.json
178       end
179     end
180   end
181 end