summaryrefslogtreecommitdiff
path: root/app/models/milestone.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/milestone.rb')
-rw-r--r--app/models/milestone.rb68
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