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