discourse/app/controllers/search_controller.rb
Sam Saffron 30990006a9 DEV: enable frozen string literal on all files
This reduces chances of errors where consumers of strings mutate inputs
and reduces memory usage of the app.

Test suite passes now, but there may be some stuff left, so we will run
a few sites on a branch prior to merging
2019-05-13 09:31:32 +08:00

158 lines
4.6 KiB
Ruby

# frozen_string_literal: true
require_dependency 'search'
class SearchController < ApplicationController
skip_before_action :check_xhr, only: :show
def self.valid_context_types
%w{user topic category private_messages}
end
def show
@search_term = params.permit(:q)[:q]
# a q param has been given but it's not in the correct format
# eg: ?q[foo]=bar
if params[:q].present? && !@search_term.present?
raise Discourse::InvalidParameters.new(:q)
end
if @search_term.present? &&
@search_term.length < SiteSetting.min_search_term_length
raise Discourse::InvalidParameters.new(:q)
end
search_args = {
type_filter: 'topic',
guardian: guardian,
include_blurbs: true,
blurb_length: 300,
page: if params[:page].to_i <= 10
[params[:page].to_i, 1].max
end
}
context, type = lookup_search_context
if context
search_args[:search_context] = context
search_args[:type_filter] = type if type
end
search_args[:search_type] = :full_page
search_args[:ip_address] = request.remote_ip
search_args[:user_id] = current_user.id if current_user.present?
search = Search.new(@search_term, search_args)
result = search.execute
result.find_user_data(guardian) if result
serializer = serialize_data(result, GroupedSearchResultSerializer, result: result)
respond_to do |format|
format.html do
store_preloaded("search", MultiJson.dump(serializer))
end
format.json do
render_json_dump(serializer)
end
end
end
def query
params.require(:term)
search_args = { guardian: guardian }
search_args[:type_filter] = params[:type_filter] if params[:type_filter].present?
search_args[:include_blurbs] = params[:include_blurbs] == "true" if params[:include_blurbs].present?
search_args[:search_for_id] = true if params[:search_for_id].present?
context, type = lookup_search_context
if context
search_args[:search_context] = context
search_args[:type_filter] = type if type
end
search_args[:search_type] = :header
search_args[:ip_address] = request.remote_ip
search_args[:user_id] = current_user.id if current_user.present?
search_args[:restrict_to_archetype] = params[:restrict_to_archetype] if params[:restrict_to_archetype].present?
search = Search.new(params[:term], search_args)
result = search.execute
render_serialized(result, GroupedSearchResultSerializer, result: result)
end
def click
params.require(:search_log_id)
params.require(:search_result_type)
params.require(:search_result_id)
search_result_type = params[:search_result_type].downcase.to_sym
if SearchLog.search_result_types.has_key?(search_result_type)
attributes = { id: params[:search_log_id] }
if current_user.present?
attributes[:user_id] = current_user.id
else
attributes[:ip_address] = request.remote_ip
end
if search_result_type == :tag
search_result_id = Tag.find_by_name(params[:search_result_id])&.id
else
search_result_id = params[:search_result_id]
end
SearchLog.where(attributes).update_all(
search_result_type: SearchLog.search_result_types[search_result_type],
search_result_id: search_result_id
)
end
render json: success_json
end
protected
def lookup_search_context
return if params[:skip_context] == "true"
search_context = params[:search_context]
unless search_context
if (context = params[:context]) && (id = params[:context_id])
search_context = { type: context, id: id }
end
end
if search_context.present?
raise Discourse::InvalidParameters.new(:search_context) unless SearchController.valid_context_types.include?(search_context[:type])
raise Discourse::InvalidParameters.new(:search_context) if search_context[:id].blank?
# A user is found by username
context_obj = nil
if ['user', 'private_messages'].include? search_context[:type]
context_obj = User.find_by(username_lower: search_context[:id].downcase)
elsif 'category' == search_context[:type]
context_obj = Category.find_by(id: search_context[:id].to_i)
elsif 'topic' == search_context[:type]
context_obj = Topic.find_by(id: search_context[:id].to_i)
end
type_filter = nil
if search_context[:type] == 'private_messages'
type_filter = 'private_messages'
end
guardian.ensure_can_see!(context_obj)
[context_obj, type_filter]
end
end
end