can_priorization.rb 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. module CanPriorization
  3. extend ActiveSupport::Concern
  4. included do
  5. before_create :fill_prio
  6. before_update :rearrangement
  7. end
  8. def rearrangement
  9. # rearrange only in case of changed prio
  10. return true if !changes['prio']
  11. rearranged_prio = 0
  12. rearrangement_previous_ordered_ids.each do |entry_id|
  13. # don't process currently updated entry
  14. next if id == entry_id
  15. rearranged_prio += 1
  16. # increase rearranged prio by one to avoid a collition
  17. # with the changed prio of current instance
  18. if rearranged_prio == prio
  19. rearranged_prio += 1
  20. end
  21. rearrange_entry(entry_id, rearranged_prio)
  22. end
  23. end
  24. def fill_prio
  25. return true if prio.present?
  26. self.prio = self.class.calculate_prio
  27. true
  28. end
  29. def rearrangement_previous_ordered_ids
  30. self.class.reorder(
  31. prio: :asc,
  32. updated_at: :desc
  33. ).pluck(:id)
  34. end
  35. def rearrange_entry(id, prio)
  36. # don't start rearranging logic for entrys that have already been rearranged
  37. self.class.without_callback(:update, :before, :rearrangement) do
  38. # fetch and update entry only if prio needs to change
  39. entry = self.class.where(
  40. id: id
  41. ).where.not(
  42. prio: prio
  43. ).take
  44. next if entry.blank?
  45. entry.update!(prio: prio)
  46. end
  47. end
  48. # methods defined here are going to extend the class, not the instance of it
  49. class_methods do
  50. def calculate_prio
  51. existing_maximum = maximum(:prio)
  52. return 0 if !existing_maximum
  53. existing_maximum + 1
  54. end
  55. end
  56. end