diaspora/app/controllers/api/v1/search_controller.rb
Benjamin Neff 4edaebb94f
Remove "Did you mean?" from api errors when a parameter is missing
This isn't helpful at all for an api if you don't send a required
parameter and get an error response that just tells you what parameters
that were available.

This is a new feature with rails >= 6.1 and ruby >= 2.7, so this just
keeps the old behaviour of older rails/ruby versions.
2022-07-20 21:35:02 +02:00

118 lines
4 KiB
Ruby

# frozen_string_literal: true
module Api
module V1
class SearchController < Api::V1::BaseController
USER_FILTER_CONTACTS = "contacts"
USER_FILTER_RECEIVING_CONTACTS = "contacts:receiving"
USER_FILTER_SHARING_CONTACTS = "contacts:sharing"
USER_FILTER_ASPECTS_PREFIX = "aspect:"
USER_FILTERS_EXACT_MATCH = [USER_FILTER_CONTACTS, USER_FILTER_RECEIVING_CONTACTS,
USER_FILTER_SHARING_CONTACTS].freeze
USER_FILTERS_PREFIX_MATCH = [USER_FILTER_ASPECTS_PREFIX].freeze
before_action do
require_access_token %w[public:read]
end
rescue_from RuntimeError do |e|
render_error 422, e.message
end
def user_index
user_page = index_pager(people_query).response
user_page[:data] = user_page[:data].map {|p| PersonPresenter.new(p).as_api_json }
render_paged_api_response user_page
end
def post_index
posts_page = time_pager(posts_query, "posts.created_at", "created_at").response
posts_page[:data] = posts_page[:data].map {|post| PostPresenter.new(post).as_api_response }
render_paged_api_response posts_page
end
def tag_index
tags_page = index_pager(tags_query).response
tags_page[:data] = tags_page[:data].pluck(:name)
render_paged_api_response tags_page
end
private
def time_pager(query, query_time_field, data_time_field)
Api::Paging::RestPaginatorBuilder.new(query, request).time_pager(params, query_time_field, data_time_field)
end
def people_query
tag = params[:tag]
name_or_handle = params[:name_or_handle]
raise "Parameters tag and name_or_handle are exclusive" if tag.present? && name_or_handle.present?
query = if tag.present?
# scope filters to only searchable people already
Person.profile_tagged_with(tag)
elsif name_or_handle.present?
Person.searchable(contacts_read? && current_user) # rubocop:disable Rails/DynamicFindBy
.find_by_substring(name_or_handle)
else
raise "Missing parameter tag or name_or_handle"
end
query = query.where(closed_account: false)
user_filters.each do |filter|
query = query.contacts_of(current_user) if filter == USER_FILTER_CONTACTS
if filter == USER_FILTER_RECEIVING_CONTACTS
query = query.contacts_of(current_user).where(contacts: {receiving: true})
end
if filter == USER_FILTER_SHARING_CONTACTS
query = query.contacts_of(current_user).where(contacts: {sharing: true})
end
if filter.start_with?(USER_FILTER_ASPECTS_PREFIX) # rubocop:disable Style/Next
_, ids = filter.split(":", 2)
ids = ids.split(",").map {|id|
Integer(id) rescue raise("Invalid aspect filter") # rubocop:disable Style/RescueModifier
}
raise "Invalid aspect filter" unless current_user.aspects.where(id: ids).count == ids.size
query = Person.where(id: query.all_from_aspects(ids, current_user).select(:id))
end
end
query.distinct
end
def posts_query
if private_read?
Stream::Tag.new(current_user, params.require(:tag)).posts
else
Stream::Tag.new(nil, params.require(:tag)).posts
end
end
def tags_query
ActsAsTaggableOn::Tag.autocomplete(params.require(:query))
end
def user_filters
@user_filters ||= Array(params[:filter]).uniq.tap do |filters|
raise "Invalid filter" unless filters.all? {|filter|
USER_FILTERS_EXACT_MATCH.include?(filter) ||
USER_FILTERS_PREFIX_MATCH.any? {|prefix| filter.start_with?(prefix) }
}
# For now all filters require contacts:read
require_access_token %w[contacts:read] unless filters.empty?
end
end
def contacts_read?
access_token? %w[contacts:read]
end
end
end
end