Is it possible to add Tags to audit log?

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?

Parents
  • 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

Reply
  • 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

Children