mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-28 22:16:15 +10:00
Improve performance of viewing individual issues This MR does two things: 1. `Issue#related_branches` no longer performs Git operations that aren't needed 2. The output of `Repository#exists?` is now cached and flushed properly Combined these two changes should further cut down the amount of Git operations performed when viewing individual issues (and possibly other pages). See merge request !3296
166 lines
4.2 KiB
Ruby
166 lines
4.2 KiB
Ruby
# == Schema Information
|
|
#
|
|
# Table name: issues
|
|
#
|
|
# id :integer not null, primary key
|
|
# title :string(255)
|
|
# assignee_id :integer
|
|
# author_id :integer
|
|
# project_id :integer
|
|
# created_at :datetime
|
|
# updated_at :datetime
|
|
# position :integer default(0)
|
|
# branch_name :string(255)
|
|
# description :text
|
|
# milestone_id :integer
|
|
# state :string(255)
|
|
# iid :integer
|
|
# updated_by_id :integer
|
|
# moved_to_id :integer
|
|
#
|
|
|
|
require 'carrierwave/orm/activerecord'
|
|
require 'file_size_validator'
|
|
|
|
class Issue < ActiveRecord::Base
|
|
include InternalId
|
|
include Issuable
|
|
include Referable
|
|
include Sortable
|
|
include Taskable
|
|
|
|
ActsAsTaggableOn.strict_case_match = true
|
|
|
|
belongs_to :project
|
|
belongs_to :moved_to, class_name: 'Issue'
|
|
|
|
validates :project, presence: true
|
|
|
|
scope :of_group,
|
|
->(group) { where(project_id: group.projects.select(:id).reorder(nil)) }
|
|
|
|
scope :cared, ->(user) { where(assignee_id: user) }
|
|
scope :open_for, ->(user) { opened.assigned_to(user) }
|
|
scope :in_projects, ->(project_ids) { where(project_id: project_ids) }
|
|
|
|
state_machine :state, initial: :opened do
|
|
event :close do
|
|
transition [:reopened, :opened] => :closed
|
|
end
|
|
|
|
event :reopen do
|
|
transition closed: :reopened
|
|
end
|
|
|
|
state :opened
|
|
state :reopened
|
|
state :closed
|
|
end
|
|
|
|
def hook_attrs
|
|
attributes
|
|
end
|
|
|
|
def self.visible_to_user(user)
|
|
return where(confidential: false) if user.blank?
|
|
return all if user.admin?
|
|
|
|
where('issues.confidential = false OR (issues.confidential = true AND (issues.author_id = :user_id OR issues.assignee_id = :user_id OR issues.project_id IN(:project_ids)))', user_id: user.id, project_ids: user.authorized_projects.select(:id))
|
|
end
|
|
|
|
def self.reference_prefix
|
|
'#'
|
|
end
|
|
|
|
# Pattern used to extract `#123` issue references from text
|
|
#
|
|
# This pattern supports cross-project references.
|
|
def self.reference_pattern
|
|
%r{
|
|
(#{Project.reference_pattern})?
|
|
#{Regexp.escape(reference_prefix)}(?<issue>\d+)
|
|
}x
|
|
end
|
|
|
|
def self.link_reference_pattern
|
|
super("issues", /(?<issue>\d+)/)
|
|
end
|
|
|
|
def to_reference(from_project = nil)
|
|
reference = "#{self.class.reference_prefix}#{iid}"
|
|
|
|
if cross_project_reference?(from_project)
|
|
reference = project.to_reference + reference
|
|
end
|
|
|
|
reference
|
|
end
|
|
|
|
def referenced_merge_requests(current_user = nil)
|
|
@referenced_merge_requests ||= {}
|
|
@referenced_merge_requests[current_user] ||= begin
|
|
Gitlab::ReferenceExtractor.lazily do
|
|
[self, *notes].flat_map do |note|
|
|
note.all_references(current_user).merge_requests
|
|
end
|
|
end.sort_by(&:iid).uniq
|
|
end
|
|
end
|
|
|
|
def related_branches
|
|
project.repository.branch_names.select do |branch|
|
|
branch.end_with?("-#{iid}")
|
|
end
|
|
end
|
|
|
|
# Reset issue events cache
|
|
#
|
|
# Since we do cache @event we need to reset cache in special cases:
|
|
# * when an issue is updated
|
|
# Events cache stored like events/23-20130109142513.
|
|
# The cache key includes updated_at timestamp.
|
|
# Thus it will automatically generate a new fragment
|
|
# when the event is updated because the key changes.
|
|
def reset_events_cache
|
|
Event.reset_event_cache_for(self)
|
|
end
|
|
|
|
# To allow polymorphism with MergeRequest.
|
|
def source_project
|
|
project
|
|
end
|
|
|
|
# From all notes on this issue, we'll select the system notes about linked
|
|
# merge requests. Of those, the MRs closing `self` are returned.
|
|
def closed_by_merge_requests(current_user = nil)
|
|
return [] unless open?
|
|
|
|
notes.system.flat_map do |note|
|
|
note.all_references(current_user).merge_requests
|
|
end.uniq.select { |mr| mr.open? && mr.closes_issue?(self) }
|
|
end
|
|
|
|
def moved?
|
|
!moved_to.nil?
|
|
end
|
|
|
|
def can_move?(user, to_project = nil)
|
|
if to_project
|
|
return false unless user.can?(:admin_issue, to_project)
|
|
end
|
|
|
|
!moved? && user.can?(:admin_issue, self.project)
|
|
end
|
|
|
|
def to_branch_name
|
|
"#{title.parameterize}-#{iid}"
|
|
end
|
|
|
|
def can_be_worked_on?(current_user)
|
|
!self.closed? &&
|
|
!self.project.forked? &&
|
|
self.related_branches.empty? &&
|
|
self.closed_by_merge_requests(current_user).empty?
|
|
end
|
|
end
|