Commit c0f6df43 authored by Valery Sizov's avatar Valery Sizov Committed by Valery Sizov

elastic search init commit

parent 2154fef2
......@@ -4,45 +4,56 @@ class SearchController < ApplicationController
layout 'search'
def show
return if params[:search].nil? || params[:search].blank?
# return if params[:search].nil? || params[:search].blank?
@search_term = params[:search]
# @search_term = params[:search]
if params[:project_id].present?
@project = Project.find_by(id: params[:project_id])
@project = nil unless can?(current_user, :download_code, @project)
end
# if params[:project_id].present?
# @project = Project.find_by(id: params[:project_id])
# @project = nil unless can?(current_user, :download_code, @project)
# end
# if params[:group_id].present?
# @group = Group.find_by(id: params[:group_id])
# @group = nil unless can?(current_user, :read_group, @group)
# end
# @scope = params[:scope]
# @show_snippets = params[:snippets].eql? 'true'
# @search_results =
# if @project
# unless %w(blobs notes issues merge_requests milestones wiki_blobs
# commits).include?(@scope)
# @scope = 'blobs'
# end
# Search::ProjectService.new(@project, current_user, params).execute
# elsif @show_snippets
# unless %w(snippet_blobs snippet_titles).include?(@scope)
# @scope = 'snippet_blobs'
# end
# Search::SnippetService.new(current_user, params).execute
# else
# unless %w(projects issues merge_requests milestones).include?(@scope)
# @scope = 'projects'
# end
# Search::GlobalService.new(current_user, params).execute
# end
# @objects = @search_results.objects(@scope, params[:page])
@group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
if params[:group_id].present?
@group = Group.find_by(id: params[:group_id])
@group = nil unless can?(current_user, :read_group, @group)
if project
return access_denied! unless can?(current_user, :download_code, project)
@search_results = SearchService.new(current_user, params).project_search(project)
else
@search_results = SearchService.new(current_user, params).global_search
end
@scope = params[:scope]
@show_snippets = params[:snippets].eql? 'true'
@search_results =
if @project
unless %w(blobs notes issues merge_requests milestones wiki_blobs
commits).include?(@scope)
@scope = 'blobs'
end
Search::ProjectService.new(@project, current_user, params).execute
elsif @show_snippets
unless %w(snippet_blobs snippet_titles).include?(@scope)
@scope = 'snippet_blobs'
end
Search::SnippetService.new(current_user, params).execute
else
unless %w(projects issues merge_requests milestones).include?(@scope)
@scope = 'projects'
end
Search::GlobalService.new(current_user, params).execute
end
@objects = @search_results.objects(@scope, params[:page])
@search_results = SearchDecorator.new(@search_results, params[:type])
end
def autocomplete
......
module ApplicationSearch
extend ActiveSupport::Concern
included do
include Elasticsearch::Model
# $ host git-elasticsearch-1.production.infra.home
# git-elasticsearch-1.production.infra.home has address 10.40.56.23
self.__elasticsearch__.client = Elasticsearch::Client.new host: Gitlab.config.elasticsearch.host, port: Gitlab.config.elasticsearch.port
index_name [Rails.application.class.parent_name.downcase, self.name.downcase, Rails.env].join('-')
settings \
index: {
query: {
default_field: :name
},
analysis: {
:analyzer => {
:index_analyzer => {
type: "custom",
tokenizer: "ngram_tokenizer",
filter: %w(lowercase asciifolding name_ngrams)
},
:search_analyzer => {
type: "custom",
tokenizer: "standard",
filter: %w(lowercase asciifolding )
}
},
tokenizer: {
ngram_tokenizer: {
type: "NGram",
min_gram: 1,
max_gram: 20,
token_chars: %w(letter digit connector_punctuation punctuation)
}
},
filter: {
name_ngrams: {
type: "NGram",
max_gram: 20,
min_gram: 1
}
}
}
}
after_commit lambda { Resque.enqueue(Elastic::BaseIndexer, :index, self.class.to_s, self.id) }, on: :create
after_commit lambda { Resque.enqueue(Elastic::BaseIndexer, :update, self.class.to_s, self.id) }, on: :update
after_commit lambda { Resque.enqueue(Elastic::BaseIndexer, :delete, self.class.to_s, self.id) }, on: :destroy
after_touch lambda { Resque.enqueue(Elastic::BaseIndexer, :update, self.class.to_s, self.id) }
end
module ClassMethods
def highlight_options(fields)
es_fields = fields.map { |field| field.split('^').first }.inject({}) do |memo, field|
memo[field.to_sym] = {}
memo
end
{
pre_tags: ["gitlabelasticsearch→"],
post_tags: ["←gitlabelasticsearch"],
fields: es_fields
}
end
end
end
module GroupsSearch
extend ActiveSupport::Concern
included do
include ApplicationSearch
mappings do
indexes :id, type: :integer
indexes :name, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :path, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :description, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :created_at, type: :date
indexes :name_sort, type: :string, index: :not_analyzed
indexes :created_at_sort, type: :string, index: 'not_analyzed'
indexes :updated_at_sort, type: :string, index: 'not_analyzed'
end
def as_indexed_json(options = {})
as_json.merge({
name_sort: name.downcase,
created_at_sort: created_at,
updated_at_sort: updated_at
})
end
def self.search(query, page: 1, per: 20, options: {})
page ||= 1
if options[:in].blank?
options[:in] = %w(name^10 path^5)
else
options[:in].push(%w(name^10 path^5) - options[:in])
end
query_hash = {
query: {
filtered: {
query: {
multi_match: {
fields: options[:in],
query: "#{query}",
operator: :and
}
},
},
},
size: per,
from: per * (page.to_i - 1)
}
if query.blank?
query_hash[:query][:filtered][:query] = { match_all: {}}
query_hash[:track_scores] = true
end
if options[:gids]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
ids: {
values: options[:gids]
}
}
end
options[:order] = :default if options[:order].blank?
order = case options[:order].to_sym
when :newest
{ created_at_sort: { order: :asc, mode: :min } }
when :oldest
{ created_at_sort: { order: :desc, mode: :min } }
when :recently_updated
{ updated_at_sort: { order: :asc, mode: :min } }
when :last_updated
{ updated_at_sort: { order: :desc, mode: :min } }
else
{ name_sort: { order: :asc, mode: :min } }
end
query_hash[:sort] = [
order,
:_score
]
#query_hash[:sort] = [
#{ name_sort: { order: :asc, mode: :min }},
#:_score
#]
if options[:highlight]
query_hash[:highlight] = highlight_options(options[:in])
end
self.__elasticsearch__.search(query_hash)
end
end
end
module IssuesSearch
extend ActiveSupport::Concern
included do
include ApplicationSearch
mappings do
indexes :id, type: :integer, index: :not_analyzed
indexes :iid, type: :integer, index: :not_analyzed
indexes :title, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :description, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :created_at, type: :date
indexes :updated_at, type: :date
indexes :state, type: :string
indexes :project_id, type: :integer, index: :not_analyzed
indexes :author_id, type: :integer, index: :not_analyzed
#indexes :assignee_id, type: :integer, index: :not_analyzed
indexes :project, type: :nested
indexes :author, type: :nested
#indexes :assignee, type: :nested
indexes :title_sort, type: :string, index: 'not_analyzed'
indexes :updated_at_sort, type: :date, index: :not_analyzed
indexes :created_at_sort, type: :string, index: :not_analyzed
end
def as_indexed_json(options = {})
as_json(
include: {
project: { only: :id },
author: { only: :id },
#assignee: { only: :id }
}
).merge({
title_sort: title.downcase,
updated_at_sort: updated_at,
created_at_sort: created_at
})
end
def self.search(query, page: 1, per: 20, options: {})
page ||= 1
if options[:in].blank?
options[:in] = %w(title^2 description)
else
options[:in].push(%w(title^2 description) - options[:in])
end
query_hash = {
query: {
filtered: {
query: {
multi_match: {
fields: options[:in],
query: "#{query}",
operator: :and
}
},
},
},
size: per,
from: per * (page.to_i - 1)
}
if query.blank?
query_hash[:query][:filtered][:query] = { match_all: {}}
query_hash[:track_scores] = true
end
if options[:projects_ids]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
terms: {
project_id: [options[:projects_ids]].flatten
}
}
end
options[:order] = :default if options[:order].blank?
order = case options[:order].to_sym
when :newest
{ created_at_sort: { order: :asc, mode: :min } }
when :oldest
{ created_at_sort: { order: :desc, mode: :min } }
when :recently_updated
{ updated_at_sort: { order: :asc, mode: :min } }
when :last_updated
{ updated_at_sort: { order: :desc, mode: :min } }
else
{ title_sort: { order: :asc, mode: :min } }
end
query_hash[:sort] = [
order,
:_score
]
if options[:highlight]
query_hash[:highlight] = { fields: options[:in].inject({}) { |a, o| a[o.to_sym] = {} } }
end
self.__elasticsearch__.search(query_hash)
end
end
end
module MergeRequestsSearch
extend ActiveSupport::Concern
included do
include ApplicationSearch
mappings do
indexes :id, type: :integer, index: :not_analyzed
indexes :iid, type: :integer, index: :not_analyzed
indexes :target_branch, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :source_branch, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :title, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :description, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :created_at, type: :date
indexes :updated_at, type: :date
indexes :state, type: :string
indexes :merge_status, type: :string
indexes :source_project_id, type: :integer, index: :not_analyzed
indexes :target_project_id, type: :integer, index: :not_analyzed
indexes :author_id, type: :integer, index: :not_analyzed
#indexes :assignee_id, type: :integer, index: :not_analyzed
indexes :source_project, type: :nested
indexes :target_project, type: :nested
indexes :author, type: :nested
#indexes :assignee, type: :nested
indexes :title_sort, type: :string, index: 'not_analyzed'
indexes :created_at_sort, type: :string, index: 'not_analyzed'
indexes :updated_at_sort, type: :string, index: 'not_analyzed'
end
def as_indexed_json(options = {})
as_json(
include: {
source_project: { only: :id },
target_project: { only: :id },
author: { only: :id },
#assignee: { only: :id }
}
).merge({
title_sort: title.downcase,
updated_at_sort: updated_at,
created_at_sort: created_at
})
end
def self.search(query, page: 1, per: 20, options: {})
page ||= 1
if options[:in].blank?
options[:in] = %w(title^2 description)
else
options[:in].push(%w(title^2 description) - options[:in])
end
query_hash = {
query: {
filtered: {
query: {
multi_match: {
fields: options[:in],
query: "#{query}",
operator: :and
}
},
},
},
facets: {
targetProjectFacet: {
terms: {
field: :target_project_id,
all_terms: true,
size: Project.count
}
}
},
size: per,
from: per * (page.to_i - 1)
}
if query.blank?
query_hash[:query][:filtered][:query] = { match_all: {}}
query_hash[:track_scores] = true
end
if options[:projects_ids]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
or: [
terms: {
source_project_id: [options[:projects_ids]].flatten
},
terms: {
target_project_id: [options[:projects_ids]].flatten
}
]
}
end
options[:order] = :default if options[:order].blank?
order = case options[:order].to_sym
when :newest
{ created_at_sort: { order: :asc, mode: :min } }
when :oldest
{ created_at_sort: { order: :desc, mode: :min } }
when :recently_updated
{ updated_at_sort: { order: :asc, mode: :min } }
when :last_updated
{ updated_at_sort: { order: :desc, mode: :min } }
else
{ title_sort: { order: :asc, mode: :min } }
end
query_hash[:sort] = [
order,
:_score
]
if options[:highlight]
query_hash[:highlight] = highlight_options(options[:in])
end
self.__elasticsearch__.search(query_hash)
end
end
end
module ProjectsSearch
extend ActiveSupport::Concern
included do
include ApplicationSearch
mappings do
indexes :id, type: :integer, index: 'not_analyzed'
indexes :name, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :path, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :name_with_namespace, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :path_with_namespace, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :description, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :namespace_id, type: :integer, index: 'not_analyzed'
indexes :created_at, type: :date
indexes :archived, type: :boolean
indexes :visibility_level, type: :integer, index: 'not_analyzed'
indexes :last_activity_at, type: :date
indexes :last_pushed_at, type: :date
indexes :owners, type: :nested
indexes :masters, type: :nested
indexes :developers, type: :nested
indexes :reporters, type: :nested
indexes :guests, type: :nested
indexes :categories, type: :nested
indexes :name_with_namespace_sort, type: :string, index: 'not_analyzed'
indexes :created_at_sort, type: :string, index: 'not_analyzed'
indexes :updated_at_sort, type: :string, index: 'not_analyzed'
end
def as_indexed_json(options={})
as_json(
include: {
owners: { only: :id },
masters: { only: :id },
developers: { only: :id },
reporters: { only: :id },
guests: { only: :id },
categories: { only: :name}
}
).merge({
name_with_namespace: name_with_namespace,
name_with_namespace_sort: name_with_namespace.downcase,
path_with_namespace: path_with_namespace,
updated_at_sort: updated_at,
created_at_sort: created_at
})
end
def self.search(query, page: 1, per: 20, options: {})
page ||= 1
if options[:in].blank?
options[:in] = %w(name^10 name_with_namespace^2 path_with_namespace path^9)
else
options[:in].push(%w(name^10 name_with_namespace^2 path_with_namespace path^9) - options[:in])
end
query_hash = {
query: {
filtered: {
query: {
multi_match: {
fields: options[:in],
query: "#{query}",
operator: :and
}
},
},
},
facets: {
namespaceFacet: {
terms: {
field: :namespace_id,
all_terms: true,
size: Namespace.count
}
},
categoryFacet: {
terms: {
field: "categories.name",
all_terms: true,
# FIXME. Remove to_a
size: Project.category_counts.to_a.count
}
}
},
size: per,
from: per * (page.to_i - 1)
}
if query.blank?
query_hash[:query][:filtered][:query] = { match_all: {} }
query_hash[:track_scores] = true
end
if options[:abandoned]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
range: {
last_pushed_at: {
lte: "now-6M/m"
}
}
}
end
if options[:with_push]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
not: {
missing: {
field: :last_pushed_at,
existence: true,
null_value: true
}
}
}
end
if options[:namespace_id]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
terms: {
namespace_id: [options[:namespace_id]].flatten
}
}
end
if options[:category]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
nested: {
path: :categories,
filter: {
term: { "categories.name" => options[:category] }
}
}
}
end
if options[:non_archived]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
terms: {
archived: [!options[:non_archived]].flatten
}
}
end
if options[:visibility_levels]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
terms: {
visibility_level: [options[:visibility_levels]].flatten
}
}
end
if !options[:owner_id].blank?
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
nested: {
path: :owners,
filter: {
term: { "owners.id" => options[:owner_id] }
}
}
}
end
if options[:pids]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
ids: {
values: options[:pids]
}
}
end
options[:order] = :default if options[:order].blank?
order = case options[:order].to_sym
when :newest
{ created_at_sort: { order: :asc, mode: :min } }
when :oldest
{ created_at_sort: { order: :desc, mode: :min } }
when :recently_updated
{ updated_at_sort: { order: :asc, mode: :min } }
when :last_updated
{ updated_at_sort: { order: :desc, mode: :min } }
else
{ name_with_namespace_sort: { order: :asc, mode: :min } }
end
query_hash[:sort] = [
order,
:_score
]
if options[:highlight]
query_hash[:highlight] = highlight_options(options[:in])
end
self.__elasticsearch__.search(query_hash)
end
end
end
module RepositoriesSearch
extend ActiveSupport::Concern
included do
include Elasticsearch::Git::Repository
self.__elasticsearch__.client = Elasticsearch::Client.new host: Gitlab.config.elasticsearch.host, port: Gitlab.config.elasticsearch.port
def repository_id
project.id
end
def self.repositories_count
Project.count
end
def client_for_indexing
self.__elasticsearch__.client
end
def self.import
Repository.__elasticsearch__.create_index! force: true
Project.find_each do |project|
if project.repository.exists? && !project.repository.empty?
begin
project.repository.index_commits
rescue
end
begin
project.repository.index_blobs
rescue
end
end
end
end
end
end
module UsersSearch
extend ActiveSupport::Concern
included do
include ApplicationSearch
mappings do
indexes :id, type: :integer
indexes :email, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :name, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :username, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :bio, type: :string
indexes :skype, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :linkedin, type: :string
indexes :twitter, type: :string, index_options: 'offsets', search_analyzer: :search_analyzer, index_analyzer: :index_analyzer
indexes :state, type: :string
indexes :website_url, type: :string
indexes :created_at, type: :date
indexes :admin, type: :boolean
indexes :name_sort, type: :string, index: 'not_analyzed'
indexes :created_at_sort, type: :string, index: 'not_analyzed'
indexes :updated_at_sort, type: :string, index: 'not_analyzed'
end
def as_indexed_json(options = {})
as_json.merge({
name_sort: name.downcase,
updated_at_sort: updated_at,
created_at_sort: created_at
})
end
def self.search(query, page: 1, per: 20, options: {})
page ||= 1
per ||= 20
if options[:in].blank?
options[:in] = %w(name^3 username^2 email)
else
options[:in].push(%w(name^3 username^2 email) - options[:in])
end
query_hash = {
query: {
filtered: {
query: {
multi_match: {
fields: options[:in],
query: "#{query}",
operator: :and
}
},
},
},
size: per,
from: per * (page.to_i - 1)
}
if query.blank?
query_hash[:query][:filtered][:query] = { match_all: {}}
query_hash[:track_scores] = true
end
if options[:uids]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
ids: {
values: options[:uids]
}
}
end
if options[:active]
query_hash[:query][:filtered][:filter] ||= { and: [] }
query_hash[:query][:filtered][:filter][:and] << {
terms: {
state: ["active"]
}
}
end
options[:order] = :default if options[:order].blank?
order = case options[:order].to_sym
when :newest
{ created_at_sort: { order: :asc, mode: :min } }
when :oldest
{ created_at_sort: { order: :desc, mode: :min } }
when :recently_updated
{ updated_at_sort: { order: :asc, mode: :min } }
when :last_updated
{ updated_at_sort: { order: :desc, mode: :min } }
else
{ name_sort: { order: :asc, mode: :min } }
end
query_hash[:sort] = [
order,
:_score
]
if options[:highlight]
query_hash[:highlight] = highlight_options(options[:in])
end
self.__elasticsearch__.search(query_hash)
end
end
end
......@@ -19,6 +19,7 @@ require 'file_size_validator'
class Group < Namespace
include Gitlab::ConfigHelper
include Referable
include GroupsSearch
has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember'
alias_method :members, :group_members
......
......@@ -27,6 +27,8 @@ class Issue < ActiveRecord::Base
include Referable
include Sortable
include Taskable
include IssuesSearch
WEIGHT_RANGE = 1..9
ActsAsTaggableOn.strict_case_match = true
......
......@@ -35,6 +35,7 @@ class MergeRequest < ActiveRecord::Base
include Referable
include Sortable
include Taskable
include MergeRequestsSearch
belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project"
belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
......
......@@ -51,6 +51,7 @@ class Project < ActiveRecord::Base
include AfterCommitQueue
include CaseSensitivity
include TokenAuthenticatable
include ProjectsSearch
extend Gitlab::ConfigHelper
......
require 'securerandom'
class Repository
include RepositoriesSearch
class CommitError < StandardError; end
MIRROR_REMOTE = "upstream"
......
......@@ -73,6 +73,7 @@ class User < ActiveRecord::Base
include Sortable
include CaseSensitivity
include TokenAuthenticatable
include UsersSearch
add_authentication_token_field :authentication_token
......
class SearchService < BaseService
def global_search
query = params[:search]
{
groups: search_in_groups(query),
users: search_in_users(query),
projects: search_in_projects(query),
merge_requests: search_in_merge_requests(query),
issues: search_in_issues(query),
repositories: search_in_repository(query),
}
end
def project_search(project)
query = params[:search]
{
groups: {},
users: {},
projects: {},
merge_requests: search_in_merge_requests(query, project),
issues: search_in_issues(query, project),
repositories: search_in_repository(query, project),
}
end
private
def search_in_projects(query)
opt = {
pids: projects_ids,
order: params[:order],
fields: %w(name^10 path^9 description^5
name_with_namespace^2 path_with_namespace),
highlight: true
}
group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
opt[:namespace_id] = group.id if group
opt[:category] = params[:category] if params[:category].present?
begin
response = Project.search(query, options: opt, page: page)
categories_list = if query.blank?
Project.category_counts.map do |category|
{ category: category.name, count: category.count }
end
else
response.response["facets"]["categoryFacet"]["terms"].map do |term|
{ category: term["term"], count: term["count"] }
end
end
{
records: response.records,
results: response.results,
response: response.response,
total_count: response.total_count,
namespaces: namespaces(response.response["facets"]["namespaceFacet"]["terms"]),
categories: categories_list
}
rescue Exception => e
{}
end
end
def search_in_groups(query)
opt = {
gids: current_user ? current_user.authorized_groups.ids : [],
order: params[:order],
fields: %w(name^10 path^5 description),
highlight: true
}
begin
response = Group.search(query, options: opt, page: page)
{
records: response.records,
results: response.results,
response: response.response,
total_count: response.total_count
}
rescue Exception => e
{}
end
end
def search_in_users(query)
opt = {
active: true,
order: params[:order],
highlight: true
}
begin
response = User.search(query, options: opt, page: page)
{
records: response.records,
results: response.results,
response: response.response,
total_count: response.total_count
}
rescue Exception => e
{}
end
end
def search_in_merge_requests(query, project = nil)
opt = {
projects_ids: project ? [project.id] : projects_ids,
order: params[:order],
highlight: true
}
begin
response = MergeRequest.search(query, options: opt, page: page)
{
records: response.records,
results: response.results,
response: response.response,
total_count: response.total_count
}
rescue Exception => e
{}
end
end
def search_in_issues(query, project = nil)
opt = {
projects_ids: project ? [project.id] : projects_ids,
order: params[:order]
}
begin
response = Issue.search(query, options: opt, page: page)
{
records: response.records,
results: response.results,
response: response.response,
total_count: response.total_count
}
rescue Exception => e
{}
end
end
def search_in_repository(query, project = nil)
opt = {
repository_id: project ? [project.id] : projects_ids,
highlight: true,
order: params[:order]
}
if params[:language].present? && params[:language] != 'All'
opt.merge!({ language: params[:language] })
end
begin
res = Repository.search(query, options: opt, page: page)
res[:blobs][:projects] = project_filter(res[:blobs][:repositories]) || []
res[:commits][:projects] = project_filter(res[:commits][:repositories]) || []
res
rescue Exception => e
{}
end
end
def projects_ids
@allowed_projects_ids ||= begin
if params[:namespace].present?
namespace = Namespace.find_by(path: params[:namespace])
if namespace
return namespace.projects.where(id: known_projects_ids).pluck(:id)
end
end
known_projects_ids
end
end
def page
return @current_page if defined?(@current_page)
@current_page = params[:page].to_i
@current_page = 1 if @current_page == 0
@current_page
end
def known_projects_ids
known_projects_ids = []
known_projects_ids += current_user.known_projects.pluck(:id) if current_user
known_projects_ids + Project.public_or_internal_only(current_user).pluck(:id)
end
def project_filter(es_results)
terms = es_results.
select { |term| term['count'] > 0 }.
inject({}) do |memo, term|
memo[term["term"]] = term["count"]
memo
end
projects_meta_data = Project.joins(:namespace).where(id: terms.keys).
pluck(['projects.name','projects.path',
'namespaces.name as namespace_name',
'namespaces.path as namespace_path',
'projects.id'].join(","))
if projects_meta_data.any?
projects_meta_data.map do |meta|
{
name: meta[2] + ' / ' + meta[0],
path: meta[3] + ' / ' + meta[1],
count: terms[meta[4]]
}
end.sort { |x, y| y[:count] <=> x[:count] }
else
[]
end
end
def namespaces(terms)
founded_terms = terms.select { |term| term['count'] > 0 }
grouped_terms = founded_terms.inject({}) do |memo, term|
memo[term["term"]] = term["count"]
memo
end
namespaces_meta_data = Namespace.find(grouped_terms.keys)
if namespaces_meta_data.any?
namespaces_meta_data.map do |namespace|
{ namespace: namespace, count: grouped_terms[namespace.id] }
end.sort { |x, y| y[:count] <=> x[:count] }
else
[]
end
end
end
......@@ -16,7 +16,8 @@ module Gitlab
#{config.root}/app/models/hooks
#{config.root}/app/models/concerns
#{config.root}/app/models/project_services
#{config.root}/app/models/members))
#{config.root}/app/models/members
#{config.root}/app/elastic))
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment