Added test for relations_for_node where the relation had been deleted.
[rails.git] / app / controllers / relation_controller.rb
1 class RelationController < ApplicationController
2   require 'xml/libxml'
3
4   session :off
5   before_filter :authorize, :only => [:create, :update, :delete]
6   before_filter :check_write_availability, :only => [:create, :update, :delete]
7   before_filter :check_read_availability, :except => [:create, :update, :delete]
8   after_filter :compress_output
9
10   def create
11     begin
12       if request.put?
13         relation = Relation.from_xml(request.raw_post, true)
14
15         if relation
16           relation.create_with_history @user
17           render :text => relation.id.to_s, :content_type => "text/plain"
18         else
19           render :nothing => true, :status => :bad_request
20         end
21       else
22         render :nothing => true, :status => :method_not_allowed
23       end
24     rescue OSM::APIError => ex
25       render ex.render_opts
26     end
27   end
28
29   def read
30     begin
31       relation = Relation.find(params[:id])
32       response.headers['Last-Modified'] = relation.timestamp.rfc822
33       if relation.visible
34         render :text => relation.to_xml.to_s, :content_type => "text/xml"
35       else
36         render :text => "", :status => :gone
37       end
38     rescue ActiveRecord::RecordNotFound
39       render :nothing => true, :status => :not_found
40     rescue
41       render :nothing => true, :status => :internal_server_error
42     end
43   end
44
45   def update
46     logger.debug request.raw_post
47     begin
48       relation = Relation.find(params[:id])
49       new_relation = Relation.from_xml(request.raw_post)
50
51       if new_relation and new_relation.id == relation.id
52         relation.update_from new_relation, @user
53         render :text => relation.version.to_s, :content_type => "text/plain"
54       else
55         render :nothing => true, :status => :bad_request
56       end
57     rescue ActiveRecord::RecordNotFound
58       render :nothing => true, :status => :not_found
59     rescue OSM::APIError => ex
60       render ex.render_opts
61     end
62   end
63
64   def delete
65 #XXX check if member somewhere!
66     begin
67       relation = Relation.find(params[:id])
68       new_relation = Relation.from_xml(request.raw_post)
69       if new_relation and new_relation.id == relation.id
70         relation.delete_with_history!(new_relation, @user)
71         render :text => relation.version.to_s, :content_type => "text/plain"
72       else
73         render :nothing => true, :status => :bad_request
74       end
75     rescue OSM::APIError => ex
76       render ex.render_opts
77     rescue ActiveRecord::RecordNotFound
78       render :nothing => true, :status => :not_found
79     end
80   end
81
82   # -----------------------------------------------------------------
83   # full
84   # 
85   # input parameters: id
86   #
87   # returns XML representation of one relation object plus all its
88   # members, plus all nodes part of member ways
89   # -----------------------------------------------------------------
90   def full
91     begin
92       relation = Relation.find(params[:id])
93
94       if relation.visible
95
96         # first collect nodes, ways, and relations referenced by this relation.
97         
98         ways = Way.find_by_sql("select w.* from current_ways w,current_relation_members rm where "+
99             "rm.member_type='way' and rm.member_id=w.id and rm.id=#{relation.id}");
100         nodes = Node.find_by_sql("select n.* from current_nodes n,current_relation_members rm where "+
101             "rm.member_type='node' and rm.member_id=n.id and rm.id=#{relation.id}");
102         # note query is built to exclude self just in case.
103         relations = Relation.find_by_sql("select r.* from current_relations r,current_relation_members rm where "+
104             "rm.member_type='relation' and rm.member_id=r.id and rm.id=#{relation.id} and r.id<>rm.id");
105
106         # now additionally collect nodes referenced by ways. Note how we recursively 
107         # evaluate ways but NOT relations.
108
109         node_ids = nodes.collect {|node| node.id }
110         way_node_ids = ways.collect { |way|
111            way.way_nodes.collect { |way_node| way_node.node_id }
112         }
113         way_node_ids.flatten!
114         way_node_ids.uniq
115         way_node_ids -= node_ids
116         nodes += Node.find(way_node_ids)
117     
118         # create XML.
119         doc = OSM::API.new.get_xml_doc
120         visible_nodes = {}
121         user_display_name_cache = {}
122
123         nodes.each do |node|
124           if node.visible? # should be unnecessary if data is consistent.
125             doc.root << node.to_xml_node(user_display_name_cache)
126             visible_nodes[node.id] = node
127           end
128         end
129         ways.each do |way|
130           if way.visible? # should be unnecessary if data is consistent.
131             doc.root << way.to_xml_node(visible_nodes, user_display_name_cache)
132           end
133         end
134         relations.each do |rel|
135           if rel.visible? # should be unnecessary if data is consistent.
136             doc.root << rel.to_xml_node(user_display_name_cache)
137           end
138         end
139         # finally add self and output
140         doc.root << relation.to_xml_node(user_display_name_cache)
141         render :text => doc.to_s, :content_type => "text/xml"
142
143       else
144
145         render :text => "", :status => :gone
146       end
147
148     rescue ActiveRecord::RecordNotFound
149       render :nothing => true, :status => :not_found
150
151     rescue
152       render :nothing => true, :status => :internal_server_error
153     end
154   end
155
156   def relations
157     ids = params['relations'].split(',').collect { |w| w.to_i }
158
159     if ids.length > 0
160       doc = OSM::API.new.get_xml_doc
161
162       Relation.find(ids).each do |relation|
163         doc.root << relation.to_xml_node
164       end
165
166       render :text => doc.to_s, :content_type => "text/xml"
167     else
168       render :nothing => true, :status => :bad_request
169     end
170   end
171
172   def relations_for_way
173     relations_for_object("way")
174   end
175   def relations_for_node
176     relations_for_object("node")
177   end
178   def relations_for_relation
179     relations_for_object("relation")
180   end
181
182   def relations_for_object(objtype)
183     relationids = RelationMember.find(:all, :conditions => ['member_type=? and member_id=?', objtype, params[:id]]).collect { |ws| ws.id }.uniq
184
185     doc = OSM::API.new.get_xml_doc
186
187     Relation.find(relationids).each do |relation|
188       doc.root << relation.to_xml_node if relation.visible
189     end
190
191     render :text => doc.to_s, :content_type => "text/xml"
192   end
193 end