123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- module CanBePublished
- extend ActiveSupport::Concern
- def can_be_published_aasm
- @can_be_published_aasm ||= StateMachine.new(self)
- end
- def visible?
- can_be_published_aasm.published?
- end
- def visible_internally?
- can_be_published_aasm.internal? || visible?
- end
- class_methods do
- def inverse_relation_name(scope_name)
- "can_be_published_#{scope_name}_#{model_name.plural}"
- end
- end
- included do
- validate :archived_after_internal
- validate :archived_after_published
- validate :published_after_internal
- before_save :update_user_references
- after_save :schedule_touch
- after_save :update_active_publicly
- after_destroy :update_active_publicly
- after_touch :update_active_publicly
- %i[archived published internal].each do |scope_name|
- local = :"#{scope_name}_by"
- remote = inverse_relation_name(scope_name).to_sym
- belongs_to local, class_name: 'User', inverse_of: remote, optional: true
- # Deletion of users is handled in User.destroy_move_dependency_ownership and resets fields to user_id: 1, so skip dependent: here.
- User.has_many remote, class_name: model_name, inverse_of: local, foreign_key: "#{local}_id" # rubocop:disable Rails/HasManyOrHasOneDependent
- User.association_attributes_ignored remote
- end
- scope :published, lambda {
- timestamp = Time.zone.now
- date_earlier(:published_at, timestamp).date_later_or_nil(:archived_at, timestamp)
- }
- scope :archived, lambda {
- timestamp = Time.zone.now
- date_earlier(:archived_at, timestamp)
- }
- scope :only_internal, lambda {
- timestamp = Time.zone.now
- date_earlier(:internal_at, timestamp)
- .date_later_or_nil(:archived_at, timestamp)
- .date_later_or_nil(:published_at, timestamp)
- }
- scope :internal, lambda {
- timestamp = Time.zone.now
- internal = arel_table[:internal_at].lt(timestamp)
- published = arel_table[:published_at].lt(timestamp)
- where(internal.or(published))
- .date_later_or_nil(:archived_at, timestamp)
- }
- scope :date_earlier, lambda { |field, timestamp|
- where arel_table[field].lt(timestamp)
- }
- scope :date_later_or_nil, lambda { |field, timestamp|
- where arel_table[field].gt(timestamp).or(arel_table[field].eq(nil))
- }
- end
- def update_user_references
- return if can_be_published_aasm.aasm.current_event.present? # state machine is handling it
- %i[archived internal published].each do |scope_name|
- update_user_reference_item(scope_name)
- end
- end
- def update_user_reference_item(scope_name)
- return if !send(:"#{scope_name}_at_changed?")
- send(:"#{scope_name}_by_id=", UserInfo.current_user_id)
- end
- def archived_after_internal
- return if internal_at.nil? || archived_at.nil? || archived_at >= internal_at
- errors.add(:archived_at, __('date must be no earlier than internal date'))
- end
- def archived_after_published
- return if published_at.nil? || archived_at.nil? || archived_at >= published_at
- errors.add(:archived_at, __('date must be no earlier than published date'))
- end
- def published_after_internal
- return if published_at.nil? || internal_at.nil? || published_at >= internal_at
- errors.add(:published_at, __('date must be no earlier than internal date'))
- end
- def schedule_touch_for(attr)
- date = saved_changes[attr]&.last
- return if date.nil? || date <= Time.zone.now
- ScheduledTouchJob.touch_at(self, date)
- end
- def schedule_touch
- %i[published_at archived_at].each { |attr| schedule_touch_for(attr) }
- end
- def update_active_publicly
- CanBePublished.update_active_publicly!
- end
- def self.update_active_publicly!
- Setting.set('kb_active_publicly', active_publicly?)
- end
- def self.active_publicly?
- KnowledgeBase::Answer
- .published
- .joins(category: :knowledge_base)
- .exists?(knowledge_bases: { active: true })
- end
- end
|