1 class NoteController < ApplicationController
3 layout 'site', :only => [:mine]
5 before_filter :check_api_readable
6 before_filter :authorize_web, :only => [:create, :close, :update, :delete, :mine]
7 before_filter :check_api_writable, :only => [:create, :close, :update, :delete]
8 before_filter :set_locale, :only => [:mine]
9 after_filter :compress_output
10 around_filter :api_call_handle_error, :api_call_timeout
12 # Help methods for checking boundary sanity and area size
16 # Return a list of notes in a given area
18 # Figure out the bbox - we prefer a bbox argument but also
19 # support the old, deprecated, method with four arguments
21 raise OSM::APIBadUserInput.new("Invalid bbox") unless params[:bbox].count(",") == 3
23 bbox = params[:bbox].split(",")
25 raise OSM::APIBadUserInput.new("No l was given") unless params[:l]
26 raise OSM::APIBadUserInput.new("No r was given") unless params[:r]
27 raise OSM::APIBadUserInput.new("No b was given") unless params[:b]
28 raise OSM::APIBadUserInput.new("No t was given") unless params[:t]
30 bbox = [ params[:l], params[:b], params[:r], params[:t] ]
33 # Get the sanitised boundaries
34 @min_lon, @min_lat, @max_lon, @max_lat = sanitise_boundaries(bbox)
36 # Get any conditions that need to be applied
37 conditions = closed_condition
39 # Check that the boundaries are valid
40 check_boundaries(@min_lon, @min_lat, @max_lon, @max_lat, MAX_NOTE_REQUEST_AREA)
42 # Find the notes we want to return
43 @notes = Note.find_by_area(@min_lat, @min_lon, @max_lat, @max_lon,
44 :include => :comments,
45 :conditions => conditions,
46 :order => "updated_at DESC",
47 :limit => result_limit)
50 respond_to do |format|
61 # Check the arguments are sane
62 raise OSM::APIBadUserInput.new("No lat was given") unless params[:lat]
63 raise OSM::APIBadUserInput.new("No lon was given") unless params[:lon]
64 raise OSM::APIBadUserInput.new("No text was given") unless params[:text]
66 # Extract the arguments
67 lon = params[:lon].to_f
68 lat = params[:lat].to_f
69 comment = params[:text]
72 # Include in a transaction to ensure that there is always a note_comment for every note
75 @note = Note.create(:lat => lat, :lon => lon)
76 raise OSM::APIBadUserInput.new("The note is outside this world") unless @note.in_world?
78 #TODO: move this into a helper function
80 url = "http://nominatim.openstreetmap.org/reverse?lat=" + lat.to_s + "&lon=" + lon.to_s + "&zoom=16"
81 response = REXML::Document.new(Net::HTTP.get(URI.parse(url)))
83 if result = response.get_text("reversegeocode/result")
84 @note.nearby_place = result.to_s
86 @note.nearby_place = "unknown"
88 rescue Exception => err
89 @note.nearby_place = "unknown"
95 # Add a comment to the note
96 add_comment(@note, comment, name, "opened")
104 # Add a comment to an existing note
106 # Check the arguments are sane
107 raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
108 raise OSM::APIBadUserInput.new("No text was given") unless params[:text]
110 # Extract the arguments
111 id = params[:id].to_i
112 comment = params[:text]
113 name = params[:name] or "NoName"
115 # Find the note and check it is valid
117 raise OSM::APINotFoundError unless note
118 raise OSM::APIAlreadyDeletedError unless note.visible?
120 # Add a comment to the note
122 add_comment(note, comment, name, "commented")
125 # Send an OK response
132 # Check the arguments are sane
133 raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
135 # Extract the arguments
136 id = params[:id].to_i
139 # Find the note and check it is valid
140 note = Note.find_by_id(id)
141 raise OSM::APINotFoundError unless note
142 raise OSM::APIAlreadyDeletedError unless note.visible?
144 # Close the note and add a comment
148 add_comment(note, nil, name, "closed")
151 # Send an OK response
156 # Get a feed of recent notes and comments
158 # Get any conditions that need to be applied
159 conditions = closed_condition
163 raise OSM::APIBadUserInput.new("Invalid bbox") unless params[:bbox].count(",") == 3
165 @min_lon, @min_lat, @max_lon, @max_lat = sanitise_boundaries(params[:bbox].split(','))
167 check_boundaries(@min_lon, @min_lat, @max_lon, @max_lat, MAX_NOTE_REQUEST_AREA)
169 conditions = cond_merge conditions, [OSM.sql_for_area(@min_lat, @min_lon, @max_lat, @max_lon, "notes.")]
172 # Find the comments we want to return
173 @comments = NoteComment.find(:all,
174 :conditions => conditions,
175 :order => "created_at DESC",
176 :limit => result_limit,
181 respond_to do |format|
189 # Check the arguments are sane
190 raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
192 # Find the note and check it is valid
193 @note = Note.find(params[:id])
194 raise OSM::APINotFoundError unless @note
195 raise OSM::APIAlreadyDeletedError unless @note.visible?
198 respond_to do |format|
207 # Delete (hide) a note
209 # Check the arguments are sane
210 raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
212 # Extract the arguments
213 id = params[:id].to_i
216 # Find the note and check it is valid
218 raise OSM::APINotFoundError unless note
219 raise OSM::APIAlreadyDeletedError unless note.visible?
221 # Mark the note as hidden
223 note.status = "hidden"
226 add_comment(note, nil, name, "hidden")
230 render :text => "ok\n", :content_type => "text/html"
234 # Return a list of notes matching a given string
236 # Check the arguments are sane
237 raise OSM::APIBadUserInput.new("No query string was given") unless params[:q]
239 # Get any conditions that need to be applied
240 conditions = closed_condition
241 conditions = cond_merge conditions, ['note_comments.body ~ ?', params[:q]]
243 # Find the notes we want to return
244 @notes = Note.find(:all,
245 :conditions => conditions,
246 :order => "updated_at DESC",
247 :limit => result_limit,
249 :include => :comments)
252 respond_to do |format|
253 format.html { render :action => :list, :format => :rjs, :content_type => "text/javascript"}
254 format.rss { render :action => :list }
256 format.xml { render :action => :list }
257 format.json { render :action => :list }
258 format.gpx { render :action => :list }
263 if params[:display_name]
264 @user2 = User.find_by_display_name(params[:display_name], :conditions => { :status => ["active", "confirmed"] })
267 if @user2.data_public? or @user2 == @user
268 conditions = ['note_comments.author_id = ?', @user2.id]
270 conditions = ['false']
272 else #if request.format == :html
273 @title = t 'user.no_such_user.title'
274 @not_found_user = params[:display_name]
275 render :template => 'user/no_such_user', :status => :not_found
281 user_link = render_to_string :partial => "user", :object => @user2
284 @title = t 'note.mine.title', :user => @user2.display_name
285 @heading = t 'note.mine.heading', :user => @user2.display_name
286 @description = t 'note.mine.description', :user => user_link
288 @page = (params[:page] || 1).to_i
291 @notes = Note.find(:all,
292 :include => [:comments, {:comments => :author}],
294 :order => "updated_at DESC",
295 :conditions => conditions,
296 :offset => (@page - 1) * @page_size,
297 :limit => @page_size).uniq
301 #------------------------------------------------------------
302 # utility functions below.
303 #------------------------------------------------------------
306 # merge two conditions
307 # TODO: this is a copy from changeset_controler.rb and should be factored out to share
312 return [ a_str + " AND " + b_str ] + a + b
321 # Render an OK response
323 if params[:format] == "js"
324 render :text => "osbResponse();", :content_type => "text/javascript"
326 render :text => "ok " + @note.id.to_s + "\n", :content_type => "text/plain" if @note
327 render :text => "ok\n", :content_type => "text/plain" unless @note
332 # Get the maximum number of results to return
334 if params[:limit] and params[:limit].to_i > 0 and params[:limit].to_i < 10000
342 # Generate a condition to choose which bugs we want based
343 # on their status and the user's request parameters
346 closed_since = params[:closed].to_i
352 conditions = ["status != 'hidden'"]
353 elsif closed_since > 0
354 conditions = ["(status = 'open' OR (status = 'closed' AND closed_at > '#{Time.now - closed_since.days}'))"]
356 conditions = ["status = 'open'"]
363 # Add a comment to a note
364 def add_comment(note, text, name, event)
365 name = "NoName" if name.nil?
367 attributes = { :visible => true, :event => event, :body => text }
370 attributes[:author_id] = @user.id
371 attributes[:author_name] = @user.display_name
373 attributes[:author_ip] = request.remote_ip
374 attributes[:author_name] = name + " (a)"
377 note.comments.create(attributes)
379 note.comments.map { |c| c.author }.uniq.each do |user|
380 if user and user != @user
381 Notifier.deliver_note_comment_notification(comment, user)