aeolus-incubator/tim

View on GitHub
app/filters/tim/user_keys_filter.rb

Summary

Maintainability
A
1 hr
Test Coverage
# FIXME Remove replace_user_keys(map) once support for custom XML with nested
# resources is supported.

module Tim
  class UserKeysFilter

    @@user_keys = YAML.load(File.read(File.join(Tim::Engine.root, "config", "user_keys.yml")))

    def self.before(controller)
      if controller.request.format == "application/xml"
        begin
          @controller = controller
          resource_name = @controller.controller_name.singularize.to_sym
          set_template_params(resource_name)
          @controller.params[resource_name] = replace_user_keys(@controller.params[resource_name], @@user_keys[resource_name])
        rescue => e
          @controller.head :unprocessable_entity
        end
      end
    end

    # Replaces all instances of user keys with those defined in @@user_keys
    # Supports N levels of nested maps.
    def self.replace_user_keys(map, user_keys)
      modified_map = map.clone
      map.each_pair do |key, value|
        # Sets the full template XML in the template.xml attribute
        if key == "template" || key == :template
          modified_map[key] = { :xml => template_xml }
        end

        if user_keys.has_key? key
          if map[key].instance_of? Hash
            # FIXME Using recursion in this way increases heap memory usage.
            # If we decide to stick with this approach a more memory efficient
            # implementation should be considered.
            modified_map[key] = replace_user_keys(map[key], user_keys)
          elsif map[key].instance_of? Array
            modified_map[key] = map[key].collect { |v| replace_user_keys(v, user_keys)}
          end
          modified_map[user_keys[key]] = modified_map.delete(key)
        end
      end
      modified_map
    end

    # We are storing raw XML in the templates.xml attributes.  Therefore we
    # must retrieve the raw XML from the request body.
    def self.set_template_params(resource_name)
      if resource_name == :template
        @controller.params[:template] = { :xml => template_xml }
      end
    end

    def self.template_xml
      ::Nokogiri::XML(@controller.request.body.read).xpath("//template").to_xml
    end
  end
end