Rubocop and update files

This commit is contained in:
Brandon Robins
2017-12-28 20:30:17 -06:00
parent a5c476c82c
commit 5b7d67ee57
9 changed files with 323 additions and 186 deletions

View File

@@ -2,3 +2,17 @@ AllCops:
TargetRubyVersion: 2.3
Exclude:
- 'spec/dummy/**/*'
Metrics/ClassLength:
Exclude:
- 'lib/calligraphy/resource/resource.rb'
Metrics/AbcSize:
Exclude:
- 'lib/calligraphy/rails/mapper.rb'
Metrics/LineLength:
Exclude:
- 'lib/calligraphy/rails/mapper.rb'
Metrics/MethodLength:
Exclude:
- 'lib/calligraphy/rails/mapper.rb'
Style/ClassVars:
Enabled: False

View File

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'calligraphy/rails/mapper'
require 'calligraphy/rails/web_dav_methods'
require 'calligraphy/rails/web_dav_preconditions'
@@ -24,6 +26,7 @@ require 'calligraphy/web_dav_request/proppatch'
require 'calligraphy/web_dav_request/put'
require 'calligraphy/web_dav_request/unlock'
#:nodoc:
module Calligraphy
# Constants used throughout Calligraphy.
DAV_NS = 'DAV:'
@@ -39,17 +42,17 @@ module Calligraphy
# HTTP methods allowed by the WebDavRequests controller.
mattr_accessor :allowed_http_methods
@@allowed_http_methods = %w(
@@allowed_http_methods = %w[
options get put delete copy move
mkcol propfind proppatch lock unlock
)
]
# Proc responsible for returning the user's password, API key,
# or HA1 digest hash so that Rails can check user credentials.
# Should be overridden to handle your particular application's
# user and/or authentication setup.
mattr_accessor :digest_password_procedure
@@digest_password_procedure = Proc.new { |username| 'changeme!' }
@@digest_password_procedure = proc { |_username| 'changeme!' }
# If Digest Authentication is enabled by default.
mattr_accessor :enable_digest_authentication
@@ -61,15 +64,15 @@ module Calligraphy
# Maximum lock lifetime in seconds.
mattr_accessor :lock_timeout_period
@@lock_timeout_period = 86400
@@lock_timeout_period = 86_400
# The HTTP actions Calligraphy uses to create mappings between WebDAV
# HTTP verbs and URLs and WebDAV controller actions.
mattr_accessor :web_dav_actions
@@web_dav_actions = %i(
@@web_dav_actions = %i[
options get put delete copy move
mkcol propfind proppatch lock unlock
)
]
# Default way to set up Calligraphy.
# Run `rails generate calligraphy:install` to generate a

View File

