From 967e3e6d5a4870ee99603bf79e5d2e9afab76fad Mon Sep 17 00:00:00 2001 From: "COLA@Redmine.local" Date: Wed, 22 Feb 2017 19:08:11 +0100 Subject: [PATCH 1/4] Fixing the file extension in formatted_name that was not fixed correctly in #657 --- app/models/dmsf_file_revision.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/dmsf_file_revision.rb b/app/models/dmsf_file_revision.rb index e8799acd..1d6da7b6 100644 --- a/app/models/dmsf_file_revision.rb +++ b/app/models/dmsf_file_revision.rb @@ -270,7 +270,7 @@ class DmsfFileRevision < ActiveRecord::Base format2.sub!('%v', self.version) format2.sub!('%i', self.dmsf_file.id.to_s) format2.sub!('%r', self.id.to_s) - format2 + ext if ext + format2 += ext if ext format2 end From 6c539ec85bd2bcdd64a8253fc61fda16606cd0e3 Mon Sep 17 00:00:00 2001 From: "COLA@Redmine.local" Date: Wed, 22 Feb 2017 19:03:53 +0100 Subject: [PATCH 2/4] Moving a file or folder must also invalidate the source folder --- app/models/dmsf_file.rb | 3 +++ lib/redmine_dmsf/webdav/dmsf_resource.rb | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/app/models/dmsf_file.rb b/app/models/dmsf_file.rb index f42b6499..9eff3823 100644 --- a/app/models/dmsf_file.rb +++ b/app/models/dmsf_file.rb @@ -260,6 +260,9 @@ class DmsfFile < ActiveRecord::Base end end end + + # Must invalidate source parent folder cache before moving + RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key) self.container_type = self.container_type self.container_id = container.id diff --git a/lib/redmine_dmsf/webdav/dmsf_resource.rb b/lib/redmine_dmsf/webdav/dmsf_resource.rb index dff5caaf..ec9a7da0 100644 --- a/lib/redmine_dmsf/webdav/dmsf_resource.rb +++ b/lib/redmine_dmsf/webdav/dmsf_resource.rb @@ -273,6 +273,9 @@ module RedmineDmsf if dest.exist? MethodNotAllowed else + # Must invalidate source parent folder cache before moving + RedmineDmsf::Webdav::Cache.invalidate_item(folder.propfind_cache_key) + if(parent.projectless_path == '/') #Project root folder.dmsf_folder_id = nil else @@ -337,6 +340,8 @@ module RedmineDmsf else if (project == resource.project) && (file.last_revision.size == 0) # Moving a zero sized file within the same project, just update the dmsf_folder + # Must invalidate source parent folder cache before moving + RedmineDmsf::Webdav::Cache.invalidate_item(file.propfind_cache_key) file.dmsf_folder = f else return InternalServerError unless file.move_to(resource.project, f) From 268b18765489ce3896322ca997793d4513615763 Mon Sep 17 00:00:00 2001 From: "COLA@Redmine.local" Date: Fri, 24 Feb 2017 21:43:14 +0100 Subject: [PATCH 3/4] PROPFIND/allprop must return 'supportedlock' and 'lockdiscovery' for ProjectResource. --- lib/redmine_dmsf/webdav/project_resource.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/redmine_dmsf/webdav/project_resource.rb b/lib/redmine_dmsf/webdav/project_resource.rb index aa6dc3f6..dfce0434 100644 --- a/lib/redmine_dmsf/webdav/project_resource.rb +++ b/lib/redmine_dmsf/webdav/project_resource.rb @@ -104,6 +104,13 @@ module RedmineDmsf def file nil end + + # Available properties + def properties + %w(creationdate displayname getlastmodified getetag resourcetype getcontenttype getcontentlength supportedlock lockdiscovery).collect do |prop| + {:name => prop, :ns_href => 'DAV:'} + end + end def project_id self.project.id if self.project From b5c89607fdcc6486a7409714a7e51a8e209dfcf9 Mon Sep 17 00:00:00 2001 From: "COLA@Redmine.local" Date: Fri, 24 Feb 2017 21:51:53 +0100 Subject: [PATCH 4/4] Locking/unlocking a file invalidates relevant cache entries #674 Fixed PROPFIND/allprop to return correct props for ProjectResource. --- lib/redmine_dmsf/lockable.rb | 13 +++ .../webdav/dmsf_webdav_propfind_test.rb | 102 ++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/lib/redmine_dmsf/lockable.rb b/lib/redmine_dmsf/lockable.rb index 3b17dbff..f403f186 100644 --- a/lib/redmine_dmsf/lockable.rb +++ b/lib/redmine_dmsf/lockable.rb @@ -73,6 +73,12 @@ module RedmineDmsf l.save! reload locks.reload + + # Invalidate PROPFIND (for parent folder) + RedmineDmsf::Webdav::Cache.invalidate_item(self.propfind_cache_key) + # Invalidate PROPSTATS + RedmineDmsf::Webdav::Cache.delete("PROPSTATS/#{RedmineDmsf::Webdav::ProjectResource.create_project_name(self.project)}/#{self.dmsf_path_str}") if self.is_a?(DmsfFolder) + RedmineDmsf::Webdav::Cache.delete("PROPSTATS/#{self.id}-#{self.last_revision.id}") if self.is_a?(DmsfFile) return l end @@ -136,6 +142,13 @@ module RedmineDmsf end end end + + # Invalidate PROPFIND (for parent folder) + RedmineDmsf::Webdav::Cache.invalidate_item(self.propfind_cache_key) + # Invalidate PROPSTATS + RedmineDmsf::Webdav::Cache.delete("PROPSTATS/#{RedmineDmsf::Webdav::ProjectResource.create_project_name(self.project)}/#{self.dmsf_path_str}") if self.is_a?(DmsfFolder) + RedmineDmsf::Webdav::Cache.delete("PROPSTATS/#{self.id}-#{self.last_revision.id}") if self.is_a?(DmsfFile) + reload locks.reload end diff --git a/test/integration/webdav/dmsf_webdav_propfind_test.rb b/test/integration/webdav/dmsf_webdav_propfind_test.rb index ce412ef0..a91d51fa 100644 --- a/test/integration/webdav/dmsf_webdav_propfind_test.rb +++ b/test/integration/webdav/dmsf_webdav_propfind_test.rb @@ -372,4 +372,106 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") end + def test_propfind_depth1_on_project1_for_admin_with_cache_and_locks + RedmineDmsf::Webdav::Cache.init_testcache + + log_user 'admin', 'admin' # login as admin + assert !User.current.anonymous?, 'Current user is anonymous' + + assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +7 do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => '1'}) + assert_response 207 # MultiStatus + end + + # Verify that everything exists in the cache as it should + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder1.title}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder6.title}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file1.id}-#{@file1.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file9.id}-#{@file9.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file10.id}-#{@file10.last_revision.id}") + + # Lock a file and verify that the PROPSTATS for the file and the PROPFIND were deleted + assert @file1.lock!, "File failed to be locked by #{User.current.name}" + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder1.title}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder6.title}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file1.id}-#{@file1.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file9.id}-#{@file9.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file10.id}-#{@file10.last_revision.id}") + + assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +1 do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => '1'}) + assert_response 207 # MultiStatus + end + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file1.id}-#{@file1.last_revision.id}") + + # Unlock a file and verify that the PROPSTATS for the file and the PROPFIND were deleted + assert @file1.unlock!, "File failed to be unlocked by #{User.current.name}" + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder1.title}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder6.title}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file1.id}-#{@file1.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file9.id}-#{@file9.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file10.id}-#{@file10.last_revision.id}") + + assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +1 do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => '1'}) + assert_response 207 # MultiStatus + end + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file1.id}-#{@file1.last_revision.id}") + + # Lock a folder and verify that the PROPSTATS for the file and the PROPFIND were deleted + assert @folder1.lock!, "File failed to be locked by #{User.current.name}" + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder1.title}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder6.title}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file1.id}-#{@file1.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file9.id}-#{@file9.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file10.id}-#{@file10.last_revision.id}") + + assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +1 do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => '1'}) + assert_response 207 # MultiStatus + end + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder1.title}") + + # Unlock a folder and verify that the PROPSTATS for the file and the PROPFIND were deleted + assert @folder1.unlock!, "File failed to be unlocked by #{User.current.name}" + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder1.title}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder6.title}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file1.id}-#{@file1.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file9.id}-#{@file9.last_revision.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@file10.id}-#{@file10.last_revision.id}") + + assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +1 do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => '1'}) + assert_response 207 # MultiStatus + end + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + assert RedmineDmsf::Webdav::Cache.exist?("PROPSTATS/#{@project1.identifier}/#{@folder1.title}") + end + end \ No newline at end of file