X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/e3b8b8933044104bb515d34c3d36851caba78ac7..663f3e48e354bd0fce64a2111be0139a6a335839:/app/controllers/note_controller.rb?ds=sidebyside diff --git a/app/controllers/note_controller.rb b/app/controllers/note_controller.rb index fb68280b3..fe83f7d03 100644 --- a/app/controllers/note_controller.rb +++ b/app/controllers/note_controller.rb @@ -5,66 +5,69 @@ class NoteController < ApplicationController before_filter :check_api_readable before_filter :authorize_web, :only => [:create, :close, :update, :delete, :mine] before_filter :check_api_writable, :only => [:create, :close, :update, :delete] - before_filter :require_moderator, :only => [:delete] before_filter :set_locale, :only => [:mine] after_filter :compress_output around_filter :api_call_handle_error, :api_call_timeout - # Help methods for checking boundary sanity and area size - include MapBoundary - + ## + # Return a list of notes in a given area def list - # Figure out the bbox - bbox = params['bbox'] - - if bbox and bbox.count(',') == 3 - bbox = bbox.split(',') - @min_lon, @min_lat, @max_lon, @max_lat = sanitise_boundaries(bbox) + # Figure out the bbox - we prefer a bbox argument but also + # support the old, deprecated, method with four arguments + if params[:bbox] + bbox = BoundingBox.from_bbox_params(params) else - #Fallback to old style, this is deprecated and should not be used - raise OSM::APIBadUserInput.new("No l was given") unless params['l'] - raise OSM::APIBadUserInput.new("No r was given") unless params['r'] - raise OSM::APIBadUserInput.new("No b was given") unless params['b'] - raise OSM::APIBadUserInput.new("No t was given") unless params['t'] - - @min_lon = params['l'].to_f - @max_lon = params['r'].to_f - @min_lat = params['b'].to_f - @max_lat = params['t'].to_f + raise OSM::APIBadUserInput.new("No l was given") unless params[:l] + raise OSM::APIBadUserInput.new("No r was given") unless params[:r] + raise OSM::APIBadUserInput.new("No b was given") unless params[:b] + raise OSM::APIBadUserInput.new("No t was given") unless params[:t] + + bbox = BoundingBox.from_lrbt_params(params) end - limit = getLimit - conditions = closedCondition - - check_boundaries(@min_lon, @min_lat, @max_lon, @max_lat, MAX_NOTE_REQUEST_AREA) + # Get the sanitised boundaries + @min_lon, @min_lat, @max_lon, @max_lat = sanitise_boundaries(bbox) + + # Get any conditions that need to be applied + notes = closed_condition(Note.scoped) + + # Check that the boundaries are valid + bbox.check_boundaries + + # Check the the bounding box is not too big + bbox.check_size(MAX_NOTE_REQUEST_AREA) - @notes = Note.find_by_area(@min_lat, @min_lon, @max_lat, @max_lon, :include => :comments, :order => "updated_at DESC", :limit => limit, :conditions => conditions) + # Find the notes we want to return + @notes = notes.bbox(bbox).order("updated_at DESC").limit(result_limit).preload(:comments) + # Render the result respond_to do |format| - format.html {render :template => 'note/list.rjs', :content_type => "text/javascript"} - format.rss {render :template => 'note/list.rss'} - format.js - format.xml {render :template => 'note/list.xml'} - format.json { render :json => @notes.to_json(:methods => [:lat, :lon], :only => [:id, :status, :created_at], :include => { :comments => { :only => [:author_name, :created_at, :body]}}) } - format.gpx {render :template => 'note/list.gpx'} + format.rss + format.xml + format.json + format.gpx end end + ## + # Create a new note def create - raise OSM::APIBadUserInput.new("No lat was given") unless params['lat'] - raise OSM::APIBadUserInput.new("No lon was given") unless params['lon'] - raise OSM::APIBadUserInput.new("No text was given") unless params['text'] - - lon = params['lon'].to_f - lat = params['lat'].to_f - comment = params['text'] - - name = "NoName" - name = params['name'] if params['name'] - - #Include in a transaction to ensure that there is always a note_comment for every note + # Check the arguments are sane + raise OSM::APIBadUserInput.new("No lat was given") unless params[:lat] + raise OSM::APIBadUserInput.new("No lon was given") unless params[:lon] + raise OSM::APIBadUserInput.new("No text was given") unless params[:text] + + # Extract the arguments + lon = params[:lon].to_f + lat = params[:lat].to_f + comment = params[:text] + name = params[:name] + + # Include in a transaction to ensure that there is always a note_comment for every note Note.transaction do - @note = Note.create_bug(lat, lon) + # Create the note + @note = Note.create(:lat => lat, :lon => lon) + raise OSM::APIBadUserInput.new("The note is outside this world") unless @note.in_world? #TODO: move this into a helper function begin @@ -80,116 +83,167 @@ class NoteController < ApplicationController @note.nearby_place = "unknown" end + # Save the note @note.save + # Add a comment to the note add_comment(@note, comment, name, "opened") end - + + # Send an OK response render_ok end + ## + # Add a comment to an existing note def update - raise OSM::APIBadUserInput.new("No id was given") unless params['id'] - raise OSM::APIBadUserInput.new("No text was given") unless params['text'] + # Check the arguments are sane + raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + raise OSM::APIBadUserInput.new("No text was given") unless params[:text] - name = "NoName" - name = params['name'] if params['name'] - - id = params['id'].to_i + # Extract the arguments + id = params[:id].to_i + comment = params[:text] + name = params[:name] or "NoName" + # Find the note and check it is valid note = Note.find(id) raise OSM::APINotFoundError unless note - raise OSM::APIAlreadyDeletedError unless note.visible + raise OSM::APIAlreadyDeletedError unless note.visible? + # Add a comment to the note Note.transaction do - add_comment(note, params['text'], name, "commented") + add_comment(note, comment, name, "commented") end + # Send an OK response render_ok end + ## + # Close a note def close - raise OSM::APIBadUserInput.new("No id was given") unless params['id'] - - id = params['id'].to_i - name = "NoName" - name = params['name'] if params['name'] + # Check the arguments are sane + raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + + # Extract the arguments + id = params[:id].to_i + name = params[:name] + # Find the note and check it is valid note = Note.find_by_id(id) raise OSM::APINotFoundError unless note - raise OSM::APIAlreadyDeletedError unless note.visible + raise OSM::APIAlreadyDeletedError unless note.visible? + # Close the note and add a comment Note.transaction do note.close - add_comment(note, :nil, name, "closed") + + add_comment(note, nil, name, "closed") end + # Send an OK response render_ok end + ## + # Get a feed of recent notes and comments def rss - limit = getLimit - conditions = closedCondition - - # Figure out the bbox - bbox = params['bbox'] + # Get any conditions that need to be applied + notes = closed_condition(Note.scoped) - if bbox and bbox.count(',') == 3 - bbox = bbox.split(',') - @min_lon, @min_lat, @max_lon, @max_lat = sanitise_boundaries(bbox) + # Process any bbox + if params[:bbox] + bbox = BoundingBox.from_bbox_params(params) - check_boundaries(@min_lon, @min_lat, @max_lon, @max_lat, MAX_NOTE_REQUEST_AREA) + bbox.check_boundaries + bbox.check_size(MAX_NOTE_REQUEST_AREA) - conditions = cond_merge conditions, [OSM.sql_for_area(@min_lat, @min_lon, @max_lat, @max_lon)] + notes = notes.bbox(bbox) end - @comments = NoteComment.find(:all, :limit => limit, :order => "created_at DESC", :joins => :note, :include => :note, :conditions => conditions) - render :template => 'note/rss.rss' + # Find the comments we want to return + @comments = NoteComment.where(:note => notes).order("created_at DESC").limit(result_limit).include(:note) + + # Render the result + respond_to do |format| + format.rss + end end + ## + # Read a note def read - @note = Note.find(params['id']) + # Check the arguments are sane + raise OSM::APIBadUserInput.new("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 unless @note.visible + raise OSM::APIAlreadyDeletedError unless @note.visible? + # Render the result respond_to do |format| - format.rss format.xml - format.json { render :json => @note.to_json(:methods => [:lat, :lon], :only => [:id, :status, :created_at], :include => { :comments => { :only => [:author_name, :created_at, :body]}}) } + format.rss + format.json format.gpx end end + ## + # Delete (hide) a note def delete - note = note.find(params['id']) + # Check the arguments are sane + raise OSM::APIBadUserInput.new("No id was given") unless params[:id] + + # Extract the arguments + id = params[:id].to_i + name = params[:name] + + # Find the note and check it is valid + note = Note.find(id) raise OSM::APINotFoundError unless note - raise OSM::APIAlreadyDeletedError unless note.visible + raise OSM::APIAlreadyDeletedError unless note.visible? + # Mark the note as hidden Note.transaction do note.status = "hidden" note.save - add_comment(note, :nil, name, "hidden") + + add_comment(note, nil, name, "hidden") end + # Render the result render :text => "ok\n", :content_type => "text/html" end + ## + # Return a list of notes matching a given string def search - raise OSM::APIBadUserInput.new("No query string was given") unless params['q'] - limit = getLimit - conditions = closedCondition - conditions = cond_merge conditions, ['note_comments.body ~ ?', params['q']] + # Check the arguments are sane + raise OSM::APIBadUserInput.new("No query string was given") unless params[:q] + + # Get any conditions that need to be applied + conditions = closed_condition + conditions = cond_merge conditions, ['note_comments.body ~ ?', params[:q]] - #TODO: There should be a better way to do this. CloseConditions are ignored at the moment + # Find the notes we want to return + @notes = Note.find(:all, + :conditions => conditions, + :order => "updated_at DESC", + :limit => result_limit, + :joins => :comments, + :include => :comments) - @notes = Note.find(:all, :limit => limit, :order => "updated_at DESC", :joins => :comments, :include => :comments, :conditions => conditions).uniq + # Render the result respond_to do |format| - format.html {render :template => 'note/list.rjs', :content_type => "text/javascript"} - format.rss {render :template => 'note/list.rss'} + format.html { render :action => :list, :format => :rjs, :content_type => "text/javascript"} + format.rss { render :action => :list } format.js - format.xml {render :template => 'note/list.xml'} - format.json { render :json => @notes.to_json(:methods => [:lat, :lon], :only => [:id, :status, :created_at], :include => { :comments => { :only => [:author_name, :created_at, :body]}}) } - format.gpx {render :template => 'note/list.gpx'} + format.xml { render :action => :list } + format.json { render :action => :list } + format.gpx { render :action => :list } end end @@ -236,74 +290,68 @@ private # utility functions below. #------------------------------------------------------------ - ## - # merge two conditions - # TODO: this is a copy from changeset_controler.rb and should be factored out to share - def cond_merge(a, b) - if a and b - a_str = a.shift - b_str = b.shift - return [ a_str + " AND " + b_str ] + a + b - elsif a - return a - else b - return b - end - end - + ## + # Render an OK response def render_ok - output_js = :false - output_js = :true if params['format'] == "js" - - if output_js == :true + if params[:format] == "js" render :text => "osbResponse();", :content_type => "text/javascript" else - render :text => "ok " + @note.id.to_s + "\n", :content_type => "text/html" if @note - render :text => "ok\n", :content_type => "text/html" unless @note + render :text => "ok " + @note.id.to_s + "\n", :content_type => "text/plain" if @note + render :text => "ok\n", :content_type => "text/plain" unless @note end end - def getLimit - limit = 100 - limit = params['limit'] if ((params['limit']) && (params['limit'].to_i < 10000) && (params['limit'].to_i > 0)) - return limit + ## + # Get the maximum number of results to return + def result_limit + if params[:limit] and params[:limit].to_i > 0 and params[:limit].to_i < 10000 + params[:limit].to_i + else + 100 + end end - def closedCondition - closed_since = 7 unless params['closed'] - closed_since = params['closed'].to_i if params['closed'] + ## + # Generate a condition to choose which bugs we want based + # on their status and the user's request parameters + def closed_condition(notes) + if params[:closed] + closed_since = params[:closed].to_i + else + closed_since = 7 + end if closed_since < 0 - conditions = ["status != 'hidden'"] + notes = notes.where("status != 'hidden'") elsif closed_since > 0 - conditions = ["((status = 'open') OR ((status = 'closed' ) AND (closed_at > '" + (Time.now - closed_since.days).to_s + "')))"] + notes = notes.where("(status = 'open' OR (status = 'closed' AND closed_at > '#{Time.now - closed_since.days}'))") else - conditions = ["status = 'open'"] + notes = notes.where("status = 'open'") end - return conditions + return notes end - def add_comment(note, text, name, event) - comment = note.comments.create(:visible => true, :event => event) - comment.body = text unless text == :nil + ## + # Add a comment to a note + def add_comment(note, text, name, event) + name = "NoName" if name.nil? + + attributes = { :visible => true, :event => event, :body => text } + if @user - comment.author_id = @user.id - comment.author_name = @user.display_name + attributes[:author_id] = @user.id + attributes[:author_name] = @user.display_name else - comment.author_ip = request.remote_ip - comment.author_name = name + " (a)" + attributes[:author_ip] = request.remote_ip + attributes[:author_name] = name + " (a)" end - comment.save - note.save - - sent_to = Set.new - note.comments.each do | cmt | - if cmt.author - unless sent_to.include?(cmt.author) - Notifier.deliver_note_comment_notification(note_comment, cmt.author) unless cmt.author == @user - sent_to.add(cmt.author) - end + + note.comments.create(attributes) + + note.comments.map { |c| c.author }.uniq.each do |user| + if user and user != @user + Notifier.deliver_note_comment_notification(comment, user) end end end