X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/db52805f97b9134a66fe1b1240d81e1e6f60736a..23479067254696a9a59f89deeff93e22e0f3e661:/app/controllers/api/notes_controller.rb diff --git a/app/controllers/api/notes_controller.rb b/app/controllers/api/notes_controller.rb index c152c6272..7e2e7fb79 100644 --- a/app/controllers/api/notes_controller.rb +++ b/app/controllers/api/notes_controller.rb @@ -1,6 +1,5 @@ module Api class NotesController < ApiController - before_action :check_api_readable before_action :check_api_writable, :only => [:create, :comment, :close, :reopen, :destroy] before_action :setup_user_auth, :only => [:create, :show] before_action :authorize, :only => [:close, :reopen, :destroy, :comment] @@ -8,7 +7,6 @@ module Api authorize_resource before_action :set_locale - around_action :api_call_handle_error, :api_call_timeout before_action :set_request_formats, :except => [:feed] ## @@ -18,13 +16,10 @@ module Api # support the old, deprecated, method with four arguments if params[:bbox] bbox = BoundingBox.from_bbox_params(params) - else - raise OSM::APIBadUserInput, "No l was given" unless params[:l] - raise OSM::APIBadUserInput, "No r was given" unless params[:r] - raise OSM::APIBadUserInput, "No b was given" unless params[:b] - raise OSM::APIBadUserInput, "No t was given" unless params[:t] - + elsif params[:l] && params[:r] && params[:b] && params[:t] bbox = BoundingBox.from_lrbt_params(params) + else + raise OSM::APIBadUserInput, "The parameter bbox is required" end # Get any conditions that need to be applied @@ -35,6 +30,10 @@ module Api # Check the the bounding box is not too big bbox.check_size(Settings.max_note_request_area) + @min_lon = bbox.min_lon + @min_lat = bbox.min_lat + @max_lon = bbox.max_lon + @max_lat = bbox.max_lat # Find the notes we want to return @notes = notes.bbox(bbox).order("updated_at DESC").limit(result_limit).preload(:comments) @@ -48,6 +47,26 @@ module Api end end + ## + # Read a note + def show + # Check the arguments are sane + raise OSM::APIBadUserInput, "No id was given" unless params[:id] + + # Find the note and check it is valid + @note = Note.find(params[:id]) + raise OSM::APINotFoundError unless @note + raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? || current_user&.moderator? + + # Render the result + respond_to do |format| + format.xml + format.rss + format.json + format.gpx + end + end + ## # Create a new note def create @@ -84,12 +103,39 @@ module Api end end + ## + # Delete (hide) a note + def destroy + # Check the arguments are sane + raise OSM::APIBadUserInput, "No id was given" unless params[:id] + + # Extract the arguments + id = params[:id].to_i + comment = params[:text] + + # Find the note and check it is valid + Note.transaction do + @note = Note.lock.find(id) + raise OSM::APINotFoundError unless @note + raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? + + # Mark the note as hidden + @note.status = "hidden" + @note.save + + add_comment(@note, comment, "hidden", :notify => false) + end + + # Return a copy of the updated note + respond_to do |format| + format.xml { render :action => :show } + format.json { render :action => :show } + end + end + ## # Add a comment to an existing note def comment - # Check the ACLs - raise OSM::APIAccessDenied if current_user.nil? && Acl.no_note_comment(request.remote_ip) - # Check the arguments are sane raise OSM::APIBadUserInput, "No id was given" unless params[:id] raise OSM::APIBadUserInput, "No text was given" if params[:text].blank? @@ -99,13 +145,13 @@ module Api comment = params[:text] # Find the note and check it is valid - @note = Note.find(id) - raise OSM::APINotFoundError unless @note - raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? - raise OSM::APINoteAlreadyClosedError, @note if @note.closed? - - # Add a comment to the note Note.transaction do + @note = Note.lock.find(id) + raise OSM::APINotFoundError unless @note + raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? + raise OSM::APINoteAlreadyClosedError, @note if @note.closed? + + # Add a comment to the note add_comment(@note, comment, "commented") end @@ -127,13 +173,13 @@ module Api comment = params[:text] # Find the note and check it is valid - @note = Note.find_by(:id => id) - raise OSM::APINotFoundError unless @note - raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? - raise OSM::APINoteAlreadyClosedError, @note if @note.closed? - - # Close the note and add a comment Note.transaction do + @note = Note.lock.find_by(:id => id) + raise OSM::APINotFoundError unless @note + raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? + raise OSM::APINoteAlreadyClosedError, @note if @note.closed? + + # Close the note and add a comment @note.close add_comment(@note, comment, "closed") @@ -157,13 +203,13 @@ module Api comment = params[:text] # Find the note and check it is valid - @note = Note.find_by(:id => id) - raise OSM::APINotFoundError unless @note - raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? || current_user.moderator? - raise OSM::APINoteAlreadyOpenError, @note unless @note.closed? || !@note.visible? - - # Reopen the note and add a comment Note.transaction do + @note = Note.lock.find_by(:id => id) + raise OSM::APINotFoundError unless @note + raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? || current_user.moderator? + raise OSM::APINoteAlreadyOpenError, @note unless @note.closed? || !@note.visible? + + # Reopen the note and add a comment @note.reopen add_comment(@note, comment, "reopened") @@ -181,73 +227,16 @@ module Api def feed # Get any conditions that need to be applied notes = closed_condition(Note.all) - - # Process any bbox - if params[:bbox] - bbox = BoundingBox.from_bbox_params(params) - - bbox.check_boundaries - bbox.check_size(Settings.max_note_request_area) - - notes = notes.bbox(bbox) - end + notes = bbox_condition(notes) # Find the comments we want to return - @comments = NoteComment.where(:note_id => notes).order("created_at DESC").limit(result_limit).preload(:note) - - # Render the result - respond_to do |format| - format.rss - end - end - - ## - # Read a note - def show - # Check the arguments are sane - raise OSM::APIBadUserInput, "No id was given" unless params[:id] - - # Find the note and check it is valid - @note = Note.find(params[:id]) - raise OSM::APINotFoundError unless @note - raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? || current_user&.moderator? + @comments = NoteComment.where(:note => notes) + .order(:created_at => :desc).limit(result_limit) + .preload(:author, :note => { :comments => :author }) # Render the result respond_to do |format| - format.xml format.rss - format.json - format.gpx - end - end - - ## - # Delete (hide) a note - def destroy - # Check the arguments are sane - raise OSM::APIBadUserInput, "No id was given" unless params[:id] - - # Extract the arguments - id = params[:id].to_i - comment = params[:text] - - # Find the note and check it is valid - @note = Note.find(id) - raise OSM::APINotFoundError unless @note - raise OSM::APIAlreadyDeletedError.new("note", @note.id) unless @note.visible? - - # Mark the note as hidden - Note.transaction do - @note.status = "hidden" - @note.save - - add_comment(@note, comment, "hidden", :notify => false) - end - - # Return a copy of the updated note - respond_to do |format| - format.xml { render :action => :show } - format.json { render :action => :show } end end @@ -256,6 +245,7 @@ module Api def search # Get the initial set of notes @notes = closed_condition(Note.all) + @notes = bbox_condition(@notes) # Add any user filter if params[:display_name] || params[:user] @@ -337,13 +327,13 @@ module Api # Get the maximum number of results to return def result_limit if params[:limit] - if params[:limit].to_i.positive? && params[:limit].to_i <= 10000 + if params[:limit].to_i.positive? && params[:limit].to_i <= Settings.max_note_query_limit params[:limit].to_i else - raise OSM::APIBadUserInput, "Note limit must be between 1 and 10000" + raise OSM::APIBadUserInput, "Note limit must be between 1 and #{Settings.max_note_query_limit}" end else - 100 + Settings.default_note_query_limit end end @@ -352,9 +342,9 @@ module Api # on their status and the user's request parameters def closed_condition(notes) closed_since = if params[:closed] - params[:closed].to_i + params[:closed].to_i.days else - 7 + Note::DEFAULT_FRESHLY_CLOSED_LIMIT end if closed_since.negative? @@ -362,28 +352,59 @@ module Api elsif closed_since.positive? notes.where(:status => "open") .or(notes.where(:status => "closed") - .where(notes.arel_table[:closed_at].gt(Time.now.utc - closed_since.days))) + .where(notes.arel_table[:closed_at].gt(Time.now.utc - closed_since))) else notes.where(:status => "open") end end + ## + # Generate a condition to choose which notes we want based + # on the user's bounding box request parameters + def bbox_condition(notes) + if params[:bbox] + bbox = BoundingBox.from_bbox_params(params) + + bbox.check_boundaries + bbox.check_size(Settings.max_note_request_area) + + @min_lon = bbox.min_lon + @min_lat = bbox.min_lat + @max_lon = bbox.max_lon + @max_lat = bbox.max_lat + + notes.bbox(bbox) + else + notes + end + end + ## # Add a comment to a note def add_comment(note, text, event, notify: true) attributes = { :visible => true, :event => event, :body => text } - if current_user - attributes[:author_id] = current_user.id + if doorkeeper_token + author = current_user if scope_enabled?(:write_notes) + else + author = current_user + end + + if author + attributes[:author_id] = author.id else attributes[:author_ip] = request.remote_ip end comment = note.comments.create!(attributes) - note.comments.map(&:author).uniq.each do |user| - UserMailer.note_comment_notification(comment, user).deliver_later if notify && user && user != current_user && user.visible? + if notify + note.subscribers.visible.each do |user| + UserMailer.note_comment_notification(comment, user).deliver_later if current_user != user + end end + + NoteSubscription.find_or_create_by(:note => note, :user => current_user) if current_user end end end