diff options
Diffstat (limited to 'app/models/milestone.rb')
-rw-r--r-- | app/models/milestone.rb | 68 |
1 files changed, 44 insertions, 24 deletions
diff --git a/app/models/milestone.rb b/app/models/milestone.rb index d8c7536cd31..de7183bf6b4 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -19,21 +19,25 @@ class Milestone < ActiveRecord::Base MilestoneStruct = Struct.new(:title, :name, :id) None = MilestoneStruct.new('No Milestone', 'No Milestone', 0) Any = MilestoneStruct.new('Any Milestone', '', -1) + Upcoming = MilestoneStruct.new('Upcoming', '#upcoming', -2) include InternalId include Sortable + include Referable include StripAttribute + include Milestoneish belongs_to :project has_many :issues + has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues has_many :merge_requests - has_many :participants, through: :issues, source: :assignee + has_many :participants, -> { distinct.reorder('users.name') }, through: :issues, source: :assignee scope :active, -> { with_state(:active) } scope :closed, -> { with_state(:closed) } scope :of_projects, ->(ids) { where(project_id: ids) } - validates :title, presence: true + validates :title, presence: true, uniqueness: { scope: :project_id } validates :project, presence: true strip_attributes :title @@ -55,44 +59,60 @@ class Milestone < ActiveRecord::Base alias_attribute :name, :title class << self + # Searches for milestones matching the given query. + # + # This method uses ILIKE on PostgreSQL and LIKE on MySQL. + # + # query - The search query as a String + # + # Returns an ActiveRecord::Relation. def search(query) - query = "%#{query}%" - where("title like ? or description like ?", query, query) + t = arel_table + pattern = "%#{query}%" + + where(t[:title].matches(pattern).or(t[:description].matches(pattern))) end end - def expired? - if due_date - due_date.past? - else - false - end + def self.reference_pattern + nil + end + + def self.link_reference_pattern + super("milestones", /(?<milestone>\d+)/) end - def open_items_count - self.issues.opened.count + self.merge_requests.opened.count + def self.upcoming + self.where('due_date > ?', Time.now).order(due_date: :asc).first end - def closed_items_count - self.issues.closed.count + self.merge_requests.closed_and_merged.count + def to_reference(from_project = nil) + escaped_title = self.title.gsub("]", "\\]") + + h = Gitlab::Application.routes.url_helpers + url = h.namespace_project_milestone_url(self.project.namespace, self.project, self) + + "[#{escaped_title}](#{url})" end - def total_items_count - self.issues.count + self.merge_requests.count + def reference_link_text(from_project = nil) + self.title end - def percent_complete - ((closed_items_count * 100) / total_items_count).abs - rescue ZeroDivisionError - 0 + def expired? + if due_date + due_date.past? + else + false + end end def expires_at if due_date if due_date.past? - "expired at #{due_date.stamp("Aug 21, 2011")}" + "expired on #{due_date.to_s(:medium)}" else - "expires at #{due_date.stamp("Aug 21, 2011")}" + "expires on #{due_date.to_s(:medium)}" end end end @@ -101,8 +121,8 @@ class Milestone < ActiveRecord::Base active? && issues.opened.count.zero? end - def is_empty? - total_items_count.zero? + def is_empty?(user = nil) + total_items_count(user).zero? end def author_id |