Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add changeset comment search api with filtering by author and time #4359

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/abilities/api_ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def initialize(token)
can :create, Note unless token

can [:read, :download], Changeset
can :read, ChangesetComment
can :read, Tracepoint
can :read, User
can :read, Node
Expand Down
15 changes: 13 additions & 2 deletions app/controllers/api/changeset_comments_controller.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
module Api
class ChangesetCommentsController < ApiController
before_action :check_api_writable
before_action :authorize
include QueryMethods

before_action :check_api_writable, :except => [:index]
before_action :authorize, :except => [:index]

authorize_resource

before_action :require_public_data, :only => [:create]

before_action :set_request_formats

##
# show all comments or search for a subset
def index
@comments = ChangesetComment.includes(:author).where(:visible => true).order("created_at DESC")
@comments = query_conditions_time(@comments)
@comments = query_conditions_user(@comments, :author)
@comments = query_limit(@comments)
end

##
# Add a comment to a changeset
def create
Expand Down
47 changes: 4 additions & 43 deletions app/controllers/api/changesets_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module Api
class ChangesetsController < ApiController
include QueryMethods

before_action :check_api_writable, :only => [:create, :update, :upload, :subscribe, :unsubscribe]
before_action :setup_user_auth, :only => [:show]
before_action :authorize, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe]
Expand Down Expand Up @@ -30,7 +32,7 @@ def index
changesets = conditions_bbox(changesets, bbox)
changesets = conditions_user(changesets, params["user"], params["display_name"])
changesets = conditions_time(changesets, params["time"])
changesets = conditions_from_to(changesets, params["from"], params["to"])
changesets = query_conditions_time(changesets)
changesets = conditions_open(changesets, params["open"])
changesets = conditions_closed(changesets, params["closed"])
changesets = conditions_ids(changesets, params["changesets"])
Expand All @@ -43,7 +45,7 @@ def index
end

# limit the result
changesets = changesets.limit(result_limit)
changesets = query_limit(changesets)

# preload users, tags and comments, and render result
@changesets = changesets.preload(:user, :changeset_tags, :comments)
Expand Down Expand Up @@ -337,33 +339,6 @@ def conditions_time(changesets, time)
raise OSM::APIBadUserInput, e.message.to_s
end

##
# restrict changesets to those opened during a particular time period
# works similar to from..to of notes controller, including the requirement of 'from' when specifying 'to'
def conditions_from_to(changesets, from, to)
if from
begin
from = Time.parse(from).utc
rescue ArgumentError
raise OSM::APIBadUserInput, "Date #{from} is in a wrong format"
end

begin
to = if to
Time.parse(to).utc
else
Time.now.utc
end
rescue ArgumentError
raise OSM::APIBadUserInput, "Date #{to} is in a wrong format"
end

changesets.where(:created_at => from..to)
else
changesets
end
end

##
# return changesets which are open (haven't been closed yet)
# we do this by seeing if the 'closed at' time is in the future. Also if we've
Expand Down Expand Up @@ -403,19 +378,5 @@ def conditions_ids(changesets, ids)
changesets.where(:id => ids)
end
end

##
# Get the maximum number of results to return
def result_limit
if params[:limit]
if params[:limit].to_i.positive? && params[:limit].to_i <= Settings.max_changeset_query_limit
params[:limit].to_i
else
raise OSM::APIBadUserInput, "Changeset limit must be between 1 and #{Settings.max_changeset_query_limit}"
end
else
Settings.default_changeset_query_limit
end
end
end
end
72 changes: 18 additions & 54 deletions app/controllers/api/notes_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module Api
class NotesController < ApiController
include QueryMethods

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]
Expand Down Expand Up @@ -36,7 +38,9 @@ def index
@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)
notes = notes.bbox(bbox).order("updated_at DESC")
notes = query_limit(notes)
@notes = notes.preload(:comments)

# Render the result
respond_to do |format|
Expand Down Expand Up @@ -231,8 +235,9 @@ def feed

# Find the comments we want to return
@comments = NoteComment.where(:note => notes)
.order(:created_at => :desc).limit(result_limit)
.preload(:author, :note => { :comments => :author })
.order(:created_at => :desc)
@comments = query_limit(@comments)
@comments = @comments.preload(:author, :note => { :comments => :author })

# Render the result
respond_to do |format|
Expand All @@ -248,47 +253,19 @@ def search
@notes = bbox_condition(@notes)

# Add any user filter
if params[:display_name] || params[:user]
if params[:display_name]
@user = User.find_by(:display_name => params[:display_name])

raise OSM::APIBadUserInput, "User #{params[:display_name]} not known" unless @user
else
@user = User.find_by(:id => params[:user])

raise OSM::APIBadUserInput, "User #{params[:user]} not known" unless @user
end

@notes = @notes.joins(:comments).where(:note_comments => { :author_id => @user })
end
user = query_conditions_user_value
@notes = @notes.joins(:comments).where(:note_comments => { :author_id => user }) if user

# Add any text filter
@notes = @notes.joins(:comments).where("to_tsvector('english', note_comments.body) @@ plainto_tsquery('english', ?)", params[:q]) if params[:q]

# Add any date filter
if params[:from]
begin
from = Time.parse(params[:from]).utc
rescue ArgumentError
raise OSM::APIBadUserInput, "Date #{params[:from]} is in a wrong format"
end

begin
to = if params[:to]
Time.parse(params[:to]).utc
else
Time.now.utc
end
rescue ArgumentError
raise OSM::APIBadUserInput, "Date #{params[:to]} is in a wrong format"
end

