Use Nokogiri::XML throughout FileResource

Removes Calligraphy::XML::Node and Calligraphy::XML::Namespace in favor
of using Nokogiri's XML classes.
This commit is contained in:
Brandon Robins
2018-01-25 22:29:15 -06:00
committed by Brandon Robins
parent 96116543d3
commit 6324f17f90
7 changed files with 83 additions and 85 deletions

View File

@@ -7,8 +7,6 @@ require 'calligraphy/rails/web_dav_requests_controller'
require 'calligraphy/xml/web_dav_elements' require 'calligraphy/xml/web_dav_elements'
require 'calligraphy/xml/builder' require 'calligraphy/xml/builder'
require 'calligraphy/xml/namespace'
require 'calligraphy/xml/node'
require 'calligraphy/xml/utils' require 'calligraphy/xml/utils'
require 'calligraphy/utils' require 'calligraphy/utils'

View File

@@ -12,6 +12,7 @@ module Calligraphy
].freeze ].freeze
include Calligraphy::Utils include Calligraphy::Utils
include Calligraphy::XML::Utils
#:nodoc: #:nodoc:
def initialize(resource: nil, req: nil, mount: nil, root_dir: Dir.pwd) def initialize(resource: nil, req: nil, mount: nil, root_dir: Dir.pwd)
@@ -129,6 +130,7 @@ module Calligraphy
nodes.each do |node| nodes.each do |node|
next unless node.is_a? Nokogiri::XML::Element next unless node.is_a? Nokogiri::XML::Element
properties[node.name.to_sym] = node properties[node.name.to_sym] = node
end end
@@ -182,6 +184,7 @@ module Calligraphy
end end
end end
properties[:found] = properties[:found].uniq.flatten if properties[:found]
properties properties
end end
@@ -378,39 +381,46 @@ module Calligraphy
end end
def create_lock_token def create_lock_token
token = Calligraphy::XML::Node.new href = xml_node 'href'
token.name = 'locktoken' href.content = ['urn', 'uuid', SecureRandom.uuid].join ':'
href = Calligraphy::XML::Node.new token = xml_node 'locktoken'
href.name = 'href' token.add_child href
href.text = ['urn', 'uuid', SecureRandom.uuid].join ':' token.serialize
token.children = [href]
token
end end
def timeout_node def timeout_node
Calligraphy::XML::Node.new.tap do |node| node = xml_node 'timeout'
node.name = 'timeout' node.content = ['Second', Calligraphy.lock_timeout_period].join '-'
node.text = ['Second', Calligraphy.lock_timeout_period].join '-' node.serialize
end
end end
def add_lock_properties(activelock, properties) def add_lock_properties(activelock, properties)
properties.each_key do |prop| properties.each_key do |prop|
activelock[prop] = Calligraphy::XML::Node.new properties[prop] activelock[prop] = properties[prop].serialize
end end
end end
def fetch_lock_info def fetch_lock_info
return nil if @store.nil? return nil if @store.nil?
@lock_info = @store.transaction(true) { @store[:lockdiscovery] } @lock_info = @store.transaction(true) do
@store[:lockdiscovery]&.map do |lock_info|
lock_info.transform_values do |xml_fragment|
parse_serialized_fragment xml_fragment
end
end
end
@lock_info.nil? ? nil : map_array_of_hashes(@lock_info) @lock_info.nil? ? nil : map_array_of_hashes(@lock_info)
end end
def lockscope def lockscope
@lock_info[-1][:lockscope].children[0].name @lock_info[-1][:lockscope]
.children
.select { |x| x.is_a? Nokogiri::XML::Element }
.last
.name
end end
def can_unlock?(headers = nil) def can_unlock?(headers = nil)
@@ -423,7 +433,8 @@ module Calligraphy
def lock_tokens def lock_tokens
fetch_lock_info fetch_lock_info
@lock_info&.each { |x| x }&.map { |k| k[:locktoken].children[0].text }
@lock_info&.each { |x| x }&.map { |x| x[:locktoken].text.strip }
end end
def locking_ancestor?(ancestor_path, ancestors, headers = nil) def locking_ancestor?(ancestor_path, ancestors, headers = nil)
@@ -508,13 +519,11 @@ module Calligraphy
def get_property(prop) def get_property(prop)
case prop.name case prop.name
when 'lockdiscovery'
fetch_lock_info
when *DAV_PROPERTY_METHODS when *DAV_PROPERTY_METHODS
prop.content = send prop.name prop.content = send prop.name
prop prop
else else
get_custom_property prop.name get_custom_property prop.name, deserialize: true
end end
end end
@@ -562,8 +571,15 @@ module Calligraphy
JSON.generate [exclusive_write, shared_write] JSON.generate [exclusive_write, shared_write]
end end
def get_custom_property(prop) def get_custom_property(prop, deserialize: false)
@store_properties ||= @store.transaction(true) { @store[:properties] } @store_properties ||= @store.transaction(true) do
if deserialize
deserialize_stored_properties @store[:properties]
else
@store[:properties]
end
end
@store_properties[prop.to_sym] unless @store_properties.nil? || prop.nil? @store_properties[prop.to_sym] unless @store_properties.nil? || prop.nil?
end end
@@ -594,10 +610,9 @@ module Calligraphy
prop.children.each do |property| prop.children.each do |property|
next unless node.is_a? Nokogiri::XML::Element next unless node.is_a? Nokogiri::XML::Element
node = Calligraphy::XML::Node.new property
prop_sym = property.name.to_sym prop_sym = property.name.to_sym
store_property_node node, prop_sym store_property_node property.serialize, prop_sym
actions[:set].push property actions[:set].push property
end end
@@ -624,15 +639,18 @@ module Calligraphy
def store_mismatch_namespace_property_node(node, prop) def store_mismatch_namespace_property_node(node, prop)
node_arr = @store[:properties][prop] node_arr = @store[:properties][prop]
namespace_mismatch = node_arr.select do |x| namespace_mismatch = node_arr.select do |stored_node|
x.namespace.href == node.namespace.href same_namespace? stored_node, node
end.length.positive? end.length.positive?
@store[:properties][prop].push node unless namespace_mismatch @store[:properties][prop].push node unless namespace_mismatch
end end
def same_namespace?(node1, node2) def same_namespace?(node1, node2)
node1.namespace&.href == node2.namespace&.href node1_xml = parse_serialized_fragment node1
node2_xml = parse_serialized_fragment node2
node1_xml.namespace&.href == node2_xml.namespace&.href
end end
def store_mismatch_namespace_property_nodes(node, prop) def store_mismatch_namespace_property_nodes(node, prop)
@@ -669,7 +687,11 @@ module Calligraphy
ancestor_store.transaction do ancestor_store.transaction do
ancestor_store[:lockdiscovery][-1][:timeout] = timeout_node ancestor_store[:lockdiscovery][-1][:timeout] = timeout_node
ancestor_store[:lockdiscovery] ancestor_store[:lockdiscovery]&.map do |lock_info|
lock_info.transform_values do |xml_fragment|
parse_serialized_fragment xml_fragment
end
end
end end
end end
@@ -681,7 +703,7 @@ module Calligraphy
@store.delete :lockdiscovery @store.delete :lockdiscovery
else else
@store[:lockdiscovery] = @store[:lockdiscovery].reject do |activelock| @store[:lockdiscovery] = @store[:lockdiscovery].reject do |activelock|
activelock[:locktoken].children[0].text == token activelock[:locktoken].include? token
end end
end end
end end

