118 lines
4.1 KiB
Ruby
118 lines
4.1 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 ActionController::ParameterMissing, 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
|