195 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| module Gitlab
 | |
|   class ProjectSearchResults < SearchResults
 | |
|     attr_reader :project, :repository_ref
 | |
| 
 | |
|     def initialize(current_user, project, query, repository_ref = nil)
 | |
|       @current_user = current_user
 | |
|       @project = project
 | |
|       @repository_ref = repository_ref.presence
 | |
|       @query = query
 | |
|     end
 | |
| 
 | |
|     def objects(scope, page: nil, per_page: DEFAULT_PER_PAGE, preload_method: nil)
 | |
|       case scope
 | |
|       when 'notes'
 | |
|         notes.page(page).per(per_page)
 | |
|       when 'blobs'
 | |
|         paginated_blobs(blobs(limit: limit_up_to_page(page, per_page)), page, per_page)
 | |
|       when 'wiki_blobs'
 | |
|         paginated_wiki_blobs(wiki_blobs(limit: limit_up_to_page(page, per_page)), page, per_page)
 | |
|       when 'commits'
 | |
|         paginated_commits(page, per_page)
 | |
|       when 'users'
 | |
|         users.page(page).per(per_page)
 | |
|       else
 | |
|         super(scope, page: page, per_page: per_page, without_count: false)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     def formatted_count(scope)
 | |
|       case scope
 | |
|       when 'blobs'
 | |
|         formatted_limited_count(limited_blobs_count)
 | |
|       when 'notes'
 | |
|         formatted_limited_count(limited_notes_count)
 | |
|       when 'wiki_blobs'
 | |
|         wiki_blobs_count.to_s
 | |
|       when 'commits'
 | |
|         formatted_limited_count(commits_count)
 | |
|       else
 | |
|         super
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     def users
 | |
|       super.where(id: @project.team.members) # rubocop:disable CodeReuse/ActiveRecord
 | |
|     end
 | |
| 
 | |
|     def limited_blobs_count
 | |
|       @limited_blobs_count ||= blobs(limit: count_limit).count
 | |
|     end
 | |
| 
 | |
|     # rubocop: disable CodeReuse/ActiveRecord
 | |
|     def limited_notes_count
 | |
|       return @limited_notes_count if defined?(@limited_notes_count)
 | |
| 
 | |
|       types = %w(issue merge_request commit snippet)
 | |
|       @limited_notes_count = 0
 | |
| 
 | |
|       types.each do |type|
 | |
|         @limited_notes_count += notes_finder(type).limit(count_limit).count
 | |
|         break if @limited_notes_count >= count_limit
 | |
|       end
 | |
| 
 | |
|       @limited_notes_count
 | |
|     end
 | |
|     # rubocop: enable CodeReuse/ActiveRecord
 | |
| 
 | |
|     def wiki_blobs_count
 | |
|       @wiki_blobs_count ||= wiki_blobs(limit: count_limit).count
 | |
|     end
 | |
| 
 | |
|     def commits_count
 | |
|       @commits_count ||= commits(limit: count_limit).count
 | |
|     end
 | |
| 
 | |
|     def single_commit_result?
 | |
|       return false if commits_count != 1
 | |
| 
 | |
|       counts = %i(limited_milestones_count limited_notes_count
 | |
|                   limited_merge_requests_count limited_issues_count
 | |
|                   limited_blobs_count wiki_blobs_count)
 | |
|       counts.all? { |count_method| public_send(count_method) == 0 } # rubocop:disable GitlabSecurity/PublicSend
 | |
|     end
 | |
| 
 | |
|     private
 | |
| 
 | |
|     def paginated_commits(page, per_page)
 | |
|       results = commits(limit: limit_up_to_page(page, per_page))
 | |
| 
 | |
|       Kaminari.paginate_array(results).page(page).per(per_page)
 | |
|     end
 | |
| 
 | |
|     def paginated_blobs(blobs, page, per_page)
 | |
|       results = Kaminari.paginate_array(blobs).page(page).per(per_page)
 | |
| 
 | |
