diff --git a/CHANGELOG.md b/CHANGELOG.md index cfcfa237..ef10200d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## Next Release + +- Add `allChildren` and `getNextPageOfChildren` methods to `user` service + ## v7.0.0 (2023-12-01) Upgrading major versions of this project? Refer to the [Upgrade Guide](UPGRADE_GUIDE.md). diff --git a/lib/EasyPost/Service/UserService.php b/lib/EasyPost/Service/UserService.php index d9a39e1f..c19bba6a 100644 --- a/lib/EasyPost/Service/UserService.php +++ b/lib/EasyPost/Service/UserService.php @@ -2,6 +2,7 @@ namespace EasyPost\Service; +use EasyPost\Exception\General\EndOfPaginationException; use EasyPost\Http\Requestor; use EasyPost\Util\InternalUtil; @@ -139,4 +140,60 @@ public function updateBrand(string $id, mixed $params = null): mixed return InternalUtil::convertToEasyPostObject($this->client, $response); } + + /** + * Retrieve all child users. + * + * @param mixed $params + * @return mixed + */ + public function allChildren(mixed $params = null): mixed + { + self::validate($params); + + $url = '/users/children'; + $response = Requestor::request($this->client, 'get', $url, $params); + if (isset($params)) { + $response['_params'] = $params; + } + + return InternalUtil::convertToEasyPostObject($this->client, $response); + } + + /** + * Retrieve the next page of child User collection + * + * @param mixed $children + * @param int|null $pageSize + * @return mixed + */ + public function getNextPageOfChildren(mixed $children, ?int $pageSize = null): mixed + { + $userArray = $children['children']; + $userParams = $children['_params'] ?? null; + + // Check to see if there is another page server-side before attempting to retrieve it + if (empty($userArray) || !$children['has_more']) { + throw new EndOfPaginationException(); + } + + $params = [ + 'page_size' => $pageSize, + 'before_id' => $userArray[count($userArray) - 1]['id'] + ]; + + if (isset($userParams)) { + $params = array_merge($params, $userParams); + } + + // Retrieve a page of users from the server + $children = $this->allChildren($params); + + // If the page we just retrieved is empty, then we have reached the end of the list + if (empty($children['children'])) { + throw new EndOfPaginationException(); + } + + return $children; + } } diff --git a/test/EasyPost/UserTest.php b/test/EasyPost/UserTest.php index a117c6f8..2f063bd8 100644 --- a/test/EasyPost/UserTest.php +++ b/test/EasyPost/UserTest.php @@ -3,7 +3,9 @@ namespace EasyPost\Test; use EasyPost\EasyPostClient; +use EasyPost\Exception\General\EndOfPaginationException; use EasyPost\User; +use Exception; class UserTest extends \PHPUnit\Framework\TestCase { @@ -73,6 +75,52 @@ public function testRetrieveMe(): void $this->assertStringMatchesFormat('user_%s', $user->id); } + /** + * Test retrieving all child users. + */ + public function testAllChildren(): void + { + TestUtil::setupCassette('users/allChildren.yml'); + + $children = self::$client->user->allChildren([ + 'page_size' => Fixture::pageSize(), + ]); + + $userArray = $children['children']; + + $this->assertLessThanOrEqual($userArray, Fixture::pageSize()); + $this->assertNotNull($children['has_more']); + $this->assertContainsOnlyInstancesOf(User::class, $userArray); + } + + /** + * Test retrieving next page. + * @noinspection RedundantSuppression + * @throws Exception + */ + public function testGetNextPageOfChildren(): void + { + TestUtil::setupCassette('users/getNextPageOfChildren.yml'); + + try { + $children = self::$client->user->allChildren([ + 'page_size' => Fixture::pageSize(), + ]); + $nextPage = self::$client->user->getNextPageOfChildren($children, Fixture::pageSize()); + + $firstIdOfFirstPage = $children['children'][0]->id; + $secondIdOfSecondPage = $nextPage['children'][0]->id; + + $this->assertNotEquals($firstIdOfFirstPage, $secondIdOfSecondPage); + } catch (EndOfPaginationException $error) { + // There's no second page, that's not a failure + $this->assertTrue(true); + } catch (Exception $error) { + /** @noinspection PhpExceptionImmediatelyRethrownInspection */ + throw $error; + } + } + /** * Test updating the authenticated user. */ diff --git a/test/cassettes/users/allChildren.yml b/test/cassettes/users/allChildren.yml new file mode 100644 index 00000000..8eb9bc16 --- /dev/null +++ b/test/cassettes/users/allChildren.yml @@ -0,0 +1,78 @@ + +- + request: + method: GET + url: 'https://api.easypost.com/v2/users/children?page_size=5' + headers: + Host: api.easypost.com + Accept-Encoding: '' + Accept: application/json + Authorization: '' + Content-Type: application/json + User-Agent: '' + response: + status: + code: 200 + message: OK + headers: + x-frame-options: SAMEORIGIN + x-xss-protection: '1; mode=block' + x-content-type-options: nosniff + x-download-options: noopen + x-permitted-cross-domain-policies: none + referrer-policy: strict-origin-when-cross-origin + x-ep-request-uuid: 3c78c40b6597056af44028d1000d5fda + cache-control: 'private, no-cache, no-store' + pragma: no-cache + expires: '0' + content-type: 'application/json; charset=utf-8' + content-length: '887' + x-runtime: '0.038435' + x-node: bigweb36nuq + x-version-label: easypost-202401041812-437974c716-master + x-backend: easypost + x-proxied: ['intlb2nuq 2c48984abf', 'extlb2nuq 003ad9bca0'] + strict-transport-security: 'max-age=31536000; includeSubDomains; preload' + body: '{"children":[{"id":"user_3c44214dcf744d169c3f2db034fd965e","object":"User","parent_id":"user_465eab8bb86844108100be2d4d5288ab","name":"Test User","phone_number":"","verified":true,"created_at":"2022-11-23T21:03:03Z"},{"id":"user_78019b89199646358298fd311435458f","object":"User","parent_id":"user_465eab8bb86844108100be2d4d5288ab","name":"Test User","phone_number":"","verified":true,"created_at":"2022-12-02T22:41:09Z"},{"id":"user_1a2e9fb7903c4a08b2da7d7f57150370","object":"User","parent_id":"user_465eab8bb86844108100be2d4d5288ab","name":"Test User","phone_number":"","verified":true,"created_at":"2022-12-02T22:43:07Z"},{"id":"user_f01890d357374ac3837ff556a957b9b4","object":"User","parent_id":"user_465eab8bb86844108100be2d4d5288ab","name":"Test User","phone_number":"","verified":true,"created_at":"2022-12-05T17:00:14Z"}],"has_more":false}' + curl_info: + url: 'https://api.easypost.com/v2/users/children?page_size=5' + content_type: 'application/json; charset=utf-8' + http_code: 200 + header_size: 688 + request_size: 303 + filetime: -1 + ssl_verify_result: 0 + redirect_count: 0 + total_time: 0.289887 + namelookup_time: 0.109241 + connect_time: 0.15427 + pretransfer_time: 0.21253 + size_upload: 0.0 + size_download: 887.0 + speed_download: 3059.0 + speed_upload: 0.0 + download_content_length: 887.0 + upload_content_length: 0.0 + starttransfer_time: 0.28986 + redirect_time: 0.0 + redirect_url: '' + primary_ip: 169.62.110.130 + certinfo: { } + primary_port: 443 + local_ip: 172.168.100.149 + local_port: 57058 + http_version: 2 + protocol: 2 + ssl_verifyresult: 0 + scheme: HTTPS + appconnect_time_us: 212452 + connect_time_us: 154270 + namelookup_time_us: 109241 + pretransfer_time_us: 212530 + redirect_time_us: 0 + starttransfer_time_us: 289860 + total_time_us: 289887 + effective_method: GET + capath: '' + cainfo: '' + index: 0 diff --git a/test/cassettes/users/getNextPageOfChildren.yml b/test/cassettes/users/getNextPageOfChildren.yml new file mode 100644 index 00000000..2e78efa3 --- /dev/null +++ b/test/cassettes/users/getNextPageOfChildren.yml @@ -0,0 +1,78 @@ + +- + request: + method: GET + url: 'https://api.easypost.com/v2/users/children?page_size=5' + headers: + Host: api.easypost.com + Accept-Encoding: '' + Accept: application/json + Authorization: '' + Content-Type: application/json + User-Agent: '' + response: + status: + code: 200 + message: OK + headers: + x-frame-options: SAMEORIGIN + x-xss-protection: '1; mode=block' + x-content-type-options: nosniff + x-download-options: noopen + x-permitted-cross-domain-policies: none + referrer-policy: strict-origin-when-cross-origin + x-ep-request-uuid: 3c78c40b6597056bf0221b62000d5ffb + cache-control: 'private, no-cache, no-store' + pragma: no-cache + expires: '0' + content-type: 'application/json; charset=utf-8' + content-length: '887' + x-runtime: '0.035511' + x-node: bigweb36nuq + x-version-label: easypost-202401041812-437974c716-master + x-backend: easypost + x-proxied: ['intlb1nuq 2c48984abf', 'extlb2nuq 003ad9bca0'] + strict-transport-security: 'max-age=31536000; includeSubDomains; preload' + body: '{"children":[{"id":"user_3c44214dcf744d169c3f2db034fd965e","object":"User","parent_id":"user_465eab8bb86844108100be2d4d5288ab","name":"Test User","phone_number":"","verified":true,"created_at":"2022-11-23T21:03:03Z"},{"id":"user_78019b89199646358298fd311435458f","object":"User","parent_id":"user_465eab8bb86844108100be2d4d5288ab","name":"Test User","phone_number":"","verified":true,"created_at":"2022-12-02T22:41:09Z"},{"id":"user_1a2e9fb7903c4a08b2da7d7f57150370","object":"User","parent_id":"user_465eab8bb86844108100be2d4d5288ab","name":"Test User","phone_number":"","verified":true,"created_at":"2022-12-02T22:43:07Z"},{"id":"user_f01890d357374ac3837ff556a957b9b4","object":"User","parent_id":"user_465eab8bb86844108100be2d4d5288ab","name":"Test User","phone_number":"","verified":true,"created_at":"2022-12-05T17:00:14Z"}],"has_more":false}' + curl_info: + url: 'https://api.easypost.com/v2/users/children?page_size=5' + content_type: 'application/json; charset=utf-8' + http_code: 200 + header_size: 688 + request_size: 303 + filetime: -1 + ssl_verify_result: 0 + redirect_count: 0 + total_time: 0.15691 + namelookup_time: 0.001169 + connect_time: 0.042299 + pretransfer_time: 0.081692 + size_upload: 0.0 + size_download: 887.0 + speed_download: 5652.0 + speed_upload: 0.0 + download_content_length: 887.0 + upload_content_length: 0.0 + starttransfer_time: 0.156866 + redirect_time: 0.0 + redirect_url: '' + primary_ip: 169.62.110.130 + certinfo: { } + primary_port: 443 + local_ip: 172.168.100.149 + local_port: 57059 + http_version: 2 + protocol: 2 + ssl_verifyresult: 0 + scheme: HTTPS + appconnect_time_us: 81617 + connect_time_us: 42299 + namelookup_time_us: 1169 + pretransfer_time_us: 81692 + redirect_time_us: 0 + starttransfer_time_us: 156866 + total_time_us: 156910 + effective_method: GET + capath: '' + cainfo: '' + index: 0