Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-15 12:07:59 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-15 12:07:59 +0300
commite5731d5194e20deb33725943248c5899e4fdf05d (patch)
treeaac082e7b302151dfe38a8a58c0c90f1a66fa017 /app/models/iteration.rb
parent1e9d859394883d104191c51fa18c2353f7bcc1fd (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/models/iteration.rb')
-rw-r--r--app/models/iteration.rb82
1 files changed, 73 insertions, 9 deletions
diff --git a/app/models/iteration.rb b/app/models/iteration.rb
index 630d25d3ec5..bcb25012973 100644
--- a/app/models/iteration.rb
+++ b/app/models/iteration.rb
@@ -5,9 +5,12 @@ class Iteration < ApplicationRecord
self.table_name = 'sprints'
- STATE_ID_MAP = {
- active: 1,
- closed: 2
+ attr_accessor :skip_future_date_validation
+
+ STATE_ENUM_MAP = {
+ upcoming: 1,
+ started: 2,
+ closed: 3
}.with_indifferent_access.freeze
include AtomicInternalId
@@ -21,16 +24,77 @@ class Iteration < ApplicationRecord
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.iterations&.maximum(:iid) }
has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.iterations&.maximum(:iid) }
- state_machine :state, initial: :active do
+ validates :start_date, presence: true
+ validates :due_date, presence: true
+
+ validate :dates_do_not_overlap, if: :start_or_due_dates_changed?
+ validate :future_date, if: :start_or_due_dates_changed?, unless: :skip_future_date_validation
+
+ scope :upcoming, -> { with_state(:upcoming) }
+ scope :started, -> { with_state(:started) }
+
+ state_machine :state_enum, initial: :upcoming do
+ event :start do
+ transition upcoming: :started
+ end
+
event :close do
- transition active: :closed
+ transition [:upcoming, :started] => :closed
end
- event :activate do
- transition closed: :active
+ state :upcoming, value: Iteration::STATE_ENUM_MAP[:upcoming]
+ state :started, value: Iteration::STATE_ENUM_MAP[:started]
+ state :closed, value: Iteration::STATE_ENUM_MAP[:closed]
+ end
+
+ # Alias to state machine .with_state_enum method
+ # This needs to be defined after the state machine block to avoid errors
+ class << self
+ alias_method :with_state, :with_state_enum
+ alias_method :with_states, :with_state_enums
+
+ def filter_by_state(iterations, state)
+ case state
+ when 'closed' then iterations.closed
+ when 'started' then iterations.started
+ when 'opened' then iterations.started.or(iterations.upcoming)
+ when 'all' then iterations
+ else iterations.upcoming
+ end
end
+ end
+
+ def state
+ STATE_ENUM_MAP.key(state_enum)
+ end
- state :active, value: Iteration::STATE_ID_MAP[:active]
- state :closed, value: Iteration::STATE_ID_MAP[:closed]
+ def state=(value)
+ self.state_enum = STATE_ENUM_MAP[value]
+ end
+
+ private
+
+ def start_or_due_dates_changed?
+ start_date_changed? || due_date_changed?
+ end
+
+ # ensure dates do not overlap with other Iterations in the same group/project
+ def dates_do_not_overlap
+ return unless resource_parent.iterations.within_timeframe(start_date, due_date).exists?
+
+ errors.add(:base, s_("Iteration|Dates cannot overlap with other existing Iterations"))
+ end
+
+ # ensure dates are in the future
+ def future_date
+ if start_date_changed?
+ errors.add(:start_date, s_("Iteration|cannot be in the past")) if start_date < Date.today
+ errors.add(:start_date, s_("Iteration|cannot be more than 500 years in the future")) if start_date > 500.years.from_now
+ end
+
+ if due_date_changed?
+ errors.add(:due_date, s_("Iteration|cannot be in the past")) if due_date < Date.today
+ errors.add(:due_date, s_("Iteration|cannot be more than 500 years in the future")) if due_date > 500.years.from_now
+ end
end
end