category.rb 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class KnowledgeBase::Category < ApplicationModel
  3. include HasTranslations
  4. include HasAgentAllowedParams
  5. include ChecksKbClientNotification
  6. include ChecksKbClientVisibility
  7. AGENT_ALLOWED_ATTRIBUTES = %i[knowledge_base_id parent_id category_icon].freeze
  8. AGENT_ALLOWED_NESTED_RELATIONS = %i[translations].freeze
  9. belongs_to :knowledge_base, inverse_of: :categories
  10. has_many :answers, class_name: 'KnowledgeBase::Answer',
  11. inverse_of: :category,
  12. dependent: :restrict_with_exception
  13. has_many :children, class_name: 'KnowledgeBase::Category',
  14. foreign_key: :parent_id,
  15. inverse_of: :parent,
  16. dependent: :restrict_with_exception
  17. belongs_to :parent, class_name: 'KnowledgeBase::Category',
  18. inverse_of: :children,
  19. touch: true,
  20. optional: true
  21. has_many :permissions, class_name: 'KnowledgeBase::Permission',
  22. as: :permissionable,
  23. autosave: true,
  24. dependent: :destroy
  25. validates :category_icon, presence: true
  26. validate :cannot_be_child_of_parent
  27. scope :root, -> { where(parent: nil) }
  28. scope :sorted, -> { order(position: :asc) }
  29. acts_as_list scope: :parent, top_of_list: 0
  30. alias assets_essential assets
  31. def assets(data = {})
  32. return data if assets_added_to?(data)
  33. data = super(data)
  34. data = knowledge_base.assets(data)
  35. data = ApplicationModel::CanAssets.reduce(translations, data)
  36. # include parent category or KB for root to have full path
  37. (parent || knowledge_base).assets(data)
  38. end
  39. def self_parent?(candidate)
  40. return true if candidate == parent
  41. true if parent&.self_parent?(candidate)
  42. end
  43. def self_with_children
  44. [self] + children.map(&:self_with_children).flatten
  45. end
  46. def self_with_parents
  47. result = [self]
  48. check = self
  49. while check.parent.present?
  50. result << check.parent
  51. check = check.parent
  52. end
  53. result
  54. end
  55. def self_with_children_answers
  56. KnowledgeBase::Answer.where(category_id: self_with_children_ids)
  57. end
  58. def self_with_children_ids
  59. output = [id]
  60. output << KnowledgeBase::Category.where(parent_id: output.last).pluck(:id) while output.last.present?
  61. output.flatten
  62. end
  63. def full_destroy!
  64. transaction do
  65. answers.each(&:destroy!)
  66. answers.reset
  67. children.reset
  68. destroy!
  69. end
  70. end
  71. def public_content?(kb_locale = nil)
  72. scope = self_with_children_answers.published
  73. scope = scope.localed(kb_locale.system_locale) if kb_locale
  74. scope.any?
  75. end
  76. def internal_content?(kb_locale = nil)
  77. scope = self_with_children_answers.internal
  78. scope = scope.localed(kb_locale.system_locale) if kb_locale
  79. scope.any?
  80. end
  81. def visible?(kb_locale = nil)
  82. public_content?(kb_locale)
  83. end
  84. def api_url
  85. Rails.application.routes.url_helpers.knowledge_base_category_path(knowledge_base, self)
  86. end
  87. def permissions_effective
  88. cache_key = KnowledgeBase::Permission.cache_key self
  89. Rails.cache.fetch cache_key do
  90. KnowledgeBase::Category::Permission.new(self).permissions_effective
  91. end
  92. end
  93. def attributes_with_association_ids
  94. attrs = super
  95. attrs[:permissions_effective] = permissions_effective
  96. attrs
  97. end
  98. private
  99. def cannot_be_child_of_parent
  100. errors.add(:parent_id, __('cannot be a subcategory of the parent category')) if self_parent?(self)
  101. end
  102. def sibling_categories
  103. parent&.children || knowledge_base.categories.root
  104. end
  105. end