gitlab-org--gitlab-foss/app/controllers/concerns/issuable_collections.rb

174 lines
5.2 KiB
Ruby
Raw Normal View History

module IssuableCollections
extend ActiveSupport::Concern
include SortingHelper
include Gitlab::IssuableMetadata
include Gitlab::Utils::StrongMemoize
included do
2017-11-07 08:34:12 -05:00
helper_method :finder
end
private
# rubocop:disable Gitlab/ModuleWithInstanceVariables
2017-11-07 08:34:12 -05:00
def set_issuables_index
@issuables = issuables_collection
set_pagination
2017-11-07 08:34:12 -05:00
return if redirect_out_of_range(@total_pages)
if params[:label_name].present?
2017-11-07 08:34:12 -05:00
labels_params = { project_id: @project.id, title: params[:label_name] }
@labels = LabelsFinder.new(current_user, labels_params).execute
end
@users = []
2017-11-07 08:34:12 -05:00
if params[:assignee_id].present?
assignee = User.find_by_id(params[:assignee_id])
@users.push(assignee) if assignee
end
2017-11-07 08:34:12 -05:00
if params[:author_id].present?
author = User.find_by_id(params[:author_id])
@users.push(author) if author
end
end
def set_pagination
return if pagination_disabled?
@issuables = @issuables.page(params[:page])
@issuable_meta_data = issuable_meta_data(@issuables, collection_type)
@total_pages = issuable_page_count
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def pagination_disabled?
false
end
2017-11-07 08:34:12 -05:00
def issuables_collection
finder.execute.preload(preload_for_collection)
end
2017-11-07 08:34:12 -05:00
def redirect_out_of_range(total_pages)
return false if total_pages.nil? || total_pages.zero?
out_of_range = @issuables.current_page > total_pages # rubocop:disable Gitlab/ModuleWithInstanceVariables
if out_of_range
redirect_to(url_for(params.merge(page: total_pages, only_path: true)))
end
out_of_range
end
2017-11-07 08:34:12 -05:00
def issuable_page_count
page_count_for_relation(@issuables, finder.row_count) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def page_count_for_relation(relation, row_count)
limit = relation.limit_value.to_f
return 1 if limit.zero?
(row_count.to_f / limit).ceil
end
def issuable_finder_for(finder_class)
finder_class.new(current_user, filter_params)
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def filter_params
set_sort_order_from_cookie
set_default_state
# Skip irrelevant Rails routing params
@filter_params = params.dup.except(:controller, :action, :namespace_id)
@filter_params[:sort] ||= default_sort_order
@sort = @filter_params[:sort]
if @project
@filter_params[:project_id] = @project.id
elsif @group
@filter_params[:group_id] = @group.id
@filter_params[:include_subgroups] = true
else
# TODO: this filter ignore issues/mr created in public or
# internal repos where you are not a member. Enable this filter
# or improve current implementation to filter only issues you
# created or assigned or mentioned
# @filter_params[:authorized_only] = true
end
@filter_params.permit(IssuableFinder::VALID_PARAMS)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def set_default_state
params[:state] = 'opened' if params[:state].blank?
end
def set_sort_order_from_cookie
key = 'issuable_sort'
cookies[key] = params[:sort] if params[:sort].present?
2017-09-22 20:46:53 -04:00
cookies[key] = update_cookie_value(cookies[key])
params[:sort] = cookies[key]
end
def default_sort_order
case params[:state]
2017-09-22 20:46:53 -04:00
when 'opened', 'all' then sort_value_created_date
when 'merged', 'closed' then sort_value_recently_updated
2017-09-22 20:46:53 -04:00
else sort_value_created_date
end
end
# Update old values to the actual ones.
def update_cookie_value(value)
case value
when 'id_asc' then sort_value_oldest_created
when 'id_desc' then sort_value_recently_created
when 'created_asc' then sort_value_created_date
when 'created_desc' then sort_value_created_date
when 'due_date_asc' then sort_value_due_date
when 'due_date_desc' then sort_value_due_date
when 'milestone_due_asc' then sort_value_milestone
when 'milestone_due_desc' then sort_value_milestone
when 'downvotes_asc' then sort_value_popularity
when 'downvotes_desc' then sort_value_popularity
else value
end
end
2017-11-07 08:34:12 -05:00
def finder
strong_memoize(:finder) do
issuable_finder_for(@finder_type) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
2017-11-07 08:34:12 -05:00
end
def collection_type
@collection_type ||= case finder
when IssuesFinder
'Issue'
when MergeRequestsFinder
'MergeRequest'
end
end
def preload_for_collection
@preload_for_collection ||= case collection_type
when 'Issue'
[:project, :author, :assignees, :labels, :milestone, project: :namespace]
when 'MergeRequest'
[
:source_project, :target_project, :author, :assignee, :labels, :milestone,
Use latest_merge_request_diff association Compared to the merge_request_diff association: 1. It's simpler to query. The query uses a foreign key to the merge_request_diffs table, so no ordering is necessary. 2. It's faster for preloading. The merge_request_diff association has to load every diff for the MRs in the set, then discard all but the most recent for each. This association means that Rails can just query for N diffs from N MRs. 3. It's more complicated to update. This is a bidirectional foreign key, so we need to update two tables when adding a diff record. This also means we need to handle this as a special case when importing a GitLab project. There is some juggling with this association in the merge request model: * `MergeRequest#latest_merge_request_diff` is _always_ the latest diff. * `MergeRequest#merge_request_diff` reuses `MergeRequest#latest_merge_request_diff` unless: * Arguments are passed. These are typically to force-reload the association. * It doesn't exist. That means we might be trying to implicitly create a diff. This only seems to happen in specs. * The association is already loaded. This is important for the reasons explained in the comment, which I'll reiterate here: if we a) load a non-latest diff, then b) get its `merge_request`, then c) get that MR's `merge_request_diff`, we should get the diff we loaded in c), even though that's not the latest diff. Basically, `MergeRequest#merge_request_diff` is the latest diff in most cases, but not quite all.
2017-11-15 12:22:18 -05:00
head_pipeline: :project, target_project: :namespace, latest_merge_request_diff: :merge_request_diff_commits
2017-11-07 08:34:12 -05:00
]
end
end
end