@@ -1,166 +1,174 @@
module ActionDispatch::Routing
class Mapper
module HttpHelpers
# Define a Calligraphy route that only recognizes HTTP COPY.
# copy 'bacon', to: 'food#bacon'
def copy(*args, &block)
args = set_web_dav_args args
map_method :copy, args, &block
# frozen_string_literal: true
module ActionDispatch
module Routing
class Mapper
#:nodoc:
module HttpHelpers
# Define a Calligraphy route that only recognizes HTTP COPY.
# copy 'bacon', to: 'food#bacon'
def copy(*args, &block)
args = web_dav_args args
map_method :copy, args, &block
end
# Define a Calligraphy route that only recognizes HTTP HEAD.
# head 'bacon', to: 'food#bacon'
def head(*args, &block)
args = web_dav_args args
map_method :head, args, &block
end
# Define a Calligraphy route that only recognizes HTTP LOCK.
# lock 'bacon', to: 'food#bacon'
def lock(*args, &block)
args = web_dav_args args
map_method :lock, args, &block
end
# Define a Calligraphy route that only recognizes HTTP MKCOL.
# mkcol 'bacon', to: 'food#bacon'
def mkcol(*args, &block)
args = web_dav_args args
map_method :mkcol, args, &block
end
# Define a Calligraphy route that only recognizes HTTP MOVE.
# move 'bacon', to: 'food#bacon'
def move(*args, &block)
args = web_dav_args args
map_method :move, args, &block
end
# Define a Calligraphy route that only recognizes HTTP OPTIONS.
# options 'bacon', to: 'food#bacon'
def options(*args, &block)
args = web_dav_args args
map_method :options, args, &block
end
# Define a Calligraphy route that only recognizes HTTP PROPFIND.
# propfind 'bacon', to: 'food#bacon'
def propfind(*args, &block)
args = web_dav_args args
map_method :propfind, args, &block
end
# Define a Calligraphy route that only recognizes HTTP PROPPATCH.
# proppatch 'bacon', to: 'food#bacon'
def proppatch(*args, &block)
args = web_dav_args args
map_method :proppatch, args, &block
end
# Define a Calligraphy route that only recognizes HTTP UNLOCK.
# unlock 'bacon', to: 'food#bacon'
def unlock(*args, &block)
args = web_dav_args args
map_method :unlock, args, &block
end
# Define a Calligraphy route that only recognizes HTTP DELETE.
# web_dav_delete 'broccoli', to: 'food#broccoli'
def web_dav_delete(*args, &block)
args = web_dav_args args
map_method :delete, args, &block
end
# Define a Calligraphy route that only recognizes HTTP GET.
# web_dav_get 'bacon', to: 'food#bacon'
def web_dav_get(*args, &block)
args = web_dav_args args
map_method :get, args, &block
end
# Define a Calligraphy route that only recognizes HTTP PUT.
# web_dav_put 'bacon', to: 'food#bacon'
def web_dav_put(*args, &block)
args = web_dav_args args
map_method :put, args, &block
end
private
def web_dav_args(args)
options = {
controller: 'calligraphy/rails/web_dav_requests',
action: 'invoke_method'
}
[args[0], options]
end
end
# Define a Calligraphy route that only recognizes HTTP HEAD.
# head 'bacon', to: 'food#bacon'
def head(*args, &block)
args = set_web_dav_args args
map_method :head, args, &block
end
# Define a Calligraphy route that only recognizes HTTP LOCK.
# lock 'bacon', to: 'food#bacon'
def lock(*args, &block)
args = set_web_dav_args args
map_method :lock, args, &block
end
# Define a Calligraphy route that only recognizes HTTP MKCOL.
# mkcol 'bacon', to: 'food#bacon'
def mkcol(*args, &block)
args = set_web_dav_args args
map_method :mkcol, args, &block
end
# Define a Calligraphy route that only recognizes HTTP MOVE.
# move 'bacon', to: 'food#bacon'
def move(*args, &block)
args = set_web_dav_args args
map_method :move, args, &block
end
# Define a Calligraphy route that only recognizes HTTP OPTIONS.
# options 'bacon', to: 'food#bacon'
def options(*args, &block)
args = set_web_dav_args args
map_method :options, args, &block
end
# Define a Calligraphy route that only recognizes HTTP PROPFIND.
# propfind 'bacon', to: 'food#bacon'
def propfind(*args, &block)
args = set_web_dav_args args
map_method :propfind, args, &block
end
# Define a Calligraphy route that only recognizes HTTP PROPPATCH.
# proppatch 'bacon', to: 'food#bacon'
def proppatch(*args, &block)
args = set_web_dav_args args
map_method :proppatch, args, &block
end
# Define a Calligraphy route that only recognizes HTTP UNLOCK.
# unlock 'bacon', to: 'food#bacon'
def unlock(*args, &block)
args = set_web_dav_args args
map_method :unlock, args, &block
end
# Define a Calligraphy route that only recognizes HTTP DELETE.
# web_dav_delete 'broccoli', to: 'food#broccoli'
def web_dav_delete(*args, &block)
args = set_web_dav_args args
map_method :delete, args, &block
end
# Define a Calligraphy route that only recognizes HTTP GET.
# web_dav_get 'bacon', to: 'food#bacon'
def web_dav_get(*args, &block)
args = set_web_dav_args args
map_method :get, args, &block
end
# Define a Calligraphy route that only recognizes HTTP PUT.
# web_dav_put 'bacon', to: 'food#bacon'
def web_dav_put(*args, &block)
args = set_web_dav_args args
map_method :put, args, &block
end
private
def set_web_dav_args(args)
options = {
controller: 'calligraphy/rails/web_dav_requests',
action: 'invoke_method'
}
[args[0], options]
end
end
module Resources
class Resource
def web_dav_actions
if @only
Array(@only).map(&:to_sym)
elsif @except
Calligraphy.web_dav_actions - Array(@except).map(&:to_sym)
else
Calligraphy.web_dav_actions
#:nodoc:
module Resources
#:nodoc:
class Resource
# Returns the available WebDAV HTTP verbs based on Calligraphy
# configuration and Rails routing options.
def web_dav_actions
if @only
Array(@only).map(&:to_sym)
elsif @except
Calligraphy.web_dav_actions - Array(@except).map(&:to_sym)
else
Calligraphy.web_dav_actions
end
end
end
end
# With Calligraphy, a resourceful route provides mappings between WebDAV
# HTTP verbs and URLs and WebDAV controller actions. A single entry in
# the routing file, such as:
#
# calligraphy_resource :photos
#
# creates eleven different routes in your application, all mapping to the
# WebDavRequests controller:
#
# OPTIONS /photos/*resource
# GET /photos/*resource
# PUT /photos/*resource
# DELETE /photos/*resource
# COPY /photos/*resource
# MOVE /photos/*resource
# MKCOL /photos/*resource
# PROPFIND /photos/*resource
# PROPPATCH /photos/*resource
# LOCK /photos/*resource
# UNLOCK /photos/*resource
def calligraphy_resource(*resources, &block)
options = resources.extract_options!.dup
# With Calligraphy, a resourceful route provides mappings between WebDAV
# HTTP verbs and URLs and WebDAV controller actions. A single entry in
# the routing file, such as:
#
# calligraphy_resource :photos
#
# creates eleven different routes in your application, all mapping to
# the WebDavRequests controller:
#
# OPTIONS /photos/*resource
# GET /photos/*resource
# PUT /photos/*resource
# DELETE /photos/*resource
# COPY /photos/*resource
# MOVE /photos/*resource
# MKCOL /photos/*resource
# PROPFIND /photos/*resource
# PROPPATCH /photos/*resource
# LOCK /photos/*resource
# UNLOCK /photos/*resource
def calligraphy_resource(*resources, &block)
options = resources.extract_options!.dup
if apply_common_behavior_for :calligraphy_resource, resources, options, &block
return self
end
if apply_common_behavior_for :calligraphy_resource, resources, options, &block
return self
end
with_scope_level(:resource) do
options = apply_action_options options
singleton_resoure = ActionDispatch::Routing::Mapper::SingletonResource
with_scope_level(:resource) do
options = apply_action_options options
resource_scope(singleton_resoure.new resources.pop, api_only?, @scope[:shallow], options) do
yield if block_given?
resource_scope(SingletonResource.new(resources.pop, api_only?, @scope[:shallow], options)) do
yield if block_given?
concerns(options[:concerns]) if options[:concerns]
concerns(options[:concerns]) if options[:concerns]
set_mappings_for_web_dav_resources
set_mappings_for_web_dav_resources
end
end
end
end
private
private
def set_mappings_for_web_dav_resources
parent_resource.web_dav_actions.each do |action|
# Rails already defines GET, PUT, and DELETE actions which we don't
# want to override. Instead, we map WebDAV GET, PUT, and DELETE
# HTTP actions to 'web_dav_' prefixed methods.
if [:get, :put, :delete].include? action
send "web_dav_#{action.to_s}", '*resource'
else
send action, '*resource'
def set_mappings_for_web_dav_resources
parent_resource.web_dav_actions.each do |action|
# Rails already defines GET, PUT, and DELETE actions which we don't
# want to override. Instead, we map WebDAV GET, PUT, and DELETE
# HTTP actions to 'web_dav_' prefixed methods.
if %i[get put delete].include? action
send "web_dav_#{action}", '*resource'
else
send action, '*resource'
end
end
end
end

