Rubocop XML module files and update method references

This commit is contained in:
Brandon Robins
2017-12-30 22:01:24 -06:00
parent 5b7d67ee57
commit b9a7cb88f9
9 changed files with 248 additions and 171 deletions

View File

@@ -5,6 +5,7 @@ require 'calligraphy/rails/web_dav_methods'
require 'calligraphy/rails/web_dav_preconditions' require 'calligraphy/rails/web_dav_preconditions'
require 'calligraphy/rails/web_dav_requests_controller' require 'calligraphy/rails/web_dav_requests_controller'
require 'calligraphy/xml/web_dav_elements'
require 'calligraphy/xml/builder' require 'calligraphy/xml/builder'
require 'calligraphy/xml/namespace' require 'calligraphy/xml/namespace'
require 'calligraphy/xml/node' require 'calligraphy/xml/node'

View File

@@ -8,6 +8,7 @@ module Calligraphy
attr_reader :resource_exists attr_reader :resource_exists
#:nodoc:
def initialize(headers:, request:, response:, resource:) def initialize(headers:, request:, response:, resource:)
super super
@@ -59,7 +60,7 @@ module Calligraphy
def build_response(lock_properties) def build_response(lock_properties)
builder = xml_builder builder = xml_builder
xml_res = builder.lock_res lock_properties xml_res = builder.lock_response lock_properties
lock_token = extract_lock_token lock_properties lock_token = extract_lock_token lock_properties
prepare_response_headers lock_token prepare_response_headers lock_token

View File

@@ -13,7 +13,8 @@ module Calligraphy
properties = @resource.propfind xml properties = @resource.propfind xml
builder = xml_builder builder = xml_builder
xml_res = builder.propfind_res @resource.full_request_path, properties xml_res = builder.propfind_response(@resource.full_request_path,
properties)
set_xml_content_type set_xml_content_type

View File

@@ -18,7 +18,8 @@ module Calligraphy
actions = @resource.proppatch xml actions = @resource.proppatch xml
builder = xml_builder builder = xml_builder
xml_res = builder.proppatch_res @resource.full_request_path, actions xml_res = builder.proppatch_response(@resource.full_request_path,
actions)
set_xml_content_type set_xml_content_type

View File

