Commit c5aabfb7 authored by Nick Thomas's avatar Nick Thomas

Remove an unnecessary "included do ... end" block in app/models/concerns/approvable.rb

parent eb24ebf4
module Approvable module Approvable
extend ActiveSupport::Concern def requires_approve?
approvals_required.nonzero?
included do end
def requires_approve?
approvals_required.nonzero?
end
def approved? def approved?
approvals_left < 1 approvals_left < 1
end end
# Number of approvals remaining (excluding existing approvals) before the MR is # Number of approvals remaining (excluding existing approvals) before the MR is
# considered approved. If there are fewer potential approvers than approvals left, # considered approved. If there are fewer potential approvers than approvals left,
# choose the lower so the MR doesn't get 'stuck' in a state where it can't be approved. # choose the lower so the MR doesn't get 'stuck' in a state where it can't be approved.
# #
def approvals_left def approvals_left
[ [
[approvals_required - approvals.count, number_of_potential_approvers].min, [approvals_required - approvals.count, number_of_potential_approvers].min,
0 0
].max ].max
end end
def approvals_required def approvals_required
approvals_before_merge || target_project.approvals_before_merge approvals_before_merge || target_project.approvals_before_merge
end end
# An MR can potentially be approved by: # An MR can potentially be approved by:
# - anyone in the approvers list # - anyone in the approvers list
# - any other project member with developer access or higher (if there are no approvers # - any other project member with developer access or higher (if there are no approvers
# left) # left)
# #
# It cannot be approved by: # It cannot be approved by:
# - a user who has already approved the MR # - a user who has already approved the MR
# - the MR author # - the MR author
# #
def number_of_potential_approvers def number_of_potential_approvers
has_access = ['access_level > ?', Member::REPORTER] has_access = ['access_level > ?', Member::REPORTER]
users_with_access = { id: project.project_authorizations.where(has_access).select(:user_id) } users_with_access = { id: project.project_authorizations.where(has_access).select(:user_id) }
all_approvers = all_approvers_including_groups all_approvers = all_approvers_including_groups
users_relation = User.active.where.not(id: approvals.select(:user_id)) users_relation = User.active.where.not(id: approvals.select(:user_id))
users_relation = users_relation.where.not(id: author.id) if author users_relation = users_relation.where.not(id: author.id) if author
# This is an optimisation for large instances. Instead of getting the # This is an optimisation for large instances. Instead of getting the
# count of all users who meet the conditions in a single query, which # count of all users who meet the conditions in a single query, which
# produces a slow query plan, we get the union of all users with access # produces a slow query plan, we get the union of all users with access
# and all users in the approvers list, and count them. # and all users in the approvers list, and count them.
if all_approvers.any? if all_approvers.any?
specific_approvers = { id: all_approvers.map(&:id) } specific_approvers = { id: all_approvers.map(&:id) }
union = Gitlab::SQL::Union.new([ union = Gitlab::SQL::Union.new([
users_relation.where(users_with_access).select(:id), users_relation.where(users_with_access).select(:id),
users_relation.where(specific_approvers).select(:id) users_relation.where(specific_approvers).select(:id)
]) ])
User.from("(#{union.to_sql}) subquery").count User.from("(#{union.to_sql}) subquery").count
else else
users_relation.where(users_with_access).count users_relation.where(users_with_access).count
end
end end
end
# Users in the list of approvers who have not already approved this MR. # Users in the list of approvers who have not already approved this MR.
# #
def approvers_left def approvers_left
User.where(id: all_approvers_including_groups.map(&:id)).where.not(id: approvals.select(:user_id)) User.where(id: all_approvers_including_groups.map(&:id)).where.not(id: approvals.select(:user_id))
end end
# The list of approvers from either this MR (if they've been set on the MR) or the # The list of approvers from either this MR (if they've been set on the MR) or the
# target project. Excludes the author by default. # target project. Excludes the author by default.
# #
# Before a merge request has been created, author will be nil, so pass the current user # Before a merge request has been created, author will be nil, so pass the current user
# on the MR create page. # on the MR create page.
# #
def overall_approvers def overall_approvers
approvers_relation = approvers_overwritten? ? approvers : target_project.approvers approvers_relation = approvers_overwritten? ? approvers : target_project.approvers
approvers_relation = approvers_relation.where.not(user_id: author.id) if author approvers_relation = approvers_relation.where.not(user_id: author.id) if author
approvers_relation approvers_relation
end end
def overall_approver_groups def overall_approver_groups
approvers_overwritten? ? approver_groups : target_project.approver_groups approvers_overwritten? ? approver_groups : target_project.approver_groups
end end
def all_approvers_including_groups def all_approvers_including_groups
approvers = [] approvers = []
# Approvers from direct assignment # Approvers from direct assignment
approvers << approvers_from_users approvers << approvers_from_users
approvers << approvers_from_groups approvers << approvers_from_groups
approvers.flatten approvers.flatten
end end
def approvers_from_users def approvers_from_users
overall_approvers.map(&:user) overall_approvers.map(&:user)
end end
def approvers_from_groups def approvers_from_groups
group_approvers = [] group_approvers = []
overall_approver_groups.each do |approver_group| overall_approver_groups.each do |approver_group|
group_approvers << approver_group.users group_approvers << approver_group.users
end end
group_approvers.flatten! group_approvers.flatten!
group_approvers.delete(author) group_approvers.delete(author)
group_approvers group_approvers
end end
def approvers_overwritten? def approvers_overwritten?
approvers.to_a.any? || approver_groups.to_a.any? approvers.to_a.any? || approver_groups.to_a.any?
end end
def can_approve?(user) def can_approve?(user)
return false unless user return false unless user
return true if approvers_left.include?(user) return true if approvers_left.include?(user)
return false if user == author return false if user == author
return false unless user.can?(:update_merge_request, self) return false unless user.can?(:update_merge_request, self)
any_approver_allowed? && approvals.where(user: user).empty? any_approver_allowed? && approvals.where(user: user).empty?
end end
def has_approved?(user) def has_approved?(user)
return false unless user return false unless user
approved_by_users.include?(user) approved_by_users.include?(user)
end end
# Once there are fewer approvers left in the list than approvals required, allow other # Once there are fewer approvers left in the list than approvals required, allow other
# project members to approve the MR. # project members to approve the MR.
# #
def any_approver_allowed? def any_approver_allowed?
approvals_left > approvers_left.count approvals_left > approvers_left.count
end end
def approved_by_users def approved_by_users
approvals.map(&:user) approvals.map(&:user)
end end
def approver_ids=(value) def approver_ids=(value)
value.split(",").map(&:strip).each do |user_id| value.split(",").map(&:strip).each do |user_id|
next if author && user_id == author.id next if author && user_id == author.id
approvers.find_or_initialize_by(user_id: user_id, target_id: id) approvers.find_or_initialize_by(user_id: user_id, target_id: id)
end
end end
end
def approver_group_ids=(value) def approver_group_ids=(value)
value.split(",").map(&:strip).each do |group_id| value.split(",").map(&:strip).each do |group_id|
approver_groups.find_or_initialize_by(group_id: group_id, target_id: id) approver_groups.find_or_initialize_by(group_id: group_id, target_id: id)
end
end end
end end
end end
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