diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d651ea..6ca0d72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v2.2.8] - 2023-09-18 +### Added +- Endpoints for uploading and getting user's initials +- Endpoints for uploading and getting user's signature + ## [v2.2.7] - 2023-03-24 ### Updated - Fixed type of `invite_link_instructions` parameter in routing detail diff --git a/README.md b/README.md index 1f9efc1..f2c28da 100644 --- a/README.md +++ b/README.md @@ -40,13 +40,17 @@ Simple API Client to integrate SignNow with your application or website. Sign do * [Get User Event Subscriptions](#get-event-subscriptions) * [Create User Event Subscription](#create-event-subscription) * [Delete User Event Subscription](#delete-event-subscription) - * [Embedded invites] (#embedded-invites) + * [Embedded invites](#embedded-invites) * [Create embedded invites](#create-embedded-invites) * [Create signing link](#create-signing-link) * [Prolong signing link](#prolong-signing-link) * [Delete embedded invites](#delete-embedded-invites) * [Reassign signers](#reassign-signers) - + * [User](#user) + * [Upload Initials](#upload-initials) + * [Get Initials](#get-initials) + * [Upload Signature](#upload-signature) + * [Get Signature](#get-signature) ## Requirements PHP 7.1 or newer @@ -104,10 +108,14 @@ $entityManager = $auth->bearerByPassword('YOUR_BASIC_TOKEN_STRING', 'username', SignNow PHP SDK is covered with functional tests using Codeception and Phiremock. Phiremock allows us to mock calls to SignNow API. All the calls pass at 127.0.0.1 port 8008. Ensure that this port is not in use in the local machine before running test. -Test execution in console: +All the tests execution in console: ```bash vendor/bin/codecept run functional ``` +A single test execution in console: +```bash +vendor/bin/codecept run tests/functional/Template/CreateCest.php +``` Also, tests might be useful as examples of using SignNow PHP SDK. ### Sandbox Directory [sandbox](sandbox) contains php script to taste some SDK feature. @@ -579,3 +587,75 @@ $documentUniqueId = '0d3122a857514462a67515c0a39c6015780518f2'; $embedInvite->delete($documentUniqueId); ``` #### Reassign signers +### User +### Upload Initials +```php +use SignNow\Api\Action\OAuth as SignNowOAuth; +use SignNow\Api\Action\User\Initial as UserInitial; + +$auth = new SignNowOAuth('https://api.signnow.com'); +$initial = new UserInitial( + $auth->bearerByPassword('YOUR_BASIC_TOKEN', 'user', 'password') +); + +$userInitialBase64EncodedImage = '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'; +$entity = $initial->upload($userInitialBase64EncodedImage); + +echo $entity->getId(), PHP_EOL, + $entity->getWidth(), PHP_EOL, + $entity->getHeight(), PHP_EOL; +``` +### Get Initials +```php +use SignNow\Api\Action\OAuth as SignNowOAuth; +use SignNow\Api\Action\User\Initial as UserInitial; + +$auth = new SignNowOAuth('https://api.signnow.com'); +$initial = new UserInitial( + $auth->bearerByPassword('YOUR_BASIC_TOKEN', 'user', 'password') +); + +$entity = $initial->get(); + +$signatureImage = base64_decode($entity->getData()); + +echo $entity->getId(), PHP_EOL, + $entity->getWidth(), PHP_EOL, + $entity->getHeight(), PHP_EOL; +``` +### Upload Signature +```php +use SignNow\Api\Action\OAuth as SignNowOAuth; +use SignNow\Api\Action\User\Signature as UserSignature; + +$auth = new SignNowOAuth('https://api.signnow.com'); +$signature = new UserSignature( + $auth->bearerByPassword('YOUR_BASIC_TOKEN', 'user', 'password') +); + +$userSignatureImage = file_get_contents('/path/to/image'); +$userSignatureBase64EncodedImage = base64_decode($userSignatureImage); +$entity = $signature->upload($userSignatureBase64EncodedImage); + +echo $entity->getId(), PHP_EOL, + $entity->getWidth(), PHP_EOL, + $entity->getHeight(), PHP_EOL; +``` +### Get Signature +```php +use SignNow\Api\Action\OAuth as SignNowOAuth; +use SignNow\Api\Action\User\Signature as UserSignature; + +$auth = new SignNowOAuth('https://api.signnow.com'); +$signature = new UserSignature( + $auth->bearerByPassword('YOUR_BASIC_TOKEN', 'user', 'password') +); + +$entity = $signature->get(); + +$signatureImage = base64_decode($entity->getData()); + +echo $entity->getId(), PHP_EOL, + $entity->getWidth(), PHP_EOL, + $entity->getHeight(), PHP_EOL; +``` diff --git a/src/Action/User/Initial.php b/src/Action/User/Initial.php new file mode 100644 index 0000000..c6d659c --- /dev/null +++ b/src/Action/User/Initial.php @@ -0,0 +1,61 @@ +entityManager = $entityManager; + } + + /** + * @param string $base64ImageData + * + * @return object|ImageResponse + * @throws EntityManagerException|ReflectionException + */ + public function upload(string $base64ImageData): ImageResponse + { + $this->entityManager->setUpdateHttpMethod(Request::METHOD_PUT); + + return $this->entityManager->update( + new UserInitialEntity($base64ImageData) + ); + } + + /** + * @return object|ImageResponse + * @throws EntityManagerException|ReflectionException + */ + public function get(): ImageResponse + { + return $this->entityManager->get( + new UserInitialEntity() + ); + } +} diff --git a/src/Action/User/Signature.php b/src/Action/User/Signature.php new file mode 100644 index 0000000..b794754 --- /dev/null +++ b/src/Action/User/Signature.php @@ -0,0 +1,61 @@ +entityManager = $entityManager; + } + + /** + * @param string $base64ImageData + * + * @return object|ImageResponse + * @throws EntityManagerException|ReflectionException + */ + public function upload(string $base64ImageData): ImageResponse + { + $this->entityManager->setUpdateHttpMethod(Request::METHOD_PUT); + + return $this->entityManager->update( + new UserSignatureEntity($base64ImageData) + ); + } + + /** + * @return object|ImageResponse + * @throws EntityManagerException|ReflectionException + */ + public function get(): ImageResponse + { + return $this->entityManager->get( + new UserSignatureEntity() + ); + } +} diff --git a/src/Entity/User/ImageResponse.php b/src/Entity/User/ImageResponse.php new file mode 100644 index 0000000..1615f37 --- /dev/null +++ b/src/Entity/User/ImageResponse.php @@ -0,0 +1,102 @@ +uniqueId ?? $this->id; + } + + /** + * @return int + */ + public function getWidth(): int + { + return $this->width; + } + + /** + * @return int + */ + public function getHeight(): int + { + return $this->height; + } + + /** + * @return int + */ + public function getCreated(): int + { + return $this->created; + } + + /** + * @return string + */ + public function getData(): string + { + return $this->data; + } +} diff --git a/src/Entity/User/Initial.php b/src/Entity/User/Initial.php new file mode 100644 index 0000000..2e7fbec --- /dev/null +++ b/src/Entity/User/Initial.php @@ -0,0 +1,35 @@ +data = $data; + } +} diff --git a/src/Entity/User/Signature.php b/src/Entity/User/Signature.php new file mode 100644 index 0000000..8021f7b --- /dev/null +++ b/src/Entity/User/Signature.php @@ -0,0 +1,35 @@ +data = $data; + } +} diff --git a/tests/_support/Module/Mock/ApiUserMock.php b/tests/_support/Module/Mock/ApiUserMock.php new file mode 100644 index 0000000..8d18a91 --- /dev/null +++ b/tests/_support/Module/Mock/ApiUserMock.php @@ -0,0 +1,162 @@ +phiremock = $phiremock; + } + + /** + * {@inheritdoc} + */ + public function _depends() + { + return [ + 'Phiremock' => sprintf('"%s" depends on module "Phiremock"', __CLASS__), + ]; + } + + /** + * @return void + * @throws ClientExceptionInterface + * @throws Exception + */ + public function mockGetUserInitial(): void + { + $this->phiremock->expectARequestToRemoteServiceWithAResponse( + Phiremock::on( + A::getRequest() + ->andUrl(Is::equalTo(self::USER_INITIAL_URL)) + )->then( + Respond::withStatusCode(200) + ->andHeader('Content-Type', 'application/json') + ->andBody( + json_encode( + [ + 'id' => Str::generateUniqueId(), + 'width' => 100, + 'height' => 100, + 'created' => time(), + ] + ) + ) + ) + ); + } + + /** + * @return void + * @throws ClientExceptionInterface + * @throws Exception + */ + public function mockUpdateUserInitial(): void + { + $this->phiremock->expectARequestToRemoteServiceWithAResponse( + Phiremock::on( + A::putRequest() + ->andUrl(Is::equalTo(self::USER_INITIAL_URL)) + )->then( + Respond::withStatusCode(200) + ->andHeader('Content-Type', 'application/json') + ->andBody( + json_encode( + [ + 'id' => Str::generateUniqueId(), + 'width' => 100, + 'height' => 100, + 'created' => time(), + ] + ) + ) + ) + ); + } + + /** + * @return void + * @throws ClientExceptionInterface + * @throws Exception + */ + public function mockGetUserSignature(): void + { + $this->phiremock->expectARequestToRemoteServiceWithAResponse( + Phiremock::on( + A::getRequest() + ->andUrl(Is::equalTo(self::USER_SIGNATURE_URL)) + )->then( + Respond::withStatusCode(200) + ->andHeader('Content-Type', 'application/json') + ->andBody( + json_encode( + [ + 'id' => Str::generateUniqueId(), + 'width' => 100, + 'height' => 100, + 'created' => time(), + ] + ) + ) + ) + ); + } + + /** + * @return void + * @throws ClientExceptionInterface + * @throws Exception + */ + public function mockUpdateUserSignature(): void + { + $this->phiremock->expectARequestToRemoteServiceWithAResponse( + Phiremock::on( + A::putRequest() + ->andUrl(Is::equalTo(self::USER_SIGNATURE_URL)) + )->then( + Respond::withStatusCode(200) + ->andHeader('Content-Type', 'application/json') + ->andBody( + json_encode( + [ + 'id' => Str::generateUniqueId(), + 'width' => 100, + 'height' => 100, + 'created' => time(), + ] + ) + ) + ) + ); + } +} diff --git a/tests/functional.suite.yml b/tests/functional.suite.yml index 04e1201..3c34574 100644 --- a/tests/functional.suite.yml +++ b/tests/functional.suite.yml @@ -38,4 +38,6 @@ modules: depends: Phiremock - \Module\Mock\Debug: depends: Phiremock + - \Module\Mock\ApiUserMock: + depends: Phiremock step_decorators: ~ diff --git a/tests/functional/User/UserInitialCest.php b/tests/functional/User/UserInitialCest.php new file mode 100644 index 0000000..2efb7ee --- /dev/null +++ b/tests/functional/User/UserInitialCest.php @@ -0,0 +1,73 @@ +auth = $this->createSignNowBearerTokenAuth($I); + } + + /** + * @throws ReflectionException + * @throws EntityManagerException + */ + public function testUpdate(FunctionalTester $I): void + { + $I->mockUpdateUserInitial(); + + $initial = new Initial($this->auth); + + $base64encodedImageOfInitial = Str::getBase64Image(); + + $entity = $initial->upload($base64encodedImageOfInitial); + + $I->assertSame(40, strlen($entity->getId())); + $I->assertSame(100, $entity->getWidth()); + $I->assertSame(100, $entity->getHeight()); + $I->assertIsInt($entity->getCreated()); + } + + /** + * @throws ReflectionException + * @throws EntityManagerException + */ + public function testGet(FunctionalTester $I): void + { + $I->mockGetUserInitial(); + + $initial = new Initial($this->auth); + + + $entity = $initial->get(); + + $I->assertSame(40, strlen($entity->getId())); + $I->assertSame(100, $entity->getWidth()); + $I->assertSame(100, $entity->getHeight()); + $I->assertIsInt($entity->getCreated()); + } +} diff --git a/tests/functional/User/UserSignatureCest.php b/tests/functional/User/UserSignatureCest.php new file mode 100644 index 0000000..f473d79 --- /dev/null +++ b/tests/functional/User/UserSignatureCest.php @@ -0,0 +1,73 @@ +auth = $this->createSignNowBearerTokenAuth($I); + } + + /** + * @throws ReflectionException + * @throws EntityManagerException + */ + public function testUpdate(FunctionalTester $I): void + { + $I->mockUpdateUserSignature(); + + $signature = new Signature($this->auth); + + $base64encodedImageOfSignature = Str::getBase64Image(); + + $entity = $signature->upload($base64encodedImageOfSignature); + + $I->assertSame(40, strlen($entity->getId())); + $I->assertSame(100, $entity->getWidth()); + $I->assertSame(100, $entity->getHeight()); + $I->assertIsInt($entity->getCreated()); + } + + /** + * @throws ReflectionException + * @throws EntityManagerException + */ + public function testGet(FunctionalTester $I): void + { + $I->mockGetUserSignature(); + + $signature = new Signature($this->auth); + + + $entity = $signature->get(); + + $I->assertSame(40, strlen($entity->getId())); + $I->assertSame(100, $entity->getWidth()); + $I->assertSame(100, $entity->getHeight()); + $I->assertIsInt($entity->getCreated()); + } +}