@@ -1,167 +1,118 @@
module Calligraphy::XML # frozen_string_literal: true
class Builder
SUPPORTED_NS_TAGS = %w(
creationdate displayname exclusive getcontentlanguage getcontentlength
getcontenttype getetag getlastmodified href lockdiscovery lockscope
locktype owner write
)
attr_reader :dav_ns, :default_ns, :server_protocol module Calligraphy
module XML
# Responsible for building XML responses for WebDAV requests.
class Builder
include Calligraphy::XML::WebDavElements
def initialize(dav_ns: 'D', server_protocol: 'HTTP/1.1') attr_reader :dav_ns, :default_ns, :server_protocol
@dav_ns = dav_ns
@default_ns = { "xmlns:#{@dav_ns}" => 'DAV:' }
@server_protocol = server_protocol
end
def lock_res(activelock_properties) #:nodoc:
build :prop do |xml| def initialize(dav_ns: 'D', server_protocol: 'HTTP/1.1')
xml.lockdiscovery do @dav_ns = dav_ns
activelock_properties.each do |properties| @default_ns = { "xmlns:#{@dav_ns}" => 'DAV:' }
activelock xml, properties @server_protocol = server_protocol
end end
private
def build(tag)
Nokogiri::XML::Builder.new do |xml|
xml[@dav_ns].send(tag, @default_ns) { yield xml }
end.to_xml
end
def multistatus
build :multistatus do |xml|
xml.response { yield xml }
end end
end end
end
def propfind_res(path, properties) def property_drilldown(xml, property)
multistatus do |xml| if property.is_a? Array
href xml, path iterate_and_drilldown xml, property
propstat xml, properties[:found], :ok elsif DAV_NS_TAGS.include? property.name
propstat xml, properties[:not_found], :not_found supported_ns_tag xml, property
end elsif property.namespace&.href
end non_supported_ns_tag xml, property
else
def proppatch_res(path, actions) nil_ns_tag xml, property
multistatus do |xml|
href xml, path
propstat xml, actions[:set]
propstat xml, actions[:remove]
end
end
private
def build(tag)
Nokogiri::XML::Builder.new do |xml|
xml[@dav_ns].send(tag, @default_ns) do
yield xml
end end
end.to_xml end
end
def activelock(xml, property_set) def iterate_and_drilldown(xml, property_set)
xml.activelock do
property_set.each do |property| property_set.each do |property|
property_drilldown xml, property property_drilldown xml, property
end end
end end
end
def href(xml, path) def supported_ns_tag(xml, property)
xml.href path if DAV_NS_METHODS.include? property.name
end return send property.name, xml, property
def multistatus
build :multistatus do |xml|
xml.response do
yield xml
end end
end
end
def prop(xml, property_set)
xml.prop do
property_set.each do |property|
property_drilldown xml, property
end
end
end
def propstat(xml, property_set, status=:ok)
return unless property_set.length > 0
xml.propstat do
prop xml, property_set
status xml, status
end
end
def resourcetype(xml, property)
if property.children.text == 'collection'
xml[@dav_ns].resourcetype do
xml.send 'collection'
end
else
xml[@dav_ns].resourcetype
end
end
def status(xml, status)
xml.status status_message status
end
def supportedlock(xml, property)
children = JSON.parse property.text, symbolize_names: true
xml[@dav_ns].supportedlock do
children.each do |child|
xml[@dav_ns].lockentry do
xml[@dav_ns].lockscope do
xml.text child[:lockentry][:lockscope]
end
xml[@dav_ns].locktype do
xml.text child[:lockentry][:locktype]
end
end
end
end
end
# NOTE: `xml[@dav_ns].send timeout` results in Timeout being called, so
# we have this timeout method for convenience
def timeout(xml, property)
xml[@dav_ns].timeout do
xml.text property.text
end
end
def property_drilldown(xml, property)
if property.is_a? Array
property.each do |prop|
property_drilldown xml, prop
end
elsif property.children && property.text.nil?
xml.send property.name do
property.children.each do |child|
property_drilldown xml, child
end
end
elsif property.name == 'resourcetype'
resourcetype xml, property
elsif property.name == 'supportedlock'
supportedlock xml, property
elsif property.name == 'timeout'
timeout xml, property
elsif SUPPORTED_NS_TAGS.include? property.name
xml[@dav_ns].send property.name do xml[@dav_ns].send property.name do
xml.text property.text if property.children
iterate_and_drilldown xml, property.children
else
xml.text property.text
end
end end
elsif property.namespace && property.namespace.href end
def non_supported_ns_tag(xml, property)
xml.send property.name, xmlns: property.namespace.href do xml.send property.name, xmlns: property.namespace.href do
xml.text property.text if property.children
iterate_and_drilldown xml, property.children
else
xml.text property.text
end
end end
else end
def nil_ns_tag(xml, property)
xml.send property.name, property.text do xml.send property.name, property.text do
xml.parent.namespace = nil xml.parent.namespace = nil
end end
end end
end
def status_message(status) def self_closing_tag(xml, text)
status_code = Rack::Utils.status_code status xml.send text
[@server_protocol, status_code, Rack::Utils::HTTP_STATUS_CODES[status_code]].join ' ' end
def href(xml, path)
xml[@dav_ns].href path
end
def prop(xml, property_set)
xml[@dav_ns].prop do
iterate_and_drilldown xml, property_set
end
end
def propstat(xml, property_set, status = :ok)
return if property_set.empty?
xml[@dav_ns].propstat do
prop xml, property_set
status xml, status
end
end
def status(xml, status)
xml[@dav_ns].status status_message status
end
def status_message(status)
status_code = Rack::Utils.status_code status
[
@server_protocol,
status_code,
Rack::Utils::HTTP_STATUS_CODES[status_code]
].join ' '
end
end end
end end
end end

View File

@@ -1,10 +1,16 @@
module Calligraphy::XML # frozen_string_literal: true
class Namespace
attr_accessor :href, :prefix
def initialize(namespace) module Calligraphy
@href = namespace.href if namespace.href module XML
@prefix = namespace.prefix if namespace.prefix # 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 end
end end

View File

