CommentsContext.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. require __DIR__ . '/../../vendor/autoload.php';
  8. class CommentsContext implements \Behat\Behat\Context\Context {
  9. /** @var string */
  10. private $baseUrl;
  11. /** @var array */
  12. private $response;
  13. /** @var int */
  14. private $commentId;
  15. /** @var int */
  16. private $fileId;
  17. /**
  18. * @param string $baseUrl
  19. */
  20. public function __construct($baseUrl) {
  21. $this->baseUrl = $baseUrl;
  22. // in case of ci deployment we take the server url from the environment
  23. $testServerUrl = getenv('TEST_SERVER_URL');
  24. if ($testServerUrl !== false) {
  25. $this->baseUrl = substr($testServerUrl, 0, -5);
  26. }
  27. }
  28. /**
  29. * get a named entry from response instead of picking a random entry from values
  30. *
  31. * @param string $path
  32. *
  33. * @return array|string
  34. * @throws Exception
  35. */
  36. private function getValueFromNamedEntries(string $path, array $response): mixed {
  37. $next = '';
  38. if (str_contains($path, ' ')) {
  39. [$key, $next] = explode(' ', $path, 2);
  40. } else {
  41. $key = $path;
  42. }
  43. foreach ($response as $entry) {
  44. if ($entry['name'] === $key) {
  45. if ($next !== '') {
  46. return $this->getValueFromNamedEntries($next, $entry['value']);
  47. } else {
  48. return $entry['value'];
  49. }
  50. }
  51. }
  52. return null;
  53. }
  54. /** @AfterScenario */
  55. public function teardownScenario() {
  56. $client = new \GuzzleHttp\Client();
  57. try {
  58. $client->delete(
  59. $this->baseUrl . '/remote.php/webdav/myFileToComment.txt',
  60. [
  61. 'auth' => [
  62. 'user0',
  63. '123456',
  64. ],
  65. 'headers' => [
  66. 'Content-Type' => 'application/json',
  67. ],
  68. ]
  69. );
  70. } catch (\GuzzleHttp\Exception\ClientException $e) {
  71. $e->getResponse();
  72. }
  73. }
  74. /**
  75. * @param string $path
  76. * @return int
  77. */
  78. private function getFileIdForPath($path) {
  79. $url = $this->baseUrl . '/remote.php/webdav/' . $path;
  80. $context = stream_context_create([
  81. 'http' => [
  82. 'method' => 'PROPFIND',
  83. 'header' => "Authorization: Basic dXNlcjA6MTIzNDU2\r\nContent-Type: application/x-www-form-urlencoded",
  84. 'content' => '<?xml version="1.0"?>
  85. <d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
  86. <d:prop>
  87. <oc:fileid />
  88. </d:prop>
  89. </d:propfind>'
  90. ]
  91. ]);
  92. $response = file_get_contents($url, false, $context);
  93. preg_match_all('/\<oc:fileid\>(.*)\<\/oc:fileid\>/', $response, $matches);
  94. return (int)$matches[1][0];
  95. }
  96. /**
  97. * @When :user posts a comment with content :content on the file named :fileName it should return :statusCode
  98. * @param string $user
  99. * @param string $content
  100. * @param string $fileName
  101. * @param int $statusCode
  102. * @throws \Exception
  103. */
  104. public function postsACommentWithContentOnTheFileNamedItShouldReturn($user, $content, $fileName, $statusCode) {
  105. $fileId = $this->getFileIdForPath($fileName);
  106. $this->fileId = (int)$fileId;
  107. $url = $this->baseUrl . '/remote.php/dav/comments/files/' . $fileId . '/';
  108. $client = new \GuzzleHttp\Client();
  109. try {
  110. $res = $client->post(
  111. $url,
  112. [
  113. 'body' => '{"actorId":"user0","actorDisplayName":"user0","actorType":"users","verb":"comment","message":"' . $content . '","creationDateTime":"Thu, 18 Feb 2016 17:04:18 GMT","objectType":"files"}',
  114. 'auth' => [
  115. $user,
  116. '123456',
  117. ],
  118. 'headers' => [
  119. 'Content-Type' => 'application/json',
  120. ],
  121. ]
  122. );
  123. } catch (\GuzzleHttp\Exception\ClientException $e) {
  124. $res = $e->getResponse();
  125. }
  126. if ($res->getStatusCode() !== (int)$statusCode) {
  127. throw new \Exception("Response status code was not $statusCode (" . $res->getStatusCode() . ')');
  128. }
  129. }
  130. /**
  131. * @Then As :user load all the comments of the file named :fileName it should return :statusCode
  132. * @param string $user
  133. * @param string $fileName
  134. * @param int $statusCode
  135. * @throws \Exception
  136. */
  137. public function asLoadloadAllTheCommentsOfTheFileNamedItShouldReturn($user, $fileName, $statusCode) {
  138. $fileId = $this->getFileIdForPath($fileName);
  139. $url = $this->baseUrl . '/remote.php/dav/comments/files/' . $fileId . '/';
  140. try {
  141. $client = new \GuzzleHttp\Client();
  142. $res = $client->request(
  143. 'REPORT',
  144. $url,
  145. [
  146. 'body' => '<?xml version="1.0" encoding="utf-8" ?>
  147. <oc:filter-comments xmlns:oc="http://owncloud.org/ns">
  148. <oc:limit>200</oc:limit>
  149. <oc:offset>0</oc:offset>
  150. </oc:filter-comments>
  151. ',
  152. 'auth' => [
  153. $user,
  154. '123456',
  155. ],
  156. 'headers' => [
  157. 'Content-Type' => 'application/json',
  158. ],
  159. ]
  160. );
  161. } catch (\GuzzleHttp\Exception\ClientException $e) {
  162. $res = $e->getResponse();
  163. }
  164. if ($res->getStatusCode() !== (int)$statusCode) {
  165. throw new \Exception("Response status code was not $statusCode (" . $res->getStatusCode() . ')');
  166. }
  167. if ($res->getStatusCode() === 207) {
  168. $service = new Sabre\Xml\Service();
  169. $this->response = $service->parse($res->getBody()->getContents());
  170. $this->commentId = (int)($this->getValueFromNamedEntries('{DAV:}response {DAV:}propstat {DAV:}prop {http://owncloud.org/ns}id', $this->response ?? []) ?? 0);
  171. }
  172. }
  173. /**
  174. * @Given As :user sending :verb to :url with
  175. * @param string $user
  176. * @param string $verb
  177. * @param string $url
  178. * @param \Behat\Gherkin\Node\TableNode $body
  179. * @throws \Exception
  180. */
  181. public function asUserSendingToWith($user, $verb, $url, \Behat\Gherkin\Node\TableNode $body) {
  182. $client = new \GuzzleHttp\Client();
  183. $options = [];
  184. $options['auth'] = [$user, '123456'];
  185. $fd = $body->getRowsHash();
  186. $options['form_params'] = $fd;
  187. $options['headers'] = [
  188. 'OCS-APIREQUEST' => 'true',
  189. ];
  190. $client->request($verb, $this->baseUrl . '/ocs/v1.php/' . $url, $options);
  191. }
  192. /**
  193. * @Then As :user delete the created comment it should return :statusCode
  194. * @param string $user
  195. * @param int $statusCode
  196. * @throws \Exception
  197. */
  198. public function asDeleteTheCreatedCommentItShouldReturn($user, $statusCode) {
  199. $url = $this->baseUrl . '/remote.php/dav/comments/files/' . $this->fileId . '/' . $this->commentId;
  200. $client = new \GuzzleHttp\Client();
  201. try {
  202. $res = $client->delete(
  203. $url,
  204. [
  205. 'auth' => [
  206. $user,
  207. '123456',
  208. ],
  209. 'headers' => [
  210. 'Content-Type' => 'application/json',
  211. ],
  212. ]
  213. );
  214. } catch (\GuzzleHttp\Exception\ClientException $e) {
  215. $res = $e->getResponse();
  216. }
  217. if ($res->getStatusCode() !== (int)$statusCode) {
  218. throw new \Exception("Response status code was not $statusCode (" . $res->getStatusCode() . ')');
  219. }
  220. }
  221. /**
  222. * @Then the response should contain a property :key with value :value
  223. * @param string $key
  224. * @param string $value
  225. * @throws \Exception
  226. */
  227. public function theResponseShouldContainAPropertyWithValue($key, $value) {
  228. // $keys = $this->response[0]['value'][1]['value'][0]['value'];
  229. $keys = $this->getValueFromNamedEntries('{DAV:}response {DAV:}propstat {DAV:}prop', $this->response);
  230. $found = false;
  231. foreach ($keys as $singleKey) {
  232. if ($singleKey['name'] === '{http://owncloud.org/ns}' . substr($key, 3)) {
  233. if ($singleKey['value'] === $value) {
  234. $found = true;
  235. }
  236. }
  237. }
  238. if ($found === false) {
  239. throw new \Exception("Cannot find property $key with $value");
  240. }
  241. }
  242. /**
  243. * @Then the response should contain only :number comments
  244. * @param int $number
  245. * @throws \Exception
  246. */
  247. public function theResponseShouldContainOnlyComments($number) {
  248. $count = 0;
  249. if ($this->response !== null) {
  250. $count = count($this->response);
  251. }
  252. if ($count !== (int)$number) {
  253. throw new \Exception("Found more comments than $number (" . $count . ')');
  254. }
  255. }
  256. /**
  257. * @Then As :user edit the last created comment and set text to :text it should return :statusCode
  258. * @param string $user
  259. * @param string $text
  260. * @param int $statusCode
  261. * @throws \Exception
  262. */
  263. public function asEditTheLastCreatedCommentAndSetTextToItShouldReturn($user, $text, $statusCode) {
  264. $client = new \GuzzleHttp\Client();
  265. $options = [];
  266. $options['auth'] = [$user, '123456'];
  267. $options['body'] = '<?xml version="1.0"?>
  268. <d:propertyupdate xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
  269. <d:set>
  270. <d:prop>
  271. <oc:message>' . $text . '</oc:message>
  272. </d:prop>
  273. </d:set>
  274. </d:propertyupdate>';
  275. try {
  276. $res = $client->request('PROPPATCH', $this->baseUrl . '/remote.php/dav/comments/files/' . $this->fileId . '/' . $this->commentId, $options);
  277. } catch (\GuzzleHttp\Exception\ClientException $e) {
  278. $res = $e->getResponse();
  279. }
  280. if ($res->getStatusCode() !== (int)$statusCode) {
  281. throw new \Exception("Response status code was not $statusCode (" . $res->getStatusCode() . ')');
  282. }
  283. }
  284. }