diff --git a/audit/audit.go b/audit/audit.go index 319083bc474ce03368a657dbab906a3ea7c8666d..6780cba7ad1b0e6a7c45a1be26ba546b254ad885 100644 --- a/audit/audit.go +++ b/audit/audit.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors" + "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/logs" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/number_utils" "reflect" "regexp" @@ -39,6 +40,10 @@ func VerifyAuditEvents(original interface{}, new interface{}) error { } func GetChanges(original interface{}, new interface{}) (map[string]interface{}, error) { + // Clean audit events + cleanStruct(original) + cleanStruct(new) + changes := map[string]interface{}{} changelog, err := diff.Diff(original, new) if err != nil { @@ -128,6 +133,70 @@ func GetChanges(original interface{}, new interface{}) (map[string]interface{}, return changes, nil } + +func cleanStruct(object interface{}) interface{} { + defer func() { + if err := recover(); err != nil { + logs.ErrorMsg(fmt.Sprintf("audit event panic: %+v", err)) + } + }() + + // If the object is empty, we have nothing to do + if object == nil { + return object + } + + // Convert the object to a pointer + if reflect.ValueOf(object).Kind() != reflect.Ptr { + val := reflect.ValueOf(object) + // Create a new pointer to a new value of the type of the object + ptr := reflect.New(reflect.TypeOf(object)) + // Set the newly created pointer to point to the object + ptr.Elem().Set(val) + // Overwrite the original object + object = ptr.Interface() + } + + // Get the value of the object + val := reflect.ValueOf(object) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + + // We can only clean structs + if val.Kind() != reflect.Struct { + return object + } + + // Loop through the field tags to see if we should include the related object or not. + // We default to exclude, unless specified to include + for i := 0; i < val.NumField(); i++ { + fieldVal := val.Field(i) + structField := val.Type().Field(i) + + // Determine whether the field should be included or excluded + value, _ := structField.Tag.Lookup("audit") + shouldIncludeForAudit := value == "true" + shouldExcludeForAudit := value == "false" + + // If the audit tag is present and specified to 'true', we should always include the relation + if shouldIncludeForAudit { + continue + } + + // By default, all bun relations are excluded + isBunRelationField := strings.Contains(structField.Tag.Get("bun"), "rel:") + if shouldExcludeForAudit || isBunRelationField { + if fieldVal.CanSet() { + // Set the field to its zero value (nil for pointers) + fieldVal.Set(reflect.Zero(fieldVal.Type())) + } + } + } + + return object +} + func ChildObjectChanges(changes map[string]interface{}, objectPath string, fieldPath string, changeFrom interface{}, changeTo interface{}) { objectKey := ToSnakeCase(objectPath)