diff --git a/build/integration/features/bootstrap/TagsContext.php b/build/integration/features/bootstrap/TagsContext.php index 10d0b9ae54..882f5d9e13 100644 --- a/build/integration/features/bootstrap/TagsContext.php +++ b/build/integration/features/bootstrap/TagsContext.php @@ -97,28 +97,36 @@ class TagsContext implements \Behat\Behat\Context\Context { } /** - * @When :user creates a :type tag with name :name * @param string $user * @param string $type * @param string $name - * @throws \Exception + * @param string $groups */ - public function createsATagWithName($user, $type, $name) { - $userVisible = 'true'; - $userAssignable = 'true'; + private function createTag($user, $type, $name, $groups = null) { + $userVisible = true; + $userAssignable = true; switch ($type) { case 'normal': break; case 'not user-assignable': - $userAssignable = 'false'; + $userAssignable = false; break; case 'not user-visible': - $userVisible = 'false'; + $userVisible = false; break; default: throw new \Exception('Unsupported type'); } + $body = [ + 'name' => $name, + 'userVisible' => $userVisible, + 'userAssignable' => $userAssignable, + ]; + if ($groups !== null) { + $body['groups'] = $groups; + } + try { $this->response = $this->client->post( $this->baseUrl . '/remote.php/dav/systemtags/', @@ -130,14 +138,37 @@ class TagsContext implements \Behat\Behat\Context\Context { 'headers' => [ 'Content-Type' => 'application/json', ], - 'body' => '{"name":"'.$name.'","userVisible":'.$userVisible.',"userAssignable":'.$userAssignable.'}', + 'body' => json_encode($body) ] ); - } catch (\GuzzleHttp\Exception\ClientException $e){ + } catch (\GuzzleHttp\Exception\ClientException $e) { $this->response = $e->getResponse(); } } + /** + * @When :user creates a :type tag with name :name + * @param string $user + * @param string $type + * @param string $name + * @throws \Exception + */ + public function createsATagWithName($user, $type, $name) { + $this->createTag($user, $type, $name); + } + + /** + * @When :user creates a :type tag with name :name and groups :groups + * @param string $user + * @param string $type + * @param string $name + * @param string $groups + * @throws \Exception + */ + public function createsATagWithNameAndGroups($user, $type, $name, $groups) { + $this->createTag($user, $type, $name, $groups); + } + /** * @Then The response should have a status code :statusCode * @param int $statusCode @@ -155,21 +186,30 @@ class TagsContext implements \Behat\Behat\Context\Context { * @param string $user * @return array */ - private function requestTagsForUser($user) { + private function requestTagsForUser($user, $withGroups = false) { try { - $request = $this->client->createRequest( - 'PROPFIND', - $this->baseUrl . '/remote.php/dav/systemtags/', - [ - 'body' => ' + $body = ' - + + +'; + + if ($withGroups) { + $body .= ''; + } + + $body .= ' -', +'; + $request = $this->client->createRequest( + 'PROPFIND', + $this->baseUrl . '/remote.php/dav/systemtags/', + [ + 'body' => $body, 'auth' => [ $user, $this->getPasswordForUser($user), @@ -193,11 +233,16 @@ class TagsContext implements \Behat\Behat\Context\Context { continue; } + // FIXME: use actual property names instead of guessing index position $tags[$singleEntry[0]['value']] = [ 'display-name' => $singleEntry[1]['value'], 'user-visible' => $singleEntry[2]['value'], 'user-assignable' => $singleEntry[3]['value'], + 'can-assign' => $singleEntry[4]['value'], ]; + if (isset($singleEntry[5])) { + $tags[$singleEntry[0]['value']]['groups'] = $singleEntry[5]['value']; + } } return $tags; @@ -238,6 +283,42 @@ class TagsContext implements \Behat\Behat\Context\Context { } } + /** + * @Then the user :user :can assign The :type tag with name :tagName + */ + public function theUserCanAssignTheTag($user, $can, $type, $tagName) { + $foundTag = $this->findTag($type, $tagName, $user); + if ($foundTag === null) { + throw new \Exception('No matching tag found'); + } + + if ($can === 'can') { + $expected = 'true'; + } else if ($can === 'cannot') { + $expected = 'false'; + } else { + throw new \Exception('Invalid condition, must be "can" or "cannot"'); + } + + if ($foundTag['can-assign'] !== $expected) { + throw new \Exception('Tag cannot be assigned by user'); + } + } + + /** + * @Then The :type tag with name :tagName has the groups :groups + */ + public function theTagHasGroup($type, $tagName, $groups) { + $foundTag = $this->findTag($type, $tagName, 'admin', true); + if ($foundTag === null) { + throw new \Exception('No matching tag found'); + } + + if ($foundTag['groups'] !== $groups) { + throw new \Exception('Tag has groups "' . $foundTag['group'] . '" instead of the expected "' . $groups . '"'); + } + } + /** * @Then :count tags should exist for :user * @param int $count @@ -250,6 +331,45 @@ class TagsContext implements \Behat\Behat\Context\Context { } } + /** + * Find tag by type and name + * + * @param string $type tag type + * @param string $tagName tag name + * @param string $user retrieved from which user + * @param bool $withGroups whether to also query the tag's groups + * + * @return array tag values or null if not found + */ + private function findTag($type, $tagName, $user = 'admin', $withGroups = false) { + $tags = $this->requestTagsForUser($user, $withGroups); + $userAssignable = 'true'; + $userVisible = 'true'; + switch ($type) { + case 'normal': + break; + case 'not user-assignable': + $userAssignable = 'false'; + break; + case 'not user-visible': + $userVisible = 'false'; + break; + default: + throw new \Exception('Unsupported type'); + } + + $foundTag = null; + foreach ($tags as $tag) { + if ($tag['display-name'] === $tagName + && $tag['user-visible'] === $userVisible + && $tag['user-assignable'] === $userAssignable) { + $foundTag = $tag; + break; + } + } + return $foundTag; + } + /** * @param string $name * @return int @@ -304,6 +424,44 @@ class TagsContext implements \Behat\Behat\Context\Context { } } + /** + * @When :user edits the tag with name :oldNmae and sets its groups to :groups + * @param string $user + * @param string $oldName + * @param string $groups + * @throws \Exception + */ + public function editsTheTagWithNameAndSetsItsGroupsTo($user, $oldName, $groups) { + $tagId = $this->findTagIdByName($oldName); + if($tagId === 0) { + throw new \Exception('Could not find tag to rename'); + } + + try { + $request = $this->client->createRequest( + 'PROPPATCH', + $this->baseUrl . '/remote.php/dav/systemtags/' . $tagId, + [ + 'body' => ' + + + + ' . $groups . ' + + +', + 'auth' => [ + $user, + $this->getPasswordForUser($user), + ], + ] + ); + $this->response = $this->client->send($request); + } catch (\GuzzleHttp\Exception\ClientException $e) { + $this->response = $e->getResponse(); + } + } + /** * @When :user deletes the tag with name :name * @param string $user diff --git a/build/integration/features/tags.feature b/build/integration/features/tags.feature index 286fb62bf4..d793c0d3c6 100644 --- a/build/integration/features/tags.feature +++ b/build/integration/features/tags.feature @@ -21,6 +21,18 @@ Feature: tags 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" @@ -45,6 +57,19 @@ Feature: tags 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 work Given user "user0" exists Given "admin" creates a "normal" tag with name "MySuperAwesomeTagName" @@ -122,6 +147,23 @@ Feature: tags 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" sending "POST" to "/apps/files_sharing/api/v1/shares" with + | path | myFileToTag.txt | + | shareWith | user1 | + | shareType | 0 | + 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 @@ -368,3 +410,18 @@ Feature: tags 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" + diff --git a/build/jsdocs9.tar.bz2 b/build/jsdocs9.tar.bz2 new file mode 100644 index 0000000000..dfab675733 Binary files /dev/null and b/build/jsdocs9.tar.bz2 differ