You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1036 lines
28 KiB
1036 lines
28 KiB
<?php
|
|
|
|
/**
|
|
*
|
|
* @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
|
|
*
|
|
* @license GNU AGPL version 3 or any later version
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* 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
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
use Behat\Behat\Context\Context;
|
|
use Behat\Gherkin\Node\TableNode;
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Cookie\CookieJar;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
class SharingContext implements Context {
|
|
|
|
/** @var string */
|
|
private $baseUrl = '';
|
|
|
|
/** @var ResponseInterface */
|
|
private $response = null;
|
|
|
|
/** @var string */
|
|
private $currentUser = '';
|
|
|
|
/** @var string */
|
|
private $regularUserPassword;
|
|
|
|
/** @var \SimpleXMLElement */
|
|
private $lastCreatedShareData = null;
|
|
|
|
public function __construct(string $baseUrl, array $admin, string $regularUserPassword) {
|
|
$this->baseUrl = $baseUrl;
|
|
$this->adminUser = $admin;
|
|
$this->regularUserPassword = $regularUserPassword;
|
|
|
|
// in case of ci deployment we take the server url from the environment
|
|
$testServerUrl = getenv('TEST_SERVER_URL');
|
|
if ($testServerUrl !== false) {
|
|
$this->baseUrl = $testServerUrl;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Given user :user creates folder :destination
|
|
*
|
|
* @param string $user
|
|
* @param string $destination
|
|
*/
|
|
public function userCreatesFolder($user, $destination) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = "/$user/$destination/";
|
|
|
|
$this->sendingToDav('MKCOL', $url);
|
|
|
|
$this->theHTTPStatusCodeShouldBe(201);
|
|
}
|
|
|
|
/**
|
|
* @Given user :user moves file :source to :destination
|
|
*
|
|
* @param string $user
|
|
* @param string $source
|
|
* @param string $destination
|
|
*/
|
|
public function userMovesFileTo(string $user, string $source, string $destination) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = "/$user/$source";
|
|
|
|
$headers = [];
|
|
$headers['Destination'] = $this->baseUrl . "remote.php/dav/files/$user/" . $destination;
|
|
|
|
$this->sendingToDav('MOVE', $url, $headers);
|
|
}
|
|
|
|
/**
|
|
* @Given user :user moves file :source to :destination with :statusCode
|
|
*
|
|
* @param string $user
|
|
* @param string $source
|
|
* @param string $destination
|
|
* @param int statusCode
|
|
*/
|
|
public function userMovesFileToWith(string $user, string $source, string $destination, int $statusCode) {
|
|
$this->userMovesFileTo($user, $source, $destination);
|
|
$this->theHTTPStatusCodeShouldBe($statusCode);
|
|
}
|
|
|
|
/**
|
|
* @Given user :user deletes file :file
|
|
*
|
|
* @param string $user
|
|
* @param string $file
|
|
*/
|
|
public function userDeletesFile($user, $file) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = "/$user/$file";
|
|
|
|
$this->sendingToDav('DELETE', $url);
|
|
|
|
$this->theHTTPStatusCodeShouldBe(204);
|
|
}
|
|
|
|
/**
|
|
* @When user :user shares :path with user :sharee
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param string $sharee
|
|
* @param TableNode|null $body
|
|
*/
|
|
public function userSharesWithUser(string $user, string $path, string $sharee, TableNode $body = null) {
|
|
$this->userSharesWith($user, $path, 0 /*IShare::TYPE_USER*/, $sharee, $body);
|
|
}
|
|
|
|
/**
|
|
* @When user :user shares :path with user :sharee with OCS :statusCode
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param string $sharee
|
|
* @param int $statusCode
|
|
*/
|
|
public function userSharesWithUserWithOcs(string $user, string $path, string $sharee, int $statusCode) {
|
|
$this->userSharesWithUser($user, $path, $sharee);
|
|
$this->theOCSStatusCodeShouldBe($statusCode);
|
|
}
|
|
|
|
/**
|
|
* @When user :user shares :path with group :sharee
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param string $sharee
|
|
* @param TableNode|null $body
|
|
*/
|
|
public function userSharesWithGroup(string $user, string $path, string $sharee, TableNode $body = null) {
|
|
$this->userSharesWith($user, $path, 1 /*IShare::TYPE_GROUP*/, $sharee, $body);
|
|
}
|
|
|
|
/**
|
|
* @When user :user shares :path with group :sharee with OCS :statusCode
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param string $sharee
|
|
* @param int $statusCode
|
|
*/
|
|
public function userSharesWithGroupWithOcs(string $user, string $path, string $sharee, int $statusCode) {
|
|
$this->userSharesWithGroup($user, $path, $sharee);
|
|
$this->theOCSStatusCodeShouldBe($statusCode);
|
|
}
|
|
|
|
/**
|
|
* @When user :user shares :path with room :room
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param string $room
|
|
* @param TableNode|null $body
|
|
*/
|
|
public function userSharesWithRoom(string $user, string $path, string $room, TableNode $body = null) {
|
|
$this->userSharesWith($user, $path, 10 /*IShare::TYPE_ROOM*/, FeatureContext::getTokenForIdentifier($room), $body);
|
|
}
|
|
|
|
/**
|
|
* @When user :user shares :path with room :room with OCS :statusCode
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param string $room
|
|
* @param int $statusCode
|
|
*/
|
|
public function userSharesWithRoomWithOcs(string $user, string $path, string $room, int $statusCode) {
|
|
$this->userSharesWithRoom($user, $path, $room);
|
|
$this->theOCSStatusCodeShouldBe($statusCode);
|
|
}
|
|
|
|
/**
|
|
* @When user :user shares :path by link
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param TableNode|null $body
|
|
*/
|
|
public function userSharesByLink(string $user, string $path, TableNode $body = null) {
|
|
$this->userSharesWith($user, $path, 3 /*IShare::TYPE_LINK*/, '', $body);
|
|
}
|
|
|
|
/**
|
|
* @When user :user shares :path by link with OCS :statusCode
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param int $statusCode
|
|
* @param TableNode|null $body
|
|
*/
|
|
public function userSharesByLinkWithOcs(string $user, string $path, int $statusCode, TableNode $body = null) {
|
|
$this->userSharesByLink($user, $path, $body);
|
|
$this->theOCSStatusCodeShouldBe($statusCode);
|
|
}
|
|
|
|
/**
|
|
* @When user :user updates last share with
|
|
*
|
|
* @param string $user
|
|
* @param TableNode $body
|
|
*/
|
|
public function userUpdatesLastShareWith(string $user, TableNode $body) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares/' . $this->getLastShareId();
|
|
|
|
$this->sendingTo('PUT', $url, $body);
|
|
}
|
|
|
|
/**
|
|
* @When user :user deletes last share
|
|
*
|
|
* @param string $user
|
|
*/
|
|
public function userDeletesLastShare(string $user) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares/' . $this->getLastShareId();
|
|
|
|
$this->sendingTo('DELETE', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user deletes last share with OCS :statusCode
|
|
*
|
|
* @param string $user
|
|
* @param int $statusCode
|
|
*/
|
|
public function userDeletesLastShareWithOcs(string $user, int $statusCode) {
|
|
$this->userDeletesLastShare($user);
|
|
$this->theOCSStatusCodeShouldBe($statusCode);
|
|
}
|
|
|
|
/**
|
|
* @When user :user restores last share
|
|
*
|
|
* @param string $user
|
|
*/
|
|
public function userRestoresLastShareWithOcs(string $user) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/deletedshares/ocRoomShare:' . $this->getLastShareId();
|
|
|
|
$this->sendingTo('POST', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets last share
|
|
*/
|
|
public function userGetsLastShare(string $user) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares/' . $this->getLastShareId();
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user accepts last share
|
|
*
|
|
* @param string $user
|
|
*/
|
|
public function userAcceptsLastShare(string $user) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares/pending/' . $this->getLastShareId();
|
|
|
|
$this->sendingTo('POST', $url);
|
|
|
|
$this->theHTTPStatusCodeShouldBe(200);
|
|
$this->theOCSStatusCodeShouldBe(100);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets all shares
|
|
*
|
|
* @param string $user
|
|
*/
|
|
public function userGetsAllShares(string $user) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares';
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets all shares and reshares
|
|
*
|
|
* @param string $user
|
|
*/
|
|
public function userGetsAllSharesAndReshares(string $user) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares?reshares=true';
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets all shares for :path
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
*/
|
|
public function userGetsAllSharesFor(string $user, string $path) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares?path=' . $path;
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets all shares and reshares for :path
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
*/
|
|
public function userGetsAllSharesAndResharesFor(string $user, string $path) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares?reshares=true&path=' . $path;
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets all shares for :path and its subfiles
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
*/
|
|
public function userGetsAllSharesForAndItsSubfiles(string $user, string $path) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares?subfiles=true&path=' . $path;
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets all received shares
|
|
*
|
|
* @param string $user
|
|
*/
|
|
public function userGetsAllReceivedShares(string $user) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares?shared_with_me=true';
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets all received shares for :path
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
*/
|
|
public function userGetsAllReceivedSharesFor(string $user, string $path) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares?shared_with_me=true&path=' . $path;
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets deleted shares
|
|
*
|
|
* @param string $user
|
|
*/
|
|
public function userGetsDeletedShares(string $user) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/deletedshares';
|
|
|
|
$this->sendingTo('GET', $url);
|
|
}
|
|
|
|
/**
|
|
* @When /^user "([^"]*)" gets sharees for$/
|
|
*
|
|
* @param string $user
|
|
* @param TableNode $body
|
|
*/
|
|
public function userGetsShareesFor(string $user, TableNode $body) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/sharees';
|
|
|
|
$parameters = [];
|
|
$parameters[] = 'shareType=10'; // IShare::TYPE_ROOM,
|
|
$parameters[] = 'itemType=file';
|
|
foreach ($body->getRowsHash() as $key => $value) {
|
|
$parameters[] = $key . '=' . $value;
|
|
}
|
|
|
|
$url .= '?' . implode('&', $parameters);
|
|
|
|
$this->sendingTo('GET', $url);
|
|
|
|
\PHPUnit\Framework\Assert::assertEquals(200, $this->response->getStatusCode());
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets the DAV properties for :path
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
*/
|
|
public function userGetsTheDavPropertiesFor(string $user, string $path) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = "/$user/$path";
|
|
|
|
$this->sendingToDav('PROPFIND', $url);
|
|
|
|
$this->theHTTPStatusCodeShouldBe(207);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets the share-type DAV property for :path
|
|
*
|
|
* @param string $user
|
|
* @param string $path
|
|
*/
|
|
public function userGetsTheShareTypeDavPropertyFor(string $user, string $path) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = "/$user/$path";
|
|
|
|
$headers = null;
|
|
|
|
$body = '<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">' .
|
|
' <d:prop>' .
|
|
' <oc:share-types/>' .
|
|
' </d:prop>' .
|
|
'</d:propfind>';
|
|
|
|
$this->sendingToDav('PROPFIND', $url, $headers, $body);
|
|
|
|
$this->theHTTPStatusCodeShouldBe(207);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets recent files
|
|
*
|
|
* @param string $user
|
|
*/
|
|
public function userGetsRecentFiles(string $user) {
|
|
// Recents endpoint is not an OCS endpoint, so a request token must be
|
|
// provided.
|
|
list($requestToken, $cookieJar) = $this->loggingInUsingWebAs($user);
|
|
|
|
$url = '/index.php/apps/files/api/v1/recent';
|
|
|
|
$this->sendingToWithRequestToken('GET', $url, $requestToken, $cookieJar);
|
|
}
|
|
|
|
/**
|
|
* @When transfering ownership from :user1 to :user2
|
|
*
|
|
* @param string $user1
|
|
* @param string $user2
|
|
*/
|
|
public function transferingOwnershipFromTo(string $user1, string $user2) {
|
|
$args = ['files:transfer-ownership', $user1, $user2];
|
|
|
|
$args = array_map(function ($arg) {
|
|
return escapeshellarg($arg);
|
|
}, $args);
|
|
$args[] = '--no-ansi';
|
|
$args = implode(' ', $args);
|
|
|
|
$descriptor = [
|
|
0 => ['pipe', 'r'],
|
|
1 => ['pipe', 'w'],
|
|
2 => ['pipe', 'w'],
|
|
];
|
|
$process = proc_open('php console.php ' . $args, $descriptor, $pipes, '../../../../');
|
|
$lastStdOut = stream_get_contents($pipes[1]);
|
|
$lastStdErr = stream_get_contents($pipes[2]);
|
|
$lastCode = proc_close($process);
|
|
|
|
// Clean opcode cache
|
|
$client = new GuzzleHttp\Client();
|
|
$client->request('GET', $this->baseUrl . '/apps/testing/clean_opcode_cache.php');
|
|
|
|
\PHPUnit\Framework\Assert::assertEquals(0, $lastCode);
|
|
}
|
|
|
|
/**
|
|
* @Then the OCS status code should be :statusCode
|
|
*
|
|
* @param int $statusCode
|
|
*/
|
|
public function theOCSStatusCodeShouldBe(int $statusCode) {
|
|
$meta = $this->getXmlResponse()->meta[0];
|
|
|
|
\PHPUnit\Framework\Assert::assertEquals($statusCode, (int)$meta->statuscode, 'Response message: ' . (string)$meta->message);
|
|
}
|
|
|
|
/**
|
|
* @Then the HTTP status code should be :statusCode
|
|
*
|
|
* @param int $statusCode
|
|
*/
|
|
public function theHTTPStatusCodeShouldBe(int $statusCode) {
|
|
\PHPUnit\Framework\Assert::assertEquals($statusCode, $this->response->getStatusCode());
|
|
}
|
|
|
|
/**
|
|
* @Then the list of returned shares has :count shares
|
|
*/
|
|
public function theListOfReturnedSharesHasShares(int $count) {
|
|
$this->theHTTPStatusCodeShouldBe(200);
|
|
$this->theOCSStatusCodeShouldBe(100);
|
|
|
|
$returnedShares = $this->getXmlResponse()->data[0];
|
|
|
|
\PHPUnit\Framework\Assert::assertEquals($count, count($returnedShares->element));
|
|
}
|
|
|
|
/**
|
|
* @Then share is returned with
|
|
*
|
|
* @param TableNode $body
|
|
*/
|
|
public function shareIsReturnedWith(TableNode $body) {
|
|
$this->shareXIsReturnedWith(0, $body);
|
|
}
|
|
|
|
/**
|
|
* @Then share :number is returned with
|
|
*
|
|
* @param int $number
|
|
* @param TableNode $body
|
|
*/
|
|
public function shareXIsReturnedWith(int $number, TableNode $body) {
|
|
$this->theHTTPStatusCodeShouldBe(200);
|
|
$this->theOCSStatusCodeShouldBe(100);
|
|
|
|
if (!($body instanceof TableNode)) {
|
|
return;
|
|
}
|
|
|
|
$returnedShare = $this->getXmlResponse()->data[0];
|
|
if ($returnedShare->element) {
|
|
$returnedShare = (array) $returnedShare;
|
|
$returnedShare = $returnedShare['element'];
|
|
if (is_array($returnedShare)) {
|
|
usort($returnedShare, static function ($share1, $share2) {
|
|
return (int) $share1->id - (int) $share2->id;
|
|
});
|
|
}
|
|
|
|
$returnedShare = $returnedShare[$number];
|
|
}
|
|
|
|
$defaultExpectedFields = [
|
|
'id' => 'A_NUMBER',
|
|
'share_type' => '10', // IShare::TYPE_ROOM,
|
|
'permissions' => '19',
|
|
'stime' => 'A_NUMBER',
|
|
'parent' => '',
|
|
'expiration' => '',
|
|
'token' => '',
|
|
'storage' => 'A_NUMBER',
|
|
'item_source' => 'A_NUMBER',
|
|
'file_source' => 'A_NUMBER',
|
|
'file_parent' => 'A_NUMBER',
|
|
'mail_send' => '0',
|
|
];
|
|
|
|
$fields = $body->getRowsHash();
|
|
if (isset($fields['share_type']) && ($fields['share_type'] === '10' || $fields['share_type'] === '11')) {
|
|
$defaultExpectedFields['share_with_link'] = 'URL';
|
|
}
|
|
|
|
$expectedFields = array_merge($defaultExpectedFields, $fields);
|
|
|
|
if (!array_key_exists('uid_file_owner', $expectedFields) &&
|
|
array_key_exists('uid_owner', $expectedFields)) {
|
|
$expectedFields['uid_file_owner'] = $expectedFields['uid_owner'];
|
|
}
|
|
if (!array_key_exists('displayname_file_owner', $expectedFields) &&
|
|
array_key_exists('displayname_owner', $expectedFields)) {
|
|
$expectedFields['displayname_file_owner'] = $expectedFields['displayname_owner'];
|
|
}
|
|
|
|
if (array_key_exists('share_type', $expectedFields) &&
|
|
$expectedFields['share_type'] == 10 /* IShare::TYPE_ROOM */ &&
|
|
array_key_exists('share_with', $expectedFields)) {
|
|
if ($expectedFields['share_with'] === 'private_conversation') {
|
|
$expectedFields['share_with'] = 'REGEXP /^private_conversation_[0-9a-f]{6}$/';
|
|
$expectedFields['share_with_link'] = '';
|
|
} else {
|
|
$expectedFields['share_with'] = FeatureContext::getTokenForIdentifier($expectedFields['share_with']);
|
|
}
|
|
}
|
|
|
|
if (array_key_exists('share_with_link', $expectedFields) &&
|
|
$expectedFields['share_with_link'] === 'URL') {
|
|
if (array_key_exists('share_with', $expectedFields)) {
|
|
$expectedFields['share_with_link'] = $this->baseUrl . 'index.php/call/' . $expectedFields['share_with'];
|
|
} else {
|
|
$expectedFields['share_with_link'] = 'REGEXP ' . '/\/call\//';
|
|
}
|
|
}
|
|
|
|
foreach ($expectedFields as $field => $value) {
|
|
$share = json_decode(json_encode($returnedShare), true);
|
|
if (isset($share[$field]) && empty($share[$field]) && is_array($share[$field])) {
|
|
// Fix XML parsing fails
|
|
$share[$field] = '';
|
|
}
|
|
$this->assertFieldIsInReturnedShare($field, $value, $share);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Then /^"([^"]*)" sharees returned (are|is empty)$/
|
|
*
|
|
* Each sharee is specified as "| room name | room test identifier |"; the
|
|
* name is checked against the returned "label" value, and the room test
|
|
* identifier is used to get the room token, which is checked against the
|
|
* returned "shareWith" value. The returned "shareType" value is expected to
|
|
* always be "IShare::TYPE_ROOM", so there is no need to specify it.
|
|
*
|
|
* @param string $shareeType
|
|
* @param string $isEmpty
|
|
* @param TableNode|null $shareesList
|
|
*/
|
|
public function shareesReturnedAreIsEmpty(string $shareeType, string $isEmpty, TableNode $shareesList = null) {
|
|
if ($isEmpty !== 'is empty') {
|
|
$sharees = [];
|
|
foreach ($shareesList->getRows() as $row) {
|
|
$expectedSharee = [$row[0]];
|
|
$expectedSharee[] = 10; // IShare::TYPE_ROOM
|
|
$expectedSharee[] = FeatureContext::getTokenForIdentifier($row[1]);
|
|
$sharees[] = $expectedSharee;
|
|
}
|
|
$respondedArray = $this->getArrayOfShareesResponded($this->response, $shareeType);
|
|
usort($sharees, function ($a, $b) {
|
|
return $a[2] <=> $b[2]; // Sort by token
|
|
});
|
|
usort($respondedArray, function ($a, $b) {
|
|
return $a[2] <=> $b[2]; // Sort by token
|
|
});
|
|
\PHPUnit\Framework\Assert::assertEquals($sharees, $respondedArray);
|
|
} else {
|
|
$respondedArray = $this->getArrayOfShareesResponded($this->response, $shareeType);
|
|
\PHPUnit\Framework\Assert::assertEmpty($respondedArray);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Then the list of returned files for :user is
|
|
*
|
|
* @param string $user
|
|
* @param TableNode|null $table
|
|
*/
|
|
public function theListOfReturnedFilesForIs(string $user, TableNode $table = null) {
|
|
$xmlResponse = $this->getXmlResponse();
|
|
$xmlResponse->registerXPathNamespace('d', 'DAV:');
|
|
|
|
$hrefs = [];
|
|
foreach ($xmlResponse->xpath('//d:response/d:href') as $href) {
|
|
$hrefs[] = (string)$href;
|
|
}
|
|
|
|
$expectedHrefs = [];
|
|
if ($table !== null) {
|
|
foreach ($table->getRows() as $row) {
|
|
$expectedHrefs[] = '/remote.php/dav/files/' . $user . (string)$row[0];
|
|
}
|
|
}
|
|
|
|
\PHPUnit\Framework\Assert::assertEquals($expectedHrefs, $hrefs);
|
|
}
|
|
|
|
/**
|
|
* @Then the response contains a share-types DAV property with
|
|
*
|
|
* @param TableNode|null $table
|
|
*/
|
|
public function theResponseContainsAShareTypesDavPropertyWith(TableNode $table = null) {
|
|
$xmlResponse = $this->getXmlResponse();
|
|
$xmlResponse->registerXPathNamespace('oc', 'http://owncloud.org/ns');
|
|
|
|
$shareTypes = [];
|
|
foreach ($xmlResponse->xpath('//oc:share-types/oc:share-type') as $shareType) {
|
|
$shareTypes[] = (int)$shareType;
|
|
}
|
|
|
|
$expectedShareTypes = [];
|
|
if ($table !== null) {
|
|
foreach ($table->getRows() as $row) {
|
|
$expectedShareTypes[] = (int)$row[0];
|
|
}
|
|
}
|
|
|
|
\PHPUnit\Framework\Assert::assertEquals($expectedShareTypes, $shareTypes);
|
|
}
|
|
|
|
/**
|
|
* @Then the response contains a share-types file property for :path with
|
|
*
|
|
* @param string $path
|
|
* @param TableNode|null $table
|
|
*/
|
|
public function theResponseContainsAShareTypesFilesPropertyForWith(string $path, TableNode $table = null) {
|
|
$response = json_decode($this->response->getBody());
|
|
|
|
$fileForPath = array_filter($response->files, function ($file) use ($path) {
|
|
$filePath = $file->path . (substr($file->path, -1) === '/'? '': '/');
|
|
return ($filePath . $file->name) === $path;
|
|
});
|
|
|
|
if (empty($fileForPath)) {
|
|
\PHPUnit\Framework\Assert::fail("$path not found in the response");
|
|
}
|
|
|
|
$fileForPath = array_shift($fileForPath);
|
|
|
|
$shareTypes = [];
|
|
if (property_exists($fileForPath, 'shareTypes')) {
|
|
foreach ($fileForPath->shareTypes as $shareType) {
|
|
$shareTypes[] = (int)$shareType;
|
|
}
|
|
}
|
|
|
|
$expectedShareTypes = [];
|
|
if ($table !== null) {
|
|
foreach ($table->getRows() as $row) {
|
|
$expectedShareTypes[] = (int)$row[0];
|
|
}
|
|
}
|
|
|
|
\PHPUnit\Framework\Assert::assertEquals($expectedShareTypes, $shareTypes);
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
* @param string $path
|
|
* @param string $shareType
|
|
* @param string $shareWith
|
|
* @param TableNode|null $body
|
|
*/
|
|
private function userSharesWith(string $user, string $path, string $shareType, string $shareWith, TableNode $body = null) {
|
|
$this->currentUser = $user;
|
|
|
|
$url = '/apps/files_sharing/api/v1/shares';
|
|
|
|
$parameters = [];
|
|
$parameters[] = 'path=' . $path;
|
|
$parameters[] = 'shareType=' . $shareType;
|
|
$parameters[] = 'shareWith=' . $shareWith;
|
|
|
|
if ($body instanceof TableNode) {
|
|
foreach ($body->getRowsHash() as $key => $value) {
|
|
if ($key === 'expireDate' && $value !== 'invalid date') {
|
|
$value = date('Y-m-d', strtotime($value));
|
|
}
|
|
$parameters[] = $key . '=' . $value;
|
|
}
|
|
}
|
|
|
|
$url .= '?' . implode('&', $parameters);
|
|
|
|
$this->sendingTo('POST', $url);
|
|
|
|
$this->lastCreatedShareData = $this->getXmlResponse();
|
|
}
|
|
|
|
/**
|
|
* @param string $verb
|
|
* @param string $url
|
|
* @param TableNode $body
|
|
*/
|
|
private function sendingTo(string $verb, string $url, TableNode $body = null) {
|
|
$fullUrl = $this->baseUrl . "ocs/v1.php" . $url;
|
|
$client = new Client();
|
|
$options = [];
|
|
if ($this->currentUser === 'admin') {
|
|
$options['auth'] = $this->adminUser;
|
|
} else {
|
|
$options['auth'] = [$this->currentUser, $this->regularUserPassword];
|
|
}
|
|
$options['headers'] = [
|
|
'OCS_APIREQUEST' => 'true'
|
|
];
|
|
if ($body instanceof TableNode) {
|
|
$fd = $body->getRowsHash();
|
|
if (array_key_exists('expireDate', $fd)) {
|
|
$fd['expireDate'] = date('Y-m-d', strtotime($fd['expireDate']));
|
|
}
|
|
$options['form_params'] = $fd;
|
|
}
|
|
|
|
try {
|
|
$this->response = $client->request($verb, $fullUrl, $options);
|
|
} catch (GuzzleHttp\Exception\ClientException $ex) {
|
|
$this->response = $ex->getResponse();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $verb
|
|
* @param string $url
|
|
* @param array $headers
|
|
* @param string $body
|
|
*/
|
|
private function sendingToDav(string $verb, string $url, array $headers = null, string $body = null) {
|
|
$fullUrl = $this->baseUrl . "remote.php/dav/files" . $url;
|
|
$client = new Client();
|
|
$options = [];
|
|
if ($this->currentUser === 'admin') {
|
|
$options['auth'] = $this->adminUser;
|
|
} else {
|
|
$options['auth'] = [$this->currentUser, $this->regularUserPassword];
|
|
}
|
|
$options['headers'] = [
|
|
'OCS_APIREQUEST' => 'true'
|
|
];
|
|
if ($headers !== null) {
|
|
$options['headers'] = array_merge($options['headers'], $headers);
|
|
}
|
|
if ($body !== null) {
|
|
$options['body'] = $body;
|
|
}
|
|
|
|
try {
|
|
$this->response = $client->request($verb, $fullUrl, $options);
|
|
} catch (GuzzleHttp\Exception\ClientException $ex) {
|
|
$this->response = $ex->getResponse();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $verb
|
|
* @param string $url
|
|
* @param string $requestToken
|
|
* @param CookieJar $cookieJar
|
|
*/
|
|
private function sendingToWithRequestToken(string $verb, string $url, string $requestToken, CookieJar $cookieJar) {
|
|
$fullUrl = $this->baseUrl . $url;
|
|
|
|
$client = new Client();
|
|
try {
|
|
$this->response = $client->request(
|
|
$verb,
|
|
$fullUrl,
|
|
[
|
|
'cookies' => $cookieJar,
|
|
'headers' => [
|
|
'requesttoken' => $requestToken
|
|
]
|
|
]
|
|
);
|
|
} catch (GuzzleHttp\Exception\ClientException $e) {
|
|
$this->response = $e->getResponse();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param ResponseInterface $response
|
|
* @return string
|
|
*/
|
|
private function extractRequestTokenFromResponse(ResponseInterface $response): string {
|
|
return substr(preg_replace('/(.*)data-requesttoken="(.*)">(.*)/sm', '\2', $response->getBody()->getContents()), 0, 89);
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
*/
|
|
private function loggingInUsingWebAs(string $user) {
|
|
$loginUrl = $this->baseUrl . '/login';
|
|
|
|
$cookieJar = new CookieJar();
|
|
|
|
// Request a new session and extract CSRF token
|
|
$client = new Client();
|
|
$response = $client->get(
|
|
$loginUrl,
|
|
[
|
|
'cookies' => $cookieJar,
|
|
]
|
|
);
|
|
$requestToken = $this->extractRequestTokenFromResponse($response);
|
|
|
|
// Login and extract new token
|
|
$password = ($user === 'admin') ? $this->adminUser[1] : $this->regularUserPassword;
|
|
$client = new Client();
|
|
$response = $client->post(
|
|
$loginUrl,
|
|
[
|
|
'form_params' => [
|
|
'user' => $user,
|
|
'password' => $password,
|
|
'requesttoken' => $requestToken,
|
|
],
|
|
'cookies' => $cookieJar,
|
|
]
|
|
);
|
|
$requestToken = $this->extractRequestTokenFromResponse($response);
|
|
|
|
return [$requestToken, $cookieJar];
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getLastShareToken(): string {
|
|
return (string)$this->lastCreatedShareData->data[0]->token;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
private function getLastShareId(): string {
|
|
return (string)$this->lastCreatedShareData->data[0]->id;
|
|
}
|
|
|
|
/**
|
|
* @return SimpleXMLElement
|
|
*/
|
|
private function getXmlResponse(): \SimpleXMLElement {
|
|
return simplexml_load_string($this->response->getBody());
|
|
}
|
|
|
|
/**
|
|
* @param string $field
|
|
* @param string $contentExpected
|
|
* @param \SimpleXMLElement $returnedShare
|
|
*/
|
|
private function assertFieldIsInReturnedShare(string $field, string $contentExpected, array $returnedShare) {
|
|
if ($contentExpected === 'IGNORE') {
|
|
return;
|
|
}
|
|
|
|
if (!array_key_exists($field, $returnedShare)) {
|
|
\PHPUnit\Framework\Assert::fail("$field was not found in response");
|
|
}
|
|
|
|
if ($field === 'expiration' && !empty($contentExpected)) {
|
|
$contentExpected = date('Y-m-d', strtotime($contentExpected)) . " 00:00:00";
|
|
}
|
|
|
|
if ($contentExpected === 'A_NUMBER') {
|
|
\PHPUnit\Framework\Assert::assertTrue(is_numeric((string)$returnedShare[$field]), "Field '$field' is not a number: " . $returnedShare[$field]);
|
|
} elseif ($contentExpected === 'A_TOKEN') {
|
|
// A token is composed by 15 characters from
|
|
// ISecureRandom::CHAR_HUMAN_READABLE.
|
|
\PHPUnit\Framework\Assert::assertRegExp('/^[abcdefgijkmnopqrstwxyzABCDEFGHJKLMNPQRSTWXYZ23456789]{15}$/', (string)$returnedShare[$field], "Field '$field' is not a token");
|
|
} elseif (strpos($contentExpected, 'REGEXP ') === 0) {
|
|
\PHPUnit\Framework\Assert::assertRegExp(substr($contentExpected, strlen('REGEXP ')), (string)$returnedShare[$field], "Field '$field' does not match");
|
|
} else {
|
|
\PHPUnit\Framework\Assert::assertEquals($contentExpected, (string)$returnedShare[$field], "Field '$field' does not match");
|
|
}
|
|
}
|
|
|
|
private function getArrayOfShareesResponded(ResponseInterface $response, string $shareeType) {
|
|
$elements = simplexml_load_string($response->getBody())->data;
|
|
$elements = json_decode(json_encode($elements), 1);
|
|
if (strpos($shareeType, 'exact ') === 0) {
|
|
$elements = $elements['exact'];
|
|
$shareeType = substr($shareeType, 6);
|
|
}
|
|
|
|
// "simplexml_load_string" creates a SimpleXMLElement object for each
|
|
// XML element with child elements. In turn, each child is indexed by
|
|
// its tag in the SimpleXMLElement object. However, when there are
|
|
// several child XML elements with the same tag, an array with all the
|
|
// children with the same tag is indexed instead. Therefore, when the
|
|
// XML contains
|
|
// <rooms>
|
|
// <element>
|
|
// <label>...</label>
|
|
// <value>...</value>
|
|
// </element>
|
|
// </rooms>
|
|
// the "$elements[$shareeType]" variable contains an "element" key which
|
|
// in turn contains "label" and "value" keys, but when the XML contains
|
|
// <rooms>
|
|
// <element>
|
|
// <label>...</label>
|
|
// <value>...</value>
|
|
// </element>
|
|
// <element>
|
|
// <label>...</label>
|
|
// <value>...</value>
|
|
// </element>
|
|
// </rooms>
|
|
// the "$elements[$shareeType]" variable contains an "element" key which
|
|
// in turn contains "0" and "1" keys, and in turn each one contains
|
|
// "label" and "value" keys.
|
|
$elements = $elements[$shareeType];
|
|
if (array_key_exists('element', $elements) && is_int(array_keys($elements['element'])[0])) {
|
|
$elements = $elements['element'];
|
|
}
|
|
|
|
$sharees = [];
|
|
foreach ($elements as $element) {
|
|
$sharees[] = [$element['label'], $element['value']['shareType'], $element['value']['shareWith']];
|
|
}
|
|
return $sharees;
|
|
}
|
|
}
|