Skip to content

Commit

Permalink
Add basic custom property support
Browse files Browse the repository at this point in the history
  • Loading branch information
jatoben committed Jul 27, 2015
1 parent 4b3ec91 commit 87ca415
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 21 deletions.
56 changes: 36 additions & 20 deletions lib/rack_dav/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,19 +159,19 @@ def propfind
raise NotFound if not resource.exist?

if not request_match("/d:propfind/d:allprop").empty?
names = resource.property_names
nodes = resource.property_names.map { |e| Nokogiri::XML::Element.new(e, request_document) }
else
names = request_match("/d:propfind/d:prop/d:*").map { |e| e.name }
names = resource.property_names if names.empty?
raise BadRequest if names.empty?
nodes = request_match("/d:propfind/d:prop/*")
nodes = resource.property_names.map { |e| Nokogiri::XML::Element.new(e, request_document) } if nodes.empty?
raise BadRequest if nodes.empty?
end

multistatus do |xml|
for resource in find_resources
resource.path.gsub!(/\/\//, '/')
xml.response do
xml.href "http://#{host}#{url_escape resource.path}"
propstats xml, get_properties(resource, names)
propstats xml, get_properties(resource, nodes)
end
end
end
Expand All @@ -180,19 +180,18 @@ def propfind
def proppatch
raise NotFound if not resource.exist?

prop_rem = request_match("/d:propertyupdate/d:remove/d:prop/d:*").map { |e| [e.name] }
prop_set = request_match("/d:propertyupdate/d:set/d:prop/d:*").map { |e| [e.name, e.text] }
prop_rem = request_match("/d:propertyupdate/d:remove/d:prop/*")
prop_set = request_match("/d:propertyupdate/d:set/d:prop/*")

multistatus do |xml|
for resource in find_resources
xml.response do
xml.href "http://#{host}#{resource.path}"
propstats xml, set_properties(resource, prop_set)
propstats xml, set_properties(resource, prop_rem)
end
end
end

resource.save
end

def lock
Expand Down Expand Up @@ -320,6 +319,14 @@ def request_match(pattern)
request_document.xpath(pattern, 'd' => 'DAV:')
end

def qualified_node_name(node)
node.namespace.nil? || node.namespace.prefix.nil? ? node.name : "#{node.namespace.prefix}:#{node.name}"
end

def qualified_property_name(node)
node.namespace.nil? || node.namespace.href == 'DAV:' ? node.name : "{#{node.namespace.href}}#{node.name}"
end

# Quick and dirty parsing of the WEBDAV Timeout header.
# Refuses infinity, rejects anything but Second- timeouts
#
Expand Down Expand Up @@ -381,29 +388,29 @@ def response_errors(xml, errors)
end
end

def get_properties(resource, names)
def get_properties(resource, nodes)
stats = Hash.new { |h, k| h[k] = [] }
for name in names
for node in nodes
begin
map_exceptions do
stats[OK] << [name, resource.get_property(name)]
stats[OK] << [node, resource.get_property(qualified_property_name(node))]
end
rescue Status
stats[$!] << name
stats[$!] << node
end
end
stats
end

def set_properties(resource, pairs)
def set_properties(resource, nodes)
stats = Hash.new { |h, k| h[k] = [] }
for name, value in pairs
for node in nodes
begin
map_exceptions do
stats[OK] << [name, resource.set_property(name, value)]
stats[OK] << [node, resource.set_property(qualified_property_name(node), node.text)]
end
rescue Status
stats[$!] << name
stats[$!] << node
end
end
stats
Expand All @@ -414,13 +421,22 @@ def propstats(xml, stats)
for status, props in stats
xml.propstat do
xml.prop do
for name, value in props
for node, value in props
if value.is_a?(Nokogiri::XML::Node)
xml.send(name) do
xml.send(qualified_node_name(node).to_sym) do
rexml_convert(xml, value)
end
else
xml.send(name, value)
attrs = {}
unless node.namespace.nil?
unless node.namespace.prefix.nil?
attrs = { "xmlns:#{node.namespace.prefix}" => node.namespace.href }
else
attrs = { 'xmlns' => node.namespace.href }
end
end

xml.send(qualified_node_name(node).to_sym, value, attrs)
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion lib/rack_dav/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ def get_property(name)
when 'getcontenttype' then content_type
when 'getetag' then etag
when 'getlastmodified' then last_modified.httpdate
else self.get_custom_property(name) if self.respond_to?(:get_custom_property)
end
end

Expand All @@ -157,13 +158,14 @@ def set_property(name, value)
when 'getcontenttype' then self.content_type = value
when 'getetag' then self.etag = value
when 'getlastmodified' then self.last_modified = Time.httpdate(value)
else self.set_custom_property(name, value) if self.respond_to?(:set_custom_property)
end
rescue ArgumentError
raise HTTPStatus::Conflict
end

def remove_property(name)
raise HTTPStatus::Forbidden
raise HTTPStatus::Forbidden if property_names.include?(name)
end

def parent
Expand Down

0 comments on commit 87ca415

Please sign in to comment.