View File

@@ -26,7 +26,7 @@ module Calligraphy
def can_copy?(options)
copy_options = { can_copy: false, ancestor_exist: false, locked: false }
overwrite = is_true? options[:overwrite]
overwrite = true? options[:overwrite]
destination = options[:destination].tap { |s| s.slice! @mount_point }
copy_options[:ancestor_exist] = File.exist? parent_path(destination)
@@ -62,9 +62,10 @@ module Calligraphy
File.directory? @src_path
end
# Creates a duplicate of the resource in `options[:destination]`.
def copy(options)
destination = options[:destination].tap { |s| s.slice! @mount_point }
preserve_existing = is_false? options[:overwrite]
preserve_existing = false? options[:overwrite]
to_path = join_paths @root_dir, destination
to_path_exists = File.exist? to_path

View File

@@ -1,143 +1,248 @@
# frozen_string_literal: true
module Calligraphy
# Resource base class.
#
# All custom resource classes should be inherited from Resource and should
# implement the relevant methods needed for the desired level of WebDAV
# support.
class Resource
attr_accessor :client_nonce, :contents, :updated_at
attr_reader :full_request_path, :mount_point, :request_body, :request_path, :root_dir
attr_reader :full_request_path, :mount_point, :request_body, :request_path,
:root_dir
def initialize(resource: nil, req: nil, mount: nil, root_dir: nil)
@full_request_path = req&.original_url
@mount_point = mount || req&.path&.tap { |s| s.slice! resource }
@request_body = req&.body&.read || ''
@request_path = mount.nil? ? resource : resource.split(mount)[-1]
@root_dir = root_dir
end
# Responsible for returning a boolean value indicating if an ancestor
# exists for the resource.
#
# Used in COPY and MKCOL requests.
def ancestor_exist?
raise NotImplementedError
end
def can_copy?(options)
# Responsible for returning a boolean value indicating if the resource
# can be copied.
#
# Used in COPY and MOVE (which inherits from COPY) requests.
def can_copy?(_options)
raise NotImplementedError
end
# Responsible for returning a boolean value indicating if the resource
# is a collection.
#
# Used in DELETE, MKCOL, MOVE, and PUT requests.
def collection?
raise NotImplementedError
end
def copy(options)
# Responsible for creating a duplicate of the resource in
# `options[:destination]` (see section 9.8 of RFC4918).
#
# Used in COPY and MOVE (which inherits from COPY) requests.
def copy(_options)
raise NotImplementedError
end
# Responsible for creating a new collection based on the resource (see
# section 9.3 of RFC4918).
#
# Used in MKCOL requests.
def create_collection
raise NotImplementedError
end
# A DAV-compliant resource can advertise several classes of compliance.
# `dav_compliance` is responsible for returning the classes of WebDAV
# compliance that the resource supports (see section 18 of RFC4918).
#
# Used in OPTIONS requests.
def dav_compliance
'1, 2, 3'
end
# Responsible for deleting a resource collection (see section 9.6 of
# RFC4918).
#
# Used in DELETE and MOVE requests.
def delete_collection
raise NotImplementedError
end
# Responsible for returning unique identifier used to create an etag.
#
# Used in precondition validation, as well as GET, HEAD, and PROPFIND
# requests.
def etag
raise NotImplementedError
end
# Responsible for indicating if the resource already exists.
#
# Used in DELETE, LOCK, MKCOL, and MOVE requests.
def exists?
raise NotImplementedError
end
def lock(nodes, depth='infinity')
# Responsible for creating a lock on the resource (see section 9.10 of
# RFC4918).
#
# Used in LOCK requests.
def lock(_nodes, _depth = 'infinity')
raise NotImplementedError
end
# Responsible for indicating if a resource lock is exclusive.
#
# Used in LOCK requests.
def lock_is_exclusive?
raise NotImplementedError
end
def lock_tokens
raise NotImplementedError
end
# Responsible for indicating if a resource is current locked.
#
# Used in LOCK requests.
def locked?
raise NotImplementedError
end
def locked_to_user?(headers=nil)
# Responsible for indicating if a resource is locked to the current user.
#
# Used in DELETE, LOCK, MOVE, PROPPATCH, and PUT requests.
def locked_to_user?(_headers = nil)
raise NotImplementedError
end
def propfind(nodes)
# Responsible for handling the retrieval of properties defined on the
# resource (see section 9.1 of RFC4918).
#
# Used in PROPFIND requests.
def propfind(_nodes)
raise NotImplementedError
end
def proppatch(nodes)
# Responsible for handling the addition and/or removal of properties
# defined on the resource through a PROPPATCH request (see section 9.2 of
# RFC4918).
#
# Used in PROPPATCH requests.
def proppatch(_nodes)
raise NotImplementedError
end
# Responsible for setting and returning the contents of a resource
# if it is readable (see section 9.4 of RFC4918).
#
# Used in GET requests.
def read
raise NotImplementedError
end
# Responsible for indicating if a resource is readable.
#
# Used in GET and HEAD requests.
def readable?
exists? && !collection?
end
# Responsible for refreshing locks (see section 9.10.2 of RFC4918).
#
# Used in LOCK requests.
def refresh_lock
raise NotImplementedError
end
def unlock(token)
# Responsible for unlocking a resource lock (see section 9.11 of RFC4918).
#
# Used in UNLOCK requests.
def unlock(_token)
raise NotImplementedError
end
def write(contents=@request_body.to_s)
# Responsible for writing contents to a resource (see section 9.7 of
# RFC4918).
#
# Used in PUT requests.
def write(_contents = @request_body.to_s)
raise NotImplementedError
end
private
# DAV property which can be retrieved by a PROPFIND request. `creationdate`
# records the time and date the resource was created (see section 15.1 of
# RFC4918).
def creationdate
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request. `displayname`
# returns a name for the resource that is suitable for presentation to the
# user (see section 15.2 of RFC4918).
def displayname
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request.
# `getcontentlanguage` returns the Content-Language header value (see
# section 15.3 of RFC4918).
def getcontentlanguage
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request.
# `getcontentlength` returns the Content-Length header value (see section
# 15.4 of RFC4918).
def getcontentlength
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request.
# `getcontenttype` returns the Content-Type header value (see section
# 15.5 of RFC4918).
def getcontenttype
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request.
# `getetag` returns the ETag header value (see section 15.6 of RFC4918).
def getetag
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request.
# `getlastmodified` returns the Last-Modified header value (see section
# 15.7 of RFC4918).
def getlastmodified
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request.
# `lockdiscovery` describes the active locks on a resource (see section
# 15.8 of RFC4918).
def lockdiscovery
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request.
# `resourcetype` specifies the nature of the resource (see section 15.9 of
# RFC4918).
def resourcetype
raise NotImplementedError
end
# DAV property which can be retrieved by a PROPFIND request.
# `supportedlock` provides a listing of the lock capabilities supported by
# the resource (see section 15.10 of RFC4918).
def supportedlock
raise NotImplementedError
end
def get_custom_property(prop)
raise NotImplementedError
end
end
end
end

