diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml
index 42f5f88ac8a7..a87d4fe44c6c 100644
--- a/build/integration/config/behat.yml
+++ b/build/integration/config/behat.yml
@@ -12,6 +12,8 @@ default:
- admin
- admin
regular_user_password: 123456
+ - CommentsContext:
+ baseUrl: http://localhost:8080
federation:
paths:
- %paths.base%/../federation_features
diff --git a/build/integration/features/bootstrap/CommentsContext.php b/build/integration/features/bootstrap/CommentsContext.php
new file mode 100644
index 000000000000..ccd43ff6cb73
--- /dev/null
+++ b/build/integration/features/bootstrap/CommentsContext.php
@@ -0,0 +1,242 @@
+
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see
+ *
+ */
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+class CommentsContext implements \Behat\Behat\Context\Context {
+ /** @var string */
+ private $baseUrl;
+ /** @var array */
+ private $response;
+ /** @var int */
+ private $commentId;
+ /** @var int */
+ private $fileId;
+
+ /**
+ * @param string $baseUrl
+ */
+ public function __construct($baseUrl) {
+ $this->baseUrl = $baseUrl;
+
+ // in case of ci deployment we take the server url from the environment
+ $testServerUrl = getenv('TEST_SERVER_URL');
+ if ($testServerUrl !== false) {
+ $this->baseUrl = substr($testServerUrl, 0, -5);
+ }
+ }
+
+ /**
+ * @return int
+ */
+ private function getFileIdForPath($path) {
+ $url = $this->baseUrl.'/remote.php/webdav/'.$path;
+ $context = stream_context_create(array(
+ 'http' => array(
+ 'method' => 'PROPFIND',
+ 'header' => "Authorization: Basic dXNlcjA6MTIzNDU2\r\nContent-Type: application/x-www-form-urlencoded",
+ 'content' => '
+
+
+
+
+'
+ )
+ ));
+
+ $response = file_get_contents($url, false, $context);
+ preg_match_all('/\(.*)\<\/oc:fileid\>/', $response, $matches);
+ return (int)$matches[1][0];
+ }
+
+ /**
+ * @When :user posts a comment with content :content on the file named :fileName it should return :statusCode
+ */
+ public function postsACommentWithContentOnTheFileNamedItShouldReturn($user, $content, $fileName, $statusCode) {
+ $fileId = $this->getFileIdForPath($fileName);
+ $this->fileId = (int)$fileId;
+ $url = $this->baseUrl.'/remote.php/dav/comments/files/'.$fileId.'/';
+
+ $client = new \GuzzleHttp\Client();
+ try {
+ $res = $client->post(
+ $url,
+ [
+ 'body' => '{"actorId":"user0","actorDisplayName":"user0","actorType":"users","verb":"comment","message":"' . $content . '","creationDateTime":"Thu, 18 Feb 2016 17:04:18 GMT","objectType":"files"}',
+ 'auth' => [
+ $user,
+ '123456',
+ ],
+ 'headers' => [
+ 'Content-Type' => 'application/json',
+ ],
+ ]
+ );
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ $res = $e->getResponse();
+ }
+
+ if($res->getStatusCode() !== (int)$statusCode) {
+ throw new \Exception("Response status code was not $statusCode (".$res->getStatusCode().")");
+ }
+ }
+
+
+ /**
+ * @Then As :user load all the comments of the file named :fileName it should return :statusCode
+ */
+ public function asLoadloadAllTheCommentsOfTheFileNamedItShouldReturn($user, $fileName, $statusCode) {
+ $fileId = $this->getFileIdForPath($fileName);
+ $url = $this->baseUrl.'/remote.php/dav/comments/files/'.$fileId.'/';
+
+ try {
+ $client = new \GuzzleHttp\Client();
+ $res = $client->createRequest(
+ 'REPORT',
+ $url,
+ [
+ 'body' => '
+
+ 200
+ 0
+
+',
+ 'auth' => [
+ $user,
+ '123456',
+ ],
+ 'headers' => [
+ 'Content-Type' => 'application/json',
+ ],
+ ]
+ );
+ $res = $client->send($res);
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ $res = $e->getResponse();
+ }
+
+ if($res->getStatusCode() !== (int)$statusCode) {
+ throw new \Exception("Response status code was not $statusCode (".$res->getStatusCode().")");
+ }
+
+ if($res->getStatusCode() === 207) {
+ $service = new Sabre\Xml\Service();
+ $this->response = $service->parse($res->getBody()->getContents());
+ $this->commentId = (int)$this->response[0]['value'][2]['value'][0]['value'][0]['value'];
+ }
+ }
+
+ /**
+ * @Given As :user sending :verb to :url with
+ */
+ public function asUserSendingToWith($user, $verb, $url, \Behat\Gherkin\Node\TableNode $body) {
+ $client = new \GuzzleHttp\Client();
+ $options = [];
+ $options['auth'] = [$user, '123456'];
+ $fd = $body->getRowsHash();
+ $options['body'] = $fd;
+ $client->send($client->createRequest($verb, $this->baseUrl.'/ocs/v1.php/'.$url, $options));
+ }
+
+ /**
+ * @Then As :user delete the created comment it should return :statusCode
+ */
+ public function asDeleteTheCreatedCommentItShouldReturn($user, $statusCode) {
+ $url = $this->baseUrl.'/remote.php/dav/comments/files/'.$this->fileId.'/'.$this->commentId;
+
+ $client = new \GuzzleHttp\Client();
+ try {
+ $res = $client->delete(
+ $url,
+ [
+ 'auth' => [
+ $user,
+ '123456',
+ ],
+ 'headers' => [
+ 'Content-Type' => 'application/json',
+ ],
+ ]
+ );
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ $res = $e->getResponse();
+ }
+
+ if($res->getStatusCode() !== (int)$statusCode) {
+ throw new \Exception("Response status code was not $statusCode (".$res->getStatusCode().")");
+ }
+ }
+
+ /**
+ * @Then the response should contain a property :key with value :value
+ */
+ public function theResponseShouldContainAPropertyWithValue($key, $value) {
+ $keys = $this->response[0]['value'][2]['value'][0]['value'];
+ $found = false;
+ foreach($keys as $singleKey) {
+ if($singleKey['name'] === '{http://owncloud.org/ns}'.substr($key, 3)) {
+ if($singleKey['value'] === $value) {
+ $found = true;
+ }
+ }
+ }
+ if($found === false) {
+ throw new \Exception("Cannot find property $key with $value");
+ }
+ }
+
+ /**
+ * @Then the response should contain only :number comments
+ */
+ public function theResponseShouldContainOnlyComments($number) {
+ if(count($this->response) !== (int)$number) {
+ throw new \Exception("Found more comments than $number (".count($this->response).")");
+ }
+ }
+
+ /**
+ * @Then As :user edit the last created comment and set text to :text it should return :statusCode
+ */
+ public function asEditTheLastCreatedCommentAndSetTextToItShouldReturn($user, $text, $statusCode) {
+ $client = new \GuzzleHttp\Client();
+ $options = [];
+ $options['auth'] = [$user, '123456'];
+ $options['body'] = '
+
+
+
+ '.$text.'
+
+
+';
+ try {
+ $res = $client->send($client->createRequest('PROPPATCH', $this->baseUrl.'/remote.php/dav/comments/files/' . $this->fileId . '/' . $this->commentId, $options));
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ $res = $e->getResponse();
+ }
+
+ if($res->getStatusCode() !== (int)$statusCode) {
+ throw new \Exception("Response status code was not $statusCode (".$res->getStatusCode().")");
+ }
+ }
+
+
+}
diff --git a/build/integration/features/bootstrap/Sharing.php b/build/integration/features/bootstrap/Sharing.php
index 5103b4af5085..faf8e0bf5075 100644
--- a/build/integration/features/bootstrap/Sharing.php
+++ b/build/integration/features/bootstrap/Sharing.php
@@ -370,5 +370,49 @@ public function checkShareFields($body){
}
}
+ /**
+ * @Then As :user remove all shares from the file named :fileName
+ */
+ public function asRemoveAllSharesFromTheFileNamed($user, $fileName) {
+ $url = $this->baseUrl.'v2.php/apps/files_sharing/api/v1/shares?format=json';
+ $client = new \GuzzleHttp\Client();
+ $res = $client->get(
+ $url,
+ [
+ 'auth' => [
+ $user,
+ '123456',
+ ],
+ 'headers' => [
+ 'Content-Type' => 'application/json',
+ ],
+ ]
+ );
+ $json = json_decode($res->getBody()->getContents(), true);
+ $deleted = false;
+ foreach($json['ocs']['data'] as $data) {
+ if (stripslashes($data['path']) === $fileName) {
+ $id = $data['id'];
+ $client->delete(
+ $this->baseUrl.'v2.php/apps/files_sharing/api/v1/shares/'.$id,
+ [
+ 'auth' => [
+ $user,
+ '123456',
+ ],
+ 'headers' => [
+ 'Content-Type' => 'application/json',
+ ],
+ ]
+ );
+ $deleted = true;
+ }
+ }
+
+ if($deleted === false) {
+ throw new \Exception("Could not delete file $fileName");
+ }
+ }
+
}
diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php
index 49cd565cf265..58fdfed17119 100644
--- a/build/integration/features/bootstrap/WebDav.php
+++ b/build/integration/features/bootstrap/WebDav.php
@@ -9,8 +9,7 @@
require __DIR__ . '/../../vendor/autoload.php';
-trait WebDav{
-
+trait WebDav {
/** @var string*/
private $davPath = "remote.php/webdav";
@@ -162,6 +161,18 @@ public function userUploadsAFileTo($user, $source, $destination)
}
}
+ /**
+ * @When User :user deletes file :file
+ */
+ public function userDeletesFile($user, $file) {
+ try {
+ $this->response = $this->makeDavRequest($user, 'DELETE', $file, []);
+ } catch (\GuzzleHttp\Exception\ServerException $e) {
+ // 4xx and 5xx responses cause an exception
+ $this->response = $e->getResponse();
+ }
+ }
+
/**
* @Given User :user created a folder :destination
*/
diff --git a/build/integration/features/comments.feature b/build/integration/features/comments.feature
new file mode 100644
index 000000000000..10b451249144
--- /dev/null
+++ b/build/integration/features/comments.feature
@@ -0,0 +1,228 @@
+Feature: comments
+ Scenario: Creating a comment on a file belonging to myself
+ Given user "user0" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And "User0" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user0"
+ And the response should contain only "1" comments
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Creating a comment on a shared file belonging to another user
+ Given user "user0" exists
+ Given user "user1" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
+ | path | myFileToComment.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ And "user1" posts a comment with content "A comment from another user" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "A comment from another user"
+ And the response should contain a property "oc:actorDisplayName" with value "user1"
+ And the response should contain only "1" comments
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Creating a comment on a non-shared file belonging to another user
+ Given user "user0" exists
+ Given user "user1" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ When "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "404"
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Reading comments on a non-shared file belonging to another user
+ Given user "user0" exists
+ Given user "user1" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "404"
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Deleting my own comments on a file belonging to myself
+ Given user "user0" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And "User0" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user0"
+ And the response should contain only "1" comments
+ Then As "user0" delete the created comment it should return "204"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain only "0" comments
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Deleting my own comments on a file shared by somebody else
+ Given user "user0" exists
+ Given user "user1" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
+ | path | myFileToComment.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ And "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user1"
+ And the response should contain only "1" comments
+ Then As "user1" delete the created comment it should return "204"
+ Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain only "0" comments
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Deleting my own comments on a file unshared by someone else
+ Given user "user0" exists
+ Given user "user1" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
+ | path | myFileToComment.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ And "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user1"
+ And the response should contain only "1" comments
+ And As "user0" remove all shares from the file named "/myFileToComment.txt"
+ Then As "user1" delete the created comment it should return "404"
+ Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "404"
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Edit my own comments on a file belonging to myself
+ Given user "user0" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And "User0" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user0"
+ And the response should contain only "1" comments
+ Then As "user0" edit the last created comment and set text to "My edited comment" it should return "207"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My edited comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user0"
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Edit my own comments on a file shared by someone with me
+ Given user "user0" exists
+ Given user "user1" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
+ | path | myFileToComment.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ And "User1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user1"
+ And the response should contain only "1" comments
+ Then As "user1" edit the last created comment and set text to "My edited comment" it should return "207"
+ Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My edited comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user1"
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Edit my own comments on a file unshared by someone with me
+ Given user "user0" exists
+ Given user "user1" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
+ | path | myFileToComment.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ And "User1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user1"
+ And the response should contain only "1" comments
+ And As "user0" remove all shares from the file named "/myFileToComment.txt"
+ Then As "user1" edit the last created comment and set text to "My edited comment" it should return "404"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user1"
+ Then User "user0" deletes file "/myFileToComment.txt"
+
+ Scenario: Edit comments of other users should not be possible
+ Given user "user0" exists
+ Given user "user1" exists
+ And As an "user0"
+ And User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
+ And As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
+ | path | myFileToComment.txt |
+ | shareWith | user1 |
+ | shareType | 0 |
+ And "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
+ Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
+ And the response should contain a property "oc:parentId" with value "0"
+ And the response should contain a property "oc:childrenCount" with value "0"
+ And the response should contain a property "oc:verb" with value "comment"
+ And the response should contain a property "oc:actorType" with value "users"
+ And the response should contain a property "oc:objectType" with value "files"
+ And the response should contain a property "oc:message" with value "My first comment"
+ And the response should contain a property "oc:actorDisplayName" with value "user1"
+ And the response should contain only "1" comments
+ Then As "user0" edit the last created comment and set text to "My edited comment" it should return "403"
+ Then User "user0" deletes file "/myFileToComment.txt"
\ No newline at end of file