2017-01-31 17:13:45 +00:00
|
|
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
2017-05-02 15:21:13 +00:00
|
|
|
module HasHistory
|
2017-01-31 17:13:45 +00:00
|
|
|
extend ActiveSupport::Concern
|
|
|
|
|
|
|
|
included do
|
|
|
|
attr_accessor :history_changes_last_done
|
|
|
|
|
|
|
|
after_create :history_create
|
|
|
|
after_update :history_update
|
|
|
|
after_destroy :history_destroy
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
log object create history, if configured - will be executed automatically
|
|
|
|
|
|
|
|
model = Model.find(123)
|
|
|
|
model.history_create
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def history_create
|
|
|
|
history_log('created', created_by_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
log object update history with all updated attributes, if configured - will be executed automatically
|
|
|
|
|
|
|
|
model = Model.find(123)
|
|
|
|
model.history_update
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def history_update
|
2017-09-23 06:25:55 +00:00
|
|
|
return if !saved_changes?
|
2017-01-31 17:13:45 +00:00
|
|
|
|
|
|
|
# return if it's no update
|
|
|
|
return if new_record?
|
|
|
|
|
|
|
|
# new record also triggers update, so ignore new records
|
2017-09-23 06:25:55 +00:00
|
|
|
changes = saved_changes
|
2017-11-23 08:09:44 +00:00
|
|
|
history_changes_last_done&.each do |key, value|
|
|
|
|
if changes.key?(key) && changes[key] == value
|
|
|
|
changes.delete(key)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-01-31 17:13:45 +00:00
|
|
|
end
|
|
|
|
self.history_changes_last_done = changes
|
|
|
|
#logger.info 'updated ' + self.changes.inspect
|
|
|
|
|
|
|
|
return if changes['id'] && !changes['id'][0]
|
|
|
|
|
|
|
|
ignored_attributes = self.class.instance_variable_get(:@history_attributes_ignored) || []
|
2017-11-23 08:09:44 +00:00
|
|
|
ignored_attributes += %i[created_at updated_at created_by_id updated_by_id]
|
2017-01-31 17:13:45 +00:00
|
|
|
|
2017-10-01 12:25:52 +00:00
|
|
|
changes.each do |key, value|
|
2017-01-31 17:13:45 +00:00
|
|
|
|
|
|
|
next if ignored_attributes.include?(key.to_sym)
|
|
|
|
|
|
|
|
# get attribute name
|
|
|
|
attribute_name = key.to_s
|
|
|
|
if attribute_name[-3, 3] == '_id'
|
|
|
|
attribute_name = attribute_name[ 0, attribute_name.length - 3 ]
|
|
|
|
end
|
|
|
|
|
|
|
|
value_id = []
|
|
|
|
value_str = [ value[0], value[1] ]
|
|
|
|
if key.to_s[-3, 3] == '_id'
|
|
|
|
value_id[0] = value[0]
|
|
|
|
value_id[1] = value[1]
|
|
|
|
|
|
|
|
if respond_to?(attribute_name) && send(attribute_name)
|
|
|
|
relation_class = send(attribute_name).class
|
|
|
|
if relation_class && value_id[0]
|
|
|
|
relation_model = relation_class.lookup(id: value_id[0])
|
|
|
|
if relation_model
|
|
|
|
if relation_model['name']
|
|
|
|
value_str[0] = relation_model['name']
|
|
|
|
elsif relation_model.respond_to?('fullname')
|
|
|
|
value_str[0] = relation_model.send('fullname')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if relation_class && value_id[1]
|
|
|
|
relation_model = relation_class.lookup(id: value_id[1])
|
|
|
|
if relation_model
|
|
|
|
if relation_model['name']
|
|
|
|
value_str[1] = relation_model['name']
|
|
|
|
elsif relation_model.respond_to?('fullname')
|
|
|
|
value_str[1] = relation_model.send('fullname')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
data = {
|
|
|
|
history_attribute: attribute_name,
|
2018-12-19 17:31:51 +00:00
|
|
|
value_from: value_str[0].to_s,
|
|
|
|
value_to: value_str[1].to_s,
|
|
|
|
id_from: value_id[0],
|
|
|
|
id_to: value_id[1],
|
2017-01-31 17:13:45 +00:00
|
|
|
}
|
|
|
|
#logger.info "HIST NEW #{self.class.to_s}.find(#{self.id}) #{data.inspect}"
|
|
|
|
history_log('updated', updated_by_id, data)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-01-31 17:13:45 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
delete object history, will be executed automatically
|
|
|
|
|
|
|
|
model = Model.find(123)
|
|
|
|
model.history_destroy
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def history_destroy
|
|
|
|
History.remove(self.class.to_s, id)
|
|
|
|
end
|
|
|
|
|
2017-05-02 15:21:13 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
create history entry for this object
|
|
|
|
|
|
|
|
organization = Organization.find(123)
|
|
|
|
result = organization.history_log('created', user_id)
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
result = true # false
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def history_log(type, user_id, attributes = {})
|
|
|
|
|
|
|
|
attributes.merge!(
|
|
|
|
o_id: self['id'],
|
|
|
|
history_type: type,
|
|
|
|
history_object: self.class.name,
|
|
|
|
related_o_id: nil,
|
|
|
|
related_history_object: nil,
|
|
|
|
created_by_id: user_id,
|
|
|
|
updated_at: updated_at,
|
|
|
|
created_at: updated_at,
|
|
|
|
).merge!(history_log_attributes)
|
|
|
|
|
|
|
|
History.add(attributes)
|
|
|
|
end
|
|
|
|
|
|
|
|
# callback function to overwrite
|
|
|
|
# default history log attributes
|
|
|
|
# gets called from history_log
|
|
|
|
def history_log_attributes
|
|
|
|
{}
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
get history log for this object
|
|
|
|
|
|
|
|
organization = Organization.find(123)
|
|
|
|
result = organization.history_get()
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
result = [
|
|
|
|
{
|
|
|
|
:type => 'created',
|
|
|
|
:object => 'Organization',
|
|
|
|
:created_by_id => 3,
|
|
|
|
:created_at => "2013-08-19 20:41:33",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
:type => 'updated',
|
|
|
|
:object => 'Organization',
|
|
|
|
:attribute => 'note',
|
|
|
|
:o_id => 1,
|
|
|
|
:id_to => nil,
|
|
|
|
:id_from => nil,
|
|
|
|
:value_from => "some note",
|
|
|
|
:value_to => "some other note",
|
|
|
|
:created_by_id => 3,
|
|
|
|
:created_at => "2013-08-19 20:41:33",
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
|
|
|
to get history log for this object with all assets
|
|
|
|
|
|
|
|
organization = Organization.find(123)
|
|
|
|
result = organization.history_get(true)
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
result = {
|
|
|
|
:history => [
|
|
|
|
{ ... },
|
|
|
|
{ ... },
|
|
|
|
],
|
|
|
|
:assets => {
|
|
|
|
...
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def history_get(fulldata = false)
|
|
|
|
if !fulldata
|
|
|
|
return History.list(self.class.name, self['id'])
|
|
|
|
end
|
|
|
|
|
|
|
|
# get related objects
|
|
|
|
history = History.list(self.class.name, self['id'], nil, true)
|
2017-10-01 12:25:52 +00:00
|
|
|
history[:list].each do |item|
|
2017-05-02 15:21:13 +00:00
|
|
|
record = Kernel.const_get(item['object']).find(item['o_id'])
|
|
|
|
|
|
|
|
history[:assets] = record.assets(history[:assets])
|
|
|
|
|
|
|
|
if item['related_object']
|
|
|
|
record = Kernel.const_get(item['related_object']).find(item['related_o_id'])
|
|
|
|
history[:assets] = record.assets(history[:assets])
|
|
|
|
end
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-05-02 15:21:13 +00:00
|
|
|
{
|
|
|
|
history: history[:list],
|
2018-12-19 17:31:51 +00:00
|
|
|
assets: history[:assets],
|
2017-05-02 15:21:13 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2017-01-31 17:13:45 +00:00
|
|
|
# methods defined here are going to extend the class, not the instance of it
|
|
|
|
class_methods do
|
|
|
|
=begin
|
|
|
|
|
|
|
|
serve methode to ignore model attributes in historization
|
|
|
|
|
|
|
|
class Model < ApplicationModel
|
2017-05-02 15:21:13 +00:00
|
|
|
include HasHistory
|
2017-01-31 17:13:45 +00:00
|
|
|
history_attributes_ignored :create_article_type_id, :preferences
|
|
|
|
end
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def history_attributes_ignored(*attributes)
|
|
|
|
@history_attributes_ignored = attributes
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|