Skip to content

Commit

Permalink
Merge pull request #34046 from owncloud/webdavHelperPROPPATCH
Browse files Browse the repository at this point in the history
use WebDavHelper to set & retrieve custom properties
  • Loading branch information
phil-davis authored Jan 7, 2019
2 parents da55d26 + 04eee87 commit 884e7f6
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 68 deletions.
95 changes: 78 additions & 17 deletions tests/TestHelpers/WebDavHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public static function getFileIdForPath(
* @param string[] $properties
* string can contain namespace prefix,
* if no prefix is given 'd:' is used as prefix
* if associated array is used then the key will be used as namespace
* @param int $folderDepth
* @param string $type
* @param int $davPathVersionToUse
Expand All @@ -104,28 +105,88 @@ public static function propfind(
$type = "files",
$davPathVersionToUse = 2
) {
$headers = ['Depth' => $folderDepth];
$body = '<?xml version="1.0"?>
<d:propfind
xmlns:d="DAV:"
xmlns:oc="http://owncloud.org/ns"
xmlns:ocs="http://open-collaboration-services.org/ns">
<d:prop>';
foreach ($properties as $property) {
//if no namespace is given in the property add the default one
if (\strpos($property, ":") === false) {
$property = "d:$property";
$propertyBody = "";
$extraNamespaces = "";
foreach ($properties as $namespaceString => $property) {
if (\is_int($namespaceString)) {
//default namespace prefix if the property has no array key
//also used if no prefix is given in the property value
$namespacePrefix = "d";
} else {
//calculate the namespace prefix and namespace from the array key
$matches = [];
\preg_match("/^(.*)='(.*)'$/", $namespaceString, $matches);
$nameSpace = $matches[2];
$namespacePrefix = $matches[1];
$extraNamespaces .= " xmlns:$namespacePrefix=\"$nameSpace\" ";
}
//if a namespace prefix is given in the property value use that
if (\strpos($property, ":") !== false) {
$propertyParts = \explode(":", $property);
$namespacePrefix = $propertyParts[0];
$property = $propertyParts[1];
}
$body .= "<$property/>";
$propertyBody .= "<$namespacePrefix:$property/>";
}

$body .= '</d:prop></d:propfind>';

$response = self::makeDavRequest(
$headers = ['Depth' => $folderDepth];
$body = "<?xml version=\"1.0\"?>
<d:propfind
xmlns:d=\"DAV:\"
xmlns:oc=\"http://owncloud.org/ns\"
xmlns:ocs=\"http://open-collaboration-services.org/ns\"
$extraNamespaces>
<d:prop>$propertyBody</d:prop>
</d:propfind>";
return self::makeDavRequest(
$baseUrl, $user, $password, "PROPFIND", $path, $headers, $body,
null, $davPathVersionToUse, $type
);
return $response;
}

/**
*
* @param string $baseUrl
* @param string $user
* @param string $password
* @param string $path
* @param string $propertyName
* @param string $propertyValue
* @param string $namespaceString string containing prefix and namespace
* e.g "x1='http://whatever.org/ns'"
* @param number $davPathVersionToUse
*
* @return ResponseInterface
*/
public static function proppatch(
$baseUrl,
$user,
$password,
$path,
$propertyName,
$propertyValue,
$namespaceString,
$davPathVersionToUse = 2
) {
$matches = [];
\preg_match("/^(.*)='(.*)'$/", $namespaceString, $matches);
$namespace = $matches[2];
$namespacePrefix = $matches[1];
$propertyBody = "<$namespacePrefix:$propertyName" .
" xmlns:$namespacePrefix=\"$namespace\">" .
"$propertyValue" .
"</$namespacePrefix:$propertyName>";
$body = "<?xml version=\"1.0\"?>
<d:propertyupdate xmlns:d=\"DAV:\"
xmlns:oc=\"http://owncloud.org/ns\">
<d:set>
<d:prop>$propertyBody</d:prop>
</d:set>
</d:propertyupdate>";

return self::makeDavRequest(
$baseUrl, $user, $password, "PROPPATCH", $path, [], $body,
null, $davPathVersionToUse
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,22 @@ Feature: set file properties
Scenario Outline: Setting custom DAV property and reading it
Given using <dav_version> DAV path
And user "user0" has uploaded file "filesForUpload/textfile.txt" to "/testcustomprop.txt"
And user "user0" has set property "{http://whatever.org/ns}very-custom-prop" of file "/testcustomprop.txt" to "veryCustomPropValue"
When user "user0" gets a custom property "{http://whatever.org/ns}very-custom-prop" of file "/testcustomprop.txt"
Then the response should contain a custom "{http://whatever.org/ns}very-custom-prop" property with "veryCustomPropValue"
And user "user0" has set property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testcustomprop.txt" to "veryCustomPropValue"
When user "user0" gets a custom property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testcustomprop.txt"
Then the response should contain a custom "very-custom-prop" property with namespace "x1='http://whatever.org/ns'" and value "veryCustomPropValue"
Examples:
| dav_version |
| old |
| new |

@skip @issue-32670
@issue-32670
Scenario Outline: Setting custom complex DAV property and reading it
Given using <dav_version> DAV path
And user "user0" has uploaded file "filesForUpload/textfile.txt" to "/testcustomprop.txt"
And user "user0" has set property "{http://whatever.org/ns}very-custom-prop" of file "/testcustomprop.txt" to complex "<foo xmlns='http://bar'/>"
When user "user0" gets a custom property "{http://whatever.org/ns}very-custom-prop" of file "/testcustomprop.txt"
Then the response should contain a custom "{http://whatever.org/ns}very-custom-prop" property with "<foo xmlns='http://bar'/>"
And user "user0" has set property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testcustomprop.txt" to "<foo xmlns='http://bar'/>"
When user "user0" gets a custom property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testcustomprop.txt"
Then the response should contain a custom "very-custom-prop" property with namespace "x1='http://whatever.org/ns'" and value "Object"
#Then the response should contain a custom "very-custom-prop" property with namespace "x1='http://whatever.org/ns'" and value "<foo xmlns='http://bar'/>"
Examples:
| dav_version |
| old |
Expand All @@ -35,10 +36,10 @@ Feature: set file properties
Scenario Outline: Setting custom DAV property and reading it after the file is renamed
Given using <dav_version> DAV path
And user "user0" has uploaded file "filesForUpload/textfile.txt" to "/testcustompropwithmove.txt"
And user "user0" has set property "{http://whatever.org/ns}very-custom-prop" of file "/testcustompropwithmove.txt" to "valueForMovetest"
And user "user0" has set property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testcustompropwithmove.txt" to "valueForMovetest"
And user "user0" has moved file "/testcustompropwithmove.txt" to "/catchmeifyoucan.txt"
When user "user0" gets a custom property "{http://whatever.org/ns}very-custom-prop" of file "/catchmeifyoucan.txt"
Then the response should contain a custom "{http://whatever.org/ns}very-custom-prop" property with "valueForMovetest"
When user "user0" gets a custom property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/catchmeifyoucan.txt"
Then the response should contain a custom "very-custom-prop" property with namespace "x1='http://whatever.org/ns'" and value "valueForMovetest"
Examples:
| dav_version |
| old |
Expand All @@ -53,9 +54,9 @@ Feature: set file properties
| shareType | 0 |
| permissions | 31 |
| shareWith | user1 |
And user "user0" has set property "{http://whatever.org/ns}very-custom-prop" of file "/testcustompropshared.txt" to "valueForSharetest"
When user "user1" gets a custom property "{http://whatever.org/ns}very-custom-prop" of file "/testcustompropshared.txt"
Then the response should contain a custom "{http://whatever.org/ns}very-custom-prop" property with "valueForSharetest"
And user "user0" has set property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testcustompropshared.txt" to "valueForSharetest"
When user "user1" gets a custom property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testcustompropshared.txt"
Then the response should contain a custom "very-custom-prop" property with namespace "x1='http://whatever.org/ns'" and value "valueForSharetest"
Examples:
| dav_version |
| old |
Expand All @@ -64,10 +65,10 @@ Feature: set file properties
Scenario Outline: Setting custom DAV property using one endpoint and reading it with other endpoint
Given using <action_dav_version> DAV path
And user "user0" has uploaded file "filesForUpload/textfile.txt" to "/testnewold.txt"
And user "user0" has set property "{http://whatever.org/ns}very-custom-prop" of file "/testnewold.txt" to "lucky"
And user "user0" has set property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testnewold.txt" to "lucky"
And using <other_dav_version> DAV path
When user "user0" gets a custom property "{http://whatever.org/ns}very-custom-prop" of file "/testnewold.txt"
Then the response should contain a custom "{http://whatever.org/ns}very-custom-prop" property with "lucky"
When user "user0" gets a custom property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testnewold.txt"
Then the response should contain a custom "very-custom-prop" property with namespace "x1='http://whatever.org/ns'" and value "lucky"
Examples:
| action_dav_version | other_dav_version |
| old | new |
Expand All @@ -76,7 +77,7 @@ Feature: set file properties
Scenario: Setting custom DAV property using an old endpoint and reading it using a new endpoint
Given using old DAV path
Given user "user0" has uploaded file "filesForUpload/textfile.txt" to "/testoldnew.txt"
And user "user0" has set property "{http://whatever.org/ns}very-custom-prop" of file "/testoldnew.txt" to "constant"
And user "user0" has set property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testoldnew.txt" to "constant"
And using new DAV path
When user "user0" gets a custom property "{http://whatever.org/ns}very-custom-prop" of file "/testoldnew.txt"
Then the response should contain a custom "{http://whatever.org/ns}very-custom-prop" property with "constant"
When user "user0" gets a custom property "very-custom-prop" with namespace "x1='http://whatever.org/ns'" of file "/testoldnew.txt"
Then the response should contain a custom "very-custom-prop" property with namespace "x1='http://whatever.org/ns'" and value "constant"
78 changes: 46 additions & 32 deletions tests/acceptance/features/bootstrap/WebDav.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@
use GuzzleHttp\Stream\StreamInterface;
use Guzzle\Http\Exception\BadResponseException;
use Sabre\DAV\Client as SClient;
use Sabre\DAV\Xml\Property\ResourceType;
use TestHelpers\OcsApiHelper;
use TestHelpers\SetupHelper;
use TestHelpers\UploadHelper;
use TestHelpers\WebDavHelper;
use TestHelpers\HttpRequestHelper;
use Sabre\DAV\Xml\Property\Complex;
use TestHelpers\Asserts\WebDav as WebDavAssert;

require __DIR__ . '/../../../../lib/composer/autoload.php';
Expand Down Expand Up @@ -999,70 +997,86 @@ public function theUserGetsPropertiesOfFolder($path, $propertiesTable) {
}

/**
* @When user :user gets a custom property :propertyName of file :path
* @When user :user gets a custom property :propertyName with namespace :namespace of file :path
*
* @param string $user
* @param string $propertyName
* @param string $namespace namespace in form of "x1='http://whatever.org/ns'"
* @param string $path
*
* @return void
*/
public function userGetsPropertiesOfFile($user, $propertyName, $path) {
$client = $this->getSabreClient($user);
public function userGetsPropertiesOfFile($user, $propertyName, $namespace, $path) {
$properties = [
$propertyName
$namespace => $propertyName
];
$this->response = $client->propfind(
$this->makeSabrePath($user, $path), $properties
$this->response = WebDavHelper::propfind(
$this->getBaseUrl(),
$this->getActualUsername($user),
$this->getUserPassword($user), $path,
$properties
);
}

/**
* @When /^user "([^"]*)" sets property "([^"]*)" of (?:file|folder|entry) "([^"]*)" to\s?(complex|) "([^"]*)" using the WebDAV API$/
* @Given /^user "([^"]*)" has set property "([^"]*)" of (?:file|folder|entry) "([^"]*)" to\s?(complex|) "([^"]*)"$/
* @When /^user "([^"]*)" sets property "([^"]*)" with namespace "([^"]*)" of (?:file|folder|entry) "([^"]*)" to "([^"]*)" using the WebDAV API$/
* @Given /^user "([^"]*)" has set property "([^"]*)" with namespace "([^"]*)" of (?:file|folder|entry) "([^"]*)" to "([^"]*)"$/
*
* @param string $user user id who sets the property
* @param string $propertyName name of property in Clark notation
* @param string $namespace namespace in form of "x1='http://whatever.org/ns'"
* @param string $path path on which to set properties to
* @param string $complex if set to "complex", will parse the property value with the Complex type
* @param string $propertyValue property value
*
* @return void
*/
public function userHasSetPropertyOfEntryTo(
$user, $propertyName, $path, $complex, $propertyValue
public function userHasSetPropertyWithNamespaceOfEntryTo(
$user, $propertyName, $namespace, $path, $propertyValue
) {
$client = $this->getSabreClient($user);
if ($complex === 'complex') {
$propertyValue = new Complex($propertyValue);
}
$properties = [
$propertyName => $propertyValue
];
$client->proppatch($this->makeSabrePath($user, $path), $properties);
WebDavHelper::proppatch(
$this->getBaseUrl(),
$this->getActualUsername($user),
$this->getUserPassword($user), $path,
$propertyName, $propertyValue, $namespace,
$this->getDavPathVersion()
);
}

/**
* @Then /^the response should contain a custom "([^"]*)" property with "([^"]*)"$/
* @Then /^the response should contain a custom "([^"]*)" property with namespace "([^"]*)" and value "([^"]*)"$/
*
* @param string $propertyName
* @param string $namespaceString
* @param string $propertyValue
*
* @return void
* @throws \Exception
*/
public function theResponseShouldContainACustomPropertyWithValue(
$propertyName, $propertyValue
$propertyName, $namespaceString, $propertyValue
) {
$keys = $this->response;
if (!\array_key_exists($propertyName, $keys)) {
throw new \Exception("Cannot find property \"$propertyName\"");
}
if ($keys[$propertyName] !== $propertyValue) {
throw new \Exception(
"\"$propertyName\" has a value \"${keys[$propertyName]}\" but \"$propertyValue\" expected"
);
}
$this->responseXmlObject = HttpRequestHelper::getResponseXml(
$this->response
);
//calculate the namespace prefix and namespace
$matches = [];
\preg_match("/^(.*)='(.*)'$/", $namespaceString, $matches);
$nameSpace = $matches[2];
$nameSpacePrefix = $matches[1];
$this->responseXmlObject->registerXPathNamespace(
$nameSpacePrefix, $nameSpace
);
$xmlPart = $this->responseXmlObject->xpath(
"//d:prop/" . "$nameSpacePrefix:$propertyName"
);
PHPUnit_Framework_Assert::assertArrayHasKey(
0, $xmlPart, "Cannot find property \"$propertyName\""
);
PHPUnit_Framework_Assert::assertEquals(
$propertyValue, $xmlPart[0]->__toString(),
"\"$propertyName\" has a value \"" .
$xmlPart[0]->__toString() . "\" but \"$propertyValue\" expected"
);
}

/**
Expand Down

0 comments on commit 884e7f6

Please sign in to comment.