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:
committed by
Brandon Robins
parent
96116543d3
commit
6324f17f90
@@ -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'
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user