list.rb 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. # Create a list of history events for a given object.
  3. #
  4. # An entry in the list contains the following information:
  5. # - created_at: The timestamp when the event was created.
  6. # - issuer: The issuer who created the event.
  7. # - action: The type of the event.
  8. # - object: The object the event is related to.
  9. # - attribute: The attribute of the object that was changed.
  10. # - changes: The changes that were made to the attribute.
  11. #
  12. # The object and issuer attributes contain a pseudo object if the related
  13. # object doesn't exist anymore with the following information:
  14. # - klass: The name of the object's class.
  15. # - info: Additional information about the object.
  16. #
  17. # Example:
  18. #
  19. # Service::History::List.new(current_user:).execute(object: ticket)
  20. # # => [
  21. # # {
  22. # # created_at: ActiveRecord::DateTime,
  23. # # issuer: User,
  24. # # action: 'created',
  25. # # object: Ticket,
  26. # # attribute: nil,
  27. # # changes: { from: nil, to: nil }
  28. # # },
  29. # # {
  30. # # created_at: ActiveRecord::DateTime,
  31. # # issuer: User,
  32. # # action: 'created',
  33. # # object: Ticket::Article,
  34. # # attribute: nil,
  35. # # changes: { from: nil, to: nil }
  36. # # {
  37. # # created_at: ActiveRecord::DateTime,
  38. # # issuer: PostmasterFilter,
  39. # # action: 'updated',
  40. # # object: Ticket,
  41. # # attribute: 'title',
  42. # # changes: { from: 'Old title', to: 'New title' }
  43. # # }
  44. # # ]
  45. class Service::History::List < Service::BaseWithCurrentUser
  46. include Service::History::Concerns::FixEventObject
  47. def execute(object:)
  48. @object = object
  49. Pundit.authorize(current_user, object, :show?)
  50. raise __('Object does not support history') if !object.class.const_defined?(:HasHistory)
  51. fetch_list(object)
  52. end
  53. private
  54. def fetch_list(object)
  55. History.list(
  56. object.class.name,
  57. object.id,
  58. object.history_relation_object,
  59. raw: true
  60. ).map { |entry| event(entry) }
  61. end
  62. def event(entry)
  63. event = {
  64. created_at: entry.created_at,
  65. issuer: issuer(entry),
  66. action: entry.history_type.name,
  67. object: object(entry),
  68. attribute: entry.history_attribute&.name,
  69. changes: changes(entry),
  70. }
  71. fix_event_object(event, entry)
  72. event
  73. end
  74. def issuer(entry)
  75. if entry.sourceable_type.present?
  76. klass = entry.sourceable_type.constantize
  77. klass.find(entry.sourceable_id)
  78. else
  79. User.find(entry.created_by_id)
  80. end
  81. rescue ActiveRecord::RecordNotFound
  82. {
  83. klass: entry.sourceable_type.presence || 'User',
  84. info: entry.sourceable_name.presence
  85. }
  86. end
  87. def object(entry)
  88. return { klass: entry.history_object.name } if entry.history_object.name == @object.class.name && entry.o_id == @object.id
  89. begin
  90. klass = entry.history_object.name.constantize
  91. klass.find(entry.o_id)
  92. rescue ActiveRecord::RecordNotFound
  93. { klass: entry.history_object.name }
  94. end
  95. end
  96. def changes(entry)
  97. {
  98. from: entry.value_from,
  99. to: entry.value_to
  100. }
  101. end
  102. end