aboutsummaryrefslogtreecommitdiffstats
path: root/build/integration/files_features
diff options
context:
space:
mode:
Diffstat (limited to 'build/integration/files_features')
-rw-r--r--build/integration/files_features/checksums.feature63
-rw-r--r--build/integration/files_features/download.feature296
-rw-r--r--build/integration/files_features/external-storage.feature127
-rw-r--r--build/integration/files_features/favorites.feature152
-rw-r--r--build/integration/files_features/metadata.feature16
-rw-r--r--build/integration/files_features/tags.feature465
-rw-r--r--build/integration/files_features/transfer-ownership.feature576
-rw-r--r--build/integration/files_features/trashbin.feature84
-rw-r--r--build/integration/files_features/windows_compatibility.feature68
9 files changed, 1847 insertions, 0 deletions
diff --git a/build/integration/files_features/checksums.feature b/build/integration/files_features/checksums.feature
new file mode 100644
index 00000000000..d797c7a503e
--- /dev/null
+++ b/build/integration/files_features/checksums.feature
@@ -0,0 +1,63 @@
+# SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+# SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+# SPDX-License-Identifier: AGPL-3.0-only
+Feature: checksums
+
+ Scenario: Uploading a file with checksum should work
+ Given user "user0" exists
+ When user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ Then The webdav response should have a status code "201"
+
+ Scenario: Uploading a file with checksum should return the checksum in the propfind
+ Given user "user0" exists
+ And user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ When user "user0" request the checksum of "/myChecksumFile.txt" via propfind
+ Then The webdav checksum should match "MD5:d70b40f177b14b470d1756a3c12b963a"
+
+ Scenario: Uploading a file with checksum should return the checksum in the download header
+ Given user "user0" exists
+ And user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ When user "user0" downloads the file "/myChecksumFile.txt"
+ Then The header checksum should match "MD5:d70b40f177b14b470d1756a3c12b963a"
+
+ Scenario: Moving a file with checksum should return the checksum in the propfind
+ Given user "user0" exists
+ And user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ When User "user0" moved file "/myChecksumFile.txt" to "/myMovedChecksumFile.txt"
+ And user "user0" request the checksum of "/myMovedChecksumFile.txt" via propfind
+ Then The webdav checksum should match "MD5:d70b40f177b14b470d1756a3c12b963a"
+
+ Scenario: Moving file with checksum should return the checksum in the download header
+ Given user "user0" exists
+ And user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ When User "user0" moved file "/myChecksumFile.txt" to "/myMovedChecksumFile.txt"
+ And user "user0" downloads the file "/myMovedChecksumFile.txt"
+ Then The header checksum should match "MD5:d70b40f177b14b470d1756a3c12b963a"
+
+ Scenario: Copying a file with checksum should return the checksum in the propfind
+ Given user "user0" exists
+ And user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ When User "user0" copied file "/myChecksumFile.txt" to "/myChecksumFileCopy.txt"
+ And user "user0" request the checksum of "/myChecksumFileCopy.txt" via propfind
+ Then The webdav checksum should match "MD5:d70b40f177b14b470d1756a3c12b963a"
+
+ Scenario: Copying file with checksum should return the checksum in the download header
+ Given user "user0" exists
+ And user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ When User "user0" copied file "/myChecksumFile.txt" to "/myChecksumFileCopy.txt"
+ And user "user0" downloads the file "/myChecksumFileCopy.txt"
+ Then The header checksum should match "MD5:d70b40f177b14b470d1756a3c12b963a"
+
+ Scenario: Overwriting a file with checksum should remove the checksum and not return it in the propfind
+ Given user "user0" exists
+ And user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ When user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt"
+ And user "user0" request the checksum of "/myChecksumFile.txt" via propfind
+ Then The webdav checksum should be empty
+
+ Scenario: Overwriting a file with checksum should remove the checksum and not return it in the download header
+ Given user "user0" exists
+ And user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt" with checksum "MD5:d70b40f177b14b470d1756a3c12b963a"
+ When user "user0" uploads file "data/textfile.txt" to "/myChecksumFile.txt"
+ And user "user0" downloads the file "/myChecksumFile.txt"
+ Then The OC-Checksum header should not be there
diff --git a/build/integration/files_features/download.feature b/build/integration/files_features/download.feature
new file mode 100644
index 00000000000..f9d4e7e95b9
--- /dev/null
+++ b/build/integration/files_features/download.feature
@@ -0,0 +1,296 @@
+# SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: AGPL-3.0-or-later
+Feature: download
+
+ Scenario: downloading 2 small files
+ Given using new dav path
+ And user "user0" exists
+ And User "user0" copies file "/welcome.txt" to "/welcome2.txt"
+ When user "user0" downloads zip file for entries '"welcome.txt","welcome2.txt"' in folder "/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a file named "welcome.txt" with the contents of "/welcome.txt" from "user0" data
+ And the downloaded zip file contains a file named "welcome2.txt" with the contents of "/welcome2.txt" from "user0" data
+
+ Scenario: downloading a small file and a directory
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/emptySubFolder"
+ When user "user0" downloads zip file for entries '"welcome.txt","emptySubFolder"' in folder "/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a file named "welcome.txt" with the contents of "/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "emptySubFolder/"
+
+ Scenario: downloading a small file and 2 nested directories
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/subFolder"
+ And user "user0" created a folder "/subFolder/emptySubSubFolder"
+ When user "user0" downloads zip file for entries '"welcome.txt","subFolder"' in folder "/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a file named "welcome.txt" with the contents of "/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "subFolder/"
+ And the downloaded zip file contains a folder named "subFolder/emptySubSubFolder/"
+
+ Scenario: downloading dir with 2 small files
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/sparseFolder"
+ And User "user0" copies file "/welcome.txt" to "/sparseFolder/welcome.txt"
+ And User "user0" copies file "/welcome.txt" to "/sparseFolder/welcome2.txt"
+ When user "user0" downloads zip file for entries '"sparseFolder"' in folder "/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a folder named "sparseFolder/"
+ And the downloaded zip file contains a file named "sparseFolder/welcome.txt" with the contents of "/sparseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a file named "sparseFolder/welcome2.txt" with the contents of "/sparseFolder/welcome2.txt" from "user0" data
+
+ Scenario: downloading dir with a small file and a directory
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/sparseFolder"
+ And User "user0" copies file "/welcome.txt" to "/sparseFolder/welcome.txt"
+ And user "user0" created a folder "/sparseFolder/emptySubFolder"
+ When user "user0" downloads zip file for entries '"sparseFolder"' in folder "/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a folder named "sparseFolder/"
+ And the downloaded zip file contains a file named "sparseFolder/welcome.txt" with the contents of "/sparseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "sparseFolder/emptySubFolder/"
+
+ Scenario: downloading dir with a small file and 2 nested directories
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/sparseFolder"
+ And User "user0" copies file "/welcome.txt" to "/sparseFolder/welcome.txt"
+ And user "user0" created a folder "/sparseFolder/subFolder"
+ And user "user0" created a folder "/sparseFolder/subFolder/emptySubSubFolder"
+ When user "user0" downloads zip file for entries '"sparseFolder"' in folder "/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a folder named "sparseFolder/"
+ And the downloaded zip file contains a file named "sparseFolder/welcome.txt" with the contents of "/sparseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "sparseFolder/subFolder/"
+ And the downloaded zip file contains a folder named "sparseFolder/subFolder/emptySubSubFolder/"
+
+ Scenario: downloading (from folder) 2 small files
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/baseFolder"
+ And User "user0" copies file "/welcome.txt" to "/baseFolder/welcome.txt"
+ And User "user0" copies file "/welcome.txt" to "/baseFolder/welcome2.txt"
+ When user "user0" downloads zip file for entries '"welcome.txt","welcome2.txt"' in folder "/baseFolder/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a file named "welcome.txt" with the contents of "/baseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a file named "welcome2.txt" with the contents of "/baseFolder/welcome2.txt" from "user0" data
+
+ Scenario: downloading (from folder) a small file and a directory
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/baseFolder"
+ And User "user0" copies file "/welcome.txt" to "/baseFolder/welcome.txt"
+ And user "user0" created a folder "/baseFolder/emptySubFolder"
+ When user "user0" downloads zip file for entries '"welcome.txt","emptySubFolder"' in folder "/baseFolder/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a file named "welcome.txt" with the contents of "/baseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "emptySubFolder/"
+
+ Scenario: downloading (from folder) a small file and 2 nested directories
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/baseFolder"
+ And User "user0" copies file "/welcome.txt" to "/baseFolder/welcome.txt"
+ And user "user0" created a folder "/baseFolder/subFolder"
+ And user "user0" created a folder "/baseFolder/subFolder/emptySubSubFolder"
+ When user "user0" downloads zip file for entries '"welcome.txt","subFolder"' in folder "/baseFolder/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a file named "welcome.txt" with the contents of "/baseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "subFolder/"
+ And the downloaded zip file contains a folder named "subFolder/emptySubSubFolder/"
+
+ Scenario: downloading (from folder) dir with 2 small files
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/baseFolder"
+ And user "user0" created a folder "/baseFolder/sparseFolder"
+ And User "user0" copies file "/welcome.txt" to "/baseFolder/sparseFolder/welcome.txt"
+ And User "user0" copies file "/welcome.txt" to "/baseFolder/sparseFolder/welcome2.txt"
+ When user "user0" downloads zip file for entries '"sparseFolder"' in folder "/baseFolder/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a folder named "sparseFolder/"
+ And the downloaded zip file contains a file named "sparseFolder/welcome.txt" with the contents of "/baseFolder/sparseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a file named "sparseFolder/welcome2.txt" with the contents of "/baseFolder/sparseFolder/welcome2.txt" from "user0" data
+
+ Scenario: downloading (from folder) dir with a small file and a directory
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/baseFolder"
+ And user "user0" created a folder "/baseFolder/sparseFolder"
+ And User "user0" copies file "/welcome.txt" to "/baseFolder/sparseFolder/welcome.txt"
+ And user "user0" created a folder "/baseFolder/sparseFolder/emptySubFolder"
+ When user "user0" downloads zip file for entries '"sparseFolder"' in folder "/baseFolder/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a folder named "sparseFolder/"
+ And the downloaded zip file contains a file named "sparseFolder/welcome.txt" with the contents of "/baseFolder/sparseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "sparseFolder/emptySubFolder/"
+
+ Scenario: downloading (from folder) dir with a small file and 2 nested directories
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/baseFolder"
+ And user "user0" created a folder "/baseFolder/sparseFolder"
+ And User "user0" copies file "/welcome.txt" to "/baseFolder/sparseFolder/welcome.txt"
+ And user "user0" created a folder "/baseFolder/sparseFolder/subFolder"
+ And user "user0" created a folder "/baseFolder/sparseFolder/subFolder/emptySubSubFolder"
+ When user "user0" downloads zip file for entries '"sparseFolder"' in folder "/baseFolder/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a folder named "sparseFolder/"
+ And the downloaded zip file contains a file named "sparseFolder/welcome.txt" with the contents of "/baseFolder/sparseFolder/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "sparseFolder/subFolder/"
+ And the downloaded zip file contains a folder named "sparseFolder/subFolder/emptySubSubFolder/"
+
+ @large
+ Scenario: downloading small file and dir with 65524 small files and 9 nested directories
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/crowdedFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder1"
+ And file "/crowdedFolder/subFolder1/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder1"
+ And user "user0" created a folder "/crowdedFolder/subFolder2"
+ And file "/crowdedFolder/subFolder2/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder2"
+ And user "user0" created a folder "/crowdedFolder/subFolder3"
+ And file "/crowdedFolder/subFolder3/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder3"
+ And user "user0" created a folder "/crowdedFolder/subFolder4"
+ And file "/crowdedFolder/subFolder4/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder4"
+ And user "user0" created a folder "/crowdedFolder/subFolder5"
+ And file "/crowdedFolder/subFolder5/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder5"
+ And user "user0" created a folder "/crowdedFolder/subFolder6"
+ And file "/crowdedFolder/subFolder6/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder6"
+ And user "user0" created a folder "/crowdedFolder/subFolder7"
+ And file "/crowdedFolder/subFolder7/test.txt" is created "5524" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder7"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/subSubFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/subSubFolder/emptySubSubSubFolder"
+ When user "user0" downloads zip file for entries '"welcome.txt","crowdedFolder"' in folder "/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a file named "welcome.txt" with the contents of "/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "crowdedFolder/"
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder1/"
+ And the downloaded zip file contains a file named "crowdedFolder/subFolder1/test.txt-0" with the contents of "/crowdedFolder/subFolder1/test.txt-0" from "user0" data
+ And the downloaded zip file contains a file named "crowdedFolder/subFolder7/test.txt-5523" with the contents of "/crowdedFolder/subFolder7/test.txt-5523" from "user0" data
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder7/subSubFolder/emptySubSubSubFolder/"
+
+ @large
+ Scenario: downloading dir with 65525 small files and 9 nested directories
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/crowdedFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder1"
+ And file "/crowdedFolder/subFolder1/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder1"
+ And user "user0" created a folder "/crowdedFolder/subFolder2"
+ And file "/crowdedFolder/subFolder2/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder2"
+ And user "user0" created a folder "/crowdedFolder/subFolder3"
+ And file "/crowdedFolder/subFolder3/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder3"
+ And user "user0" created a folder "/crowdedFolder/subFolder4"
+ And file "/crowdedFolder/subFolder4/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder4"
+ And user "user0" created a folder "/crowdedFolder/subFolder5"
+ And file "/crowdedFolder/subFolder5/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder5"
+ And user "user0" created a folder "/crowdedFolder/subFolder6"
+ And file "/crowdedFolder/subFolder6/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder6"
+ And user "user0" created a folder "/crowdedFolder/subFolder7"
+ And file "/crowdedFolder/subFolder7/test.txt" is created "5525" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder7"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/subSubFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/subSubFolder/emptySubSubSubFolder"
+ When user "user0" downloads zip file for entries '"crowdedFolder"' in folder "/"
+ Then the downloaded file is a zip file
+ And the downloaded zip file contains a folder named "crowdedFolder/"
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder1/"
+ And the downloaded zip file contains a file named "crowdedFolder/subFolder1/test.txt-0" with the contents of "/crowdedFolder/subFolder1/test.txt-0" from "user0" data
+ And the downloaded zip file contains a file named "crowdedFolder/subFolder7/test.txt-5524" with the contents of "/crowdedFolder/subFolder7/test.txt-5524" from "user0" data
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder7/subSubFolder/emptySubSubSubFolder/"
+
+ @large
+ Scenario: downloading small file and dir with 65524 small files and 10 nested directories returns a zip64
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/crowdedFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder1"
+ And file "/crowdedFolder/subFolder1/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder1"
+ And user "user0" created a folder "/crowdedFolder/subFolder2"
+ And file "/crowdedFolder/subFolder2/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder2"
+ And user "user0" created a folder "/crowdedFolder/subFolder3"
+ And file "/crowdedFolder/subFolder3/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder3"
+ And user "user0" created a folder "/crowdedFolder/subFolder4"
+ And file "/crowdedFolder/subFolder4/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder4"
+ And user "user0" created a folder "/crowdedFolder/subFolder5"
+ And file "/crowdedFolder/subFolder5/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder5"
+ And user "user0" created a folder "/crowdedFolder/subFolder6"
+ And file "/crowdedFolder/subFolder6/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder6"
+ And user "user0" created a folder "/crowdedFolder/subFolder7"
+ And file "/crowdedFolder/subFolder7/test.txt" is created "5524" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder7"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/subSubFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/subSubFolder/emptySubSubSubFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/emptySubSubFolder"
+ When user "user0" downloads zip file for entries '"welcome.txt","crowdedFolder"' in folder "/"
+ Then the downloaded zip file is a zip64 file
+ And the downloaded zip file contains a file named "welcome.txt" with the contents of "/welcome.txt" from "user0" data
+ And the downloaded zip file contains a folder named "crowdedFolder/"
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder1/"
+ And the downloaded zip file contains a file named "crowdedFolder/subFolder1/test.txt-0" with the contents of "/crowdedFolder/subFolder1/test.txt-0" from "user0" data
+ And the downloaded zip file contains a file named "crowdedFolder/subFolder7/test.txt-5523" with the contents of "/crowdedFolder/subFolder7/test.txt-5523" from "user0" data
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder7/subSubFolder/emptySubSubSubFolder/"
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder7/emptySubSubFolder/"
+
+ @large
+ Scenario: downloading dir with 65525 small files and 10 nested directories returns a zip64
+ Given using new dav path
+ And user "user0" exists
+ And user "user0" created a folder "/crowdedFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder1"
+ And file "/crowdedFolder/subFolder1/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder1"
+ And user "user0" created a folder "/crowdedFolder/subFolder2"
+ And file "/crowdedFolder/subFolder2/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder2"
+ And user "user0" created a folder "/crowdedFolder/subFolder3"
+ And file "/crowdedFolder/subFolder3/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder3"
+ And user "user0" created a folder "/crowdedFolder/subFolder4"
+ And file "/crowdedFolder/subFolder4/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder4"
+ And user "user0" created a folder "/crowdedFolder/subFolder5"
+ And file "/crowdedFolder/subFolder5/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder5"
+ And user "user0" created a folder "/crowdedFolder/subFolder6"
+ And file "/crowdedFolder/subFolder6/test.txt" is created "10000" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder6"
+ And user "user0" created a folder "/crowdedFolder/subFolder7"
+ And file "/crowdedFolder/subFolder7/test.txt" is created "5525" times in "user0" user data
+ And invoking occ with "files:scan --path /user0/files/crowdedFolder/subFolder7"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/subSubFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/subSubFolder/emptySubSubSubFolder"
+ And user "user0" created a folder "/crowdedFolder/subFolder7/emptySubSubFolder"
+ When user "user0" downloads zip file for entries '"crowdedFolder"' in folder "/"
+ Then the downloaded zip file is a zip64 file
+ And the downloaded zip file contains a folder named "crowdedFolder/"
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder1/"
+ And the downloaded zip file contains a file named "crowdedFolder/subFolder1/test.txt-0" with the contents of "/crowdedFolder/subFolder1/test.txt-0" from "user0" data
+ And the downloaded zip file contains a file named "crowdedFolder/subFolder7/test.txt-5524" with the contents of "/crowdedFolder/subFolder7/test.txt-5524" from "user0" data
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder7/subSubFolder/emptySubSubSubFolder/"
+ And the downloaded zip file contains a folder named "crowdedFolder/subFolder7/emptySubSubFolder/"
diff --git a/build/integration/files_features/external-storage.feature b/build/integration/files_features/external-storage.feature
new file mode 100644
index 00000000000..77abeb6c5a4
--- /dev/null
+++ b/build/integration/files_features/external-storage.feature
@@ -0,0 +1,127 @@
+# SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+# SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+# SPDX-License-Identifier: AGPL-3.0-only
+Feature: external-storage
+ Background:
+ Given using api version "1"
+ Given using old dav path
+
+ @local_storage
+ Scenario: Share by link a file inside a local external storage
+ Given user "user0" exists
+ And user "user1" exists
+ And As an "user0"
+ And user "user0" created a folder "/local_storage/foo"
+ And User "user0" moved file "/textfile0.txt" to "/local_storage/foo/textfile0.txt"
+ And folder "/local_storage/foo" of user "user0" is shared with user "user1"
+ And As an "user1"
+ And accepting last share
+ When creating a share with
+ | path | foo |
+ | shareType | 3 |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And Share fields of last share match with
+ | id | A_NUMBER |
+ | url | AN_URL |
+ | token | A_TOKEN |
+ | mimetype | httpd/unix-directory |
+
+ Scenario: Shares don't overwrite external storage
+ Given user "user0" exists
+ And user "user1" exists
+ And As an "user0"
+ And User "user0" moved file "/textfile0.txt" to "/local_storage/textfile0.txt"
+ And invoking occ with "files_external:create --user user0 test local null::null -c datadir=./build/integration/work/local_storage"
+ And invoking occ with "files:scan --path /user0/files/test"
+ And as "user0" the file "/local_storage/textfile0.txt" exists
+ And as "user0" the folder "/test" exists
+ And as "user0" the file "/test/textfile0.txt" exists
+ And As an "user1"
+ And user "user1" created a folder "/test"
+ And User "user1" moved file "/textfile0.txt" to "/test/textfile1.txt"
+ And folder "/test" of user "user1" is shared with user "user0"
+ And As an "user0"
+ Then as "user0" the file "/test/textfile1.txt" does not exist
+
+ Scenario: Move a file into storage works
+ Given user "user0" exists
+ And user "user1" exists
+ And As an "user0"
+ And user "user0" created a folder "/local_storage/foo1"
+ When User "user0" moved file "/textfile0.txt" to "/local_storage/foo1/textfile0.txt"
+ Then as "user1" the file "/local_storage/foo1/textfile0.txt" exists
+ And as "user0" the file "/local_storage/foo1/textfile0.txt" exists
+
+ Scenario: Move a file out of the storage works
+ Given user "user0" exists
+ And user "user1" exists
+ And As an "user0"
+ And user "user0" created a folder "/local_storage/foo2"
+ And User "user0" moved file "/textfile0.txt" to "/local_storage/foo2/textfile0.txt"
+ When User "user1" moved file "/local_storage/foo2/textfile0.txt" to "/local.txt"
+ Then as "user1" the file "/local_storage/foo2/textfile0.txt" does not exist
+ And as "user0" the file "/local_storage/foo2/textfile0.txt" does not exist
+ And as "user1" the file "/local.txt" exists
+
+
+
+ Scenario: Save an external storage with password provided by user
+ Given Logging in using web as "admin"
+ And logged in user creates external global storage
+ | mountPoint | "ExternalStorageTest" |
+ | backend | "owncloud" |
+ | authMechanism | "password::userprovided" |
+ | backendOptions | {"host":"http://localhost:8080","secure":false} |
+ And fields of last external storage match with
+ | status | 2 |
+ When logged in user updates last external userglobal storage
+ | backendOptions | {"user":"admin","password":"admin"} |
+ Then fields of last external storage match with
+ | status | 0 |
+
+ Scenario: Save an external storage again with an unmodified password provided by user
+ Given Logging in using web as "admin"
+ And logged in user creates external global storage
+ | mountPoint | "ExternalStorageTest" |
+ | backend | "owncloud" |
+ | authMechanism | "password::userprovided" |
+ | backendOptions | {"host":"http://localhost:8080","secure":false} |
+ And fields of last external storage match with
+ | status | 2 |
+ And logged in user updates last external userglobal storage
+ | backendOptions | {"user":"admin","password":"admin"} |
+ When logged in user updates last external userglobal storage
+ | backendOptions | {"user":"admin","password":"__unmodified__"} |
+ Then fields of last external storage match with
+ | status | 0 |
+
+ Scenario: Save an external storage with global credentials provided by user
+ Given Logging in using web as "admin"
+ And logged in user creates external global storage
+ | mountPoint | "ExternalStorageTest" |
+ | backend | "owncloud" |
+ | authMechanism | "password::global::user" |
+ | backendOptions | {"host":"http://localhost:8080","secure":false} |
+ And fields of last external storage match with
+ | status | 2 |
+ When logged in user updates last external userglobal storage
+ | backendOptions | {"user":"admin","password":"admin"} |
+ Then fields of last external storage match with
+ | status | 0 |
+
+ Scenario: Save an external storage again with unmodified global credentials provided by user
+ Given Logging in using web as "admin"
+ And logged in user creates external global storage
+ | mountPoint | "ExternalStorageTest" |
+ | backend | "owncloud" |
+ | authMechanism | "password::global::user" |
+ | backendOptions | {"host":"http://localhost:8080","secure":false} |
+ And fields of last external storage match with
+ | status | 2 |
+ And logged in user updates last external userglobal storage
+ | backendOptions | {"user":"admin","password":"admin"} |
+ When logged in user updates last external userglobal storage
+ | backendOptions | {"user":"admin","password":"__unmodified__"} |
+ Then fields of last external storage match with
+ | status | 0 |
diff --git a/build/integration/files_features/favorites.feature b/build/integration/files_features/favorites.feature
new file mode 100644
index 00000000000..8e510799d20
--- /dev/null
+++ b/build/integration/files_features/favorites.feature
@@ -0,0 +1,152 @@
+# SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+# SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+# SPDX-License-Identifier: AGPL-3.0-only
+Feature: favorite
+ Background:
+ Given using api version "1"
+
+ Scenario: Favorite a folder
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/FOLDER"
+ Then as "user0" gets properties of folder "/FOLDER" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "1"
+
+ Scenario: Favorite and unfavorite a folder
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/FOLDER"
+ And user "user0" unfavorites element "/FOLDER"
+ Then as "user0" gets properties of folder "/FOLDER" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "0"
+
+ Scenario: Favorite a file
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/textfile0.txt"
+ Then as "user0" gets properties of file "/textfile0.txt" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "1"
+
+ Scenario: Favorite and unfavorite a file
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/textfile0.txt"
+ And user "user0" unfavorites element "/textfile0.txt"
+ Then as "user0" gets properties of file "/textfile0.txt" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "0"
+
+ Scenario: Favorite a folder new endpoint
+ Given using new dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/FOLDER"
+ Then as "user0" gets properties of folder "/FOLDER" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "1"
+
+ Scenario: Favorite and unfavorite a folder new endpoint
+ Given using new dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/FOLDER"
+ And user "user0" unfavorites element "/FOLDER"
+ Then as "user0" gets properties of folder "/FOLDER" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "0"
+
+ Scenario: Favorite a file new endpoint
+ Given using new dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/textfile0.txt"
+ Then as "user0" gets properties of file "/textfile0.txt" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "1"
+
+ Scenario: Favorite and unfavorite a file new endpoint
+ Given using new dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/textfile0.txt"
+ And user "user0" unfavorites element "/textfile0.txt"
+ Then as "user0" gets properties of file "/textfile0.txt" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "0"
+
+ Scenario: Get favorited elements of a folder
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/FOLDER"
+ And user "user0" favorites element "/textfile0.txt"
+ And user "user0" favorites element "/textfile1.txt"
+ Then user "user0" in folder "/" should have favorited the following elements
+ | /FOLDER |
+ | /textfile0.txt |
+ | /textfile1.txt |
+
+ Scenario: Get favorited elements of a folder using new path
+ Given using new dav path
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/FOLDER"
+ And user "user0" favorites element "/textfile0.txt"
+ And user "user0" favorites element "/textfile1.txt"
+ Then user "user0" in folder "/" should have favorited the following elements
+ | /FOLDER |
+ | /textfile0.txt |
+ | /textfile1.txt |
+
+ Scenario: Get favorited elements of a subfolder
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ And user "user0" created a folder "/subfolder"
+ And User "user0" moves file "/textfile0.txt" to "/subfolder/textfile0.txt"
+ And User "user0" moves file "/textfile1.txt" to "/subfolder/textfile1.txt"
+ And User "user0" moves file "/textfile2.txt" to "/subfolder/textfile2.txt"
+ When user "user0" favorites element "/subfolder/textfile0.txt"
+ And user "user0" favorites element "/subfolder/textfile1.txt"
+ And user "user0" favorites element "/subfolder/textfile2.txt"
+ And user "user0" unfavorites element "/subfolder/textfile1.txt"
+ Then user "user0" in folder "/subfolder" should have favorited the following elements
+ | /subfolder/textfile0.txt |
+ | /subfolder/textfile2.txt |
+
+ Scenario: Get favorited elements of a subfolder using new path
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ And user "user0" created a folder "/subfolder"
+ And User "user0" moves file "/textfile0.txt" to "/subfolder/textfile0.txt"
+ And User "user0" moves file "/textfile1.txt" to "/subfolder/textfile1.txt"
+ And User "user0" moves file "/textfile2.txt" to "/subfolder/textfile2.txt"
+ When user "user0" favorites element "/subfolder/textfile0.txt"
+ And user "user0" favorites element "/subfolder/textfile1.txt"
+ And user "user0" favorites element "/subfolder/textfile2.txt"
+ And user "user0" unfavorites element "/subfolder/textfile1.txt"
+ Then user "user0" in folder "/subfolder" should have favorited the following elements
+ | /subfolder/textfile0.txt |
+ | /subfolder/textfile2.txt |
+
+ Scenario: moving a favorite file out of a share keeps favorite state
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ And user "user1" exists
+ And user "user0" created a folder "/shared"
+ And User "user0" moved file "/textfile0.txt" to "/shared/shared_file.txt"
+ And folder "/shared" of user "user0" is shared with user "user1"
+ And user "user1" accepts last share
+ And user "user1" favorites element "/shared/shared_file.txt"
+ When User "user1" moved file "/shared/shared_file.txt" to "/taken_out.txt"
+ Then user "user1" in folder "/" should have favorited the following elements
+ | /taken_out.txt |
diff --git a/build/integration/files_features/metadata.feature b/build/integration/files_features/metadata.feature
new file mode 100644
index 00000000000..553a7b62306
--- /dev/null
+++ b/build/integration/files_features/metadata.feature
@@ -0,0 +1,16 @@
+# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: AGPL-3.0-only
+Feature: metadata
+
+ Scenario: Setting metadata works
+ Given user "user0" exists
+ When User "user0" uploads file with content "AAA" to "/test.txt"
+ And User "user0" sets the "metadata-files-live-photo" prop with value "metadata-value" on "/test.txt"
+ Then User "user0" should see the prop "metadata-files-live-photo" equal to "metadata-value" for file "/test.txt"
+
+ Scenario: Deleting metadata works
+ Given user "user0" exists
+ When User "user0" uploads file with content "AAA" to "/test.txt"
+ And User "user0" sets the "metadata-files-live-photo" prop with value "metadata-value" on "/test.txt"
+ And User "user0" deletes the "metadata-files-live-photo" prop on "/test.txt"
+ Then User "user0" should not see the prop "metadata-files-live-photo" for file "/test.txt"
diff --git a/build/integration/files_features/tags.feature b/build/integration/files_features/tags.feature
new file mode 100644
index 00000000000..fef8068cbc8
--- /dev/null
+++ b/build/integration/files_features/tags.feature
@@ -0,0 +1,465 @@
+# SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+# SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+# SPDX-License-Identifier: AGPL-3.0-only
+Feature: tags
+
+ Scenario: Creating a normal tag as regular user should work
+ Given user "user0" exists
+ When "user0" creates a "normal" tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "201"
+ And The following tags should exist for "admin"
+ |MySuperAwesomeTagName|true|true|
+ And The following tags should exist for "user0"
+ |MySuperAwesomeTagName|true|true|
+
+ Scenario: Creating a not user-assignable tag as regular user should fail
+ Given user "user0" exists
+ When "user0" creates a "not user-assignable" tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "400"
+ And "0" tags should exist for "admin"
+
+ Scenario: Creating a not user-visible tag as regular user should fail
+ Given user "user0" exists
+ When "user0" creates a "not user-visible" tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "400"
+ And "0" tags should exist for "admin"
+
+ Scenario: Creating a not user-assignable tag with groups as admin should work
+ Given user "user0" exists
+ When "admin" creates a "not user-assignable" tag with name "TagWithGroups" and groups "group1|group2"
+ Then The response should have a status code "201"
+ And The "not user-assignable" tag with name "TagWithGroups" has the groups "group1|group2"
+
+ Scenario: Creating a normal tag with groups as regular user should fail
+ Given user "user0" exists
+ When "user0" creates a "normal" tag with name "MySuperAwesomeTagName" and groups "group1|group2"
+ Then The response should have a status code "400"
+ And "0" tags should exist for "user0"
+
+ Scenario: Renaming a normal tag as regular user should work
+ Given user "user0" exists
+ Given "admin" creates a "normal" tag with name "MySuperAwesomeTagName"
+ When "user0" edits the tag with name "MySuperAwesomeTagName" and sets its name to "AnotherTagName"
+ Then The response should have a status code "207"
+ And The following tags should exist for "admin"
+ |AnotherTagName|true|true|
+
+ Scenario: Renaming a not user-assignable tag as regular user should fail
+ Given user "user0" exists
+ Given "admin" creates a "not user-assignable" tag with name "MySuperAwesomeTagName"
+ When "user0" edits the tag with name "MySuperAwesomeTagName" and sets its name to "AnotherTagName"
+ Then The response should have a status code "403"
+ And The following tags should exist for "admin"
+ |MySuperAwesomeTagName|true|false|
+
+ Scenario: Renaming a not user-visible tag as regular user should fail
+ Given user "user0" exists
+ Given "admin" creates a "not user-visible" tag with name "MySuperAwesomeTagName"
+ When "user0" edits the tag with name "MySuperAwesomeTagName" and sets its name to "AnotherTagName"
+ Then The response should have a status code "404"
+ And The following tags should exist for "admin"
+ |MySuperAwesomeTagName|false|true|
+
+ Scenario: Editing tag groups as admin should work
+ Given user "user0" exists
+ Given "admin" creates a "not user-assignable" tag with name "TagWithGroups" and groups "group1|group2"
+ When "admin" edits the tag with name "TagWithGroups" and sets its groups to "group1|group3"
+ Then The response should have a status code "207"
+ And The "not user-assignable" tag with name "TagWithGroups" has the groups "group1|group3"
+
+ Scenario: Editing tag groups as regular user should fail
+ Given user "user0" exists
+ Given "admin" creates a "not user-assignable" tag with name "TagWithGroups"
+ When "user0" edits the tag with name "TagWithGroups" and sets its groups to "group1|group3"
+ Then The response should have a status code "403"
+
+ Scenario: Deleting a normal tag as regular user should fail
+ Given user "user0" exists
+ Given "admin" creates a "normal" tag with name "MySuperAwesomeTagName"
+ When "user0" deletes the tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "403"
+ And The following tags should exist for "admin"
+ |MySuperAwesomeTagName|true|true|
+
+ Scenario: Deleting a not user-assignable tag as regular user should fail
+ Given user "user0" exists
+ Given "admin" creates a "not user-assignable" tag with name "MySuperAwesomeTagName"
+ When "user0" deletes the tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "403"
+ And The following tags should exist for "admin"
+ |MySuperAwesomeTagName|true|false|
+
+ Scenario: Deleting a not user-visible tag as regular user should fail
+ Given user "user0" exists
+ Given "admin" creates a "not user-visible" tag with name "MySuperAwesomeTagName"
+ When "user0" deletes the tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "404"
+ And The following tags should exist for "admin"
+ |MySuperAwesomeTagName|false|true|
+
+ Scenario: Deleting a normal tag as admin should work
+ Given "admin" creates a "normal" tag with name "MySuperAwesomeTagName"
+ When "admin" deletes the tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "204"
+ And "0" tags should exist for "admin"
+
+ Scenario: Deleting a not user-assignable tag as admin should work
+ Given "admin" creates a "not user-assignable" tag with name "MySuperAwesomeTagName"
+ When "admin" deletes the tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "204"
+ And "0" tags should exist for "admin"
+
+ Scenario: Deleting a not user-visible tag as admin should work
+ Given "admin" creates a "not user-visible" tag with name "MySuperAwesomeTagName"
+ When "admin" deletes the tag with name "MySuperAwesomeTagName"
+ Then The response should have a status code "204"
+ And "0" tags should exist for "admin"
+
+ Scenario: Assigning a normal tag to a file shared by someone else as regular user should work
+ Given user "user0" exists
+ Given user "12345" exists
+ Given "admin" creates a "normal" tag with name "MySuperAwesomeTagName"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | 12345 |
+ | shareType | 0 |
+ Given user "12345" accepts last share
+ When "12345" adds the tag "MySuperAwesomeTagName" to "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "201"
+ And "/myFileToTag.txt" shared by "user0" has the following tags
+ |MySuperAwesomeTagName|
+
+ Scenario: Assigning a normal tag to a file belonging to someone else as regular user should fail
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "normal" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ When "user0" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ When "user1" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "404"
+ And "/myFileToTag.txt" shared by "user0" has the following tags
+ |MyFirstTag|
+
+ Scenario: Assigning a not user-assignable tag to a file shared by someone else as regular user should fail
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "normal" tag with name "MyFirstTag"
+ Given "admin" creates a "not user-assignable" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ When "user0" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ When "user1" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "403"
+ And "/myFileToTag.txt" shared by "user0" has the following tags
+ |MyFirstTag|
+
+ Scenario: Assigning a not user-assignable tag to a file shared by someone else as regular user belongs to tag's groups should work
+ Given user "user0" exists
+ Given user "user1" exists
+ Given group "group1" exists
+ Given user "user1" belongs to group "group1"
+ Given "admin" creates a "not user-assignable" tag with name "MySuperAwesomeTagName" and groups "group1"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ When "user1" adds the tag "MySuperAwesomeTagName" to "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "201"
+ And "/myFileToTag.txt" shared by "user0" has the following tags
+ |MySuperAwesomeTagName|
+
+
+ Scenario: Assigning a not user-visible tag to a file shared by someone else as regular user should fail
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "normal" tag with name "MyFirstTag"
+ Given "admin" creates a "not user-visible" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ When "user0" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ When "user1" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "412"
+ And "/myFileToTag.txt" shared by "user0" has the following tags
+ |MyFirstTag|
+
+ Scenario: Assigning a not user-visible tag to a file shared by someone else as admin user should work
+ Given user "user0" exists
+ Given "admin" creates a "normal" tag with name "MyFirstTag"
+ Given "admin" creates a "not user-visible" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | admin |
+ | shareType | 0 |
+ Given user "admin" accepts last share
+ When "user0" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ When "admin" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "201"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "admin"
+ |MyFirstTag|
+ |MySecondTag|
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MyFirstTag|
+
+ Scenario: Assigning a not user-assignable tag to a file shared by someone else as admin user should worj
+ Given user "user0" exists
+ Given "admin" creates a "normal" tag with name "MyFirstTag"
+ Given "admin" creates a "not user-assignable" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | admin |
+ | shareType | 0 |
+ Given user "admin" accepts last share
+ When "user0" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ When "admin" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "201"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "admin"
+ |MyFirstTag|
+ |MySecondTag|
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MyFirstTag|
+ |MySecondTag|
+
+ Scenario: Unassigning a normal tag from a file shared by someone else as regular user should work
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "normal" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ Given "user0" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ Given "user0" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ When "user1" removes the tag "MyFirstTag" from "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "204"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MySecondTag|
+
+ Scenario: Unassigning a normal tag from a file unshared by someone else as regular user should fail
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "normal" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given "user0" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ Given "user0" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ When "user1" removes the tag "MyFirstTag" from "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "404"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MyFirstTag|
+ |MySecondTag|
+
+ Scenario: Unassigning a not user-visible tag from a file shared by someone else as regular user should fail
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "not user-visible" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | admin |
+ | shareType | 0 |
+ Given user "admin" accepts last share
+ Given "admin" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ Given "user0" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ When "user1" removes the tag "MyFirstTag" from "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "404"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MySecondTag|
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "admin"
+ |MyFirstTag|
+ |MySecondTag|
+
+ Scenario: Unassigning a not user-visible tag from a file shared by someone else as admin should work
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "not user-visible" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | admin |
+ | shareType | 0 |
+ Given user "admin" accepts last share
+ Given "admin" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ Given "user0" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ When "admin" removes the tag "MyFirstTag" from "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "204"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MySecondTag|
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "admin"
+ |MySecondTag|
+
+ Scenario: Unassigning a not user-visible tag from a file unshared by someone else should fail
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "not user-visible" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | admin |
+ | shareType | 0 |
+ Given user "admin" accepts last share
+ Given "admin" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ Given "user0" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ Given As "user0" remove all shares from the file named "/myFileToTag.txt"
+ When "admin" removes the tag "MyFirstTag" from "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "404"
+
+ Scenario: Unassigning a not user-assignable tag from a file shared by someone else as regular user should fail
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "not user-assignable" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | admin |
+ | shareType | 0 |
+ Given user "admin" accepts last share
+ Given "admin" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ Given "user0" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ When "user1" removes the tag "MyFirstTag" from "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "403"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MyFirstTag|
+ |MySecondTag|
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "admin"
+ |MyFirstTag|
+ |MySecondTag|
+
+ Scenario: Unassigning a not user-assignable tag from a file shared by someone else as admin should work
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "not user-assignable" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | admin |
+ | shareType | 0 |
+ Given user "admin" accepts last share
+ Given "admin" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ Given "user0" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ When "admin" removes the tag "MyFirstTag" from "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "204"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MySecondTag|
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "admin"
+ |MySecondTag|
+
+ Scenario: Unassigning a not user-assignable tag from a file unshared by someone else should fail
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "not user-assignable" tag with name "MyFirstTag"
+ Given "admin" creates a "normal" tag with name "MySecondTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ Given user "user1" accepts last share
+ Given as "user0" creating a share with
+ | path | myFileToTag.txt |
+ | shareWith | admin |
+ | shareType | 0 |
+ Given user "admin" accepts last share
+ Given "admin" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ Given "user0" adds the tag "MySecondTag" to "/myFileToTag.txt" shared by "user0"
+ Given As "user0" remove all shares from the file named "/myFileToTag.txt"
+ When "admin" removes the tag "MyFirstTag" from "/myFileToTag.txt" shared by "user0"
+ Then The response should have a status code "404"
+
+ Scenario: Overwriting existing normal tags should fail
+ Given user "user0" exists
+ Given "user0" creates a "normal" tag with name "MyFirstTag"
+ When "user0" creates a "normal" tag with name "MyFirstTag"
+ Then The response should have a status code "409"
+
+ Scenario: Overwriting existing not user-assignable tags should fail
+ Given "admin" creates a "not user-assignable" tag with name "MyFirstTag"
+ When "admin" creates a "not user-assignable" tag with name "MyFirstTag"
+ Then The response should have a status code "409"
+
+ Scenario: Overwriting existing not user-visible tags should fail
+ Given "admin" creates a "not user-visible" tag with name "MyFirstTag"
+ When "admin" creates a "not user-visible" tag with name "MyFirstTag"
+ Then The response should have a status code "409"
+
+ Scenario: Getting tags only works with access to the file
+ Given user "user0" exists
+ Given user "user1" exists
+ Given "admin" creates a "normal" tag with name "MyFirstTag"
+ Given user "user0" uploads file "data/textfile.txt" to "/myFileToTag.txt"
+ When "user0" adds the tag "MyFirstTag" to "/myFileToTag.txt" shared by "user0"
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user0"
+ |MyFirstTag|
+ And "/myFileToTag.txt" shared by "user0" has the following tags for "user1"
+ ||
+ And The response should have a status code "404"
+
+ Scenario: User can assign tags when in the tag's groups
+ Given user "user0" exists
+ Given group "group1" exists
+ Given user "user0" belongs to group "group1"
+ When "admin" creates a "not user-assignable" tag with name "TagWithGroups" and groups "group1|group2"
+ Then The response should have a status code "201"
+ And the user "user0" can assign the "not user-assignable" tag with name "TagWithGroups"
+
+ Scenario: User cannot assign tags when not in the tag's groups
+ Given user "user0" exists
+ When "admin" creates a "not user-assignable" tag with name "TagWithGroups" and groups "group1|group2"
+ Then The response should have a status code "201"
+ And the user "user0" cannot assign the "not user-assignable" tag with name "TagWithGroups"
+
+ Scenario: Assign a normal tag to a file
+ Given user "user0" exists
+ And "admin" creates a "normal" tag with name "Etiqueta"
+ And As an "user0"
+ When "user0" adds the tag "Etiqueta" to "/textfile0.txt" owned by "user0"
+ Then The response should have a status code "201"
+ And "textfile0.txt" owned by "user0" has the following tags
+ | Etiqueta |
+
diff --git a/build/integration/files_features/transfer-ownership.feature b/build/integration/files_features/transfer-ownership.feature
new file mode 100644
index 00000000000..6f7a7944166
--- /dev/null
+++ b/build/integration/files_features/transfer-ownership.feature
@@ -0,0 +1,576 @@
+# SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+# SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+# SPDX-License-Identifier: AGPL-3.0-only
+Feature: transfer-ownership
+
+ Scenario: transferring ownership of a file
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" uploads file "data/textfile.txt" to "/somefile.txt"
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the file "/somefile.txt" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the file "/somefile.txt" exists
+
+ Scenario: transferring ownership of a folder
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+
+ Scenario: transferring ownership from user with risky display name
+ Given user "user0" with displayname "user0 \"risky\"? ヂspḷay 'na|\/|e':.#" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And transfer folder name contains "Transferred from user0 -risky- ヂspḷay -na|-|e- on"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+
+ Scenario: transferring ownership of file shares
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user0" uploads file "data/textfile.txt" to "/somefile.txt"
+ And file "/somefile.txt" of user "user0" is shared with user "user2" with permissions 19
+ And user "user2" accepts last share
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the file "/somefile.txt" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the file "/somefile.txt" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user1 |
+ | uid_file_owner | user1 |
+ | share_with | user2 |
+
+ Scenario: transferring ownership of folder shared with third user
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with user "user2" with permissions 31
+ And user "user2" accepts last share
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user1 |
+ | uid_file_owner | user1 |
+ | share_with | user2 |
+
+ Scenario: transferring ownership of folder shared with transfer recipient
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with user "user1" with permissions 31
+ And user "user1" accepts last share
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ Then as "user1" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And Getting info of last share
+ And the OCS status code should be "404"
+
+ Scenario: transferring ownership of folder doubly shared with third user
+ Given group "group1" exists
+ And user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user2" belongs to group "group1"
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with group "group1" with permissions 31
+ And user "user2" accepts last share
+ And folder "/test" of user "user0" is shared with user "user2" with permissions 31
+ And user "user2" accepts last share
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user1 |
+ | uid_file_owner | user1 |
+ | share_with | user2 |
+
+ Scenario: transferring ownership of file shares to user with the same id as the group
+ Given user "user0" exists
+ And user "test" exists
+ And user "user2" exists
+ And group "test" exists
+ And user "user2" belongs to group "test"
+ And User "user0" uploads file "data/textfile.txt" to "/somefile.txt"
+ And file "/somefile.txt" of user "user0" is shared with group "test"
+ And user "user2" accepts last share
+ When transferring ownership from "user0" to "test"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the file "/somefile.txt" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "test" the file "/somefile.txt" exists
+ And As an "test"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | test |
+ | uid_file_owner | test |
+ | share_with | test |
+
+ Scenario: transferring ownership of folder reshared with another user
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user3" exists
+ And User "user3" created a folder "/test"
+ And User "user3" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user3" is shared with user "user0" with permissions 31
+ And user "user0" accepts last share
+ And folder "/test" of user "user0" is shared with user "user2" with permissions 31
+ And user "user2" accepts last share
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user0 |
+ | uid_file_owner | user3 |
+ | share_with | user2 |
+
+ Scenario: transferring ownership of folder reshared with group to a user in the group
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user3" exists
+ And group "group1" exists
+ And user "user1" belongs to group "group1"
+ And User "user3" created a folder "/test"
+ And User "user3" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user3" is shared with user "user0" with permissions 31
+ And user "user0" accepts last share
+ And folder "/test" of user "user0" is shared with group "group1" with permissions 31
+ And user "user1" accepts last share
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And using old dav path
+ Then as "user0" the folder "/test" does not exist
+ When As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then as "user1" the folder "/test" exists
+ And Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user1 |
+ | uid_file_owner | user3 |
+ | share_with | group1 |
+
+ Scenario: transferring ownership of folder reshared with group to a user not in the group
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user3" exists
+ And group "group1" exists
+ And user "user2" belongs to group "group1"
+ And User "user3" created a folder "/test"
+ And User "user3" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user3" is shared with user "user0" with permissions 31
+ And user "user0" accepts last share
+ And folder "/test" of user "user0" is shared with group "group1" with permissions 31
+ And user "user2" accepts last share
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user0 |
+ | uid_file_owner | user3 |
+ | share_with | group1 |
+
+ Scenario: transferring ownership transfers received shares
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user2" created a folder "/test"
+ And folder "/test" of user "user2" is shared with user "user0" with permissions 31
+ And user "user0" accepts last share
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then as "user1" the folder "/test" exists
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And As an "user2"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user2 |
+ | uid_file_owner | user2 |
+ | share_with | user1 |
+
+ @local_storage
+ Scenario: transferring ownership does not transfer external storage
+ Given user "user0" exists
+ And user "user1" exists
+ When transferring ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then as "user1" the folder "/local_storage" does not exist
+
+ Scenario: transferring ownership does not fail with shared trashed files
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user0" created a folder "/sub"
+ And User "user0" created a folder "/sub/test"
+ And folder "/sub/test" of user "user0" is shared with user "user2" with permissions 31
+ And user "user2" accepts last share
+ And User "user0" deletes folder "/sub"
+ When transferring ownership from "user0" to "user1"
+ Then the command was successful
+
+ Scenario: transferring ownership fails with invalid source user
+ Given user "user0" exists
+ When transferring ownership from "invalid_user" to "user0"
+ Then the command output contains the text "Unknown source user"
+ And the command failed with exit code 1
+
+ Scenario: transferring ownership fails with invalid target user
+ Given user "user0" exists
+ When transferring ownership from "user0" to "invalid_user"
+ Then the command output contains the text "Unknown destination user invalid_user"
+ And the command failed with exit code 1
+
+ Scenario: transferring ownership of a file
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" uploads file "data/textfile.txt" to "/somefile.txt"
+ When transferring ownership of path "somefile.txt" from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the file "/somefile.txt" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the file "/somefile.txt" exists
+
+ Scenario: transferring ownership of a folder
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ When transferring ownership of path "test" from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+
+ Scenario: transferring ownership from user with risky display name
+ Given user "user0" with displayname "user0 \"risky\"? ヂspḷay 'na|\/|e':.#" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ When transferring ownership of path "test" from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And transfer folder name contains "Transferred from user0 -risky- ヂspḷay -na|-|e- on"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+
+ Scenario: transferring ownership of path does not affect other files
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And User "user0" created a folder "/test2"
+ And User "user0" uploads file "data/textfile.txt" to "/test2/somefile.txt"
+ When transferring ownership of path "test" from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And as "user0" the folder "/test2" exists
+ And as "user0" the file "/test2/somefile.txt" exists
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And as "user1" the folder "/test2" does not exist
+
+ Scenario: transferring ownership of path does not affect other shares
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And User "user0" created a folder "/test2"
+ And User "user0" uploads file "data/textfile.txt" to "/test2/sharedfile.txt"
+ And file "/test2/sharedfile.txt" of user "user0" is shared with user "user1" with permissions 19
+ And user "user1" accepts last share
+ When transferring ownership of path "test" from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And as "user0" the folder "/test2" exists
+ And as "user0" the file "/test2/sharedfile.txt" exists
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And as "user1" the folder "/test2" does not exist
+ And using old dav path
+ And as "user1" the file "/sharedfile.txt" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user0 |
+ | uid_file_owner | user0 |
+ | share_with | user1 |
+
+ Scenario: transferring ownership of file shares
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And file "/test/somefile.txt" of user "user0" is shared with user "user2" with permissions 19
+ And user "user2" accepts last share
+ When transferring ownership of path "test" from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user1 |
+ | uid_file_owner | user1 |
+ | share_with | user2 |
+
+ Scenario: transferring ownership of folder shared with third user
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with user "user2" with permissions 31
+ And user "user2" accepts last share
+ When transferring ownership of path "test" from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user1 |
+ | uid_file_owner | user1 |
+ | share_with | user2 |
+
+ Scenario: transferring ownership of folder shared with transfer recipient
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with user "user1" with permissions 31
+ And user "user1" accepts last share
+ When transferring ownership of path "test" from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ Then as "user1" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And Getting info of last share
+ And the OCS status code should be "404"
+
+ Scenario: transferring ownership of folder doubly shared with third user
+ Given group "group1" exists
+ And user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user2" belongs to group "group1"
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with group "group1" with permissions 31
+ And user "user2" accepts last share
+ And folder "/test" of user "user0" is shared with user "user2" with permissions 31
+ And user "user2" accepts last share
+ When transferring ownership of path "test" from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+ And using old dav path
+ And as "user0" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And as "user1" the folder "/test" exists
+ And As an "user1"
+ And Getting info of last share
+ And the OCS status code should be "100"
+ And Share fields of last share match with
+ | uid_owner | user1 |
+ | uid_file_owner | user1 |
+ | share_with | user2 |
+
+ Scenario: transferring ownership of path fails for reshares
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user3" exists
+ And User "user3" created a folder "/test"
+ And User "user3" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user3" is shared with user "user0" with permissions 31
+ And user "user0" accepts last share
+ And folder "/test" of user "user0" is shared with user "user2" with permissions 31
+ And user "user2" accepts last share
+ When transferring ownership of path "test" from "user0" to "user1"
+ Then the command failed with exit code 1
+ And the command error output contains the text "Moving a storage (user0/files/test) into another storage (user1) is not allowed"
+
+ Scenario: transferring ownership transfers received shares into subdir when requested
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user2" created a folder "/transfer-share"
+ And User "user2" created a folder "/do-not-transfer"
+ And User "user0" created a folder "/sub"
+ And folder "/transfer-share" of user "user2" is shared with user "user0" with permissions 31
+ And user "user0" accepts last share
+ And User "user0" moved folder "/transfer-share" to "/sub/transfer-share"
+ And folder "/do-not-transfer" of user "user2" is shared with user "user0" with permissions 31
+ And user "user0" accepts last share
+ When transferring ownership of path "sub" from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then as "user1" the folder "/sub" exists
+ And as "user1" the folder "/do-not-transfer" does not exist
+ And as "user1" the folder "/sub/do-not-transfer" does not exist
+ And as "user1" the folder "/sub/transfer-share" exists
+ And using old dav path
+ And as "user1" the folder "/transfer-share" does not exist
+ And as "user1" the folder "/do-not-transfer" does not exist
+ And using old dav path
+ And as "user0" the folder "/sub" does not exist
+ And as "user0" the folder "/do-not-transfer" exists
+ And Getting info of last share
+ And the OCS status code should be "404"
+
+ Scenario: transferring ownership does not transfer external storage
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/sub"
+ When transferring ownership of path "sub" from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then as "user1" the folder "/local_storage" does not exist
+
+ Scenario: transferring ownership fails with invalid source user
+ Given user "user0" exists
+ And User "user0" created a folder "/sub"
+ When transferring ownership of path "sub" from "invalid_user" to "user0"
+ Then the command output contains the text "Unknown source user"
+ And the command failed with exit code 1
+
+ Scenario: transferring ownership fails with invalid target user
+ Given user "user0" exists
+ And User "user0" created a folder "/sub"
+ When transferring ownership of path "sub" from "user0" to "invalid_user"
+ Then the command output contains the text "Unknown destination user invalid_user"
+ And the command failed with exit code 1
+
+ Scenario: transferring ownership fails with invalid path
+ Given user "user0" exists
+ And user "user1" exists
+ When transferring ownership of path "test" from "user0" to "user1"
+ Then the command output contains the text "Unknown path provided: test"
+ And the command failed with exit code 1
diff --git a/build/integration/files_features/trashbin.feature b/build/integration/files_features/trashbin.feature
new file mode 100644
index 00000000000..fd84e396ba3
--- /dev/null
+++ b/build/integration/files_features/trashbin.feature
@@ -0,0 +1,84 @@
+# SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+# SPDX-FileCopyrightText: 2017 ownCloud, Inc.
+# SPDX-License-Identifier: AGPL-3.0-only
+Feature: trashbin
+ Background:
+ Given using api version "1"
+ And using new dav path
+ And As an "admin"
+ And app "files_trashbin" is enabled
+
+ Scenario: deleting a file moves it to trashbin
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" deletes file "/textfile0.txt"
+ Then user "user0" in trash folder "/" should have 1 element
+ And user "user0" in trash folder "/" should have the following elements
+ | textfile0.txt |
+
+ Scenario: clearing the trashbin
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" deletes file "/textfile0.txt"
+ And User "user0" empties trashbin
+ Then user "user0" in trash folder "/" should have 0 elements
+
+ Scenario: restoring file from trashbin
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" deletes file "/textfile0.txt"
+ And user "user0" in restores "/textfile0.txt" from trash
+ Then user "user0" in trash folder "/" should have 0 elements
+ And as "user0" the file "/textfile0.txt" exists
+
+ Scenario: deleting and restoring a folder
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" created a folder "/testfolder"
+ And User "user0" moves file "/textfile0.txt" to "/testfolder/textfile0.txt"
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+ And User "user0" deletes file "/testfolder"
+ And user "user0" in trash folder "/" should have 1 element
+ And user "user0" in trash folder "/" should have the following elements
+ | testfolder |
+ And user "user0" in trash folder "/testfolder" should have 1 element
+ And user "user0" in trash folder "/testfolder" should have the following elements
+ | textfile0.txt |
+ And user "user0" in restores "/testfolder" from trash
+ Then user "user0" in trash folder "/" should have 0 elements
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+
+ Scenario: deleting a file from a subfolder and restoring it moves it back to the subfolder
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" created a folder "/testfolder"
+ And User "user0" moves file "/textfile0.txt" to "/testfolder/textfile0.txt"
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+ And User "user0" deletes file "/testfolder/textfile0.txt"
+ And user "user0" in trash folder "/" should have 1 element
+ And user "user0" in trash folder "/" should have the following elements
+ | textfile0.txt |
+ And user "user0" in restores "/textfile0.txt" from trash
+ Then user "user0" in trash folder "/" should have 0 elements
+ And as "user0" the file "/textfile0.txt" does not exist
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+
+ Scenario: deleting and a folder and restoring a file inside it
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" created a folder "/testfolder"
+ And User "user0" moves file "/textfile0.txt" to "/testfolder/textfile0.txt"
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+ And User "user0" deletes file "/testfolder"
+ And user "user0" in trash folder "/" should have 1 element
+ And user "user0" in trash folder "/" should have the following elements
+ | testfolder |
+ And user "user0" in trash folder "/testfolder" should have 1 element
+ And user "user0" in trash folder "/testfolder" should have the following elements
+ | textfile0.txt |
+ And user "user0" in restores "/testfolder/textfile0.txt" from trash
+ Then user "user0" in trash folder "/" should have 1 elements
+ And user "user0" in trash folder "/testfolder" should have 0 element
+ And as "user0" the file "/textfile0.txt" exists
+
+
diff --git a/build/integration/files_features/windows_compatibility.feature b/build/integration/files_features/windows_compatibility.feature
new file mode 100644
index 00000000000..feaaca1ed3a
--- /dev/null
+++ b/build/integration/files_features/windows_compatibility.feature
@@ -0,0 +1,68 @@
+# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+Feature: Windows compatible filenames
+ Background:
+ Given using api version "1"
+ And using new dav path
+ And As an "admin"
+
+ Scenario: prevent upload files with invalid name
+ Given As an "admin"
+ And user "user0" exists
+ And invoking occ with "files:windows-compatible-filenames --enable"
+ Given User "user0" created a folder "/com1"
+ Then as "user0" the file "/com1" does not exist
+
+ Scenario: renaming a folder with invalid name
+ Given As an "admin"
+ When invoking occ with "files:windows-compatible-filenames --disable"
+ And user "user0" exists
+ Given User "user0" created a folder "/aux"
+ When invoking occ with "files:windows-compatible-filenames --enable"
+ And invoking occ with "files:sanitize-filenames user0"
+ Then as "user0" the file "/aux" does not exist
+ And as "user0" the file "/aux (renamed)" exists
+
+ Scenario: renaming a file with invalid base name
+ Given As an "admin"
+ When invoking occ with "files:windows-compatible-filenames --disable"
+ And user "user0" exists
+ When User "user0" uploads file with content "hello" to "/com0.txt"
+ And invoking occ with "files:windows-compatible-filenames --enable"
+ And invoking occ with "files:sanitize-filenames user0"
+ Then as "user0" the file "/com0.txt" does not exist
+ And as "user0" the file "/com0 (renamed).txt" exists
+
+ Scenario: renaming a file with invalid extension
+ Given As an "admin"
+ When invoking occ with "files:windows-compatible-filenames --disable"
+ And user "user0" exists
+ When User "user0" uploads file with content "hello" to "/foo.txt."
+ And as "user0" the file "/foo.txt." exists
+ And invoking occ with "files:windows-compatible-filenames --enable"
+ And invoking occ with "files:sanitize-filenames user0"
+ Then as "user0" the file "/foo.txt." does not exist
+ And as "user0" the file "/foo.txt" exists
+
+ Scenario: renaming a file with invalid character
+ Given As an "admin"
+ When invoking occ with "files:windows-compatible-filenames --disable"
+ And user "user0" exists
+ When User "user0" uploads file with content "hello" to "/2*2=4.txt"
+ And as "user0" the file "/2*2=4.txt" exists
+ And invoking occ with "files:windows-compatible-filenames --enable"
+ And invoking occ with "files:sanitize-filenames user0"
+ Then as "user0" the file "/2*2=4.txt" does not exist
+ And as "user0" the file "/2_2=4.txt" exists
+
+ Scenario: renaming a file with invalid character and replacement setup
+ Given As an "admin"
+ When invoking occ with "files:windows-compatible-filenames --disable"
+ And user "user0" exists
+ When User "user0" uploads file with content "hello" to "/2*3=6.txt"
+ And as "user0" the file "/2*3=6.txt" exists
+ And invoking occ with "files:windows-compatible-filenames --enable"
+ And invoking occ with "files:sanitize-filenames --char-replacement + user0"
+ Then as "user0" the file "/2*3=6.txt" does not exist
+ And as "user0" the file "/2+3=6.txt" exists