diff options
Diffstat (limited to 'app/models/milestone.rb')
-rw-r--r-- | app/models/milestone.rb | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/app/models/milestone.rb b/app/models/milestone.rb index f6277fe532c..8cfb69349cf 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -7,17 +7,49 @@ class Milestone < ActiveRecord::Base Upcoming = MilestoneStruct.new('Upcoming', '#upcoming', -2) Started = MilestoneStruct.new('Started', '#started', -3) - include SharedMilestoneProperties include InternalId include Sortable include Referable include Milestoneish + include StripAttribute + include CacheMarkdownField belongs_to :project + belongs_to :group has_many :events, as: :target, dependent: :destroy + has_many :issues + has_many :merge_requests + has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues + + validate :uniqueness_of_title, if: :title_changed? + validate :start_date_should_be_less_than_due_date, if: proc { |m| m.start_date.present? && m.due_date.present? } + + strip_attributes :title + alias_attribute :name, :title + + cache_markdown_field :title, pipeline: :single_line + cache_markdown_field :description + scope :of_projects, ->(ids) { where(project_id: ids) } + scope :of_groups, ->(ids) { where(group_id: ids) } + scope :active, -> { with_state(:active) } + scope :closed, -> { with_state(:closed) } + + state_machine :state, initial: :active do + event :close do + transition active: :closed + end + + event :activate do + transition closed: :active + end + + state :closed + + state :active + end class << self # Searches for milestones matching the given query. @@ -33,6 +65,14 @@ class Milestone < ActiveRecord::Base where(t[:title].matches(pattern).or(t[:description].matches(pattern))) end + + def filter_by_state(milestones, state) + case state + when 'closed' then milestones.closed + when 'all' then milestones + else milestones.active + end + end end def self.reference_prefix @@ -111,7 +151,11 @@ class Milestone < ActiveRecord::Base format_reference = milestone_format_reference(format) reference = "#{self.class.reference_prefix}#{format_reference}" - "#{project.to_reference(from_project, full: full)}#{reference}" + if project + "#{project.to_reference(from_project, full: full)}#{reference}" + elsif group + "#{group.to_reference}#{reference}" + end end def reference_link_text(from_project = nil) @@ -130,8 +174,30 @@ class Milestone < ActiveRecord::Base nil end + def safe_title + title.to_slug.normalize.to_s + end + private + def start_date_should_be_less_than_due_date + if due_date <= start_date + errors.add(:start_date, "Can't be greater than due date") + end + end + + # Milestone titles must be unique across project milestones and group milestones + def uniqueness_of_title + if group + title_exists = group.milestones.find_by_title(title).present? + title_exists ||= Milestone.where(project: group.projects).find_by_title(title).present? + elsif project + title_exists = project.milestones.find_by_title(title).present? + end + + errors.add(:title, "Must be unique across project milestones and group milestones.") if title_exists + end + def milestone_format_reference(format = :iid) raise ArgumentError, 'Unknown format' unless [:iid, :name].include?(format) |