View File

@@ -34,6 +34,8 @@ module Calligraphy
# Given an array of hashes, returns an array of hash values. # Given an array of hashes, returns an array of hash values.
def map_array_of_hashes(arr_hashes) def map_array_of_hashes(arr_hashes)
return if arr_hashes.nil?
[].tap do |output_array| [].tap do |output_array|
arr_hashes.each do |hash| arr_hashes.each do |hash|
output_array.push hash.values output_array.push hash.values

View File

@@ -71,8 +71,9 @@ module Calligraphy
def extract_lock_token(properties) def extract_lock_token(properties)
properties[-1] properties[-1]
.select { |x| x.name == 'locktoken' }[0] .select { |x| x.name == 'locktoken' }[0]
.children[0] .children
.text .text
.strip
end end
def prepare_response_headers(lock_token) def prepare_response_headers(lock_token)

View File

@@ -1,16 +0,0 @@
# frozen_string_literal: true
module Calligraphy
module XML
# Simple XML namespace, used to store a namespace's href and prefix values.
class Namespace
attr_accessor :href, :prefix
#:nodoc:
def initialize(namespace)
@href = namespace.href if namespace.href
@prefix = namespace.prefix if namespace.prefix
end
end
end
end

View File

@@ -1,36 +0,0 @@
# frozen_string_literal: true
module Calligraphy
module XML
# Simple XML node, used to store resource properties in Resource methods
# and later to create XML response bodies.
class Node
attr_accessor :children, :name, :namespace, :text
#:nodoc:
def initialize(node = nil)
return if node.nil?
@name = node.name
@text = node.text unless node.text.empty?
if node.namespace
@namespace = Calligraphy::XML::Namespace.new node.namespace
end
return unless node_has_children node
@children = []
node.children.each { |x| @children.push Calligraphy::XML::Node.new x }
end
private
def node_has_children(node)
return false if node.children.nil?
node.children.length.positive?
end
end
end
end

View File

@@ -26,6 +26,24 @@ module Calligraphy
end.flatten end.flatten
end end
# Parses a serialized string or array fragment to XML.
def parse_serialized_fragment(fragment)
xml_str = fragment.is_a?(Array) ? fragment.join : fragment
xml = Nokogiri::XML.fragment(xml_str).children
fragment.is_a?(Array) ? xml : xml[-1]
end
# Iterates through each property in `properties` hash and deserializes
# the property's value.
def deserialize_stored_properties(properties)
return if properties.nil?
properties.each_pair do |k, v|
properties[k] = parse_serialized_fragment v
end
end
# Iterates through top level nodes, finds node names that match and # Iterates through top level nodes, finds node names that match and
# separates matching nodes from non-matching nodes. # separates matching nodes from non-matching nodes.
def separate_nodes_by_name(nodes, match_name) def separate_nodes_by_name(nodes, match_name)
@@ -34,14 +52,19 @@ module Calligraphy
next unless node.is_a? Nokogiri::XML::Element next unless node.is_a? Nokogiri::XML::Element
if node.name == match_name if node.name == match_name
property[:found].push Calligraphy::XML::Node.new node property[:found].push node
else else
property[:not_found].push Calligraphy::XML::Node.new node property[:not_found].push node
end end
end end
end end
end end
# Creates a new instance of Nokogiri::XML::Node with a given name.
def xml_node(name)
Nokogiri::XML::Node.new name, dummy_doc
end
private private
def dav_namespace(xml) def dav_namespace(xml)
@@ -49,6 +72,10 @@ module Calligraphy
return v if v == Calligraphy::DAV_NS return v if v == Calligraphy::DAV_NS
end end
end end
def dummy_doc
Nokogiri::XML::Document.new
end
end end
end end
end end