taskbar.rb 3.6 KB

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