diff options
Diffstat (limited to 'app/models/work_items/parent_link.rb')
-rw-r--r-- | app/models/work_items/parent_link.rb | 62 |
1 files changed, 39 insertions, 23 deletions
diff --git a/app/models/work_items/parent_link.rb b/app/models/work_items/parent_link.rb index 13d6db3e08e..33857fb08c2 100644 --- a/app/models/work_items/parent_link.rb +++ b/app/models/work_items/parent_link.rb @@ -12,12 +12,14 @@ module WorkItems validates :work_item_parent, presence: true validates :work_item, presence: true, uniqueness: true - validate :validate_child_type - validate :validate_parent_type + validate :validate_hierarchy_restrictions + validate :validate_cyclic_reference validate :validate_same_project validate :validate_max_children validate :validate_confidentiality + scope :for_parents, ->(parent_ids) { where(work_item_parent_id: parent_ids) } + class << self def has_public_children?(parent_id) joins(:work_item).where(work_item_parent_id: parent_id, 'issues.confidential': false).exists? @@ -33,27 +35,6 @@ module WorkItems private - def validate_child_type - return unless work_item - - unless work_item.task? - errors.add :work_item, _('only Task can be assigned as a child in hierarchy.') - end - end - - def validate_parent_type - return unless work_item_parent - - base_type = work_item_parent.work_item_type.base_type.to_sym - unless PARENT_TYPES.include?(base_type) - parent_names = WorkItems::Type::BASE_TYPES.slice(*WorkItems::ParentLink::PARENT_TYPES) - .values.map { |type| type[:name] } - - errors.add :work_item_parent, _('only %{parent_types} can be parent of Task.') % - { parent_types: parent_names.to_sentence } - end - end - def validate_same_project return if work_item.nil? || work_item_parent.nil? @@ -79,5 +60,40 @@ module WorkItems "parent. Make the work item confidential and try again.") end end + + def validate_hierarchy_restrictions + return unless work_item && work_item_parent + + restriction = ::WorkItems::HierarchyRestriction + .find_by_parent_type_id_and_child_type_id(work_item_parent.work_item_type_id, work_item.work_item_type_id) + + if restriction.nil? + errors.add :work_item, _('is not allowed to add this type of parent') + return + end + + validate_depth(restriction.maximum_depth) + end + + def validate_depth(depth) + return unless depth + return if work_item.work_item_type_id != work_item_parent.work_item_type_id + + if work_item_parent.same_type_base_and_ancestors.count + work_item.same_type_descendants_depth > depth + errors.add :work_item, _('reached maximum depth') + end + end + + def validate_cyclic_reference + return unless work_item_parent&.id && work_item&.id + + if work_item.id == work_item_parent.id + errors.add :work_item, _('is not allowed to point to itself') + end + + if work_item_parent.ancestors.detect { |ancestor| work_item.id == ancestor.id } + errors.add :work_item, _('is already present in ancestors') + end + end end end |