1 class NotesController < ApplicationController
 
   2   layout "site", :only => [:mine]
 
   4   before_action :check_api_readable
 
   5   before_action :authorize_web, :only => [:mine]
 
   6   before_action :setup_user_auth, :only => [:create, :comment]
 
   7   before_action :authorize, :only => [:close, :reopen, :destroy]
 
   8   before_action :require_moderator, :only => [:destroy]
 
   9   before_action :check_api_writable, :only => [:create, :comment, :close, :reopen, :destroy]
 
  10   before_action :require_allow_write_notes, :only => [:create, :comment, :close, :reopen, :destroy]
 
  11   before_action :set_locale
 
  12   around_action :api_call_handle_error, :api_call_timeout
 
  15   # Return a list of notes in a given area
 
  17     # Figure out the bbox - we prefer a bbox argument but also
 
  18     # support the old, deprecated, method with four arguments
 
  20       bbox = BoundingBox.from_bbox_params(params)
 
  22       fail OSM::APIBadUserInput.new("No l was given") unless params[:l]
 
  23       fail OSM::APIBadUserInput.new("No r was given") unless params[:r]
 
  24       fail OSM::APIBadUserInput.new("No b was given") unless params[:b]
 
  25       fail OSM::APIBadUserInput.new("No t was given") unless params[:t]
 
  27       bbox = BoundingBox.from_lrbt_params(params)
 
  30     # Get any conditions that need to be applied
 
  31     notes = closed_condition(Note.all)
 
  33     # Check that the boundaries are valid
 
  36     # Check the the bounding box is not too big
 
  37     bbox.check_size(MAX_NOTE_REQUEST_AREA)
 
  39     # Find the notes we want to return
 
  40     @notes = notes.bbox(bbox).order("updated_at DESC").limit(result_limit).preload(:comments)
 
  43     respond_to do |format|
 
  55     fail OSM::APIAccessDenied if Acl.no_note_comment(request.remote_ip)
 
  57     # Check the arguments are sane
 
  58     fail OSM::APIBadUserInput.new("No lat was given") unless params[:lat]
 
  59     fail OSM::APIBadUserInput.new("No lon was given") unless params[:lon]
 
  60     fail OSM::APIBadUserInput.new("No text was given") if params[:text].blank?
 
  62     # Extract the arguments
 
  63     lon = OSM.parse_float(params[:lon], OSM::APIBadUserInput, "lon was not a number")
 
  64     lat = OSM.parse_float(params[:lat], OSM::APIBadUserInput, "lat was not a number")
 
  65     comment = params[:text]
 
  67     # Include in a transaction to ensure that there is always a note_comment for every note
 
  70       @note = Note.create(:lat => lat, :lon => lon)
 
  71       fail OSM::APIBadUserInput.new("The note is outside this world") unless @note.in_world?
 
  76       # Add a comment to the note
 
  77       add_comment(@note, comment, "opened")
 
  80     # Return a copy of the new note
 
  81     respond_to do |format|
 
  82       format.xml { render :action => :show }
 
  83       format.json { render :action => :show }
 
  88   # Add a comment to an existing note
 
  91     fail OSM::APIAccessDenied if Acl.no_note_comment(request.remote_ip)
 
  93     # Check the arguments are sane
 
  94     fail OSM::APIBadUserInput.new("No id was given") unless params[:id]
 
  95     fail OSM::APIBadUserInput.new("No text was given") if params[:text].blank?
 
  97     # Extract the arguments
 
  99     comment = params[:text]
 
 101     # Find the note and check it is valid
 
 102     @note = Note.find(id)
 
 103     fail OSM::APINotFoundError unless @note
 
 104     fail OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
 
 105     fail OSM::APINoteAlreadyClosedError.new(@note) if @note.closed?
 
 107     # Add a comment to the note
 
 109       add_comment(@note, comment, "commented")
 
 112     # Return a copy of the updated note
 
 113     respond_to do |format|
 
 114       format.xml { render :action => :show }
 
 115       format.json { render :action => :show }
 
 122     # Check the arguments are sane
 
 123     fail OSM::APIBadUserInput.new("No id was given") unless params[:id]
 
 125     # Extract the arguments
 
 126     id = params[:id].to_i
 
 127     comment = params[:text]
 
 129     # Find the note and check it is valid
 
 130     @note = Note.find_by_id(id)
 
 131     fail OSM::APINotFoundError unless @note
 
 132     fail OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
 
 133     fail OSM::APINoteAlreadyClosedError.new(@note) if @note.closed?
 
 135     # Close the note and add a comment
 
 139       add_comment(@note, comment, "closed")
 
 142     # Return a copy of the updated note
 
 143     respond_to do |format|
 
 144       format.xml { render :action => :show }
 
 145       format.json { render :action => :show }
 
 152     # Check the arguments are sane
 
 153     fail OSM::APIBadUserInput.new("No id was given") unless params[:id]
 
 155     # Extract the arguments
 
 156     id = params[:id].to_i
 
 157     comment = params[:text]
 
 159     # Find the note and check it is valid
 
 160     @note = Note.find_by_id(id)
 
 161     fail OSM::APINotFoundError unless @note
 
 162     fail OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? || @user.moderator?
 
 163     fail OSM::APINoteAlreadyOpenError.new(@note) unless @note.closed? || !@note.visible?
 
 165     # Reopen the note and add a comment
 
 169       add_comment(@note, comment, "reopened")
 
 172     # Return a copy of the updated note
 
 173     respond_to do |format|
 
 174       format.xml { render :action => :show }
 
 175       format.json { render :action => :show }
 
 180   # Get a feed of recent notes and comments
 
 182     # Get any conditions that need to be applied
 
 183     notes = closed_condition(Note.all)
 
 187       bbox = BoundingBox.from_bbox_params(params)
 
 189       bbox.check_boundaries
 
 190       bbox.check_size(MAX_NOTE_REQUEST_AREA)
 
 192       notes = notes.bbox(bbox)
 
 195     # Find the comments we want to return
 
 196     @comments = NoteComment.where(:note_id => notes).order("created_at DESC").limit(result_limit).preload(:note)
 
 199     respond_to do |format|
 
 207     # Check the arguments are sane
 
 208     fail OSM::APIBadUserInput.new("No id was given") unless params[:id]
 
 210     # Find the note and check it is valid
 
 211     @note = Note.find(params[:id])
 
 212     fail OSM::APINotFoundError unless @note
 
 213     fail OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
 
 216     respond_to do |format|
 
 225   # Delete (hide) a note
 
 227     # Check the arguments are sane
 
 228     fail OSM::APIBadUserInput.new("No id was given") unless params[:id]
 
 230     # Extract the arguments
 
 231     id = params[:id].to_i
 
 232     comment = params[:text]
 
 234     # Find the note and check it is valid
 
 235     @note = Note.find(id)
 
 236     fail OSM::APINotFoundError unless @note
 
 237     fail OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible?
 
 239     # Mark the note as hidden
 
 241       @note.status = "hidden"
 
 244       add_comment(@note, comment, "hidden", false)
 
 247     # Return a copy of the updated note
 
 248     respond_to do |format|
 
 249       format.xml { render :action => :show }
 
 250       format.json { render :action => :show }
 
 255   # Return a list of notes matching a given string
 
 257     # Check the arguments are sane
 
 258     fail OSM::APIBadUserInput.new("No query string was given") unless params[:q]
 
 260     # Get any conditions that need to be applied
 
 261     @notes = closed_condition(Note.all)
 
 262     @notes = @notes.joins(:comments).where("to_tsvector('english', note_comments.body) @@ plainto_tsquery('english', ?)", params[:q])
 
 264     # Find the notes we want to return
 
 265     @notes = @notes.order("updated_at DESC").limit(result_limit).preload(:comments)
 
 268     respond_to do |format|
 
 269       format.rss { render :action => :index }
 
 270       format.xml { render :action => :index }
 
 271       format.json { render :action => :index }
 
 272       format.gpx { render :action => :index }
 
 277   # Display a list of notes by a specified user
 
 279     if params[:display_name]
 
 280       if @this_user = User.active.find_by_display_name(params[:display_name])
 
 281         @title =  t "note.mine.title", :user => @this_user.display_name
 
 282         @heading =  t "note.mine.heading", :user => @this_user.display_name
 
 283         @description = t "note.mine.subheading", :user => render_to_string(:partial => "user", :object => @this_user)
 
 284         @page = (params[:page] || 1).to_i
 
 286         @notes = @this_user.notes.order("updated_at DESC, id").uniq.offset((@page - 1) * @page_size).limit(@page_size).preload(:comments => :author).to_a
 
 288         @title = t "user.no_such_user.title"
 
 289         @not_found_user = params[:display_name]
 
 291         render :template => "user/no_such_user", :status => :not_found
 
 298   #------------------------------------------------------------
 
 299   # utility functions below.
 
 300   #------------------------------------------------------------
 
 303   # Render an OK response
 
 305     if params[:format] == "js"
 
 306       render :text => "osbResponse();", :content_type => "text/javascript"
 
 308       render :text => "ok " + @note.id.to_s + "\n", :content_type => "text/plain" if @note
 
 309       render :text => "ok\n", :content_type => "text/plain" unless @note
 
 314   # Get the maximum number of results to return
 
 317       if params[:limit].to_i > 0 && params[:limit].to_i <= 10000
 
 320         fail OSM::APIBadUserInput.new("Note limit must be between 1 and 10000")
 
 328   # Generate a condition to choose which bugs we want based
 
 329   # on their status and the user's request parameters
 
 330   def closed_condition(notes)
 
 332       closed_since = params[:closed].to_i
 
 338       notes = notes.where("status != 'hidden'")
 
 339     elsif closed_since > 0
 
 340       notes = notes.where("(status = 'open' OR (status = 'closed' AND closed_at > '#{Time.now - closed_since.days}'))")
 
 342       notes = notes.where("status = 'open'")
 
 349   # Add a comment to a note
 
 350   def add_comment(note, text, event, notify = true)
 
 351     attributes = { :visible => true, :event => event, :body => text }
 
 354       attributes[:author_id] = @user.id
 
 356       attributes[:author_ip] = request.remote_ip
 
 359     comment = note.comments.create(attributes)
 
 361     note.comments.map(&:author).uniq.each do |user|
 
 362       if notify && user && user != @user
 
 363         Notifier.note_comment_notification(comment, user).deliver_now