From 8522d872fc550461d786f7f9037c3929bed520d4 Mon Sep 17 00:00:00 2001 From: Brandon Robins Date: Sat, 28 Oct 2017 12:01:30 -0500 Subject: [PATCH] Add all WebDavRequest classes --- lib/calligraphy.rb | 10 +++++++ lib/calligraphy/copy.rb | 37 +++++++++++++++++++++++++ lib/calligraphy/delete.rb | 17 ++++++++++++ lib/calligraphy/get.rb | 12 +++++++++ lib/calligraphy/lock.rb | 52 ++++++++++++++++++++++++++++++++++++ lib/calligraphy/mkcol.rb | 20 ++++++++++++++ lib/calligraphy/move.rb | 31 +++++++++++++++++++++ lib/calligraphy/propfind.rb | 18 +++++++++++++ lib/calligraphy/proppatch.rb | 20 ++++++++++++++ lib/calligraphy/put.rb | 12 +++++++++ lib/calligraphy/unlock.rb | 13 +++++++++ 11 files changed, 242 insertions(+) create mode 100644 lib/calligraphy/copy.rb create mode 100644 lib/calligraphy/delete.rb create mode 100644 lib/calligraphy/get.rb create mode 100644 lib/calligraphy/lock.rb create mode 100644 lib/calligraphy/mkcol.rb create mode 100644 lib/calligraphy/move.rb create mode 100644 lib/calligraphy/propfind.rb create mode 100644 lib/calligraphy/proppatch.rb create mode 100644 lib/calligraphy/put.rb create mode 100644 lib/calligraphy/unlock.rb diff --git a/lib/calligraphy.rb b/lib/calligraphy.rb index 06d646c..e47bc77 100644 --- a/lib/calligraphy.rb +++ b/lib/calligraphy.rb @@ -11,6 +11,16 @@ require 'calligraphy/resource' require 'calligraphy/file_resource' require 'calligraphy/web_dav_request' +require 'calligraphy/copy' +require 'calligraphy/delete' +require 'calligraphy/get' +require 'calligraphy/lock' +require 'calligraphy/mkcol' +require 'calligraphy/move' +require 'calligraphy/propfind' +require 'calligraphy/proppatch' +require 'calligraphy/put' +require 'calligraphy/unlock' module Calligraphy DAV_NS = 'DAV:' diff --git a/lib/calligraphy/copy.rb b/lib/calligraphy/copy.rb new file mode 100644 index 0000000..0bbf54c --- /dev/null +++ b/lib/calligraphy/copy.rb @@ -0,0 +1,37 @@ +module Calligraphy + class Copy < WebDavRequest + def request + options = copy_move_options + can_copy = @resource.can_copy? options + + if can_copy[:ancestor_exist] + return :precondition_failed + else + return :conflict + end unless can_copy[:can_copy] + + return :locked if can_copy[:locked] + + overwritten = @resource.copy options + return overwritten ? :no_content : :created + end + + private + + def copy_move_options + { + depth: @headers['Depth'], + destination: remove_trailing_slash(destination_header), + overwrite: @headers['Overwrite'] || true + } + end + + def destination_header + @headers['Destination'].split(@headers['Host'])[-1] + end + + def remove_trailing_slash(input) + input[-1] == '/' ? input[0..-2] : input + end + end +end diff --git a/lib/calligraphy/delete.rb b/lib/calligraphy/delete.rb new file mode 100644 index 0000000..d1455fb --- /dev/null +++ b/lib/calligraphy/delete.rb @@ -0,0 +1,17 @@ +module Calligraphy + class Delete < WebDavRequest + def request + return :locked if @resource.locked_to_user? @headers + + if @resource.collection? + @resource.delete_collection + + return :no_content + else + return :not_found unless @resource.exists? + end + + return :no_content + end + end +end diff --git a/lib/calligraphy/get.rb b/lib/calligraphy/get.rb new file mode 100644 index 0000000..b675ffb --- /dev/null +++ b/lib/calligraphy/get.rb @@ -0,0 +1,12 @@ +module Calligraphy + class Get < WebDavRequest + def request(head: false) + if @resource.readable? + return :ok if head + return :ok, @resource.read + else + return :not_found + end + end + end +end diff --git a/lib/calligraphy/lock.rb b/lib/calligraphy/lock.rb new file mode 100644 index 0000000..e8cd323 --- /dev/null +++ b/lib/calligraphy/lock.rb @@ -0,0 +1,52 @@ +module Calligraphy + class Lock < WebDavRequest + include Calligraphy::XML::Utils + + def request + if @resource.request_body.blank? && !@resource.locked_to_user?(@headers) + lock_properties = @resource.refresh_lock + elsif (@resource.locked? && @resource.lock_is_exclusive?) || + (@resource.locked_to_user?(@headers) && !xml_contains_shared_lock?) + return :locked + else + resource_exists_beforehand = @resource.exists? + + xml = xml_for body: body, node: 'lockinfo' + return :bad_request if xml == :bad_request + + lock_properties = @resource.lock xml, headers['Depth'] + end + + builder = xml_builder + xml_res = builder.lock_res lock_properties + + lock_token = lock_properties[-1] + .select { |x| x.name == 'locktoken' }[0] + .children[0] + .text + + response.headers['Lock-Token'] = "<#{lock_token}>" + set_xml_content_type + + if resource_exists_beforehand + return :ok, xml_res + else + return :created, xml_res + end + end + + private + + def xml_contains_shared_lock? + lock_type = nil + xml = xml_for body: body, node: 'lockinfo' + xml.each do |node| + next unless node.is_a? Nokogiri::XML::Element + + lock_type = node.children[0].name if node.name == 'lockscope' + end + + lock_type == 'shared' + end + end +end diff --git a/lib/calligraphy/mkcol.rb b/lib/calligraphy/mkcol.rb new file mode 100644 index 0000000..2e0609d --- /dev/null +++ b/lib/calligraphy/mkcol.rb @@ -0,0 +1,20 @@ +module Calligraphy + class Mkcol < WebDavRequest + def request + return :method_not_allowed if @resource.exists? + return :conflict unless @resource.ancestor_exist? + return :unsupported_media_type unless @resource.request_body.blank? + + @resource.create_collection + set_content_location_header + + return :created + end + + private + + def set_content_location_header + @response.headers['Content-Location'] = @resource.full_request_path + end + end +end diff --git a/lib/calligraphy/move.rb b/lib/calligraphy/move.rb new file mode 100644 index 0000000..74513df --- /dev/null +++ b/lib/calligraphy/move.rb @@ -0,0 +1,31 @@ +module Calligraphy + class Move < Copy + def request + return :locked if @resource.locked_to_user? @headers + + options = copy_move_options + + if @resource.is_true? options[:overwrite] + to_path = options[:destination].tap { |s| s.slice! @resource.mount_point } + to_resource = @resource.class.new resource: to_path, req: @request + + if to_resource.exists? + to_resource.delete_collection + to_resource_existed = true + end + end + + copy_status = super + return copy_status if [:precondition_failed, :conflict].include? copy_status + + @resource.delete_collection + + if copy_status == :created && to_resource_existed + return :no_content + else + response.headers['Location'] = options[:destination] if copy_status == :created + return copy_status + end + end + end +end diff --git a/lib/calligraphy/propfind.rb b/lib/calligraphy/propfind.rb new file mode 100644 index 0000000..fdc30a9 --- /dev/null +++ b/lib/calligraphy/propfind.rb @@ -0,0 +1,18 @@ +module Calligraphy + class Propfind < WebDavRequest + include Calligraphy::XML::Utils + + def request + xml = xml_for body: body, node: 'propfind' + return :bad_request if xml == :bad_request + + properties = @resource.propfind xml + + builder = xml_builder + xml_res = builder.propfind_res @resource.full_request_path, properties + + set_xml_content_type + return :multi_status, xml_res + end + end +end diff --git a/lib/calligraphy/proppatch.rb b/lib/calligraphy/proppatch.rb new file mode 100644 index 0000000..6d7cb67 --- /dev/null +++ b/lib/calligraphy/proppatch.rb @@ -0,0 +1,20 @@ +module Calligraphy + class Proppatch < WebDavRequest + include Calligraphy::XML::Utils + + def request + return :locked if @resource.locked_to_user? @headers + + xml = xml_for body: body, node: 'propertyupdate' + return :bad_request if xml == :bad_request + + actions = @resource.proppatch xml + + builder = xml_builder + xml_res = builder.proppatch_res @resource.full_request_path, actions + + set_xml_content_type + return :multi_status, xml_res + end + end +end diff --git a/lib/calligraphy/put.rb b/lib/calligraphy/put.rb new file mode 100644 index 0000000..4e03c1a --- /dev/null +++ b/lib/calligraphy/put.rb @@ -0,0 +1,12 @@ +module Calligraphy + class Put < WebDavRequest + def request + return :locked if @resource.locked_to_user? headers + return :method_not_allowed if @resource.collection? + + @resource.write + + return :created, @resource.contents + end + end +end diff --git a/lib/calligraphy/unlock.rb b/lib/calligraphy/unlock.rb new file mode 100644 index 0000000..254c617 --- /dev/null +++ b/lib/calligraphy/unlock.rb @@ -0,0 +1,13 @@ +module Calligraphy + class Unlock < WebDavRequest + def request + return :bad_request if @headers['Lock-Token'].nil? + + @resource.unlock lock_token_header + end + + def lock_token_header + @headers['Lock-Token'].gsub Calligraphy::LOCK_TOKEN_ANGLE_REGEX, '' + end + end +end