We're having an issue with some users removing tags from records. Since Tags are a related object and not a field, I'm not sure if or how it's possible to audit those changes.
Has anyone had this request/issue and what was your solution?
We're having an issue with some users removing tags from records. Since Tags are a related object and not a field, I'm not sure if or how it's possible to audit those changes.
Has anyone had this request/issue and what was your solution?
NOTE: This code was written for this post and barely tested, needs work.
A Tag is, at its lowest level, a relationship between the Tags Module and the module you are tagging (an entry in tag_bean_rel)
This means that you can leverage the before/after relationship add/delete logic hooks to add entries to the Audit Log.
in custom/modules/Tags/logic_hooks.php
$hook_version = 1; $hook_array = Array(); $hook_array['after_relationship_add'][] = Array(0, 'tag_added_audit_log', 'custom/modules/Tags/TagsLogic.php','TagsLogic', 'tag_added_audit_log'); $hook_array['after_relationship_delete'][] = Array(0, 'tag_removed_audit_log', 'custom/modules/Tags/TagsLogic.php','TagsLogic', 'tag_removed_audit_log');
You need two functions, one for each of the events (add/remove) but they are essentially identical except I set:
for the ADD:
before value = ''
after value = the tag
for the REMOVE
before value = the tag
after value = ''
<?php class TagsLogic { //call after relationship add function tag_added_audit_log ($bean,$event,$arguments) { global $db; $module = $arguments['related_module']; $bean_id = $arguments['related_id']; $parentBean = BeanFactory::retrieveBean($module, $bean_id); if(!empty($parentBean) && $db->tableExists($parentBean->get_audit_table_name())) { $changes = array( 'field_name' => 'Tags', 'data_type' => 'tag', 'before' => '', 'after' => $bean->name, ); $sql = $bean->auditSQL($parentBean, $changes, ''); $db->query($bean->auditSQL($parentBean, $changes, '')); } } //call after relationship delete function tag_removed_audit_log ($bean,$event,$arguments) { global $db; $module = $arguments['related_module']; $bean_id = $arguments['related_id']; $parentBean = BeanFactory::retrieveBean($module, $bean_id); if(!empty($parentBean) && $db->tableExists($parentBean->get_audit_table_name())) { $changes = array( 'field_name' => 'Tags', 'data_type' => 'tag', 'before' => $bean->name, 'after' => '', ); $sql = $bean->auditSQL($parentBean, $changes, ''); $db->query($bean->auditSQL($parentBean, $changes, '')); } } }
By putting the logic hook on the side of the Tags module it triggers for all tags on any module using tags and it puts the audit in that module's audit table IF an audit table exists.
NOTE: even though in the back end the query is correctly setting the current_user_id for the person who made the change, it is not showing in the audit log. I suspect this is because I left out the event_id
Check data/SugarBean.php you will see that the public function auditSQL(SugarBean $bean, $changes, $event_id) expects an event_id.
Based on the post by Harald here: What is the event_id for? you may need to figure out how to add a properly formatted audit_events record to link to the audit table, I suspect it is using some information from that event to populate that column.
in audit_event.source I see things like:
'{"subject":{"_type":"user","id":"3341c0ac-cbf5-7ee0-4df2-5419adf1b88b","_module":"Users","client":{"_type":"rest-api"}},"attributes":{"platform":"base"}}'
and
'{"subject":{"_type":"logic-hook","class":"UpdateLog","method":"update_log","label":null},"attributes":[]}'
Make sure you do a QRR after adding the code, and make sure to test it thoroughly, I'm NOT using this code, I wrote it tonight for you and briefly tested to make sure it works.
What can I say, I like puzzles :)
Hope this helps
FrancescaS
NOTE: This code was written for this post and barely tested, needs work.
A Tag is, at its lowest level, a relationship between the Tags Module and the module you are tagging (an entry in tag_bean_rel)
This means that you can leverage the before/after relationship add/delete logic hooks to add entries to the Audit Log.
in custom/modules/Tags/logic_hooks.php
$hook_version = 1; $hook_array = Array(); $hook_array['after_relationship_add'][] = Array(0, 'tag_added_audit_log', 'custom/modules/Tags/TagsLogic.php','TagsLogic', 'tag_added_audit_log'); $hook_array['after_relationship_delete'][] = Array(0, 'tag_removed_audit_log', 'custom/modules/Tags/TagsLogic.php','TagsLogic', 'tag_removed_audit_log');
You need two functions, one for each of the events (add/remove) but they are essentially identical except I set:
for the ADD:
before value = ''
after value = the tag
for the REMOVE
before value = the tag
after value = ''
<?php class TagsLogic { //call after relationship add function tag_added_audit_log ($bean,$event,$arguments) { global $db; $module = $arguments['related_module']; $bean_id = $arguments['related_id']; $parentBean = BeanFactory::retrieveBean($module, $bean_id); if(!empty($parentBean) && $db->tableExists($parentBean->get_audit_table_name())) { $changes = array( 'field_name' => 'Tags', 'data_type' => 'tag', 'before' => '', 'after' => $bean->name, ); $sql = $bean->auditSQL($parentBean, $changes, ''); $db->query($bean->auditSQL($parentBean, $changes, '')); } } //call after relationship delete function tag_removed_audit_log ($bean,$event,$arguments) { global $db; $module = $arguments['related_module']; $bean_id = $arguments['related_id']; $parentBean = BeanFactory::retrieveBean($module, $bean_id); if(!empty($parentBean) && $db->tableExists($parentBean->get_audit_table_name())) { $changes = array( 'field_name' => 'Tags', 'data_type' => 'tag', 'before' => $bean->name, 'after' => '', ); $sql = $bean->auditSQL($parentBean, $changes, ''); $db->query($bean->auditSQL($parentBean, $changes, '')); } } }
By putting the logic hook on the side of the Tags module it triggers for all tags on any module using tags and it puts the audit in that module's audit table IF an audit table exists.
NOTE: even though in the back end the query is correctly setting the current_user_id for the person who made the change, it is not showing in the audit log. I suspect this is because I left out the event_id
Check data/SugarBean.php you will see that the public function auditSQL(SugarBean $bean, $changes, $event_id) expects an event_id.
Based on the post by Harald here: What is the event_id for? you may need to figure out how to add a properly formatted audit_events record to link to the audit table, I suspect it is using some information from that event to populate that column.
in audit_event.source I see things like:
'{"subject":{"_type":"user","id":"3341c0ac-cbf5-7ee0-4df2-5419adf1b88b","_module":"Users","client":{"_type":"rest-api"}},"attributes":{"platform":"base"}}'
and
'{"subject":{"_type":"logic-hook","class":"UpdateLog","method":"update_log","label":null},"attributes":[]}'
Make sure you do a QRR after adding the code, and make sure to test it thoroughly, I'm NOT using this code, I wrote it tonight for you and briefly tested to make sure it works.
What can I say, I like puzzles :)
Hope this helps
FrancescaS
Hi Francesca,
Thanks for that idea! I'll have to share that with my admin and see if that's something that we could look further into.