View File

@@ -1,13 +1,16 @@
module Calligraphy
module Utils
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE']
# frozen_string_literal: true
def is_true?(val)
module Calligraphy
# Miscellaneous convenience methods.
module Utils
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].freeze
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].freeze
def true?(val)
TRUE_VALUES.include? val
end
def is_false?(val)
def false?(val)
FALSE_VALUES.include? val
end
@@ -26,13 +29,14 @@ module Calligraphy
def map_array_of_hashes(arr_hashes)
[].tap do |output_array|
arr_hashes.each do |hash|
output_array.push hash.map { |k, v| v }
output_array.push(hash.map { |_k, v| v })
end
end
end
def extract_lock_token(if_header)
if_header.scan(Calligraphy::LOCK_TOKEN_REGEX)&.flatten[0]
token = if_header.scan(Calligraphy::LOCK_TOKEN_REGEX)
token.flatten.first if token.is_a? Array
end
def lockentry_hash(scope, type)

View File

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Calligraphy
VERSION = '0.2.1'
end

View File

@@ -7,7 +7,7 @@ module Calligraphy
def execute
return :locked if @resource.locked_to_user? @headers
if @resource.is_true? options[:overwrite]
if @resource.true? options[:overwrite]
previous_resource_existed = overwrite_destination
end

View File

@@ -4,12 +4,12 @@ RSpec.describe 'Resource' do
context 'base method' do
resource_methods_without_inputs = %w(
ancestor_exist? collection? create_collection delete_collection etag
exists? lock_is_exclusive? lock_tokens locked? read readable? refresh_lock
exists? lock_is_exclusive? locked? read readable? refresh_lock
creationdate displayname getcontentlanguage getcontentlength getcontenttype
getetag getlastmodified lockdiscovery resourcetype supportedlock
)
resource_methods_with_inputs = %w(
can_copy? copy lock locked_to_user? propfind proppatch unlock write get_custom_property
can_copy? copy lock locked_to_user? propfind proppatch unlock write
)
resource_methods_without_inputs.each do |method|