zammad/zammad

View on GitHub
app/models/concerns/checks_human_changes.rb

Summary

Maintainability
A
0 mins
Test Coverage
# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/

module ChecksHumanChanges
  extend ActiveSupport::Concern

  def human_changes(record_changes, record, user = nil)
    return {} if record_changes.blank?

    locale = user.try(:locale) || Setting.get('locale_default') || 'en-us'
    attribute_list = allowed_attributes(record.class.name, user)
    user_related_changes = user_changes(record_changes, attribute_list)

    readable_changes(record, user_related_changes, attribute_list, locale)
  end

  private

  def allowed_attributes(object, user)
    ObjectManager::Object.new(object).attributes(user, skip_permission: user.nil?).index_by { |item| item[:name] }
  end

  def user_changes(record_changes, attribute_list)
    user_related_changes = {}
    record_changes.each do |key, value|
      # If no config exists, use all attributes or if config exists, just use
      # existing attributes for user
      if attribute_list.blank? || attribute_list[key.to_s]
        user_related_changes[key] = value
      end
    end
    user_related_changes
  end

  def readable_changes(record, user_related_changes, attribute_list, locale)
    changes = {}
    user_related_changes.each do |key, value|
      is_relation_field = key.to_s.end_with?('_id')

      attribute_name = attribute_name(is_relation_field, key)

      if is_relation_field
        value = id_to_relation_value(record, attribute_name, value)
      end

      attribute = attribute_list&.dig(key.to_s)
      display = display_name(attribute) || attribute_name
      changes[display] = display_value(locale, value, attribute)
    end

    changes
  end

  def attribute_name(is_relation_field, key)
    attribute_name = key.to_s

    return attribute_name[0..-4] if is_relation_field

    attribute_name
  end

  def id_to_relation_value(record, attribute_name, value)
    relation_class = record.public_send(attribute_name)&.class
    value.map do |id|
      next id if !relation_class

      relation_model_visible_value(relation_class, id)
    end
  end

  def relation_model_visible_value(relation_class, id)
    relation_model = relation_class.lookup(id: id)
    return id.to_s if !relation_model

    return relation_model['name'] if relation_model['name']
    return relation_model.fullname if relation_model.respond_to?(:fullname)

    id
  end

  def display_name(attribute)
    return attribute[:display].to_s if attribute && attribute[:display]

    nil
  end

  def display_value(locale, value, attribute)
    if attribute && attribute[:translate]
      return [Translation.translate(locale, value[0]), Translation.translate(locale, value[1])]
    end

    [value[0].to_s, value[1].to_s]
  end

end