taskbar.rb 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. # Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. class Taskbar < ApplicationModel
  3. include ChecksClientNotification
  4. include ::Taskbar::HasAttachments
  5. include Taskbar::Assets
  6. include Taskbar::TriggersSubscriptions
  7. include Taskbar::List
  8. include Taskbar::Validator
  9. TASKBAR_APPS = %w[desktop mobile].freeze
  10. TASKBAR_ENTITIES = %w[
  11. OrganizationProfile
  12. Search
  13. TicketCreate
  14. TicketZoom
  15. UserProfile
  16. ].freeze
  17. store :state
  18. store :params
  19. store :preferences
  20. belongs_to :user
  21. validates :app, inclusion: { in: TASKBAR_APPS }
  22. before_create :update_last_contact, :set_user, :update_preferences_infos
  23. before_update :update_last_contact, :set_user, :update_preferences_infos
  24. after_update :notify_clients
  25. after_destroy :update_preferences_infos, :notify_clients
  26. after_commit :update_related_taskbars
  27. association_attributes_ignored :user
  28. client_notification_events_ignored :create, :update, :touch
  29. client_notification_send_to :user_id
  30. attr_accessor :local_update
  31. default_scope { order(:id) }
  32. scope :related_taskbars, lambda { |taskbar|
  33. where(key: taskbar.key)
  34. .where.not(id: taskbar.id)
  35. }
  36. def state_changed?
  37. return false if state.blank?
  38. state.each_value do |value|
  39. if value.is_a? Hash
  40. value.each do |key1, value1|
  41. next if value1.blank?
  42. next if key1 == 'form_id'
  43. return true
  44. end
  45. else
  46. next if value.blank?
  47. return true
  48. end
  49. end
  50. false
  51. end
  52. def attributes_with_association_names(empty_keys: false)
  53. add_attachments_to_attributes(super)
  54. end
  55. def attributes_with_association_ids
  56. add_attachments_to_attributes(super)
  57. end
  58. def as_json(options = {})
  59. add_attachments_to_attributes(super)
  60. end
  61. def preferences_task_info
  62. output = { user_id:, apps: { app.to_sym => { last_contact: last_contact, changed: state_changed? } } }
  63. output[:id] = id if persisted?
  64. output
  65. end
  66. def related_taskbars
  67. self.class.related_taskbars(self)
  68. end
  69. def touch_last_contact!
  70. # Don't inform the current user (only!) about live user and item updates.
  71. self.skip_live_user_trigger = true
  72. self.skip_item_trigger = true
  73. self.last_contact = Time.zone.now
  74. save!
  75. end
  76. def collect_related_tasks
  77. related_taskbars.map(&:preferences_task_info)
  78. .tap { |arr| arr.push(preferences_task_info) if !destroyed? }
  79. .each_with_object({}) { |elem, memo| reduce_related_tasks(elem, memo) }
  80. .values
  81. .sort_by { |elem| elem[:id] || Float::MAX } # sort by IDs to pass old tests
  82. end
  83. private
  84. def update_last_contact
  85. return true if local_update
  86. return true if changes.blank?
  87. if changes['notify']
  88. count = 0
  89. changes.each_key do |attribute|
  90. next if attribute == 'updated_at'
  91. next if attribute == 'created_at'
  92. count += 1
  93. end
  94. return true if count <= 1
  95. end
  96. self.last_contact = Time.zone.now
  97. end
  98. def set_user
  99. return true if local_update
  100. return true if !UserInfo.current_user_id
  101. self.user_id = UserInfo.current_user_id
  102. end
  103. def update_preferences_infos
  104. return if key == 'Search'
  105. return if local_update
  106. return if changed_only_prio?
  107. preferences = self.preferences || {}
  108. preferences[:tasks] = collect_related_tasks
  109. # remember preferences for current taskbar
  110. self.preferences = preferences if !destroyed?
  111. end
  112. def changed_only_prio?
  113. changed_attribute_names_to_save.to_set == Set.new(%w[updated_at prio])
  114. end
  115. def reduce_related_tasks(elem, memo)
  116. key = elem[:user_id]
  117. if memo[key]
  118. memo[key].deep_merge! elem
  119. return
  120. end
  121. memo[key] = elem
  122. end
  123. def update_related_taskbars
  124. return if key == 'Search'
  125. return if local_update
  126. return if changed_only_prio?
  127. TaskbarUpdateRelatedTasksJob.perform_later(related_taskbars.map(&:id))
  128. end
  129. def notify_clients
  130. return true if !saved_change_to_attribute?('preferences')
  131. data = {
  132. event: 'taskbar:preferences',
  133. data: {
  134. id: id,
  135. key: key,
  136. preferences: preferences,
  137. },
  138. }
  139. PushMessages.send_to(
  140. user_id,
  141. data,
  142. )
  143. end
  144. end