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|
51 format.html { render :format => :rjs, :content_type => "text/javascript" }
55 format.json { render :json => @notes.to_json }
63 # Check the arguments are sane
64 raise OSM::APIBadUserInput.new("No lat was given") unless params[:lat]
65 raise OSM::APIBadUserInput.new("No lon was given") unless params[:lon]
66 raise OSM::APIBadUserInput.new("No text was given") unless params[:text]
68 # Extract the arguments
69 lon = params[:lon].to_f
70 lat = params[:lat].to_f
71 comment = params[:text]
74 # Include in a transaction to ensure that there is always a note_comment for every note
77 @note = Note.create(:lat => lat, :lon => lon)
78 raise OSM::APIBadUserInput.new("The note is outside this world") unless @note.in_world?
80 #TODO: move this into a helper function
82 url = "http://nominatim.openstreetmap.org/reverse?lat=" + lat.to_s + "&lon=" + lon.to_s + "&zoom=16"
83 response = REXML::Document.new(Net::HTTP.get(URI.parse(url)))
85 if result = response.get_text("reversegeocode/result")
86 @note.nearby_place = result.to_s
88 @note.nearby_place = "unknown"
90 rescue Exception => err
91 @note.nearby_place = "unknown"
97 # Add a comment to the note
98 add_comment(@note, comment, name, "opened")
101 # Send an OK response
106 # Add a comment to an existing note
108 # Check the arguments are sane
109 raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
110 raise OSM::APIBadUserInput.new("No text was given") unless params[:text]
112 # Extract the arguments
113 id = params[:id].to_i
114 comment = params[:text]
115 name = params[:name] or "NoName"
117 # Find the note and check it is valid
119 raise OSM::APINotFoundError unless note
120 raise OSM::APIAlreadyDeletedError unless note.visible?
122 # Add a comment to the note
124 add_comment(note, comment, name, "commented")
127 # Send an OK response
134 # Check the arguments are sane
135 raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
137 # Extract the arguments
138 id = params[:id].to_i
141 # Find the note and check it is valid
142 note = Note.find_by_id(id)
143 raise OSM::APINotFoundError unless note
144 raise OSM::APIAlreadyDeletedError unless note.visible?
146 # Close the note and add a comment
150 add_comment(note, nil, name, "closed")
153 # Send an OK response
158 # Get a feed of recent notes and comments
160 # Get any conditions that need to be applied
161 conditions = closed_condition
165 raise OSM::APIBadUserInput.new("Invalid bbox") unless params[:bbox].count(",") == 3
167 @min_lon, @min_lat, @max_lon, @max_lat = sanitise_boundaries(params[:bbox].split(','))
169 check_boundaries(@min_lon, @min_lat, @max_lon, @max_lat, MAX_NOTE_REQUEST_AREA)
171 conditions = cond_merge conditions, [OSM.sql_for_area(@min_lat, @min_lon, @max_lat, @max_lon, "notes.")]
174 # Find the comments we want to return
175 @comments = NoteComment.find(:all,
176 :conditions => conditions,
177 :order => "created_at DESC",
178 :limit => result_limit,
183 respond_to do |format|
191 # Check the arguments are sane
192 raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
194 # Find the note and check it is valid
195 @note = Note.find(params[:id])
196 raise OSM::APINotFoundError unless @note
197 raise OSM::APIAlreadyDeletedError unless @note.visible?
200 respond_to do |format|
203 format.json { render :json => @note.to_json }
209 # Delete (hide) a note
211 # Check the arguments are sane
212 raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
214 # Extract the arguments
215 id = params[:id].to_i
218 # Find the note and check it is valid
220 raise OSM::APINotFoundError unless note
221 raise OSM::APIAlreadyDeletedError unless note.visible?
223 # Mark the note as hidden
225 note.status = "hidden"
228 add_comment(note, nil, name, "hidden")
232 render :text => "ok\n", :content_type => "text/html"
236 # Return a list of notes matching a given string
238 # Check the arguments are sane
239 raise OSM::APIBadUserInput.new("No query string was given") unless params[:q]
241 # Get any conditions that need to be applied
242 conditions = closed_condition
243 conditions = cond_merge conditions, ['note_comments.body ~ ?', params[:q]]
245 # Find the notes we want to return
246 @notes = Note.find(:all,
247 :conditions => conditions,
248 :order => "updated_at DESC",
249 :limit => result_limit,
251 :include => :comments)
254 respond_to do |format|
255 format.html { render :action => :list, :format => :rjs, :content_type => "text/javascript"}
256 format.rss { render :action => :list }
258 format.xml { render :action => :list }
259 format.json { render :json => @notes.to_json }
260 format.gpx { render :action => :list }
265 if params[:display_name]
266 @user2 = User.find_by_display_name(params[:display_name], :conditions => { :status => ["active", "confirmed"] })
269 if @user2.data_public? or @user2 == @user
270 conditions = ['note_comments.author_id = ?', @user2.id]
272 conditions = ['false']
274 else #if request.format == :html
275 @title = t 'user.no_such_user.title'
276 @not_found_user = params[:display_name]
277 render :template => 'user/no_such_user', :status => :not_found
283 user_link = render_to_string :partial => "user", :object => @user2
286 @title = t 'note.mine.title', :user => @user2.display_name
287 @heading = t 'note.mine.heading', :user => @user2.display_name
288 @description = t 'note.mine.description', :user => user_link
290 @page = (params[:page] || 1).to_i
293 @notes = Note.find(:all,
294 :include => [:comments, {:comments => :author}],
296 :order => "updated_at DESC",
297 :conditions => conditions,
298 :offset => (@page - 1) * @page_size,
299 :limit => @page_size).uniq
303 #------------------------------------------------------------
304 # utility functions below.
305 #------------------------------------------------------------
308 # merge two conditions
309 # TODO: this is a copy from changeset_controler.rb and should be factored out to share
314 return [ a_str + " AND " + b_str ] + a + b
323 # Render an OK response
325 if params[:format] == "js"
326 render :text => "osbResponse();", :content_type => "text/javascript"
328 render :text => "ok " + @note.id.to_s + "\n", :content_type => "text/plain" if @note
329 render :text => "ok\n", :content_type => "text/plain" unless @note
334 # Get the maximum number of results to return
336 if params[:limit] and params[:limit].to_i > 0 and params[:limit].to_i < 10000
344 # Generate a condition to choose which bugs we want based
345 # on their status and the user's request parameters
348 closed_since = params[:closed].to_i
354 conditions = ["status != 'hidden'"]
355 elsif closed_since > 0
356 conditions = ["(status = 'open' OR (status = 'closed' AND closed_at > '#{Time.now - closed_since.days}'))"]
358 conditions = ["status = 'open'"]
365 # Add a comment to a note
366 def add_comment(note, text, name, event)
367 name = "NoName" if name.nil?
369 attributes = { :visible => true, :event => event, :body => text }
372 attributes[:author_id] = @user.id
373 attributes[:author_name] = @user.display_name
375 attributes[:author_ip] = request.remote_ip
376 attributes[:author_name] = name + " (a)"
379 note.comments.create(attributes)
381 note.comments.map { |c| c.author }.uniq.each do |user|
382 if user and user != @user
383 Notifier.deliver_note_comment_notification(comment, user)