Add support for allprop and propname
This commit is contained in:
@@ -6,9 +6,9 @@ module Calligraphy
|
||||
# Resource responsible for writing and deleting directories and files to disk.
|
||||
class FileResource < Resource
|
||||
DAV_PROPERTY_METHODS = %w[
|
||||
creationdate displayname getcontentlanguage getcontentlength
|
||||
getcontenttype getetag getlastmodified lockdiscovery resourcetype
|
||||
supportedlock
|
||||
allprop creationdate displayname getcontentlanguage getcontentlength
|
||||
getcontenttype getetag getlastmodified lockdiscovery propname
|
||||
resourcetype supportedlock
|
||||
].freeze
|
||||
|
||||
include Calligraphy::Utils
|
||||
@@ -174,15 +174,7 @@ module Calligraphy
|
||||
def propfind(nodes)
|
||||
properties = { found: [], not_found: [] }
|
||||
|
||||
nodes.each do |node|
|
||||
node.children.each do |prop|
|
||||
next unless prop.is_a? Nokogiri::XML::Element
|
||||
|
||||
value = get_property prop
|
||||
|
||||
update_found_properties properties, prop, value
|
||||
end
|
||||
end
|
||||
find_properties_from_xml_elements nodes, properties
|
||||
|
||||
properties[:found] = properties[:found].uniq.flatten if properties[:found]
|
||||
properties
|
||||
@@ -507,6 +499,30 @@ module Calligraphy
|
||||
(lock_info[:check_creator] && (lock_info[:creator] == client_nonce))
|
||||
end
|
||||
|
||||
def find_properties_from_xml_elements(nodes, properties)
|
||||
nodes.each do |node|
|
||||
next unless node.is_a? Nokogiri::XML::Element
|
||||
|
||||
if node.children.length.positive?
|
||||
find_properties_from_property_nodes node, properties
|
||||
else
|
||||
value = get_property node
|
||||
|
||||
update_found_properties properties, node, value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def find_properties_from_property_nodes(node, properties)
|
||||
node.children.each do |prop|
|
||||
next unless prop.is_a? Nokogiri::XML::Element
|
||||
|
||||
value = get_property prop
|
||||
|
||||
update_found_properties properties, prop, value
|
||||
end
|
||||
end
|
||||
|
||||
def ancestor_lock_tokens(lock_info)
|
||||
lock_info[:lock].each { |x| x }.map { |k| k[:locktoken].children[0].text }
|
||||
end
|
||||
@@ -521,55 +537,94 @@ module Calligraphy
|
||||
def get_property(prop)
|
||||
case prop.name
|
||||
when *DAV_PROPERTY_METHODS
|
||||
prop.content = send prop.name
|
||||
prop
|
||||
send prop.name, prop
|
||||
else
|
||||
get_custom_property prop.name, deserialize: true
|
||||
end
|
||||
end
|
||||
|
||||
def creationdate
|
||||
@stats[:created_at]
|
||||
def allprop(_prop)
|
||||
get_custom_property nil, deserialize: true
|
||||
|
||||
{}.tap do |properties|
|
||||
@store_properties.each_value do |node|
|
||||
next unless node.is_a? Nokogiri::XML::Element
|
||||
|
||||
properties[node.name.to_sym] = node
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def displayname
|
||||
get_custom_property(:displayname) || @name
|
||||
def creationdate(prop)
|
||||
prop.content = @stats[:created_at]
|
||||
prop
|
||||
end
|
||||
|
||||
def getcontentlanguage
|
||||
get_custom_property :contentlanguage
|
||||
def displayname(prop)
|
||||
prop.content = get_custom_property(:displayname) || @name
|
||||
prop
|
||||
end
|
||||
|
||||
def getcontentlength
|
||||
@stats[:size]
|
||||
def getcontentlanguage(prop)
|
||||
prop.content = get_custom_property :contentlanguage
|
||||
prop
|
||||
end
|
||||
|
||||
def getcontenttype
|
||||
get_custom_property :contenttype
|
||||
def getcontentlength(prop)
|
||||
prop.content = @stats[:size]
|
||||
prop
|
||||
end
|
||||
|
||||
def getetag
|
||||
def getcontenttype(prop)
|
||||
prop.content = get_custom_property :contenttype
|
||||
prop
|
||||
end
|
||||
|
||||
def getetag(prop)
|
||||
cache_key = ActiveSupport::Cache.expand_cache_key [@resource.etag, '']
|
||||
"W/\"#{Digest::MD5.hexdigest(cache_key)}\""
|
||||
|
||||
prop.content = "W/\"#{Digest::MD5.hexdigest(cache_key)}\""
|
||||
prop
|
||||
end
|
||||
|
||||
def getlastmodified
|
||||
@updated_at
|
||||
def getlastmodified(prop)
|
||||
prop.content = @updated_at
|
||||
prop
|
||||
end
|
||||
|
||||
def lockdiscovery
|
||||
fetch_lock_info
|
||||
# def include(prop)
|
||||
# # TODO: Implement
|
||||
# prop
|
||||
# end
|
||||
|
||||
def lockdiscovery(prop)
|
||||
prop.content = fetch_lock_info
|
||||
prop
|
||||
end
|
||||
|
||||
def resourcetype
|
||||
'collection' if collection?
|
||||
def propname(_prop)
|
||||
get_custom_property nil, deserialize: true
|
||||
|
||||
{}.tap do |properties|
|
||||
@store_properties.each_value do |node|
|
||||
next unless node.is_a? Nokogiri::XML::Element
|
||||
|
||||
properties[node.name.to_sym] = xml_node node.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def supportedlock
|
||||
def resourcetype(prop)
|
||||
prop.content = 'collection' if collection?
|
||||
prop
|
||||
end
|
||||
|
||||
def supportedlock(prop)
|
||||
exclusive_write = lockentry_hash('exclusive', 'write')
|
||||
shared_write = lockentry_hash('shared', 'write')
|
||||
|
||||
JSON.generate [exclusive_write, shared_write]
|
||||
prop.content = JSON.generate [exclusive_write, shared_write]
|
||||
prop
|
||||
end
|
||||
|
||||
def get_custom_property(prop, deserialize: false)
|
||||
@@ -609,11 +664,10 @@ module Calligraphy
|
||||
def add_properties(node, actions)
|
||||
node.children.each do |prop|
|
||||
prop.children.each do |property|
|
||||
next unless node.is_a? Nokogiri::XML::Element
|
||||
next unless property.is_a? Nokogiri::XML::Element
|
||||
|
||||
prop_sym = property.name.to_sym
|
||||
|
||||
store_property_node property.serialize, prop_sym
|
||||
store_property_node property.clone.serialize, prop_sym
|
||||
|
||||
actions[:set].push property
|
||||
end
|
||||
|
||||
59
spec/requests/propfind_spec.rb
Normal file
59
spec/requests/propfind_spec.rb
Normal file
@@ -0,0 +1,59 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
require 'rails_helper'
|
||||
require 'support/request_helpers'
|
||||
require 'support/examples/propfind'
|
||||
require 'support/examples/proppatch'
|
||||
|
||||
RSpec.describe 'PROPFIND', type: :request do
|
||||
before(:all) do
|
||||
tmp_dir = Rails.root.join('../../tmp').to_path
|
||||
Dir.mkdir tmp_dir unless File.exists? tmp_dir
|
||||
|
||||
webdav_dir = Rails.root.join('../../tmp/webdav').to_path
|
||||
FileUtils.rm_r webdav_dir if File.exists? webdav_dir
|
||||
Dir.mkdir webdav_dir
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
allow(Calligraphy).to receive(:enable_digest_authentication)
|
||||
.and_return(false)
|
||||
end
|
||||
|
||||
context 'with xml defintiion' do
|
||||
before(:each) do
|
||||
put '/webdav/bar.html', headers: {
|
||||
RAW_POST_DATA: 'hello world'
|
||||
}
|
||||
proppatch '/webdav/bar.html', headers: {
|
||||
RAW_POST_DATA: Support::Examples::Proppatch.rfc4918_9_2_2
|
||||
}
|
||||
end
|
||||
|
||||
describe 'allprop' do
|
||||
it 'returns all property names and values' do
|
||||
propfind '/webdav/bar.html', headers: {
|
||||
RAW_POST_DATA: Support::Examples::Propfind.allprop
|
||||
}
|
||||
|
||||
expect(response.status).to eq(207)
|
||||
expect(response.body).to include('Authors')
|
||||
expect(response.body).to include('Author>')
|
||||
expect(response.body).to include('Jim')
|
||||
expect(response.body).to include('Roy')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'propname' do
|
||||
it 'returns all property names' do
|
||||
propfind '/webdav/bar.html', headers: {
|
||||
RAW_POST_DATA: Support::Examples::Propfind.propname
|
||||
}
|
||||
|
||||
expect(response.status).to eq(207)
|
||||
expect(response.body).to include('Authors/')
|
||||
expect(response.body).to_not include('Author/')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
25
spec/support/examples/propfind.rb
Normal file
25
spec/support/examples/propfind.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
module Support
|
||||
module Examples
|
||||
module Propfind
|
||||
def self.allprop
|
||||
<<~XML
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:propfind xmlns:D="DAV:">
|
||||
<D:allprop/>
|
||||
</D:propfind>
|
||||
XML
|
||||
end
|
||||
|
||||
def self.propname
|
||||
<<~XML
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:propfind xmlns:D="DAV:">
|
||||
<D:propname/>
|
||||
</D:propfind>
|
||||
XML
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
28
spec/support/examples/proppatch.rb
Normal file
28
spec/support/examples/proppatch.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
module Support
|
||||
module Examples
|
||||
module Proppatch
|
||||
# RFC4918: 9.2.2
|
||||
def self.rfc4918_9_2_2
|
||||
<<~XML
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:propertyupdate xmlns:D="DAV:"
|
||||
xmlns:Z="http://ns.example.com/standards/z39.50/">
|
||||
<D:set>
|
||||
<D:prop>
|
||||
<Z:Authors>
|
||||
<Z:Author>Jim Whitehead</Z:Author>
|
||||
<Z:Author>Roy Fielding</Z:Author>
|
||||
</Z:Authors>
|
||||
</D:prop>
|
||||
</D:set>
|
||||
<D:remove>
|
||||
<D:prop><Z:Copyright-Owner/></D:prop>
|
||||
</D:remove>
|
||||
</D:propertyupdate>
|
||||
XML
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user