From 67ce3c66cb546dfd5cfb0c5a179d4b8829de693d Mon Sep 17 00:00:00 2001 From: SergkeiM Date: Wed, 29 Jul 2026 12:57:37 +0300 Subject: [PATCH] feat: Enhance Accounts API and client documentation generation The Accounts API client has been significantly expanded and restructured to include new functionality for managing account profiles, organizations, subscriptions, and API tokens. Existing audit logs functionality has been reorganized under a new `Logs` accessor to better reflect the Cloudflare API structure, and the `Roles` API methods have been removed. To accommodate these changes and improve maintainability for complex API hierarchies, the documentation generation script (`bin/generate-client-docs.php`) was refactored. It now recursively generates nested markdown files and directories, ensuring accurate and up-to-date client API reference documentation, and automatically removes stale files during regeneration. --- bin/generate-client-docs.php | 113 +++++++----- docs/content/2.client/00.accounts/00.index.md | 76 +++++++- .../{02.members.md => 01.members.md} | 0 docs/content/2.client/00.accounts/01.roles.md | 60 ------- .../2.client/00.accounts/02.logs/00.index.md | 11 ++ .../2.client/00.accounts/02.logs/01.audit.md | 87 +++++++++ .../2.client/00.accounts/03.audit-logs.md | 34 ---- .../2.client/00.accounts/03.subscriptions.md | 113 ++++++++++++ .../00.accounts/04.tokens/00.index.md | 169 ++++++++++++++++++ .../04.tokens/01.permission-groups.md | 34 ++++ .../00.accounts/04.tokens/02.value.md | 33 ++++ src/Endpoints/Accounts.php | 74 ++++++-- src/Endpoints/Accounts/Logs.php | 19 ++ src/Endpoints/Accounts/Logs/Audit.php | 58 ++++++ src/Endpoints/Accounts/Roles.php | 39 ---- src/Endpoints/Accounts/Subscriptions.php | 69 +++++++ src/Endpoints/Accounts/Tokens.php | 123 +++++++++++++ .../PermissionGroups.php} | 14 +- src/Endpoints/Accounts/Tokens/Value.php | 24 +++ .../Endpoints/Accounts/Logs/AuditTest.php | 72 ++++++++ test/Tests/Endpoints/Accounts/RolesTest.php | 41 ----- .../Endpoints/Accounts/SubscriptionsTest.php | 75 ++++++++ .../PermissionGroupsTest.php} | 10 +- .../Endpoints/Accounts/Tokens/ValueTest.php | 27 +++ test/Tests/Endpoints/Accounts/TokensTest.php | 112 ++++++++++++ test/Tests/Endpoints/AccountsTest.php | 43 +++++ 26 files changed, 1289 insertions(+), 241 deletions(-) rename docs/content/2.client/00.accounts/{02.members.md => 01.members.md} (100%) delete mode 100644 docs/content/2.client/00.accounts/01.roles.md create mode 100644 docs/content/2.client/00.accounts/02.logs/00.index.md create mode 100644 docs/content/2.client/00.accounts/02.logs/01.audit.md delete mode 100644 docs/content/2.client/00.accounts/03.audit-logs.md create mode 100644 docs/content/2.client/00.accounts/03.subscriptions.md create mode 100644 docs/content/2.client/00.accounts/04.tokens/00.index.md create mode 100644 docs/content/2.client/00.accounts/04.tokens/01.permission-groups.md create mode 100644 docs/content/2.client/00.accounts/04.tokens/02.value.md create mode 100644 src/Endpoints/Accounts/Logs.php create mode 100644 src/Endpoints/Accounts/Logs/Audit.php delete mode 100644 src/Endpoints/Accounts/Roles.php create mode 100644 src/Endpoints/Accounts/Subscriptions.php create mode 100644 src/Endpoints/Accounts/Tokens.php rename src/Endpoints/Accounts/{AuditLogs.php => Tokens/PermissionGroups.php} (50%) create mode 100644 src/Endpoints/Accounts/Tokens/Value.php create mode 100644 test/Tests/Endpoints/Accounts/Logs/AuditTest.php delete mode 100644 test/Tests/Endpoints/Accounts/RolesTest.php create mode 100644 test/Tests/Endpoints/Accounts/SubscriptionsTest.php rename test/Tests/Endpoints/Accounts/{AuditLogsTest.php => Tokens/PermissionGroupsTest.php} (57%) create mode 100644 test/Tests/Endpoints/Accounts/Tokens/ValueTest.php create mode 100644 test/Tests/Endpoints/Accounts/TokensTest.php diff --git a/bin/generate-client-docs.php b/bin/generate-client-docs.php index c23ef7a..d1194cd 100644 --- a/bin/generate-client-docs.php +++ b/bin/generate-client-docs.php @@ -267,17 +267,26 @@ function frontmatter(string $title, string $description): string // --------------------------------------------------------------------- // 4. Walk the tree and write files +// +// Recursive to any depth: a node with no child accessors renders as a +// flat NN.slug.md file; a node with children renders as a folder with +// its own 00.index.md (API methods + a Related list) plus one file +// (flat or, recursively, another folder) per child. // --------------------------------------------------------------------- -@mkdir($outDir, 0777, true); -file_put_contents($outDir . '/.navigation.yml', "title: Client Reference\nicon: i-lucide-terminal\n"); - -$topIndex = 0; -foreach ($topLevel as $accessorName => $class) { +function writeNode( + DocBlockFactory $docFactory, + string $accessorName, + string $accessorChain, + string $class, + string $dir, + int $prefixIndex, + string $urlPath +): void { [$rc, $apiMethods, $children] = analyzeClass($class); $slug = kebab($accessorName); - $prefix = str_pad((string) $topIndex++, 2, '0', STR_PAD_LEFT); + $prefix = str_pad((string) $prefixIndex, 2, '0', STR_PAD_LEFT); $title = humanize($accessorName); $classDoc = docblockFor($docFactory, $rc); @@ -285,21 +294,21 @@ function frontmatter(string $title, string $description): string $classSummary = $realSummary !== '' ? $realSummary : "{$title} endpoint reference."; if (empty($children)) { - // flat file: docs/content/2.client/NN.slug.md + // flat file: .../NN.slug.md $body = frontmatter($title, $classSummary); if ($realSummary !== '') { $body .= $realSummary . "\n\n"; } foreach ($apiMethods as $m) { - $body .= renderMethodSection($docFactory, $m, "{$accessorName}()"); + $body .= renderMethodSection($docFactory, $m, $accessorChain); } - file_put_contents("{$outDir}/{$prefix}.{$slug}.md", $body); - continue; + file_put_contents("{$dir}/{$prefix}.{$slug}.md", $body); + return; } - // folder with index.md + one file per child - $dir = "{$outDir}/{$prefix}.{$slug}"; - @mkdir($dir, 0777, true); + // folder with index.md + one file (or subfolder) per child + $nodeDir = "{$dir}/{$prefix}.{$slug}"; + @mkdir($nodeDir, 0777, true); $body = frontmatter($title, $classSummary); if ($realSummary !== '') { @@ -307,47 +316,65 @@ function frontmatter(string $title, string $description): string } foreach ($apiMethods as $m) { - $body .= renderMethodSection($docFactory, $m, "{$accessorName}()"); + $body .= renderMethodSection($docFactory, $m, $accessorChain); } - if (!empty($children)) { - $body .= "## Related\n\n"; - foreach ($children as $childAccessor => $childClass) { - $childTitle = humanize($childAccessor); - $body .= "- [{$childTitle}](/client/{$slug}/" . kebab($childAccessor) . ")\n"; - } - $body .= "\n"; + $body .= "## Related\n\n"; + foreach ($children as $childAccessor => $childClass) { + $childTitle = humanize($childAccessor); + $body .= "- [{$childTitle}]({$urlPath}/" . kebab($childAccessor) . ")\n"; } + $body .= "\n"; - file_put_contents("{$dir}/00.index.md", $body); + file_put_contents("{$nodeDir}/00.index.md", $body); $childIndex = 1; foreach ($children as $childAccessor => $childClass) { - [$childRc, $childApiMethods, $grandchildren] = analyzeClass($childClass); - - $childSlug = kebab($childAccessor); - $childPrefix = str_pad((string) $childIndex++, 2, '0', STR_PAD_LEFT); - $childTitle = humanize($childAccessor); - - $childClassDoc = docblockFor($docFactory, $childRc); - $realChildSummary = $childClassDoc?->getSummary() ?: ''; - $childSummary = $realChildSummary !== '' ? $realChildSummary : "{$childTitle} endpoint reference."; - - $childBody = frontmatter($childTitle, $childSummary); - if ($realChildSummary !== '') { - $childBody .= $realChildSummary . "\n\n"; - } + writeNode( + $docFactory, + $childAccessor, + "{$accessorChain}->{$childAccessor}()", + $childClass, + $nodeDir, + $childIndex++, + "{$urlPath}/" . kebab($childAccessor) + ); + } +} - foreach ($childApiMethods as $m) { - $childBody .= renderMethodSection($docFactory, $m, "{$accessorName}()->{$childAccessor}()"); +function rrmdir(string $dir): void +{ + if (!is_dir($dir)) { + return; + } + foreach (scandir($dir) as $entry) { + if ($entry === '.' || $entry === '..') { + continue; } + $path = "{$dir}/{$entry}"; + is_dir($path) ? rrmdir($path) : unlink($path); + } + rmdir($dir); +} - if (!empty($grandchildren)) { - fwrite(STDERR, "WARNING: {$childClass} has its own child accessors — grandchild nesting isn't handled, methods skipped: " . implode(', ', array_keys($grandchildren)) . "\n"); - } +// Wipe the generated tree first so renumbered/removed accessors don't +// leave stale files behind (this whole directory is mechanical output; +// hand-curated docs live under 2.api instead). +rrmdir($outDir); +@mkdir($outDir, 0777, true); +file_put_contents($outDir . '/.navigation.yml', "title: Client Reference\nicon: i-lucide-terminal\n"); - file_put_contents("{$dir}/{$childPrefix}.{$childSlug}.md", $childBody); - } +$topIndex = 0; +foreach ($topLevel as $accessorName => $class) { + writeNode( + $docFactory, + $accessorName, + "{$accessorName}()", + $class, + $outDir, + $topIndex++, + '/client/' . kebab($accessorName) + ); } echo "Generated client reference docs in {$outDir}\n"; diff --git a/docs/content/2.client/00.accounts/00.index.md b/docs/content/2.client/00.accounts/00.index.md index 38864b8..6ab127f 100644 --- a/docs/content/2.client/00.accounts/00.index.md +++ b/docs/content/2.client/00.accounts/00.index.md @@ -132,9 +132,81 @@ $response = $client->accounts()->delete('ACCOUNT_ID'); View this operation on the Cloudflare API Reference :: +## Profile + +Get account profile. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." +--- +:: + +```php [php] +$response = $client->accounts()->profile('ACCOUNT_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/Accounts_getAccountProfile"} +View this operation on the Cloudflare API Reference +:: + +## Update Profile + +Modify account profile. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "values" + type: "array" + required: false + description: "Account profile values." + default: "[]" +--- +:: + +```php [php] +$response = $client->accounts()->updateProfile('ACCOUNT_ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/Accounts_modifyAccountProfile"} +View this operation on the Cloudflare API Reference +:: + +## Organizations + +List account organizations. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." +--- +:: + +```php [php] +$response = $client->accounts()->organizations('ACCOUNT_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/Accounts_listAccountOrganizations"} +View this operation on the Cloudflare API Reference +:: + ## Related -- [Roles](/client/accounts/roles) - [Members](/client/accounts/members) -- [Audit Logs](/client/accounts/audit-logs) +- [Logs](/client/accounts/logs) +- [Subscriptions](/client/accounts/subscriptions) +- [Tokens](/client/accounts/tokens) diff --git a/docs/content/2.client/00.accounts/02.members.md b/docs/content/2.client/00.accounts/01.members.md similarity index 100% rename from docs/content/2.client/00.accounts/02.members.md rename to docs/content/2.client/00.accounts/01.members.md diff --git a/docs/content/2.client/00.accounts/01.roles.md b/docs/content/2.client/00.accounts/01.roles.md deleted file mode 100644 index d64ddf7..0000000 --- a/docs/content/2.client/00.accounts/01.roles.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Roles -description: "Roles endpoint reference." -navigation: - title: Roles ---- - -## List - -Get all available roles for an account. - -::params-table ---- -params: - - name: "accountId" - type: "string" - required: true - description: "Account identifier." - - name: "params" - type: "array" - required: false - description: "Array containing the necessary params." - default: "[]" ---- -:: - -```php [php] -$response = $client->accounts()->roles()->list('ACCOUNT_ID', []); -``` - -::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-roles-list-roles"} -View this operation on the Cloudflare API Reference -:: - -## Get - -Get information about a specific role for an account. - -::params-table ---- -params: - - name: "accountId" - type: "string" - required: true - description: "Account identifier." - - name: "roleId" - type: "string" - required: true - description: "Role identifier." ---- -:: - -```php [php] -$response = $client->accounts()->roles()->get('ACCOUNT_ID', 'ROLE_ID'); -``` - -::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-roles-role-details"} -View this operation on the Cloudflare API Reference -:: - diff --git a/docs/content/2.client/00.accounts/02.logs/00.index.md b/docs/content/2.client/00.accounts/02.logs/00.index.md new file mode 100644 index 0000000..ac2d630 --- /dev/null +++ b/docs/content/2.client/00.accounts/02.logs/00.index.md @@ -0,0 +1,11 @@ +--- +title: Logs +description: "Logs endpoint reference." +navigation: + title: Logs +--- + +## Related + +- [Audit](/client/accounts/logs/audit) + diff --git a/docs/content/2.client/00.accounts/02.logs/01.audit.md b/docs/content/2.client/00.accounts/02.logs/01.audit.md new file mode 100644 index 0000000..217e65c --- /dev/null +++ b/docs/content/2.client/00.accounts/02.logs/01.audit.md @@ -0,0 +1,87 @@ +--- +title: Audit +description: "Audit endpoint reference." +navigation: + title: Audit +--- + +## List + +Gets a list of audit logs for an account. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "params" + type: "array" + required: false + description: "Array containing the necessary params, requires since and before." + default: "[]" +--- +:: + +```php [php] +$response = $client->accounts()->logs()->audit()->list('ACCOUNT_ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/audit-logs-v2-get-account-audit-logs"} +View this operation on the Cloudflare API Reference +:: + +## History + +Returns the chronological change history for the resource identified by the given audit log entry. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "id" + type: "string" + required: true + description: "Audit log entry identifier used to locate the resource." + - name: "params" + type: "array" + required: false + description: "Array containing the necessary params, requires action_time, since and before." + default: "[]" +--- +:: + +```php [php] +$response = $client->accounts()->logs()->audit()->history('ACCOUNT_ID', 'ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/audit-logs-v2-get-account-audit-log-history"} +View this operation on the Cloudflare API Reference +:: + +## Product Categories + +Lists the available audit log product categories and the resource products each one expands to. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." +--- +:: + +```php [php] +$response = $client->accounts()->logs()->audit()->productCategories('ACCOUNT_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/audit-logs-v2-list-account-product-categories"} +View this operation on the Cloudflare API Reference +:: + diff --git a/docs/content/2.client/00.accounts/03.audit-logs.md b/docs/content/2.client/00.accounts/03.audit-logs.md deleted file mode 100644 index 37d77f9..0000000 --- a/docs/content/2.client/00.accounts/03.audit-logs.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Audit Logs -description: "Audit Logs endpoint reference." -navigation: - title: Audit Logs ---- - -## List - -Gets a list of audit logs for an account. Can be filtered by who made the change, on which zone, and the timeframe of the change. - -::params-table ---- -params: - - name: "accountId" - type: "string" - required: true - description: "Account identifier." - - name: "params" - type: "array" - required: false - description: "Array containing the necessary params." - default: "[]" ---- -:: - -```php [php] -$response = $client->accounts()->auditLogs()->list('ACCOUNT_ID', []); -``` - -::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/audit-logs-get-account-audit-logs"} -View this operation on the Cloudflare API Reference -:: - diff --git a/docs/content/2.client/00.accounts/03.subscriptions.md b/docs/content/2.client/00.accounts/03.subscriptions.md new file mode 100644 index 0000000..405e2b0 --- /dev/null +++ b/docs/content/2.client/00.accounts/03.subscriptions.md @@ -0,0 +1,113 @@ +--- +title: Subscriptions +description: "Subscriptions endpoint reference." +navigation: + title: Subscriptions +--- + +## List + +Lists all of an account's subscriptions. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." +--- +:: + +```php [php] +$response = $client->accounts()->subscriptions()->list('ACCOUNT_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-subscriptions-list-subscriptions"} +View this operation on the Cloudflare API Reference +:: + +## Create + +Creates an account subscription. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "values" + type: "array" + required: false + description: "Subscription values, e.g. frequency, rate_plan." + default: "[]" +--- +:: + +```php [php] +$response = $client->accounts()->subscriptions()->create('ACCOUNT_ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-subscriptions-create-subscription"} +View this operation on the Cloudflare API Reference +:: + +## Update + +Updates an account subscription. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "subscriptionId" + type: "string" + required: true + description: "Subscription identifier tag." + - name: "values" + type: "array" + required: false + description: "Subscription values, e.g. frequency, rate_plan." + default: "[]" +--- +:: + +```php [php] +$response = $client->accounts()->subscriptions()->update('ACCOUNT_ID', 'SUBSCRIPTION_ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-subscriptions-update-subscription"} +View this operation on the Cloudflare API Reference +:: + +## Delete + +Deletes an account's subscription. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "subscriptionId" + type: "string" + required: true + description: "Subscription identifier tag." +--- +:: + +```php [php] +$response = $client->accounts()->subscriptions()->delete('ACCOUNT_ID', 'SUBSCRIPTION_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-subscriptions-delete-subscription"} +View this operation on the Cloudflare API Reference +:: + diff --git a/docs/content/2.client/00.accounts/04.tokens/00.index.md b/docs/content/2.client/00.accounts/04.tokens/00.index.md new file mode 100644 index 0000000..01edfdb --- /dev/null +++ b/docs/content/2.client/00.accounts/04.tokens/00.index.md @@ -0,0 +1,169 @@ +--- +title: Tokens +description: "Tokens endpoint reference." +navigation: + title: Tokens +--- + +## List + +List all Account Owned API tokens created for this account. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "params" + type: "array" + required: false + description: "Array containing the necessary params." + default: "[]" +--- +:: + +```php [php] +$response = $client->accounts()->tokens()->list('ACCOUNT_ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-api-tokens-list-tokens"} +View this operation on the Cloudflare API Reference +:: + +## Create + +Create a new Account Owned API token. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "values" + type: "array" + required: true + description: "Token values, requires name and policies." +--- +:: + +```php [php] +$response = $client->accounts()->tokens()->create('ACCOUNT_ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-api-tokens-create-token"} +View this operation on the Cloudflare API Reference +:: + +## Get + +Get information about a specific Account Owned API token. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "tokenId" + type: "string" + required: true + description: "Token identifier." +--- +:: + +```php [php] +$response = $client->accounts()->tokens()->get('ACCOUNT_ID', 'TOKEN_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-api-tokens-token-details"} +View this operation on the Cloudflare API Reference +:: + +## Update + +Update an existing token. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "tokenId" + type: "string" + required: true + description: "Token identifier." + - name: "values" + type: "array" + required: true + description: "Token values, e.g. name, policies, condition, status." +--- +:: + +```php [php] +$response = $client->accounts()->tokens()->update('ACCOUNT_ID', 'TOKEN_ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-api-tokens-update-token"} +View this operation on the Cloudflare API Reference +:: + +## Delete + +Destroy an Account Owned API token. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "tokenId" + type: "string" + required: true + description: "Token identifier." +--- +:: + +```php [php] +$response = $client->accounts()->tokens()->delete('ACCOUNT_ID', 'TOKEN_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-api-tokens-delete-token"} +View this operation on the Cloudflare API Reference +:: + +## Verify + +Test whether a token works. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." +--- +:: + +```php [php] +$response = $client->accounts()->tokens()->verify('ACCOUNT_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-api-tokens-verify-token"} +View this operation on the Cloudflare API Reference +:: + +## Related + +- [Permission Groups](/client/accounts/tokens/permission-groups) +- [Value](/client/accounts/tokens/value) + diff --git a/docs/content/2.client/00.accounts/04.tokens/01.permission-groups.md b/docs/content/2.client/00.accounts/04.tokens/01.permission-groups.md new file mode 100644 index 0000000..0eaa3a9 --- /dev/null +++ b/docs/content/2.client/00.accounts/04.tokens/01.permission-groups.md @@ -0,0 +1,34 @@ +--- +title: Permission Groups +description: "Permission Groups endpoint reference." +navigation: + title: Permission Groups +--- + +## List + +Find all available permission groups for Account Owned API Tokens. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "params" + type: "array" + required: false + description: "Array containing the necessary params, e.g. name, scope." + default: "[]" +--- +:: + +```php [php] +$response = $client->accounts()->tokens()->permissionGroups()->list('ACCOUNT_ID', []); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-api-tokens-list-permission-groups"} +View this operation on the Cloudflare API Reference +:: + diff --git a/docs/content/2.client/00.accounts/04.tokens/02.value.md b/docs/content/2.client/00.accounts/04.tokens/02.value.md new file mode 100644 index 0000000..3ae9cb7 --- /dev/null +++ b/docs/content/2.client/00.accounts/04.tokens/02.value.md @@ -0,0 +1,33 @@ +--- +title: Value +description: "Value endpoint reference." +navigation: + title: Value +--- + +## Roll + +Roll the Account Owned API token secret. + +::params-table +--- +params: + - name: "accountId" + type: "string" + required: true + description: "Account identifier." + - name: "tokenId" + type: "string" + required: true + description: "Token identifier." +--- +:: + +```php [php] +$response = $client->accounts()->tokens()->value()->roll('ACCOUNT_ID', 'TOKEN_ID'); +``` + +::callout{icon="i-simple-icons-cloudflare" to="https://developers.cloudflare.com/api/operations/account-api-tokens-roll-token"} +View this operation on the Cloudflare API Reference +:: + diff --git a/src/Endpoints/Accounts.php b/src/Endpoints/Accounts.php index 769e4ee..077d243 100644 --- a/src/Endpoints/Accounts.php +++ b/src/Endpoints/Accounts.php @@ -3,9 +3,10 @@ namespace Cloudflare\Endpoints; use Cloudflare\Contracts\ResponseInterface; -use Cloudflare\Endpoints\Accounts\Roles; use Cloudflare\Endpoints\Accounts\Members; -use Cloudflare\Endpoints\Accounts\AuditLogs; +use Cloudflare\Endpoints\Accounts\Logs; +use Cloudflare\Endpoints\Accounts\Subscriptions; +use Cloudflare\Endpoints\Accounts\Tokens; /** * @link https://developers.cloudflare.com/api/operations/accounts-list-accounts @@ -107,13 +108,46 @@ public function delete(string $accountId): ResponseInterface } /** - * Account Roles + * Get account profile. * - * @return \Cloudflare\Endpoints\Accounts\Roles + * @link https://developers.cloudflare.com/api/operations/Accounts_getAccountProfile + * + * @param string $accountId Account identifier. + * + * @return \Cloudflare\Contracts\ResponseInterface Account Profile response. */ - public function roles(): Roles + public function profile(string $accountId): ResponseInterface { - return new Roles($this->getClient()); + return $this->getHttpClient()->get("/accounts/{$accountId}/profile"); + } + + /** + * Modify account profile. + * + * @link https://developers.cloudflare.com/api/operations/Accounts_modifyAccountProfile + * + * @param string $accountId Account identifier. + * @param array $values Account profile values. + * + * @return \Cloudflare\Contracts\ResponseInterface Update Account Profile response. + */ + public function updateProfile(string $accountId, array $values = []): ResponseInterface + { + return $this->getHttpClient()->put("/accounts/{$accountId}/profile", $values); + } + + /** + * List account organizations. + * + * @link https://developers.cloudflare.com/api/operations/Accounts_listAccountOrganizations + * + * @param string $accountId Account identifier. + * + * @return \Cloudflare\Contracts\ResponseInterface List Account Organizations response. + */ + public function organizations(string $accountId): ResponseInterface + { + return $this->getHttpClient()->get("/accounts/{$accountId}/organizations"); } /** @@ -127,12 +161,32 @@ public function members(): Members } /** - * Account audit logs + * Account Logs + * + * @return \Cloudflare\Endpoints\Accounts\Logs + */ + public function logs(): Logs + { + return new Logs($this->getClient()); + } + + /** + * Account Subscriptions + * + * @return \Cloudflare\Endpoints\Accounts\Subscriptions + */ + public function subscriptions(): Subscriptions + { + return new Subscriptions($this->getClient()); + } + + /** + * Account Owned API Tokens * - * @return \Cloudflare\Endpoints\Accounts\AuditLogs + * @return \Cloudflare\Endpoints\Accounts\Tokens */ - public function auditLogs(): AuditLogs + public function tokens(): Tokens { - return new AuditLogs($this->getClient()); + return new Tokens($this->getClient()); } } diff --git a/src/Endpoints/Accounts/Logs.php b/src/Endpoints/Accounts/Logs.php new file mode 100644 index 0000000..01a51f8 --- /dev/null +++ b/src/Endpoints/Accounts/Logs.php @@ -0,0 +1,19 @@ +getClient()); + } +} diff --git a/src/Endpoints/Accounts/Logs/Audit.php b/src/Endpoints/Accounts/Logs/Audit.php new file mode 100644 index 0000000..6f28724 --- /dev/null +++ b/src/Endpoints/Accounts/Logs/Audit.php @@ -0,0 +1,58 @@ +requiredParams(['since', 'before'], $params); + + return $this->getHttpClient()->get("/accounts/{$accountId}/logs/audit", $params); + } + + /** + * Returns the chronological change history for the resource identified by the given audit log entry. + * + * @link https://developers.cloudflare.com/api/operations/audit-logs-v2-get-account-audit-log-history + * + * @param string $accountId Account identifier. + * @param string $id Audit log entry identifier used to locate the resource. + * @param array $params Array containing the necessary params, requires action_time, since and before. + * + * @return ResponseInterface Audit Log History response. + */ + public function history(string $accountId, string $id, array $params = []): ResponseInterface + { + $this->requiredParams(['action_time', 'since', 'before'], $params); + + return $this->getHttpClient()->get("/accounts/{$accountId}/logs/audit/{$id}/history", $params); + } + + /** + * Lists the available audit log product categories and the resource products each one expands to. + * + * @link https://developers.cloudflare.com/api/operations/audit-logs-v2-list-account-product-categories + * + * @param string $accountId Account identifier. + * + * @return ResponseInterface List Product Categories response. + */ + public function productCategories(string $accountId): ResponseInterface + { + return $this->getHttpClient()->get("/accounts/{$accountId}/logs/audit/product_categories"); + } +} diff --git a/src/Endpoints/Accounts/Roles.php b/src/Endpoints/Accounts/Roles.php deleted file mode 100644 index 31722c2..0000000 --- a/src/Endpoints/Accounts/Roles.php +++ /dev/null @@ -1,39 +0,0 @@ -getHttpClient()->get("/accounts/{$accountId}/roles", $params); - } - - /** - * Get information about a specific role for an account. - * - * @link https://developers.cloudflare.com/api/operations/account-roles-role-details - * - * @param string $accountId Account identifier. - * @param string $roleId Role identifier. - * - * @return ResponseInterface Role Details response - */ - public function get(string $accountId, string $roleId): ResponseInterface - { - return $this->getHttpClient()->get("/accounts/{$accountId}/roles/{$roleId}"); - } -} diff --git a/src/Endpoints/Accounts/Subscriptions.php b/src/Endpoints/Accounts/Subscriptions.php new file mode 100644 index 0000000..b76aa11 --- /dev/null +++ b/src/Endpoints/Accounts/Subscriptions.php @@ -0,0 +1,69 @@ +getHttpClient()->get("/accounts/{$accountId}/subscriptions"); + } + + /** + * Creates an account subscription. + * + * @link https://developers.cloudflare.com/api/operations/account-subscriptions-create-subscription + * + * @param string $accountId Account identifier. + * @param array $values Subscription values, e.g. frequency, rate_plan. + * + * @return ResponseInterface Create Subscription response. + */ + public function create(string $accountId, array $values = []): ResponseInterface + { + return $this->getHttpClient()->post("/accounts/{$accountId}/subscriptions", $values); + } + + /** + * Updates an account subscription. + * + * @link https://developers.cloudflare.com/api/operations/account-subscriptions-update-subscription + * + * @param string $accountId Account identifier. + * @param string $subscriptionId Subscription identifier tag. + * @param array $values Subscription values, e.g. frequency, rate_plan. + * + * @return ResponseInterface Update Subscription response. + */ + public function update(string $accountId, string $subscriptionId, array $values = []): ResponseInterface + { + return $this->getHttpClient()->put("/accounts/{$accountId}/subscriptions/{$subscriptionId}", $values); + } + + /** + * Deletes an account's subscription. + * + * @link https://developers.cloudflare.com/api/operations/account-subscriptions-delete-subscription + * + * @param string $accountId Account identifier. + * @param string $subscriptionId Subscription identifier tag. + * + * @return ResponseInterface Delete Subscription response. + */ + public function delete(string $accountId, string $subscriptionId): ResponseInterface + { + return $this->getHttpClient()->delete("/accounts/{$accountId}/subscriptions/{$subscriptionId}"); + } +} diff --git a/src/Endpoints/Accounts/Tokens.php b/src/Endpoints/Accounts/Tokens.php new file mode 100644 index 0000000..d31d8ba --- /dev/null +++ b/src/Endpoints/Accounts/Tokens.php @@ -0,0 +1,123 @@ +getHttpClient()->get("/accounts/{$accountId}/tokens", $params); + } + + /** + * Create a new Account Owned API token. + * + * @link https://developers.cloudflare.com/api/operations/account-api-tokens-create-token + * + * @param string $accountId Account identifier. + * @param array $values Token values, requires name and policies. + * + * @return ResponseInterface Create Token response. + */ + public function create(string $accountId, array $values): ResponseInterface + { + $this->requiredParams(['name', 'policies'], $values); + + return $this->getHttpClient()->post("/accounts/{$accountId}/tokens", $values); + } + + /** + * Get information about a specific Account Owned API token. + * + * @link https://developers.cloudflare.com/api/operations/account-api-tokens-token-details + * + * @param string $accountId Account identifier. + * @param string $tokenId Token identifier. + * + * @return ResponseInterface Token Details response. + */ + public function get(string $accountId, string $tokenId): ResponseInterface + { + return $this->getHttpClient()->get("/accounts/{$accountId}/tokens/{$tokenId}"); + } + + /** + * Update an existing token. + * + * @link https://developers.cloudflare.com/api/operations/account-api-tokens-update-token + * + * @param string $accountId Account identifier. + * @param string $tokenId Token identifier. + * @param array $values Token values, e.g. name, policies, condition, status. + * + * @return ResponseInterface Update Token response. + */ + public function update(string $accountId, string $tokenId, array $values): ResponseInterface + { + return $this->getHttpClient()->put("/accounts/{$accountId}/tokens/{$tokenId}", $values); + } + + /** + * Destroy an Account Owned API token. + * + * @link https://developers.cloudflare.com/api/operations/account-api-tokens-delete-token + * + * @param string $accountId Account identifier. + * @param string $tokenId Token identifier. + * + * @return ResponseInterface Delete Token response. + */ + public function delete(string $accountId, string $tokenId): ResponseInterface + { + return $this->getHttpClient()->delete("/accounts/{$accountId}/tokens/{$tokenId}"); + } + + /** + * Test whether a token works. + * + * @link https://developers.cloudflare.com/api/operations/account-api-tokens-verify-token + * + * @param string $accountId Account identifier. + * + * @return ResponseInterface Verify Token response. + */ + public function verify(string $accountId): ResponseInterface + { + return $this->getHttpClient()->get("/accounts/{$accountId}/tokens/verify"); + } + + /** + * Account Owned API Token Permission Groups + * + * @return \Cloudflare\Endpoints\Accounts\Tokens\PermissionGroups + */ + public function permissionGroups(): PermissionGroups + { + return new PermissionGroups($this->getClient()); + } + + /** + * Account Owned API Token Value + * + * @return \Cloudflare\Endpoints\Accounts\Tokens\Value + */ + public function value(): Value + { + return new Value($this->getClient()); + } +} diff --git a/src/Endpoints/Accounts/AuditLogs.php b/src/Endpoints/Accounts/Tokens/PermissionGroups.php similarity index 50% rename from src/Endpoints/Accounts/AuditLogs.php rename to src/Endpoints/Accounts/Tokens/PermissionGroups.php index a7a605a..b10d3b4 100644 --- a/src/Endpoints/Accounts/AuditLogs.php +++ b/src/Endpoints/Accounts/Tokens/PermissionGroups.php @@ -1,24 +1,24 @@ getHttpClient()->get("/accounts/{$accountId}/audit_logs", $params); + return $this->getHttpClient()->get("/accounts/{$accountId}/tokens/permission_groups", $params); } } diff --git a/src/Endpoints/Accounts/Tokens/Value.php b/src/Endpoints/Accounts/Tokens/Value.php new file mode 100644 index 0000000..9336f4a --- /dev/null +++ b/src/Endpoints/Accounts/Tokens/Value.php @@ -0,0 +1,24 @@ +getHttpClient()->put("/accounts/{$accountId}/tokens/{$tokenId}/value", []); + } +} diff --git a/test/Tests/Endpoints/Accounts/Logs/AuditTest.php b/test/Tests/Endpoints/Accounts/Logs/AuditTest.php new file mode 100644 index 0000000..e24f696 --- /dev/null +++ b/test/Tests/Endpoints/Accounts/Logs/AuditTest.php @@ -0,0 +1,72 @@ +mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => [['id' => 'audit_log_id']]])), + ]); + + $response = $client->accounts()->logs()->audit()->list('account_id', [ + 'since' => '2024-10-30', + 'before' => '2024-10-31', + ]); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/logs/audit', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldThrowExceptionWhenListParamsAreMissing() + { + $client = $this->mockClient([]); + + $this->expectException(\Cloudflare\Exceptions\MissingArgumentException::class); + + $client->accounts()->logs()->audit()->list('account_id'); + } + + #[Test] + public function shouldGetHistory() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => [['id' => 'audit_log_id']]])), + ]); + + $response = $client->accounts()->logs()->audit()->history('account_id', 'audit_log_id', [ + 'action_time' => '2024-10-30T15:00:00Z', + 'since' => '2024-10-30', + 'before' => '2024-10-31', + ]); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/logs/audit/audit_log_id/history', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldListProductCategories() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => [['product' => 'access']]])), + ]); + + $response = $client->accounts()->logs()->audit()->productCategories('account_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/logs/audit/product_categories', $this->lastRequest()->getUri()->getPath()); + } +} diff --git a/test/Tests/Endpoints/Accounts/RolesTest.php b/test/Tests/Endpoints/Accounts/RolesTest.php deleted file mode 100644 index 8f2be20..0000000 --- a/test/Tests/Endpoints/Accounts/RolesTest.php +++ /dev/null @@ -1,41 +0,0 @@ -mockClient([ - new Response(200, [], json_encode(['success' => true, 'result' => [['id' => 'role_id']]])), - ]); - - $response = $client->accounts()->roles()->list('account_id'); - - $this->assertTrue($response->successful()); - $this->assertSame('GET', $this->lastRequest()->getMethod()); - $this->assertSame('/client/v4/accounts/account_id/roles', $this->lastRequest()->getUri()->getPath()); - } - - #[Test] - public function shouldGetDetails() - { - $client = $this->mockClient([ - new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'role_id']])), - ]); - - $response = $client->accounts()->roles()->get('account_id', 'role_id'); - - $this->assertTrue($response->successful()); - $this->assertSame('GET', $this->lastRequest()->getMethod()); - $this->assertSame('/client/v4/accounts/account_id/roles/role_id', $this->lastRequest()->getUri()->getPath()); - } -} diff --git a/test/Tests/Endpoints/Accounts/SubscriptionsTest.php b/test/Tests/Endpoints/Accounts/SubscriptionsTest.php new file mode 100644 index 0000000..ce95c22 --- /dev/null +++ b/test/Tests/Endpoints/Accounts/SubscriptionsTest.php @@ -0,0 +1,75 @@ +mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => [['id' => 'subscription_id']]])), + ]); + + $response = $client->accounts()->subscriptions()->list('account_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/subscriptions', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldCreate() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'subscription_id']])), + ]); + + $response = $client->accounts()->subscriptions()->create('account_id', [ + 'frequency' => 'monthly', + ]); + + $this->assertTrue($response->successful()); + $this->assertSame('POST', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/subscriptions', $this->lastRequest()->getUri()->getPath()); + $this->assertSame(['frequency' => 'monthly'], json_decode((string) $this->lastRequest()->getBody(), true)); + } + + #[Test] + public function shouldUpdate() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'subscription_id']])), + ]); + + $response = $client->accounts()->subscriptions()->update('account_id', 'subscription_id', [ + 'frequency' => 'yearly', + ]); + + $this->assertTrue($response->successful()); + $this->assertSame('PUT', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/subscriptions/subscription_id', $this->lastRequest()->getUri()->getPath()); + $this->assertSame(['frequency' => 'yearly'], json_decode((string) $this->lastRequest()->getBody(), true)); + } + + #[Test] + public function shouldDelete() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['subscription_id' => 'subscription_id']])), + ]); + + $response = $client->accounts()->subscriptions()->delete('account_id', 'subscription_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('DELETE', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/subscriptions/subscription_id', $this->lastRequest()->getUri()->getPath()); + } +} diff --git a/test/Tests/Endpoints/Accounts/AuditLogsTest.php b/test/Tests/Endpoints/Accounts/Tokens/PermissionGroupsTest.php similarity index 57% rename from test/Tests/Endpoints/Accounts/AuditLogsTest.php rename to test/Tests/Endpoints/Accounts/Tokens/PermissionGroupsTest.php index 54430fa..e30ffe4 100644 --- a/test/Tests/Endpoints/Accounts/AuditLogsTest.php +++ b/test/Tests/Endpoints/Accounts/Tokens/PermissionGroupsTest.php @@ -1,13 +1,13 @@ mockClient([ - new Response(200, [], json_encode(['success' => true, 'result' => [['id' => 'log_id']]])), + new Response(200, [], json_encode(['success' => true, 'result' => [['id' => 'permission_group_id']]])), ]); - $response = $client->accounts()->auditLogs()->list('account_id'); + $response = $client->accounts()->tokens()->permissionGroups()->list('account_id'); $this->assertTrue($response->successful()); $this->assertSame('GET', $this->lastRequest()->getMethod()); - $this->assertSame('/client/v4/accounts/account_id/audit_logs', $this->lastRequest()->getUri()->getPath()); + $this->assertSame('/client/v4/accounts/account_id/tokens/permission_groups', $this->lastRequest()->getUri()->getPath()); } } diff --git a/test/Tests/Endpoints/Accounts/Tokens/ValueTest.php b/test/Tests/Endpoints/Accounts/Tokens/ValueTest.php new file mode 100644 index 0000000..474f534 --- /dev/null +++ b/test/Tests/Endpoints/Accounts/Tokens/ValueTest.php @@ -0,0 +1,27 @@ +mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['value' => 'new_token_secret']])), + ]); + + $response = $client->accounts()->tokens()->value()->roll('account_id', 'token_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('PUT', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/tokens/token_id/value', $this->lastRequest()->getUri()->getPath()); + } +} diff --git a/test/Tests/Endpoints/Accounts/TokensTest.php b/test/Tests/Endpoints/Accounts/TokensTest.php new file mode 100644 index 0000000..d3c337d --- /dev/null +++ b/test/Tests/Endpoints/Accounts/TokensTest.php @@ -0,0 +1,112 @@ +mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => [['id' => 'token_id']]])), + ]); + + $response = $client->accounts()->tokens()->list('account_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/tokens', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldCreate() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'token_id']])), + ]); + + $response = $client->accounts()->tokens()->create('account_id', [ + 'name' => 'readonly token', + 'policies' => [['effect' => 'allow']], + ]); + + $this->assertTrue($response->successful()); + $this->assertSame('POST', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/tokens', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldThrowExceptionWhenCreateParamsAreMissing() + { + $client = $this->mockClient([]); + + $this->expectException(\Cloudflare\Exceptions\MissingArgumentException::class); + + $client->accounts()->tokens()->create('account_id', ['name' => 'readonly token']); + } + + #[Test] + public function shouldGetDetails() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'token_id']])), + ]); + + $response = $client->accounts()->tokens()->get('account_id', 'token_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/tokens/token_id', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldUpdate() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'token_id']])), + ]); + + $response = $client->accounts()->tokens()->update('account_id', 'token_id', [ + 'name' => 'renamed token', + ]); + + $this->assertTrue($response->successful()); + $this->assertSame('PUT', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/tokens/token_id', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldDelete() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'token_id']])), + ]); + + $response = $client->accounts()->tokens()->delete('account_id', 'token_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('DELETE', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/tokens/token_id', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldVerify() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'token_id', 'status' => 'active']])), + ]); + + $response = $client->accounts()->tokens()->verify('account_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/tokens/verify', $this->lastRequest()->getUri()->getPath()); + } +} diff --git a/test/Tests/Endpoints/AccountsTest.php b/test/Tests/Endpoints/AccountsTest.php index 205011d..3614b69 100644 --- a/test/Tests/Endpoints/AccountsTest.php +++ b/test/Tests/Endpoints/AccountsTest.php @@ -116,4 +116,47 @@ public function shouldDelete() $this->assertSame('DELETE', $this->lastRequest()->getMethod()); $this->assertSame('/client/v4/accounts/account_id', $this->lastRequest()->getUri()->getPath()); } + + #[Test] + public function shouldGetProfile() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'account_id']])), + ]); + + $response = $client->accounts()->profile('account_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/profile', $this->lastRequest()->getUri()->getPath()); + } + + #[Test] + public function shouldUpdateProfile() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => ['id' => 'account_id']])), + ]); + + $response = $client->accounts()->updateProfile('account_id', ['name' => 'renamed']); + + $this->assertTrue($response->successful()); + $this->assertSame('PUT', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/profile', $this->lastRequest()->getUri()->getPath()); + $this->assertSame(['name' => 'renamed'], json_decode((string) $this->lastRequest()->getBody(), true)); + } + + #[Test] + public function shouldListOrganizations() + { + $client = $this->mockClient([ + new Response(200, [], json_encode(['success' => true, 'result' => [['id' => 'organization_id']]])), + ]); + + $response = $client->accounts()->organizations('account_id'); + + $this->assertTrue($response->successful()); + $this->assertSame('GET', $this->lastRequest()->getMethod()); + $this->assertSame('/client/v4/accounts/account_id/organizations', $this->lastRequest()->getUri()->getPath()); + } }