|       Gitlab::Search::FoundBlob.preload_blobs(results)
 | |
| 
 | |
|       results
 | |
|     end
 | |
| 
 | |
|     def paginated_wiki_blobs(blobs, page, per_page)
 | |
|       blob_array = paginated_blobs(blobs, page, per_page)
 | |
|       blob_array.map! do |blob|
 | |
|         Gitlab::Search::FoundWikiPage.new(blob)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     def limit_up_to_page(page, per_page)
 | |
|       current_page = page&.to_i || 1
 | |
|       offset = per_page * (current_page - 1)
 | |
|       count_limit + offset
 | |
|     end
 | |
| 
 | |
|     def blobs(limit: count_limit)
 | |
|       return [] unless Ability.allowed?(@current_user, :download_code, @project)
 | |
| 
 | |
|       @blobs ||= Gitlab::FileFinder.new(project, repository_project_ref).find(query, content_match_cutoff: limit)
 | |
|     end
 | |
| 
 | |
|     def wiki_blobs(limit: count_limit)
 | |
|       return [] unless Ability.allowed?(@current_user, :read_wiki, @project)
 | |
| 
 | |
|       @wiki_blobs ||= begin
 | |
|         if project.wiki_enabled? && query.present?
 | |
|           if project.wiki.empty?
 | |
|             []
 | |
|           else
 | |
|             Gitlab::WikiFileFinder.new(project, repository_wiki_ref).find(query, content_match_cutoff: limit)
 | |
|           end
 | |
|         else
 | |
|           []
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     def notes
 | |
|       @notes ||= notes_finder(nil)
 | |
|     end
 | |
| 
 | |
|     # rubocop: disable CodeReuse/ActiveRecord
 | |
|     def notes_finder(type)
 | |
|       NotesFinder.new(@current_user, search: query, target_type: type, project: project).execute.user.order('updated_at DESC')
 | |
|     end
 | |
|     # rubocop: enable CodeReuse/ActiveRecord
 | |
| 
 | |
|     def commits(limit:)
 | |
|       @commits ||= find_commits(query, limit: limit)
 | |
|     end
 | |
| 
 | |
|     def find_commits(query, limit:)
 | |
|       return [] unless Ability.allowed?(@current_user, :download_code, @project)
 | |
| 
 | |
|       commits = find_commits_by_message(query, limit: limit)
 | |
|       commit_by_sha = find_commit_by_sha(query)
 | |
|       commits |= [commit_by_sha] if commit_by_sha
 | |
|       commits
 | |
|     end
 | |
| 
 | |
|     def find_commits_by_message(query, limit:)
 | |
|       project.repository.find_commits_by_message(query, repository_project_ref, nil, limit)
 | |
|     end
 | |
| 
 | |
|     def find_commit_by_sha(query)
 | |
|       key = query.strip
 | |
|       project.repository.commit(key) if Commit.valid_hash?(key)
 | |
|     end
 | |
| 
 | |
|     # rubocop: disable CodeReuse/ActiveRecord
 | |
|     def project_ids_relation
 | |
|       Project.where(id: project).select(:id).reorder(nil)
 | |
|     end
 | |
|     # rubocop: enabled CodeReuse/ActiveRecord
 | |
| 
 | |
|     def filter_milestones_by_project(milestones)
 | |
|       return Milestone.none unless Ability.allowed?(@current_user, :read_milestone, @project)
 | |
| 
 | |
|       milestones.where(project_id: project.id) # rubocop: disable CodeReuse/ActiveRecord
 | |
|     end
 | |
| 
 | |
|     def repository_project_ref
 | |
|       @repository_project_ref ||= repository_ref || project.default_branch
 | |
|     end
 | |
| 
 | |
|     def repository_wiki_ref
 | |
|       @repository_wiki_ref ||= repository_ref || project.wiki.default_branch
 | |
|     end
 | |
| 
 | |
|     def issuable_params
 | |
|       super.merge(project_id: project.id)
 | |
|     end
 | |
|   end
 | |
| end
 |