2011-12-19 15:30:14 +00:00
|
|
|
class Issue < ActiveRecord::Base
|
2014-03-11 07:39:25 +00:00
|
|
|
include Feed::Issue
|
2014-10-20 20:18:34 +01:00
|
|
|
|
|
|
|
STATUSES = [
|
|
|
|
STATUS_OPEN = 'open',
|
2014-10-22 20:10:52 +01:00
|
|
|
STATUS_REOPEN = 'reopen',
|
2014-10-20 20:18:34 +01:00
|
|
|
STATUS_CLOSED = 'closed'
|
|
|
|
]
|
|
|
|
HASH_TAG_REGEXP = /([a-zA-Z0-9\-_]*\/)?([a-zA-Z0-9\-_]*)?#([0-9]+)/
|
2014-11-07 22:09:32 +00:00
|
|
|
self.per_page = 20
|
2011-12-19 15:30:14 +00:00
|
|
|
|
|
|
|
belongs_to :project
|
|
|
|
belongs_to :user
|
2014-10-20 20:18:34 +01:00
|
|
|
belongs_to :assignee,
|
|
|
|
class_name: 'User',
|
|
|
|
foreign_key: 'assignee_id'
|
|
|
|
|
|
|
|
belongs_to :closer,
|
|
|
|
class_name: 'User',
|
|
|
|
foreign_key: 'closed_by'
|
|
|
|
|
|
|
|
has_many :comments,
|
|
|
|
as: :commentable,
|
|
|
|
dependent: :destroy
|
|
|
|
|
|
|
|
has_many :subscribes,
|
|
|
|
as: :subscribeable,
|
|
|
|
dependent: :destroy
|
|
|
|
|
|
|
|
has_many :labelings,
|
|
|
|
dependent: :destroy
|
|
|
|
|
|
|
|
has_many :labels,
|
|
|
|
-> { uniq },
|
|
|
|
through: :labelings
|
2011-12-19 15:30:14 +00:00
|
|
|
|
2014-03-21 09:38:40 +00:00
|
|
|
has_one :pull_request#, dependent: :destroy
|
2011-12-19 15:30:14 +00:00
|
|
|
|
2014-11-25 16:42:02 +00:00
|
|
|
validates :title, :body, :project, presence: true
|
2014-11-28 16:19:06 +00:00
|
|
|
validates :title, length: { maximum: 100 }
|
|
|
|
validates :body, length: { maximum: 10000 }
|
2011-12-19 15:30:14 +00:00
|
|
|
|
|
|
|
after_create :set_serial_id
|
2011-12-26 15:48:57 +00:00
|
|
|
after_create :subscribe_users
|
2012-01-12 13:07:54 +00:00
|
|
|
after_update :subscribe_issue_assigned_user
|
2011-12-19 15:30:14 +00:00
|
|
|
|
2014-10-20 20:18:34 +01:00
|
|
|
before_create :update_statistic
|
|
|
|
before_update :update_statistic
|
|
|
|
|
2014-11-27 18:55:03 +00:00
|
|
|
accepts_nested_attributes_for :labelings,
|
2015-04-29 00:26:03 +01:00
|
|
|
reject_if: -> (attributes) { attributes['label_id'].blank? },
|
2014-11-28 18:36:24 +00:00
|
|
|
allow_destroy: true
|
2012-02-27 16:10:12 +00:00
|
|
|
|
2014-10-22 20:10:52 +01:00
|
|
|
scope :opened, -> { where(status: [STATUS_OPEN, STATUS_REOPEN]) }
|
2014-10-20 20:18:34 +01:00
|
|
|
scope :closed, -> { where(status: STATUS_CLOSED) }
|
2012-02-28 14:28:11 +00:00
|
|
|
|
2014-10-22 20:10:52 +01:00
|
|
|
scope :needed_checking, -> { where(issues: { status: %w(open reopen blocked ready already) }) }
|
2014-10-20 20:18:34 +01:00
|
|
|
scope :not_closed_or_merged, -> { needed_checking }
|
|
|
|
scope :closed_or_merged, -> { where(issues: { status: %w(closed merged) }) }
|
2012-09-26 12:46:23 +01:00
|
|
|
# Using mb_chars for correct transform to lowercase ('Русский Текст'.downcase => "Русский Текст")
|
2014-10-20 20:18:34 +01:00
|
|
|
scope :search, ->(q) {
|
|
|
|
where("#{table_name}.title ILIKE ?", "%#{q.mb_chars.downcase}%") if q.present?
|
|
|
|
}
|
2014-03-11 07:39:25 +00:00
|
|
|
scope :without_pull_requests, -> {
|
2014-04-29 08:18:12 +01:00
|
|
|
where('NOT EXISTS (select null from pull_requests as pr where pr.issue_id = issues.id)').
|
|
|
|
references(:pull_requests)
|
2014-03-11 07:39:25 +00:00
|
|
|
}
|
2012-06-04 18:00:19 +01:00
|
|
|
|
2014-10-20 20:18:34 +01:00
|
|
|
attr_accessor :new_pull_request
|
|
|
|
|
2011-12-27 17:49:08 +00:00
|
|
|
def assign_uname
|
2012-04-13 20:44:04 +01:00
|
|
|
assignee.uname if assignee
|
2011-12-27 17:49:08 +00:00
|
|
|
end
|
|
|
|
|
2011-12-28 02:57:42 +00:00
|
|
|
def to_param
|
|
|
|
serial_id.to_s
|
|
|
|
end
|
|
|
|
|
2012-01-13 15:07:01 +00:00
|
|
|
def subscribe_creator(creator_id)
|
2014-10-20 20:18:34 +01:00
|
|
|
unless self.subscribes.exists?(user_id: creator_id)
|
2014-01-21 04:51:49 +00:00
|
|
|
self.subscribes.create(user_id: creator_id)
|
2012-01-13 15:07:01 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-02-28 14:05:18 +00:00
|
|
|
def closed?
|
2014-10-20 20:18:34 +01:00
|
|
|
closed_by && closed_at && status == STATUS_CLOSED
|
2012-02-28 14:05:18 +00:00
|
|
|
end
|
|
|
|
|
2012-06-28 11:44:55 +01:00
|
|
|
def set_close(closed_by)
|
2014-10-20 20:18:34 +01:00
|
|
|
self.closed_at = Time.now.utc
|
|
|
|
self.closer = closed_by
|
2014-10-22 20:15:08 +01:00
|
|
|
self.status = STATUS_CLOSED
|
2012-02-28 14:05:18 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def set_open
|
2014-10-20 20:18:34 +01:00
|
|
|
self.closed_at = self.closed_by = nil
|
2014-10-22 20:15:08 +01:00
|
|
|
self.status = STATUS_REOPEN
|
2012-02-28 14:05:18 +00:00
|
|
|
end
|
|
|
|
|
2012-12-13 18:18:22 +00:00
|
|
|
def collect_recipients
|
2015-05-05 13:25:29 +01:00
|
|
|
recipients = self.project.all_members
|
2012-12-13 18:18:22 +00:00
|
|
|
recipients = recipients | [self.assignee] if self.assignee
|
2012-01-27 12:06:04 +00:00
|
|
|
recipients
|
|
|
|
end
|
|
|
|
|
2015-03-14 22:10:04 +00:00
|
|
|
def self.find_by_hash_tag(hash_tag, current_user, project)
|
2014-10-20 20:18:34 +01:00
|
|
|
hash_tag =~ HASH_TAG_REGEXP
|
|
|
|
owner_uname = Regexp.last_match[1].presence || Regexp.last_match[2].presence || project.owner.uname
|
|
|
|
project_name = Regexp.last_match[1] ? Regexp.last_match[2] : project.name
|
|
|
|
serial_id = Regexp.last_match[3]
|
2015-03-14 22:10:04 +00:00
|
|
|
project = Project.find_by_owner_and_name(owner_uname.chomp('/'), project_name)
|
2013-03-29 18:06:23 +00:00
|
|
|
return nil unless project
|
2015-03-14 22:10:04 +00:00
|
|
|
return nil unless ProjectPolicy.new(current_user, project).show?
|
2014-01-21 04:51:49 +00:00
|
|
|
project.issues.where(serial_id: serial_id).first
|
2013-03-29 18:06:23 +00:00
|
|
|
end
|
|
|
|
|
2011-12-19 15:30:14 +00:00
|
|
|
protected
|
|
|
|
|
2014-10-20 20:18:34 +01:00
|
|
|
def update_statistic
|
|
|
|
key = (pull_request || new_pull_request) ? Statistic::KEY_PULL_REQUEST : Statistic::KEY_ISSUE
|
|
|
|
Statistic.statsd_increment(
|
|
|
|
activity_at: Time.now,
|
|
|
|
key: "#{key}.#{status}",
|
|
|
|
project_id: project_id,
|
|
|
|
user_id: closed_by || user_id,
|
|
|
|
) if new_record? || status_changed?
|
|
|
|
end
|
|
|
|
|
2011-12-19 15:30:14 +00:00
|
|
|
def set_serial_id
|
2015-06-03 15:33:42 +01:00
|
|
|
self.serial_id = self.project.issues.maximum(:serial_id).to_i+1
|
2011-12-20 16:57:34 +00:00
|
|
|
self.save!
|
2011-12-19 15:30:14 +00:00
|
|
|
end
|
2011-12-26 15:48:57 +00:00
|
|
|
|
|
|
|
def subscribe_users
|
2012-12-13 18:18:22 +00:00
|
|
|
collect_recipients.each do |recipient|
|
2014-01-21 04:51:49 +00:00
|
|
|
if recipient.notifier.new_comment && !self.subscribes.exists?(user_id: recipient.id)
|
|
|
|
ss = self.subscribes.create(user_id: recipient.id)
|
2012-03-13 13:56:58 +00:00
|
|
|
end
|
2011-12-26 15:48:57 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-01-12 13:07:54 +00:00
|
|
|
def subscribe_issue_assigned_user
|
2012-04-13 20:44:04 +01:00
|
|
|
if self.assignee_id && self.assignee_id_changed?
|
2014-04-09 22:20:39 +01:00
|
|
|
self.subscribes.where(user_id: self.assignee_id_was).first.try(:destroy) unless self.assignee_id_was.blank?
|
2014-01-21 04:51:49 +00:00
|
|
|
if self.assignee.notifier.issue_assign && !self.subscribes.exists?(user_id: self.assignee_id)
|
|
|
|
self.subscribes.create(user_id: self.assignee_id)
|
2012-01-12 13:07:54 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2011-12-19 15:30:14 +00:00
|
|
|
end
|