diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b853d2..7940874 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,12 +13,14 @@ Návod pro přechod: [UPGRADE-2.0.md](UPGRADE-2.0.md). - Data k odeslání, která nejdou převést na JSON (např. neplatné UTF-8), vyhodí `EcomailFlexibeeRequestFail`. Verze 1.4 v takovém případě tiše odeslala požadavek bez platného těla. Základní URL bez schématu nebo hostitele je odmítnuta při vytvoření klienta. ### Nové +- Přílohy záznamů: `getAttachments()`, `getAttachmentContent()`, `addAttachment()` a `deleteAttachment()` (#31). `HttpClient::send()` odešle `CurlRequest` včetně binárního těla. - `Client::findByCodes()` načte více záznamů evidence podle seznamu kódů jedním requestem (#43). - `Client` a `CompanyClient` přijímají volitelný `HttpClient`. - `Config::debugMode()` a `Config::withEvidence()`. - Výchozí timeouty požadavků (5 s spojení, 25 s celkem). ### Opravy +- Odpověď se čte jako PDF jen u `GET`, jehož cesta končí na `.pdf`. Dříve stačilo, aby URL kdekoli obsahovala `.pdf`, např. nahrání přílohy `faktura.pdf` nebo filtr s `.pdf`. - Kód záznamu s apostrofem je odmítnut výjimkou `EcomailFlexibeeInvalidRequestParameter`. Dříve mohl změnit význam filtru `(kod eq '…')`. - Ověření TLS certifikátu se při přihlášení přes session nevypíná, pokud je `$verifySSLCertificate` zapnuté. - Název firmy v URL pro obnovu zálohy je zakódovaný (`&` nebo `#` v názvu už nerozbije URL). diff --git a/README.md b/README.md index b885e65..bb3da50 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,16 @@ $client->deleteById($id, $dryRun); $client->deleteByCode($code, $dryRun); ``` +## Přílohy +Přílohy záznamu evidence (podle id záznamu): +``` +$attachments = $client->getAttachments($evidenceItemId); // pole EvidenceResult (id, nazSoub, contentType, …) +$content = $client->getAttachmentContent($evidenceItemId, $attachmentId); // binární obsah přílohy +$attachmentId = $client->addAttachment($evidenceItemId, 'faktura.pdf', $content, 'application/pdf'); +$client->deleteAttachment($evidenceItemId, $attachmentId); +``` +Existující přílohu FlexiBee neumí změnit, je potřeba ji smazat a nahrát znovu. Dokumentace FlexiBee: [Přílohy](https://podpora.flexibee.eu/cs/articles/4722200-prilohy). + ## Generování PDF Systém Flexibee umožňuje vrátit vygenerované faktury. ``` diff --git a/UPGRADE-2.0.md b/UPGRADE-2.0.md index cc622f1..7ecc49b 100644 --- a/UPGRADE-2.0.md +++ b/UPGRADE-2.0.md @@ -64,5 +64,6 @@ Následující změny se týkají jen kódu, který tyto třídy používá nebo - `EcomailFlexibee\Http\UrlBuilder` už nedědí z `Purl\Url`. Zděděné metody (`setPath()`, `setQuery()`, `getUrl()` …) nejsou k dispozici a konstruktor nepřijímá `Purl\ParserInterface`. - `EcomailFlexibee\Validator\ParameterValidator` už nedědí z `Rakit\Validation\Validator`. - `EcomailFlexibee\Http\ResponseFactory::createFromOutput()` má navíc parametr `?string $curlInfoDebug`. +- `EcomailFlexibee\Http\HttpCurlBuilder::build()` přijímá `CurlRequest` a `Config` místo samostatných parametrů. `HttpClient::request()` zůstává beze změny. - `EcomailFlexibee\Config` a `EcomailFlexibee\Result\EvidenceResult` jsou `readonly` třídy. - Název firmy v `UrlBuilder::createRestoreUrl()` se v URL kóduje (`rawurlencode()`). diff --git a/src/Client.php b/src/Client.php index 0a4a581..22aa846 100644 --- a/src/Client.php +++ b/src/Client.php @@ -5,7 +5,9 @@ namespace EcomailFlexibee; use EcomailFlexibee\Exception\EcomailFlexibeeNoEvidenceResult; +use EcomailFlexibee\Exception\EcomailFlexibeeRequestFail; use EcomailFlexibee\Exception\EcomailFlexibeeSaveFailed; +use EcomailFlexibee\Http\CurlRequest; use EcomailFlexibee\Http\HttpClient; use EcomailFlexibee\Http\Method; use EcomailFlexibee\Http\Response\FlexibeeResponse; @@ -262,6 +264,90 @@ public function findByCode(string $code, array $uriParameters = []): EvidenceRes } } + /** + * @return array<\EcomailFlexibee\Result\EvidenceResult> + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeConnectionFail + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeForbidden + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeInvalidAuthorization + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeMethodNotAllowed + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeNotAcceptableRequest + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeRequestFail + */ + public function getAttachments(int $id): array + { + return $this->responseHydrator->convertResponseToAttachments( + $this->httpClient->request($this->queryBuilder->createAttachmentsUrl($id), Method::GET, [], [], [], $this->config), + ); + } + + /** + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeConnectionFail + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeForbidden + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeInvalidAuthorization + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeMethodNotAllowed + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeNoEvidenceResult + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeNotAcceptableRequest + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeRequestFail + */ + public function getAttachmentContent(int $id, int $attachmentId): string + { + $content = $this->httpClient->request( + $this->queryBuilder->createAttachmentContentUrl($id, $attachmentId), + Method::GET, + [], + [], + [], + $this->config, + )->getData()['attachmentContent'] ?? null; + + if (!is_string($content)) { + throw new EcomailFlexibeeNoEvidenceResult(); + } + + return $content; + } + + /** + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeConnectionFail + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeForbidden + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeInvalidAuthorization + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeMethodNotAllowed + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeNotAcceptableRequest + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeRequestFail + */ + public function addAttachment(int $id, string $fileName, string $content, string $contentType): int + { + $response = $this->httpClient->send( + new CurlRequest( + $this->queryBuilder->createNewAttachmentUrl($id, $fileName), + Method::PUT, + headers: [sprintf('Content-Type: %s', $contentType), 'Accept: application/json'], + body: $content, + ), + $this->config, + ); + $result = $response->getData()[0] ?? null; + + if (is_array($result) && isset($result['id']) && is_numeric($result['id'])) { + return (int) $result['id']; + } + + throw new EcomailFlexibeeRequestFail('FlexiBee did not return the ID of the new attachment.'); + } + + /** + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeConnectionFail + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeForbidden + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeInvalidAuthorization + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeMethodNotAllowed + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeNotAcceptableRequest + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeRequestFail + */ + public function deleteAttachment(int $id, int $attachmentId): void + { + $this->httpClient->request($this->queryBuilder->createAttachmentUrl($id, $attachmentId), Method::DELETE, [], [], [], $this->config); + } + /** * @param list $codes * @param array $uriParameters diff --git a/src/Http/CurlOptionsFactory.php b/src/Http/CurlOptionsFactory.php index 4f9b261..a4ca120 100644 --- a/src/Http/CurlOptionsFactory.php +++ b/src/Http/CurlOptionsFactory.php @@ -63,12 +63,10 @@ public function create(CurlRequest $request, Config $config): array CURLOPT_USERAGENT => self::USER_AGENT, ] + $this->createAuthenticationOptions($config); - if (count($request->postFields) > 0) { - $options[CURLOPT_POSTFIELDS] = $this->encodePostFields($request->postFields); - } + $postFields = $this->createPostFields($request); - if (count($request->queryParameters) > 0) { - $options[CURLOPT_POSTFIELDS] = http_build_query($request->queryParameters); + if ($postFields !== null) { + $options[CURLOPT_POSTFIELDS] = $postFields; } $headers = $request->headers; @@ -112,4 +110,20 @@ private function encodePostFields(array $postFields): string } } + /** + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeRequestFail + */ + private function createPostFields(CurlRequest $request): ?string + { + if (count($request->queryParameters) > 0) { + return http_build_query($request->queryParameters); + } + + if ($request->body !== null) { + return $request->body; + } + + return count($request->postFields) > 0 ? $this->encodePostFields($request->postFields) : null; + } + } diff --git a/src/Http/CurlRequest.php b/src/Http/CurlRequest.php index befe031..c7a2817 100644 --- a/src/Http/CurlRequest.php +++ b/src/Http/CurlRequest.php @@ -18,6 +18,7 @@ public function __construct( public array $postFields = [], public array $queryParameters = [], public array $headers = [], + public ?string $body = null, ) { } diff --git a/src/Http/HttpClient.php b/src/Http/HttpClient.php index 921cb3c..86a52ad 100644 --- a/src/Http/HttpClient.php +++ b/src/Http/HttpClient.php @@ -40,8 +40,20 @@ public function __construct() { */ public function request(string $url, Method $httpMethod, array $postFields, array $queryParameters, array $headers, Config $config): FlexibeeResponse { + return $this->send(new CurlRequest($url, $httpMethod, $postFields, $queryParameters, $headers), $config); + } - $ch = $this->httpCurlBuilder->build($url, $httpMethod, $postFields, $queryParameters, $headers, $config); + /** + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeConnectionFail + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeForbidden + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeInvalidAuthorization + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeMethodNotAllowed + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeNotAcceptableRequest + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeRequestFail + */ + public function send(CurlRequest $request, Config $config): FlexibeeResponse + { + $ch = $this->httpCurlBuilder->build($request, $config); $output = curl_exec($ch); $output = is_string($output) ? $output : null; @@ -52,8 +64,8 @@ public function request(string $url, Method $httpMethod, array $postFields, arra $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); return ResponseFactory::createFromOutput( - $url, - $httpMethod, + $request->url, + $request->httpMethod, $output, $statusCode, curl_errno($ch), diff --git a/src/Http/HttpCurlBuilder.php b/src/Http/HttpCurlBuilder.php index 6bad11c..2d0c478 100644 --- a/src/Http/HttpCurlBuilder.php +++ b/src/Http/HttpCurlBuilder.php @@ -21,14 +21,12 @@ public function __construct() } /** - * @param array $postFields - * @param array $queryParameters - * @param array $headers + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeRequestFail */ - public function build(string $url, Method $httpMethod, array $postFields, array $queryParameters, array $headers, Config $config): CurlHandle + public function build(CurlRequest $request, Config $config): CurlHandle { $ch = curl_init(); - curl_setopt_array($ch, $this->curlOptionsFactory->create(new CurlRequest($url, $httpMethod, $postFields, $queryParameters, $headers), $config)); + curl_setopt_array($ch, $this->curlOptionsFactory->create($request, $config)); return $ch; } diff --git a/src/Http/Response/FlexibeeAttachmentResponse.php b/src/Http/Response/FlexibeeAttachmentResponse.php new file mode 100644 index 0000000..d69e4ef --- /dev/null +++ b/src/Http/Response/FlexibeeAttachmentResponse.php @@ -0,0 +1,17 @@ + $attachmentContent, + ]); + } + +} diff --git a/src/Http/ResponseFactory.php b/src/Http/ResponseFactory.php index c1af413..851a5a1 100644 --- a/src/Http/ResponseFactory.php +++ b/src/Http/ResponseFactory.php @@ -10,6 +10,7 @@ use EcomailFlexibee\Exception\EcomailFlexibeeMethodNotAllowed; use EcomailFlexibee\Exception\EcomailFlexibeeNotAcceptableRequest; use EcomailFlexibee\Exception\EcomailFlexibeeRequestFail; +use EcomailFlexibee\Http\Response\FlexibeeAttachmentResponse; use EcomailFlexibee\Http\Response\FlexibeeBackupResponse; use EcomailFlexibee\Http\Response\FlexibeePdfResponse; use EcomailFlexibee\Http\Response\FlexibeeResponse; @@ -22,11 +23,13 @@ use function is_string; use function json_decode; use function mb_stripos; -use function mb_strpos; +use function parse_url; use function reset; use function sprintf; +use function str_ends_with; use const CURLE_OK; +use const PHP_URL_PATH; final class ResponseFactory { @@ -56,15 +59,25 @@ public static function createFromOutput( throw new EcomailFlexibeeConnectionFail(sprintf('cURL error (%s): %s', $errorNumber, $errorMessage)); } - if (mb_strpos($url, '.pdf') !== false) { + return self::createBinaryResponse($url, $httpMethod, $responseContent, $statusCode) + ?? self::createFromJson($responseContent, $statusCode, $curlInfoDebug); + } + + private static function createBinaryResponse(string $url, Method $httpMethod, string $responseContent, int $statusCode): ?FlexibeeResponse + { + if ($httpMethod !== Method::GET) { + return null; + } + + if (str_ends_with((string) parse_url($url, PHP_URL_PATH), '.pdf')) { return new FlexibeePdfResponse($responseContent); } - if ($httpMethod === Method::GET && mb_stripos($url, '/backup') !== false) { + if (mb_stripos($url, '/backup') !== false) { return new FlexibeeBackupResponse($responseContent); } - return self::createFromJson($responseContent, $statusCode, $curlInfoDebug); + return $statusCode === 200 && str_ends_with($url, '/content') ? new FlexibeeAttachmentResponse($responseContent) : null; } /** diff --git a/src/Http/ResponseHydrator.php b/src/Http/ResponseHydrator.php index 9f5c2d7..15e3eea 100644 --- a/src/Http/ResponseHydrator.php +++ b/src/Http/ResponseHydrator.php @@ -19,6 +19,8 @@ class ResponseHydrator { + private const ATTACHMENTS_KEY = 'priloha'; + public function __construct(private readonly Config $config) { } @@ -54,6 +56,17 @@ public function convertResponseToPaginatedEvidenceResults(Response $response): a ]; } + /** + * @return array<\EcomailFlexibee\Result\EvidenceResult> + * @throws \EcomailFlexibee\Exception\EcomailFlexibeeRequestFail + */ + public function convertResponseToAttachments(Response $response): array + { + $attachments = $this->getDataOrThrowRequestFail($response)[self::ATTACHMENTS_KEY] ?? []; + + return is_array($attachments) ? $this->createEvidenceResults($attachments) : []; + } + public function convertResponseToEvidenceResult(Response $response, bool $throwException): EvidenceResult { $data = $response->getData(); diff --git a/src/Http/UrlBuilder.php b/src/Http/UrlBuilder.php index 468f3f4..3e21557 100644 --- a/src/Http/UrlBuilder.php +++ b/src/Http/UrlBuilder.php @@ -117,6 +117,26 @@ public function createUriByCodeOnly(string $code, array $uriParameters): string return $this->createUrl($this->buildPathWithIdOrFilter(sprintf('(kod eq \'%s\')', $code)), $uriParameters); } + public function createAttachmentsUrl(int $id): string + { + return $this->createUrl(sprintf('%s.json', $this->buildAttachmentsPath($id))); + } + + public function createAttachmentUrl(int $id, int $attachmentId): string + { + return $this->createUrl(sprintf('%s/%d.json', $this->buildAttachmentsPath($id), $attachmentId)); + } + + public function createAttachmentContentUrl(int $id, int $attachmentId): string + { + return $this->createUrl(sprintf('%s/%d/content', $this->buildAttachmentsPath($id), $attachmentId)); + } + + public function createNewAttachmentUrl(int $id, string $fileName): string + { + return $this->createUrl(sprintf('%s/new/%s', $this->buildAttachmentsPath($id), rawurlencode($fileName))); + } + /** * @param list $codes * @param array $uriParameters @@ -183,6 +203,11 @@ private function buildPathWithIdOrFilter(string|int $filterQueryOrId, string $fo return sprintf('c/%s/%s/%s.%s', $this->company, $this->evidence, $filterQueryOrId, $format); } + private function buildAttachmentsPath(int $id): string + { + return sprintf('c/%s/%s/%d/prilohy', $this->company, $this->evidence, $id); + } + private function buildPathForOnlyEvidence(): string { return sprintf('c/%s/%s.json', $this->company, $this->evidence); diff --git a/tests/ClientOfflineTest.php b/tests/ClientOfflineTest.php index 3a1e450..8d9cf3c 100644 --- a/tests/ClientOfflineTest.php +++ b/tests/ClientOfflineTest.php @@ -7,9 +7,12 @@ use EcomailFlexibee\Client; use EcomailFlexibee\Config as ClientConfig; use EcomailFlexibee\Exception\EcomailFlexibeeNoEvidenceResult; +use EcomailFlexibee\Exception\EcomailFlexibeeRequestFail; use EcomailFlexibee\Exception\EcomailFlexibeeSaveFailed; +use EcomailFlexibee\Http\CurlRequest; use EcomailFlexibee\Http\HttpClient; use EcomailFlexibee\Http\Method; +use EcomailFlexibee\Http\Response\FlexibeeAttachmentResponse; use EcomailFlexibee\Http\Response\FlexibeeResponse; use EcomailFlexibee\Result\EvidenceResult; use Mockery; @@ -202,6 +205,72 @@ public function testCountInEvidenceReturnsTheRowCount(): void Assert::assertSame(12, $this->createClient($this->respondWithResponse($response))->countInEvidence()); } + public function testGetAttachmentsReturnsAttachmentsOfTheRecord(): void + { + $httpClient = Mockery::mock(HttpClient::class); + $httpClient->shouldReceive('request') + ->once() + ->with('https://demo.flexibee.eu/c/demo/adresar/7/prilohy.json', Method::GET, [], [], [], Mockery::type(ClientConfig::class)) + ->andReturn($this->createResponse(['priloha' => [['id' => '14']]])); + + Assert::assertEquals([new EvidenceResult(['id' => '14'])], $this->createClient($httpClient)->getAttachments(7)); + } + + public function testGetAttachmentContentReturnsTheBinaryContent(): void + { + $client = $this->createClient($this->respondWithResponse(new FlexibeeAttachmentResponse("\x89PNG"))); + + Assert::assertSame("\x89PNG", $client->getAttachmentContent(7, 14)); + } + + public function testGetAttachmentContentThrowsWhenTheAttachmentIsMissing(): void + { + $client = $this->createClient($this->respondWith([], statusCode: 404)); + + $this->expectException(EcomailFlexibeeNoEvidenceResult::class); + + $client->getAttachmentContent(7, 99); + } + + public function testAddAttachmentUploadsRawContentAndReturnsTheNewId(): void + { + $httpClient = Mockery::mock(HttpClient::class); + $httpClient->shouldReceive('send') + ->once() + ->with( + Mockery::on(static fn (CurlRequest $request): bool => $request->url === 'https://demo.flexibee.eu/c/demo/adresar/7/prilohy/new/invoice.txt' + && $request->httpMethod === Method::PUT + && $request->headers === ['Content-Type: text/plain', 'Accept: application/json'] + && $request->body === 'content' + && $request->postFields === []), + Mockery::type(ClientConfig::class), + ) + ->andReturn($this->createResponse([['id' => '5837', 'ref' => '/c/demo/adresar/7/prilohy/5837.json']], statusCode: 201)); + + Assert::assertSame(5_837, $this->createClient($httpClient)->addAttachment(7, 'invoice.txt', 'content', 'text/plain')); + } + + public function testAddAttachmentThrowsWhenTheResponseHasNoId(): void + { + $httpClient = Mockery::mock(HttpClient::class); + $httpClient->shouldReceive('send')->andReturn($this->createResponse([])); + + $this->expectException(EcomailFlexibeeRequestFail::class); + + $this->createClient($httpClient)->addAttachment(7, 'invoice.txt', 'content', 'text/plain'); + } + + public function testDeleteAttachmentSendsDeleteToTheAttachmentDetail(): void + { + $httpClient = Mockery::mock(HttpClient::class); + $httpClient->shouldReceive('request') + ->once() + ->with('https://demo.flexibee.eu/c/demo/adresar/7/prilohy/14.json', Method::DELETE, [], [], [], Mockery::type(ClientConfig::class)) + ->andReturn($this->createResponse([])); + + $this->createClient($httpClient)->deleteAttachment(7, 14); + } + private function createClient(HttpClient $httpClient): Client { return new Client(new ClientConfig('https://demo.flexibee.eu', 'demo', 'user', 'pass', 'adresar', verifySSLCertificate: true), $httpClient); diff --git a/tests/Http/CurlOptionsFactoryTest.php b/tests/Http/CurlOptionsFactoryTest.php index 8273992..739c59f 100644 --- a/tests/Http/CurlOptionsFactoryTest.php +++ b/tests/Http/CurlOptionsFactoryTest.php @@ -136,4 +136,15 @@ public function testQueryParametersReplacePostFields(): void Assert::assertSame('username=u&password=p', $options[CURLOPT_POSTFIELDS]); } + public function testSendsRawBodyAsIs(): void + { + $config = new Config('https://demo.flexibee.eu', 'demo', 'user', 'pass', 'cenik', verifySSLCertificate: true); + $request = new CurlRequest('https://demo.flexibee.eu', Method::PUT, headers: ['Content-Type: text/plain'], body: 'raw bytes'); + + $options = (new CurlOptionsFactory())->create($request, $config); + + Assert::assertSame('raw bytes', $options[CURLOPT_POSTFIELDS]); + Assert::assertSame(['Content-Type: text/plain'], $options[CURLOPT_HTTPHEADER]); + } + } diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 19d9a18..8d8a80f 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -5,6 +5,7 @@ namespace EcomailFlexibeeTest\Http; use EcomailFlexibee\Config; +use EcomailFlexibee\Http\CurlRequest; use EcomailFlexibee\Http\HttpClient; use EcomailFlexibee\Http\Method; use PHPUnit\Framework\Assert; @@ -31,6 +32,13 @@ public function testDebugModeDoesNotBreakTheRequest(): void Assert::assertSame(['@version' => '1.0', 'adresar' => [['id' => '1']]], $response->getData()); } + public function testSendsCurlRequest(): void + { + $response = (new HttpClient())->send(new CurlRequest($this->getFixtureUrl(), Method::GET), $this->createConfig(debugMode: false)); + + Assert::assertSame(['@version' => '1.0', 'adresar' => [['id' => '1']]], $response->getData()); + } + private function getFixtureUrl(): string { return sprintf('file://%s', realpath(__DIR__ . '/fixtures/adresar.json')); diff --git a/tests/Http/QueryBuilderTest.php b/tests/Http/QueryBuilderTest.php index 3978538..c2da4c6 100644 --- a/tests/Http/QueryBuilderTest.php +++ b/tests/Http/QueryBuilderTest.php @@ -160,6 +160,19 @@ public function testRejectsBaseUrlWithoutSchemeOrHost(): void new UrlBuilder(new Config('user:secret@demo.flexibee.eu', 'demo', 'u', 'p', 'adresar', verifySSLCertificate: false)); } + public function testCreatesAttachmentUrls(): void + { + $urlBuilder = new UrlBuilder(new Config(TestConfig::HOST, TestConfig::COMPANY, 'u', 'p', 'cenik', verifySSLCertificate: false)); + + Assert::assertSame('https://demo.flexibee.eu/c/demo/cenik/164/prilohy.json', $urlBuilder->createAttachmentsUrl(164)); + Assert::assertSame('https://demo.flexibee.eu/c/demo/cenik/164/prilohy/15/content', $urlBuilder->createAttachmentContentUrl(164, 15)); + Assert::assertSame('https://demo.flexibee.eu/c/demo/cenik/164/prilohy/15.json', $urlBuilder->createAttachmentUrl(164, 15)); + Assert::assertSame( + 'https://demo.flexibee.eu/c/demo/cenik/164/prilohy/new/m%C3%B4j%20s%C3%BAbor%23%3F.txt', + $urlBuilder->createNewAttachmentUrl(164, 'môj súbor#?.txt'), + ); + } + protected function setUp(): void { parent::setUp(); diff --git a/tests/Http/ResponseFactoryTest.php b/tests/Http/ResponseFactoryTest.php index dab8935..e5cc3b3 100644 --- a/tests/Http/ResponseFactoryTest.php +++ b/tests/Http/ResponseFactoryTest.php @@ -11,6 +11,7 @@ use EcomailFlexibee\Exception\EcomailFlexibeeNotAcceptableRequest; use EcomailFlexibee\Exception\EcomailFlexibeeRequestFail; use EcomailFlexibee\Http\Method; +use EcomailFlexibee\Http\Response\FlexibeeAttachmentResponse; use EcomailFlexibee\Http\Response\FlexibeeBackupResponse; use EcomailFlexibee\Http\Response\FlexibeePdfResponse; use EcomailFlexibee\Http\ResponseFactory; @@ -179,4 +180,82 @@ public function testServerErrorWithoutErrorDetailsThrowsResponseMessage(): void ); } + public function testAttachmentContentUrlReturnsAttachmentResponse(): void + { + $response = ResponseFactory::createFromOutput( + 'https://demo.flexibee.eu/c/demo/cenik/164/prilohy/15/content', + Method::GET, + "\x89PNG", + 200, + CURLE_OK, + errorMessage: null, + curlInfoDebug: null, + ); + + Assert::assertInstanceOf(FlexibeeAttachmentResponse::class, $response); + Assert::assertSame(['attachmentContent' => "\x89PNG"], $response->getData()); + } + + public function testMissingAttachmentContentIsParsedAsJson(): void + { + $response = ResponseFactory::createFromOutput( + 'https://demo.flexibee.eu/c/demo/cenik/164/prilohy/99/content', + Method::GET, + '{"winstrom":{"success":"false","message":"Not found"}}', + 404, + CURLE_OK, + errorMessage: null, + curlInfoDebug: null, + ); + + Assert::assertNotInstanceOf(FlexibeeAttachmentResponse::class, $response); + Assert::assertFalse($response->isSuccess()); + } + + public function testUploadOfPdfAttachmentIsParsedAsJson(): void + { + $response = ResponseFactory::createFromOutput( + 'https://demo.flexibee.eu/c/demo/cenik/164/prilohy/new/faktura.pdf', + Method::PUT, + '{"winstrom":{"success":"true","results":[{"id":"5837"}]}}', + 201, + CURLE_OK, + errorMessage: null, + curlInfoDebug: null, + ); + + Assert::assertNotInstanceOf(FlexibeePdfResponse::class, $response); + Assert::assertSame([['id' => '5837']], $response->getData()); + } + + public function testSearchFilterMentioningPdfIsParsedAsJson(): void + { + $response = ResponseFactory::createFromOutput( + "https://demo.flexibee.eu/c/demo/priloha/(nazSoub%20like%20'.pdf').json?limit=0", + Method::GET, + '{"winstrom":{"priloha":[]}}', + 200, + CURLE_OK, + errorMessage: null, + curlInfoDebug: null, + ); + + Assert::assertNotInstanceOf(FlexibeePdfResponse::class, $response); + } + + public function testPdfUrlWithQueryReturnsPdfResponse(): void + { + $response = ResponseFactory::createFromOutput( + 'https://demo.flexibee.eu/c/demo/faktura-vydana/1.pdf?report-name=x', + Method::GET, + '%PDF', + 200, + CURLE_OK, + errorMessage: null, + curlInfoDebug: null, + ); + + Assert::assertInstanceOf(FlexibeePdfResponse::class, $response); + } + } diff --git a/tests/Http/ResponseHydratorTest.php b/tests/Http/ResponseHydratorTest.php index 9b3b1f9..2e1aa06 100644 --- a/tests/Http/ResponseHydratorTest.php +++ b/tests/Http/ResponseHydratorTest.php @@ -133,6 +133,30 @@ public function testMissingEvidenceReturnsEmptyResultForEmptyData(): void Assert::assertEquals(new EvidenceResult([]), $result); } + public function testAttachmentsAreReadFromThePrilohaCollection(): void + { + $response = $this->createResponse(['priloha' => [['id' => '14', 'nazSoub' => 'a.jpg'], ['id' => '15', 'nazSoub' => 'b.jpg']]]); + + $results = $this->createHydrator()->convertResponseToAttachments($response); + + Assert::assertEquals( + [new EvidenceResult(['id' => '14', 'nazSoub' => 'a.jpg']), new EvidenceResult(['id' => '15', 'nazSoub' => 'b.jpg'])], + $results, + ); + } + + public function testRecordWithoutAttachmentsHasNoAttachments(): void + { + Assert::assertSame([], $this->createHydrator()->convertResponseToAttachments($this->createResponse([]))); + } + + public function testFailedAttachmentsResponseThrowsRequestFail(): void + { + $this->expectException(EcomailFlexibeeRequestFail::class); + + $this->createHydrator()->convertResponseToAttachments($this->createResponse(['success' => 'false', 'message' => 'Denied'])); + } + private function createHydrator(): ResponseHydrator { return new ResponseHydrator(