diff --git a/build/integration/features/bootstrap/AppConfiguration.php b/build/integration/features/bootstrap/AppConfiguration.php index 1313e3421072d..0606729b030b9 100644 --- a/build/integration/features/bootstrap/AppConfiguration.php +++ b/build/integration/features/bootstrap/AppConfiguration.php @@ -14,11 +14,9 @@ require __DIR__ . '/autoload.php'; trait AppConfiguration { - /** @var string */ - private $currentUser = ''; - /** @var ResponseInterface */ - private $response = null; + private string $currentUser = ''; + private ?ResponseInterface $response = null; abstract public function sendingTo(string $verb, string $url); abstract public function sendingToWith(string $verb, string $url, ?TableNode $body); diff --git a/build/integration/features/bootstrap/Auth.php b/build/integration/features/bootstrap/Auth.php index 13be6fa9cc323..80e6a6e380939 100644 --- a/build/integration/features/bootstrap/Auth.php +++ b/build/integration/features/bootstrap/Auth.php @@ -5,26 +5,20 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-or-later */ -use GuzzleHttp\Client; +use GuzzleHttp\Client as GClient; use GuzzleHttp\Cookie\CookieJar; -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Exception\ServerException; require __DIR__ . '/autoload.php'; trait Auth { - /** @var string */ - private $unrestrictedClientToken; - /** @var string */ - private $restrictedClientToken; - /** @var Client */ - private $client; - /** @var string */ - private $responseXml; + private ?string $unrestrictedClientToken; + private ?string $restrictedClientToken; + private ?GClient $client; + private ?string $responseXml; /** @BeforeScenario */ public function setUpScenario() { - $this->client = new Client(); + $this->client = $this->getGuzzleClient(null); $this->responseXml = ''; $this->cookieJar = new CookieJar(); } @@ -38,27 +32,15 @@ public function requestingWith($url, $method) { private function sendRequest($url, $method, $authHeader = null, $useCookies = false) { $fullUrl = substr($this->baseUrl, 0, -5) . $url; - try { - if ($useCookies) { - $options = [ - 'cookies' => $this->cookieJar, - ]; - } else { - $options = []; - } - if ($authHeader) { - $options['headers'] = [ - 'Authorization' => $authHeader - ]; - } - $options['headers']['OCS_APIREQUEST'] = 'true'; - $options['headers']['requesttoken'] = $this->requestToken; - $this->response = $this->client->request($method, $fullUrl, $options); - } catch (ClientException $ex) { - $this->response = $ex->getResponse(); - } catch (ServerException $ex) { - $this->response = $ex->getResponse(); + if ($useCookies) { + $options['cookies'] = $this->cookieJar; } + if ($authHeader) { + $options['headers'] = [ 'Authorization' => $authHeader ]; + } + $options['headers']['OCS_APIREQUEST'] = 'true'; + $options['headers']['requesttoken'] = $this->requestToken; + $this->response = $this->client->request($method, $fullUrl, $options); } /** @@ -69,33 +51,18 @@ public function theCsrfTokenIsExtractedFromThePreviousResponse() { } /** - * @param bool $loginViaWeb * @return object */ - private function createClientToken($loginViaWeb = true) { + private function createClientToken(bool $loginViaWeb = true) { if ($loginViaWeb) { $this->loggingInUsingWebAs('user0'); } - $fullUrl = substr($this->baseUrl, 0, -5) . '/index.php/settings/personal/authtokens'; - $client = new Client(); - $options = [ - 'auth' => [ - 'user0', - $loginViaWeb ? '123456' : $this->restrictedClientToken, - ], - 'form_params' => [ - 'requesttoken' => $this->requestToken, - 'name' => md5(microtime()), - ], - 'cookies' => $this->cookieJar, - ]; - - try { - $this->response = $client->request('POST', $fullUrl, $options); - } catch (\GuzzleHttp\Exception\ServerException $e) { - $this->response = $e->getResponse(); - } + $client = $this->getGuzzleClient(null); + $options['auth'] = [ 'user0', $loginViaWeb ? '123456' : $this->restrictedClientToken ]; + $options['form_params'] = [ 'requesttoken' => $this->requestToken, 'name' => md5(microtime()) ]; + $options['cookies'] = $this->cookieJar; + $this->response = $client->request('POST', $fullUrl, $options); return json_decode($this->response->getBody()->getContents()); } @@ -106,20 +73,14 @@ public function aNewRestrictedClientTokenIsAdded() { $tokenObj = $this->createClientToken(); $newCreatedTokenId = $tokenObj->deviceToken->id; $fullUrl = substr($this->baseUrl, 0, -5) . '/index.php/settings/personal/authtokens/' . $newCreatedTokenId; - $client = new Client(); - $options = [ - 'auth' => ['user0', '123456'], - 'headers' => [ - 'requesttoken' => $this->requestToken, - ], - 'json' => [ - 'name' => md5(microtime()), - 'scope' => [ - 'filesystem' => false, - ], - ], - 'cookies' => $this->cookieJar, + $client = $this->getGuzzleClient(null); + $options['auth'] = [ 'user0', '123456' ]; + $options['headers'] = [ 'requesttoken' => $this->requestToken ]; + $options['json'] = [ + 'name' => md5(microtime()), + 'scope' => [ 'filesystem' => false ], ]; + $options['cookies'] = $this->cookieJar; $this->response = $client->request('PUT', $fullUrl, $options); $this->restrictedClientToken = $tokenObj->token; } @@ -207,29 +168,23 @@ public function aNewBrowserSessionIsStarted($remember = false) { $baseUrl = substr($this->baseUrl, 0, -5); $loginUrl = $baseUrl . '/login'; // Request a new session and extract CSRF token - $client = new Client(); - $response = $client->get($loginUrl, [ - 'cookies' => $this->cookieJar, - ]); - $this->extracRequestTokenFromResponse($response); + $client = $this->getGuzzleClient(null); + $options['cookies'] = $this->cookieJar; + $response = $client->get($loginUrl, $options); + $this->extractRequestTokenFromResponse($response); // Login and extract new token - $client = new Client(); - $response = $client->post( - $loginUrl, [ - 'form_params' => [ - 'user' => 'user0', - 'password' => '123456', - 'rememberme' => $remember ? '1' : '0', - 'requesttoken' => $this->requestToken, - ], - 'cookies' => $this->cookieJar, - 'headers' => [ - 'Origin' => $baseUrl, - ], - ] - ); - $this->extracRequestTokenFromResponse($response); + $client = $this->getGuzzleClient(null); + $options['form_params'] = [ + 'user' => 'user0', + 'password' => '123456', + 'rememberme' => $remember ? '1' : '0', + 'requesttoken' => $this->requestToken, + ]; + $options['cookies'] = $this->cookieJar; + $options['headers'] = [ 'Origin' => $baseUrl ]; + $response = $client->post($loginUrl, $options); + $this->extractRequestTokenFromResponse($response); } /** diff --git a/build/integration/features/bootstrap/BasicStructure.php b/build/integration/features/bootstrap/BasicStructure.php index 8d1d3b38793f5..342d1dd309996 100644 --- a/build/integration/features/bootstrap/BasicStructure.php +++ b/build/integration/features/bootstrap/BasicStructure.php @@ -6,10 +6,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ use Behat\Gherkin\Node\TableNode; -use GuzzleHttp\Client; use GuzzleHttp\Cookie\CookieJar; -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Exception\ServerException; use PHPUnit\Framework\Assert; use Psr\Http\Message\ResponseInterface; @@ -22,33 +19,21 @@ trait BasicStructure { use Mail; use Theming; - /** @var string */ - private $currentUser = ''; - - /** @var string */ - private $currentServer = ''; - - /** @var string */ - private $baseUrl = ''; - - /** @var int */ - private $apiVersion = 1; - - /** @var ResponseInterface */ - private $response = null; - - /** @var CookieJar */ - private $cookieJar; - - /** @var string */ - private $requestToken; - - protected $adminUser; - protected $regularUser; - protected $localBaseUrl; - protected $remoteBaseUrl; - - public function __construct($baseUrl, $admin, $regular_user_password) { + private string $currentUser = ''; + private string $currentServer = ''; + private string $baseUrl = ''; + private int $apiVersion = 1; + private ?ResponseInterface $response = null; + private CookieJar $cookieJar; + private string $requestToken; + + /** @var array{0:string,1:string} */ + protected array $adminUser; + protected string $regularUser; + protected string $localBaseUrl = ''; + protected string $remoteBaseUrl = ''; + + public function __construct(string $baseUrl, array $admin, string $regular_user_password) { // Initialize your context here $this->baseUrl = $baseUrl; $this->adminUser = $admin; @@ -146,63 +131,24 @@ public function simplifyArray(array $arrayOfArrays): array { */ public function sendingToWith(string $verb, string $url, ?TableNode $body): void { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php" . $url; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } elseif (strpos($this->currentUser, 'anonymous') !== 0) { - $options['auth'] = [$this->currentUser, $this->regularUser]; - } - $options['headers'] = [ - 'OCS-APIRequest' => 'true' - ]; + $client = $this->getGuzzleClient($this->currentUser); + $options['headers'] = [ 'OCS-APIRequest' => 'true' ]; if ($body instanceof TableNode) { - $fd = $body->getRowsHash(); - $options['form_params'] = $fd; - } - - // TODO: Fix this hack! - if ($verb === 'PUT' && $body === null) { - $options['form_params'] = [ - 'foo' => 'bar', - ]; - } - - try { - $this->response = $client->request($verb, $fullUrl, $options); - } catch (ClientException $ex) { - $this->response = $ex->getResponse(); - } catch (ServerException $ex) { - $this->response = $ex->getResponse(); + $options['form_params'] = $body->getRowsHash(); } + $this->response = $client->request($verb, $fullUrl, $options); } protected function sendRequestForJSON(string $verb, string $url, TableNode|array|null $body = null, array $headers = []): void { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php" . $url; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = ['admin', 'admin']; - } elseif (strpos($this->currentUser, 'anonymous') !== 0) { - $options['auth'] = [$this->currentUser, $this->regularUser]; - } + $client = $this->getGuzzleClient($this->currentUser); if ($body instanceof TableNode) { - $fd = $body->getRowsHash(); - $options['form_params'] = $fd; + $options['form_params'] = $body->getRowsHash(); } elseif (is_array($body)) { $options['form_params'] = $body; } - - $options['headers'] = array_merge($headers, [ - 'OCS-ApiRequest' => 'true', - 'Accept' => 'application/json', - ]); - - try { - $this->response = $client->{$verb}($fullUrl, $options); - } catch (ClientException $ex) { - $this->response = $ex->getResponse(); - } + $options['headers'] = array_merge($headers, [ 'OCS-APIRequest' => 'true', 'Accept' => 'application/json' ]); + $this->response = $client->{$verb}($fullUrl, $options); } /** @@ -215,24 +161,12 @@ public function sendingToDirectUrl($verb, $url) { } public function sendingToWithDirectUrl($verb, $url, $body) { - $fullUrl = substr($this->baseUrl, 0, -5) . $url; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } elseif (strpos($this->currentUser, 'anonymous') !== 0) { - $options['auth'] = [$this->currentUser, $this->regularUser]; - } + $fullUrl = substr($this->baseUrl, 0, -5) . $url; // drops `/ocs/` + $client = $this->getGuzzleClient($this->currentUser); if ($body instanceof TableNode) { - $fd = $body->getRowsHash(); - $options['form_params'] = $fd; - } - - try { - $this->response = $client->request($verb, $fullUrl, $options); - } catch (ClientException $ex) { - $this->response = $ex->getResponse(); + $options['form_params'] = $body->getRowsHash(); } + $this->response = $client->request($verb, $fullUrl, $options); } public function isExpectedUrl($possibleUrl, $finalPart) { @@ -268,7 +202,7 @@ public function theContentTypeShouldbe($contentType) { /** * @param ResponseInterface $response */ - private function extracRequestTokenFromResponse(ResponseInterface $response) { + private function extractRequestTokenFromResponse(ResponseInterface $response) { $this->requestToken = substr(preg_replace('/(.*)data-requesttoken="(.*)">(.*)/sm', '\2', $response->getBody()->getContents()), 0, 89); } @@ -279,34 +213,20 @@ private function extracRequestTokenFromResponse(ResponseInterface $response) { public function loggingInUsingWebAs($user) { $baseUrl = substr($this->baseUrl, 0, -5); $loginUrl = $baseUrl . '/index.php/login'; + // Request a new session and extract CSRF token - $client = new Client(); - $response = $client->get( - $loginUrl, - [ - 'cookies' => $this->cookieJar, - ] - ); - $this->extracRequestTokenFromResponse($response); + $client = $this->getGuzzleClient(null); + $response = $client->get($loginUrl, [ 'cookies' => $this->cookieJar ]); + $this->extractRequestTokenFromResponse($response); // Login and extract new token + $client = $this->getGuzzleClient(null); $password = ($user === 'admin') ? 'admin' : '123456'; - $client = new Client(); - $response = $client->post( - $loginUrl, - [ - 'form_params' => [ - 'user' => $user, - 'password' => $password, - 'requesttoken' => $this->requestToken, - ], - 'cookies' => $this->cookieJar, - 'headers' => [ - 'Origin' => $baseUrl, - ], - ] - ); - $this->extracRequestTokenFromResponse($response); + $options['form_params'] = [ 'user' => $user, 'password' => $password, 'requesttoken' => $this->requestToken ]; + $options['cookies'] = $this->cookieJar; + $options['headers'] = [ 'Origin' => $baseUrl ]; + $response = $client->post($loginUrl, $options); + $this->extractRequestTokenFromResponse($response); } /** @@ -317,31 +237,16 @@ public function loggingInUsingWebAs($user) { */ public function sendingAToWithRequesttoken($method, $url, $body = null) { $baseUrl = substr($this->baseUrl, 0, -5); - - $options = [ - 'cookies' => $this->cookieJar, - 'headers' => [ - 'requesttoken' => $this->requestToken - ], - ]; - + $fullUrl = $baseUrl . $url; + $client = $this->getGuzzleClient(null); + $options['cookies'] = $this->cookieJar; + $options['headers'] = [ 'requesttoken' => $this->requestToken ]; if ($body instanceof TableNode) { - $fd = $body->getRowsHash(); - $options['form_params'] = $fd; - } elseif ($body) { + $options['form_params'] = $body->getRowsHash(); + } elseif (is_array($body)) { $options = array_merge_recursive($options, $body); } - - $client = new Client(); - try { - $this->response = $client->request( - $method, - $baseUrl . $url, - $options - ); - } catch (ClientException $e) { - $this->response = $e->getResponse(); - } + $this->response = $client->request($method, $fullUrl, $options); } /** @@ -351,19 +256,10 @@ public function sendingAToWithRequesttoken($method, $url, $body = null) { */ public function sendingAToWithoutRequesttoken($method, $url) { $baseUrl = substr($this->baseUrl, 0, -5); - - $client = new Client(); - try { - $this->response = $client->request( - $method, - $baseUrl . $url, - [ - 'cookies' => $this->cookieJar - ] - ); - } catch (ClientException $e) { - $this->response = $e->getResponse(); - } + $fullUrl = $baseUrl . $url; + $client = $this->getGuzzleClient(null); + $options['cookies'] = $this->cookieJar; + $this->response = $client->request($method, $fullUrl, $options); } public static function removeFile($path, $filename) { diff --git a/build/integration/features/bootstrap/CollaborationContext.php b/build/integration/features/bootstrap/CollaborationContext.php index 3b17eb62b6f3a..233a7ca54c8b9 100644 --- a/build/integration/features/bootstrap/CollaborationContext.php +++ b/build/integration/features/bootstrap/CollaborationContext.php @@ -8,7 +8,6 @@ */ use Behat\Behat\Context\Context; use Behat\Gherkin\Node\TableNode; -use GuzzleHttp\Client; use PHPUnit\Framework\Assert; require __DIR__ . '/autoload.php'; @@ -66,23 +65,14 @@ private function getAutocompleteWithType(int $type, string $search, TableNode $f /** * @Given /^there is a contact in an addressbook$/ */ - public function thereIsAContactInAnAddressbook() { + public function thereIsAContactInAnAddressbook(): void { $this->usingNewDavPath(); - try { - $destination = '/users/admin/myaddressbook'; - $data = 'myaddressbook'; - $this->response = $this->makeDavRequest($this->currentUser, 'MKCOL', $destination, ['Content-Type' => 'application/xml'], $data, 'addressbooks'); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $destination = '/users/admin/myaddressbook'; + $data = 'myaddressbook'; + $this->response = $this->makeDavRequest($this->currentUser, 'MKCOL', $destination, ['Content-Type' => 'application/xml'], $data, 'addressbooks'); - try { - $destination = '/users/admin/myaddressbook/contact1.vcf'; - $data = <<response = $this->makeDavRequest($this->currentUser, 'PUT', $destination, [], $data, 'addressbooks'); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest($this->currentUser, 'PUT', $destination, [], $data, 'addressbooks'); } protected function resetAppConfigs(): void { @@ -116,27 +99,12 @@ protected function resetAppConfigs(): void { /** * @Given /^user "([^"]*)" has status "([^"]*)"$/ - * @param string $user - * @param string $status */ - public function assureUserHasStatus($user, $status) { + public function assureUserHasStatus(string $user, string $status) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/user_status/api/v1/user_status/status"; - $client = new Client(); - $options = [ - 'headers' => [ - 'OCS-APIREQUEST' => 'true', - ], - ]; - if ($user === 'admin') { - $options['auth'] = $this->adminUser; - } else { - $options['auth'] = [$user, $this->regularUser]; - } - - $options['form_params'] = [ - 'statusType' => $status - ]; - + $client = $this->getGuzzleClient($user); + $options['headers'] = [ 'OCS-APIREQUEST' => 'true' ]; + $options['form_params'] = ['statusType' => $status ]; $this->response = $client->put($fullUrl, $options); $this->theHTTPStatusCodeShouldBe(200); @@ -144,29 +112,14 @@ public function assureUserHasStatus($user, $status) { unset($options['form_params']); $this->response = $client->get($fullUrl, $options); $this->theHTTPStatusCodeShouldBe(200); - $returnedStatus = json_decode(json_encode(simplexml_load_string($this->response->getBody()->getContents())->data), true)['status']; Assert::assertEquals($status, $returnedStatus); } - /** - * @param string $user - * @return null|array - */ public function getStatusList(string $user): ?array { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/user_status/api/v1/statuses"; - $client = new Client(); - $options = [ - 'headers' => [ - 'OCS-APIREQUEST' => 'true', - ], - ]; - if ($user === 'admin') { - $options['auth'] = $this->adminUser; - } else { - $options['auth'] = [$user, $this->regularUser]; - } - + $client = $this->getGuzzleClient($user); + $options['headers'] = [ 'OCS-APIREQUEST' => 'true' ]; $this->response = $client->get($fullUrl, $options); $this->theHTTPStatusCodeShouldBe(200); @@ -176,9 +129,6 @@ public function getStatusList(string $user): ?array { /** * @Given /^user statuses for "([^"]*)" list "([^"]*)" with status "([^"]*)"$/ - * @param string $user - * @param string $statusUser - * @param string $status */ public function assertStatusesList(string $user, string $statusUser, string $status): void { $statusList = $this->getStatusList($user); @@ -197,7 +147,6 @@ public function assertStatusesList(string $user, string $statusUser, string $sta /** * @Given /^user statuses for "([^"]*)" are empty$/ - * @param string $user */ public function assertStatusesEmpty(string $user): void { $statusList = $this->getStatusList($user); diff --git a/build/integration/features/bootstrap/FilesDropContext.php b/build/integration/features/bootstrap/FilesDropContext.php index 4ccb58f08646f..54fa8eedbcd21 100644 --- a/build/integration/features/bootstrap/FilesDropContext.php +++ b/build/integration/features/bootstrap/FilesDropContext.php @@ -6,7 +6,6 @@ */ use Behat\Behat\Context\Context; use Behat\Behat\Context\SnippetAcceptingContext; -use GuzzleHttp\Client; require __DIR__ . '/autoload.php'; @@ -17,32 +16,15 @@ class FilesDropContext implements Context, SnippetAcceptingContext { * @When Dropping file :path with :content */ public function droppingFileWith($path, $content, $nickname = null) { - $client = new Client(); - $options = []; - if (count($this->lastShareData->data->element) > 0) { - $token = $this->lastShareData->data[0]->token; - } else { - $token = $this->lastShareData->data[0]->token; - } - - $base = substr($this->baseUrl, 0, -4); - $fullUrl = str_replace('//', '/', $base . "/public.php/dav/files/$token/$path"); - - $options['headers'] = [ - 'X-REQUESTED-WITH' => 'XMLHttpRequest', - ]; - + $token = $this->lastShareData->data[0]->token; + $fullUrl = $this->getDavBaseUrl() . "public.php/dav/files/$token/$path"; + $client = $this->getGuzzleClient(null); + $options['headers'] = [ 'X-REQUESTED-WITH' => 'XMLHttpRequest' ]; + $options['body'] = \GuzzleHttp\Psr7\Utils::streamFor($content); if ($nickname) { $options['headers']['X-NC-NICKNAME'] = $nickname; } - - $options['body'] = \GuzzleHttp\Psr7\Utils::streamFor($content); - - try { - $this->response = $client->request('PUT', $fullUrl, $options); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $this->response = $client->request('PUT', $fullUrl, $options); } @@ -58,30 +40,14 @@ public function droppingFileWithAs($path, $content, $nickname) { * @When Creating folder :folder in drop */ public function creatingFolderInDrop($folder, $nickname = null) { - $client = new Client(); - $options = []; - if (count($this->lastShareData->data->element) > 0) { - $token = $this->lastShareData->data[0]->token; - } else { - $token = $this->lastShareData->data[0]->token; - } - - $base = substr($this->baseUrl, 0, -4); - $fullUrl = str_replace('//', '/', $base . "/public.php/dav/files/$token/$folder"); - - $options['headers'] = [ - 'X-REQUESTED-WITH' => 'XMLHttpRequest', - ]; - + $token = $this->lastShareData->data[0]->token; + $fullUrl = $this->getDavBaseUrl() . "public.php/dav/files/$token/$folder"; + $client = $this->getGuzzleClient(null); + $options['headers'] = [ 'X-REQUESTED-WITH' => 'XMLHttpRequest' ]; if ($nickname) { $options['headers']['X-NC-NICKNAME'] = $nickname; } - - try { - $this->response = $client->request('MKCOL', $fullUrl, $options); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $this->response = $client->request('MKCOL', $fullUrl, $options); } diff --git a/build/integration/features/bootstrap/FilesRemindersContext.php b/build/integration/features/bootstrap/FilesRemindersContext.php index ba2ea5784d336..4f38adb6014df 100644 --- a/build/integration/features/bootstrap/FilesRemindersContext.php +++ b/build/integration/features/bootstrap/FilesRemindersContext.php @@ -26,7 +26,6 @@ public function settingAReminderForFileWithDueDate($path, $dueDate) { 'PUT', '/apps/files_reminders/api/v1/' . $fileId, ['dueDate' => $dueDate], - ['OCS-APIREQUEST' => 'true'] ); } @@ -39,7 +38,6 @@ public function retrievingTheReminderForFile($path, $dueDate) { 'GET', '/apps/files_reminders/api/v1/' . $fileId, null, - ['OCS-APIREQUEST' => 'true'] ); $response = $this->getDueDateFromOCSResponse(); Assert::assertEquals($dueDate, $response); @@ -54,7 +52,6 @@ public function retrievingTheReminderForFileIsNotSet($path) { 'GET', '/apps/files_reminders/api/v1/' . $fileId, null, - ['OCS-APIREQUEST' => 'true'] ); $response = $this->getDueDateFromOCSResponse(); Assert::assertNull($response); @@ -69,7 +66,6 @@ public function removingTheReminderForFile($path) { 'DELETE', '/apps/files_reminders/api/v1/' . $fileId, null, - ['OCS-APIREQUEST' => 'true'] ); } diff --git a/build/integration/features/bootstrap/Mail.php b/build/integration/features/bootstrap/Mail.php index d48ed6399c521..fddc37c8ebb90 100644 --- a/build/integration/features/bootstrap/Mail.php +++ b/build/integration/features/bootstrap/Mail.php @@ -8,10 +8,7 @@ trait Mail { // CommandLine trait is expected to be used in the class that uses this // trait. - /** - * @var string - */ - private $fakeSmtpServerPid; + private ?string $fakeSmtpServerPid = null; /** * @AfterScenario diff --git a/build/integration/features/bootstrap/Provisioning.php b/build/integration/features/bootstrap/Provisioning.php index c539e4e9b53d5..77a854c6391b3 100644 --- a/build/integration/features/bootstrap/Provisioning.php +++ b/build/integration/features/bootstrap/Provisioning.php @@ -7,7 +7,6 @@ */ use Behat\Gherkin\Node\TableNode; -use GuzzleHttp\Client; use GuzzleHttp\Message\ResponseInterface; use PHPUnit\Framework\Assert; @@ -47,14 +46,44 @@ public function restoreAppsEnabledStateAfterScenario() { } } + /** + * Sends an authenticated OCS request using the centralized Guzzle client. + * + * @param string $method HTTP method (GET, POST, PUT, DELETE) + * @param string $url Full URL to request + * @param array $additionalOptions Extra Guzzle request options (form_params, headers to merge, etc.) + * @return \Psr\Http\Message\ResponseInterface + */ + private function sendOcsRequest(string $method, string $url, array $additionalOptions = []): \Psr\Http\Message\ResponseInterface { + $client = $this->getGuzzleClient($this->currentUser); + $options = array_merge_recursive([ + 'headers' => [ + 'OCS-APIREQUEST' => 'true', + ], + ], $additionalOptions); + return $client->request($method, $url, $options); + } + + /** + * Sends an authenticated OCS request, always as admin. + */ + private function sendOcsRequestAsAdmin(string $method, string $url, array $additionalOptions = []): \Psr\Http\Message\ResponseInterface { + $client = $this->getGuzzleClient('admin'); + $options = array_merge_recursive([ + 'headers' => [ + 'OCS-APIREQUEST' => 'true', + ], + ], $additionalOptions); + return $client->request($method, $url, $options); + } + /** * @Given /^user "([^"]*)" exists$/ * @param string $user */ public function assureUserExists($user) { - try { - $this->userExists($user); - } catch (\GuzzleHttp\Exception\ClientException $ex) { + $this->userExists($user); + if ($this->response->getStatusCode() !== 200) { $previous_user = $this->currentUser; $this->currentUser = 'admin'; $this->creatingTheUser($user); @@ -69,9 +98,8 @@ public function assureUserExists($user) { * @param string $user */ public function assureUserWithDisplaynameExists($user, $displayname) { - try { - $this->userExists($user); - } catch (\GuzzleHttp\Exception\ClientException $ex) { + $this->userExists($user); + if ($this->response->getStatusCode() !== 200) { $previous_user = $this->currentUser; $this->currentUser = 'admin'; $this->creatingTheUser($user, $displayname); @@ -86,60 +114,45 @@ public function assureUserWithDisplaynameExists($user, $displayname) { * @param string $user */ public function userDoesNotExist($user) { - try { - $this->userExists($user); - } catch (\GuzzleHttp\Exception\ClientException $ex) { - $this->response = $ex->getResponse(); - Assert::assertEquals(404, $ex->getResponse()->getStatusCode()); + $this->userExists($user); + if ($this->response->getStatusCode() === 404) { return; } $previous_user = $this->currentUser; $this->currentUser = 'admin'; $this->deletingTheUser($user); $this->currentUser = $previous_user; - try { - $this->userExists($user); - } catch (\GuzzleHttp\Exception\ClientException $ex) { - $this->response = $ex->getResponse(); - Assert::assertEquals(404, $ex->getResponse()->getStatusCode()); - } + $this->userExists($user); + Assert::assertEquals(404, $this->response->getStatusCode()); } public function creatingTheUser($user, $displayname = '') { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - - $options['form_params'] = [ + $formParams = [ 'userid' => $user, 'password' => '123456' ]; if ($displayname !== '') { - $options['form_params']['displayName'] = $displayname; + $formParams['displayName'] = $displayname; } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->post($fullUrl, $options); + $this->response = $this->sendOcsRequest('POST', $fullUrl, [ + 'form_params' => $formParams, + ]); if ($this->currentServer === 'LOCAL') { $this->createdUsers[$user] = $user; } elseif ($this->currentServer === 'REMOTE') { $this->createdRemoteUsers[$user] = $user; } - //Quick hack to login once with the current user - $options2 = [ - 'auth' => [$user, '123456'], - ]; - $options2['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; + // Quick hack to login once with the current user + $client = $this->getGuzzleClient(null); $url = $fullUrl . '/' . $user; - $client->get($url, $options2); + $client->get($url, [ + 'auth' => [$user, '123456'], + 'headers' => [ + 'OCS-APIREQUEST' => 'true', + ], + ]); } /** @@ -150,18 +163,7 @@ public function creatingTheUser($user, $displayname = '') { */ public function userHasSetting($user, $settings) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } else { - $options['auth'] = [$this->currentUser, $this->regularUser]; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $response = $client->get($fullUrl, $options); + $response = $this->sendOcsRequest('GET', $fullUrl); foreach ($settings->getRows() as $setting) { $value = json_decode(json_encode(simplexml_load_string($response->getBody())->data->{$setting[0]}), 1); if (isset($value['element']) && in_array($setting[0], ['additional_mail', 'additional_mailScope'], true)) { @@ -182,19 +184,11 @@ public function userHasSetting($user, $settings) { */ public function userHasProfileData(string $user, ?TableNode $settings): void { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/profile/$user"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } else { - $options['auth'] = [$this->currentUser, $this->regularUser]; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - 'Accept' => 'application/json', - ]; - - $response = $client->get($fullUrl, $options); + $response = $this->sendOcsRequest('GET', $fullUrl, [ + 'headers' => [ + 'Accept' => 'application/json', + ], + ]); $body = $response->getBody()->getContents(); $data = json_decode($body, true); $data = $data['ocs']['data']; @@ -211,23 +205,12 @@ public function userHasProfileData(string $user, ?TableNode $settings): void { /** * @Then /^group "([^"]*)" has$/ * - * @param string $user + * @param string $group * @param TableNode|null $settings */ public function groupHasSetting($group, $settings) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups/details?search=$group"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } else { - $options['auth'] = [$this->currentUser, $this->regularUser]; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $response = $client->get($fullUrl, $options); + $response = $this->sendOcsRequest('GET', $fullUrl); $groupDetails = simplexml_load_string($response->getBody())->data[0]->groups[0]->element; foreach ($settings->getRows() as $setting) { $value = json_decode(json_encode($groupDetails->{$setting[0]}), 1); @@ -251,18 +234,7 @@ public function userHasEditableFields($user, $fields) { if ($user !== 'self') { $fullUrl .= '/' . $user; } - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } else { - $options['auth'] = [$this->currentUser, $this->regularUser]; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $response = $client->get($fullUrl, $options); + $response = $this->sendOcsRequest('GET', $fullUrl); $fieldsArray = json_decode(json_encode(simplexml_load_string($response->getBody())->data->element), 1); $expectedFields = $fields->getRows(); @@ -276,17 +248,11 @@ public function userHasEditableFields($user, $fields) { /** * @Then /^search users by phone for region "([^"]*)" with$/ * - * @param string $user - * @param TableNode|null $settings + * @param string $region + * @param TableNode $searchTable */ public function searchUserByPhone($region, TableNode $searchTable) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/search/by-phone"; - $client = new Client(); - $options = []; - $options['auth'] = $this->adminUser; - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; $search = []; foreach ($searchTable->getRows() as $row) { @@ -296,12 +262,12 @@ public function searchUserByPhone($region, TableNode $searchTable) { $search[$row[0]][] = $row[1]; } - $options['form_params'] = [ - 'location' => $region, - 'search' => $search, - ]; - - $this->response = $client->post($fullUrl, $options); + $this->response = $this->sendOcsRequestAsAdmin('POST', $fullUrl, [ + 'form_params' => [ + 'location' => $region, + 'search' => $search, + ], + ]); } public function createUser($user) { @@ -338,14 +304,7 @@ public function deleteGroup($group) { public function userExists($user) { $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user"; - $client = new Client(); - $options = []; - $options['auth'] = $this->adminUser; - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true' - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequestAsAdmin('GET', $fullUrl); } /** @@ -355,16 +314,7 @@ public function userExists($user) { */ public function checkThatUserBelongsToGroup($user, $group) { $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequest('GET', $fullUrl); $respondedArray = $this->getArrayOfGroupsResponded($this->response); sort($respondedArray); Assert::assertContains($group, $respondedArray); @@ -373,16 +323,7 @@ public function checkThatUserBelongsToGroup($user, $group) { public function userBelongsToGroup($user, $group) { $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequest('GET', $fullUrl); $respondedArray = $this->getArrayOfGroupsResponded($this->response); if (array_key_exists($group, $respondedArray)) { @@ -416,16 +357,7 @@ public function assureUserBelongsToGroup($user, $group) { */ public function userDoesNotBelongToGroup($user, $group) { $fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequest('GET', $fullUrl); $groups = [$group]; $respondedArray = $this->getArrayOfGroupsResponded($this->response); Assert::assertNotEqualsCanonicalizing($groups, $respondedArray); @@ -438,20 +370,11 @@ public function userDoesNotBelongToGroup($user, $group) { */ public function creatingTheGroup($group) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - - $options['form_params'] = [ - 'groupid' => $group, - ]; - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->post($fullUrl, $options); + $this->response = $this->sendOcsRequest('POST', $fullUrl, [ + 'form_params' => [ + 'groupid' => $group, + ], + ]); if ($this->currentServer === 'LOCAL') { $this->createdGroups[$group] = $group; } elseif ($this->currentServer === 'REMOTE') { @@ -464,20 +387,7 @@ public function creatingTheGroup($group) { */ public function assureUserIsDisabled($user) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user/disable"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - // TODO: fix hack - $options['form_params'] = [ - 'foo' => 'bar' - ]; - - $this->response = $client->put($fullUrl, $options); + $this->response = $this->sendOcsRequest('PUT', $fullUrl); } /** @@ -486,16 +396,7 @@ public function assureUserIsDisabled($user) { */ public function deletingTheUser($user) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->delete($fullUrl, $options); + $this->response = $this->sendOcsRequest('DELETE', $fullUrl); } /** @@ -504,16 +405,7 @@ public function deletingTheUser($user) { */ public function deletingTheGroup($group) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups/$group"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->delete($fullUrl, $options); + $this->response = $this->sendOcsRequest('DELETE', $fullUrl); if ($this->currentServer === 'LOCAL') { unset($this->createdGroups[$group]); @@ -540,33 +432,17 @@ public function addUserToGroup($user, $group) { */ public function addingUserToGroup($user, $group) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user/groups"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $options['form_params'] = [ - 'groupid' => $group, - ]; - - $this->response = $client->post($fullUrl, $options); + $this->response = $this->sendOcsRequest('POST', $fullUrl, [ + 'form_params' => [ + 'groupid' => $group, + ], + ]); } public function groupExists($group) { $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group"; - $client = new Client(); - $options = []; - $options['auth'] = $this->adminUser; - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequestAsAdmin('GET', $fullUrl); } /** @@ -574,9 +450,8 @@ public function groupExists($group) { * @param string $group */ public function assureGroupExists($group) { - try { - $this->groupExists($group); - } catch (\GuzzleHttp\Exception\ClientException $ex) { + $this->groupExists($group); + if ($this->response->getStatusCode() !== 200) { $previous_user = $this->currentUser; $this->currentUser = 'admin'; $this->creatingTheGroup($group); @@ -591,23 +466,16 @@ public function assureGroupExists($group) { * @param string $group */ public function groupDoesNotExist($group) { - try { - $this->groupExists($group); - } catch (\GuzzleHttp\Exception\ClientException $ex) { - $this->response = $ex->getResponse(); - Assert::assertEquals(404, $ex->getResponse()->getStatusCode()); + $this->groupExists($group); + if ($this->response->getStatusCode() === 404) { return; } $previous_user = $this->currentUser; $this->currentUser = 'admin'; $this->deletingTheGroup($group); $this->currentUser = $previous_user; - try { - $this->groupExists($group); - } catch (\GuzzleHttp\Exception\ClientException $ex) { - $this->response = $ex->getResponse(); - Assert::assertEquals(404, $ex->getResponse()->getStatusCode()); - } + $this->groupExists($group); + Assert::assertEquals(404, $this->response->getStatusCode()); } /** @@ -617,16 +485,7 @@ public function groupDoesNotExist($group) { */ public function userIsSubadminOfGroup($user, $group) { $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group/subadmins"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequest('GET', $fullUrl); $respondedArray = $this->getArrayOfSubadminsResponded($this->response); sort($respondedArray); Assert::assertContains($user, $respondedArray); @@ -640,18 +499,11 @@ public function userIsSubadminOfGroup($user, $group) { */ public function assureUserIsSubadminOfGroup($user, $group) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user/subadmins"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['form_params'] = [ - 'groupid' => $group - ]; - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - $this->response = $client->post($fullUrl, $options); + $this->response = $this->sendOcsRequest('POST', $fullUrl, [ + 'form_params' => [ + 'groupid' => $group, + ], + ]); Assert::assertEquals(200, $this->response->getStatusCode()); } @@ -662,16 +514,7 @@ public function assureUserIsSubadminOfGroup($user, $group) { */ public function userIsNotSubadminOfGroup($user, $group) { $fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group/subadmins"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequest('GET', $fullUrl); $respondedArray = $this->getArrayOfSubadminsResponded($this->response); sort($respondedArray); Assert::assertNotContains($user, $respondedArray); @@ -847,16 +690,7 @@ public function appEnabledStateWillBeRestoredOnceTheScenarioFinishes($app) { private function getAppsWithFilter($filter) { $fullUrl = $this->baseUrl . 'v2.php/cloud/apps?filter=' . $filter; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequest('GET', $fullUrl); return $this->getArrayOfAppsResponded($this->response); } @@ -899,16 +733,7 @@ public function appIsNotEnabled($app) { */ public function userIsDisabled($user) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequest('GET', $fullUrl); // false in xml is empty Assert::assertTrue(empty(simplexml_load_string($this->response->getBody())->data[0]->enabled)); } @@ -919,16 +744,7 @@ public function userIsDisabled($user) { */ public function userIsEnabled($user) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequest('GET', $fullUrl); // boolean to string is integer Assert::assertEquals('1', simplexml_load_string($this->response->getBody())->data[0]->enabled); } @@ -963,10 +779,7 @@ public function userHasUnlimitedQuota($user) { */ public function getUserHome($user) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user"; - $client = new Client(); - $options = []; - $options['auth'] = $this->adminUser; - $this->response = $client->get($fullUrl, $options); + $this->response = $this->sendOcsRequestAsAdmin('GET', $fullUrl); return simplexml_load_string($this->response->getBody())->data[0]->home; } @@ -1009,18 +822,7 @@ public function cleanupGroups() { */ public function userHasNotSetting($user, TableNode $settings) { $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user"; - $client = new Client(); - $options = []; - if ($this->currentUser === 'admin') { - $options['auth'] = $this->adminUser; - } else { - $options['auth'] = [$this->currentUser, $this->regularUser]; - } - $options['headers'] = [ - 'OCS-APIREQUEST' => 'true', - ]; - - $response = $client->get($fullUrl, $options); + $response = $this->sendOcsRequest('GET', $fullUrl); foreach ($settings->getRows() as $setting) { $value = json_decode(json_encode(simplexml_load_string($response->getBody())->data->{$setting[0]}), 1); if (isset($value[0])) { diff --git a/build/integration/features/bootstrap/Sharing.php b/build/integration/features/bootstrap/Sharing.php index aba3d3090beca..41dad1a3ddd3a 100644 --- a/build/integration/features/bootstrap/Sharing.php +++ b/build/integration/features/bootstrap/Sharing.php @@ -23,8 +23,7 @@ trait Sharing { /** @var SimpleXMLElement[] */ private array $storedShareData = []; private ?string $savedShareId = null; - /** @var ResponseInterface */ - private $response; + private ?ResponseInterface $response = null; /** * @Given /^as "([^"]*)" creating a share with$/ diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php index fb552ce785b75..ce5f99c9dcadc 100644 --- a/build/integration/features/bootstrap/WebDav.php +++ b/build/integration/features/bootstrap/WebDav.php @@ -22,8 +22,7 @@ trait WebDav { private bool $usingOldDavPath = true; private ?array $storedETAG = null; // map with user as key and another map as value, which has path as key and etag as value private ?int $storedFileID = null; - /** @var ResponseInterface */ - private $response; + private ?ResponseInterface $response = null; private array $parsedResponse = []; private string $s3MultipartDestination; private string $uploadId; @@ -69,25 +68,100 @@ public function getDavFilesPath($user) { } } - public function makeDavRequest($user, $method, $path, $headers, $body = null, $type = 'files') { + /** + * Returns the base URL for DAV operations (strips trailing "/ocs" from baseUrl). + */ + private function getDavBaseUrl(): string { + return substr($this->baseUrl, 0, -4); + } + + /** + * Resolves the full DAV endpoint URL for a given user, path, and request type. + * + * @param string|null $user The acting user + * @param string $path The resource path (e.g. "/myFile.txt") + * @param string $type One of 'files', 'uploads', or a DAV sub-collection name + * @return string The fully qualified URL + */ + private function getDavUrl(?string $user, string $path, string $type = 'files'): string { + $base = $this->getDavBaseUrl(); + if ($type === 'files') { - $fullUrl = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user) . "$path"; + return $base . $this->getDavFilesPath($user) . $path; } elseif ($type === 'uploads') { - $fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath . "$path"; - } else { - $fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath . '/' . $type . "$path"; + return $base . $this->davPath . $path; } - $client = new GClient(); + + return $base . $this->davPath . '/' . $type . $path; + } + + /** + * Returns the auth credentials for a user as a [username, password] tuple + * suitable for both Guzzle's 'auth' option and Sabre client construction. + * + * @param string|null $user + * @return array{string, string}|null Null if user is empty (unauthenticated) + */ + private function getAuthForUser(?string $user): ?array { + if ($user === 'admin') { + return $this->adminUser; + } elseif ($user !== null && $user !== '' && !str_starts_with($user, 'anonymous')) { + return [$user, $this->regularUser]; + } + + return null; + } + + /** + * Returns a pre-configured Sabre DAV client for the given user. + */ + public function getSabreClient(string $user): SClient { + $auth = $this->getAuthForUser($user); + + return new SClient([ + 'baseUri' => $this->getDavBaseUrl(), + 'userName' => $auth[0] ?? $user, + 'password' => $auth[1] ?? '', + 'authType' => SClient::AUTH_BASIC, + ]); + } + + /** + * Returns a pre-configured Guzzle client for the given user. + * + * Centralizes: base URL, auth resolution, http_errors suppression, + * and any future cross-cutting middleware (logging, retries, etc.). + * + * @param string|null $user The acting user, 'admin', or null/empty for unauthenticated + * @param array $extraConfig Additional Guzzle constructor config to merge + */ + public function getGuzzleClient(?string $user = null, array $extraConfig = []): GClient { + $config = [ + 'http_errors' => false, + ]; + + $auth = $this->getAuthForUser($user); + if ($auth !== null) { + $config['auth'] = $auth; + } + + return new GClient(array_merge($config, $extraConfig)); + } + + /** + * Returns the full DAV URL prefix for Destination headers, etc. + */ + public function getFullDavFilesUrl(string $user): string { + return $this->getDavBaseUrl() . $this->getDavFilesPath($user); + } + + public function makeDavRequest($user, $method, $path, $headers, $body = null, $type = 'files') { + $client = $this->getGuzzleClient($user); $options = [ 'headers' => $headers, - 'body' => $body + 'body' => $body, ]; - if ($user === 'admin') { - $options['auth'] = $this->adminUser; - } elseif ($user !== '') { - $options['auth'] = [$user, $this->regularUser]; - } - return $client->request($method, $fullUrl, $options); + return $client->request($method, $this->getDavUrl($user, $path, $type), $options); } /** @@ -110,13 +184,8 @@ public function userMovedFile($user, $entry, $fileSource, $fileDestination) { * @param string $fileDestination */ public function userMovesFile($user, $entry, $fileSource, $fileDestination) { - $fullUrl = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user); - $headers['Destination'] = $fullUrl . $fileDestination; - try { - $this->response = $this->makeDavRequest($user, 'MOVE', $fileSource, $headers); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $headers['Destination'] = $this->getFullDavFilesUrl($user) . $fileDestination; + $this->response = $this->makeDavRequest($user, 'MOVE', $fileSource, $headers); } /** @@ -126,14 +195,8 @@ public function userMovesFile($user, $entry, $fileSource, $fileDestination) { * @param string $fileDestination */ public function userCopiesFileTo($user, $fileSource, $fileDestination) { - $fullUrl = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user); - $headers['Destination'] = $fullUrl . $fileDestination; - try { - $this->response = $this->makeDavRequest($user, 'COPY', $fileSource, $headers); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx and 5xx responses cause an exception - $this->response = $e->getResponse(); - } + $headers['Destination'] = $this->getFullDavFilesUrl($user) . $fileDestination; + $this->response = $this->makeDavRequest($user, 'COPY', $fileSource, $headers); } /** @@ -152,14 +215,9 @@ public function downloadFileWithRange($fileSource, $range) { */ public function downloadPublicFileWithRange($range) { $token = $this->lastShareData->data->token; - $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/dav/files/$token"; - - $client = new GClient(); - $options = []; - $options['headers'] = [ - 'Range' => $range - ]; - + $fullUrl = $this->getDavBaseUrl() . "public.php/dav/files/$token"; + $client = $this->getGuzzleClient(null); + $options['headers'] = [ 'Range' => $range ]; $this->response = $client->request('GET', $fullUrl, $options); } @@ -169,15 +227,9 @@ public function downloadPublicFileWithRange($range) { */ public function downloadPublicFileInsideAFolderWithRange($path, $range) { $token = $this->lastShareData->data->token; - $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/dav/files/$token/$path"; - - $client = new GClient(); - $options = [ - 'headers' => [ - 'Range' => $range - ] - ]; - + $fullUrl = $this->getDavBaseUrl() . "public.php/dav/files/$token/$path"; + $client = $this->getGuzzleClient(null); + $options['headers'] = [ 'Range' => $range ]; $this->response = $client->request('GET', $fullUrl, $options); } @@ -243,11 +295,7 @@ public function downloadedContentWhenDownloadindShouldBe($fileSource, $range, $c * @When Downloading folder :folderName */ public function downloadingFolder(string $folderName) { - try { - $this->response = $this->makeDavRequest($this->currentUser, 'GET', $folderName, ['Accept' => 'application/zip']); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest($this->currentUser, 'GET', $folderName, ['Accept' => 'application/zip']); } /** @@ -255,19 +303,10 @@ public function downloadingFolder(string $folderName) { */ public function downloadPublicFolder(string $folderName) { $token = $this->lastShareData->data->token; - $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/dav/files/$token/$folderName"; - - $client = new GClient(); - $options = []; - $options['headers'] = [ - 'Accept' => 'application/zip' - ]; - - try { - $this->response = $client->request('GET', $fullUrl, $options); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $fullUrl = $this->getDavBaseUrl() . "public.php/dav/files/$token/$folderName"; + $client = $this->getGuzzleClient(null); + $options['headers'] = [ 'Accept' => 'application/zip' ]; + $this->response = $client->request('GET', $fullUrl, $options); } /** @@ -275,11 +314,7 @@ public function downloadPublicFolder(string $folderName) { * @param string $fileName */ public function downloadingFile($fileName) { - try { - $this->response = $this->makeDavRequest($this->currentUser, 'GET', $fileName, []); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest($this->currentUser, 'GET', $fileName, []); } /** @@ -287,20 +322,10 @@ public function downloadingFile($fileName) { */ public function downloadingPublicFile(string $filename) { $token = $this->lastShareData->data->token; - $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/dav/files/$token/$filename"; - - $client = new GClient(); - $options = [ - 'headers' => [ - 'X-Requested-With' => 'XMLHttpRequest', - ] - ]; - - try { - $this->response = $client->request('GET', $fullUrl, $options); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $fullUrl = $this->getDavBaseUrl() . "public.php/dav/files/$token/$filename"; + $client = $this->getGuzzleClient(null); + $options['headers'] = [ 'X-Requested-With' => 'XMLHttpRequest' ]; + $this->response = $client->request('GET', $fullUrl, $options); } /** @@ -308,14 +333,9 @@ public function downloadingPublicFile(string $filename) { */ public function downloadingPublicFileWithoutHeader(string $filename) { $token = $this->lastShareData->data->token; - $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/dav/files/$token/$filename"; - - $client = new GClient(); - try { - $this->response = $client->request('GET', $fullUrl); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $fullUrl = $this->getDavBaseUrl() . "public.php/dav/files/$token/$filename"; + $client = $this->getGuzzleClient(null); + $this->response = $client->request('GET', $fullUrl); } /** @@ -588,19 +608,7 @@ public function searchFile(string $user, ?string $properties = null, ?string $sc '; - try { - $this->response = $this->makeDavRequest($user, 'SEARCH', '', [ - 'Content-Type' => 'text/xml' - ], $body, ''); - - var_dump((string)$this->response->getBody()); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest($user, 'SEARCH', '', ['Content-Type' => 'text/xml'], $body, ''); } /* Returns the elements of a report command @@ -635,24 +643,6 @@ public function makeSabrePath($user, $path, $type = 'files') { } } - public function getSabreClient($user) { - $fullUrl = substr($this->baseUrl, 0, -4); - - $settings = [ - 'baseUri' => $fullUrl, - 'userName' => $user, - ]; - - if ($user === 'admin') { - $settings['password'] = $this->adminUser[1]; - } else { - $settings['password'] = $this->regularUser; - } - $settings['authType'] = SClient::AUTH_BASIC; - - return new SClient($settings); - } - /** * @Then /^user "([^"]*)" should see following elements$/ * @param string $user @@ -680,15 +670,7 @@ public function checkElementList($user, $expectedElements) { */ public function userUploadsAFileTo($user, $source, $destination) { $file = \GuzzleHttp\Psr7\Utils::streamFor(fopen($source, 'r')); - try { - $this->response = $this->makeDavRequest($user, 'PUT', $destination, [], $file); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest($user, 'PUT', $destination, [], $file); } /** @@ -712,15 +694,7 @@ public function userAddsAFileTo($user, $bytes, $destination) { */ public function userUploadsAFileWithContentTo($user, $content, $destination) { $file = \GuzzleHttp\Psr7\Utils::streamFor($content); - try { - $this->response = $this->makeDavRequest($user, 'PUT', $destination, [], $file); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest($user, 'PUT', $destination, [], $file); } /** @@ -730,15 +704,7 @@ public function userUploadsAFileWithContentTo($user, $content, $destination) { * @param string $file */ public function userDeletesFile($user, $type, $file) { - try { - $this->response = $this->makeDavRequest($user, 'DELETE', $file, []); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest($user, 'DELETE', $file, []); } /** @@ -747,16 +713,8 @@ public function userDeletesFile($user, $type, $file) { * @param string $destination */ public function userCreatedAFolder($user, $destination) { - try { - $destination = '/' . ltrim($destination, '/'); - $this->response = $this->makeDavRequest($user, 'MKCOL', $destination, []); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $destination = '/' . ltrim($destination, '/'); + $this->response = $this->makeDavRequest($user, 'MKCOL', $destination, []); } /** @@ -800,17 +758,15 @@ public function userUploadsBulkedFiles($user, $name1, $content1, $name2, $conten fwrite($stream, $body); rewind($stream); - $client = new GClient(); + $client = $this->getGuzzleClient($user); $options = [ - 'auth' => [$user, $this->regularUser], 'headers' => [ 'Content-Type' => 'multipart/related; boundary=' . $boundary, 'Content-Length' => (string)strlen($body), ], 'body' => $body ]; - - return $client->request('POST', substr($this->baseUrl, 0, -4) . 'remote.php/dav/bulk', $options); + return $client->request('POST', $this->getDavBaseUrl() . 'remote.php/dav/bulk', $options); } /** @@ -836,10 +792,8 @@ public function userUploadsNewChunkFileOfWithToId($user, $num, $data, $id) { */ public function userMovesNewChunkFileWithIdToMychunkedfile($user, $id, $dest) { $source = '/uploads/' . $user . '/' . $id . '/.file'; - $destination = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user) . $dest; - $this->makeDavRequest($user, 'MOVE', $source, [ - 'Destination' => $destination - ], null, 'uploads'); + $headers['Destination'] = $this->getFullDavFilesUrl($user) . $dest; + $this->makeDavRequest($user, 'MOVE', $source, $headers, null, 'uploads'); } /** @@ -847,16 +801,9 @@ public function userMovesNewChunkFileWithIdToMychunkedfile($user, $id, $dest) { */ public function userMovesNewChunkFileWithIdToMychunkedfileWithSize($user, $id, $dest, $size) { $source = '/uploads/' . $user . '/' . $id . '/.file'; - $destination = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user) . $dest; - - try { - $this->response = $this->makeDavRequest($user, 'MOVE', $source, [ - 'Destination' => $destination, - 'OC-Total-Length' => $size - ], null, 'uploads'); - } catch (\GuzzleHttp\Exception\BadResponseException $ex) { - $this->response = $ex->getResponse(); - } + $headers['Destination'] = $this->getFullDavFilesUrl($user) . $dest; + $headers['OC-Total-Length'] = $size; + $this->response = $this->makeDavRequest($user, 'MOVE', $source, $headers, null, 'uploads'); } @@ -867,9 +814,8 @@ public function userCreatesANewChunkingv2UploadWithIdAndDestination($user, $id, $this->s3MultipartDestination = $this->getTargetDestination($user, $targetDestination); $this->newUploadId(); $destination = '/uploads/' . $user . '/' . $this->getUploadId($id); - $this->response = $this->makeDavRequest($user, 'MKCOL', $destination, [ - 'Destination' => $this->s3MultipartDestination, - ], null, 'uploads'); + $headers['Destination'] = $this->s3MultipartDestination; + $this->response = $this->makeDavRequest($user, 'MKCOL', $destination, $headers, null, 'uploads'); } /** @@ -878,9 +824,8 @@ public function userCreatesANewChunkingv2UploadWithIdAndDestination($user, $id, public function userUploadsNewChunkv2FileToIdAndDestination($user, $num, $id) { $data = \GuzzleHttp\Psr7\Utils::streamFor(fopen('/tmp/part-upload-' . $num, 'r')); $destination = '/uploads/' . $user . '/' . $this->getUploadId($id) . '/' . $num; - $this->response = $this->makeDavRequest($user, 'PUT', $destination, [ - 'Destination' => $this->s3MultipartDestination - ], $data, 'uploads'); + $headers['Destination'] = $this->s3MultipartDestination; + $this->response = $this->makeDavRequest($user, 'PUT', $destination, $headers, $data, 'uploads'); } /** @@ -888,21 +833,12 @@ public function userUploadsNewChunkv2FileToIdAndDestination($user, $num, $id) { */ public function userMovesNewChunkv2FileWithIdToMychunkedfileAndDestination($user, $id) { $source = '/uploads/' . $user . '/' . $this->getUploadId($id) . '/.file'; - try { - $this->response = $this->makeDavRequest($user, 'MOVE', $source, [ - 'Destination' => $this->s3MultipartDestination, - ], null, 'uploads'); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $headers['Destination'] = $this->s3MultipartDestination; + $this->response = $this->makeDavRequest($user, 'MOVE', $source, $headers, null, 'uploads'); } private function getTargetDestination(string $user, string $destination): string { - return substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user) . $destination; + return $this->getFullDavFilesUrl($user) . $destination; } private function getUploadId(string $id): string { @@ -917,15 +853,7 @@ private function newUploadId() { * @Given /^Downloading file "([^"]*)" as "([^"]*)"$/ */ public function downloadingFileAs($fileName, $user) { - try { - $this->response = $this->makeDavRequest($user, 'GET', $fileName, []); - } catch (\GuzzleHttp\Exception\ServerException $e) { - // 5xx responses cause a server exception - $this->response = $e->getResponse(); - } catch (\GuzzleHttp\Exception\ClientException $e) { - // 4xx responses cause a client exception - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest($user, 'GET', $fileName, []); } /** @@ -955,27 +883,11 @@ public function userUnfavoritesElement($user, $path) { /*Set the elements of a proppatch, $folderDepth requires 1 to see elements without children*/ public function changeFavStateOfAnElement($user, $path, $favOrUnfav, $folderDepth, $properties = null) { - $fullUrl = substr($this->baseUrl, 0, -4); - $settings = [ - 'baseUri' => $fullUrl, - 'userName' => $user, - ]; - if ($user === 'admin') { - $settings['password'] = $this->adminUser[1]; - } else { - $settings['password'] = $this->regularUser; - } - $settings['authType'] = SClient::AUTH_BASIC; - - $client = new SClient($settings); + $client = $this->getSabreClient($user); if (!$properties) { - $properties = [ - '{http://owncloud.org/ns}favorite' => $favOrUnfav - ]; + $properties = ['{http://owncloud.org/ns}favorite' => $favOrUnfav]; } - - $response = $client->proppatch($this->getDavFilesPath($user) . $path, $properties, $folderDepth); - return $response; + return $client->proppatch($this->getDavFilesPath($user) . $path, $properties, $folderDepth); } /** @@ -1010,11 +922,7 @@ public function checkIfETAGHasChanged($path, $user) { * @When Connecting to dav endpoint */ public function connectingToDavEndpoint() { - try { - $this->response = $this->makeDavRequest(null, 'PROPFIND', '', []); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest(null, 'PROPFIND', '', []); } /** @@ -1027,11 +935,7 @@ public function requestingShareNote() { } else { $token = $this->lastShareData->data->token; } - try { - $this->response = $this->makeDavRequest('', 'PROPFIND', $token, [], $propfind); - } catch (\GuzzleHttp\Exception\ClientException $e) { - $this->response = $e->getResponse(); - } + $this->response = $this->makeDavRequest('', 'PROPFIND', $token, [], $propfind); } /** diff --git a/build/integration/features/provisioning-v1.feature b/build/integration/features/provisioning-v1.feature index 62b58279c616c..c9037b39f4c40 100644 --- a/build/integration/features/provisioning-v1.feature +++ b/build/integration/features/provisioning-v1.feature @@ -858,7 +858,7 @@ Feature: provisioning And Assure user "subadmin" is subadmin of group "new-group" And assure user "subadmin" is disabled And As an "subadmin" - When sending "PUT" to "/cloud/users/subadmin/enabled" + When sending "PUT" to "/cloud/users/subadmin/enable" And As an "admin" And user "subadmin" is disabled