]> git.openstreetmap.org Git - rails.git/blob - app/controllers/notes_controller.rb
Add a new write_notes permission needed for OAuth access to notes
[rails.git] / app / controllers / notes_controller.rb
1 class NotesController < ApplicationController
2
3   layout 'site', :only => [:mine]
4
5   before_filter :check_api_readable
6   before_filter :authorize_web, :only => [:mine]
7   before_filter :setup_user_auth, :only => [:create, :comment]
8   before_filter :authorize, :only => [:close, :destroy]
9   before_filter :check_api_writable, :only => [:create, :comment, :close, :destroy]
10   before_filter :require_allow_write_notes, :only => [:create, :comment, :close, :destroy]
11   before_filter :set_locale, :only => [:mine]
12   after_filter :compress_output
13   around_filter :api_call_handle_error, :api_call_timeout
14
15   ##
16   # Return a list of notes in a given area
17   def index
18     # Figure out the bbox - we prefer a bbox argument but also
19     # support the old, deprecated, method with four arguments
20     if params[:bbox]
21       bbox = BoundingBox.from_bbox_params(params)
22     else
23       raise OSM::APIBadUserInput.new("No l was given") unless params[:l]
24       raise OSM::APIBadUserInput.new("No r was given") unless params[:r]
25       raise OSM::APIBadUserInput.new("No b was given") unless params[:b]
26       raise OSM::APIBadUserInput.new("No t was given") unless params[:t]
27
28       bbox = BoundingBox.from_lrbt_params(params)
29     end
30
31     # Get any conditions that need to be applied
32     notes = closed_condition(Note.scoped)
33
34     # Check that the boundaries are valid
35     bbox.check_boundaries
36
37     # Check the the bounding box is not too big
38     bbox.check_size(MAX_NOTE_REQUEST_AREA)
39
40     # Find the notes we want to return
41     @notes = notes.bbox(bbox).order("updated_at DESC").limit(result_limit).preload(:comments)
42
43     # Render the result
44     respond_to do |format|
45       format.rss
46       format.xml
47       format.json
48       format.gpx
49     end
50   end
51
52   ##
53   # Create a new note
54   def create
55     # Check the arguments are sane
56     raise OSM::APIBadUserInput.new("No lat was given") unless params[:lat]
57     raise OSM::APIBadUserInput.new("No lon was given") unless params[:lon]
58     raise OSM::APIBadUserInput.new("No text was given") if params[:text].blank?
59
60     # Extract the arguments
61     lon = params[:lon].to_f
62     lat = params[:lat].to_f
63     comment = params[:text]
64
65     # Include in a transaction to ensure that there is always a note_comment for every note
66     Note.transaction do
67       # Create the note
68       @note = Note.create(:lat => lat, :lon => lon)
69       raise OSM::APIBadUserInput.new("The note is outside this world") unless @note.in_world?
70
71       # Save the note
72       @note.save!
73
74       # Add a comment to the note
75       add_comment(@note, comment, "opened")
76     end
77
78     # Return a copy of the new note
79     respond_to do |format|
80       format.xml { render :action => :show }
81       format.json { render :action => :show }
82     end
83   end
84
85   ##
86   # Add a comment to an existing note
87   def comment
88     # Check the arguments are sane
89     raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
90     raise OSM::APIBadUserInput.new("No text was given") if params[:text].blank?
91
92     # Extract the arguments
93     id = params[:id].to_i
94     comment = params[:text]
95
96     # Find the note and check it is valid
97     @note = Note.find(id)
98     raise OSM::APINotFoundError unless @note
99     raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
100     raise OSM::APINoteAlreadyClosedError.new(@note) if @note.closed?
101
102     # Add a comment to the note
103     Note.transaction do
104       add_comment(@note, comment, "commented")
105     end
106
107     # Return a copy of the updated note
108     respond_to do |format|
109       format.xml { render :action => :show }
110       format.json { render :action => :show }
111     end
112   end
113
114   ##
115   # Close a note
116   def close
117     # Check the arguments are sane
118     raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
119
120     # Extract the arguments
121     id = params[:id].to_i
122     comment = params[:text]
123
124     # Find the note and check it is valid
125     @note = Note.find_by_id(id)
126     raise OSM::APINotFoundError unless @note
127     raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
128     raise OSM::APINoteAlreadyClosedError.new(@note) if @note.closed?
129
130     # Close the note and add a comment
131     Note.transaction do
132       @note.close
133
134       add_comment(@note, comment, "closed")
135     end
136
137     # Return a copy of the updated note
138     respond_to do |format|
139       format.xml { render :action => :show }
140       format.json { render :action => :show }
141     end
142   end 
143
144   ##
145   # Get a feed of recent notes and comments
146   def feed
147     # Get any conditions that need to be applied
148     notes = closed_condition(Note.scoped)
149
150     # Process any bbox
151     if params[:bbox]
152       bbox = BoundingBox.from_bbox_params(params)
153
154       bbox.check_boundaries
155       bbox.check_size(MAX_NOTE_REQUEST_AREA)
156
157       notes = notes.bbox(bbox)
158     end
159
160     # Find the comments we want to return
161     @comments = NoteComment.where(:note_id => notes).order("created_at DESC").limit(result_limit).preload(:note)
162
163     # Render the result
164     respond_to do |format|
165       format.rss
166     end
167   end
168
169   ##
170   # Read a note
171   def show
172     # Check the arguments are sane
173     raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
174
175     # Find the note and check it is valid
176     @note = Note.find(params[:id])
177     raise OSM::APINotFoundError unless @note
178     raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
179
180     # Render the result
181     respond_to do |format|
182       format.xml
183       format.rss
184       format.json
185       format.gpx
186     end
187   end
188
189   ##
190   # Delete (hide) a note
191   def destroy
192     # Check the arguments are sane
193     raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
194
195     # Extract the arguments
196     id = params[:id].to_i
197
198     # Find the note and check it is valid
199     note = Note.find(id)
200     raise OSM::APINotFoundError unless note
201     raise OSM::APIAlreadyDeletedError.new("note", note.id) unless note.visible?
202
203     # Mark the note as hidden
204     Note.transaction do
205       note.status = "hidden"
206       note.save
207
208       add_comment(note, nil, "hidden")
209     end
210
211     # Render the result
212     render :text => "ok\n", :content_type => "text/html" 
213   end
214
215   ##
216   # Return a list of notes matching a given string
217   def search
218     # Check the arguments are sane
219     raise OSM::APIBadUserInput.new("No query string was given") unless params[:q]
220
221     # Get any conditions that need to be applied
222     @notes = closed_condition(Note.scoped)
223     @notes = @notes.joins(:comments).where("note_comments.body ~ ?", params[:q])
224
225     # Find the notes we want to return
226     @notes = @notes.order("updated_at DESC").limit(result_limit).preload(:comments)
227
228     # Render the result
229     respond_to do |format|
230       format.rss { render :action => :index }
231       format.xml { render :action => :index }
232       format.json { render :action => :index }
233       format.gpx { render :action => :index }
234     end
235   end
236
237   ##
238   # Display a list of notes by a specified user
239   def mine
240     if params[:display_name] 
241       if @this_user = User.active.find_by_display_name(params[:display_name])
242         @title =  t 'note.mine.title', :user => @this_user.display_name 
243         @heading =  t 'note.mine.heading', :user => @this_user.display_name 
244         @description = t 'note.mine.subheading', :user => render_to_string(:partial => "user", :object => @this_user)
245         @page = (params[:page] || 1).to_i 
246         @page_size = 10
247         @notes = @this_user.notes.order("updated_at DESC, id").uniq.offset((@page - 1) * @page_size).limit(@page_size).preload(:comments => :author)
248       else
249         @title = t 'user.no_such_user.title' 
250         @not_found_user = params[:display_name] 
251
252         render :template => 'user/no_such_user', :status => :not_found 
253       end 
254     end
255   end
256
257 private 
258   #------------------------------------------------------------ 
259   # utility functions below. 
260   #------------------------------------------------------------   
261  
262   ##
263   # Render an OK response
264   def render_ok
265     if params[:format] == "js"
266       render :text => "osbResponse();", :content_type => "text/javascript" 
267     else
268       render :text => "ok " + @note.id.to_s + "\n", :content_type => "text/plain" if @note
269       render :text => "ok\n", :content_type => "text/plain" unless @note
270     end
271   end
272
273   ##
274   # Get the maximum number of results to return
275   def result_limit
276     if params[:limit] and params[:limit].to_i > 0 and params[:limit].to_i < 10000
277       params[:limit].to_i
278     else
279       100
280     end
281   end
282
283   ##
284   # Generate a condition to choose which bugs we want based
285   # on their status and the user's request parameters
286   def closed_condition(notes)
287     if params[:closed]
288       closed_since = params[:closed].to_i
289     else
290       closed_since = 7
291     end
292         
293     if closed_since < 0
294       notes = notes.where("status != 'hidden'")
295     elsif closed_since > 0
296       notes = notes.where("(status = 'open' OR (status = 'closed' AND closed_at > '#{Time.now - closed_since.days}'))")
297     else
298       notes = notes.where("status = 'open'")
299     end
300
301     return notes
302   end
303
304   ##
305   # Add a comment to a note
306   def add_comment(note, text, event)
307     attributes = { :visible => true, :event => event, :body => text }
308
309     if @user  
310       attributes[:author_id] = @user.id
311     else  
312       attributes[:author_ip] = request.remote_ip
313     end
314
315     comment = note.comments.create(attributes, :without_protection => true)
316
317     note.comments.map { |c| c.author }.uniq.each do |user|
318       if user and user != @user
319         Notifier.note_comment_notification(comment, user).deliver
320       end
321     end
322   end
323 end