# IssuableFinder # # Used to filter Issues and MergeRequests collections by set of params # # Arguments: # klass - actual class like Issue or MergeRequest # current_user - which user use # params: # scope: 'created-by-me' or 'assigned-to-me' or 'all' # state: 'open' or 'closed' or 'all' # group_id: integer # project_id: integer # milestone_title: string # assignee_id: integer # search: string # label_name: string # sort: string # require_relative 'projects_finder' class IssuableFinder NONE = '0' attr_accessor :current_user, :params def initialize(current_user, params) @current_user = current_user @params = params end def execute items = init_collection items = by_scope(items) items = by_state(items) items = by_group(items) items = by_project(items) items = by_search(items) items = by_milestone(items) items = by_assignee(items) items = by_author(items) items = by_label(items) sort(items) end def group return @group if defined?(@group) @group = if params[:group_id].present? Group.find(params[:group_id]) else nil end end def project? params[:project_id].present? end def project return @project if defined?(@project) if project? @project = Project.find(params[:project_id]) unless Ability.abilities.allowed?(current_user, :read_project, @project) @project = nil end else @project = nil end @project end def projects return @projects if defined?(@projects) if project? @projects = project elsif current_user && params[:authorized_only].presence && !current_user_related? @projects = current_user.authorized_projects.reorder(nil) else @projects = ProjectsFinder.new.execute(current_user, group: group). reorder(nil) end end def search params[:search].presence end def milestones? params[:milestone_title].present? end def filter_by_no_milestone? milestones? && params[:milestone_title] == Milestone::None.title end def milestones return @milestones if defined?(@milestones) @milestones = if milestones? scope = Milestone.where(project_id: projects) scope.where(title: params[:milestone_title]) else nil end end def labels? params[:label_name].present? end def filter_by_no_label? labels? && params[:label_name] == Label::None.title end def labels return @labels if defined?(@labels) if labels? && !filter_by_no_label? @labels = Label.where(title: label_names) if projects @labels = @labels.where(project: projects) end else @labels = Label.none end end def assignee? params[:assignee_id].present? end def assignee return @assignee if defined?(@assignee) @assignee = if assignee? && params[:assignee_id] != NONE User.find(params[:assignee_id]) else nil end end def author? params[:author_id].present? end def author return @author if defined?(@author) @author = if author? && params[:author_id] != NONE User.find(params[:author_id]) else nil end end private def init_collection klass.all end def by_scope(items) case params[:scope] when 'created-by-me', 'authored' then items.where(author_id: current_user.id) when 'all' then items when 'assigned-to-me' then items.where(assignee_id: current_user.id) else raise 'You must specify default scope' end end def by_state(items) case params[:state] when 'closed' items.closed when 'merged' items.respond_to?(:merged) ? items.merged : items.closed when 'all' items when 'opened' items.opened else raise 'You must specify default state' end end def by_group(items) items = items.of_group(group) if group items end def by_project(items) items = if project? items.of_projects(projects).references_project elsif projects items.merge(projects.reorder(nil)).join_project else items.none end items end def by_search(items) items = items.search(search) if search items end def sort(items) # Ensure we always have an explicit sort order (instead of inheriting # multiple orders when combining ActiveRecord::Relation objects). params[:sort] ? items.sort(params[:sort]) : items.reorder(id: :desc) end def by_assignee(items) if assignee? items = items.where(assignee_id: assignee.try(:id)) end items end def by_author(items) if author? items = items.where(author_id: author.try(:id)) end items end def by_milestone(items) if milestones? if filter_by_no_milestone? items = items.where(milestone_id: [-1, nil]) else items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] }) if projects items = items.where(milestones: { project_id: projects }) end end end items end def by_label(items) if labels? if filter_by_no_label? items = items. joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{klass.name}' AND label_links.target_id = #{klass.table_name}.id"). where(label_links: { id: nil }) else items = items.joins(:labels).where(labels: { title: label_names }) if projects items = items.where(labels: { project_id: projects }) end end end items end def label_names params[:label_name].split(',') end def current_user_related? params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me' end end