@@ -1,9 +1,16 @@
module Calligraphy::XML # frozen_string_literal: true
class Node
attr_accessor :children, :name, :namespace, :text 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?
def initialize(node=nil)
unless node.nil?
@name = node.name @name = node.name
@text = node.text unless node.text.empty? @text = node.text unless node.text.empty?
@@ -11,12 +18,18 @@ module Calligraphy::XML
@namespace = Calligraphy::XML::Namespace.new node.namespace @namespace = Calligraphy::XML::Namespace.new node.namespace
end end
if node.children&.length > 0 return unless node_has_children node
@children = []
node.children.each do |child| @children = []
@children.push Calligraphy::XML::Node.new child node.children.each { |x| @children.push Calligraphy::XML::Node.new x }
end end
end
private
def node_has_children(node)
return false if node.children.nil?
node.children.length.positive?
end end
end end
end end

View File

@@ -1,18 +1,29 @@
module Calligraphy::XML # frozen_string_literal: true
module Utils
def xml_for(body:, node:)
xml = Nokogiri::XML body
return :bad_request unless xml.errors.empty?
namespace = nil module Calligraphy
xml.root.namespace_definitions.each do |n| module XML
namespace = "#{n.prefix}|" if n&.href == Calligraphy::DAV_NS && !n.prefix.nil? # Miscellaneous XML convenience methods.
module Utils
# Returns the XML for a given XML body and node/CSS selector.
def xml_for(body:, node:)
xml = Nokogiri::XML body
return :bad_request unless xml.errors.empty?
namespace = nil
xml.root.namespace_definitions.each do |n|
namespace = "#{n.prefix}|" if dav_namespace n
end
node = node.split(' ').map! { |n| namespace + n }.join(' ') if namespace
xml.css(node).children
end end
namespace
node = node.split(' ').map! { |n| namespace + n }.join(' ') if namespace private
xml.css(node).children def dav_namespace(namespace)
namespace&.href == Calligraphy::DAV_NS && !namespace.prefix.nil?
end
end end
end end
end end

View File

@@ -0,0 +1,92 @@
# frozen_string_literal: true
module Calligraphy
module XML
# Methods to help build WebDAV elements and properties.
module WebDavElements
DAV_NS_TAGS = %w[
activelock allprop collection creationdate depth displayname error
exclusive getcontentlanguage getcontentlength getcontenttype getetag
getlastmodified href include location lockdiscovery lockentry lockinfo
lockroot lockscope locktoken locktype multistatus owner prop
propertyupdate propfind propname propstat remove response
responsedescription resourcetype set shared status supportedlock
timeout write
].freeze
DAV_NS_METHODS = %w[resourcetype supportedlock timeout].freeze
# Build an XML response for a LOCK request.
def lock_response(activelock_properties)
build :prop do |xml|
xml.lockdiscovery do
activelock_properties.each do |properties|
xml.activelock do
iterate_and_drilldown xml, properties
end
end
end
end
end
# Build an XML response for a PROPFIND request.
def propfind_response(path, properties)
multistatus do |xml|
href xml, path
propstat xml, properties[:found], :ok
propstat xml, properties[:not_found], :not_found
end
end
# Build an XML response for a PROPPATCH request.
def proppatch_response(path, actions)
multistatus do |xml|
href xml, path
propstat xml, actions[:set]
propstat xml, actions[:remove]
end
end
private
def resourcetype(xml, property)
xml[@dav_ns].resourcetype do
self_closing_tag xml, property.text if property.text == 'collection'
end
end
def supportedlock(xml, property)
children = JSON.parse property.text, symbolize_names: true
xml[@dav_ns].supportedlock do
children.each do |child|
xml[@dav_ns].lockentry do
lockscope xml, child[:lockentry][:lockscope]
locktype xml, child[:lockentry][:locktype]
end
end
end
end
def lockscope(xml, scope)
xml[@dav_ns].lockscope do
self_closing_tag xml, scope
end
end
def locktype(xml, type)
xml[@dav_ns].locktype do
self_closing_tag xml, type
end
end
# NOTE: `xml[@dav_ns].send timeout` results in Timeout being called, so
# we have this timeout method for convenience.
def timeout(xml, property)
xml[@dav_ns].timeout do
xml.text property.text
end
end
end
end
end