Fix: Webdav sometimes called without scope or type is actually a lock extension

Fix: Controller did not properly search lock attributes because of gem bug
This commit is contained in:
Daniel Munn 2012-06-27 16:19:49 +01:00
parent e3831b409f
commit 6a9fa3236f
3 changed files with 77 additions and 7 deletions

View File

@ -26,8 +26,21 @@ module RedmineDmsf
existing = locks(false)
raise DmsfLockError.new("Unable to complete lock - resource (or parent) is locked") if self.locked? && existing.empty?
unless existing.empty?
if existing[0].scope == :scope_exclusive
raise DmsfLockError.new("Unable to complete lock - resource (or parent) is locked")
if existing[0].lock_scope == :scope_exclusive
# If it's an exclusive lock and you're re-requesting the actual desired behaviour is to not return a new lock,
# but the same lock (extended)
if self.folder.locked?
raise DmsfLockError.new("Unable to complete lock - resource parent is locked")
else
if existing[0].user.id == User.current.id then
l = existing[0]
l.expires_at = expire
l.save!
return l
else
raise DmsfLockError.new("Unable to complete lock - resource is locked")
end
end
else
raise DmsfLockError.new("unable to exclusively lock a shared-locked resource") if scope == :scope_exclusive
end

View File

@ -29,6 +29,23 @@ module RedmineDmsf
OK
end
# This is just pain DIRTY
# to fix some gem bugs we're overriding their controller
def lock
begin
request.env['Timeout'] = request.env['HTTP_TIMEOUT'].split('-',2).join(',') unless request.env['HTTP_TIMEOUT'].nil?
rescue
#Nothing here
end
request_document.remove_namespaces! if ns.empty?
# We re-imlement the function ns - if its return is empty, there are no usable namespaces
# so to prevent never returning data, we stip all namespaces
super
end
#Overload the default propfind function with this
def propfind
unless(resource.exist?)
@ -63,6 +80,16 @@ module RedmineDmsf
end
end
private
def ns(opt_head = '')
_ns = opt_head
if(request_document && request_document.root && request_document.root.namespace_definitions.size > 0)
_ns = request_document.root.namespace_definitions.first.prefix.to_s
_ns += ':' unless _ns.empty?
end
_ns.empty? ? opt_head : _ns
end
end
end
end

View File

@ -397,7 +397,7 @@ module RedmineDmsf
# Lock
def lock(args)
return Conflict unless (parent.projectless_path == "/" || parent_exists?) && !collection?
return Conflict unless (parent.projectless_path == "/" || parent_exists?)
token = UUIDTools::UUID.md5_create(UUIDTools::UUID_URL_NAMESPACE, projectless_path).to_s
lock_check(args[:scope])
entity = file? ? file : folder
@ -405,10 +405,40 @@ module RedmineDmsf
if (entity.locked? && entity.locked_for_user?)
raise DAV4Rack::LockFailure.new("Failed to lock: #{@path}")
else
entity.lock!
# If scope and type are not defined, the only thing we can
# logically assume is that the lock is being refreshed (office loves
# to do this for example, so we do a few checks, try to find the lock
# and ultimately extend it, otherwise we return Conflict for any failure
if (!args[:scope] && !args[:type]) #Perhaps a lock refresh
http_if = request.env['HTTP_IF']
return Conflict if http_if.nil?
http_if = http_if.slice(1, http_if.length - 2)
return Conflict unless http_if == token
entity.lock(false).each {|l|
if l.user.id == User.current.id
l.expires_at = Time.now + 1.hour
l.save!
@response['Lock-Token'] = token
return [1.hours.to_i, token]
end
}
#Unfortunately if we're here, then it's updating a lock we can't find
return Conflict
end
scope = "scope_#{(args[:scope] || "exclusive")}".to_sym
type = "type_#{(args[:type] || "write")}".to_sym
entity.lock! scope, type, Time.now + 1.hours
@response['Lock-Token'] = token
Locked
[8600, token]
[1.hours.to_i, token]
end
rescue DmsfLockError
raise DAV4Rack::LockFailure.new("Failed to lock: #{@path}")
@ -433,7 +463,7 @@ module RedmineDmsf
entity.unlock!
NoContent
end
resue
rescue
Forbidden
end
end