scinote-web/app/controllers/search_controller.rb

274 lines
9.6 KiB
Ruby

class SearchController < ApplicationController
include IconsHelper
include ProjectFoldersHelper
before_action :load_vars, only: :index
def index
respond_to do |format|
format.html do
redirect_to new_search_path unless @search_query
end
format.json do
redirect_to new_search_path unless @search_query
case params[:group]
when 'projects'
@model = Project
search_by_name
render json: @records.includes(:team, :project_folder),
each_serializer: GlobalSearch::ProjectSerializer,
meta: {
total: @records.total_count,
next_page: (@records.next_page if @records.respond_to?(:next_page)),
}
when 'project_folders'
@model = ProjectFolder
search_by_name
render json: @records.includes(:team, :parent_folder),
each_serializer: GlobalSearch::ProjectFolderSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'reports'
@model = Report
search_by_name
render json: @records.includes(:team, :project, :user),
each_serializer: GlobalSearch::ReportSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'module_protocols'
@model = Protocol
search_by_name({ in_repository: false })
render json: @records.includes({ my_module: :experiment }, :team),
each_serializer: GlobalSearch::MyModuleProtocolSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'experiments'
@model = Experiment
search_by_name
render json: @records.includes(project: :team),
each_serializer: GlobalSearch::ExperimentSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'tasks'
@model = MyModule
search_by_name
render json: @records.includes(experiment: { project: :team }),
each_serializer: GlobalSearch::MyModuleSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'results'
@model = Result
search_by_name
render json: @records.includes(my_module: { experiment: { project: :team } }),
each_serializer: GlobalSearch::ResultSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'protocols'
@model = Protocol
search_by_name({ in_repository: true })
render json: @records,
each_serializer: GlobalSearch::ProtocolSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'label_templates'
return render json: [], meta: { disabled: true }, status: :ok unless LabelTemplate.enabled?
@model = LabelTemplate
search_by_name
render json: @records,
each_serializer: GlobalSearch::LabelTemplateSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'repository_rows'
@model = RepositoryRow
search_by_name(RepositoryRow)
render json: @records,
each_serializer: GlobalSearch::RepositoryRowSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
when 'assets'
@model = Asset
search_by_name
includes = [{ step: { protocol: { my_module: :experiment } } }, { result: { my_module: :experiment } }, :team]
render json: @records.includes(includes),
each_serializer: GlobalSearch::AssetSerializer,
meta: {
total: @records.total_count,
next_page: @records.next_page
}
return
end
end
end
end
def new
end
def quick
results = if params[:filter].present?
class_name = params[:filter].singularize
return render_422(t('general.invalid_params')) unless Constants::QUICK_SEARCH_SEARCHABLE_OBJECTS.include?(class_name)
object_quick_search(class_name)
else
Constants::QUICK_SEARCH_SEARCHABLE_OBJECTS.filter_map do |object|
next if object == 'label_template' && !LabelTemplate.enabled?
object_quick_search(object)
end.flatten.sort_by(&:updated_at).reverse.take(Constants::QUICK_SEARCH_LIMIT)
end
render json: results, each_serializer: QuickSearchSerializer
end
private
def object_quick_search(class_name)
search_model = class_name.to_s.camelize.constantize
search_object_classes = ["#{class_name.pluralize}.name"]
search_object_classes << search_model::PREFIXED_ID_SQL if search_model.respond_to?(:code)
search_model.search_by_search_fields_with_boolean(current_user,
current_team,
params[:query],
search_object_classes,
limit: Constants::QUICK_SEARCH_LIMIT,
fetch_latest_versions: class_name == 'protocol')
.order(updated_at: :desc)
end
def load_vars
query = (params.fetch(:q) { '' }).strip
@filters = params[:filters]
@include_archived = @filters.blank? || @filters[:include_archived] == 'true'
@teams = (@filters.present? && @filters[:teams]&.values) || current_user.teams
@display_query = query
splited_query = query.split
@search_query = ''
splited_query.each_with_index do |w, i|
if w.length >= Constants::NAME_MIN_LENGTH &&
w.length <= Constants::TEXT_MAX_LENGTH
@search_query += "#{splited_query[i]} "
end
end
if @search_query.blank?
flash[:error] = t('general.query.wrong_query',
min_length: Constants::NAME_MIN_LENGTH,
max_length: Constants::TEXT_MAX_LENGTH)
redirect_back(fallback_location: root_path)
else
@search_query.strip!
end
end
protected
def search_by_name(options = {})
@records = @model.search(current_user,
@include_archived,
@search_query,
nil,
teams: @teams,
users: @users,
options: options)
filter_records if @filters.present?
sort_records
paginate_records
end
def filter_records
filter_datetime!(:created_at) if @filters[:created_at].present?
filter_datetime!(:updated_at) if @filters[:updated_at].present?
filter_users! if @filters[:users].present?
end
def sort_records
@records = case params[:sort]
when 'atoz'
sort_attribute = @model.name == 'Asset' ? 'active_storage_blobs.filename' : 'name'
@records.order(sort_attribute => :asc)
when 'ztoa'
sort_attribute = @model.name == 'Asset' ? 'active_storage_blobs.filename' : 'name'
@records.order(sort_attribute => :desc)
when 'created_asc'
@records.order(created_at: :asc)
else
@records.order(created_at: :desc)
end
end
def paginate_records
@records = if params[:preview] == 'true'
@records.page(params[:page]).per(Constants::GLOBAL_SEARCH_PREVIEW_LIMIT)
else
@records.page(params[:page]).per(Constants::SEARCH_LIMIT)
end
end
def filter_datetime!(attribute)
model_name = @model.model_name.collection
if @filters[attribute][:on].present?
from_date = Time.zone.parse(@filters[attribute][:on]).beginning_of_day.utc
to_date = Time.zone.parse(@filters[attribute][:on]).end_of_day.utc
end
from_date = Time.zone.parse(@filters[attribute][:from]) if @filters[attribute][:from].present?
to_date = Time.zone.parse(@filters[attribute][:to]) if @filters[attribute][:to].present?
@records = @records.where("#{model_name}.#{attribute} >= ?", from_date) if from_date.present?
@records = @records.where("#{model_name}.#{attribute} <= ?", to_date) if to_date.present?
end
def filter_users!
@records = @records.joins("INNER JOIN activities ON #{@model.model_name.collection}.id = activities.subject_id
AND activities.subject_type= '#{@model.name}'")
user_ids = @filters[:users]&.values
@records = if @model.name == 'MyModule'
@records.where('activities.owner_id IN (?) OR users.id IN (?)', user_ids, user_ids)
else
@records.where('activities.owner_id': user_ids)
end
end
end