@notes = if params[:sort] == "updated_at"
@notes.where(:updated_at => from..to)
else
@notes.where(:created_at => from..to)
end
end
time_filter_property = if params[:sort] == "updated_at"
:updated_at
else
:created_at
end
@notes = query_conditions_time(@notes, time_filter_property)

# Choose the sort order
@notes = if params[:sort] == "created_at"
Expand All @@ -306,7 +283,8 @@ def search
end

# Find the notes we want to return
@notes = @notes.distinct.limit(result_limit).preload(:comments)
@notes = query_limit(@notes.distinct)
@notes = @notes.preload(:comments)

# Render the result
respond_to do |format|
Expand All @@ -323,20 +301,6 @@ def search
# utility functions below.
#------------------------------------------------------------

##
# Get the maximum number of results to return
def result_limit
if params[:limit]
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 #{Settings.max_note_query_limit}"
end
else
Settings.default_note_query_limit
end
end

##
# Generate a condition to choose which notes we want based
# on their status and the user's request parameters
Expand Down
25 changes: 7 additions & 18 deletions app/controllers/changeset_comments/feeds_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module ChangesetComments
class FeedsController < ApplicationController
include QueryMethods

before_action :authorize_web
before_action :set_locale

Expand All @@ -19,10 +21,13 @@ def show
changeset = Changeset.find(changeset_id)

# Return comments for this changeset only
@comments = changeset.comments.includes(:author, :changeset).reverse_order.limit(comments_limit)
@comments = changeset.comments.includes(:author, :changeset).reverse_order
@comments = query_limit(@comments)
else
# Return comments
@comments = ChangesetComment.includes(:author, :changeset).where(:visible => true).order("created_at DESC").limit(comments_limit).preload(:changeset)
@comments = ChangesetComment.includes(:author, :changeset).where(:visible => true).order("created_at DESC")
@comments = query_limit(@comments)
@comments = @comments.preload(:changeset)
end

# Render the result
Expand All @@ -32,21 +37,5 @@ def show
rescue OSM::APIBadUserInput
head :bad_request
end

private

##
# Get the maximum number of comments to return
def comments_limit
if params[:limit]
if params[:limit].to_i.positive? && params[:limit].to_i <= 10000
params[:limit].to_i
else
raise OSM::APIBadUserInput, "Comments limit must be between 1 and 10000"
end
else
100
end
end
end
end
92 changes: 92 additions & 0 deletions app/controllers/concerns/query_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
module QueryMethods
extend ActiveSupport::Concern

private

##
# Filter the resulting items by user
def query_conditions_user(items, filter_property)
user = query_conditions_user_value
items = items.where(filter_property => user) if user
items
end

##
# Get user value for query filtering by user
# Raises OSM::APIBadUserInput if user not found like notes api does, changesets api raises OSM::APINotFoundError instead
def query_conditions_user_value
if params[:display_name] || params[:user]
if params[:display_name]
user = User.find_by(:display_name => params[:display_name])

raise OSM::APIBadUserInput, "User #{params[:display_name]} not known" unless user
else
user = User.find_by(:id => params[:user])

raise OSM::APIBadUserInput, "User #{params[:user]} not known" unless user
end

user
end
end

##
# Restrict the resulting items to those created during a particular time period
# Using 'to' requires specifying 'from' as well for historical reasons
def query_conditions_time(items, filter_property = :created_at)
interval = query_conditions_time_value

if interval
items.where(filter_property => interval)
else
items
end
end

##
# Get query time interval from request parameters or nil
def query_conditions_time_value
if params[:from]
begin
from = Time.parse(params[:from]).utc
rescue ArgumentError
raise OSM::APIBadUserInput, "Date #{params[:from]} is in a wrong format"
end

begin
to = if params[:to]
Time.parse(params[:to]).utc
else
Time.now.utc
end
rescue ArgumentError
raise OSM::APIBadUserInput, "Date #{params[:to]} is in a wrong format"
end

from..to
end
end

##
# Limit the result according to request parameters and settings
def query_limit(items)
items.limit(query_limit_value)
end

##
# Get query limit value from request parameters and settings
def query_limit_value
name = controller_path.sub(%r{^api/}, "").tr("/", "_").singularize
max_limit = Settings["max_#{name}_query_limit"]
default_limit = Settings["default_#{name}_query_limit"]
if params[:limit]
if params[:limit].to_i.positive? && params[:limit].to_i <= max_limit
params[:limit].to_i
else
raise OSM::APIBadUserInput, "#{controller_name.classify} limit must be between 1 and #{max_limit}"
end
else
default_limit
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
json.id changeset_comment.id
json.visible changeset_comment.visible
json.date changeset_comment.created_at.xmlschema
if changeset_comment.author.data_public?
json.uid changeset_comment.author.id
json.user changeset_comment.author.display_name
end
json.text changeset_comment.body
12 changes: 12 additions & 0 deletions app/views/api/changeset_comments/_changeset_comment.xml.builder
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cattrs = {
"id" => changeset_comment.id,
"date" => changeset_comment.created_at.xmlschema,
"visible" => changeset_comment.visible
}
if changeset_comment.author.data_public?
cattrs["uid"] = changeset_comment.author.id
cattrs["user"] = changeset_comment.author.display_name
end
xml.comment(cattrs) do |comment_xml_node|
comment_xml_node.text(changeset_comment.body)
end
Loading
Loading