From 667034c84d428d2367da40f1c7089543659edbec Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 13 Jul 2026 10:47:19 +0530 Subject: [PATCH 1/6] chore: update PHP SDK to 27.0.0 --- CHANGELOG.md | 21 + composer.json | 3 +- docs/account.md | 2 +- docs/backups.md | 6 +- docs/examples/backups/create-restoration.md | 3 +- .../functions/get-deployment-download.md | 3 +- .../examples/functions/list-specifications.md | 5 +- docs/examples/health/get-audits-db.md | 15 - docs/examples/health/get-cache.md | 15 - docs/examples/health/get-certificate.md | 16 - docs/examples/health/get-db.md | 15 - docs/examples/health/get-pub-sub.md | 15 - docs/examples/health/get-queue-databases.md | 17 - docs/examples/health/get-queue-deletes.md | 16 - docs/examples/health/get-queue-functions.md | 16 - docs/examples/health/get-queue-logs.md | 16 - docs/examples/health/get-queue-mails.md | 16 - docs/examples/health/get-queue-messaging.md | 16 - docs/examples/health/get-queue-migrations.md | 16 - .../health/get-queue-stats-resources.md | 16 - docs/examples/health/get-queue-usage.md | 16 - docs/examples/health/get-queue-webhooks.md | 16 - docs/examples/health/get-storage-local.md | 15 - docs/examples/health/get-storage.md | 15 - docs/examples/health/get-time.md | 15 - docs/examples/messaging/list-provider-logs.md | 18 - .../messaging/list-subscriber-logs.md | 18 - docs/examples/messaging/list-topic-logs.md | 18 - .../organization/create-membership.md | 21 + .../delete-membership.md} | 8 +- .../delete.md} | 6 +- .../get-membership.md} | 8 +- docs/examples/{health => organization}/get.md | 6 +- .../list-memberships.md} | 8 +- .../update-membership.md} | 10 +- .../update.md} | 8 +- .../update-o-auth-2-appwrite.md} | 12 +- docs/examples/project/update-o-auth-2-oidc.md | 3 + .../project/update-o-auth-2-server.md | 3 +- docs/examples/sites/list-specifications.md | 5 +- docs/examples/tablesdb/create.md | 2 +- docs/examples/usage/list-events.md | 26 - docs/examples/usage/list-gauges.md | 26 - docs/functions.md | 13 +- docs/health.md | 280 ----- docs/messaging.md | 60 - docs/organization.md | 106 +- docs/project.md | 24 +- docs/sites.md | 8 +- docs/tablesdb.md | 2 +- docs/usage.md | 60 - docs/users.md | 2 +- src/Appwrite/Client.php | 89 +- src/Appwrite/Enums/BillingPlanGroup.php | 61 + src/Appwrite/Enums/DatabaseStatus.php | 61 + src/Appwrite/Enums/HealthAntivirusStatus.php | 61 - src/Appwrite/Enums/HealthCheckStatus.php | 52 - src/Appwrite/Enums/HealthQueueName.php | 151 --- src/Appwrite/Enums/OAuth2OidcPrompt.php | 70 ++ src/Appwrite/Enums/OAuthProvider.php | 9 + src/Appwrite/Enums/OrganizationKeyScopes.php | 36 + src/Appwrite/Enums/ProjectKeyScopes.php | 60 +- .../Enums/ProjectOAuth2OidcPrompt.php | 70 ++ src/Appwrite/Enums/ProjectOAuthProviderId.php | 9 + src/Appwrite/Models/ActivityEvent.php | 20 +- src/Appwrite/Models/AdditionalResource.php | 82 ++ src/Appwrite/Models/BillingPlan.php | 506 +++++++++ src/Appwrite/Models/BillingPlanAddon.php | 54 + .../Models/BillingPlanAddonDetails.php | 96 ++ .../BillingPlanDedicatedDatabaseLimits.php | 116 ++ src/Appwrite/Models/BillingPlanLimits.php | 48 + .../Models/BillingPlanSupportedAddons.php | 61 + src/Appwrite/Models/Block.php | 7 + src/Appwrite/Models/Database.php | 9 +- src/Appwrite/Models/HealthAntivirus.php | 56 - src/Appwrite/Models/HealthCertificate.php | 82 -- src/Appwrite/Models/HealthQueue.php | 47 - src/Appwrite/Models/HealthStatus.php | 63 - src/Appwrite/Models/HealthStatusList.php | 59 - src/Appwrite/Models/HealthTime.php | 61 - src/Appwrite/Models/Locale.php | 50 +- src/Appwrite/Models/Log.php | 2 +- src/Appwrite/Models/OAuth2Appwrite.php | 68 ++ src/Appwrite/Models/OAuth2Oidc.php | 24 +- src/Appwrite/Models/Organization.php | 282 +++++ src/Appwrite/Models/Program.php | 103 ++ src/Appwrite/Models/Project.php | 11 + src/Appwrite/Models/UsageBillingPlan.php | 117 ++ src/Appwrite/Models/UsageEventList.php | 66 -- src/Appwrite/Models/UsageGaugeList.php | 66 -- src/Appwrite/Models/UsageGroup.php | 106 -- src/Appwrite/Query.php | 36 + src/Appwrite/Services/Backups.php | 17 +- src/Appwrite/Services/Databases.php | 42 + src/Appwrite/Services/Functions.php | 19 +- src/Appwrite/Services/Health.php | 1012 ----------------- src/Appwrite/Services/Messaging.php | 188 --- src/Appwrite/Services/Organization.php | 332 ++++++ src/Appwrite/Services/Project.php | 56 +- src/Appwrite/Services/Sites.php | 12 +- src/Appwrite/Services/TablesDB.php | 8 +- src/Appwrite/Services/Usage.php | 218 ---- tests/Appwrite/Services/ActivitiesTest.php | 8 +- tests/Appwrite/Services/BackupsTest.php | 6 +- tests/Appwrite/Services/HealthTest.php | 518 --------- tests/Appwrite/Services/MessagingTest.php | 184 --- tests/Appwrite/Services/OrganizationTest.php | 644 +++++++++++ tests/Appwrite/Services/ProjectTest.php | 65 +- tests/Appwrite/Services/UsageTest.php | 75 -- 109 files changed, 3540 insertions(+), 3977 deletions(-) delete mode 100644 docs/examples/health/get-audits-db.md delete mode 100644 docs/examples/health/get-cache.md delete mode 100644 docs/examples/health/get-certificate.md delete mode 100644 docs/examples/health/get-db.md delete mode 100644 docs/examples/health/get-pub-sub.md delete mode 100644 docs/examples/health/get-queue-databases.md delete mode 100644 docs/examples/health/get-queue-deletes.md delete mode 100644 docs/examples/health/get-queue-functions.md delete mode 100644 docs/examples/health/get-queue-logs.md delete mode 100644 docs/examples/health/get-queue-mails.md delete mode 100644 docs/examples/health/get-queue-messaging.md delete mode 100644 docs/examples/health/get-queue-migrations.md delete mode 100644 docs/examples/health/get-queue-stats-resources.md delete mode 100644 docs/examples/health/get-queue-usage.md delete mode 100644 docs/examples/health/get-queue-webhooks.md delete mode 100644 docs/examples/health/get-storage-local.md delete mode 100644 docs/examples/health/get-storage.md delete mode 100644 docs/examples/health/get-time.md delete mode 100644 docs/examples/messaging/list-provider-logs.md delete mode 100644 docs/examples/messaging/list-subscriber-logs.md delete mode 100644 docs/examples/messaging/list-topic-logs.md create mode 100644 docs/examples/organization/create-membership.md rename docs/examples/{health/get-queue-certificates.md => organization/delete-membership.md} (62%) rename docs/examples/{health/get-antivirus.md => organization/delete.md} (69%) rename docs/examples/{health/get-queue-builds.md => organization/get-membership.md} (62%) rename docs/examples/{health => organization}/get.md (70%) rename docs/examples/{messaging/list-message-logs.md => organization/list-memberships.md} (67%) rename docs/examples/{health/get-console-pausing.md => organization/update-membership.md} (60%) rename docs/examples/{health/get-queue-audits.md => organization/update.md} (66%) rename docs/examples/{health/get-failed-jobs.md => project/update-o-auth-2-appwrite.md} (53%) delete mode 100644 docs/examples/usage/list-events.md delete mode 100644 docs/examples/usage/list-gauges.md delete mode 100644 docs/health.md delete mode 100644 docs/usage.md create mode 100644 src/Appwrite/Enums/BillingPlanGroup.php create mode 100644 src/Appwrite/Enums/DatabaseStatus.php delete mode 100644 src/Appwrite/Enums/HealthAntivirusStatus.php delete mode 100644 src/Appwrite/Enums/HealthCheckStatus.php delete mode 100644 src/Appwrite/Enums/HealthQueueName.php create mode 100644 src/Appwrite/Enums/OAuth2OidcPrompt.php create mode 100644 src/Appwrite/Enums/ProjectOAuth2OidcPrompt.php create mode 100644 src/Appwrite/Models/AdditionalResource.php create mode 100644 src/Appwrite/Models/BillingPlan.php create mode 100644 src/Appwrite/Models/BillingPlanAddon.php create mode 100644 src/Appwrite/Models/BillingPlanAddonDetails.php create mode 100644 src/Appwrite/Models/BillingPlanDedicatedDatabaseLimits.php create mode 100644 src/Appwrite/Models/BillingPlanLimits.php create mode 100644 src/Appwrite/Models/BillingPlanSupportedAddons.php delete mode 100644 src/Appwrite/Models/HealthAntivirus.php delete mode 100644 src/Appwrite/Models/HealthCertificate.php delete mode 100644 src/Appwrite/Models/HealthQueue.php delete mode 100644 src/Appwrite/Models/HealthStatus.php delete mode 100644 src/Appwrite/Models/HealthStatusList.php delete mode 100644 src/Appwrite/Models/HealthTime.php create mode 100644 src/Appwrite/Models/OAuth2Appwrite.php create mode 100644 src/Appwrite/Models/Organization.php create mode 100644 src/Appwrite/Models/Program.php create mode 100644 src/Appwrite/Models/UsageBillingPlan.php delete mode 100644 src/Appwrite/Models/UsageEventList.php delete mode 100644 src/Appwrite/Models/UsageGaugeList.php delete mode 100644 src/Appwrite/Models/UsageGroup.php delete mode 100644 src/Appwrite/Services/Health.php delete mode 100644 src/Appwrite/Services/Usage.php delete mode 100644 tests/Appwrite/Services/HealthTest.php delete mode 100644 tests/Appwrite/Services/UsageTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index adbaa019..0a41a9e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Change Log +## 27.0.0 + +* Breaking: Removed `Health` service with its models and enums +* Breaking: Removed `Usage` service and usage models +* Breaking: Removed `Messaging` methods `listMessageLogs`, `listProviderLogs`, `listSubscriberLogs`, `listTopicLogs` +* Breaking: Renamed `TablesDB::create` parameter `dedicatedDatabaseId` to `specification` +* Breaking: Removed `countryCode` and `countryName` from `ActivityEvent` model +* Added: `Organization` service `get`, `update`, `delete`, and membership CRUD methods +* Added: `Client::setSigningKey` and `Client::setBearer` for JWT and bearer authentication +* Added: vector query helpers `Query::vectorDot`, `Query::vectorCosine`, `Query::vectorEuclidean` +* Added: `appwrite` OAuth2 provider and `Project::updateOAuth2Appwrite` method +* Added: `prompt` and `maxAge` parameters to `updateOAuth2Oidc`, `defaultScopes` to `updateOAuth2Server` +* Added: `newSpecification` parameter to `Backups::createRestoration` +* Added: `type` parameter to `Functions` and `Sites` `listSpecifications` +* Added: `token` parameter to `Functions::getDeploymentDownload` +* Added: `mode` to `Block`, `status` to `Database`, geolocation/ISP fields to `Locale` models +* Added: `onboarding` and `oAuth2ServerDefaultScopes` to `Project` model +* Added: organization membership, organization, and `project.oauth2`/`stages` key scopes +* Added: billing plan models, `BillingPlanGroup`, `DatabaseStatus`, OIDC prompt enums +* Updated: deprecated `Databases` transaction and text attribute methods in favor of `TablesDB` + ## 26.1.0 * Updated: Reworked `usage.listEvents` into an aggregation query with `metric`, `interval`, `dimensions`, and `orderBy` diff --git a/composer.json b/composer.json index a5eb1aa5..54fa8a06 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "require": { "php": ">=8.2.0", "ext-curl": "*", - "ext-json": "*" + "ext-json": "*", + "adhocore/jwt": "^1.1" }, "require-dev": { "phpunit/phpunit": "^12", diff --git a/docs/account.md b/docs/account.md index 9368ea08..31ac8d2e 100644 --- a/docs/account.md +++ b/docs/account.md @@ -565,7 +565,7 @@ A user is limited to 10 active sessions at a time by default. [Learn more about | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| provider | string | **Required** OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. | | +| provider | string | **Required** OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. | | | success | string | URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API. | | | failure | string | URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API. | | | scopes | array | A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long. | [] | diff --git a/docs/backups.md b/docs/backups.md index 36a4ee91..3ad1f4eb 100644 --- a/docs/backups.md +++ b/docs/backups.md @@ -133,7 +133,10 @@ DELETE https://cloud.appwrite.io/v1/backups/policies/{policyId} POST https://cloud.appwrite.io/v1/backups/restoration ``` -** Create and trigger a new restoration for a backup on a project. ** +** Create and trigger a new restoration for a backup on a project. + +When restoring a DocumentsDB or VectorsDB database to a new resource, pass `newSpecification` to provision the restored database on a different specification than the archived one (for example, restoring onto a larger or smaller dedicated database). Use `serverless` to restore onto the shared pool, or a dedicated specification slug to restore onto a dedicated database of that size. The specification must be permitted by the organization's plan. `newSpecification` is not supported for legacy/TablesDB databases or for bucket restores. + ** ### Parameters @@ -143,6 +146,7 @@ POST https://cloud.appwrite.io/v1/backups/restoration | services | array | Array of services to restore | | | newResourceId | string | Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | newResourceName | string | Database name. Max length: 128 chars. | | +| newSpecification | string | Specification to provision the restored database on, when restoring a DocumentsDB or VectorsDB database to a new resource. Defaults to the archived database's specification. Use `serverless` for the shared pool or a dedicated specification slug. | | ```http request diff --git a/docs/examples/backups/create-restoration.md b/docs/examples/backups/create-restoration.md index 61d9e0b2..e572dd47 100644 --- a/docs/examples/backups/create-restoration.md +++ b/docs/examples/backups/create-restoration.md @@ -16,5 +16,6 @@ $result = $backups->createRestoration( archiveId: '', services: [BackupServices::DATABASES()], newResourceId: '', // optional - newResourceName: '' // optional + newResourceName: '', // optional + newSpecification: 'serverless' // optional );``` diff --git a/docs/examples/functions/get-deployment-download.md b/docs/examples/functions/get-deployment-download.md index 73842f54..e267d325 100644 --- a/docs/examples/functions/get-deployment-download.md +++ b/docs/examples/functions/get-deployment-download.md @@ -15,5 +15,6 @@ $functions = new Functions($client); $result = $functions->getDeploymentDownload( functionId: '', deploymentId: '', - type: DeploymentDownloadType::SOURCE() // optional + type: DeploymentDownloadType::SOURCE(), // optional + token: '' // optional );``` diff --git a/docs/examples/functions/list-specifications.md b/docs/examples/functions/list-specifications.md index f5afe80b..7211ce69 100644 --- a/docs/examples/functions/list-specifications.md +++ b/docs/examples/functions/list-specifications.md @@ -11,5 +11,6 @@ $client = (new Client()) $functions = new Functions($client); -$result = $functions->listSpecifications(); -``` +$result = $functions->listSpecifications( + type: 'runtimes' // optional +);``` diff --git a/docs/examples/health/get-audits-db.md b/docs/examples/health/get-audits-db.md deleted file mode 100644 index 045c32fd..00000000 --- a/docs/examples/health/get-audits-db.md +++ /dev/null @@ -1,15 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getAuditsDB(); -``` diff --git a/docs/examples/health/get-cache.md b/docs/examples/health/get-cache.md deleted file mode 100644 index 8443c64f..00000000 --- a/docs/examples/health/get-cache.md +++ /dev/null @@ -1,15 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getCache(); -``` diff --git a/docs/examples/health/get-certificate.md b/docs/examples/health/get-certificate.md deleted file mode 100644 index d1d1fd1e..00000000 --- a/docs/examples/health/get-certificate.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getCertificate( - domain: '' // optional -);``` diff --git a/docs/examples/health/get-db.md b/docs/examples/health/get-db.md deleted file mode 100644 index 1682bcf3..00000000 --- a/docs/examples/health/get-db.md +++ /dev/null @@ -1,15 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getDB(); -``` diff --git a/docs/examples/health/get-pub-sub.md b/docs/examples/health/get-pub-sub.md deleted file mode 100644 index 97dc4b6f..00000000 --- a/docs/examples/health/get-pub-sub.md +++ /dev/null @@ -1,15 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getPubSub(); -``` diff --git a/docs/examples/health/get-queue-databases.md b/docs/examples/health/get-queue-databases.md deleted file mode 100644 index 96bfb6fd..00000000 --- a/docs/examples/health/get-queue-databases.md +++ /dev/null @@ -1,17 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueDatabases( - name: '', // optional - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-deletes.md b/docs/examples/health/get-queue-deletes.md deleted file mode 100644 index 2b147f42..00000000 --- a/docs/examples/health/get-queue-deletes.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueDeletes( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-functions.md b/docs/examples/health/get-queue-functions.md deleted file mode 100644 index d5b58442..00000000 --- a/docs/examples/health/get-queue-functions.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueFunctions( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-logs.md b/docs/examples/health/get-queue-logs.md deleted file mode 100644 index cb0125cb..00000000 --- a/docs/examples/health/get-queue-logs.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueLogs( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-mails.md b/docs/examples/health/get-queue-mails.md deleted file mode 100644 index 56babd6c..00000000 --- a/docs/examples/health/get-queue-mails.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueMails( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-messaging.md b/docs/examples/health/get-queue-messaging.md deleted file mode 100644 index 4539c5d9..00000000 --- a/docs/examples/health/get-queue-messaging.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueMessaging( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-migrations.md b/docs/examples/health/get-queue-migrations.md deleted file mode 100644 index 36b8d4b4..00000000 --- a/docs/examples/health/get-queue-migrations.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueMigrations( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-stats-resources.md b/docs/examples/health/get-queue-stats-resources.md deleted file mode 100644 index da4cee7a..00000000 --- a/docs/examples/health/get-queue-stats-resources.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueStatsResources( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-usage.md b/docs/examples/health/get-queue-usage.md deleted file mode 100644 index dd35802b..00000000 --- a/docs/examples/health/get-queue-usage.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueUsage( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-queue-webhooks.md b/docs/examples/health/get-queue-webhooks.md deleted file mode 100644 index d2877ce6..00000000 --- a/docs/examples/health/get-queue-webhooks.md +++ /dev/null @@ -1,16 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getQueueWebhooks( - threshold: null // optional -);``` diff --git a/docs/examples/health/get-storage-local.md b/docs/examples/health/get-storage-local.md deleted file mode 100644 index d7524bad..00000000 --- a/docs/examples/health/get-storage-local.md +++ /dev/null @@ -1,15 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getStorageLocal(); -``` diff --git a/docs/examples/health/get-storage.md b/docs/examples/health/get-storage.md deleted file mode 100644 index 2a109dec..00000000 --- a/docs/examples/health/get-storage.md +++ /dev/null @@ -1,15 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getStorage(); -``` diff --git a/docs/examples/health/get-time.md b/docs/examples/health/get-time.md deleted file mode 100644 index 559b1797..00000000 --- a/docs/examples/health/get-time.md +++ /dev/null @@ -1,15 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$health = new Health($client); - -$result = $health->getTime(); -``` diff --git a/docs/examples/messaging/list-provider-logs.md b/docs/examples/messaging/list-provider-logs.md deleted file mode 100644 index afc3df91..00000000 --- a/docs/examples/messaging/list-provider-logs.md +++ /dev/null @@ -1,18 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$messaging = new Messaging($client); - -$result = $messaging->listProviderLogs( - providerId: '', - queries: [], // optional - total: false // optional -);``` diff --git a/docs/examples/messaging/list-subscriber-logs.md b/docs/examples/messaging/list-subscriber-logs.md deleted file mode 100644 index 7a0e5ad7..00000000 --- a/docs/examples/messaging/list-subscriber-logs.md +++ /dev/null @@ -1,18 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$messaging = new Messaging($client); - -$result = $messaging->listSubscriberLogs( - subscriberId: '', - queries: [], // optional - total: false // optional -);``` diff --git a/docs/examples/messaging/list-topic-logs.md b/docs/examples/messaging/list-topic-logs.md deleted file mode 100644 index d32d27ae..00000000 --- a/docs/examples/messaging/list-topic-logs.md +++ /dev/null @@ -1,18 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$messaging = new Messaging($client); - -$result = $messaging->listTopicLogs( - topicId: '', - queries: [], // optional - total: false // optional -);``` diff --git a/docs/examples/organization/create-membership.md b/docs/examples/organization/create-membership.md new file mode 100644 index 00000000..372c09cc --- /dev/null +++ b/docs/examples/organization/create-membership.md @@ -0,0 +1,21 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$organization = new Organization($client); + +$result = $organization->createMembership( + roles: [], + email: 'email@example.com', // optional + userId: '', // optional + phone: '+12065550100', // optional + url: 'https://example.com', // optional + name: '' // optional +);``` diff --git a/docs/examples/health/get-queue-certificates.md b/docs/examples/organization/delete-membership.md similarity index 62% rename from docs/examples/health/get-queue-certificates.md rename to docs/examples/organization/delete-membership.md index d70b6574..9da3b64f 100644 --- a/docs/examples/health/get-queue-certificates.md +++ b/docs/examples/organization/delete-membership.md @@ -2,15 +2,15 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setKey(''); // Your secret API key -$health = new Health($client); +$organization = new Organization($client); -$result = $health->getQueueCertificates( - threshold: null // optional +$result = $organization->deleteMembership( + membershipId: '' );``` diff --git a/docs/examples/health/get-antivirus.md b/docs/examples/organization/delete.md similarity index 69% rename from docs/examples/health/get-antivirus.md rename to docs/examples/organization/delete.md index 7f57d8aa..1160857a 100644 --- a/docs/examples/health/get-antivirus.md +++ b/docs/examples/organization/delete.md @@ -2,14 +2,14 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setKey(''); // Your secret API key -$health = new Health($client); +$organization = new Organization($client); -$result = $health->getAntivirus(); +$result = $organization->delete(); ``` diff --git a/docs/examples/health/get-queue-builds.md b/docs/examples/organization/get-membership.md similarity index 62% rename from docs/examples/health/get-queue-builds.md rename to docs/examples/organization/get-membership.md index 607acb20..52e2d17d 100644 --- a/docs/examples/health/get-queue-builds.md +++ b/docs/examples/organization/get-membership.md @@ -2,15 +2,15 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setKey(''); // Your secret API key -$health = new Health($client); +$organization = new Organization($client); -$result = $health->getQueueBuilds( - threshold: null // optional +$result = $organization->getMembership( + membershipId: '' );``` diff --git a/docs/examples/health/get.md b/docs/examples/organization/get.md similarity index 70% rename from docs/examples/health/get.md rename to docs/examples/organization/get.md index 4b46ac2c..6fb38198 100644 --- a/docs/examples/health/get.md +++ b/docs/examples/organization/get.md @@ -2,14 +2,14 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setKey(''); // Your secret API key -$health = new Health($client); +$organization = new Organization($client); -$result = $health->get(); +$result = $organization->get(); ``` diff --git a/docs/examples/messaging/list-message-logs.md b/docs/examples/organization/list-memberships.md similarity index 67% rename from docs/examples/messaging/list-message-logs.md rename to docs/examples/organization/list-memberships.md index 8bc5631c..17858996 100644 --- a/docs/examples/messaging/list-message-logs.md +++ b/docs/examples/organization/list-memberships.md @@ -2,17 +2,17 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setKey(''); // Your secret API key -$messaging = new Messaging($client); +$organization = new Organization($client); -$result = $messaging->listMessageLogs( - messageId: '', +$result = $organization->listMemberships( queries: [], // optional + search: '', // optional total: false // optional );``` diff --git a/docs/examples/health/get-console-pausing.md b/docs/examples/organization/update-membership.md similarity index 60% rename from docs/examples/health/get-console-pausing.md rename to docs/examples/organization/update-membership.md index 06a434d8..7097729e 100644 --- a/docs/examples/health/get-console-pausing.md +++ b/docs/examples/organization/update-membership.md @@ -2,16 +2,16 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setKey(''); // Your secret API key -$health = new Health($client); +$organization = new Organization($client); -$result = $health->getConsolePausing( - threshold: null, // optional - inactivityDays: null // optional +$result = $organization->updateMembership( + membershipId: '', + roles: [] );``` diff --git a/docs/examples/health/get-queue-audits.md b/docs/examples/organization/update.md similarity index 66% rename from docs/examples/health/get-queue-audits.md rename to docs/examples/organization/update.md index 2bfc32e8..45e7f0ff 100644 --- a/docs/examples/health/get-queue-audits.md +++ b/docs/examples/organization/update.md @@ -2,15 +2,15 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setKey(''); // Your secret API key -$health = new Health($client); +$organization = new Organization($client); -$result = $health->getQueueAudits( - threshold: null // optional +$result = $organization->update( + name: '' );``` diff --git a/docs/examples/health/get-failed-jobs.md b/docs/examples/project/update-o-auth-2-appwrite.md similarity index 53% rename from docs/examples/health/get-failed-jobs.md rename to docs/examples/project/update-o-auth-2-appwrite.md index de204109..be24abdb 100644 --- a/docs/examples/health/get-failed-jobs.md +++ b/docs/examples/project/update-o-auth-2-appwrite.md @@ -2,17 +2,17 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setKey(''); // Your secret API key -$health = new Health($client); +$project = new Project($client); -$result = $health->getFailedJobs( - name: HealthQueueName::V1DATABASE(), - threshold: null // optional +$result = $project->updateOAuth2Appwrite( + clientId: '', // optional + clientSecret: '', // optional + enabled: false // optional );``` diff --git a/docs/examples/project/update-o-auth-2-oidc.md b/docs/examples/project/update-o-auth-2-oidc.md index 1b9d9b86..2c06fe89 100644 --- a/docs/examples/project/update-o-auth-2-oidc.md +++ b/docs/examples/project/update-o-auth-2-oidc.md @@ -3,6 +3,7 @@ use Appwrite\Client; use Appwrite\Services\Project; +use Appwrite\Enums\ProjectOAuth2OidcPrompt; $client = (new Client()) ->setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -18,5 +19,7 @@ $result = $project->updateOAuth2Oidc( authorizationURL: 'https://example.com', // optional tokenURL: 'https://example.com', // optional userInfoURL: 'https://example.com', // optional + prompt: [ProjectOAuth2OidcPrompt::NONE()], // optional + maxAge: 0, // optional enabled: false // optional );``` diff --git a/docs/examples/project/update-o-auth-2-server.md b/docs/examples/project/update-o-auth-2-server.md index d8974303..9c3eb9a8 100644 --- a/docs/examples/project/update-o-auth-2-server.md +++ b/docs/examples/project/update-o-auth-2-server.md @@ -24,5 +24,6 @@ $result = $project->updateOAuth2Server( verificationUrl: 'https://example.com', // optional userCodeLength: 6, // optional userCodeFormat: 'numeric', // optional - deviceCodeDuration: 60 // optional + deviceCodeDuration: 60, // optional + defaultScopes: [] // optional );``` diff --git a/docs/examples/sites/list-specifications.md b/docs/examples/sites/list-specifications.md index 1a732b6a..33bc0c59 100644 --- a/docs/examples/sites/list-specifications.md +++ b/docs/examples/sites/list-specifications.md @@ -11,5 +11,6 @@ $client = (new Client()) $sites = new Sites($client); -$result = $sites->listSpecifications(); -``` +$result = $sites->listSpecifications( + type: 'runtimes' // optional +);``` diff --git a/docs/examples/tablesdb/create.md b/docs/examples/tablesdb/create.md index 34d30569..9cbbf307 100644 --- a/docs/examples/tablesdb/create.md +++ b/docs/examples/tablesdb/create.md @@ -15,5 +15,5 @@ $result = $tablesDB->create( databaseId: '', name: '', enabled: false, // optional - dedicatedDatabaseId: '' // optional + specification: 'serverless' // optional );``` diff --git a/docs/examples/usage/list-events.md b/docs/examples/usage/list-events.md deleted file mode 100644 index e7cfe438..00000000 --- a/docs/examples/usage/list-events.md +++ /dev/null @@ -1,26 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$usage = new Usage($client); - -$result = $usage->listEvents( - metric: '', - resource: '', // optional - resourceId: '', // optional - interval: '1m', // optional - dimensions: [], // optional - startAt: '2020-10-15T06:38:00.000+00:00', // optional - endAt: '2020-10-15T06:38:00.000+00:00', // optional - orderBy: 'time', // optional - orderDir: 'asc', // optional - limit: 1, // optional - offset: 0 // optional -);``` diff --git a/docs/examples/usage/list-gauges.md b/docs/examples/usage/list-gauges.md deleted file mode 100644 index 899c052b..00000000 --- a/docs/examples/usage/list-gauges.md +++ /dev/null @@ -1,26 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$usage = new Usage($client); - -$result = $usage->listGauges( - metric: '', - resourceId: '', // optional - teamId: '', // optional - interval: '1m', // optional - dimensions: [], // optional - startAt: '2020-10-15T06:38:00.000+00:00', // optional - endAt: '2020-10-15T06:38:00.000+00:00', // optional - orderBy: 'time', // optional - orderDir: 'asc', // optional - limit: 1, // optional - offset: 0 // optional -);``` diff --git a/docs/functions.md b/docs/functions.md index 04fed225..86be1ee9 100644 --- a/docs/functions.md +++ b/docs/functions.md @@ -37,7 +37,7 @@ POST https://cloud.appwrite.io/v1/functions | logging | boolean | When disabled, executions will exclude logs and errors, and will be slightly faster. | 1 | | entrypoint | string | Entrypoint File. This path is relative to the "providerRootDirectory". | | | commands | string | Build Commands. | | -| scopes | array | List of scopes allowed for API key auto-generated for every execution. Maximum of 100 scopes are allowed. | [] | +| scopes | array | List of scopes allowed for API key auto-generated for every execution. Maximum of 200 scopes are allowed. | [] | | installationId | string | Appwrite Installation ID for VCS (Version Control System) deployment. | | | providerRepositoryId | string | Repository ID of the repo linked to the function. | | | providerBranch | string | Production branch for the repo linked to the function. | | @@ -63,6 +63,12 @@ GET https://cloud.appwrite.io/v1/functions/specifications ** List allowed function specifications for this instance. ** +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| type | string | Specification type to list. Can be one of: runtimes, builds. | runtimes | + ```http request GET https://cloud.appwrite.io/v1/functions/{functionId} @@ -98,7 +104,7 @@ PUT https://cloud.appwrite.io/v1/functions/{functionId} | logging | boolean | When disabled, executions will exclude logs and errors, and will be slightly faster. | 1 | | entrypoint | string | Entrypoint File. This path is relative to the "providerRootDirectory". | | | commands | string | Build Commands. | | -| scopes | array | List of scopes allowed for API Key auto-generated for every execution. Maximum of 100 scopes are allowed. | [] | +| scopes | array | List of scopes allowed for API Key auto-generated for every execution. Maximum of 200 scopes are allowed. | [] | | installationId | string | Appwrite Installation ID for VCS (Version Controle System) deployment. | | | providerRepositoryId | string | Repository ID of the repo linked to the function | | | providerBranch | string | Production branch for the repo linked to the function | | @@ -106,7 +112,7 @@ PUT https://cloud.appwrite.io/v1/functions/{functionId} | providerRootDirectory | string | Path to function code in the linked repo. | | | providerBranches | array | List of branch name patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all branches. | | | providerPaths | array | List of file path patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all file changes. | | -| buildSpecification | string | Build specification for the function deployments. | [] | +| buildSpecification | string | Build specification for the function deployments. | | | runtimeSpecification | string | Runtime specification for the function executions. | [] | | deploymentRetention | integer | Days to keep non-active deployments before deletion. Value 0 means all deployments will be kept. | 0 | @@ -270,6 +276,7 @@ GET https://cloud.appwrite.io/v1/functions/{functionId}/deployments/{deploymentI | functionId | string | **Required** Function ID. | | | deploymentId | string | **Required** Deployment ID. | | | type | string | Deployment file to download. Can be: "source", "output". | source | +| token | string | Presigned source-download token for accessing this deployment without a session (jobs-service). | | ```http request diff --git a/docs/health.md b/docs/health.md deleted file mode 100644 index 2dc98889..00000000 --- a/docs/health.md +++ /dev/null @@ -1,280 +0,0 @@ -# Health Service - - -```http request -GET https://cloud.appwrite.io/v1/health -``` - -** Check the Appwrite HTTP server is up and responsive. ** - - -```http request -GET https://cloud.appwrite.io/v1/health/anti-virus -``` - -** Check the Appwrite Antivirus server is up and connection is successful. ** - - -```http request -GET https://cloud.appwrite.io/v1/health/audits-db -``` - -** Check the database that backs the audit and activity store. When the connection is reachable the endpoint returns a passing status with its response time. - ** - - -```http request -GET https://cloud.appwrite.io/v1/health/cache -``` - -** Check the Appwrite in-memory cache servers are up and connection is successful. ** - - -```http request -GET https://cloud.appwrite.io/v1/health/certificate -``` - -** Get the SSL certificate for a domain ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| domain | string | string | | - - -```http request -GET https://cloud.appwrite.io/v1/health/console-pausing -``` - -** Get console pausing health status. Monitors projects approaching the pause threshold to detect potential issues with console access tracking. - ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Percentage threshold of projects approaching pause. When hit (equal or higher), endpoint returns server error. Default value is 10. | 10 | -| inactivityDays | integer | Number of days of inactivity before a project is paused. Should match the plan's projectInactivityDays setting. Default value is 7. | 7 | - - -```http request -GET https://cloud.appwrite.io/v1/health/db -``` - -** Check the Appwrite database servers are up and connection is successful. ** - - -```http request -GET https://cloud.appwrite.io/v1/health/pubsub -``` - -** Check the Appwrite pub-sub servers are up and connection is successful. ** - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/audits -``` - -** Get the number of audit logs that are waiting to be processed in the Appwrite internal queue server. - ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/builds -``` - -** Get the number of builds that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/certificates -``` - -** Get the number of certificates that are waiting to be issued against [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/databases -``` - -** Get the number of database changes that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| name | string | Queue name for which to check the queue size | database_db_main | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/deletes -``` - -** Get the number of background destructive changes that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/failed/{name} -``` - -** Returns the amount of failed jobs in a given queue. - ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| name | string | **Required** The name of the queue | | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/functions -``` - -** Get the number of function executions that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/logs -``` - -** Get the number of logs that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/mails -``` - -** Get the number of mails that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/messaging -``` - -** Get the number of messages that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/migrations -``` - -** Get the number of migrations that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/stats-resources -``` - -** Get the number of metrics that are waiting to be processed in the Appwrite stats resources queue. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/stats-usage -``` - -** Get the number of metrics that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/queue/webhooks -``` - -** Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| threshold | integer | Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000. | 5000 | - - -```http request -GET https://cloud.appwrite.io/v1/health/storage -``` - -** Check the Appwrite storage device is up and connection is successful. ** - - -```http request -GET https://cloud.appwrite.io/v1/health/storage/local -``` - -** Check the Appwrite local storage device is up and connection is successful. ** - - -```http request -GET https://cloud.appwrite.io/v1/health/time -``` - -** Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https://en.wikipedia.org/wiki/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP. ** - diff --git a/docs/messaging.md b/docs/messaging.md index 15f8056c..e2585239 100644 --- a/docs/messaging.md +++ b/docs/messaging.md @@ -233,21 +233,6 @@ DELETE https://cloud.appwrite.io/v1/messaging/messages/{messageId} | messageId | string | **Required** Message ID. | | -```http request -GET https://cloud.appwrite.io/v1/messaging/messages/{messageId}/logs -``` - -** Get the message activity logs listed by its unique ID. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| messageId | string | **Required** Message ID. | | -| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset | [] | -| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | - - ```http request GET https://cloud.appwrite.io/v1/messaging/messages/{messageId}/targets ``` @@ -901,36 +886,6 @@ DELETE https://cloud.appwrite.io/v1/messaging/providers/{providerId} | providerId | string | **Required** Provider ID. | | -```http request -GET https://cloud.appwrite.io/v1/messaging/providers/{providerId}/logs -``` - -** Get the provider activity logs listed by its unique ID. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| providerId | string | **Required** Provider ID. | | -| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset | [] | -| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | - - -```http request -GET https://cloud.appwrite.io/v1/messaging/subscribers/{subscriberId}/logs -``` - -** Get the subscriber activity logs listed by its unique ID. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| subscriberId | string | **Required** Subscriber ID. | | -| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset | [] | -| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | - - ```http request GET https://cloud.appwrite.io/v1/messaging/topics ``` @@ -1004,21 +959,6 @@ DELETE https://cloud.appwrite.io/v1/messaging/topics/{topicId} | topicId | string | **Required** Topic ID. | | -```http request -GET https://cloud.appwrite.io/v1/messaging/topics/{topicId}/logs -``` - -** Get the topic activity logs listed by its unique ID. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| topicId | string | **Required** Topic ID. | | -| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset | [] | -| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | - - ```http request GET https://cloud.appwrite.io/v1/messaging/topics/{topicId}/subscribers ``` diff --git a/docs/organization.md b/docs/organization.md index 6bd35ae8..65a24932 100644 --- a/docs/organization.md +++ b/docs/organization.md @@ -1,6 +1,33 @@ # Organization Service +```http request +GET https://cloud.appwrite.io/v1/organization +``` + +** Get the current organization. ** + + +```http request +PUT https://cloud.appwrite.io/v1/organization +``` + +** Update the current organization's name. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| name | string | New organization name. Max length: 128 chars. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/organization +``` + +** Delete the current organization. All projects that belong to the organization are deleted as well. ** + + ```http request GET https://cloud.appwrite.io/v1/organization/keys ``` @@ -27,7 +54,7 @@ POST https://cloud.appwrite.io/v1/organization/keys | --- | --- | --- | --- | | keyId | string | Key ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | name | string | Key name. Max length: 128 chars. | | -| scopes | array | Key scopes list. Maximum of 100 scopes are allowed. | | +| scopes | array | Key scopes list. Maximum of 200 scopes are allowed. | | | expire | string | Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. | | @@ -56,7 +83,7 @@ PUT https://cloud.appwrite.io/v1/organization/keys/{keyId} | --- | --- | --- | --- | | keyId | string | **Required** Key unique ID. | | | name | string | Key name. Max length: 128 chars. | | -| scopes | array | Key scopes list. Maximum of 100 scopes are allowed. | | +| scopes | array | Key scopes list. Maximum of 200 scopes are allowed. | | | expire | string | Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. | | @@ -73,6 +100,79 @@ DELETE https://cloud.appwrite.io/v1/organization/keys/{keyId} | keyId | string | **Required** Key unique ID. | | +```http request +GET https://cloud.appwrite.io/v1/organization/memberships +``` + +** Get a list of all memberships from the current organization. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles | [] | +| search | string | Search term to filter your list results. Max length: 256 chars. | | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +POST https://cloud.appwrite.io/v1/organization/memberships +``` + +** Invite a new member to join the current organization. An email with a link to join the organization will be sent to the new member's email address. If member doesn't exist in the project it will be automatically created. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| email | string | Email of the new organization member. | | +| userId | string | ID of the user to be added to the organization. | | +| phone | string | Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. | | +| roles | array | Array of strings. Use this param to set the user roles in the organization. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 81 characters long. | | +| url | string | URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. | | +| name | string | Name of the new organization member. Max length: 128 chars. | | + + +```http request +GET https://cloud.appwrite.io/v1/organization/memberships/{membershipId} +``` + +** Get a membership from the current organization by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| membershipId | string | **Required** Membership ID. | | + + +```http request +PATCH https://cloud.appwrite.io/v1/organization/memberships/{membershipId} +``` + +** Modify the roles of a member in the current organization. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| membershipId | string | **Required** Membership ID. | | +| roles | array | An array of strings. Use this param to set the user's roles in the organization. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 81 characters long. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/organization/memberships/{membershipId} +``` + +** Remove a member from the current organization. The member is removed whether they accepted the invitation or not; a pending invitation is revoked. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| membershipId | string | **Required** Membership ID. | | + + ```http request GET https://cloud.appwrite.io/v1/organization/projects ``` @@ -83,7 +183,7 @@ GET https://cloud.appwrite.io/v1/organization/projects | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId, labels, search | [] | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId, labels, search, accessedAt | [] | | search | string | Search term to filter your list results. Max length: 256 chars. | | | total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | diff --git a/docs/project.md b/docs/project.md index 6cb25b4a..ca8f7cb6 100644 --- a/docs/project.md +++ b/docs/project.md @@ -57,7 +57,7 @@ You can also create an ephemeral API key if you need a short-lived key instead. | --- | --- | --- | --- | | keyId | string | Key ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | name | string | Key name. Max length: 128 chars. | | -| scopes | array | Key scopes list. Maximum of 100 scopes are allowed. | | +| scopes | array | Key scopes list. Maximum of 200 scopes are allowed. | | | expire | string | Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. | | @@ -73,7 +73,7 @@ You can also create a standard API key if you need a longer-lived key instead. * | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| scopes | array | Key scopes list. Maximum of 100 scopes are allowed. | | +| scopes | array | Key scopes list. Maximum of 200 scopes are allowed. | | | duration | integer | Time in seconds before ephemeral key expires. Maximum duration is 3600 seconds. | | @@ -102,7 +102,7 @@ PUT https://cloud.appwrite.io/v1/project/keys/{keyId} | --- | --- | --- | --- | | keyId | string | **Required** Key ID. | | | name | string | Key name. Max length: 128 chars. | | -| scopes | array | Key scopes list. Maximum of 100 scopes are allowed. | | +| scopes | array | Key scopes list. Maximum of 200 scopes are allowed. | | | expire | string | Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. | | @@ -237,6 +237,7 @@ PUT https://cloud.appwrite.io/v1/project/oauth2-server | userCodeLength | integer | Number of characters in the device flow user code, excluding the formatting separator. Shorter codes are easier to type but weaker; pair short codes with short expiry. Leave empty to use default 8. | | | userCodeFormat | string | Character set for device flow user codes: `numeric` (digits only — best for numeric keypads and TV remotes), `alphabetic` (letters only), or `alphanumeric` (letters and digits — highest entropy per character). Defaults to `alphanumeric`. | alphanumeric | | deviceCodeDuration | integer | Lifetime in seconds of device flow device codes and user codes. Device codes are intentionally short-lived. Leave empty to use default 600. | | +| defaultScopes | array | List of OAuth2 scopes used when an authorization request omits the scope parameter. Every default scope must also be allowed by the OAuth2 server. Maximum of 100 scopes are allowed, each up to 128 characters long. | [] | ```http request @@ -271,6 +272,21 @@ PATCH https://cloud.appwrite.io/v1/project/oauth2/apple | enabled | boolean | OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. | | +```http request +PATCH https://cloud.appwrite.io/v1/project/oauth2/appwrite +``` + +** Update the project OAuth2 Appwrite configuration. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| clientId | string | 'Client ID' of Appwrite OAuth2 app. For example: 6a42000000000000b5a0 | | +| clientSecret | string | 'Client Secret' of Appwrite OAuth2 app. For example: b86afd000000000000000000000000000000000000000000000000000ced5f93 | | +| enabled | boolean | OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. | | + + ```http request PATCH https://cloud.appwrite.io/v1/project/oauth2/auth0 ``` @@ -625,6 +641,8 @@ PATCH https://cloud.appwrite.io/v1/project/oauth2/oidc | authorizationURL | string | OpenID Connect authorization endpoint URL. Required when wellKnownURL is not provided. For example: https://myoauth.com/oauth2/authorize | | | tokenURL | string | OpenID Connect token endpoint URL. Required when wellKnownURL is not provided. For example: https://myoauth.com/oauth2/token | | | userInfoURL | string | OpenID Connect user info endpoint URL. Required when wellKnownURL is not provided. For example: https://myoauth.com/oauth2/userinfo | | +| prompt | array | Array of OpenID Connect prompt values controlling the authentication and consent screens. If "none" is included, it must be the only element. "none" means: don't display any authentication or consent screens. "login" means: prompt the user to re-authenticate. "consent" means: prompt the user for consent. "select_account" means: prompt the user to select an account. | | +| maxAge | integer | Maximum authentication age in seconds. When set, the user must have authenticated within this many seconds, otherwise they are prompted to re-authenticate. | | | enabled | boolean | OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. | | diff --git a/docs/sites.md b/docs/sites.md index 80247d5a..74c000aa 100644 --- a/docs/sites.md +++ b/docs/sites.md @@ -64,6 +64,12 @@ GET https://cloud.appwrite.io/v1/sites/specifications ** List allowed site specifications for this instance. ** +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| type | string | Specification type to list. Can be one of: runtimes, builds. | runtimes | + ```http request GET https://cloud.appwrite.io/v1/sites/{siteId} @@ -108,7 +114,7 @@ PUT https://cloud.appwrite.io/v1/sites/{siteId} | providerRootDirectory | string | Path to site code in the linked repo. | | | providerBranches | array | List of branch name patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all branches. | | | providerPaths | array | List of file path patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all file changes. | | -| buildSpecification | string | Build specification for the site deployments. | [] | +| buildSpecification | string | Build specification for the site deployments. | | | runtimeSpecification | string | Runtime specification for the SSR executions. | [] | | deploymentRetention | integer | Days to keep non-active deployments before deletion. Value 0 means all deployments will be kept. | 0 | diff --git a/docs/tablesdb.md b/docs/tablesdb.md index 7580ce10..1df71a2b 100644 --- a/docs/tablesdb.md +++ b/docs/tablesdb.md @@ -30,7 +30,7 @@ POST https://cloud.appwrite.io/v1/tablesdb | databaseId | string | Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | name | string | Database name. Max length: 128 chars. | | | enabled | boolean | Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled. | 1 | -| dedicatedDatabaseId | string | Optional dedicated database (compute) ID to attach this database to. Leave empty to create a database on the shared pool. | | +| specification | string | Database specification. Defaults to `serverless`, which creates the database on the shared pool. Any other value provisions a dedicated database on that specification. | serverless | ```http request diff --git a/docs/usage.md b/docs/usage.md deleted file mode 100644 index c8466fc9..00000000 --- a/docs/usage.md +++ /dev/null @@ -1,60 +0,0 @@ -# Usage Service - - -```http request -GET https://cloud.appwrite.io/v1/usage/events -``` - -** Aggregate usage event metrics. `metric` is required. - -**Two response shapes**: -- Omit `interval` for a flat top-N table — one row per dimension combination, no time axis. Useful for "top 10 paths by bandwidth in the last 7 days". -- Pass `interval` (`1m`, `15m`, `30m`, `1h`, `1d`) for a time series — one row per (time bucket × dimension combination). - -`dimensions[]` breaks each row down by one or more attributes (service, path, status, country, …). `resource` and `resourceId` filter the underlying events. `orderBy=value`+`orderDir=desc`+`limit=N` returns the top-N by aggregated value. When `startAt` is omitted, the default window adapts to `interval` (or 7d when interval is omitted). ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| metric | string | **Required** Metric name (required). Example: executions, network.requests. | | -| resource | string | Resource type filter (singular form). Common values: function, site, database, bucket, file, webhook, team, user, project. | | -| resourceId | string | Resource id filter. | | -| interval | string | Time interval size. Omit (null) for a flat aggregate over the whole window. Allowed: 1m, 15m, 30m, 1h, 1d. | | -| dimensions | array | Break-down dimensions (max 10). Allowed: path, method, status, service, country, region, hostname, osName, clientType, clientName, deviceName, teamId, resourceId. | [] | -| startAt | string | Range start in ISO 8601. Defaults adapt to interval (7d for the no-interval aggregate). | | -| endAt | string | Range end in ISO 8601. Defaults to the current time. | | -| orderBy | string | Column to order by. Allowed: time, value. Default time when an interval is set; otherwise value. | time | -| orderDir | string | Sort direction: asc or desc. Default desc — paired with the default limit, returns the most recent / highest-value groups first. | desc | -| limit | integer | Maximum rows to return (1-5000). | 500 | -| offset | integer | Pagination offset (0-100000). | 0 | - - -```http request -GET https://cloud.appwrite.io/v1/usage/gauges -``` - -** Aggregate usage gauge snapshots. Gauges are point-in-time values (storage totals, resource counts, …); each group carries the latest snapshot in its interval via `argMax(value, time)`. `metric` is required. - -**Two response shapes**: -- Omit `interval` for a flat top-N table — `argMax(value, time)` per dimension combination over the whole window, no time axis. Useful for "top 10 resources by current storage". -- Pass `interval` (`1m`, `15m`, `30m`, `1h`, `1d`) for a time series — one snapshot per (time bucket × dimension combination). - -`dimensions[]` breaks each row down further — only `resourceId` and `teamId` are supported on gauges. `resourceId` and `teamId` parameters filter the underlying rows. `orderBy=value`+`orderDir=desc`+`limit=N` returns the top-N. When `startAt` is omitted, the default window adapts to interval (or 7d when interval is omitted). ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| metric | string | **Required** Metric name (required). Example: files.storage, deployments.storage. | | -| resourceId | string | Resource id filter. | | -| teamId | string | Team id filter. | | -| interval | string | Time interval size. Omit (null) for a flat aggregate over the whole window. Allowed: 1m, 15m, 30m, 1h, 1d. | | -| dimensions | array | Break-down dimensions. Allowed: resourceId, teamId. | [] | -| startAt | string | Range start in ISO 8601. Defaults to endAt - 7d. | | -| endAt | string | Range end in ISO 8601. Defaults to the current time. | | -| orderBy | string | Column to order by. Allowed: time, value. Default time. | time | -| orderDir | string | Sort direction: asc or desc. Default desc — paired with the default limit, this returns the most recent groups first. Pass asc for chronological charting. | desc | -| limit | integer | Maximum rows to return (1-5000). | 500 | -| offset | integer | Pagination offset (0-100000). | 0 | - diff --git a/docs/users.md b/docs/users.md index 5c246265..02d1d014 100644 --- a/docs/users.md +++ b/docs/users.md @@ -11,7 +11,7 @@ GET https://cloud.appwrite.io/v1/users | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification, labels, impersonator | [] | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification, labels, impersonator, accessedAt | [] | | search | string | Search term to filter your list results. Max length: 256 chars. | | | total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | diff --git a/src/Appwrite/Client.php b/src/Appwrite/Client.php index 0242bc6b..2787f561 100644 --- a/src/Appwrite/Client.php +++ b/src/Appwrite/Client.php @@ -2,6 +2,8 @@ namespace Appwrite; +use Ahc\Jwt\JWT; + class Client { const METHOD_GET = 'GET'; @@ -15,6 +17,7 @@ class Client const METHOD_TRACE = 'TRACE'; const CHUNK_SIZE = 5 * 1024 * 1024; + const JWT_MAX_AGE_SECONDS = 3600; /** * Is Self Signed Certificates Allowed? @@ -37,11 +40,11 @@ class Client */ protected array $headers = [ 'content-type' => '', - 'user-agent' => 'AppwritePHPSDK/26.1.0 ()', + 'user-agent' => 'AppwritePHPSDK/27.0.0 ()', 'x-sdk-name'=> 'PHP', 'x-sdk-platform'=> 'server', 'x-sdk-language'=> 'php', - 'x-sdk-version'=> '26.1.0', + 'x-sdk-version'=> '27.0.0', ]; /** @@ -51,6 +54,27 @@ class Client */ protected array $config = []; + /** + * API key for JWT generation + * + * @var string|null + */ + protected ?string $key = null; + + /** + * Cached authorization header value + * + * @var string|null + */ + protected ?string $authorization = null; + + /** + * Authorization header expiry time + * + * @var \DateTime|null + */ + protected ?\DateTime $authorizationExpiresAt = null; + /** * Timeout in seconds * @@ -124,6 +148,26 @@ public function setJWT(string $value): Client return $this; } + /** + * Set Bearer + * + * The OAuth access token to authenticate with + * + * @param string $value + * + * @return Client + */ + public function setBearer(string $value): Client + { + $this->addHeader('Authorization', $value); + $this->config['bearer'] = $value; + $this->key = null; + $this->authorization = null; + $this->authorizationExpiresAt = null; + + return $this; + } + /** * Set Locale * @@ -258,6 +302,25 @@ public function setImpersonateUserPhone(string $value): Client return $this; } + /** + * Set Signing Key + * + * Set a secret key used to self-sign short-lived JWTs for the Authorization header + * + * @param string $key + * + * @return Client + */ + public function setSigningKey(string $key): Client + { + $this->key = $key; + $this->authorization = null; + $this->authorizationExpiresAt = null; + unset($this->headers['authorization'], $this->config['bearer']); + + return $this; + } + public function getConfig(string $key): string { @@ -334,6 +397,25 @@ public function getHeaders(): array return $this->headers; } + /** + * Get authorization header, generating a new JWT if needed + * + * @return string + */ + private function getAuthorization(): string + { + if (\is_string($this->authorization) && $this->authorizationExpiresAt > new \DateTime()) { + return $this->authorization; + } + + $jwt = new JWT($this->key, maxAge: self::JWT_MAX_AGE_SECONDS); + $this->authorization = "Bearer {$jwt->encode([])}"; + + $this->authorizationExpiresAt = (new \DateTime())->modify('+' . (self::JWT_MAX_AGE_SECONDS - 5) . ' seconds'); + + return $this->authorization; + } + /** * Call * @@ -354,6 +436,9 @@ public function call( ?string $responseType = null ) { + if ($this->key !== null) { + $this->headers['authorization'] = $this->getAuthorization(); + } $headers = array_merge($this->headers, $headers); $querySeparator = str_contains($path, '?') ? '&' : '?'; $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? $querySeparator . http_build_query($params) : '')); diff --git a/src/Appwrite/Enums/BillingPlanGroup.php b/src/Appwrite/Enums/BillingPlanGroup.php new file mode 100644 index 00000000..a58d7e91 --- /dev/null +++ b/src/Appwrite/Enums/BillingPlanGroup.php @@ -0,0 +1,61 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } + + public function jsonSerialize(): string + { + return $this->value; + } + + public static function STARTER(): BillingPlanGroup + { + if (!isset(self::$STARTER)) { + self::$STARTER = new BillingPlanGroup('starter'); + } + return self::$STARTER; + } + public static function PRO(): BillingPlanGroup + { + if (!isset(self::$PRO)) { + self::$PRO = new BillingPlanGroup('pro'); + } + return self::$PRO; + } + public static function SCALE(): BillingPlanGroup + { + if (!isset(self::$SCALE)) { + self::$SCALE = new BillingPlanGroup('scale'); + } + return self::$SCALE; + } + + public static function from(string $value): self + { + return match ($value) { + 'starter' => self::STARTER(), + 'pro' => self::PRO(), + 'scale' => self::SCALE(), + default => throw new \InvalidArgumentException('Unknown BillingPlanGroup value: ' . $value), + }; + } +} diff --git a/src/Appwrite/Enums/DatabaseStatus.php b/src/Appwrite/Enums/DatabaseStatus.php new file mode 100644 index 00000000..0555a062 --- /dev/null +++ b/src/Appwrite/Enums/DatabaseStatus.php @@ -0,0 +1,61 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } + + public function jsonSerialize(): string + { + return $this->value; + } + + public static function PROVISIONING(): DatabaseStatus + { + if (!isset(self::$PROVISIONING)) { + self::$PROVISIONING = new DatabaseStatus('provisioning'); + } + return self::$PROVISIONING; + } + public static function READY(): DatabaseStatus + { + if (!isset(self::$READY)) { + self::$READY = new DatabaseStatus('ready'); + } + return self::$READY; + } + public static function FAILED(): DatabaseStatus + { + if (!isset(self::$FAILED)) { + self::$FAILED = new DatabaseStatus('failed'); + } + return self::$FAILED; + } + + public static function from(string $value): self + { + return match ($value) { + 'provisioning' => self::PROVISIONING(), + 'ready' => self::READY(), + 'failed' => self::FAILED(), + default => throw new \InvalidArgumentException('Unknown DatabaseStatus value: ' . $value), + }; + } +} diff --git a/src/Appwrite/Enums/HealthAntivirusStatus.php b/src/Appwrite/Enums/HealthAntivirusStatus.php deleted file mode 100644 index edee6045..00000000 --- a/src/Appwrite/Enums/HealthAntivirusStatus.php +++ /dev/null @@ -1,61 +0,0 @@ -value = $value; - } - - public function __toString(): string - { - return $this->value; - } - - public function jsonSerialize(): string - { - return $this->value; - } - - public static function DISABLED(): HealthAntivirusStatus - { - if (!isset(self::$DISABLED)) { - self::$DISABLED = new HealthAntivirusStatus('disabled'); - } - return self::$DISABLED; - } - public static function OFFLINE(): HealthAntivirusStatus - { - if (!isset(self::$OFFLINE)) { - self::$OFFLINE = new HealthAntivirusStatus('offline'); - } - return self::$OFFLINE; - } - public static function ONLINE(): HealthAntivirusStatus - { - if (!isset(self::$ONLINE)) { - self::$ONLINE = new HealthAntivirusStatus('online'); - } - return self::$ONLINE; - } - - public static function from(string $value): self - { - return match ($value) { - 'disabled' => self::DISABLED(), - 'offline' => self::OFFLINE(), - 'online' => self::ONLINE(), - default => throw new \InvalidArgumentException('Unknown HealthAntivirusStatus value: ' . $value), - }; - } -} diff --git a/src/Appwrite/Enums/HealthCheckStatus.php b/src/Appwrite/Enums/HealthCheckStatus.php deleted file mode 100644 index 8d36ec4e..00000000 --- a/src/Appwrite/Enums/HealthCheckStatus.php +++ /dev/null @@ -1,52 +0,0 @@ -value = $value; - } - - public function __toString(): string - { - return $this->value; - } - - public function jsonSerialize(): string - { - return $this->value; - } - - public static function PASS(): HealthCheckStatus - { - if (!isset(self::$PASS)) { - self::$PASS = new HealthCheckStatus('pass'); - } - return self::$PASS; - } - public static function FAIL(): HealthCheckStatus - { - if (!isset(self::$FAIL)) { - self::$FAIL = new HealthCheckStatus('fail'); - } - return self::$FAIL; - } - - public static function from(string $value): self - { - return match ($value) { - 'pass' => self::PASS(), - 'fail' => self::FAIL(), - default => throw new \InvalidArgumentException('Unknown HealthCheckStatus value: ' . $value), - }; - } -} diff --git a/src/Appwrite/Enums/HealthQueueName.php b/src/Appwrite/Enums/HealthQueueName.php deleted file mode 100644 index e03d7c81..00000000 --- a/src/Appwrite/Enums/HealthQueueName.php +++ /dev/null @@ -1,151 +0,0 @@ -value = $value; - } - - public function __toString(): string - { - return $this->value; - } - - public function jsonSerialize(): string - { - return $this->value; - } - - public static function V1DATABASE(): HealthQueueName - { - if (!isset(self::$V1DATABASE)) { - self::$V1DATABASE = new HealthQueueName('v1-database'); - } - return self::$V1DATABASE; - } - public static function V1DELETES(): HealthQueueName - { - if (!isset(self::$V1DELETES)) { - self::$V1DELETES = new HealthQueueName('v1-deletes'); - } - return self::$V1DELETES; - } - public static function V1AUDITS(): HealthQueueName - { - if (!isset(self::$V1AUDITS)) { - self::$V1AUDITS = new HealthQueueName('v1-audits'); - } - return self::$V1AUDITS; - } - public static function V1MAILS(): HealthQueueName - { - if (!isset(self::$V1MAILS)) { - self::$V1MAILS = new HealthQueueName('v1-mails'); - } - return self::$V1MAILS; - } - public static function V1FUNCTIONS(): HealthQueueName - { - if (!isset(self::$V1FUNCTIONS)) { - self::$V1FUNCTIONS = new HealthQueueName('v1-functions'); - } - return self::$V1FUNCTIONS; - } - public static function V1STATSRESOURCES(): HealthQueueName - { - if (!isset(self::$V1STATSRESOURCES)) { - self::$V1STATSRESOURCES = new HealthQueueName('v1-stats-resources'); - } - return self::$V1STATSRESOURCES; - } - public static function V1STATSUSAGE(): HealthQueueName - { - if (!isset(self::$V1STATSUSAGE)) { - self::$V1STATSUSAGE = new HealthQueueName('v1-stats-usage'); - } - return self::$V1STATSUSAGE; - } - public static function V1WEBHOOKS(): HealthQueueName - { - if (!isset(self::$V1WEBHOOKS)) { - self::$V1WEBHOOKS = new HealthQueueName('v1-webhooks'); - } - return self::$V1WEBHOOKS; - } - public static function V1CERTIFICATES(): HealthQueueName - { - if (!isset(self::$V1CERTIFICATES)) { - self::$V1CERTIFICATES = new HealthQueueName('v1-certificates'); - } - return self::$V1CERTIFICATES; - } - public static function V1BUILDS(): HealthQueueName - { - if (!isset(self::$V1BUILDS)) { - self::$V1BUILDS = new HealthQueueName('v1-builds'); - } - return self::$V1BUILDS; - } - public static function V1SCREENSHOTS(): HealthQueueName - { - if (!isset(self::$V1SCREENSHOTS)) { - self::$V1SCREENSHOTS = new HealthQueueName('v1-screenshots'); - } - return self::$V1SCREENSHOTS; - } - public static function V1MESSAGING(): HealthQueueName - { - if (!isset(self::$V1MESSAGING)) { - self::$V1MESSAGING = new HealthQueueName('v1-messaging'); - } - return self::$V1MESSAGING; - } - public static function V1MIGRATIONS(): HealthQueueName - { - if (!isset(self::$V1MIGRATIONS)) { - self::$V1MIGRATIONS = new HealthQueueName('v1-migrations'); - } - return self::$V1MIGRATIONS; - } - - public static function from(string $value): self - { - return match ($value) { - 'v1-database' => self::V1DATABASE(), - 'v1-deletes' => self::V1DELETES(), - 'v1-audits' => self::V1AUDITS(), - 'v1-mails' => self::V1MAILS(), - 'v1-functions' => self::V1FUNCTIONS(), - 'v1-stats-resources' => self::V1STATSRESOURCES(), - 'v1-stats-usage' => self::V1STATSUSAGE(), - 'v1-webhooks' => self::V1WEBHOOKS(), - 'v1-certificates' => self::V1CERTIFICATES(), - 'v1-builds' => self::V1BUILDS(), - 'v1-screenshots' => self::V1SCREENSHOTS(), - 'v1-messaging' => self::V1MESSAGING(), - 'v1-migrations' => self::V1MIGRATIONS(), - default => throw new \InvalidArgumentException('Unknown HealthQueueName value: ' . $value), - }; - } -} diff --git a/src/Appwrite/Enums/OAuth2OidcPrompt.php b/src/Appwrite/Enums/OAuth2OidcPrompt.php new file mode 100644 index 00000000..bbdad5ad --- /dev/null +++ b/src/Appwrite/Enums/OAuth2OidcPrompt.php @@ -0,0 +1,70 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } + + public function jsonSerialize(): string + { + return $this->value; + } + + public static function NONE(): OAuth2OidcPrompt + { + if (!isset(self::$NONE)) { + self::$NONE = new OAuth2OidcPrompt('none'); + } + return self::$NONE; + } + public static function LOGIN(): OAuth2OidcPrompt + { + if (!isset(self::$LOGIN)) { + self::$LOGIN = new OAuth2OidcPrompt('login'); + } + return self::$LOGIN; + } + public static function CONSENT(): OAuth2OidcPrompt + { + if (!isset(self::$CONSENT)) { + self::$CONSENT = new OAuth2OidcPrompt('consent'); + } + return self::$CONSENT; + } + public static function SELECTACCOUNT(): OAuth2OidcPrompt + { + if (!isset(self::$SELECTACCOUNT)) { + self::$SELECTACCOUNT = new OAuth2OidcPrompt('select_account'); + } + return self::$SELECTACCOUNT; + } + + public static function from(string $value): self + { + return match ($value) { + 'none' => self::NONE(), + 'login' => self::LOGIN(), + 'consent' => self::CONSENT(), + 'select_account' => self::SELECTACCOUNT(), + default => throw new \InvalidArgumentException('Unknown OAuth2OidcPrompt value: ' . $value), + }; + } +} diff --git a/src/Appwrite/Enums/OAuthProvider.php b/src/Appwrite/Enums/OAuthProvider.php index 4763c082..decb1d46 100644 --- a/src/Appwrite/Enums/OAuthProvider.php +++ b/src/Appwrite/Enums/OAuthProvider.php @@ -8,6 +8,7 @@ class OAuthProvider implements JsonSerializable { private static OAuthProvider $AMAZON; private static OAuthProvider $APPLE; + private static OAuthProvider $APPWRITE; private static OAuthProvider $AUTH0; private static OAuthProvider $AUTHENTIK; private static OAuthProvider $AUTODESK; @@ -81,6 +82,13 @@ public static function APPLE(): OAuthProvider } return self::$APPLE; } + public static function APPWRITE(): OAuthProvider + { + if (!isset(self::$APPWRITE)) { + self::$APPWRITE = new OAuthProvider('appwrite'); + } + return self::$APPWRITE; + } public static function AUTH0(): OAuthProvider { if (!isset(self::$AUTH0)) { @@ -374,6 +382,7 @@ public static function from(string $value): self return match ($value) { 'amazon' => self::AMAZON(), 'apple' => self::APPLE(), + 'appwrite' => self::APPWRITE(), 'auth0' => self::AUTH0(), 'authentik' => self::AUTHENTIK(), 'autodesk' => self::AUTODESK(), diff --git a/src/Appwrite/Enums/OrganizationKeyScopes.php b/src/Appwrite/Enums/OrganizationKeyScopes.php index b013d0f2..7bf3987f 100644 --- a/src/Appwrite/Enums/OrganizationKeyScopes.php +++ b/src/Appwrite/Enums/OrganizationKeyScopes.php @@ -12,6 +12,10 @@ class OrganizationKeyScopes implements JsonSerializable private static OrganizationKeyScopes $DEVKEYSWRITE; private static OrganizationKeyScopes $ORGANIZATIONKEYSREAD; private static OrganizationKeyScopes $ORGANIZATIONKEYSWRITE; + private static OrganizationKeyScopes $ORGANIZATIONMEMBERSHIPSREAD; + private static OrganizationKeyScopes $ORGANIZATIONMEMBERSHIPSWRITE; + private static OrganizationKeyScopes $ORGANIZATIONREAD; + private static OrganizationKeyScopes $ORGANIZATIONWRITE; private static OrganizationKeyScopes $DOMAINSREAD; private static OrganizationKeyScopes $DOMAINSWRITE; private static OrganizationKeyScopes $KEYSREAD; @@ -76,6 +80,34 @@ public static function ORGANIZATIONKEYSWRITE(): OrganizationKeyScopes } return self::$ORGANIZATIONKEYSWRITE; } + public static function ORGANIZATIONMEMBERSHIPSREAD(): OrganizationKeyScopes + { + if (!isset(self::$ORGANIZATIONMEMBERSHIPSREAD)) { + self::$ORGANIZATIONMEMBERSHIPSREAD = new OrganizationKeyScopes('organization.memberships.read'); + } + return self::$ORGANIZATIONMEMBERSHIPSREAD; + } + public static function ORGANIZATIONMEMBERSHIPSWRITE(): OrganizationKeyScopes + { + if (!isset(self::$ORGANIZATIONMEMBERSHIPSWRITE)) { + self::$ORGANIZATIONMEMBERSHIPSWRITE = new OrganizationKeyScopes('organization.memberships.write'); + } + return self::$ORGANIZATIONMEMBERSHIPSWRITE; + } + public static function ORGANIZATIONREAD(): OrganizationKeyScopes + { + if (!isset(self::$ORGANIZATIONREAD)) { + self::$ORGANIZATIONREAD = new OrganizationKeyScopes('organization.read'); + } + return self::$ORGANIZATIONREAD; + } + public static function ORGANIZATIONWRITE(): OrganizationKeyScopes + { + if (!isset(self::$ORGANIZATIONWRITE)) { + self::$ORGANIZATIONWRITE = new OrganizationKeyScopes('organization.write'); + } + return self::$ORGANIZATIONWRITE; + } public static function DOMAINSREAD(): OrganizationKeyScopes { if (!isset(self::$DOMAINSREAD)) { @@ -114,6 +146,10 @@ public static function from(string $value): self 'devKeys.write' => self::DEVKEYSWRITE(), 'organization.keys.read' => self::ORGANIZATIONKEYSREAD(), 'organization.keys.write' => self::ORGANIZATIONKEYSWRITE(), + 'organization.memberships.read' => self::ORGANIZATIONMEMBERSHIPSREAD(), + 'organization.memberships.write' => self::ORGANIZATIONMEMBERSHIPSWRITE(), + 'organization.read' => self::ORGANIZATIONREAD(), + 'organization.write' => self::ORGANIZATIONWRITE(), 'domains.read' => self::DOMAINSREAD(), 'domains.write' => self::DOMAINSWRITE(), 'keys.read' => self::KEYSREAD(), diff --git a/src/Appwrite/Enums/ProjectKeyScopes.php b/src/Appwrite/Enums/ProjectKeyScopes.php index 2c78383f..c087a037 100644 --- a/src/Appwrite/Enums/ProjectKeyScopes.php +++ b/src/Appwrite/Enums/ProjectKeyScopes.php @@ -18,10 +18,12 @@ class ProjectKeyScopes implements JsonSerializable private static ProjectKeyScopes $POLICIESWRITE; private static ProjectKeyScopes $PROJECTPOLICIESREAD; private static ProjectKeyScopes $PROJECTPOLICIESWRITE; + private static ProjectKeyScopes $PROJECTOAUTH2READ; + private static ProjectKeyScopes $PROJECTOAUTH2WRITE; private static ProjectKeyScopes $TEMPLATESREAD; private static ProjectKeyScopes $TEMPLATESWRITE; - private static ProjectKeyScopes $OAUTH2READ; - private static ProjectKeyScopes $OAUTH2WRITE; + private static ProjectKeyScopes $STAGESREAD; + private static ProjectKeyScopes $STAGESWRITE; private static ProjectKeyScopes $USERSREAD; private static ProjectKeyScopes $USERSWRITE; private static ProjectKeyScopes $SESSIONSREAD; @@ -102,6 +104,8 @@ class ProjectKeyScopes implements JsonSerializable private static ProjectKeyScopes $EVENTSREAD; private static ProjectKeyScopes $APPSREAD; private static ProjectKeyScopes $APPSWRITE; + private static ProjectKeyScopes $OAUTH2READ; + private static ProjectKeyScopes $OAUTH2WRITE; private static ProjectKeyScopes $USAGEREAD; private string $value; @@ -205,6 +209,20 @@ public static function PROJECTPOLICIESWRITE(): ProjectKeyScopes } return self::$PROJECTPOLICIESWRITE; } + public static function PROJECTOAUTH2READ(): ProjectKeyScopes + { + if (!isset(self::$PROJECTOAUTH2READ)) { + self::$PROJECTOAUTH2READ = new ProjectKeyScopes('project.oauth2.read'); + } + return self::$PROJECTOAUTH2READ; + } + public static function PROJECTOAUTH2WRITE(): ProjectKeyScopes + { + if (!isset(self::$PROJECTOAUTH2WRITE)) { + self::$PROJECTOAUTH2WRITE = new ProjectKeyScopes('project.oauth2.write'); + } + return self::$PROJECTOAUTH2WRITE; + } public static function TEMPLATESREAD(): ProjectKeyScopes { if (!isset(self::$TEMPLATESREAD)) { @@ -219,19 +237,19 @@ public static function TEMPLATESWRITE(): ProjectKeyScopes } return self::$TEMPLATESWRITE; } - public static function OAUTH2READ(): ProjectKeyScopes + public static function STAGESREAD(): ProjectKeyScopes { - if (!isset(self::$OAUTH2READ)) { - self::$OAUTH2READ = new ProjectKeyScopes('oauth2.read'); + if (!isset(self::$STAGESREAD)) { + self::$STAGESREAD = new ProjectKeyScopes('stages.read'); } - return self::$OAUTH2READ; + return self::$STAGESREAD; } - public static function OAUTH2WRITE(): ProjectKeyScopes + public static function STAGESWRITE(): ProjectKeyScopes { - if (!isset(self::$OAUTH2WRITE)) { - self::$OAUTH2WRITE = new ProjectKeyScopes('oauth2.write'); + if (!isset(self::$STAGESWRITE)) { + self::$STAGESWRITE = new ProjectKeyScopes('stages.write'); } - return self::$OAUTH2WRITE; + return self::$STAGESWRITE; } public static function USERSREAD(): ProjectKeyScopes { @@ -793,6 +811,20 @@ public static function APPSWRITE(): ProjectKeyScopes } return self::$APPSWRITE; } + public static function OAUTH2READ(): ProjectKeyScopes + { + if (!isset(self::$OAUTH2READ)) { + self::$OAUTH2READ = new ProjectKeyScopes('oauth2.read'); + } + return self::$OAUTH2READ; + } + public static function OAUTH2WRITE(): ProjectKeyScopes + { + if (!isset(self::$OAUTH2WRITE)) { + self::$OAUTH2WRITE = new ProjectKeyScopes('oauth2.write'); + } + return self::$OAUTH2WRITE; + } public static function USAGEREAD(): ProjectKeyScopes { if (!isset(self::$USAGEREAD)) { @@ -816,10 +848,12 @@ public static function from(string $value): self 'policies.write' => self::POLICIESWRITE(), 'project.policies.read' => self::PROJECTPOLICIESREAD(), 'project.policies.write' => self::PROJECTPOLICIESWRITE(), + 'project.oauth2.read' => self::PROJECTOAUTH2READ(), + 'project.oauth2.write' => self::PROJECTOAUTH2WRITE(), 'templates.read' => self::TEMPLATESREAD(), 'templates.write' => self::TEMPLATESWRITE(), - 'oauth2.read' => self::OAUTH2READ(), - 'oauth2.write' => self::OAUTH2WRITE(), + 'stages.read' => self::STAGESREAD(), + 'stages.write' => self::STAGESWRITE(), 'users.read' => self::USERSREAD(), 'users.write' => self::USERSWRITE(), 'sessions.read' => self::SESSIONSREAD(), @@ -900,6 +934,8 @@ public static function from(string $value): self 'events.read' => self::EVENTSREAD(), 'apps.read' => self::APPSREAD(), 'apps.write' => self::APPSWRITE(), + 'oauth2.read' => self::OAUTH2READ(), + 'oauth2.write' => self::OAUTH2WRITE(), 'usage.read' => self::USAGEREAD(), default => throw new \InvalidArgumentException('Unknown ProjectKeyScopes value: ' . $value), }; diff --git a/src/Appwrite/Enums/ProjectOAuth2OidcPrompt.php b/src/Appwrite/Enums/ProjectOAuth2OidcPrompt.php new file mode 100644 index 00000000..867ee098 --- /dev/null +++ b/src/Appwrite/Enums/ProjectOAuth2OidcPrompt.php @@ -0,0 +1,70 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } + + public function jsonSerialize(): string + { + return $this->value; + } + + public static function NONE(): ProjectOAuth2OidcPrompt + { + if (!isset(self::$NONE)) { + self::$NONE = new ProjectOAuth2OidcPrompt('none'); + } + return self::$NONE; + } + public static function LOGIN(): ProjectOAuth2OidcPrompt + { + if (!isset(self::$LOGIN)) { + self::$LOGIN = new ProjectOAuth2OidcPrompt('login'); + } + return self::$LOGIN; + } + public static function CONSENT(): ProjectOAuth2OidcPrompt + { + if (!isset(self::$CONSENT)) { + self::$CONSENT = new ProjectOAuth2OidcPrompt('consent'); + } + return self::$CONSENT; + } + public static function SELECTACCOUNT(): ProjectOAuth2OidcPrompt + { + if (!isset(self::$SELECTACCOUNT)) { + self::$SELECTACCOUNT = new ProjectOAuth2OidcPrompt('select_account'); + } + return self::$SELECTACCOUNT; + } + + public static function from(string $value): self + { + return match ($value) { + 'none' => self::NONE(), + 'login' => self::LOGIN(), + 'consent' => self::CONSENT(), + 'select_account' => self::SELECTACCOUNT(), + default => throw new \InvalidArgumentException('Unknown ProjectOAuth2OidcPrompt value: ' . $value), + }; + } +} diff --git a/src/Appwrite/Enums/ProjectOAuthProviderId.php b/src/Appwrite/Enums/ProjectOAuthProviderId.php index a9325a75..7f697114 100644 --- a/src/Appwrite/Enums/ProjectOAuthProviderId.php +++ b/src/Appwrite/Enums/ProjectOAuthProviderId.php @@ -8,6 +8,7 @@ class ProjectOAuthProviderId implements JsonSerializable { private static ProjectOAuthProviderId $AMAZON; private static ProjectOAuthProviderId $APPLE; + private static ProjectOAuthProviderId $APPWRITE; private static ProjectOAuthProviderId $AUTH0; private static ProjectOAuthProviderId $AUTHENTIK; private static ProjectOAuthProviderId $AUTODESK; @@ -81,6 +82,13 @@ public static function APPLE(): ProjectOAuthProviderId } return self::$APPLE; } + public static function APPWRITE(): ProjectOAuthProviderId + { + if (!isset(self::$APPWRITE)) { + self::$APPWRITE = new ProjectOAuthProviderId('appwrite'); + } + return self::$APPWRITE; + } public static function AUTH0(): ProjectOAuthProviderId { if (!isset(self::$AUTH0)) { @@ -374,6 +382,7 @@ public static function from(string $value): self return match ($value) { 'amazon' => self::AMAZON(), 'apple' => self::APPLE(), + 'appwrite' => self::APPWRITE(), 'auth0' => self::AUTH0(), 'authentik' => self::AUTHENTIK(), 'autodesk' => self::AUTODESK(), diff --git a/src/Appwrite/Models/ActivityEvent.php b/src/Appwrite/Models/ActivityEvent.php index 287011dd..5c6429ab 100644 --- a/src/Appwrite/Models/ActivityEvent.php +++ b/src/Appwrite/Models/ActivityEvent.php @@ -30,8 +30,6 @@ * @param string $projectId project id. * @param string $teamId team id. * @param string $hostname hostname. - * @param string $countryCode country two-character iso 3166-1 alpha code. - * @param string $countryName country name. */ public function __construct( public string $id, @@ -51,9 +49,7 @@ public function __construct( public string $time, public string $projectId, public string $teamId, - public string $hostname, - public string $countryCode, - public string $countryName + public string $hostname ) { } @@ -116,12 +112,6 @@ public static function from(array $data): static if (!array_key_exists('hostname', $data)) { throw new \InvalidArgumentException('Missing required field "hostname" for ' . static::class . '.'); } - if (!array_key_exists('countryCode', $data)) { - throw new \InvalidArgumentException('Missing required field "countryCode" for ' . static::class . '.'); - } - if (!array_key_exists('countryName', $data)) { - throw new \InvalidArgumentException('Missing required field "countryName" for ' . static::class . '.'); - } return new static( id: $data['$id'], @@ -141,9 +131,7 @@ public static function from(array $data): static time: $data['time'], projectId: $data['projectId'], teamId: $data['teamId'], - hostname: $data['hostname'], - countryCode: $data['countryCode'], - countryName: $data['countryName'] + hostname: $data['hostname'] ); } @@ -170,9 +158,7 @@ public function toArray(): array 'time' => static::serializeValue($this->time), 'projectId' => static::serializeValue($this->projectId), 'teamId' => static::serializeValue($this->teamId), - 'hostname' => static::serializeValue($this->hostname), - 'countryCode' => static::serializeValue($this->countryCode), - 'countryName' => static::serializeValue($this->countryName) + 'hostname' => static::serializeValue($this->hostname) ]; return $result; diff --git a/src/Appwrite/Models/AdditionalResource.php b/src/Appwrite/Models/AdditionalResource.php new file mode 100644 index 00000000..22ccf01a --- /dev/null +++ b/src/Appwrite/Models/AdditionalResource.php @@ -0,0 +1,82 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); + } + if (!array_key_exists('unit', $data)) { + throw new \InvalidArgumentException('Missing required field "unit" for ' . static::class . '.'); + } + if (!array_key_exists('currency', $data)) { + throw new \InvalidArgumentException('Missing required field "currency" for ' . static::class . '.'); + } + if (!array_key_exists('price', $data)) { + throw new \InvalidArgumentException('Missing required field "price" for ' . static::class . '.'); + } + if (!array_key_exists('value', $data)) { + throw new \InvalidArgumentException('Missing required field "value" for ' . static::class . '.'); + } + if (!array_key_exists('invoiceDesc', $data)) { + throw new \InvalidArgumentException('Missing required field "invoiceDesc" for ' . static::class . '.'); + } + + return new static( + name: $data['name'], + unit: $data['unit'], + currency: $data['currency'], + price: $data['price'], + value: $data['value'], + invoiceDesc: $data['invoiceDesc'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'name' => static::serializeValue($this->name), + 'unit' => static::serializeValue($this->unit), + 'currency' => static::serializeValue($this->currency), + 'price' => static::serializeValue($this->price), + 'value' => static::serializeValue($this->value), + 'invoiceDesc' => static::serializeValue($this->invoiceDesc) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/BillingPlan.php b/src/Appwrite/Models/BillingPlan.php new file mode 100644 index 00000000..dcfd652e --- /dev/null +++ b/src/Appwrite/Models/BillingPlan.php @@ -0,0 +1,506 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); + } + if (!array_key_exists('desc', $data)) { + throw new \InvalidArgumentException('Missing required field "desc" for ' . static::class . '.'); + } + if (!array_key_exists('order', $data)) { + throw new \InvalidArgumentException('Missing required field "order" for ' . static::class . '.'); + } + if (!array_key_exists('price', $data)) { + throw new \InvalidArgumentException('Missing required field "price" for ' . static::class . '.'); + } + if (!array_key_exists('trial', $data)) { + throw new \InvalidArgumentException('Missing required field "trial" for ' . static::class . '.'); + } + if (!array_key_exists('bandwidth', $data)) { + throw new \InvalidArgumentException('Missing required field "bandwidth" for ' . static::class . '.'); + } + if (!array_key_exists('storage', $data)) { + throw new \InvalidArgumentException('Missing required field "storage" for ' . static::class . '.'); + } + if (!array_key_exists('imageTransformations', $data)) { + throw new \InvalidArgumentException('Missing required field "imageTransformations" for ' . static::class . '.'); + } + if (!array_key_exists('screenshotsGenerated', $data)) { + throw new \InvalidArgumentException('Missing required field "screenshotsGenerated" for ' . static::class . '.'); + } + if (!array_key_exists('members', $data)) { + throw new \InvalidArgumentException('Missing required field "members" for ' . static::class . '.'); + } + if (!array_key_exists('webhooks', $data)) { + throw new \InvalidArgumentException('Missing required field "webhooks" for ' . static::class . '.'); + } + if (!array_key_exists('projects', $data)) { + throw new \InvalidArgumentException('Missing required field "projects" for ' . static::class . '.'); + } + if (!array_key_exists('platforms', $data)) { + throw new \InvalidArgumentException('Missing required field "platforms" for ' . static::class . '.'); + } + if (!array_key_exists('users', $data)) { + throw new \InvalidArgumentException('Missing required field "users" for ' . static::class . '.'); + } + if (!array_key_exists('teams', $data)) { + throw new \InvalidArgumentException('Missing required field "teams" for ' . static::class . '.'); + } + if (!array_key_exists('databases', $data)) { + throw new \InvalidArgumentException('Missing required field "databases" for ' . static::class . '.'); + } + if (!array_key_exists('databasesReads', $data)) { + throw new \InvalidArgumentException('Missing required field "databasesReads" for ' . static::class . '.'); + } + if (!array_key_exists('databasesWrites', $data)) { + throw new \InvalidArgumentException('Missing required field "databasesWrites" for ' . static::class . '.'); + } + if (!array_key_exists('databasesBatchSize', $data)) { + throw new \InvalidArgumentException('Missing required field "databasesBatchSize" for ' . static::class . '.'); + } + if (!array_key_exists('buckets', $data)) { + throw new \InvalidArgumentException('Missing required field "buckets" for ' . static::class . '.'); + } + if (!array_key_exists('fileSize', $data)) { + throw new \InvalidArgumentException('Missing required field "fileSize" for ' . static::class . '.'); + } + if (!array_key_exists('functions', $data)) { + throw new \InvalidArgumentException('Missing required field "functions" for ' . static::class . '.'); + } + if (!array_key_exists('sites', $data)) { + throw new \InvalidArgumentException('Missing required field "sites" for ' . static::class . '.'); + } + if (!array_key_exists('executions', $data)) { + throw new \InvalidArgumentException('Missing required field "executions" for ' . static::class . '.'); + } + if (!array_key_exists('executionsRetentionCount', $data)) { + throw new \InvalidArgumentException('Missing required field "executionsRetentionCount" for ' . static::class . '.'); + } + if (!array_key_exists('GBHours', $data)) { + throw new \InvalidArgumentException('Missing required field "GBHours" for ' . static::class . '.'); + } + if (!array_key_exists('realtime', $data)) { + throw new \InvalidArgumentException('Missing required field "realtime" for ' . static::class . '.'); + } + if (!array_key_exists('realtimeMessages', $data)) { + throw new \InvalidArgumentException('Missing required field "realtimeMessages" for ' . static::class . '.'); + } + if (!array_key_exists('messages', $data)) { + throw new \InvalidArgumentException('Missing required field "messages" for ' . static::class . '.'); + } + if (!array_key_exists('topics', $data)) { + throw new \InvalidArgumentException('Missing required field "topics" for ' . static::class . '.'); + } + if (!array_key_exists('authPhone', $data)) { + throw new \InvalidArgumentException('Missing required field "authPhone" for ' . static::class . '.'); + } + if (!array_key_exists('domains', $data)) { + throw new \InvalidArgumentException('Missing required field "domains" for ' . static::class . '.'); + } + if (!array_key_exists('activityLogs', $data)) { + throw new \InvalidArgumentException('Missing required field "activityLogs" for ' . static::class . '.'); + } + if (!array_key_exists('usageLogs', $data)) { + throw new \InvalidArgumentException('Missing required field "usageLogs" for ' . static::class . '.'); + } + if (!array_key_exists('projectInactivityDays', $data)) { + throw new \InvalidArgumentException('Missing required field "projectInactivityDays" for ' . static::class . '.'); + } + if (!array_key_exists('alertLimit', $data)) { + throw new \InvalidArgumentException('Missing required field "alertLimit" for ' . static::class . '.'); + } + if (!array_key_exists('usage', $data)) { + throw new \InvalidArgumentException('Missing required field "usage" for ' . static::class . '.'); + } + if (!array_key_exists('addons', $data)) { + throw new \InvalidArgumentException('Missing required field "addons" for ' . static::class . '.'); + } + if (!array_key_exists('budgetCapEnabled', $data)) { + throw new \InvalidArgumentException('Missing required field "budgetCapEnabled" for ' . static::class . '.'); + } + if (!array_key_exists('customSmtp', $data)) { + throw new \InvalidArgumentException('Missing required field "customSmtp" for ' . static::class . '.'); + } + if (!array_key_exists('emailBranding', $data)) { + throw new \InvalidArgumentException('Missing required field "emailBranding" for ' . static::class . '.'); + } + if (!array_key_exists('requiresPaymentMethod', $data)) { + throw new \InvalidArgumentException('Missing required field "requiresPaymentMethod" for ' . static::class . '.'); + } + if (!array_key_exists('requiresBillingAddress', $data)) { + throw new \InvalidArgumentException('Missing required field "requiresBillingAddress" for ' . static::class . '.'); + } + if (!array_key_exists('isAvailable', $data)) { + throw new \InvalidArgumentException('Missing required field "isAvailable" for ' . static::class . '.'); + } + if (!array_key_exists('selfService', $data)) { + throw new \InvalidArgumentException('Missing required field "selfService" for ' . static::class . '.'); + } + if (!array_key_exists('premiumSupport', $data)) { + throw new \InvalidArgumentException('Missing required field "premiumSupport" for ' . static::class . '.'); + } + if (!array_key_exists('budgeting', $data)) { + throw new \InvalidArgumentException('Missing required field "budgeting" for ' . static::class . '.'); + } + if (!array_key_exists('supportsMockNumbers', $data)) { + throw new \InvalidArgumentException('Missing required field "supportsMockNumbers" for ' . static::class . '.'); + } + if (!array_key_exists('supportsOrganizationRoles', $data)) { + throw new \InvalidArgumentException('Missing required field "supportsOrganizationRoles" for ' . static::class . '.'); + } + if (!array_key_exists('supportsCredits', $data)) { + throw new \InvalidArgumentException('Missing required field "supportsCredits" for ' . static::class . '.'); + } + if (!array_key_exists('supportsDisposableEmailValidation', $data)) { + throw new \InvalidArgumentException('Missing required field "supportsDisposableEmailValidation" for ' . static::class . '.'); + } + if (!array_key_exists('supportsCanonicalEmailValidation', $data)) { + throw new \InvalidArgumentException('Missing required field "supportsCanonicalEmailValidation" for ' . static::class . '.'); + } + if (!array_key_exists('supportsFreeEmailValidation', $data)) { + throw new \InvalidArgumentException('Missing required field "supportsFreeEmailValidation" for ' . static::class . '.'); + } + if (!array_key_exists('supportsCorporateEmailValidation', $data)) { + throw new \InvalidArgumentException('Missing required field "supportsCorporateEmailValidation" for ' . static::class . '.'); + } + if (!array_key_exists('supportsProjectSpecificRoles', $data)) { + throw new \InvalidArgumentException('Missing required field "supportsProjectSpecificRoles" for ' . static::class . '.'); + } + if (!array_key_exists('backupsEnabled', $data)) { + throw new \InvalidArgumentException('Missing required field "backupsEnabled" for ' . static::class . '.'); + } + if (!array_key_exists('usagePerProject', $data)) { + throw new \InvalidArgumentException('Missing required field "usagePerProject" for ' . static::class . '.'); + } + if (!array_key_exists('supportedAddons', $data)) { + throw new \InvalidArgumentException('Missing required field "supportedAddons" for ' . static::class . '.'); + } + if (!array_key_exists('backupPolicies', $data)) { + throw new \InvalidArgumentException('Missing required field "backupPolicies" for ' . static::class . '.'); + } + if (!array_key_exists('deploymentSize', $data)) { + throw new \InvalidArgumentException('Missing required field "deploymentSize" for ' . static::class . '.'); + } + if (!array_key_exists('buildSize', $data)) { + throw new \InvalidArgumentException('Missing required field "buildSize" for ' . static::class . '.'); + } + if (!array_key_exists('databasesAllowEncrypt', $data)) { + throw new \InvalidArgumentException('Missing required field "databasesAllowEncrypt" for ' . static::class . '.'); + } + if (!array_key_exists('group', $data)) { + throw new \InvalidArgumentException('Missing required field "group" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + name: $data['name'], + desc: $data['desc'], + order: $data['order'], + price: $data['price'], + trial: $data['trial'], + bandwidth: $data['bandwidth'], + storage: $data['storage'], + imageTransformations: $data['imageTransformations'], + screenshotsGenerated: $data['screenshotsGenerated'], + members: $data['members'], + webhooks: $data['webhooks'], + projects: $data['projects'], + platforms: $data['platforms'], + users: $data['users'], + teams: $data['teams'], + databases: $data['databases'], + databasesReads: $data['databasesReads'], + databasesWrites: $data['databasesWrites'], + databasesBatchSize: $data['databasesBatchSize'], + buckets: $data['buckets'], + fileSize: $data['fileSize'], + functions: $data['functions'], + sites: $data['sites'], + executions: $data['executions'], + executionsRetentionCount: $data['executionsRetentionCount'], + gBHours: $data['GBHours'], + realtime: $data['realtime'], + realtimeMessages: $data['realtimeMessages'], + messages: $data['messages'], + topics: $data['topics'], + authPhone: $data['authPhone'], + domains: $data['domains'], + activityLogs: $data['activityLogs'], + usageLogs: $data['usageLogs'], + projectInactivityDays: $data['projectInactivityDays'], + alertLimit: $data['alertLimit'], + usage: static::hydrateTypedValue(UsageBillingPlan::class, $data['usage']), + addons: static::hydrateTypedValue(BillingPlanAddon::class, $data['addons']), + budgetCapEnabled: $data['budgetCapEnabled'], + customSmtp: $data['customSmtp'], + emailBranding: $data['emailBranding'], + requiresPaymentMethod: $data['requiresPaymentMethod'], + requiresBillingAddress: $data['requiresBillingAddress'], + isAvailable: $data['isAvailable'], + selfService: $data['selfService'], + premiumSupport: $data['premiumSupport'], + budgeting: $data['budgeting'], + supportsMockNumbers: $data['supportsMockNumbers'], + supportsOrganizationRoles: $data['supportsOrganizationRoles'], + supportsCredits: $data['supportsCredits'], + supportsDisposableEmailValidation: $data['supportsDisposableEmailValidation'], + supportsCanonicalEmailValidation: $data['supportsCanonicalEmailValidation'], + supportsFreeEmailValidation: $data['supportsFreeEmailValidation'], + supportsCorporateEmailValidation: $data['supportsCorporateEmailValidation'], + supportsProjectSpecificRoles: $data['supportsProjectSpecificRoles'], + backupsEnabled: $data['backupsEnabled'], + usagePerProject: $data['usagePerProject'], + supportedAddons: static::hydrateTypedValue(BillingPlanSupportedAddons::class, $data['supportedAddons']), + backupPolicies: $data['backupPolicies'], + deploymentSize: $data['deploymentSize'], + buildSize: $data['buildSize'], + databasesAllowEncrypt: $data['databasesAllowEncrypt'], + group: static::hydrateTypedValue(BillingPlanGroup::class, $data['group']), + usageLogsIntervals: array_key_exists('usageLogsIntervals', $data) ? $data['usageLogsIntervals'] : null, + limits: array_key_exists('limits', $data) ? static::hydrateTypedValue(BillingPlanLimits::class, $data['limits'], true) : null, + program: array_key_exists('program', $data) ? static::hydrateTypedValue(Program::class, $data['program'], true) : null, + dedicatedDatabases: array_key_exists('dedicatedDatabases', $data) ? static::hydrateTypedValue(BillingPlanDedicatedDatabaseLimits::class, $data['dedicatedDatabases'], true) : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + 'name' => static::serializeValue($this->name), + 'desc' => static::serializeValue($this->desc), + 'order' => static::serializeValue($this->order), + 'price' => static::serializeValue($this->price), + 'trial' => static::serializeValue($this->trial), + 'bandwidth' => static::serializeValue($this->bandwidth), + 'storage' => static::serializeValue($this->storage), + 'imageTransformations' => static::serializeValue($this->imageTransformations), + 'screenshotsGenerated' => static::serializeValue($this->screenshotsGenerated), + 'members' => static::serializeValue($this->members), + 'webhooks' => static::serializeValue($this->webhooks), + 'projects' => static::serializeValue($this->projects), + 'platforms' => static::serializeValue($this->platforms), + 'users' => static::serializeValue($this->users), + 'teams' => static::serializeValue($this->teams), + 'databases' => static::serializeValue($this->databases), + 'databasesReads' => static::serializeValue($this->databasesReads), + 'databasesWrites' => static::serializeValue($this->databasesWrites), + 'databasesBatchSize' => static::serializeValue($this->databasesBatchSize), + 'buckets' => static::serializeValue($this->buckets), + 'fileSize' => static::serializeValue($this->fileSize), + 'functions' => static::serializeValue($this->functions), + 'sites' => static::serializeValue($this->sites), + 'executions' => static::serializeValue($this->executions), + 'executionsRetentionCount' => static::serializeValue($this->executionsRetentionCount), + 'GBHours' => static::serializeValue($this->gBHours), + 'realtime' => static::serializeValue($this->realtime), + 'realtimeMessages' => static::serializeValue($this->realtimeMessages), + 'messages' => static::serializeValue($this->messages), + 'topics' => static::serializeValue($this->topics), + 'authPhone' => static::serializeValue($this->authPhone), + 'domains' => static::serializeValue($this->domains), + 'activityLogs' => static::serializeValue($this->activityLogs), + 'usageLogs' => static::serializeValue($this->usageLogs), + 'usageLogsIntervals' => static::serializeValue($this->usageLogsIntervals), + 'projectInactivityDays' => static::serializeValue($this->projectInactivityDays), + 'alertLimit' => static::serializeValue($this->alertLimit), + 'usage' => static::serializeValue($this->usage), + 'addons' => static::serializeValue($this->addons), + 'budgetCapEnabled' => static::serializeValue($this->budgetCapEnabled), + 'customSmtp' => static::serializeValue($this->customSmtp), + 'emailBranding' => static::serializeValue($this->emailBranding), + 'requiresPaymentMethod' => static::serializeValue($this->requiresPaymentMethod), + 'requiresBillingAddress' => static::serializeValue($this->requiresBillingAddress), + 'isAvailable' => static::serializeValue($this->isAvailable), + 'selfService' => static::serializeValue($this->selfService), + 'premiumSupport' => static::serializeValue($this->premiumSupport), + 'budgeting' => static::serializeValue($this->budgeting), + 'supportsMockNumbers' => static::serializeValue($this->supportsMockNumbers), + 'supportsOrganizationRoles' => static::serializeValue($this->supportsOrganizationRoles), + 'supportsCredits' => static::serializeValue($this->supportsCredits), + 'supportsDisposableEmailValidation' => static::serializeValue($this->supportsDisposableEmailValidation), + 'supportsCanonicalEmailValidation' => static::serializeValue($this->supportsCanonicalEmailValidation), + 'supportsFreeEmailValidation' => static::serializeValue($this->supportsFreeEmailValidation), + 'supportsCorporateEmailValidation' => static::serializeValue($this->supportsCorporateEmailValidation), + 'supportsProjectSpecificRoles' => static::serializeValue($this->supportsProjectSpecificRoles), + 'backupsEnabled' => static::serializeValue($this->backupsEnabled), + 'usagePerProject' => static::serializeValue($this->usagePerProject), + 'supportedAddons' => static::serializeValue($this->supportedAddons), + 'backupPolicies' => static::serializeValue($this->backupPolicies), + 'deploymentSize' => static::serializeValue($this->deploymentSize), + 'buildSize' => static::serializeValue($this->buildSize), + 'databasesAllowEncrypt' => static::serializeValue($this->databasesAllowEncrypt), + 'limits' => static::serializeValue($this->limits), + 'group' => static::serializeValue($this->group), + 'program' => static::serializeValue($this->program), + 'dedicatedDatabases' => static::serializeValue($this->dedicatedDatabases) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/BillingPlanAddon.php b/src/Appwrite/Models/BillingPlanAddon.php new file mode 100644 index 00000000..7e79ea14 --- /dev/null +++ b/src/Appwrite/Models/BillingPlanAddon.php @@ -0,0 +1,54 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('seats', $data)) { + throw new \InvalidArgumentException('Missing required field "seats" for ' . static::class . '.'); + } + if (!array_key_exists('projects', $data)) { + throw new \InvalidArgumentException('Missing required field "projects" for ' . static::class . '.'); + } + + return new static( + seats: static::hydrateTypedValue(BillingPlanAddonDetails::class, $data['seats']), + projects: static::hydrateTypedValue(BillingPlanAddonDetails::class, $data['projects']) + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'seats' => static::serializeValue($this->seats), + 'projects' => static::serializeValue($this->projects) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/BillingPlanAddonDetails.php b/src/Appwrite/Models/BillingPlanAddonDetails.php new file mode 100644 index 00000000..60f94449 --- /dev/null +++ b/src/Appwrite/Models/BillingPlanAddonDetails.php @@ -0,0 +1,96 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('supported', $data)) { + throw new \InvalidArgumentException('Missing required field "supported" for ' . static::class . '.'); + } + if (!array_key_exists('planIncluded', $data)) { + throw new \InvalidArgumentException('Missing required field "planIncluded" for ' . static::class . '.'); + } + if (!array_key_exists('limit', $data)) { + throw new \InvalidArgumentException('Missing required field "limit" for ' . static::class . '.'); + } + if (!array_key_exists('type', $data)) { + throw new \InvalidArgumentException('Missing required field "type" for ' . static::class . '.'); + } + if (!array_key_exists('currency', $data)) { + throw new \InvalidArgumentException('Missing required field "currency" for ' . static::class . '.'); + } + if (!array_key_exists('price', $data)) { + throw new \InvalidArgumentException('Missing required field "price" for ' . static::class . '.'); + } + if (!array_key_exists('value', $data)) { + throw new \InvalidArgumentException('Missing required field "value" for ' . static::class . '.'); + } + if (!array_key_exists('invoiceDesc', $data)) { + throw new \InvalidArgumentException('Missing required field "invoiceDesc" for ' . static::class . '.'); + } + + return new static( + supported: $data['supported'], + planIncluded: $data['planIncluded'], + limit: $data['limit'], + type: $data['type'], + currency: $data['currency'], + price: $data['price'], + value: $data['value'], + invoiceDesc: $data['invoiceDesc'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'supported' => static::serializeValue($this->supported), + 'planIncluded' => static::serializeValue($this->planIncluded), + 'limit' => static::serializeValue($this->limit), + 'type' => static::serializeValue($this->type), + 'currency' => static::serializeValue($this->currency), + 'price' => static::serializeValue($this->price), + 'value' => static::serializeValue($this->value), + 'invoiceDesc' => static::serializeValue($this->invoiceDesc) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/BillingPlanDedicatedDatabaseLimits.php b/src/Appwrite/Models/BillingPlanDedicatedDatabaseLimits.php new file mode 100644 index 00000000..97a088b1 --- /dev/null +++ b/src/Appwrite/Models/BillingPlanDedicatedDatabaseLimits.php @@ -0,0 +1,116 @@ + $data + */ + public static function from(array $data): static + { + + return new static( + minCpu: array_key_exists('minCpu', $data) ? $data['minCpu'] : null, + maxCpu: array_key_exists('maxCpu', $data) ? $data['maxCpu'] : null, + minMemoryMb: array_key_exists('minMemoryMb', $data) ? $data['minMemoryMb'] : null, + maxMemoryMb: array_key_exists('maxMemoryMb', $data) ? $data['maxMemoryMb'] : null, + minStorageGb: array_key_exists('minStorageGb', $data) ? $data['minStorageGb'] : null, + maxStorageGb: array_key_exists('maxStorageGb', $data) ? $data['maxStorageGb'] : null, + maxReplicas: array_key_exists('maxReplicas', $data) ? $data['maxReplicas'] : null, + maxConnections: array_key_exists('maxConnections', $data) ? $data['maxConnections'] : null, + maxIpAllowlistSize: array_key_exists('maxIpAllowlistSize', $data) ? $data['maxIpAllowlistSize'] : null, + maxExtensions: array_key_exists('maxExtensions', $data) ? $data['maxExtensions'] : null, + maxBackupRetentionDays: array_key_exists('maxBackupRetentionDays', $data) ? $data['maxBackupRetentionDays'] : null, + maxPitrRetentionDays: array_key_exists('maxPitrRetentionDays', $data) ? $data['maxPitrRetentionDays'] : null, + maxSqlApiMaxRows: array_key_exists('maxSqlApiMaxRows', $data) ? $data['maxSqlApiMaxRows'] : null, + maxSqlApiMaxBytes: array_key_exists('maxSqlApiMaxBytes', $data) ? $data['maxSqlApiMaxBytes'] : null, + maxSqlApiTimeoutSeconds: array_key_exists('maxSqlApiTimeoutSeconds', $data) ? $data['maxSqlApiTimeoutSeconds'] : null, + maxSqlApiAllowedStatements: array_key_exists('maxSqlApiAllowedStatements', $data) ? $data['maxSqlApiAllowedStatements'] : null, + allowedSqlStatements: array_key_exists('allowedSqlStatements', $data) ? $data['allowedSqlStatements'] : null, + allowedStorageClasses: array_key_exists('allowedStorageClasses', $data) ? $data['allowedStorageClasses'] : null, + allowedSyncModes: array_key_exists('allowedSyncModes', $data) ? $data['allowedSyncModes'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'minCpu' => static::serializeValue($this->minCpu), + 'maxCpu' => static::serializeValue($this->maxCpu), + 'minMemoryMb' => static::serializeValue($this->minMemoryMb), + 'maxMemoryMb' => static::serializeValue($this->maxMemoryMb), + 'minStorageGb' => static::serializeValue($this->minStorageGb), + 'maxStorageGb' => static::serializeValue($this->maxStorageGb), + 'maxReplicas' => static::serializeValue($this->maxReplicas), + 'maxConnections' => static::serializeValue($this->maxConnections), + 'maxIpAllowlistSize' => static::serializeValue($this->maxIpAllowlistSize), + 'maxExtensions' => static::serializeValue($this->maxExtensions), + 'maxBackupRetentionDays' => static::serializeValue($this->maxBackupRetentionDays), + 'maxPitrRetentionDays' => static::serializeValue($this->maxPitrRetentionDays), + 'maxSqlApiMaxRows' => static::serializeValue($this->maxSqlApiMaxRows), + 'maxSqlApiMaxBytes' => static::serializeValue($this->maxSqlApiMaxBytes), + 'maxSqlApiTimeoutSeconds' => static::serializeValue($this->maxSqlApiTimeoutSeconds), + 'maxSqlApiAllowedStatements' => static::serializeValue($this->maxSqlApiAllowedStatements), + 'allowedSqlStatements' => static::serializeValue($this->allowedSqlStatements), + 'allowedStorageClasses' => static::serializeValue($this->allowedStorageClasses), + 'allowedSyncModes' => static::serializeValue($this->allowedSyncModes) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/BillingPlanLimits.php b/src/Appwrite/Models/BillingPlanLimits.php new file mode 100644 index 00000000..2f8d9d86 --- /dev/null +++ b/src/Appwrite/Models/BillingPlanLimits.php @@ -0,0 +1,48 @@ + $data + */ + public static function from(array $data): static + { + + return new static( + credits: array_key_exists('credits', $data) ? $data['credits'] : null, + dailyCredits: array_key_exists('dailyCredits', $data) ? $data['dailyCredits'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'credits' => static::serializeValue($this->credits), + 'dailyCredits' => static::serializeValue($this->dailyCredits) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/BillingPlanSupportedAddons.php b/src/Appwrite/Models/BillingPlanSupportedAddons.php new file mode 100644 index 00000000..344ce998 --- /dev/null +++ b/src/Appwrite/Models/BillingPlanSupportedAddons.php @@ -0,0 +1,61 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('baa', $data)) { + throw new \InvalidArgumentException('Missing required field "baa" for ' . static::class . '.'); + } + if (!array_key_exists('premiumGeoDB', $data)) { + throw new \InvalidArgumentException('Missing required field "premiumGeoDB" for ' . static::class . '.'); + } + if (!array_key_exists('premiumGeoDBOrg', $data)) { + throw new \InvalidArgumentException('Missing required field "premiumGeoDBOrg" for ' . static::class . '.'); + } + + return new static( + baa: $data['baa'], + premiumGeoDB: $data['premiumGeoDB'], + premiumGeoDBOrg: $data['premiumGeoDBOrg'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'baa' => static::serializeValue($this->baa), + 'premiumGeoDB' => static::serializeValue($this->premiumGeoDB), + 'premiumGeoDBOrg' => static::serializeValue($this->premiumGeoDBOrg) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Block.php b/src/Appwrite/Models/Block.php index 350d0c12..4079f849 100644 --- a/src/Appwrite/Models/Block.php +++ b/src/Appwrite/Models/Block.php @@ -15,6 +15,7 @@ * @param string $createdAt block creation date in iso 8601 format. * @param string $resourceType resource type that is blocked * @param string $resourceId resource identifier that is blocked + * @param string $mode block mode. full blocks reads and writes; readonly blocks writes only. * @param string $projectName name of the project this block applies to. * @param string $region region of the project this block applies to. * @param string $organizationName name of the organization that owns the project. @@ -27,6 +28,7 @@ public function __construct( public string $createdAt, public string $resourceType, public string $resourceId, + public string $mode, public string $projectName, public string $region, public string $organizationName, @@ -51,6 +53,9 @@ public static function from(array $data): static if (!array_key_exists('resourceId', $data)) { throw new \InvalidArgumentException('Missing required field "resourceId" for ' . static::class . '.'); } + if (!array_key_exists('mode', $data)) { + throw new \InvalidArgumentException('Missing required field "mode" for ' . static::class . '.'); + } if (!array_key_exists('projectName', $data)) { throw new \InvalidArgumentException('Missing required field "projectName" for ' . static::class . '.'); } @@ -71,6 +76,7 @@ public static function from(array $data): static createdAt: $data['$createdAt'], resourceType: $data['resourceType'], resourceId: $data['resourceId'], + mode: $data['mode'], projectName: $data['projectName'], region: $data['region'], organizationName: $data['organizationName'], @@ -90,6 +96,7 @@ public function toArray(): array '$createdAt' => static::serializeValue($this->createdAt), 'resourceType' => static::serializeValue($this->resourceType), 'resourceId' => static::serializeValue($this->resourceId), + 'mode' => static::serializeValue($this->mode), 'reason' => static::serializeValue($this->reason), 'expiredAt' => static::serializeValue($this->expiredAt), 'projectName' => static::serializeValue($this->projectName), diff --git a/src/Appwrite/Models/Database.php b/src/Appwrite/Models/Database.php index fc06cde2..6a226440 100644 --- a/src/Appwrite/Models/Database.php +++ b/src/Appwrite/Models/Database.php @@ -3,6 +3,7 @@ namespace Appwrite\Models; use Appwrite\Enums\DatabaseType; +use Appwrite\Enums\DatabaseStatus; /** * Database @@ -22,6 +23,7 @@ * @param DatabaseType $type database type. * @param list $policies database backup policies. * @param list $archives database backup archives. + * @param DatabaseStatus|null $status database status. possible values: `provisioning`, `ready` or `failed` */ public function __construct( public string $id, @@ -31,7 +33,8 @@ public function __construct( public bool $enabled, public DatabaseType $type, public array $policies, - public array $archives + public array $archives, + public ?DatabaseStatus $status = null ) { } @@ -83,7 +86,8 @@ public static function from(array $data): static static fn (mixed $item): mixed => static::hydrateTypedValue(BackupArchive::class, $item), $data['archives'] ) - : $data['archives'] + : $data['archives'], + status: array_key_exists('status', $data) ? static::hydrateTypedValue(DatabaseStatus::class, $data['status'], true) : null ); } @@ -99,6 +103,7 @@ public function toArray(): array '$updatedAt' => static::serializeValue($this->updatedAt), 'enabled' => static::serializeValue($this->enabled), 'type' => static::serializeValue($this->type), + 'status' => static::serializeValue($this->status), 'policies' => static::serializeValue($this->policies), 'archives' => static::serializeValue($this->archives) ]; diff --git a/src/Appwrite/Models/HealthAntivirus.php b/src/Appwrite/Models/HealthAntivirus.php deleted file mode 100644 index 31a47bbd..00000000 --- a/src/Appwrite/Models/HealthAntivirus.php +++ /dev/null @@ -1,56 +0,0 @@ - $data - */ - public static function from(array $data): static - { - if (!array_key_exists('version', $data)) { - throw new \InvalidArgumentException('Missing required field "version" for ' . static::class . '.'); - } - if (!array_key_exists('status', $data)) { - throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); - } - - return new static( - version: $data['version'], - status: static::hydrateTypedValue(HealthAntivirusStatus::class, $data['status']) - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'version' => static::serializeValue($this->version), - 'status' => static::serializeValue($this->status) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/HealthCertificate.php b/src/Appwrite/Models/HealthCertificate.php deleted file mode 100644 index bad516ff..00000000 --- a/src/Appwrite/Models/HealthCertificate.php +++ /dev/null @@ -1,82 +0,0 @@ - $data - */ - public static function from(array $data): static - { - if (!array_key_exists('name', $data)) { - throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); - } - if (!array_key_exists('subjectSN', $data)) { - throw new \InvalidArgumentException('Missing required field "subjectSN" for ' . static::class . '.'); - } - if (!array_key_exists('issuerOrganisation', $data)) { - throw new \InvalidArgumentException('Missing required field "issuerOrganisation" for ' . static::class . '.'); - } - if (!array_key_exists('validFrom', $data)) { - throw new \InvalidArgumentException('Missing required field "validFrom" for ' . static::class . '.'); - } - if (!array_key_exists('validTo', $data)) { - throw new \InvalidArgumentException('Missing required field "validTo" for ' . static::class . '.'); - } - if (!array_key_exists('signatureTypeSN', $data)) { - throw new \InvalidArgumentException('Missing required field "signatureTypeSN" for ' . static::class . '.'); - } - - return new static( - name: $data['name'], - subjectSN: $data['subjectSN'], - issuerOrganisation: $data['issuerOrganisation'], - validFrom: $data['validFrom'], - validTo: $data['validTo'], - signatureTypeSN: $data['signatureTypeSN'] - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'name' => static::serializeValue($this->name), - 'subjectSN' => static::serializeValue($this->subjectSN), - 'issuerOrganisation' => static::serializeValue($this->issuerOrganisation), - 'validFrom' => static::serializeValue($this->validFrom), - 'validTo' => static::serializeValue($this->validTo), - 'signatureTypeSN' => static::serializeValue($this->signatureTypeSN) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/HealthQueue.php b/src/Appwrite/Models/HealthQueue.php deleted file mode 100644 index f709a229..00000000 --- a/src/Appwrite/Models/HealthQueue.php +++ /dev/null @@ -1,47 +0,0 @@ - $data - */ - public static function from(array $data): static - { - if (!array_key_exists('size', $data)) { - throw new \InvalidArgumentException('Missing required field "size" for ' . static::class . '.'); - } - - return new static( - size: $data['size'] - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'size' => static::serializeValue($this->size) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/HealthStatus.php b/src/Appwrite/Models/HealthStatus.php deleted file mode 100644 index 6238a2eb..00000000 --- a/src/Appwrite/Models/HealthStatus.php +++ /dev/null @@ -1,63 +0,0 @@ - $data - */ - public static function from(array $data): static - { - if (!array_key_exists('name', $data)) { - throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); - } - if (!array_key_exists('ping', $data)) { - throw new \InvalidArgumentException('Missing required field "ping" for ' . static::class . '.'); - } - if (!array_key_exists('status', $data)) { - throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); - } - - return new static( - name: $data['name'], - ping: $data['ping'], - status: static::hydrateTypedValue(HealthCheckStatus::class, $data['status']) - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'name' => static::serializeValue($this->name), - 'ping' => static::serializeValue($this->ping), - 'status' => static::serializeValue($this->status) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/HealthStatusList.php b/src/Appwrite/Models/HealthStatusList.php deleted file mode 100644 index 4b13218d..00000000 --- a/src/Appwrite/Models/HealthStatusList.php +++ /dev/null @@ -1,59 +0,0 @@ - $statuses list of statuses. - */ - public function __construct( - public int $total, - public array $statuses - ) { - } - - /** - * @param array $data - */ - public static function from(array $data): static - { - if (!array_key_exists('total', $data)) { - throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); - } - if (!array_key_exists('statuses', $data)) { - throw new \InvalidArgumentException('Missing required field "statuses" for ' . static::class . '.'); - } - - return new static( - total: $data['total'], - statuses: is_array($data['statuses']) - ? array_map( - static fn (mixed $item): mixed => static::hydrateTypedValue(HealthStatus::class, $item), - $data['statuses'] - ) - : $data['statuses'] - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'total' => static::serializeValue($this->total), - 'statuses' => static::serializeValue($this->statuses) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/HealthTime.php b/src/Appwrite/Models/HealthTime.php deleted file mode 100644 index c3036d1e..00000000 --- a/src/Appwrite/Models/HealthTime.php +++ /dev/null @@ -1,61 +0,0 @@ - $data - */ - public static function from(array $data): static - { - if (!array_key_exists('remoteTime', $data)) { - throw new \InvalidArgumentException('Missing required field "remoteTime" for ' . static::class . '.'); - } - if (!array_key_exists('localTime', $data)) { - throw new \InvalidArgumentException('Missing required field "localTime" for ' . static::class . '.'); - } - if (!array_key_exists('diff', $data)) { - throw new \InvalidArgumentException('Missing required field "diff" for ' . static::class . '.'); - } - - return new static( - remoteTime: $data['remoteTime'], - localTime: $data['localTime'], - diff: $data['diff'] - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'remoteTime' => static::serializeValue($this->remoteTime), - 'localTime' => static::serializeValue($this->localTime), - 'diff' => static::serializeValue($this->diff) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/Locale.php b/src/Appwrite/Models/Locale.php index 183919af..e7ab2726 100644 --- a/src/Appwrite/Models/Locale.php +++ b/src/Appwrite/Models/Locale.php @@ -19,6 +19,17 @@ * @param string $continent continent name. this field support localization. * @param bool $eu true if country is part of the european union. * @param string $currency currency code in [iso 4217-1](http://en.wikipedia.org/wiki/iso_4217) three-character format + * @param string|null $city city + * @param string|null $timeZone name of timezone + * @param string|null $postalCode postal code + * @param float|null $latitude latitude + * @param float|null $longitude longitude + * @param string|null $autonomousSystemNumber autonomous system number (asn) of the ip + * @param string|null $autonomousSystemOrganization organization that owns the asn + * @param string|null $isp internet service provider of the ip + * @param string|null $connectionType connection type of the ip (e.g. cable, cellular, corporate) + * @param string|null $connectionUsageType user type classification of the ip (e.g. residential, business, hosting) + * @param string|null $connectionOrganization registered organization of the ip */ public function __construct( public string $ip, @@ -27,7 +38,18 @@ public function __construct( public string $continentCode, public string $continent, public bool $eu, - public string $currency + public string $currency, + public ?string $city = null, + public ?string $timeZone = null, + public ?string $postalCode = null, + public ?float $latitude = null, + public ?float $longitude = null, + public ?string $autonomousSystemNumber = null, + public ?string $autonomousSystemOrganization = null, + public ?string $isp = null, + public ?string $connectionType = null, + public ?string $connectionUsageType = null, + public ?string $connectionOrganization = null ) { } @@ -65,7 +87,18 @@ public static function from(array $data): static continentCode: $data['continentCode'], continent: $data['continent'], eu: $data['eu'], - currency: $data['currency'] + currency: $data['currency'], + city: array_key_exists('city', $data) ? $data['city'] : null, + timeZone: array_key_exists('timeZone', $data) ? $data['timeZone'] : null, + postalCode: array_key_exists('postalCode', $data) ? $data['postalCode'] : null, + latitude: array_key_exists('latitude', $data) ? $data['latitude'] : null, + longitude: array_key_exists('longitude', $data) ? $data['longitude'] : null, + autonomousSystemNumber: array_key_exists('autonomousSystemNumber', $data) ? $data['autonomousSystemNumber'] : null, + autonomousSystemOrganization: array_key_exists('autonomousSystemOrganization', $data) ? $data['autonomousSystemOrganization'] : null, + isp: array_key_exists('isp', $data) ? $data['isp'] : null, + connectionType: array_key_exists('connectionType', $data) ? $data['connectionType'] : null, + connectionUsageType: array_key_exists('connectionUsageType', $data) ? $data['connectionUsageType'] : null, + connectionOrganization: array_key_exists('connectionOrganization', $data) ? $data['connectionOrganization'] : null ); } @@ -81,7 +114,18 @@ public function toArray(): array 'continentCode' => static::serializeValue($this->continentCode), 'continent' => static::serializeValue($this->continent), 'eu' => static::serializeValue($this->eu), - 'currency' => static::serializeValue($this->currency) + 'currency' => static::serializeValue($this->currency), + 'city' => static::serializeValue($this->city), + 'timeZone' => static::serializeValue($this->timeZone), + 'postalCode' => static::serializeValue($this->postalCode), + 'latitude' => static::serializeValue($this->latitude), + 'longitude' => static::serializeValue($this->longitude), + 'autonomousSystemNumber' => static::serializeValue($this->autonomousSystemNumber), + 'autonomousSystemOrganization' => static::serializeValue($this->autonomousSystemOrganization), + 'isp' => static::serializeValue($this->isp), + 'connectionType' => static::serializeValue($this->connectionType), + 'connectionUsageType' => static::serializeValue($this->connectionUsageType), + 'connectionOrganization' => static::serializeValue($this->connectionOrganization) ]; return $result; diff --git a/src/Appwrite/Models/Log.php b/src/Appwrite/Models/Log.php index f3f74cee..8cb811db 100644 --- a/src/Appwrite/Models/Log.php +++ b/src/Appwrite/Models/Log.php @@ -17,7 +17,7 @@ * @param string $userEmail user email of the actor recorded for this log. during impersonation, this is the original impersonator. * @param string $userName user name of the actor recorded for this log. during impersonation, this is the original impersonator. * @param string $mode api mode when event triggered. - * @param string $userType user type who triggered the audit log. possible values: user, admin, guest, keyproject, keyaccount, keyorganization. + * @param string $userType user type who triggered the audit log. possible values: user, admin, guest, hidden, keyproject, keyaccount, keyorganization. * @param string $ip ip session in use when the session was created. * @param string $time log creation date in iso 8601 format. * @param string $osCode operating system code name. view list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/os.json). diff --git a/src/Appwrite/Models/OAuth2Appwrite.php b/src/Appwrite/Models/OAuth2Appwrite.php new file mode 100644 index 00000000..1ae1b35a --- /dev/null +++ b/src/Appwrite/Models/OAuth2Appwrite.php @@ -0,0 +1,68 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('enabled', $data)) { + throw new \InvalidArgumentException('Missing required field "enabled" for ' . static::class . '.'); + } + if (!array_key_exists('clientId', $data)) { + throw new \InvalidArgumentException('Missing required field "clientId" for ' . static::class . '.'); + } + if (!array_key_exists('clientSecret', $data)) { + throw new \InvalidArgumentException('Missing required field "clientSecret" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + enabled: $data['enabled'], + clientId: $data['clientId'], + clientSecret: $data['clientSecret'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + 'enabled' => static::serializeValue($this->enabled), + 'clientId' => static::serializeValue($this->clientId), + 'clientSecret' => static::serializeValue($this->clientSecret) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/OAuth2Oidc.php b/src/Appwrite/Models/OAuth2Oidc.php index 7fd780e9..26a21ce1 100644 --- a/src/Appwrite/Models/OAuth2Oidc.php +++ b/src/Appwrite/Models/OAuth2Oidc.php @@ -2,6 +2,8 @@ namespace Appwrite\Models; +use Appwrite\Enums\OAuth2OidcPrompt; + /** * OAuth2Oidc */ @@ -20,6 +22,8 @@ * @param string $authorizationURL openid connect authorization endpoint url. * @param string $tokenURL openid connect token endpoint url. * @param string $userInfoURL openid connect user info endpoint url. + * @param list $prompt openid connect prompt values controlling the authentication and consent screens. + * @param int|null $maxAge maximum authentication age in seconds. when set, the user must have authenticated within this many seconds. */ public function __construct( public string $id, @@ -29,7 +33,9 @@ public function __construct( public string $wellKnownURL, public string $authorizationURL, public string $tokenURL, - public string $userInfoURL + public string $userInfoURL, + public array $prompt, + public ?int $maxAge = null ) { } @@ -62,6 +68,9 @@ public static function from(array $data): static if (!array_key_exists('userInfoURL', $data)) { throw new \InvalidArgumentException('Missing required field "userInfoURL" for ' . static::class . '.'); } + if (!array_key_exists('prompt', $data)) { + throw new \InvalidArgumentException('Missing required field "prompt" for ' . static::class . '.'); + } return new static( id: $data['$id'], @@ -71,7 +80,14 @@ public static function from(array $data): static wellKnownURL: $data['wellKnownURL'], authorizationURL: $data['authorizationURL'], tokenURL: $data['tokenURL'], - userInfoURL: $data['userInfoURL'] + userInfoURL: $data['userInfoURL'], + prompt: is_array($data['prompt']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(OAuth2OidcPrompt::class, $item), + $data['prompt'] + ) + : $data['prompt'], + maxAge: array_key_exists('maxAge', $data) ? $data['maxAge'] : null ); } @@ -88,7 +104,9 @@ public function toArray(): array 'wellKnownURL' => static::serializeValue($this->wellKnownURL), 'authorizationURL' => static::serializeValue($this->authorizationURL), 'tokenURL' => static::serializeValue($this->tokenURL), - 'userInfoURL' => static::serializeValue($this->userInfoURL) + 'userInfoURL' => static::serializeValue($this->userInfoURL), + 'prompt' => static::serializeValue($this->prompt), + 'maxAge' => static::serializeValue($this->maxAge) ]; return $result; diff --git a/src/Appwrite/Models/Organization.php b/src/Appwrite/Models/Organization.php new file mode 100644 index 00000000..8842b34f --- /dev/null +++ b/src/Appwrite/Models/Organization.php @@ -0,0 +1,282 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); + } + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('prefs', $data)) { + throw new \InvalidArgumentException('Missing required field "prefs" for ' . static::class . '.'); + } + if (!array_key_exists('billingBudget', $data)) { + throw new \InvalidArgumentException('Missing required field "billingBudget" for ' . static::class . '.'); + } + if (!array_key_exists('budgetAlerts', $data)) { + throw new \InvalidArgumentException('Missing required field "budgetAlerts" for ' . static::class . '.'); + } + if (!array_key_exists('billingPlan', $data)) { + throw new \InvalidArgumentException('Missing required field "billingPlan" for ' . static::class . '.'); + } + if (!array_key_exists('billingPlanId', $data)) { + throw new \InvalidArgumentException('Missing required field "billingPlanId" for ' . static::class . '.'); + } + if (!array_key_exists('billingPlanDetails', $data)) { + throw new \InvalidArgumentException('Missing required field "billingPlanDetails" for ' . static::class . '.'); + } + if (!array_key_exists('billingEmail', $data)) { + throw new \InvalidArgumentException('Missing required field "billingEmail" for ' . static::class . '.'); + } + if (!array_key_exists('billingStartDate', $data)) { + throw new \InvalidArgumentException('Missing required field "billingStartDate" for ' . static::class . '.'); + } + if (!array_key_exists('billingCurrentInvoiceDate', $data)) { + throw new \InvalidArgumentException('Missing required field "billingCurrentInvoiceDate" for ' . static::class . '.'); + } + if (!array_key_exists('billingNextInvoiceDate', $data)) { + throw new \InvalidArgumentException('Missing required field "billingNextInvoiceDate" for ' . static::class . '.'); + } + if (!array_key_exists('billingTrialStartDate', $data)) { + throw new \InvalidArgumentException('Missing required field "billingTrialStartDate" for ' . static::class . '.'); + } + if (!array_key_exists('billingTrialDays', $data)) { + throw new \InvalidArgumentException('Missing required field "billingTrialDays" for ' . static::class . '.'); + } + if (!array_key_exists('billingAggregationId', $data)) { + throw new \InvalidArgumentException('Missing required field "billingAggregationId" for ' . static::class . '.'); + } + if (!array_key_exists('billingInvoiceId', $data)) { + throw new \InvalidArgumentException('Missing required field "billingInvoiceId" for ' . static::class . '.'); + } + if (!array_key_exists('paymentMethodId', $data)) { + throw new \InvalidArgumentException('Missing required field "paymentMethodId" for ' . static::class . '.'); + } + if (!array_key_exists('billingAddressId', $data)) { + throw new \InvalidArgumentException('Missing required field "billingAddressId" for ' . static::class . '.'); + } + if (!array_key_exists('backupPaymentMethodId', $data)) { + throw new \InvalidArgumentException('Missing required field "backupPaymentMethodId" for ' . static::class . '.'); + } + if (!array_key_exists('status', $data)) { + throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); + } + if (!array_key_exists('remarks', $data)) { + throw new \InvalidArgumentException('Missing required field "remarks" for ' . static::class . '.'); + } + if (!array_key_exists('agreementBAA', $data)) { + throw new \InvalidArgumentException('Missing required field "agreementBAA" for ' . static::class . '.'); + } + if (!array_key_exists('programManagerName', $data)) { + throw new \InvalidArgumentException('Missing required field "programManagerName" for ' . static::class . '.'); + } + if (!array_key_exists('programManagerCalendar', $data)) { + throw new \InvalidArgumentException('Missing required field "programManagerCalendar" for ' . static::class . '.'); + } + if (!array_key_exists('programDiscordChannelName', $data)) { + throw new \InvalidArgumentException('Missing required field "programDiscordChannelName" for ' . static::class . '.'); + } + if (!array_key_exists('programDiscordChannelUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "programDiscordChannelUrl" for ' . static::class . '.'); + } + if (!array_key_exists('billingPlanDowngrade', $data)) { + throw new \InvalidArgumentException('Missing required field "billingPlanDowngrade" for ' . static::class . '.'); + } + if (!array_key_exists('billingTaxId', $data)) { + throw new \InvalidArgumentException('Missing required field "billingTaxId" for ' . static::class . '.'); + } + if (!array_key_exists('markedForDeletion', $data)) { + throw new \InvalidArgumentException('Missing required field "markedForDeletion" for ' . static::class . '.'); + } + if (!array_key_exists('platform', $data)) { + throw new \InvalidArgumentException('Missing required field "platform" for ' . static::class . '.'); + } + if (!array_key_exists('projects', $data)) { + throw new \InvalidArgumentException('Missing required field "projects" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + name: $data['name'], + total: $data['total'], + prefs: static::hydrateTypedValue(Preferences::class, $data['prefs']), + billingBudget: $data['billingBudget'], + budgetAlerts: $data['budgetAlerts'], + billingPlan: $data['billingPlan'], + billingPlanId: $data['billingPlanId'], + billingPlanDetails: static::hydrateTypedValue(BillingPlan::class, $data['billingPlanDetails']), + billingEmail: $data['billingEmail'], + billingStartDate: $data['billingStartDate'], + billingCurrentInvoiceDate: $data['billingCurrentInvoiceDate'], + billingNextInvoiceDate: $data['billingNextInvoiceDate'], + billingTrialStartDate: $data['billingTrialStartDate'], + billingTrialDays: $data['billingTrialDays'], + billingAggregationId: $data['billingAggregationId'], + billingInvoiceId: $data['billingInvoiceId'], + paymentMethodId: $data['paymentMethodId'], + billingAddressId: $data['billingAddressId'], + backupPaymentMethodId: $data['backupPaymentMethodId'], + status: $data['status'], + remarks: $data['remarks'], + agreementBAA: $data['agreementBAA'], + programManagerName: $data['programManagerName'], + programManagerCalendar: $data['programManagerCalendar'], + programDiscordChannelName: $data['programDiscordChannelName'], + programDiscordChannelUrl: $data['programDiscordChannelUrl'], + billingPlanDowngrade: $data['billingPlanDowngrade'], + billingTaxId: $data['billingTaxId'], + markedForDeletion: $data['markedForDeletion'], + platform: $data['platform'], + projects: $data['projects'], + billingLimits: array_key_exists('billingLimits', $data) ? static::hydrateTypedValue(BillingLimits::class, $data['billingLimits'], true) : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'name' => static::serializeValue($this->name), + 'total' => static::serializeValue($this->total), + 'prefs' => static::serializeValue($this->prefs), + 'billingBudget' => static::serializeValue($this->billingBudget), + 'budgetAlerts' => static::serializeValue($this->budgetAlerts), + 'billingPlan' => static::serializeValue($this->billingPlan), + 'billingPlanId' => static::serializeValue($this->billingPlanId), + 'billingPlanDetails' => static::serializeValue($this->billingPlanDetails), + 'billingEmail' => static::serializeValue($this->billingEmail), + 'billingStartDate' => static::serializeValue($this->billingStartDate), + 'billingCurrentInvoiceDate' => static::serializeValue($this->billingCurrentInvoiceDate), + 'billingNextInvoiceDate' => static::serializeValue($this->billingNextInvoiceDate), + 'billingTrialStartDate' => static::serializeValue($this->billingTrialStartDate), + 'billingTrialDays' => static::serializeValue($this->billingTrialDays), + 'billingAggregationId' => static::serializeValue($this->billingAggregationId), + 'billingInvoiceId' => static::serializeValue($this->billingInvoiceId), + 'paymentMethodId' => static::serializeValue($this->paymentMethodId), + 'billingAddressId' => static::serializeValue($this->billingAddressId), + 'backupPaymentMethodId' => static::serializeValue($this->backupPaymentMethodId), + 'status' => static::serializeValue($this->status), + 'remarks' => static::serializeValue($this->remarks), + 'agreementBAA' => static::serializeValue($this->agreementBAA), + 'programManagerName' => static::serializeValue($this->programManagerName), + 'programManagerCalendar' => static::serializeValue($this->programManagerCalendar), + 'programDiscordChannelName' => static::serializeValue($this->programDiscordChannelName), + 'programDiscordChannelUrl' => static::serializeValue($this->programDiscordChannelUrl), + 'billingLimits' => static::serializeValue($this->billingLimits), + 'billingPlanDowngrade' => static::serializeValue($this->billingPlanDowngrade), + 'billingTaxId' => static::serializeValue($this->billingTaxId), + 'markedForDeletion' => static::serializeValue($this->markedForDeletion), + 'platform' => static::serializeValue($this->platform), + 'projects' => static::serializeValue($this->projects) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Program.php b/src/Appwrite/Models/Program.php new file mode 100644 index 00000000..a6bdcd53 --- /dev/null +++ b/src/Appwrite/Models/Program.php @@ -0,0 +1,103 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('title', $data)) { + throw new \InvalidArgumentException('Missing required field "title" for ' . static::class . '.'); + } + if (!array_key_exists('description', $data)) { + throw new \InvalidArgumentException('Missing required field "description" for ' . static::class . '.'); + } + if (!array_key_exists('tag', $data)) { + throw new \InvalidArgumentException('Missing required field "tag" for ' . static::class . '.'); + } + if (!array_key_exists('icon', $data)) { + throw new \InvalidArgumentException('Missing required field "icon" for ' . static::class . '.'); + } + if (!array_key_exists('url', $data)) { + throw new \InvalidArgumentException('Missing required field "url" for ' . static::class . '.'); + } + if (!array_key_exists('active', $data)) { + throw new \InvalidArgumentException('Missing required field "active" for ' . static::class . '.'); + } + if (!array_key_exists('external', $data)) { + throw new \InvalidArgumentException('Missing required field "external" for ' . static::class . '.'); + } + if (!array_key_exists('billingPlanId', $data)) { + throw new \InvalidArgumentException('Missing required field "billingPlanId" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + title: $data['title'], + description: $data['description'], + tag: $data['tag'], + icon: $data['icon'], + url: $data['url'], + active: $data['active'], + external: $data['external'], + billingPlanId: $data['billingPlanId'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + 'title' => static::serializeValue($this->title), + 'description' => static::serializeValue($this->description), + 'tag' => static::serializeValue($this->tag), + 'icon' => static::serializeValue($this->icon), + 'url' => static::serializeValue($this->url), + 'active' => static::serializeValue($this->active), + 'external' => static::serializeValue($this->external), + 'billingPlanId' => static::serializeValue($this->billingPlanId) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Project.php b/src/Appwrite/Models/Project.php index 700b7f6e..f2af24d4 100644 --- a/src/Appwrite/Models/Project.php +++ b/src/Appwrite/Models/Project.php @@ -33,6 +33,7 @@ * @param string $pingedAt last ping datetime in iso 8601 format. * @param array $labels labels for the project. * @param string $status project status + * @param array $onboarding stage progress (completed or skipped) with timestamps and actor types, keyed by stage id. * @param list $authMethods list of auth methods. * @param list $services list of services. * @param list $protocols list of protocols. @@ -42,6 +43,7 @@ * @param bool|null $oAuth2ServerEnabled oauth2 server status * @param string|null $oAuth2ServerAuthorizationUrl oauth2 server authorization url * @param array|null $oAuth2ServerScopes oauth2 server allowed scopes + * @param array|null $oAuth2ServerDefaultScopes oauth2 server scopes used when an authorization request omits the scope parameter * @param array|null $oAuth2ServerAuthorizationDetailsTypes oauth2 server accepted rfc 9396 authorization_details types * @param int|null $oAuth2ServerAccessTokenDuration oauth2 server access token duration in seconds for confidential clients * @param int|null $oAuth2ServerRefreshTokenDuration oauth2 server refresh token duration in seconds for confidential clients @@ -76,6 +78,7 @@ public function __construct( public string $pingedAt, public array $labels, public string $status, + public array $onboarding, public array $authMethods, public array $services, public array $protocols, @@ -85,6 +88,7 @@ public function __construct( public ?bool $oAuth2ServerEnabled = null, public ?string $oAuth2ServerAuthorizationUrl = null, public ?array $oAuth2ServerScopes = null, + public ?array $oAuth2ServerDefaultScopes = null, public ?array $oAuth2ServerAuthorizationDetailsTypes = null, public ?int $oAuth2ServerAccessTokenDuration = null, public ?int $oAuth2ServerRefreshTokenDuration = null, @@ -167,6 +171,9 @@ public static function from(array $data): static if (!array_key_exists('status', $data)) { throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); } + if (!array_key_exists('onboarding', $data)) { + throw new \InvalidArgumentException('Missing required field "onboarding" for ' . static::class . '.'); + } if (!array_key_exists('authMethods', $data)) { throw new \InvalidArgumentException('Missing required field "authMethods" for ' . static::class . '.'); } @@ -210,6 +217,7 @@ public static function from(array $data): static pingedAt: $data['pingedAt'], labels: $data['labels'], status: $data['status'], + onboarding: $data['onboarding'], authMethods: is_array($data['authMethods']) ? array_map( static fn (mixed $item): mixed => static::hydrateTypedValue(ProjectAuthMethod::class, $item), @@ -239,6 +247,7 @@ public static function from(array $data): static oAuth2ServerEnabled: array_key_exists('oAuth2ServerEnabled', $data) ? $data['oAuth2ServerEnabled'] : null, oAuth2ServerAuthorizationUrl: array_key_exists('oAuth2ServerAuthorizationUrl', $data) ? $data['oAuth2ServerAuthorizationUrl'] : null, oAuth2ServerScopes: array_key_exists('oAuth2ServerScopes', $data) ? $data['oAuth2ServerScopes'] : null, + oAuth2ServerDefaultScopes: array_key_exists('oAuth2ServerDefaultScopes', $data) ? $data['oAuth2ServerDefaultScopes'] : null, oAuth2ServerAuthorizationDetailsTypes: array_key_exists('oAuth2ServerAuthorizationDetailsTypes', $data) ? $data['oAuth2ServerAuthorizationDetailsTypes'] : null, oAuth2ServerAccessTokenDuration: array_key_exists('oAuth2ServerAccessTokenDuration', $data) ? $data['oAuth2ServerAccessTokenDuration'] : null, oAuth2ServerRefreshTokenDuration: array_key_exists('oAuth2ServerRefreshTokenDuration', $data) ? $data['oAuth2ServerRefreshTokenDuration'] : null, @@ -280,6 +289,7 @@ public function toArray(): array 'pingedAt' => static::serializeValue($this->pingedAt), 'labels' => static::serializeValue($this->labels), 'status' => static::serializeValue($this->status), + 'onboarding' => static::serializeValue($this->onboarding), 'authMethods' => static::serializeValue($this->authMethods), 'services' => static::serializeValue($this->services), 'protocols' => static::serializeValue($this->protocols), @@ -289,6 +299,7 @@ public function toArray(): array 'oAuth2ServerEnabled' => static::serializeValue($this->oAuth2ServerEnabled), 'oAuth2ServerAuthorizationUrl' => static::serializeValue($this->oAuth2ServerAuthorizationUrl), 'oAuth2ServerScopes' => static::serializeValue($this->oAuth2ServerScopes), + 'oAuth2ServerDefaultScopes' => static::serializeValue($this->oAuth2ServerDefaultScopes), 'oAuth2ServerAuthorizationDetailsTypes' => static::serializeValue($this->oAuth2ServerAuthorizationDetailsTypes), 'oAuth2ServerAccessTokenDuration' => static::serializeValue($this->oAuth2ServerAccessTokenDuration), 'oAuth2ServerRefreshTokenDuration' => static::serializeValue($this->oAuth2ServerRefreshTokenDuration), diff --git a/src/Appwrite/Models/UsageBillingPlan.php b/src/Appwrite/Models/UsageBillingPlan.php new file mode 100644 index 00000000..790e95f0 --- /dev/null +++ b/src/Appwrite/Models/UsageBillingPlan.php @@ -0,0 +1,117 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('bandwidth', $data)) { + throw new \InvalidArgumentException('Missing required field "bandwidth" for ' . static::class . '.'); + } + if (!array_key_exists('executions', $data)) { + throw new \InvalidArgumentException('Missing required field "executions" for ' . static::class . '.'); + } + if (!array_key_exists('member', $data)) { + throw new \InvalidArgumentException('Missing required field "member" for ' . static::class . '.'); + } + if (!array_key_exists('realtime', $data)) { + throw new \InvalidArgumentException('Missing required field "realtime" for ' . static::class . '.'); + } + if (!array_key_exists('realtimeMessages', $data)) { + throw new \InvalidArgumentException('Missing required field "realtimeMessages" for ' . static::class . '.'); + } + if (!array_key_exists('realtimeBandwidth', $data)) { + throw new \InvalidArgumentException('Missing required field "realtimeBandwidth" for ' . static::class . '.'); + } + if (!array_key_exists('storage', $data)) { + throw new \InvalidArgumentException('Missing required field "storage" for ' . static::class . '.'); + } + if (!array_key_exists('users', $data)) { + throw new \InvalidArgumentException('Missing required field "users" for ' . static::class . '.'); + } + if (!array_key_exists('GBHours', $data)) { + throw new \InvalidArgumentException('Missing required field "GBHours" for ' . static::class . '.'); + } + if (!array_key_exists('imageTransformations', $data)) { + throw new \InvalidArgumentException('Missing required field "imageTransformations" for ' . static::class . '.'); + } + if (!array_key_exists('credits', $data)) { + throw new \InvalidArgumentException('Missing required field "credits" for ' . static::class . '.'); + } + + return new static( + bandwidth: static::hydrateTypedValue(AdditionalResource::class, $data['bandwidth']), + executions: static::hydrateTypedValue(AdditionalResource::class, $data['executions']), + member: static::hydrateTypedValue(AdditionalResource::class, $data['member']), + realtime: static::hydrateTypedValue(AdditionalResource::class, $data['realtime']), + realtimeMessages: static::hydrateTypedValue(AdditionalResource::class, $data['realtimeMessages']), + realtimeBandwidth: static::hydrateTypedValue(AdditionalResource::class, $data['realtimeBandwidth']), + storage: static::hydrateTypedValue(AdditionalResource::class, $data['storage']), + users: static::hydrateTypedValue(AdditionalResource::class, $data['users']), + gBHours: static::hydrateTypedValue(AdditionalResource::class, $data['GBHours']), + imageTransformations: static::hydrateTypedValue(AdditionalResource::class, $data['imageTransformations']), + credits: static::hydrateTypedValue(AdditionalResource::class, $data['credits']) + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'bandwidth' => static::serializeValue($this->bandwidth), + 'executions' => static::serializeValue($this->executions), + 'member' => static::serializeValue($this->member), + 'realtime' => static::serializeValue($this->realtime), + 'realtimeMessages' => static::serializeValue($this->realtimeMessages), + 'realtimeBandwidth' => static::serializeValue($this->realtimeBandwidth), + 'storage' => static::serializeValue($this->storage), + 'users' => static::serializeValue($this->users), + 'GBHours' => static::serializeValue($this->gBHours), + 'imageTransformations' => static::serializeValue($this->imageTransformations), + 'credits' => static::serializeValue($this->credits) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/UsageEventList.php b/src/Appwrite/Models/UsageEventList.php deleted file mode 100644 index c6fda5bd..00000000 --- a/src/Appwrite/Models/UsageEventList.php +++ /dev/null @@ -1,66 +0,0 @@ - $groups aggregated groups ordered by time ascending. - */ - public function __construct( - public string $metric, - public string $interval, - public array $groups - ) { - } - - /** - * @param array $data - */ - public static function from(array $data): static - { - if (!array_key_exists('metric', $data)) { - throw new \InvalidArgumentException('Missing required field "metric" for ' . static::class . '.'); - } - if (!array_key_exists('interval', $data)) { - throw new \InvalidArgumentException('Missing required field "interval" for ' . static::class . '.'); - } - if (!array_key_exists('groups', $data)) { - throw new \InvalidArgumentException('Missing required field "groups" for ' . static::class . '.'); - } - - return new static( - metric: $data['metric'], - interval: $data['interval'], - groups: is_array($data['groups']) - ? array_map( - static fn (mixed $item): mixed => static::hydrateTypedValue(UsageGroup::class, $item), - $data['groups'] - ) - : $data['groups'] - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'metric' => static::serializeValue($this->metric), - 'interval' => static::serializeValue($this->interval), - 'groups' => static::serializeValue($this->groups) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/UsageGaugeList.php b/src/Appwrite/Models/UsageGaugeList.php deleted file mode 100644 index d644dad6..00000000 --- a/src/Appwrite/Models/UsageGaugeList.php +++ /dev/null @@ -1,66 +0,0 @@ - $groups aggregated groups ordered by time ascending. each group carries the latest snapshot in its interval (argmax over time). - */ - public function __construct( - public string $metric, - public string $interval, - public array $groups - ) { - } - - /** - * @param array $data - */ - public static function from(array $data): static - { - if (!array_key_exists('metric', $data)) { - throw new \InvalidArgumentException('Missing required field "metric" for ' . static::class . '.'); - } - if (!array_key_exists('interval', $data)) { - throw new \InvalidArgumentException('Missing required field "interval" for ' . static::class . '.'); - } - if (!array_key_exists('groups', $data)) { - throw new \InvalidArgumentException('Missing required field "groups" for ' . static::class . '.'); - } - - return new static( - metric: $data['metric'], - interval: $data['interval'], - groups: is_array($data['groups']) - ? array_map( - static fn (mixed $item): mixed => static::hydrateTypedValue(UsageGroup::class, $item), - $data['groups'] - ) - : $data['groups'] - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'metric' => static::serializeValue($this->metric), - 'interval' => static::serializeValue($this->interval), - 'groups' => static::serializeValue($this->groups) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/UsageGroup.php b/src/Appwrite/Models/UsageGroup.php deleted file mode 100644 index 8518023c..00000000 --- a/src/Appwrite/Models/UsageGroup.php +++ /dev/null @@ -1,106 +0,0 @@ - $data - */ - public static function from(array $data): static - { - if (!array_key_exists('time', $data)) { - throw new \InvalidArgumentException('Missing required field "time" for ' . static::class . '.'); - } - if (!array_key_exists('value', $data)) { - throw new \InvalidArgumentException('Missing required field "value" for ' . static::class . '.'); - } - - return new static( - time: $data['time'], - value: $data['value'], - path: array_key_exists('path', $data) ? $data['path'] : null, - method: array_key_exists('method', $data) ? $data['method'] : null, - status: array_key_exists('status', $data) ? $data['status'] : null, - service: array_key_exists('service', $data) ? $data['service'] : null, - country: array_key_exists('country', $data) ? $data['country'] : null, - region: array_key_exists('region', $data) ? $data['region'] : null, - hostname: array_key_exists('hostname', $data) ? $data['hostname'] : null, - osName: array_key_exists('osName', $data) ? $data['osName'] : null, - clientType: array_key_exists('clientType', $data) ? $data['clientType'] : null, - clientName: array_key_exists('clientName', $data) ? $data['clientName'] : null, - deviceName: array_key_exists('deviceName', $data) ? $data['deviceName'] : null, - teamId: array_key_exists('teamId', $data) ? $data['teamId'] : null, - resourceId: array_key_exists('resourceId', $data) ? $data['resourceId'] : null - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'time' => static::serializeValue($this->time), - 'value' => static::serializeValue($this->value), - 'path' => static::serializeValue($this->path), - 'method' => static::serializeValue($this->method), - 'status' => static::serializeValue($this->status), - 'service' => static::serializeValue($this->service), - 'country' => static::serializeValue($this->country), - 'region' => static::serializeValue($this->region), - 'hostname' => static::serializeValue($this->hostname), - 'osName' => static::serializeValue($this->osName), - 'clientType' => static::serializeValue($this->clientType), - 'clientName' => static::serializeValue($this->clientName), - 'deviceName' => static::serializeValue($this->deviceName), - 'teamId' => static::serializeValue($this->teamId), - 'resourceId' => static::serializeValue($this->resourceId) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Query.php b/src/Appwrite/Query.php index a4238640..da0abffa 100644 --- a/src/Appwrite/Query.php +++ b/src/Appwrite/Query.php @@ -573,6 +573,42 @@ public static function distanceLessThan(string $attribute, array $values, int|fl return (new Query('distanceLessThan', $attribute, [[$values, $distance, $meters]]))->__toString(); } + /** + * Vector Dot + * + * @param string $attribute + * @param array $vector + * @return string + */ + public static function vectorDot(string $attribute, array $vector): string + { + return (new Query('vectorDot', $attribute, [$vector]))->__toString(); + } + + /** + * Vector Cosine + * + * @param string $attribute + * @param array $vector + * @return string + */ + public static function vectorCosine(string $attribute, array $vector): string + { + return (new Query('vectorCosine', $attribute, [$vector]))->__toString(); + } + + /** + * Vector Euclidean + * + * @param string $attribute + * @param array $vector + * @return string + */ + public static function vectorEuclidean(string $attribute, array $vector): string + { + return (new Query('vectorEuclidean', $attribute, [$vector]))->__toString(); + } + /** * Intersects * diff --git a/src/Appwrite/Services/Backups.php b/src/Appwrite/Services/Backups.php index d490f2a3..c6cc9542 100644 --- a/src/Appwrite/Services/Backups.php +++ b/src/Appwrite/Services/Backups.php @@ -384,15 +384,26 @@ public function deletePolicy(string $policyId): string /** * Create and trigger a new restoration for a backup on a project. + * + * When restoring a DocumentsDB or VectorsDB database to a new resource, pass + * `newSpecification` to provision the restored database on a different + * specification than the archived one (for example, restoring onto a larger + * or smaller dedicated database). Use `serverless` to restore onto the shared + * pool, or a dedicated specification slug to restore onto a dedicated + * database of that size. The specification must be permitted by the + * organization's plan. `newSpecification` is not supported for + * legacy/TablesDB databases or for bucket restores. + * * * @param string $archiveId * @param array $services * @param ?string $newResourceId * @param ?string $newResourceName + * @param ?string $newSpecification * @throws AppwriteException * @return \Appwrite\Models\BackupRestoration */ - public function createRestoration(string $archiveId, array $services, ?string $newResourceId = null, ?string $newResourceName = null): \Appwrite\Models\BackupRestoration + public function createRestoration(string $archiveId, array $services, ?string $newResourceId = null, ?string $newResourceName = null, ?string $newSpecification = null): \Appwrite\Models\BackupRestoration { $apiPath = str_replace( [], @@ -412,6 +423,10 @@ public function createRestoration(string $archiveId, array $services, ?string $n $apiParams['newResourceName'] = $newResourceName; } + if (!is_null($newSpecification)) { + $apiParams['newSpecification'] = $newSpecification; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; diff --git a/src/Appwrite/Services/Databases.php b/src/Appwrite/Services/Databases.php index a9e1e766..8c7d3a33 100644 --- a/src/Appwrite/Services/Databases.php +++ b/src/Appwrite/Services/Databases.php @@ -127,6 +127,9 @@ public function create(string $databaseId, string $name, ?bool $enabled = null): * @param ?array $queries * @throws AppwriteException * @return \Appwrite\Models\TransactionList + * + * @deprecated This API has been deprecated since 1.8.0. Please use `listTransactions` instead. + * @see TablesDB::listTransactions */ public function listTransactions(?array $queries = null): \Appwrite\Models\TransactionList { @@ -167,6 +170,9 @@ public function listTransactions(?array $queries = null): \Appwrite\Models\Trans * @param ?int $ttl * @throws AppwriteException * @return \Appwrite\Models\Transaction + * + * @deprecated This API has been deprecated since 1.8.0. Please use `createTransaction` instead. + * @see TablesDB::createTransaction */ public function createTransaction(?int $ttl = null): \Appwrite\Models\Transaction { @@ -208,6 +214,9 @@ public function createTransaction(?int $ttl = null): \Appwrite\Models\Transactio * @param string $transactionId * @throws AppwriteException * @return \Appwrite\Models\Transaction + * + * @deprecated This API has been deprecated since 1.8.0. Please use `getTransaction` instead. + * @see TablesDB::getTransaction */ public function getTransaction(string $transactionId): \Appwrite\Models\Transaction { @@ -247,6 +256,9 @@ public function getTransaction(string $transactionId): \Appwrite\Models\Transact * @param ?bool $rollback * @throws AppwriteException * @return \Appwrite\Models\Transaction + * + * @deprecated This API has been deprecated since 1.8.0. Please use `updateTransaction` instead. + * @see TablesDB::updateTransaction */ public function updateTransaction(string $transactionId, ?bool $commit = null, ?bool $rollback = null): \Appwrite\Models\Transaction { @@ -293,6 +305,9 @@ public function updateTransaction(string $transactionId, ?bool $commit = null, ? * @param string $transactionId * @throws AppwriteException * @return string + * + * @deprecated This API has been deprecated since 1.8.0. Please use `deleteTransaction` instead. + * @see TablesDB::deleteTransaction */ public function deleteTransaction(string $transactionId): string { @@ -327,6 +342,9 @@ public function deleteTransaction(string $transactionId): string * @param ?array $operations * @throws AppwriteException * @return \Appwrite\Models\Transaction + * + * @deprecated This API has been deprecated since 1.8.0. Please use `createOperations` instead. + * @see TablesDB::createOperations */ public function createOperations(string $transactionId, ?array $operations = null): \Appwrite\Models\Transaction { @@ -1824,6 +1842,9 @@ public function updateLineAttribute(string $databaseId, string $collectionId, st * @param ?bool $encrypt * @throws AppwriteException * @return \Appwrite\Models\AttributeLongtext + * + * @deprecated This API has been deprecated since 1.8.0. Please use `createLongtextColumn` instead. + * @see TablesDB::createLongtextColumn */ public function createLongtextAttribute(string $databaseId, string $collectionId, string $key, bool $required, ?string $xdefault = null, ?bool $xarray = null, ?bool $encrypt = null): \Appwrite\Models\AttributeLongtext { @@ -1881,6 +1902,9 @@ public function createLongtextAttribute(string $databaseId, string $collectionId * @param ?string $newKey * @throws AppwriteException * @return \Appwrite\Models\AttributeLongtext + * + * @deprecated This API has been deprecated since 1.8.0. Please use `updateLongtextColumn` instead. + * @see TablesDB::updateLongtextColumn */ public function updateLongtextAttribute(string $databaseId, string $collectionId, string $key, bool $required, ?string $xdefault, ?string $newKey = null): \Appwrite\Models\AttributeLongtext { @@ -1931,6 +1955,9 @@ public function updateLongtextAttribute(string $databaseId, string $collectionId * @param ?bool $encrypt * @throws AppwriteException * @return \Appwrite\Models\AttributeMediumtext + * + * @deprecated This API has been deprecated since 1.8.0. Please use `createMediumtextColumn` instead. + * @see TablesDB::createMediumtextColumn */ public function createMediumtextAttribute(string $databaseId, string $collectionId, string $key, bool $required, ?string $xdefault = null, ?bool $xarray = null, ?bool $encrypt = null): \Appwrite\Models\AttributeMediumtext { @@ -1988,6 +2015,9 @@ public function createMediumtextAttribute(string $databaseId, string $collection * @param ?string $newKey * @throws AppwriteException * @return \Appwrite\Models\AttributeMediumtext + * + * @deprecated This API has been deprecated since 1.8.0. Please use `updateMediumtextColumn` instead. + * @see TablesDB::updateMediumtextColumn */ public function updateMediumtextAttribute(string $databaseId, string $collectionId, string $key, bool $required, ?string $xdefault, ?string $newKey = null): \Appwrite\Models\AttributeMediumtext { @@ -2474,6 +2504,9 @@ public function updateStringAttribute(string $databaseId, string $collectionId, * @param ?bool $encrypt * @throws AppwriteException * @return \Appwrite\Models\AttributeText + * + * @deprecated This API has been deprecated since 1.8.0. Please use `createTextColumn` instead. + * @see TablesDB::createTextColumn */ public function createTextAttribute(string $databaseId, string $collectionId, string $key, bool $required, ?string $xdefault = null, ?bool $xarray = null, ?bool $encrypt = null): \Appwrite\Models\AttributeText { @@ -2531,6 +2564,9 @@ public function createTextAttribute(string $databaseId, string $collectionId, st * @param ?string $newKey * @throws AppwriteException * @return \Appwrite\Models\AttributeText + * + * @deprecated This API has been deprecated since 1.8.0. Please use `updateTextColumn` instead. + * @see TablesDB::updateTextColumn */ public function updateTextAttribute(string $databaseId, string $collectionId, string $key, bool $required, ?string $xdefault, ?string $newKey = null): \Appwrite\Models\AttributeText { @@ -2690,6 +2726,9 @@ public function updateUrlAttribute(string $databaseId, string $collectionId, str * @param ?bool $encrypt * @throws AppwriteException * @return \Appwrite\Models\AttributeVarchar + * + * @deprecated This API has been deprecated since 1.8.0. Please use `createVarcharColumn` instead. + * @see TablesDB::createVarcharColumn */ public function createVarcharAttribute(string $databaseId, string $collectionId, string $key, int $size, bool $required, ?string $xdefault = null, ?bool $xarray = null, ?bool $encrypt = null): \Appwrite\Models\AttributeVarchar { @@ -2749,6 +2788,9 @@ public function createVarcharAttribute(string $databaseId, string $collectionId, * @param ?string $newKey * @throws AppwriteException * @return \Appwrite\Models\AttributeVarchar + * + * @deprecated This API has been deprecated since 1.8.0. Please use `updateVarcharColumn` instead. + * @see TablesDB::updateVarcharColumn */ public function updateVarcharAttribute(string $databaseId, string $collectionId, string $key, bool $required, ?string $xdefault, ?int $size = null, ?string $newKey = null): \Appwrite\Models\AttributeVarchar { diff --git a/src/Appwrite/Services/Functions.php b/src/Appwrite/Services/Functions.php index 21628d65..1db8154c 100644 --- a/src/Appwrite/Services/Functions.php +++ b/src/Appwrite/Services/Functions.php @@ -249,10 +249,11 @@ public function listRuntimes(): \Appwrite\Models\RuntimeList /** * List allowed function specifications for this instance. * + * @param ?string $type * @throws AppwriteException * @return \Appwrite\Models\SpecificationList */ - public function listSpecifications(): \Appwrite\Models\SpecificationList + public function listSpecifications(?string $type = null): \Appwrite\Models\SpecificationList { $apiPath = str_replace( [], @@ -262,6 +263,10 @@ public function listSpecifications(): \Appwrite\Models\SpecificationList $apiParams = []; + if (!is_null($type)) { + $apiParams['type'] = $type; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['accept'] = 'application/json'; @@ -416,10 +421,7 @@ public function update(string $functionId, string $name, ?Runtime $runtime = nul } $apiParams['providerBranches'] = $providerBranches; $apiParams['providerPaths'] = $providerPaths; - - if (!is_null($buildSpecification)) { - $apiParams['buildSpecification'] = $buildSpecification; - } + $apiParams['buildSpecification'] = $buildSpecification; if (!is_null($runtimeSpecification)) { $apiParams['runtimeSpecification'] = $runtimeSpecification; @@ -1111,10 +1113,11 @@ public function deleteDeployment(string $functionId, string $deploymentId): stri * @param string $functionId * @param string $deploymentId * @param ?DeploymentDownloadType $type + * @param ?string $token * @throws AppwriteException * @return string */ - public function getDeploymentDownload(string $functionId, string $deploymentId, ?DeploymentDownloadType $type = null): string + public function getDeploymentDownload(string $functionId, string $deploymentId, ?DeploymentDownloadType $type = null, ?string $token = null): string { $apiPath = str_replace( ['{functionId}', '{deploymentId}'], @@ -1130,6 +1133,10 @@ public function getDeploymentDownload(string $functionId, string $deploymentId, $apiParams['type'] = $type; } + if (!is_null($token)) { + $apiParams['token'] = $token; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['accept'] = '*/*'; diff --git a/src/Appwrite/Services/Health.php b/src/Appwrite/Services/Health.php deleted file mode 100644 index 66ea3ea9..00000000 --- a/src/Appwrite/Services/Health.php +++ /dev/null @@ -1,1012 +0,0 @@ -client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthStatus::from($response); - - } - - /** - * Check the Appwrite Antivirus server is up and connection is successful. - * - * @throws AppwriteException - * @return \Appwrite\Models\HealthAntivirus - */ - public function getAntivirus(): \Appwrite\Models\HealthAntivirus - { - $apiPath = str_replace( - [], - [], - '/health/anti-virus' - ); - - $apiParams = []; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthAntivirus::from($response); - - } - - /** - * Check the database that backs the audit and activity store. When the - * connection is reachable the endpoint returns a passing status with its - * response time. - * - * - * @throws AppwriteException - * @return \Appwrite\Models\HealthStatusList - */ - public function getAuditsDB(): \Appwrite\Models\HealthStatusList - { - $apiPath = str_replace( - [], - [], - '/health/audits-db' - ); - - $apiParams = []; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthStatusList::from($response); - - } - - /** - * Check the Appwrite in-memory cache servers are up and connection is - * successful. - * - * @throws AppwriteException - * @return \Appwrite\Models\HealthStatusList - */ - public function getCache(): \Appwrite\Models\HealthStatusList - { - $apiPath = str_replace( - [], - [], - '/health/cache' - ); - - $apiParams = []; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthStatusList::from($response); - - } - - /** - * Get the SSL certificate for a domain - * - * @param ?string $domain - * @throws AppwriteException - * @return \Appwrite\Models\HealthCertificate - */ - public function getCertificate(?string $domain = null): \Appwrite\Models\HealthCertificate - { - $apiPath = str_replace( - [], - [], - '/health/certificate' - ); - - $apiParams = []; - - if (!is_null($domain)) { - $apiParams['domain'] = $domain; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthCertificate::from($response); - - } - - /** - * Get console pausing health status. Monitors projects approaching the pause - * threshold to detect potential issues with console access tracking. - * - * - * @param ?int $threshold - * @param ?int $inactivityDays - * @throws AppwriteException - * @return \Appwrite\Models\HealthStatus - */ - public function getConsolePausing(?int $threshold = null, ?int $inactivityDays = null): \Appwrite\Models\HealthStatus - { - $apiPath = str_replace( - [], - [], - '/health/console-pausing' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - if (!is_null($inactivityDays)) { - $apiParams['inactivityDays'] = $inactivityDays; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthStatus::from($response); - - } - - /** - * Check the Appwrite database servers are up and connection is successful. - * - * @throws AppwriteException - * @return \Appwrite\Models\HealthStatusList - */ - public function getDB(): \Appwrite\Models\HealthStatusList - { - $apiPath = str_replace( - [], - [], - '/health/db' - ); - - $apiParams = []; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthStatusList::from($response); - - } - - /** - * Check the Appwrite pub-sub servers are up and connection is successful. - * - * @throws AppwriteException - * @return \Appwrite\Models\HealthStatusList - */ - public function getPubSub(): \Appwrite\Models\HealthStatusList - { - $apiPath = str_replace( - [], - [], - '/health/pubsub' - ); - - $apiParams = []; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthStatusList::from($response); - - } - - /** - * Get the number of audit logs that are waiting to be processed in the - * Appwrite internal queue server. - * - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueAudits(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/audits' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of builds that are waiting to be processed in the Appwrite - * internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueBuilds(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/builds' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of certificates that are waiting to be issued against - * [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue - * server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueCertificates(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/certificates' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of database changes that are waiting to be processed in the - * Appwrite internal queue server. - * - * @param ?string $name - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueDatabases(?string $name = null, ?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/databases' - ); - - $apiParams = []; - - if (!is_null($name)) { - $apiParams['name'] = $name; - } - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of background destructive changes that are waiting to be - * processed in the Appwrite internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueDeletes(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/deletes' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Returns the amount of failed jobs in a given queue. - * - * - * @param HealthQueueName $name - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getFailedJobs(HealthQueueName $name, ?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - ['{name}'], - [$name], - '/health/queue/failed/{name}' - ); - - $apiParams = []; - $apiParams['name'] = $name; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of function executions that are waiting to be processed in - * the Appwrite internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueFunctions(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/functions' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of logs that are waiting to be processed in the Appwrite - * internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueLogs(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/logs' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of mails that are waiting to be processed in the Appwrite - * internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueMails(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/mails' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of messages that are waiting to be processed in the Appwrite - * internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueMessaging(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/messaging' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of migrations that are waiting to be processed in the - * Appwrite internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueMigrations(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/migrations' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of metrics that are waiting to be processed in the Appwrite - * stats resources queue. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueStatsResources(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/stats-resources' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of metrics that are waiting to be processed in the Appwrite - * internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueUsage(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/stats-usage' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Get the number of webhooks that are waiting to be processed in the Appwrite - * internal queue server. - * - * @param ?int $threshold - * @throws AppwriteException - * @return \Appwrite\Models\HealthQueue - */ - public function getQueueWebhooks(?int $threshold = null): \Appwrite\Models\HealthQueue - { - $apiPath = str_replace( - [], - [], - '/health/queue/webhooks' - ); - - $apiParams = []; - - if (!is_null($threshold)) { - $apiParams['threshold'] = $threshold; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthQueue::from($response); - - } - - /** - * Check the Appwrite storage device is up and connection is successful. - * - * @throws AppwriteException - * @return \Appwrite\Models\HealthStatus - */ - public function getStorage(): \Appwrite\Models\HealthStatus - { - $apiPath = str_replace( - [], - [], - '/health/storage' - ); - - $apiParams = []; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthStatus::from($response); - - } - - /** - * Check the Appwrite local storage device is up and connection is successful. - * - * @throws AppwriteException - * @return \Appwrite\Models\HealthStatus - */ - public function getStorageLocal(): \Appwrite\Models\HealthStatus - { - $apiPath = str_replace( - [], - [], - '/health/storage/local' - ); - - $apiParams = []; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthStatus::from($response); - - } - - /** - * Check the Appwrite server time is synced with Google remote NTP server. We - * use this technology to smoothly handle leap seconds with no disruptive - * events. The [Network Time - * Protocol](https://en.wikipedia.org/wiki/Network_Time_Protocol) (NTP) is - * used by hundreds of millions of computers and devices to synchronize their - * clocks over the Internet. If your computer sets its own clock, it likely - * uses NTP. - * - * @throws AppwriteException - * @return \Appwrite\Models\HealthTime - */ - public function getTime(): \Appwrite\Models\HealthTime - { - $apiPath = str_replace( - [], - [], - '/health/time' - ); - - $apiParams = []; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\HealthTime::from($response); - - } -} diff --git a/src/Appwrite/Services/Messaging.php b/src/Appwrite/Services/Messaging.php index 76801acf..ee68c3bc 100644 --- a/src/Appwrite/Services/Messaging.php +++ b/src/Appwrite/Services/Messaging.php @@ -599,53 +599,6 @@ public function delete(string $messageId): string } - /** - * Get the message activity logs listed by its unique ID. - * - * @param string $messageId - * @param ?array $queries - * @param ?bool $total - * @throws AppwriteException - * @return \Appwrite\Models\LogList - */ - public function listMessageLogs(string $messageId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\LogList - { - $apiPath = str_replace( - ['{messageId}'], - [$messageId], - '/messaging/messages/{messageId}/logs' - ); - - $apiParams = []; - $apiParams['messageId'] = $messageId; - - if (!is_null($queries)) { - $apiParams['queries'] = $queries; - } - - if (!is_null($total)) { - $apiParams['total'] = $total; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\LogList::from($response); - - } - /** * Get a list of the targets associated with a message. * @@ -2394,100 +2347,6 @@ public function deleteProvider(string $providerId): string } - /** - * Get the provider activity logs listed by its unique ID. - * - * @param string $providerId - * @param ?array $queries - * @param ?bool $total - * @throws AppwriteException - * @return \Appwrite\Models\LogList - */ - public function listProviderLogs(string $providerId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\LogList - { - $apiPath = str_replace( - ['{providerId}'], - [$providerId], - '/messaging/providers/{providerId}/logs' - ); - - $apiParams = []; - $apiParams['providerId'] = $providerId; - - if (!is_null($queries)) { - $apiParams['queries'] = $queries; - } - - if (!is_null($total)) { - $apiParams['total'] = $total; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\LogList::from($response); - - } - - /** - * Get the subscriber activity logs listed by its unique ID. - * - * @param string $subscriberId - * @param ?array $queries - * @param ?bool $total - * @throws AppwriteException - * @return \Appwrite\Models\LogList - */ - public function listSubscriberLogs(string $subscriberId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\LogList - { - $apiPath = str_replace( - ['{subscriberId}'], - [$subscriberId], - '/messaging/subscribers/{subscriberId}/logs' - ); - - $apiParams = []; - $apiParams['subscriberId'] = $subscriberId; - - if (!is_null($queries)) { - $apiParams['queries'] = $queries; - } - - if (!is_null($total)) { - $apiParams['total'] = $total; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\LogList::from($response); - - } - /** * Get a list of all topics from the current Appwrite project. * @@ -2697,53 +2556,6 @@ public function deleteTopic(string $topicId): string } - /** - * Get the topic activity logs listed by its unique ID. - * - * @param string $topicId - * @param ?array $queries - * @param ?bool $total - * @throws AppwriteException - * @return \Appwrite\Models\LogList - */ - public function listTopicLogs(string $topicId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\LogList - { - $apiPath = str_replace( - ['{topicId}'], - [$topicId], - '/messaging/topics/{topicId}/logs' - ); - - $apiParams = []; - $apiParams['topicId'] = $topicId; - - if (!is_null($queries)) { - $apiParams['queries'] = $queries; - } - - if (!is_null($total)) { - $apiParams['total'] = $total; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\LogList::from($response); - - } - /** * Get a list of all subscribers from the current Appwrite project. * diff --git a/src/Appwrite/Services/Organization.php b/src/Appwrite/Services/Organization.php index d99efb5b..e50f89f5 100644 --- a/src/Appwrite/Services/Organization.php +++ b/src/Appwrite/Services/Organization.php @@ -16,6 +16,111 @@ public function __construct(Client $client) parent::__construct($client); } + /** + * Get the current organization. + * + * @throws AppwriteException + * @return \Appwrite\Models\Organization + */ + public function get(): \Appwrite\Models\Organization + { + $apiPath = str_replace( + [], + [], + '/organization' + ); + + $apiParams = []; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Organization::from($response); + + } + + /** + * Update the current organization's name. + * + * @param string $name + * @throws AppwriteException + * @return \Appwrite\Models\Organization + */ + public function update(string $name): \Appwrite\Models\Organization + { + $apiPath = str_replace( + [], + [], + '/organization' + ); + + $apiParams = []; + $apiParams['name'] = $name; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PUT, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Organization::from($response); + + } + + /** + * Delete the current organization. All projects that belong to the + * organization are deleted as well. + * + * @throws AppwriteException + * @return string + */ + public function delete(): string + { + $apiPath = str_replace( + [], + [], + '/organization' + ); + + $apiParams = []; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + /** * Get a list of all API keys from the current organization. * @@ -222,6 +327,233 @@ public function deleteKey(string $keyId): string } + /** + * Get a list of all memberships from the current organization. + * + * @param ?array $queries + * @param ?string $search + * @param ?bool $total + * @throws AppwriteException + * @return \Appwrite\Models\MembershipList + */ + public function listMemberships(?array $queries = null, ?string $search = null, ?bool $total = null): \Appwrite\Models\MembershipList + { + $apiPath = str_replace( + [], + [], + '/organization/memberships' + ); + + $apiParams = []; + + if (!is_null($queries)) { + $apiParams['queries'] = $queries; + } + + if (!is_null($search)) { + $apiParams['search'] = $search; + } + + if (!is_null($total)) { + $apiParams['total'] = $total; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\MembershipList::from($response); + + } + + /** + * Invite a new member to join the current organization. An email with a link + * to join the organization will be sent to the new member's email address. If + * member doesn't exist in the project it will be automatically created. + * + * @param array $roles + * @param ?string $email + * @param ?string $userId + * @param ?string $phone + * @param ?string $url + * @param ?string $name + * @throws AppwriteException + * @return \Appwrite\Models\Membership + */ + public function createMembership(array $roles, ?string $email = null, ?string $userId = null, ?string $phone = null, ?string $url = null, ?string $name = null): \Appwrite\Models\Membership + { + $apiPath = str_replace( + [], + [], + '/organization/memberships' + ); + + $apiParams = []; + $apiParams['roles'] = $roles; + + if (!is_null($email)) { + $apiParams['email'] = $email; + } + + if (!is_null($userId)) { + $apiParams['userId'] = $userId; + } + + if (!is_null($phone)) { + $apiParams['phone'] = $phone; + } + + if (!is_null($url)) { + $apiParams['url'] = $url; + } + + if (!is_null($name)) { + $apiParams['name'] = $name; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Membership::from($response); + + } + + /** + * Get a membership from the current organization by its unique ID. + * + * @param string $membershipId + * @throws AppwriteException + * @return \Appwrite\Models\Membership + */ + public function getMembership(string $membershipId): \Appwrite\Models\Membership + { + $apiPath = str_replace( + ['{membershipId}'], + [$membershipId], + '/organization/memberships/{membershipId}' + ); + + $apiParams = []; + $apiParams['membershipId'] = $membershipId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Membership::from($response); + + } + + /** + * Modify the roles of a member in the current organization. + * + * @param string $membershipId + * @param array $roles + * @throws AppwriteException + * @return \Appwrite\Models\Membership + */ + public function updateMembership(string $membershipId, array $roles): \Appwrite\Models\Membership + { + $apiPath = str_replace( + ['{membershipId}'], + [$membershipId], + '/organization/memberships/{membershipId}' + ); + + $apiParams = []; + $apiParams['membershipId'] = $membershipId; + $apiParams['roles'] = $roles; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PATCH, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Membership::from($response); + + } + + /** + * Remove a member from the current organization. The member is removed + * whether they accepted the invitation or not; a pending invitation is + * revoked. + * + * @param string $membershipId + * @throws AppwriteException + * @return string + */ + public function deleteMembership(string $membershipId): string + { + $apiPath = str_replace( + ['{membershipId}'], + [$membershipId], + '/organization/memberships/{membershipId}' + ); + + $apiParams = []; + $apiParams['membershipId'] = $membershipId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + /** * Get a list of all projects. You can use the query params to filter your * results. diff --git a/src/Appwrite/Services/Project.php b/src/Appwrite/Services/Project.php index 5e3ba5ac..475d5f8e 100644 --- a/src/Appwrite/Services/Project.php +++ b/src/Appwrite/Services/Project.php @@ -9,6 +9,7 @@ use Appwrite\Enums\ProjectAuthMethodId; use Appwrite\Enums\ProjectKeyScopes; use Appwrite\Enums\ProjectOAuth2GooglePrompt; +use Appwrite\Enums\ProjectOAuth2OidcPrompt; use Appwrite\Enums\ProjectOAuthProviderId; use Appwrite\Enums\ProjectPolicyId; use Appwrite\Enums\ProjectProtocolId; @@ -685,10 +686,11 @@ public function listOAuth2Providers(?array $queries = null, ?bool $total = null) * @param ?int $userCodeLength * @param ?string $userCodeFormat * @param ?int $deviceCodeDuration + * @param ?array $defaultScopes * @throws AppwriteException * @return \Appwrite\Models\Project */ - public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?array $scopes = null, ?array $authorizationDetailsTypes = null, ?int $accessTokenDuration = null, ?int $refreshTokenDuration = null, ?int $publicAccessTokenDuration = null, ?int $publicRefreshTokenDuration = null, ?bool $confidentialPkce = null, ?string $verificationUrl = null, ?int $userCodeLength = null, ?string $userCodeFormat = null, ?int $deviceCodeDuration = null): \Appwrite\Models\Project + public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?array $scopes = null, ?array $authorizationDetailsTypes = null, ?int $accessTokenDuration = null, ?int $refreshTokenDuration = null, ?int $publicAccessTokenDuration = null, ?int $publicRefreshTokenDuration = null, ?bool $confidentialPkce = null, ?string $verificationUrl = null, ?int $userCodeLength = null, ?string $userCodeFormat = null, ?int $deviceCodeDuration = null, ?array $defaultScopes = null): \Appwrite\Models\Project { $apiPath = str_replace( [], @@ -723,6 +725,10 @@ public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?arr } $apiParams['deviceCodeDuration'] = $deviceCodeDuration; + if (!is_null($defaultScopes)) { + $apiParams['defaultScopes'] = $defaultScopes; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; @@ -831,6 +837,48 @@ public function updateOAuth2Apple(?string $serviceId = null, ?string $keyId = nu } + /** + * Update the project OAuth2 Appwrite configuration. + * + * @param ?string $clientId + * @param ?string $clientSecret + * @param ?bool $enabled + * @throws AppwriteException + * @return \Appwrite\Models\OAuth2Appwrite + */ + public function updateOAuth2Appwrite(?string $clientId = null, ?string $clientSecret = null, ?bool $enabled = null): \Appwrite\Models\OAuth2Appwrite + { + $apiPath = str_replace( + [], + [], + '/project/oauth2/appwrite' + ); + + $apiParams = []; + $apiParams['clientId'] = $clientId; + $apiParams['clientSecret'] = $clientSecret; + $apiParams['enabled'] = $enabled; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PATCH, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\OAuth2Appwrite::from($response); + + } + /** * Update the project OAuth2 Auth0 configuration. * @@ -1780,11 +1828,13 @@ public function updateOAuth2Notion(?string $oauthClientId = null, ?string $oauth * @param ?string $authorizationURL * @param ?string $tokenURL * @param ?string $userInfoURL + * @param ?array $prompt + * @param ?int $maxAge * @param ?bool $enabled * @throws AppwriteException * @return \Appwrite\Models\OAuth2Oidc */ - public function updateOAuth2Oidc(?string $clientId = null, ?string $clientSecret = null, ?string $wellKnownURL = null, ?string $authorizationURL = null, ?string $tokenURL = null, ?string $userInfoURL = null, ?bool $enabled = null): \Appwrite\Models\OAuth2Oidc + public function updateOAuth2Oidc(?string $clientId = null, ?string $clientSecret = null, ?string $wellKnownURL = null, ?string $authorizationURL = null, ?string $tokenURL = null, ?string $userInfoURL = null, ?array $prompt = null, ?int $maxAge = null, ?bool $enabled = null): \Appwrite\Models\OAuth2Oidc { $apiPath = str_replace( [], @@ -1799,6 +1849,8 @@ public function updateOAuth2Oidc(?string $clientId = null, ?string $clientSecret $apiParams['authorizationURL'] = $authorizationURL; $apiParams['tokenURL'] = $tokenURL; $apiParams['userInfoURL'] = $userInfoURL; + $apiParams['prompt'] = $prompt; + $apiParams['maxAge'] = $maxAge; $apiParams['enabled'] = $enabled; $apiHeaders = []; diff --git a/src/Appwrite/Services/Sites.php b/src/Appwrite/Services/Sites.php index 6c2c25e3..b7e44fdb 100644 --- a/src/Appwrite/Services/Sites.php +++ b/src/Appwrite/Services/Sites.php @@ -249,10 +249,11 @@ public function listFrameworks(): \Appwrite\Models\FrameworkList /** * List allowed site specifications for this instance. * + * @param ?string $type * @throws AppwriteException * @return \Appwrite\Models\SpecificationList */ - public function listSpecifications(): \Appwrite\Models\SpecificationList + public function listSpecifications(?string $type = null): \Appwrite\Models\SpecificationList { $apiPath = str_replace( [], @@ -262,6 +263,10 @@ public function listSpecifications(): \Appwrite\Models\SpecificationList $apiParams = []; + if (!is_null($type)) { + $apiParams['type'] = $type; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['accept'] = 'application/json'; @@ -421,10 +426,7 @@ public function update(string $siteId, string $name, Framework $framework, ?bool } $apiParams['providerBranches'] = $providerBranches; $apiParams['providerPaths'] = $providerPaths; - - if (!is_null($buildSpecification)) { - $apiParams['buildSpecification'] = $buildSpecification; - } + $apiParams['buildSpecification'] = $buildSpecification; if (!is_null($runtimeSpecification)) { $apiParams['runtimeSpecification'] = $runtimeSpecification; diff --git a/src/Appwrite/Services/TablesDB.php b/src/Appwrite/Services/TablesDB.php index 4834e5f2..bff7d67b 100644 --- a/src/Appwrite/Services/TablesDB.php +++ b/src/Appwrite/Services/TablesDB.php @@ -76,11 +76,11 @@ public function list(?array $queries = null, ?string $search = null, ?bool $tota * @param string $databaseId * @param string $name * @param ?bool $enabled - * @param ?string $dedicatedDatabaseId + * @param ?string $specification * @throws AppwriteException * @return \Appwrite\Models\Database */ - public function create(string $databaseId, string $name, ?bool $enabled = null, ?string $dedicatedDatabaseId = null): \Appwrite\Models\Database + public function create(string $databaseId, string $name, ?bool $enabled = null, ?string $specification = null): \Appwrite\Models\Database { $apiPath = str_replace( [], @@ -96,8 +96,8 @@ public function create(string $databaseId, string $name, ?bool $enabled = null, $apiParams['enabled'] = $enabled; } - if (!is_null($dedicatedDatabaseId)) { - $apiParams['dedicatedDatabaseId'] = $dedicatedDatabaseId; + if (!is_null($specification)) { + $apiParams['specification'] = $specification; } $apiHeaders = []; diff --git a/src/Appwrite/Services/Usage.php b/src/Appwrite/Services/Usage.php deleted file mode 100644 index 5da84817..00000000 --- a/src/Appwrite/Services/Usage.php +++ /dev/null @@ -1,218 +0,0 @@ -client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\UsageEventList::from($response); - - } - - /** - * Aggregate usage gauge snapshots. Gauges are point-in-time values (storage - * totals, resource counts, …); each group carries the latest snapshot in - * its interval via `argMax(value, time)`. `metric` is required. - * - * **Two response shapes**: - * - Omit `interval` for a flat top-N table — `argMax(value, time)` per - * dimension combination over the whole window, no time axis. Useful for "top - * 10 resources by current storage". - * - Pass `interval` (`1m`, `15m`, `30m`, `1h`, `1d`) for a time series — - * one snapshot per (time bucket × dimension combination). - * - * `dimensions[]` breaks each row down further — only `resourceId` and - * `teamId` are supported on gauges. `resourceId` and `teamId` parameters - * filter the underlying rows. `orderBy=value`+`orderDir=desc`+`limit=N` - * returns the top-N. When `startAt` is omitted, the default window adapts to - * interval (or 7d when interval is omitted). - * - * @param string $metric - * @param ?string $resourceId - * @param ?string $teamId - * @param ?string $interval - * @param ?array $dimensions - * @param ?string $startAt - * @param ?string $endAt - * @param ?string $orderBy - * @param ?string $orderDir - * @param ?int $limit - * @param ?int $offset - * @throws AppwriteException - * @return \Appwrite\Models\UsageGaugeList - */ - public function listGauges(string $metric, ?string $resourceId = null, ?string $teamId = null, ?string $interval = null, ?array $dimensions = null, ?string $startAt = null, ?string $endAt = null, ?string $orderBy = null, ?string $orderDir = null, ?int $limit = null, ?int $offset = null): \Appwrite\Models\UsageGaugeList - { - $apiPath = str_replace( - [], - [], - '/usage/gauges' - ); - - $apiParams = []; - $apiParams['metric'] = $metric; - - if (!is_null($resourceId)) { - $apiParams['resourceId'] = $resourceId; - } - - if (!is_null($teamId)) { - $apiParams['teamId'] = $teamId; - } - - if (!is_null($interval)) { - $apiParams['interval'] = $interval; - } - - if (!is_null($dimensions)) { - $apiParams['dimensions'] = $dimensions; - } - - if (!is_null($startAt)) { - $apiParams['startAt'] = $startAt; - } - - if (!is_null($endAt)) { - $apiParams['endAt'] = $endAt; - } - - if (!is_null($orderBy)) { - $apiParams['orderBy'] = $orderBy; - } - - if (!is_null($orderDir)) { - $apiParams['orderDir'] = $orderDir; - } - - if (!is_null($limit)) { - $apiParams['limit'] = $limit; - } - - if (!is_null($offset)) { - $apiParams['offset'] = $offset; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_GET, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\UsageGaugeList::from($response); - - } -} diff --git a/tests/Appwrite/Services/ActivitiesTest.php b/tests/Appwrite/Services/ActivitiesTest.php index 4f705395..f4daf521 100644 --- a/tests/Appwrite/Services/ActivitiesTest.php +++ b/tests/Appwrite/Services/ActivitiesTest.php @@ -41,9 +41,7 @@ public function testMethodListEvents(): void "time" => "2020-10-15T06:38:00.000+00:00", "projectId" => "610fc2f985ee0", "teamId" => "610fc2f985ee0", - "hostname" => "appwrite.io", - "countryCode" => "US", - "countryName" => "United States" + "hostname" => "appwrite.io" ) ) ); @@ -80,9 +78,7 @@ public function testMethodGetEvent(): void "time" => "2020-10-15T06:38:00.000+00:00", "projectId" => "610fc2f985ee0", "teamId" => "610fc2f985ee0", - "hostname" => "appwrite.io", - "countryCode" => "US", - "countryName" => "United States" + "hostname" => "appwrite.io" ); $this->client diff --git a/tests/Appwrite/Services/BackupsTest.php b/tests/Appwrite/Services/BackupsTest.php index ee9d09d4..da100a87 100644 --- a/tests/Appwrite/Services/BackupsTest.php +++ b/tests/Appwrite/Services/BackupsTest.php @@ -280,7 +280,7 @@ public function testMethodCreateRestoration(): void "migrationId" => "did8jx6ws45jana098ab7", "services" => array(), "resources" => array(), - "options" => "{databases.database[{oldId, newId, newName}]}" + "options" => "{databases.database[{oldId, newId, newName, newSpecification}]}" ); $this->client @@ -314,7 +314,7 @@ public function testMethodListRestorations(): void "migrationId" => "did8jx6ws45jana098ab7", "services" => array(), "resources" => array(), - "options" => "{databases.database[{oldId, newId, newName}]}" + "options" => "{databases.database[{oldId, newId, newName, newSpecification}]}" ) ) ); @@ -344,7 +344,7 @@ public function testMethodGetRestoration(): void "migrationId" => "did8jx6ws45jana098ab7", "services" => array(), "resources" => array(), - "options" => "{databases.database[{oldId, newId, newName}]}" + "options" => "{databases.database[{oldId, newId, newName, newSpecification}]}" ); $this->client diff --git a/tests/Appwrite/Services/HealthTest.php b/tests/Appwrite/Services/HealthTest.php deleted file mode 100644 index 7f76bbb3..00000000 --- a/tests/Appwrite/Services/HealthTest.php +++ /dev/null @@ -1,518 +0,0 @@ -client = Mockery::mock(Client::class); - $this->health = new Health($this->client); - } - - public function testMethodGet(): void - { - $data = array( - "name" => "database", - "ping" => 128, - "status" => "pass" - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->get(); - - $this->assertInstanceOf(\Appwrite\Models\HealthStatus::class, $response); - } - - public function testMethodGetAntivirus(): void - { - $data = array( - "version" => "1.0.0", - "status" => "disabled" - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getAntivirus(); - - $this->assertInstanceOf(\Appwrite\Models\HealthAntivirus::class, $response); - } - - public function testMethodGetAuditsDB(): void - { - $data = array( - "total" => 5, - "statuses" => array( - array( - "name" => "database", - "ping" => 128, - "status" => "pass" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getAuditsDB(); - - $this->assertInstanceOf(\Appwrite\Models\HealthStatusList::class, $response); - } - - public function testMethodGetCache(): void - { - $data = array( - "total" => 5, - "statuses" => array( - array( - "name" => "database", - "ping" => 128, - "status" => "pass" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getCache(); - - $this->assertInstanceOf(\Appwrite\Models\HealthStatusList::class, $response); - } - - public function testMethodGetCertificate(): void - { - $data = array( - "name" => "/CN=www.google.com", - "subjectSN" => "[SUBJECTSN]", - "issuerOrganisation" => "[ISSUERORGANISATION]", - "validFrom" => "1704200998", - "validTo" => "1711458597", - "signatureTypeSN" => "RSA-SHA256" - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getCertificate(); - - $this->assertInstanceOf(\Appwrite\Models\HealthCertificate::class, $response); - } - - public function testMethodGetConsolePausing(): void - { - $data = array( - "name" => "database", - "ping" => 128, - "status" => "pass" - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getConsolePausing(); - - $this->assertInstanceOf(\Appwrite\Models\HealthStatus::class, $response); - } - - public function testMethodGetDB(): void - { - $data = array( - "total" => 5, - "statuses" => array( - array( - "name" => "database", - "ping" => 128, - "status" => "pass" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getDB(); - - $this->assertInstanceOf(\Appwrite\Models\HealthStatusList::class, $response); - } - - public function testMethodGetPubSub(): void - { - $data = array( - "total" => 5, - "statuses" => array( - array( - "name" => "database", - "ping" => 128, - "status" => "pass" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getPubSub(); - - $this->assertInstanceOf(\Appwrite\Models\HealthStatusList::class, $response); - } - - public function testMethodGetQueueAudits(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueAudits(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueBuilds(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueBuilds(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueCertificates(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueCertificates(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueDatabases(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueDatabases(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueDeletes(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueDeletes(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetFailedJobs(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getFailedJobs( - HealthQueueName::V1DATABASE() - ); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueFunctions(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueFunctions(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueLogs(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueLogs(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueMails(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueMails(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueMessaging(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueMessaging(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueMigrations(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueMigrations(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueStatsResources(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueStatsResources(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueUsage(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueUsage(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetQueueWebhooks(): void - { - $data = array( - "size" => 8 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getQueueWebhooks(); - - $this->assertInstanceOf(\Appwrite\Models\HealthQueue::class, $response); - } - - public function testMethodGetStorage(): void - { - $data = array( - "name" => "database", - "ping" => 128, - "status" => "pass" - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getStorage(); - - $this->assertInstanceOf(\Appwrite\Models\HealthStatus::class, $response); - } - - public function testMethodGetStorageLocal(): void - { - $data = array( - "name" => "database", - "ping" => 128, - "status" => "pass" - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getStorageLocal(); - - $this->assertInstanceOf(\Appwrite\Models\HealthStatus::class, $response); - } - - public function testMethodGetTime(): void - { - $data = array( - "remoteTime" => 1639490751, - "localTime" => 1639490844, - "diff" => 93 - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->health->getTime(); - - $this->assertInstanceOf(\Appwrite\Models\HealthTime::class, $response); - } - -} diff --git a/tests/Appwrite/Services/MessagingTest.php b/tests/Appwrite/Services/MessagingTest.php index 7b5a974c..2c51919a 100644 --- a/tests/Appwrite/Services/MessagingTest.php +++ b/tests/Appwrite/Services/MessagingTest.php @@ -276,52 +276,6 @@ public function testMethodDelete(): void $this->assertSame($data, $response); } - public function testMethodListMessageLogs(): void - { - $data = array( - "total" => 5, - "logs" => array( - array( - "event" => "account.sessions.create", - "userId" => "610fc2f985ee0", - "userEmail" => "john@appwrite.io", - "userName" => "John Doe", - "mode" => "admin", - "userType" => "user", - "ip" => "127.0.0.1", - "time" => "2020-10-15T06:38:00.000+00:00", - "osCode" => "Mac", - "osName" => "Mac", - "osVersion" => "Mac", - "clientType" => "browser", - "clientCode" => "CM", - "clientName" => "Chrome Mobile iOS", - "clientVersion" => "84.0", - "clientEngine" => "WebKit", - "clientEngineVersion" => "605.1.15", - "deviceName" => "smartphone", - "deviceBrand" => "Google", - "deviceModel" => "Nexus 5", - "countryCode" => "US", - "countryName" => "United States" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->messaging->listMessageLogs( - "" - ); - - $this->assertInstanceOf(\Appwrite\Models\LogList::class, $response); - } - public function testMethodListTargets(): void { $data = array( @@ -1090,98 +1044,6 @@ public function testMethodDeleteProvider(): void $this->assertSame($data, $response); } - public function testMethodListProviderLogs(): void - { - $data = array( - "total" => 5, - "logs" => array( - array( - "event" => "account.sessions.create", - "userId" => "610fc2f985ee0", - "userEmail" => "john@appwrite.io", - "userName" => "John Doe", - "mode" => "admin", - "userType" => "user", - "ip" => "127.0.0.1", - "time" => "2020-10-15T06:38:00.000+00:00", - "osCode" => "Mac", - "osName" => "Mac", - "osVersion" => "Mac", - "clientType" => "browser", - "clientCode" => "CM", - "clientName" => "Chrome Mobile iOS", - "clientVersion" => "84.0", - "clientEngine" => "WebKit", - "clientEngineVersion" => "605.1.15", - "deviceName" => "smartphone", - "deviceBrand" => "Google", - "deviceModel" => "Nexus 5", - "countryCode" => "US", - "countryName" => "United States" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->messaging->listProviderLogs( - "" - ); - - $this->assertInstanceOf(\Appwrite\Models\LogList::class, $response); - } - - public function testMethodListSubscriberLogs(): void - { - $data = array( - "total" => 5, - "logs" => array( - array( - "event" => "account.sessions.create", - "userId" => "610fc2f985ee0", - "userEmail" => "john@appwrite.io", - "userName" => "John Doe", - "mode" => "admin", - "userType" => "user", - "ip" => "127.0.0.1", - "time" => "2020-10-15T06:38:00.000+00:00", - "osCode" => "Mac", - "osName" => "Mac", - "osVersion" => "Mac", - "clientType" => "browser", - "clientCode" => "CM", - "clientName" => "Chrome Mobile iOS", - "clientVersion" => "84.0", - "clientEngine" => "WebKit", - "clientEngineVersion" => "605.1.15", - "deviceName" => "smartphone", - "deviceBrand" => "Google", - "deviceModel" => "Nexus 5", - "countryCode" => "US", - "countryName" => "United States" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->messaging->listSubscriberLogs( - "" - ); - - $this->assertInstanceOf(\Appwrite\Models\LogList::class, $response); - } - public function testMethodListTopics(): void { $data = array( @@ -1312,52 +1174,6 @@ public function testMethodDeleteTopic(): void $this->assertSame($data, $response); } - public function testMethodListTopicLogs(): void - { - $data = array( - "total" => 5, - "logs" => array( - array( - "event" => "account.sessions.create", - "userId" => "610fc2f985ee0", - "userEmail" => "john@appwrite.io", - "userName" => "John Doe", - "mode" => "admin", - "userType" => "user", - "ip" => "127.0.0.1", - "time" => "2020-10-15T06:38:00.000+00:00", - "osCode" => "Mac", - "osName" => "Mac", - "osVersion" => "Mac", - "clientType" => "browser", - "clientCode" => "CM", - "clientName" => "Chrome Mobile iOS", - "clientVersion" => "84.0", - "clientEngine" => "WebKit", - "clientEngineVersion" => "605.1.15", - "deviceName" => "smartphone", - "deviceBrand" => "Google", - "deviceModel" => "Nexus 5", - "countryCode" => "US", - "countryName" => "United States" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->messaging->listTopicLogs( - "" - ); - - $this->assertInstanceOf(\Appwrite\Models\LogList::class, $response); - } - public function testMethodListSubscribers(): void { $data = array( diff --git a/tests/Appwrite/Services/OrganizationTest.php b/tests/Appwrite/Services/OrganizationTest.php index 4b573c1b..237ef05f 100644 --- a/tests/Appwrite/Services/OrganizationTest.php +++ b/tests/Appwrite/Services/OrganizationTest.php @@ -20,6 +20,484 @@ protected function setUp(): void $this->organization = new Organization($this->client); } + public function testMethodGet(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "VIP", + "total" => 7, + "prefs" => array(), + "billingBudget" => 50, + "budgetAlerts" => array(), + "billingPlan" => "tier-1", + "billingPlanId" => "tier-1", + "billingPlanDetails" => array( + "\$id" => "tier-0", + "name" => "Hobby", + "desc" => "Hobby plan", + "order" => 0, + "price" => 25, + "trial" => 14, + "bandwidth" => 25, + "storage" => 25, + "imageTransformations" => 100, + "screenshotsGenerated" => 50, + "members" => 25, + "webhooks" => 25, + "projects" => 2, + "platforms" => 3, + "users" => 25, + "teams" => 25, + "databases" => 25, + "databasesReads" => 500000, + "databasesWrites" => 250000, + "databasesBatchSize" => 100, + "buckets" => 25, + "fileSize" => 25, + "functions" => 25, + "sites" => 1, + "executions" => 25, + "executionsRetentionCount" => 10000, + "GBHours" => 100, + "realtime" => 25, + "realtimeMessages" => 100000, + "messages" => 1000, + "topics" => 1, + "authPhone" => 10, + "domains" => 5, + "activityLogs" => 7, + "usageLogs" => 30, + "projectInactivityDays" => 7, + "alertLimit" => 80, + "usage" => array( + "bandwidth" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "executions" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "member" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "realtime" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "realtimeMessages" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "realtimeBandwidth" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "storage" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "users" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "GBHours" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "imageTransformations" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "credits" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ) + ), + "addons" => array( + "seats" => array( + "supported" => true, + "planIncluded" => 1, + "limit" => 5, + "type" => "numeric", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "projects" => array( + "supported" => true, + "planIncluded" => 1, + "limit" => 5, + "type" => "numeric", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ) + ), + "budgetCapEnabled" => true, + "customSmtp" => true, + "emailBranding" => true, + "requiresPaymentMethod" => true, + "requiresBillingAddress" => true, + "isAvailable" => true, + "selfService" => true, + "premiumSupport" => true, + "budgeting" => true, + "supportsMockNumbers" => true, + "supportsOrganizationRoles" => true, + "supportsCredits" => true, + "supportsDisposableEmailValidation" => true, + "supportsCanonicalEmailValidation" => true, + "supportsFreeEmailValidation" => true, + "supportsCorporateEmailValidation" => true, + "supportsProjectSpecificRoles" => true, + "backupsEnabled" => true, + "usagePerProject" => true, + "supportedAddons" => array( + "baa" => true, + "premiumGeoDB" => true, + "premiumGeoDBOrg" => true + ), + "backupPolicies" => true, + "deploymentSize" => 30, + "buildSize" => 2000, + "databasesAllowEncrypt" => true, + "group" => "starter" + ), + "billingEmail" => "billing@org.example", + "billingStartDate" => "2020-10-15T06:38:00.000+00:00", + "billingCurrentInvoiceDate" => "2020-10-15T06:38:00.000+00:00", + "billingNextInvoiceDate" => "2020-10-15T06:38:00.000+00:00", + "billingTrialStartDate" => "2020-10-15T06:38:00.000+00:00", + "billingTrialDays" => 14, + "billingAggregationId" => "adbc3de4rddfsd", + "billingInvoiceId" => "adbc3de4rddfsd", + "paymentMethodId" => "adbc3de4rddfsd", + "billingAddressId" => "adbc3de4rddfsd", + "backupPaymentMethodId" => "adbc3de4rddfsd", + "status" => "active", + "remarks" => "Pending initial payment", + "agreementBAA" => "[AGREEMENTBAA]", + "programManagerName" => "[PROGRAMMANAGERNAME]", + "programManagerCalendar" => "[PROGRAMMANAGERCALENDAR]", + "programDiscordChannelName" => "[PROGRAMDISCORDCHANNELNAME]", + "programDiscordChannelUrl" => "[PROGRAMDISCORDCHANNELURL]", + "billingPlanDowngrade" => "tier-1", + "billingTaxId" => "[BILLINGTAXID]", + "markedForDeletion" => true, + "platform" => "imagine", + "projects" => array() + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->get(); + + $this->assertInstanceOf(\Appwrite\Models\Organization::class, $response); + } + + public function testMethodUpdate(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "VIP", + "total" => 7, + "prefs" => array(), + "billingBudget" => 50, + "budgetAlerts" => array(), + "billingPlan" => "tier-1", + "billingPlanId" => "tier-1", + "billingPlanDetails" => array( + "\$id" => "tier-0", + "name" => "Hobby", + "desc" => "Hobby plan", + "order" => 0, + "price" => 25, + "trial" => 14, + "bandwidth" => 25, + "storage" => 25, + "imageTransformations" => 100, + "screenshotsGenerated" => 50, + "members" => 25, + "webhooks" => 25, + "projects" => 2, + "platforms" => 3, + "users" => 25, + "teams" => 25, + "databases" => 25, + "databasesReads" => 500000, + "databasesWrites" => 250000, + "databasesBatchSize" => 100, + "buckets" => 25, + "fileSize" => 25, + "functions" => 25, + "sites" => 1, + "executions" => 25, + "executionsRetentionCount" => 10000, + "GBHours" => 100, + "realtime" => 25, + "realtimeMessages" => 100000, + "messages" => 1000, + "topics" => 1, + "authPhone" => 10, + "domains" => 5, + "activityLogs" => 7, + "usageLogs" => 30, + "projectInactivityDays" => 7, + "alertLimit" => 80, + "usage" => array( + "bandwidth" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "executions" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "member" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "realtime" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "realtimeMessages" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "realtimeBandwidth" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "storage" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "users" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "GBHours" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "imageTransformations" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "credits" => array( + "name" => "[NAME]", + "unit" => "GB", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ) + ), + "addons" => array( + "seats" => array( + "supported" => true, + "planIncluded" => 1, + "limit" => 5, + "type" => "numeric", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ), + "projects" => array( + "supported" => true, + "planIncluded" => 1, + "limit" => 5, + "type" => "numeric", + "currency" => "USD", + "price" => 5, + "value" => 25, + "invoiceDesc" => "[INVOICEDESC]" + ) + ), + "budgetCapEnabled" => true, + "customSmtp" => true, + "emailBranding" => true, + "requiresPaymentMethod" => true, + "requiresBillingAddress" => true, + "isAvailable" => true, + "selfService" => true, + "premiumSupport" => true, + "budgeting" => true, + "supportsMockNumbers" => true, + "supportsOrganizationRoles" => true, + "supportsCredits" => true, + "supportsDisposableEmailValidation" => true, + "supportsCanonicalEmailValidation" => true, + "supportsFreeEmailValidation" => true, + "supportsCorporateEmailValidation" => true, + "supportsProjectSpecificRoles" => true, + "backupsEnabled" => true, + "usagePerProject" => true, + "supportedAddons" => array( + "baa" => true, + "premiumGeoDB" => true, + "premiumGeoDBOrg" => true + ), + "backupPolicies" => true, + "deploymentSize" => 30, + "buildSize" => 2000, + "databasesAllowEncrypt" => true, + "group" => "starter" + ), + "billingEmail" => "billing@org.example", + "billingStartDate" => "2020-10-15T06:38:00.000+00:00", + "billingCurrentInvoiceDate" => "2020-10-15T06:38:00.000+00:00", + "billingNextInvoiceDate" => "2020-10-15T06:38:00.000+00:00", + "billingTrialStartDate" => "2020-10-15T06:38:00.000+00:00", + "billingTrialDays" => 14, + "billingAggregationId" => "adbc3de4rddfsd", + "billingInvoiceId" => "adbc3de4rddfsd", + "paymentMethodId" => "adbc3de4rddfsd", + "billingAddressId" => "adbc3de4rddfsd", + "backupPaymentMethodId" => "adbc3de4rddfsd", + "status" => "active", + "remarks" => "Pending initial payment", + "agreementBAA" => "[AGREEMENTBAA]", + "programManagerName" => "[PROGRAMMANAGERNAME]", + "programManagerCalendar" => "[PROGRAMMANAGERCALENDAR]", + "programDiscordChannelName" => "[PROGRAMDISCORDCHANNELNAME]", + "programDiscordChannelUrl" => "[PROGRAMDISCORDCHANNELURL]", + "billingPlanDowngrade" => "tier-1", + "billingTaxId" => "[BILLINGTAXID]", + "markedForDeletion" => true, + "platform" => "imagine", + "projects" => array() + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->update( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Organization::class, $response); + } + + public function testMethodDelete(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->delete(); + + $this->assertSame($data, $response); + } + public function testMethodListKeys(): void { $data = array( @@ -157,6 +635,164 @@ public function testMethodDeleteKey(): void $this->assertSame($data, $response); } + public function testMethodListMemberships(): void + { + $data = array( + "total" => 5, + "memberships" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c16897e", + "userName" => "John Doe", + "userEmail" => "john@appwrite.io", + "userPhone" => "+1 555 555 5555", + "teamId" => "5e5ea5c16897e", + "teamName" => "VIP", + "invited" => "2020-10-15T06:38:00.000+00:00", + "joined" => "2020-10-15T06:38:00.000+00:00", + "confirm" => true, + "mfa" => true, + "userAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "roles" => array() + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->listMemberships(); + + $this->assertInstanceOf(\Appwrite\Models\MembershipList::class, $response); + } + + public function testMethodCreateMembership(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c16897e", + "userName" => "John Doe", + "userEmail" => "john@appwrite.io", + "userPhone" => "+1 555 555 5555", + "teamId" => "5e5ea5c16897e", + "teamName" => "VIP", + "invited" => "2020-10-15T06:38:00.000+00:00", + "joined" => "2020-10-15T06:38:00.000+00:00", + "confirm" => true, + "mfa" => true, + "userAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "roles" => array() + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->createMembership( + array() + ); + + $this->assertInstanceOf(\Appwrite\Models\Membership::class, $response); + } + + public function testMethodGetMembership(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c16897e", + "userName" => "John Doe", + "userEmail" => "john@appwrite.io", + "userPhone" => "+1 555 555 5555", + "teamId" => "5e5ea5c16897e", + "teamName" => "VIP", + "invited" => "2020-10-15T06:38:00.000+00:00", + "joined" => "2020-10-15T06:38:00.000+00:00", + "confirm" => true, + "mfa" => true, + "userAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "roles" => array() + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->getMembership( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Membership::class, $response); + } + + public function testMethodUpdateMembership(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c16897e", + "userName" => "John Doe", + "userEmail" => "john@appwrite.io", + "userPhone" => "+1 555 555 5555", + "teamId" => "5e5ea5c16897e", + "teamName" => "VIP", + "invited" => "2020-10-15T06:38:00.000+00:00", + "joined" => "2020-10-15T06:38:00.000+00:00", + "confirm" => true, + "mfa" => true, + "userAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "roles" => array() + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->updateMembership( + "", + array() + ); + + $this->assertInstanceOf(\Appwrite\Models\Membership::class, $response); + } + + public function testMethodDeleteMembership(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->deleteMembership( + "" + ); + + $this->assertSame($data, $response); + } + public function testMethodListProjects(): void { $data = array( @@ -195,6 +831,7 @@ public function testMethodListProjects(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -218,6 +855,7 @@ public function testMethodListProjects(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -277,6 +915,7 @@ public function testMethodCreateProject(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -300,6 +939,7 @@ public function testMethodCreateProject(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -360,6 +1000,7 @@ public function testMethodGetProject(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -383,6 +1024,7 @@ public function testMethodGetProject(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -442,6 +1084,7 @@ public function testMethodUpdateProject(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -465,6 +1108,7 @@ public function testMethodUpdateProject(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", diff --git a/tests/Appwrite/Services/ProjectTest.php b/tests/Appwrite/Services/ProjectTest.php index 104c8232..6cf56662 100644 --- a/tests/Appwrite/Services/ProjectTest.php +++ b/tests/Appwrite/Services/ProjectTest.php @@ -9,6 +9,7 @@ use Appwrite\Enums\ProjectAuthMethodId; use Appwrite\Enums\ProjectKeyScopes; use Appwrite\Enums\ProjectOAuth2GooglePrompt; +use Appwrite\Enums\ProjectOAuth2OidcPrompt; use Appwrite\Enums\ProjectOAuthProviderId; use Appwrite\Enums\ProjectPolicyId; use Appwrite\Enums\ProjectProtocolId; @@ -63,6 +64,7 @@ public function testMethodGet(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -86,6 +88,7 @@ public function testMethodGet(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -159,6 +162,7 @@ public function testMethodUpdateAuthMethod(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -182,6 +186,7 @@ public function testMethodUpdateAuthMethod(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -408,6 +413,7 @@ public function testMethodUpdateLabels(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -431,6 +437,7 @@ public function testMethodUpdateLabels(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -624,6 +631,7 @@ public function testMethodUpdateOAuth2Server(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -647,6 +655,7 @@ public function testMethodUpdateOAuth2Server(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -716,6 +725,27 @@ public function testMethodUpdateOAuth2Apple(): void $this->assertInstanceOf(\Appwrite\Models\OAuth2Apple::class, $response); } + public function testMethodUpdateOAuth2Appwrite(): void + { + $data = array( + "\$id" => "github", + "enabled" => true, + "clientId" => "6a42000000000000b5a0", + "clientSecret" => "b86afd000000000000000000000000000000000000000000000000000ced5f93" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->project->updateOAuth2Appwrite(); + + $this->assertInstanceOf(\Appwrite\Models\OAuth2Appwrite::class, $response); + } + public function testMethodUpdateOAuth2Auth0(): void { $data = array( @@ -1196,7 +1226,8 @@ public function testMethodUpdateOAuth2Oidc(): void "wellKnownURL" => "https://myoauth.com/.well-known/openid-configuration", "authorizationURL" => "https://myoauth.com/oauth2/authorize", "tokenURL" => "https://myoauth.com/oauth2/token", - "userInfoURL" => "https://myoauth.com/oauth2/userinfo" + "userInfoURL" => "https://myoauth.com/oauth2/userinfo", + "prompt" => array() ); $this->client @@ -1990,6 +2021,7 @@ public function testMethodUpdateDenyAliasedEmailPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2013,6 +2045,7 @@ public function testMethodUpdateDenyAliasedEmailPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2072,6 +2105,7 @@ public function testMethodUpdateDenyCorporateEmailPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2095,6 +2129,7 @@ public function testMethodUpdateDenyCorporateEmailPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2154,6 +2189,7 @@ public function testMethodUpdateDenyDisposableEmailPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2177,6 +2213,7 @@ public function testMethodUpdateDenyDisposableEmailPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2236,6 +2273,7 @@ public function testMethodUpdateDenyFreeEmailPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2259,6 +2297,7 @@ public function testMethodUpdateDenyFreeEmailPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2318,6 +2357,7 @@ public function testMethodUpdateMembershipPrivacyPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2341,6 +2381,7 @@ public function testMethodUpdateMembershipPrivacyPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2398,6 +2439,7 @@ public function testMethodUpdatePasswordDictionaryPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2421,6 +2463,7 @@ public function testMethodUpdatePasswordDictionaryPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2480,6 +2523,7 @@ public function testMethodUpdatePasswordHistoryPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2503,6 +2547,7 @@ public function testMethodUpdatePasswordHistoryPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2562,6 +2607,7 @@ public function testMethodUpdatePasswordPersonalDataPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2585,6 +2631,7 @@ public function testMethodUpdatePasswordPersonalDataPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2667,6 +2714,7 @@ public function testMethodUpdateSessionAlertPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2690,6 +2738,7 @@ public function testMethodUpdateSessionAlertPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2749,6 +2798,7 @@ public function testMethodUpdateSessionDurationPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2772,6 +2822,7 @@ public function testMethodUpdateSessionDurationPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2831,6 +2882,7 @@ public function testMethodUpdateSessionInvalidationPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2854,6 +2906,7 @@ public function testMethodUpdateSessionInvalidationPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2913,6 +2966,7 @@ public function testMethodUpdateSessionLimitPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -2936,6 +2990,7 @@ public function testMethodUpdateSessionLimitPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -2995,6 +3050,7 @@ public function testMethodUpdateUserLimitPolicy(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -3018,6 +3074,7 @@ public function testMethodUpdateUserLimitPolicy(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -3103,6 +3160,7 @@ public function testMethodUpdateProtocol(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -3126,6 +3184,7 @@ public function testMethodUpdateProtocol(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -3186,6 +3245,7 @@ public function testMethodUpdateService(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -3209,6 +3269,7 @@ public function testMethodUpdateService(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", @@ -3269,6 +3330,7 @@ public function testMethodUpdateSMTP(): void "pingedAt" => "2020-10-15T06:38:00.000+00:00", "labels" => array(), "status" => "active", + "onboarding" => array(), "authMethods" => array( array( "\$id" => "email-password", @@ -3292,6 +3354,7 @@ public function testMethodUpdateSMTP(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "resourceType" => "project", "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", "projectName" => "My Project", "region" => "fra", "organizationName" => "Acme Inc.", diff --git a/tests/Appwrite/Services/UsageTest.php b/tests/Appwrite/Services/UsageTest.php deleted file mode 100644 index c7ce46cf..00000000 --- a/tests/Appwrite/Services/UsageTest.php +++ /dev/null @@ -1,75 +0,0 @@ -client = Mockery::mock(Client::class); - $this->usage = new Usage($this->client); - } - - public function testMethodListEvents(): void - { - $data = array( - "metric" => "executions", - "interval" => "1d", - "groups" => array( - array( - "time" => "2026-04-09T12:00:00.000+00:00", - "value" => 5000 - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->usage->listEvents( - "" - ); - - $this->assertInstanceOf(\Appwrite\Models\UsageEventList::class, $response); - } - - public function testMethodListGauges(): void - { - $data = array( - "metric" => "files.storage", - "interval" => "1d", - "groups" => array( - array( - "time" => "2026-04-09T12:00:00.000+00:00", - "value" => 5000 - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->usage->listGauges( - "" - ); - - $this->assertInstanceOf(\Appwrite\Models\UsageGaugeList::class, $response); - } - -} From 9f39ef81c0fa5c826ec591632b03370b13483bd7 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 13 Jul 2026 12:10:51 +0530 Subject: [PATCH 2/6] chore: update PHP SDK to 27.0.0 --- src/Appwrite/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Client.php b/src/Appwrite/Client.php index 2787f561..9a1a4cd9 100644 --- a/src/Appwrite/Client.php +++ b/src/Appwrite/Client.php @@ -159,7 +159,7 @@ public function setJWT(string $value): Client */ public function setBearer(string $value): Client { - $this->addHeader('Authorization', $value); + $this->addHeader('Authorization', "Bearer {$value}"); $this->config['bearer'] = $value; $this->key = null; $this->authorization = null; From ab3b10f22985ad62335e0bdd292b61599bbac533 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Thu, 23 Jul 2026 16:17:21 +0530 Subject: [PATCH 3/6] chore: update PHP SDK to 27.1.0 --- CHANGELOG.md | 10 + docs/account.md | 83 ++ docs/apps.md | 315 +++++ docs/backups.md | 11 +- docs/examples/account/delete-consent-token.md | 17 + docs/examples/account/delete-consent.md | 16 + docs/examples/account/get-consent-token.md | 17 + docs/examples/account/get-consent.md | 16 + docs/examples/account/list-consent-tokens.md | 18 + docs/examples/account/list-consents.md | 17 + .../apps/create-installation-token.md | 17 + docs/examples/apps/create-key.md | 16 + docs/examples/apps/create-secret.md | 16 + docs/examples/apps/create.md | 34 + docs/examples/apps/delete-key.md | 17 + docs/examples/apps/delete-secret.md | 17 + docs/examples/apps/delete-tokens.md | 16 + docs/examples/apps/delete.md | 16 + docs/examples/apps/get-installation.md | 17 + docs/examples/apps/get-key.md | 17 + docs/examples/apps/get-secret.md | 17 + docs/examples/apps/get.md | 16 + .../examples/apps/list-installation-scopes.md | 15 + docs/examples/apps/list-installations.md | 18 + docs/examples/apps/list-keys.md | 18 + docs/examples/apps/list-o-auth-2-scopes.md | 15 + docs/examples/apps/list-secrets.md | 18 + docs/examples/apps/list.md | 17 + docs/examples/apps/update-labels.md | 17 + docs/examples/apps/update-team.md | 17 + docs/examples/apps/update.md | 35 + docs/examples/backups/create-restoration.md | 3 +- docs/examples/oauth2/approve.md | 18 + docs/examples/oauth2/authorize-post.md | 29 + docs/examples/oauth2/authorize.md | 29 + .../oauth2/create-device-authorization.md | 20 + docs/examples/oauth2/create-grant.md | 16 + docs/examples/oauth2/create-par.md | 28 + docs/examples/oauth2/create-token.md | 25 + docs/examples/oauth2/get-grant.md | 16 + docs/examples/oauth2/list-organizations.md | 18 + docs/examples/oauth2/list-projects.md | 18 + docs/examples/oauth2/reject.md | 16 + docs/examples/oauth2/revoke.md | 19 + .../organization/create-installation.md | 17 + .../organization/delete-installation.md | 16 + .../examples/organization/get-installation.md | 16 + .../organization/list-installations.md | 17 + .../organization/update-installation.md | 17 + .../project/update-o-auth-2-server.md | 1 + .../examples/sites/get-deployment-download.md | 3 +- docs/examples/tablesdb/create-failover.md | 17 + docs/examples/tablesdb/create.md | 3 +- docs/examples/tablesdb/get-replicas.md | 16 + docs/examples/tablesdb/get-status.md | 16 + docs/examples/tablesdb/list-specifications.md | 15 + docs/examples/tablesdb/update.md | 3 +- docs/examples/teams/create-installation.md | 18 + docs/examples/teams/delete-installation.md | 17 + docs/examples/teams/get-installation.md | 17 + docs/examples/teams/list-installations.md | 18 + docs/examples/teams/update-installation.md | 18 + docs/functions.md | 2 +- docs/oauth2.md | 230 ++++ docs/organization.md | 68 ++ docs/project.md | 1 + docs/sites.md | 1 + docs/tablesdb.md | 49 + docs/teams.md | 73 ++ src/Appwrite/Client.php | 4 +- src/Appwrite/Enums/DatabaseStatus.php | 99 ++ src/Appwrite/Enums/DatabaseType.php | 27 + src/Appwrite/Enums/OrganizationKeyScopes.php | 18 + src/Appwrite/Enums/ProjectKeyScopes.php | 27 + src/Appwrite/Models/ActivityEvent.php | 83 +- src/Appwrite/Models/App.php | 227 ++++ src/Appwrite/Models/AppInstallation.php | 107 ++ src/Appwrite/Models/AppInstallationList.php | 59 + src/Appwrite/Models/AppKey.php | 100 ++ src/Appwrite/Models/AppKeyList.php | 59 + src/Appwrite/Models/AppScope.php | 75 ++ src/Appwrite/Models/AppScopeList.php | 59 + src/Appwrite/Models/AppSecret.php | 100 ++ src/Appwrite/Models/AppSecretList.php | 59 + src/Appwrite/Models/AppSecretPlaintext.php | 100 ++ src/Appwrite/Models/AppsList.php | 59 + src/Appwrite/Models/BillingPlan.php | 7 + src/Appwrite/Models/Database.php | 60 +- src/Appwrite/Models/DatabaseStatus.php | 106 ++ .../Models/DatabaseStatusConnections.php | 54 + src/Appwrite/Models/DatabaseStatusReplica.php | 65 ++ src/Appwrite/Models/DatabaseStatusVolume.php | 68 ++ src/Appwrite/Models/DedicatedDatabase.php | 377 ++++++ .../Models/DedicatedDatabaseMember.php | 68 ++ .../Models/DedicatedDatabaseReplicas.php | 66 ++ .../Models/DedicatedDatabaseSpecification.php | 103 ++ .../DedicatedDatabaseSpecificationList.php | 66 ++ .../DedicatedDatabaseSpecificationPricing.php | 75 ++ src/Appwrite/Models/Oauth2Approve.php | 47 + src/Appwrite/Models/Oauth2Authorize.php | 54 + src/Appwrite/Models/Oauth2Consent.php | 110 ++ src/Appwrite/Models/Oauth2ConsentList.php | 59 + src/Appwrite/Models/Oauth2ConsentToken.php | 117 ++ .../Models/Oauth2ConsentTokenList.php | 59 + .../Models/Oauth2DeviceAuthorization.php | 82 ++ src/Appwrite/Models/Oauth2Grant.php | 124 ++ src/Appwrite/Models/Oauth2Organization.php | 47 + .../Models/Oauth2OrganizationList.php | 59 + src/Appwrite/Models/Oauth2PAR.php | 54 + src/Appwrite/Models/Oauth2Project.php | 61 + src/Appwrite/Models/Oauth2ProjectList.php | 59 + src/Appwrite/Models/Oauth2Reject.php | 47 + src/Appwrite/Models/Oauth2Token.php | 83 ++ src/Appwrite/Models/Project.php | 11 + src/Appwrite/Services/Account.php | 247 ++++ src/Appwrite/Services/Apps.php | 1026 +++++++++++++++++ src/Appwrite/Services/Backups.php | 38 +- src/Appwrite/Services/Functions.php | 5 +- src/Appwrite/Services/Oauth2.php | 782 +++++++++++++ src/Appwrite/Services/Organization.php | 208 ++++ src/Appwrite/Services/Project.php | 4 +- src/Appwrite/Services/Sites.php | 7 +- src/Appwrite/Services/TablesDB.php | 167 ++- src/Appwrite/Services/Teams.php | 218 ++++ tests/Appwrite/Services/AccountTest.php | 164 +++ tests/Appwrite/Services/ActivitiesTest.php | 26 +- tests/Appwrite/Services/AppsTest.php | 754 ++++++++++++ tests/Appwrite/Services/BackupsTest.php | 6 +- tests/Appwrite/Services/DatabasesTest.php | 120 +- tests/Appwrite/Services/Oauth2Test.php | 297 +++++ tests/Appwrite/Services/OrganizationTest.php | 147 ++- tests/Appwrite/Services/ProjectTest.php | 60 +- tests/Appwrite/Services/TablesDBTest.php | 296 +++-- tests/Appwrite/Services/TeamsTest.php | 139 +++ 134 files changed, 9671 insertions(+), 320 deletions(-) create mode 100644 docs/apps.md create mode 100644 docs/examples/account/delete-consent-token.md create mode 100644 docs/examples/account/delete-consent.md create mode 100644 docs/examples/account/get-consent-token.md create mode 100644 docs/examples/account/get-consent.md create mode 100644 docs/examples/account/list-consent-tokens.md create mode 100644 docs/examples/account/list-consents.md create mode 100644 docs/examples/apps/create-installation-token.md create mode 100644 docs/examples/apps/create-key.md create mode 100644 docs/examples/apps/create-secret.md create mode 100644 docs/examples/apps/create.md create mode 100644 docs/examples/apps/delete-key.md create mode 100644 docs/examples/apps/delete-secret.md create mode 100644 docs/examples/apps/delete-tokens.md create mode 100644 docs/examples/apps/delete.md create mode 100644 docs/examples/apps/get-installation.md create mode 100644 docs/examples/apps/get-key.md create mode 100644 docs/examples/apps/get-secret.md create mode 100644 docs/examples/apps/get.md create mode 100644 docs/examples/apps/list-installation-scopes.md create mode 100644 docs/examples/apps/list-installations.md create mode 100644 docs/examples/apps/list-keys.md create mode 100644 docs/examples/apps/list-o-auth-2-scopes.md create mode 100644 docs/examples/apps/list-secrets.md create mode 100644 docs/examples/apps/list.md create mode 100644 docs/examples/apps/update-labels.md create mode 100644 docs/examples/apps/update-team.md create mode 100644 docs/examples/apps/update.md create mode 100644 docs/examples/oauth2/approve.md create mode 100644 docs/examples/oauth2/authorize-post.md create mode 100644 docs/examples/oauth2/authorize.md create mode 100644 docs/examples/oauth2/create-device-authorization.md create mode 100644 docs/examples/oauth2/create-grant.md create mode 100644 docs/examples/oauth2/create-par.md create mode 100644 docs/examples/oauth2/create-token.md create mode 100644 docs/examples/oauth2/get-grant.md create mode 100644 docs/examples/oauth2/list-organizations.md create mode 100644 docs/examples/oauth2/list-projects.md create mode 100644 docs/examples/oauth2/reject.md create mode 100644 docs/examples/oauth2/revoke.md create mode 100644 docs/examples/organization/create-installation.md create mode 100644 docs/examples/organization/delete-installation.md create mode 100644 docs/examples/organization/get-installation.md create mode 100644 docs/examples/organization/list-installations.md create mode 100644 docs/examples/organization/update-installation.md create mode 100644 docs/examples/tablesdb/create-failover.md create mode 100644 docs/examples/tablesdb/get-replicas.md create mode 100644 docs/examples/tablesdb/get-status.md create mode 100644 docs/examples/tablesdb/list-specifications.md create mode 100644 docs/examples/teams/create-installation.md create mode 100644 docs/examples/teams/delete-installation.md create mode 100644 docs/examples/teams/get-installation.md create mode 100644 docs/examples/teams/list-installations.md create mode 100644 docs/examples/teams/update-installation.md create mode 100644 docs/oauth2.md create mode 100644 src/Appwrite/Models/App.php create mode 100644 src/Appwrite/Models/AppInstallation.php create mode 100644 src/Appwrite/Models/AppInstallationList.php create mode 100644 src/Appwrite/Models/AppKey.php create mode 100644 src/Appwrite/Models/AppKeyList.php create mode 100644 src/Appwrite/Models/AppScope.php create mode 100644 src/Appwrite/Models/AppScopeList.php create mode 100644 src/Appwrite/Models/AppSecret.php create mode 100644 src/Appwrite/Models/AppSecretList.php create mode 100644 src/Appwrite/Models/AppSecretPlaintext.php create mode 100644 src/Appwrite/Models/AppsList.php create mode 100644 src/Appwrite/Models/DatabaseStatus.php create mode 100644 src/Appwrite/Models/DatabaseStatusConnections.php create mode 100644 src/Appwrite/Models/DatabaseStatusReplica.php create mode 100644 src/Appwrite/Models/DatabaseStatusVolume.php create mode 100644 src/Appwrite/Models/DedicatedDatabase.php create mode 100644 src/Appwrite/Models/DedicatedDatabaseMember.php create mode 100644 src/Appwrite/Models/DedicatedDatabaseReplicas.php create mode 100644 src/Appwrite/Models/DedicatedDatabaseSpecification.php create mode 100644 src/Appwrite/Models/DedicatedDatabaseSpecificationList.php create mode 100644 src/Appwrite/Models/DedicatedDatabaseSpecificationPricing.php create mode 100644 src/Appwrite/Models/Oauth2Approve.php create mode 100644 src/Appwrite/Models/Oauth2Authorize.php create mode 100644 src/Appwrite/Models/Oauth2Consent.php create mode 100644 src/Appwrite/Models/Oauth2ConsentList.php create mode 100644 src/Appwrite/Models/Oauth2ConsentToken.php create mode 100644 src/Appwrite/Models/Oauth2ConsentTokenList.php create mode 100644 src/Appwrite/Models/Oauth2DeviceAuthorization.php create mode 100644 src/Appwrite/Models/Oauth2Grant.php create mode 100644 src/Appwrite/Models/Oauth2Organization.php create mode 100644 src/Appwrite/Models/Oauth2OrganizationList.php create mode 100644 src/Appwrite/Models/Oauth2PAR.php create mode 100644 src/Appwrite/Models/Oauth2Project.php create mode 100644 src/Appwrite/Models/Oauth2ProjectList.php create mode 100644 src/Appwrite/Models/Oauth2Reject.php create mode 100644 src/Appwrite/Models/Oauth2Token.php create mode 100644 src/Appwrite/Services/Apps.php create mode 100644 src/Appwrite/Services/Oauth2.php create mode 100644 tests/Appwrite/Services/AppsTest.php create mode 100644 tests/Appwrite/Services/Oauth2Test.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a41a9e4..099e71cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## 27.1.0 + +* Added: `Apps` service for managing OAuth2 applications, keys, and installations +* Added: `OAuth2` service with authorize, grant, device authorization, and consent flows +* Added: `Account` OAuth2 consent methods `listConsents`, `getConsent`, `deleteConsent`, and consent token methods +* Added: app installation management methods to `Organization` and `Teams` services +* Added: `installationAccessTokenDuration` parameter to `Project::updateOAuth2Server` +* Added: `token` parameter to `Sites::getDeploymentDownload` +* Added: `oauth2.introspect` and organization installation key scopes + ## 27.0.0 * Breaking: Removed `Health` service with its models and enums diff --git a/docs/account.md b/docs/account.md index 31ac8d2e..7600b611 100644 --- a/docs/account.md +++ b/docs/account.md @@ -24,6 +24,89 @@ POST https://cloud.appwrite.io/v1/account | name | string | User name. Max length: 128 chars. | | +```http request +GET https://cloud.appwrite.io/v1/account/consents +``` + +** Get a list of the OAuth2 consents the current user has given to third-party apps. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. | [] | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +GET https://cloud.appwrite.io/v1/account/consents/{consentId} +``` + +** Get an OAuth2 consent the current user has given to a third-party app by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| consentId | string | **Required** Consent unique ID. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/account/consents/{consentId} +``` + +** Delete an OAuth2 consent by its unique ID. All token families issued under the consent are revoked, and the app must ask for consent again to regain access. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| consentId | string | **Required** Consent unique ID. | | + + +```http request +GET https://cloud.appwrite.io/v1/account/consents/{consentId}/tokens +``` + +** Get a list of the token families issued under an OAuth2 consent. Each entry represents one authorized device or session; the token secrets themselves are never returned. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| consentId | string | **Required** Consent unique ID. | | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. | [] | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +GET https://cloud.appwrite.io/v1/account/consents/{consentId}/tokens/{tokenId} +``` + +** Get a token family issued under an OAuth2 consent by its unique ID. The token secrets themselves are never returned. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| consentId | string | **Required** Consent unique ID. | | +| tokenId | string | **Required** Token unique ID. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/account/consents/{consentId}/tokens/{tokenId} +``` + +** Delete a token family issued under an OAuth2 consent by its unique ID. The access and refresh tokens of the family stop working immediately; other token families and the consent itself are unaffected. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| consentId | string | **Required** Consent unique ID. | | +| tokenId | string | **Required** Token unique ID. | | + + ```http request PATCH https://cloud.appwrite.io/v1/account/email ``` diff --git a/docs/apps.md b/docs/apps.md new file mode 100644 index 00000000..a8d9a2e8 --- /dev/null +++ b/docs/apps.md @@ -0,0 +1,315 @@ +# Apps Service + + +```http request +GET https://cloud.appwrite.io/v1/apps +``` + +** List applications. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. | [] | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +POST https://cloud.appwrite.io/v1/apps +``` + +** Create a new application. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | Application ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | +| name | string | Application name. | | +| description | string | Application description shown to users during OAuth2 consent. | | +| clientUri | string | Application homepage URL shown to users during OAuth2 consent. | | +| logoUri | string | Application logo URL shown to users during OAuth2 consent. | | +| privacyPolicyUrl | string | Application privacy policy URL shown to users during OAuth2 consent. | | +| termsUrl | string | Application terms of service URL shown to users during OAuth2 consent. | | +| contacts | array | Application support or security contact emails. Maximum of 100 contacts are allowed. | [] | +| tagline | string | Application tagline shown to users during OAuth2 consent. | | +| tags | array | Application tags shown to users during OAuth2 consent. Maximum of 100 tags are allowed, each up to 64 characters long. | [] | +| images | array | Application image URLs shown to users during OAuth2 consent. Maximum of 100 images are allowed. | [] | +| supportUrl | string | Application support URL shown to users during OAuth2 consent. | | +| dataDeletionUrl | string | Application data deletion URL shown to users during OAuth2 consent. | | +| redirectUris | array | Redirect URIs. Each must be an https URL, an http loopback URL (localhost, 127.0.0.1, [::1]), or a private-use scheme URI (e.g. com.example.app:/oauth), and must not contain a fragment. | | +| postLogoutRedirectUris | array | Post-logout redirect URIs for OpenID Connect RP-Initiated Logout. Each must be an https URL, an http loopback URL, or a private-use scheme URI, and must not contain a fragment. After ending the user session, the logout endpoint only redirects to URIs in this list. | [] | +| enabled | boolean | Is application enabled? | 1 | +| type | string | OAuth2 client type. Use `public` for SPAs, mobile, and native apps that cannot keep a `client_secret` — PKCE is then required at the token endpoint. Use `confidential` for server-side clients that present a `client_secret`. Defaults to `confidential`. | confidential | +| deviceFlow | boolean | Allow this client to use the OAuth2 Device Authorization Grant (RFC 8628) for input-constrained devices such as TVs and CLIs. Defaults to false. | | +| teamId | string | Team unique ID. | | + + +```http request +GET https://cloud.appwrite.io/v1/apps/scopes/installations +``` + +** List scopes an application can request when installed on a team. ** + + +```http request +GET https://cloud.appwrite.io/v1/apps/scopes/oauth2 +``` + +** List scopes an application can request during the OAuth2 flow. ** + + +```http request +GET https://cloud.appwrite.io/v1/apps/{appId} +``` + +** Get an application by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID or HTTPS client ID metadata document URL. | | + + +```http request +PUT https://cloud.appwrite.io/v1/apps/{appId} +``` + +** Update an application by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| name | string | Application name. | | +| description | string | Application description shown to users during OAuth2 consent. | | +| clientUri | string | Application homepage URL shown to users during OAuth2 consent. | | +| logoUri | string | Application logo URL shown to users during OAuth2 consent. | | +| privacyPolicyUrl | string | Application privacy policy URL shown to users during OAuth2 consent. | | +| termsUrl | string | Application terms of service URL shown to users during OAuth2 consent. | | +| contacts | array | Application support or security contact emails. Maximum of 100 contacts are allowed. | [] | +| tagline | string | Application tagline shown to users during OAuth2 consent. | | +| tags | array | Application tags shown to users during OAuth2 consent. Maximum of 100 tags are allowed, each up to 64 characters long. | [] | +| images | array | Application image URLs shown to users during OAuth2 consent. Maximum of 100 images are allowed. | [] | +| supportUrl | string | Application support URL shown to users during OAuth2 consent. | | +| dataDeletionUrl | string | Application data deletion URL shown to users during OAuth2 consent. | | +| enabled | boolean | Is application enabled? | 1 | +| redirectUris | array | Redirect URIs. Each must be an https URL, an http loopback URL (localhost, 127.0.0.1, [::1]), or a private-use scheme URI (e.g. com.example.app:/oauth), and must not contain a fragment. | [] | +| postLogoutRedirectUris | array | Post-logout redirect URIs for OpenID Connect RP-Initiated Logout. Each must be an https URL, an http loopback URL, or a private-use scheme URI, and must not contain a fragment. After ending the user session, the logout endpoint only redirects to URIs in this list. | [] | +| type | string | OAuth2 client type. Use `public` for SPAs, mobile, and native apps that cannot keep a `client_secret` — PKCE is then required at the token endpoint. Use `confidential` for server-side clients that present a `client_secret`. Defaults to `confidential`. | confidential | +| deviceFlow | boolean | Allow this client to use the OAuth2 Device Authorization Grant (RFC 8628) for input-constrained devices such as TVs and CLIs. Defaults to false. | | +| installationScopes | array | Scopes the application requests when installed on a team. Organization-level and project-level scopes only; use the list scopes endpoint with `type=installation` to discover available values. Maximum of 100 scopes are allowed. | [] | +| installationRedirectUrl | string | URL users are redirected to after creating or updating an installation of this application. Must be an https URL, an http loopback URL (localhost, 127.0.0.1, [::1]), or a private-use scheme URI, and must not contain a fragment. Leave empty for no redirect. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/apps/{appId} +``` + +** Delete an application by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | + + +```http request +GET https://cloud.appwrite.io/v1/apps/{appId}/installations +``` + +** List installations of an application. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. | [] | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +GET https://cloud.appwrite.io/v1/apps/{appId}/installations/{installationId} +``` + +** Get an installation of an application by its unique ID. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| installationId | string | **Required** Installation unique ID. | | + + +```http request +POST https://cloud.appwrite.io/v1/apps/{appId}/installations/{installationId}/tokens +``` + +** Create a token for an installation of an application. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. The returned token carries the scopes and authorization details granted to the installation, and can be used as an `Authorization: Bearer` header everywhere OAuth2 access tokens are accepted. Multiple tokens can be active for the same installation at once; each token stays valid until it expires or the installation is updated or deleted. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| installationId | string | **Required** Installation unique ID. | | + + +```http request +GET https://cloud.appwrite.io/v1/apps/{appId}/keys +``` + +** List app keys for an application. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. | [] | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +POST https://cloud.appwrite.io/v1/apps/{appId}/keys +``` + +** Create a new app key for an application. App keys carry no scopes; send one in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header to list the application's installations and create installation access tokens. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | + + +```http request +GET https://cloud.appwrite.io/v1/apps/{appId}/keys/{keyId} +``` + +** Get an app key by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| keyId | string | **Required** App key unique ID. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/apps/{appId}/keys/{keyId} +``` + +** Delete an app key by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| keyId | string | **Required** App key unique ID. | | + + +```http request +PUT https://cloud.appwrite.io/v1/apps/{appId}/labels +``` + +** Update the labels of an application. Labels are read-only for clients; only a server SDK using a project API key can set them. Replaces the previous labels. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| labels | array | Array of application labels. Replaces the previous labels. Maximum of 1000 labels are allowed, each up to 36 alphanumeric characters long. | | + + +```http request +GET https://cloud.appwrite.io/v1/apps/{appId}/secrets +``` + +** List client secrets for an application. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. | [] | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +POST https://cloud.appwrite.io/v1/apps/{appId}/secrets +``` + +** Create a new client secret for an application. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | + + +```http request +GET https://cloud.appwrite.io/v1/apps/{appId}/secrets/{secretId} +``` + +** Get an application client secret by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| secretId | string | **Required** Secret unique ID. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/apps/{appId}/secrets/{secretId} +``` + +** Delete an application client secret by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| secretId | string | **Required** Secret unique ID. | | + + +```http request +PATCH https://cloud.appwrite.io/v1/apps/{appId}/team +``` + +** Transfer an application to another team by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| teamId | string | Team ID of the team to transfer application to. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/apps/{appId}/tokens +``` + +** Revoke all tokens for an application by its unique ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | + diff --git a/docs/backups.md b/docs/backups.md index 3ad1f4eb..3ba25e1d 100644 --- a/docs/backups.md +++ b/docs/backups.md @@ -135,7 +135,13 @@ POST https://cloud.appwrite.io/v1/backups/restoration ** Create and trigger a new restoration for a backup on a project. -When restoring a DocumentsDB or VectorsDB database to a new resource, pass `newSpecification` to provision the restored database on a different specification than the archived one (for example, restoring onto a larger or smaller dedicated database). Use `serverless` to restore onto the shared pool, or a dedicated specification slug to restore onto a dedicated database of that size. The specification must be permitted by the organization's plan. `newSpecification` is not supported for legacy/TablesDB databases or for bucket restores. +For a backup of one database, the restoration resolves its destination before it is queued. Pass `newResourceId` to restore into that database ID, including the archived database ID to overwrite it. When `newResourceId` is omitted, a new database ID is generated and returned in `options`. + +The restoration migration records the archived database in `resourceId` and `resourceType`, and the resolved database in `destinationResourceId` and `destinationResourceType`. Database types are stored canonically as `database`, `documentsdb`, or `vectorsdb`. Project-wide restorations leave these fields empty because they do not have a single source or destination database. + +To list every migration related to one database, use its canonical type in a nested `OR(AND(...), AND(...), AND(...))` across the root, parent, and destination relation pairs: `(resourceType, resourceId)`, `(parentResourceType, parentResourceId)`, and `(destinationResourceType, destinationResourceId)`. Legacy and TablesDB databases use `database`; the operational `resourceType` of a table migration is not rewritten to `tablesdb`. + +When restoring a DocumentsDB or VectorsDB database to a new resource from a dedicated source, the restore provisions a fresh dedicated backing database at the source database's own specification. ** ### Parameters @@ -144,9 +150,8 @@ When restoring a DocumentsDB or VectorsDB database to a new resource, pass `newS | --- | --- | --- | --- | | archiveId | string | Backup archive ID to restore | | | services | array | Array of services to restore | | -| newResourceId | string | Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | +| newResourceId | string | Destination resource ID. Omit to generate a new ID, or pass the archived resource ID to overwrite it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | newResourceName | string | Database name. Max length: 128 chars. | | -| newSpecification | string | Specification to provision the restored database on, when restoring a DocumentsDB or VectorsDB database to a new resource. Defaults to the archived database's specification. Use `serverless` for the shared pool or a dedicated specification slug. | | ```http request diff --git a/docs/examples/account/delete-consent-token.md b/docs/examples/account/delete-consent-token.md new file mode 100644 index 00000000..1cb8fcce --- /dev/null +++ b/docs/examples/account/delete-consent-token.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$account = new Account($client); + +$result = $account->deleteConsentToken( + consentId: '', + tokenId: '' +);``` diff --git a/docs/examples/account/delete-consent.md b/docs/examples/account/delete-consent.md new file mode 100644 index 00000000..0aebb0a5 --- /dev/null +++ b/docs/examples/account/delete-consent.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$account = new Account($client); + +$result = $account->deleteConsent( + consentId: '' +);``` diff --git a/docs/examples/account/get-consent-token.md b/docs/examples/account/get-consent-token.md new file mode 100644 index 00000000..dda1a1ca --- /dev/null +++ b/docs/examples/account/get-consent-token.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$account = new Account($client); + +$result = $account->getConsentToken( + consentId: '', + tokenId: '' +);``` diff --git a/docs/examples/account/get-consent.md b/docs/examples/account/get-consent.md new file mode 100644 index 00000000..f6ce59fc --- /dev/null +++ b/docs/examples/account/get-consent.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$account = new Account($client); + +$result = $account->getConsent( + consentId: '' +);``` diff --git a/docs/examples/account/list-consent-tokens.md b/docs/examples/account/list-consent-tokens.md new file mode 100644 index 00000000..0088745c --- /dev/null +++ b/docs/examples/account/list-consent-tokens.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$account = new Account($client); + +$result = $account->listConsentTokens( + consentId: '', + queries: [], // optional + total: false // optional +);``` diff --git a/docs/examples/account/list-consents.md b/docs/examples/account/list-consents.md new file mode 100644 index 00000000..b2c63a30 --- /dev/null +++ b/docs/examples/account/list-consents.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$account = new Account($client); + +$result = $account->listConsents( + queries: [], // optional + total: false // optional +);``` diff --git a/docs/examples/apps/create-installation-token.md b/docs/examples/apps/create-installation-token.md new file mode 100644 index 00000000..ef4ca380 --- /dev/null +++ b/docs/examples/apps/create-installation-token.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$apps = new Apps($client); + +$result = $apps->createInstallationToken( + appId: '', + installationId: '' +);``` diff --git a/docs/examples/apps/create-key.md b/docs/examples/apps/create-key.md new file mode 100644 index 00000000..7690aeaa --- /dev/null +++ b/docs/examples/apps/create-key.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->createKey( + appId: '' +);``` diff --git a/docs/examples/apps/create-secret.md b/docs/examples/apps/create-secret.md new file mode 100644 index 00000000..cff66b3b --- /dev/null +++ b/docs/examples/apps/create-secret.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->createSecret( + appId: '' +);``` diff --git a/docs/examples/apps/create.md b/docs/examples/apps/create.md new file mode 100644 index 00000000..8c7c2869 --- /dev/null +++ b/docs/examples/apps/create.md @@ -0,0 +1,34 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->create( + appId: '', + name: '', + redirectUris: [], + description: '', // optional + clientUri: 'https://example.com', // optional + logoUri: 'https://example.com', // optional + privacyPolicyUrl: 'https://example.com', // optional + termsUrl: 'https://example.com', // optional + contacts: [], // optional + tagline: '', // optional + tags: [], // optional + images: [], // optional + supportUrl: 'https://example.com', // optional + dataDeletionUrl: 'https://example.com', // optional + postLogoutRedirectUris: [], // optional + enabled: false, // optional + type: 'public', // optional + deviceFlow: false, // optional + teamId: '' // optional +);``` diff --git a/docs/examples/apps/delete-key.md b/docs/examples/apps/delete-key.md new file mode 100644 index 00000000..d07194eb --- /dev/null +++ b/docs/examples/apps/delete-key.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->deleteKey( + appId: '', + keyId: '' +);``` diff --git a/docs/examples/apps/delete-secret.md b/docs/examples/apps/delete-secret.md new file mode 100644 index 00000000..df614d6a --- /dev/null +++ b/docs/examples/apps/delete-secret.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->deleteSecret( + appId: '', + secretId: '' +);``` diff --git a/docs/examples/apps/delete-tokens.md b/docs/examples/apps/delete-tokens.md new file mode 100644 index 00000000..200cb924 --- /dev/null +++ b/docs/examples/apps/delete-tokens.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->deleteTokens( + appId: '' +);``` diff --git a/docs/examples/apps/delete.md b/docs/examples/apps/delete.md new file mode 100644 index 00000000..38cfcf55 --- /dev/null +++ b/docs/examples/apps/delete.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->delete( + appId: '' +);``` diff --git a/docs/examples/apps/get-installation.md b/docs/examples/apps/get-installation.md new file mode 100644 index 00000000..63de2616 --- /dev/null +++ b/docs/examples/apps/get-installation.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$apps = new Apps($client); + +$result = $apps->getInstallation( + appId: '', + installationId: '' +);``` diff --git a/docs/examples/apps/get-key.md b/docs/examples/apps/get-key.md new file mode 100644 index 00000000..78e30e19 --- /dev/null +++ b/docs/examples/apps/get-key.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->getKey( + appId: '', + keyId: '' +);``` diff --git a/docs/examples/apps/get-secret.md b/docs/examples/apps/get-secret.md new file mode 100644 index 00000000..ef4c1d4f --- /dev/null +++ b/docs/examples/apps/get-secret.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->getSecret( + appId: '', + secretId: '' +);``` diff --git a/docs/examples/apps/get.md b/docs/examples/apps/get.md new file mode 100644 index 00000000..7c9ce18a --- /dev/null +++ b/docs/examples/apps/get.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->get( + appId: '' +);``` diff --git a/docs/examples/apps/list-installation-scopes.md b/docs/examples/apps/list-installation-scopes.md new file mode 100644 index 00000000..f60f6c51 --- /dev/null +++ b/docs/examples/apps/list-installation-scopes.md @@ -0,0 +1,15 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->listInstallationScopes(); +``` diff --git a/docs/examples/apps/list-installations.md b/docs/examples/apps/list-installations.md new file mode 100644 index 00000000..fbdff242 --- /dev/null +++ b/docs/examples/apps/list-installations.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$apps = new Apps($client); + +$result = $apps->listInstallations( + appId: '', + queries: [], // optional + total: false // optional +);``` diff --git a/docs/examples/apps/list-keys.md b/docs/examples/apps/list-keys.md new file mode 100644 index 00000000..8d816537 --- /dev/null +++ b/docs/examples/apps/list-keys.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->listKeys( + appId: '', + queries: [], // optional + total: false // optional +);``` diff --git a/docs/examples/apps/list-o-auth-2-scopes.md b/docs/examples/apps/list-o-auth-2-scopes.md new file mode 100644 index 00000000..4bcfa44b --- /dev/null +++ b/docs/examples/apps/list-o-auth-2-scopes.md @@ -0,0 +1,15 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->listOAuth2Scopes(); +``` diff --git a/docs/examples/apps/list-secrets.md b/docs/examples/apps/list-secrets.md new file mode 100644 index 00000000..341fa345 --- /dev/null +++ b/docs/examples/apps/list-secrets.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->listSecrets( + appId: '', + queries: [], // optional + total: false // optional +);``` diff --git a/docs/examples/apps/list.md b/docs/examples/apps/list.md new file mode 100644 index 00000000..9add376d --- /dev/null +++ b/docs/examples/apps/list.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->list( + queries: [], // optional + total: false // optional +);``` diff --git a/docs/examples/apps/update-labels.md b/docs/examples/apps/update-labels.md new file mode 100644 index 00000000..e3786e42 --- /dev/null +++ b/docs/examples/apps/update-labels.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$apps = new Apps($client); + +$result = $apps->updateLabels( + appId: '', + labels: [] +);``` diff --git a/docs/examples/apps/update-team.md b/docs/examples/apps/update-team.md new file mode 100644 index 00000000..76ea6ce2 --- /dev/null +++ b/docs/examples/apps/update-team.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->updateTeam( + appId: '', + teamId: '' +);``` diff --git a/docs/examples/apps/update.md b/docs/examples/apps/update.md new file mode 100644 index 00000000..5d914c74 --- /dev/null +++ b/docs/examples/apps/update.md @@ -0,0 +1,35 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$apps = new Apps($client); + +$result = $apps->update( + appId: '', + name: '', + description: '', // optional + clientUri: 'https://example.com', // optional + logoUri: 'https://example.com', // optional + privacyPolicyUrl: 'https://example.com', // optional + termsUrl: 'https://example.com', // optional + contacts: [], // optional + tagline: '', // optional + tags: [], // optional + images: [], // optional + supportUrl: 'https://example.com', // optional + dataDeletionUrl: 'https://example.com', // optional + enabled: false, // optional + redirectUris: [], // optional + postLogoutRedirectUris: [], // optional + type: 'public', // optional + deviceFlow: false, // optional + installationScopes: [], // optional + installationRedirectUrl: 'https://example.com' // optional +);``` diff --git a/docs/examples/backups/create-restoration.md b/docs/examples/backups/create-restoration.md index e572dd47..61d9e0b2 100644 --- a/docs/examples/backups/create-restoration.md +++ b/docs/examples/backups/create-restoration.md @@ -16,6 +16,5 @@ $result = $backups->createRestoration( archiveId: '', services: [BackupServices::DATABASES()], newResourceId: '', // optional - newResourceName: '', // optional - newSpecification: 'serverless' // optional + newResourceName: '' // optional );``` diff --git a/docs/examples/oauth2/approve.md b/docs/examples/oauth2/approve.md new file mode 100644 index 00000000..f3c77d1a --- /dev/null +++ b/docs/examples/oauth2/approve.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->approve( + grantId: '', + authorizationDetails: '', // optional + scope: '' // optional +);``` diff --git a/docs/examples/oauth2/authorize-post.md b/docs/examples/oauth2/authorize-post.md new file mode 100644 index 00000000..8f2b1251 --- /dev/null +++ b/docs/examples/oauth2/authorize-post.md @@ -0,0 +1,29 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->authorizePost( + clientId: '', // optional + redirectUri: 'https://example.com', // optional + responseType: '', // optional + scope: '', // optional + state: '', // optional + nonce: '', // optional + codeChallenge: '', // optional + codeChallengeMethod: 's256', // optional + prompt: '', // optional + maxAge: 0, // optional + authorizationDetails: '', // optional + resource: '', // optional + audience: '', // optional + requestUri: '' // optional +);``` diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md new file mode 100644 index 00000000..c0217125 --- /dev/null +++ b/docs/examples/oauth2/authorize.md @@ -0,0 +1,29 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->authorize( + clientId: '', // optional + redirectUri: 'https://example.com', // optional + responseType: '', // optional + scope: '', // optional + state: '', // optional + nonce: '', // optional + codeChallenge: '', // optional + codeChallengeMethod: 's256', // optional + prompt: '', // optional + maxAge: 0, // optional + authorizationDetails: '', // optional + resource: '', // optional + audience: '', // optional + requestUri: '' // optional +);``` diff --git a/docs/examples/oauth2/create-device-authorization.md b/docs/examples/oauth2/create-device-authorization.md new file mode 100644 index 00000000..6da66a8b --- /dev/null +++ b/docs/examples/oauth2/create-device-authorization.md @@ -0,0 +1,20 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->createDeviceAuthorization( + clientId: '', // optional + scope: '', // optional + authorizationDetails: '', // optional + resource: '', // optional + audience: '' // optional +);``` diff --git a/docs/examples/oauth2/create-grant.md b/docs/examples/oauth2/create-grant.md new file mode 100644 index 00000000..598470f6 --- /dev/null +++ b/docs/examples/oauth2/create-grant.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->createGrant( + userCode: '' +);``` diff --git a/docs/examples/oauth2/create-par.md b/docs/examples/oauth2/create-par.md new file mode 100644 index 00000000..ca770f1b --- /dev/null +++ b/docs/examples/oauth2/create-par.md @@ -0,0 +1,28 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->createPAR( + clientId: '', + redirectUri: 'https://example.com', + responseType: 'code', + scope: '', // optional + state: '', // optional + nonce: '', // optional + codeChallenge: '', // optional + codeChallengeMethod: 's256', // optional + prompt: '', // optional + maxAge: 0, // optional + authorizationDetails: '', // optional + resource: '', // optional + audience: '' // optional +);``` diff --git a/docs/examples/oauth2/create-token.md b/docs/examples/oauth2/create-token.md new file mode 100644 index 00000000..61905d60 --- /dev/null +++ b/docs/examples/oauth2/create-token.md @@ -0,0 +1,25 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->createToken( + grantType: '', + code: '', // optional + refreshToken: '', // optional + deviceCode: '', // optional + clientId: '', // optional + clientSecret: '', // optional + codeVerifier: '', // optional + redirectUri: 'https://example.com', // optional + resource: '', // optional + audience: '' // optional +);``` diff --git a/docs/examples/oauth2/get-grant.md b/docs/examples/oauth2/get-grant.md new file mode 100644 index 00000000..b4979828 --- /dev/null +++ b/docs/examples/oauth2/get-grant.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->getGrant( + grantId: '' +);``` diff --git a/docs/examples/oauth2/list-organizations.md b/docs/examples/oauth2/list-organizations.md new file mode 100644 index 00000000..1c2fb1c4 --- /dev/null +++ b/docs/examples/oauth2/list-organizations.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->listOrganizations( + limit: 1, // optional + offset: 0, // optional + search: '' // optional +);``` diff --git a/docs/examples/oauth2/list-projects.md b/docs/examples/oauth2/list-projects.md new file mode 100644 index 00000000..ea4ff032 --- /dev/null +++ b/docs/examples/oauth2/list-projects.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->listProjects( + limit: 1, // optional + offset: 0, // optional + search: '' // optional +);``` diff --git a/docs/examples/oauth2/reject.md b/docs/examples/oauth2/reject.md new file mode 100644 index 00000000..65deab84 --- /dev/null +++ b/docs/examples/oauth2/reject.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->reject( + grantId: '' +);``` diff --git a/docs/examples/oauth2/revoke.md b/docs/examples/oauth2/revoke.md new file mode 100644 index 00000000..97c7b861 --- /dev/null +++ b/docs/examples/oauth2/revoke.md @@ -0,0 +1,19 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setSession('') // The user session to authenticate with + ->setProject(''); // Your project ID + +$oauth2 = new Oauth2($client); + +$result = $oauth2->revoke( + token: '', + tokenTypeHint: 'access_token', // optional + clientId: '', // optional + clientSecret: '' // optional +);``` diff --git a/docs/examples/organization/create-installation.md b/docs/examples/organization/create-installation.md new file mode 100644 index 00000000..51855c47 --- /dev/null +++ b/docs/examples/organization/create-installation.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$organization = new Organization($client); + +$result = $organization->createInstallation( + appId: '', + authorizationDetails: '' // optional +);``` diff --git a/docs/examples/organization/delete-installation.md b/docs/examples/organization/delete-installation.md new file mode 100644 index 00000000..23b8e692 --- /dev/null +++ b/docs/examples/organization/delete-installation.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$organization = new Organization($client); + +$result = $organization->deleteInstallation( + installationId: '' +);``` diff --git a/docs/examples/organization/get-installation.md b/docs/examples/organization/get-installation.md new file mode 100644 index 00000000..5e4b6763 --- /dev/null +++ b/docs/examples/organization/get-installation.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$organization = new Organization($client); + +$result = $organization->getInstallation( + installationId: '' +);``` diff --git a/docs/examples/organization/list-installations.md b/docs/examples/organization/list-installations.md new file mode 100644 index 00000000..170243d3 --- /dev/null +++ b/docs/examples/organization/list-installations.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$organization = new Organization($client); + +$result = $organization->listInstallations( + queries: [], // optional + total: false // optional +);``` diff --git a/docs/examples/organization/update-installation.md b/docs/examples/organization/update-installation.md new file mode 100644 index 00000000..a35f797e --- /dev/null +++ b/docs/examples/organization/update-installation.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$organization = new Organization($client); + +$result = $organization->updateInstallation( + installationId: '', + authorizationDetails: '' // optional +);``` diff --git a/docs/examples/project/update-o-auth-2-server.md b/docs/examples/project/update-o-auth-2-server.md index 9c3eb9a8..4a7782f2 100644 --- a/docs/examples/project/update-o-auth-2-server.md +++ b/docs/examples/project/update-o-auth-2-server.md @@ -20,6 +20,7 @@ $result = $project->updateOAuth2Server( refreshTokenDuration: 60, // optional publicAccessTokenDuration: 60, // optional publicRefreshTokenDuration: 60, // optional + installationAccessTokenDuration: 60, // optional confidentialPkce: false, // optional verificationUrl: 'https://example.com', // optional userCodeLength: 6, // optional diff --git a/docs/examples/sites/get-deployment-download.md b/docs/examples/sites/get-deployment-download.md index 5582e964..bfa02f11 100644 --- a/docs/examples/sites/get-deployment-download.md +++ b/docs/examples/sites/get-deployment-download.md @@ -15,5 +15,6 @@ $sites = new Sites($client); $result = $sites->getDeploymentDownload( siteId: '', deploymentId: '', - type: DeploymentDownloadType::SOURCE() // optional + type: DeploymentDownloadType::SOURCE(), // optional + token: '' // optional );``` diff --git a/docs/examples/tablesdb/create-failover.md b/docs/examples/tablesdb/create-failover.md new file mode 100644 index 00000000..fbd2837b --- /dev/null +++ b/docs/examples/tablesdb/create-failover.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->createFailover( + databaseId: '', + targetReplicaId: '' // optional +);``` diff --git a/docs/examples/tablesdb/create.md b/docs/examples/tablesdb/create.md index 9cbbf307..87c81dd2 100644 --- a/docs/examples/tablesdb/create.md +++ b/docs/examples/tablesdb/create.md @@ -15,5 +15,6 @@ $result = $tablesDB->create( databaseId: '', name: '', enabled: false, // optional - specification: 'serverless' // optional + specification: 'serverless', // optional + replicas: 0 // optional );``` diff --git a/docs/examples/tablesdb/get-replicas.md b/docs/examples/tablesdb/get-replicas.md new file mode 100644 index 00000000..0bc85769 --- /dev/null +++ b/docs/examples/tablesdb/get-replicas.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->getReplicas( + databaseId: '' +);``` diff --git a/docs/examples/tablesdb/get-status.md b/docs/examples/tablesdb/get-status.md new file mode 100644 index 00000000..e7a227c5 --- /dev/null +++ b/docs/examples/tablesdb/get-status.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->getStatus( + databaseId: '' +);``` diff --git a/docs/examples/tablesdb/list-specifications.md b/docs/examples/tablesdb/list-specifications.md new file mode 100644 index 00000000..b4080072 --- /dev/null +++ b/docs/examples/tablesdb/list-specifications.md @@ -0,0 +1,15 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->listSpecifications(); +``` diff --git a/docs/examples/tablesdb/update.md b/docs/examples/tablesdb/update.md index 126b3caf..e6c703af 100644 --- a/docs/examples/tablesdb/update.md +++ b/docs/examples/tablesdb/update.md @@ -14,5 +14,6 @@ $tablesDB = new TablesDB($client); $result = $tablesDB->update( databaseId: '', name: '', // optional - enabled: false // optional + enabled: false, // optional + replicas: 0 // optional );``` diff --git a/docs/examples/teams/create-installation.md b/docs/examples/teams/create-installation.md new file mode 100644 index 00000000..e462cf6b --- /dev/null +++ b/docs/examples/teams/create-installation.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$teams = new Teams($client); + +$result = $teams->createInstallation( + teamId: '', + appId: '', + authorizationDetails: '' // optional +);``` diff --git a/docs/examples/teams/delete-installation.md b/docs/examples/teams/delete-installation.md new file mode 100644 index 00000000..091ae091 --- /dev/null +++ b/docs/examples/teams/delete-installation.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$teams = new Teams($client); + +$result = $teams->deleteInstallation( + teamId: '', + installationId: '' +);``` diff --git a/docs/examples/teams/get-installation.md b/docs/examples/teams/get-installation.md new file mode 100644 index 00000000..440afa82 --- /dev/null +++ b/docs/examples/teams/get-installation.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$teams = new Teams($client); + +$result = $teams->getInstallation( + teamId: '', + installationId: '' +);``` diff --git a/docs/examples/teams/list-installations.md b/docs/examples/teams/list-installations.md new file mode 100644 index 00000000..678ab4bc --- /dev/null +++ b/docs/examples/teams/list-installations.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$teams = new Teams($client); + +$result = $teams->listInstallations( + teamId: '', + queries: [], // optional + total: false // optional +);``` diff --git a/docs/examples/teams/update-installation.md b/docs/examples/teams/update-installation.md new file mode 100644 index 00000000..36cdd030 --- /dev/null +++ b/docs/examples/teams/update-installation.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$teams = new Teams($client); + +$result = $teams->updateInstallation( + teamId: '', + installationId: '', + authorizationDetails: '' // optional +);``` diff --git a/docs/functions.md b/docs/functions.md index 86be1ee9..eb12a051 100644 --- a/docs/functions.md +++ b/docs/functions.md @@ -113,7 +113,7 @@ PUT https://cloud.appwrite.io/v1/functions/{functionId} | providerBranches | array | List of branch name patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all branches. | | | providerPaths | array | List of file path patterns to trigger automatic deployments. Supports wildcards. Leave empty to deploy on all file changes. | | | buildSpecification | string | Build specification for the function deployments. | | -| runtimeSpecification | string | Runtime specification for the function executions. | [] | +| runtimeSpecification | string | Runtime specification for the function executions. | | | deploymentRetention | integer | Days to keep non-active deployments before deletion. Value 0 means all deployments will be kept. | 0 | diff --git a/docs/oauth2.md b/docs/oauth2.md new file mode 100644 index 00000000..c5e315e6 --- /dev/null +++ b/docs/oauth2.md @@ -0,0 +1,230 @@ +# Oauth2 Service + + +```http request +POST https://cloud.appwrite.io/v1/oauth2/{project_id}/approve +``` + +** Approve an OAuth2 grant after the user gives consent. Returns the `redirectUrl` the end user should be sent to. The consent screen may optionally pass enriched `authorization_details` to record the concrete resources the user selected. You can pass Accept header of `application/json` to receive a JSON response instead of a redirect. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| grant_id | string | Grant ID made during authorization, provided to consent screen in URL search params. | | +| authorization_details | string | Enriched `authorization_details` the user consented to, replacing what the client requested. Each entry must use a `type` the project accepts. Optional; omit to keep the originally requested details. | | +| scope | string | Space-separated scopes the user consented to. Must be a subset of the scopes originally requested; identity scopes such as `openid` are always retained. Optional; omit to keep the originally requested scopes. | | + + +```http request +GET https://cloud.appwrite.io/v1/oauth2/{project_id}/authorize +``` + +** Begin the OAuth2 authorization flow. When called without a session, the user is redirected to the consent screen without grant ID. When called with a session, the redirect URL includes param for grant ID. You can pass Accept header of `application/json` to receive a JSON response instead of a redirect. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| client_id | string | OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. | | +| redirect_uri | string | Redirect URI where visitor will be redirected after authorization, whether successful or not. | | +| response_type | string | OAuth2 / OIDC response type. One of `code` (Authorization Code Flow), `id_token` (Implicit Flow, OIDC login only), or `code id_token` (Hybrid Flow). | | +| scope | string | Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`, `phone`. | | +| state | string | OAuth2 state. You receive this back in the redirect URI. | | +| nonce | string | OIDC nonce parameter to prevent replay attacks. Required when response_type includes `id_token`. | | +| code_challenge | string | PKCE code challenge. Required when OAuth2 app is public. | | +| code_challenge_method | string | PKCE code challenge method. Required when OAuth2 app is public. | | +| prompt | string | OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. | | +| max_age | integer | OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. | | +| authorization_details | string | Rich authorization request. JSON array of objects, each with a `type` and project-defined fields | | +| resource | string | RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. | [] | +| audience | string | Compatibility alias for a single OAuth2 resource indicator URI. | | +| request_uri | string | OAuth2 authorization request handle returned by the pushed authorization request endpoint. | | + + +```http request +POST https://cloud.appwrite.io/v1/oauth2/{project_id}/authorize +``` + +** Begin the OAuth2 authorization flow. When called without a session, the user is redirected to the consent screen without grant ID. When called with a session, the redirect URL includes param for grant ID. You can pass Accept header of `application/json` to receive a JSON response instead of a redirect. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| client_id | string | OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. | | +| redirect_uri | string | Redirect URI where visitor will be redirected after authorization, whether successful or not. | | +| response_type | string | OAuth2 / OIDC response type. One of `code` (Authorization Code Flow), `id_token` (Implicit Flow, OIDC login only), or `code id_token` (Hybrid Flow). | | +| scope | string | Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`, `phone`. | | +| state | string | OAuth2 state. You receive this back in the redirect URI. | | +| nonce | string | OIDC nonce parameter to prevent replay attacks. Required when response_type includes `id_token`. | | +| code_challenge | string | PKCE code challenge. Required when OAuth2 app is public. | | +| code_challenge_method | string | PKCE code challenge method. Required when OAuth2 app is public. | | +| prompt | string | OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. | | +| max_age | integer | OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. | | +| authorization_details | string | Rich authorization request. JSON array of objects, each with a `type` and project-defined fields | | +| resource | string | RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. | [] | +| audience | string | Compatibility alias for a single OAuth2 resource indicator URI. | | +| request_uri | string | OAuth2 authorization request handle returned by the pushed authorization request endpoint. | | + + +```http request +POST https://cloud.appwrite.io/v1/oauth2/{project_id}/device_authorization +``` + +** Start the OAuth2 Device Authorization Grant. Returns the device code, user code, verification URL, expiration, and polling interval. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| client_id | string | OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. | | +| scope | string | Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. | | +| authorization_details | string | Rich authorization request. JSON array of objects, each with a `type` and project-defined fields | | +| resource | string | RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. | [] | +| audience | string | Compatibility alias for a single OAuth2 resource indicator URI. | | + + +```http request +POST https://cloud.appwrite.io/v1/oauth2/{project_id}/grants +``` + +** Exchange a device flow user code for an OAuth2 grant. The authenticated user is bound to the pending grant. Pass the returned grant ID to the get grant endpoint to render the consent screen, then to the approve or reject endpoint to complete the flow. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| user_code | string | User code displayed on the device. | | + + +```http request +GET https://cloud.appwrite.io/v1/oauth2/{project_id}/grants/{grant_id} +``` + +** Get an OAuth2 grant by its ID. Used by the consent screen to display the details of the authorization the user is being asked to approve. A grant can only be read by the user it belongs to, or by server SDK. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client that created grant during authorization exists. | | +| grant_id | string | **Required** Grant ID made during authorization, provided to consent screen in URL search params. | | + + +```http request +GET https://cloud.appwrite.io/v1/oauth2/{project_id}/organizations +``` + +** List the organizations the OAuth2 access token can access. Resolves the token's `organization` authorization details, expanding the `*` wildcard into the concrete set of organizations the user can see. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID of the console project the OAuth2 access token was issued for. | | +| limit | integer | Maximum number of organizations to return. Between 1 and 5000. | 25 | +| offset | integer | Number of organizations to skip before returning results. Used for pagination. | 0 | +| search | string | Search term to filter your list results. Max length: 256 chars. | | + + +```http request +POST https://cloud.appwrite.io/v1/oauth2/{project_id}/par +``` + +** Store an OAuth2 authorization request server-side and receive a short-lived request_uri handle for the authorize endpoint. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| client_id | string | OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. | | +| redirect_uri | string | Redirect URI where visitor will be redirected after authorization, whether successful or not. | | +| response_type | string | OAuth2 / OIDC response type. | | +| scope | string | Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`, `phone`. | | +| state | string | OAuth2 state. You receive this back in the redirect URI. | | +| nonce | string | OIDC nonce parameter to prevent replay attacks. Required when response_type includes `id_token`. | | +| code_challenge | string | PKCE code challenge. Required when OAuth2 app is public. | | +| code_challenge_method | string | PKCE code challenge method. Required when OAuth2 app is public. | | +| prompt | string | OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. | | +| max_age | integer | OIDC max_age parameter for customization of consent screen. | | +| authorization_details | string | Rich authorization request. JSON array of objects, each with a `type` and project-defined fields | | +| resource | string | RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. | [] | +| audience | string | Compatibility alias for a single OAuth2 resource indicator URI. | | + + +```http request +GET https://cloud.appwrite.io/v1/oauth2/{project_id}/projects +``` + +** List the projects the OAuth2 access token can access. Resolves the token's `project` authorization details, expanding the `*` wildcard into the concrete set of projects the user can see. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID of the console project the OAuth2 access token was issued for. | | +| limit | integer | Maximum number of projects to return. Between 1 and 5000. | 25 | +| offset | integer | Number of projects to skip before returning results. Used for pagination. | 0 | +| search | string | Search term to filter your list results. Max length: 256 chars. | | + + +```http request +POST https://cloud.appwrite.io/v1/oauth2/{project_id}/reject +``` + +** Reject an OAuth2 grant when the user denies consent. Returns the `redirectUrl` the end user should be sent to with an `access_denied` error. You can pass Accept header of `application/json` to receive a JSON response instead of a redirect. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| grant_id | string | Grant ID made during authorization, provided to consent screen in URL search params. | | + + +```http request +POST https://cloud.appwrite.io/v1/oauth2/{project_id}/revoke +``` + +** Revoke an OAuth2 access token or refresh token. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| token | string | The access or refresh token to revoke. | | +| token_type_hint | string | Type of token to revoke (access_token or refresh_token). | | +| client_id | string | OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. | | +| client_secret | string | OAuth2 client secret. Required for confidential apps; omitted for public apps. | | + + +```http request +POST https://cloud.appwrite.io/v1/oauth2/{project_id}/token +``` + +** Exchange an OAuth2 authorization code, refresh token, or device code for access and refresh tokens. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| project_id | string | **Required** Project ID in which OAuth2 client exists. | | +| grant_type | string | OAuth2 grant type. Can be one of: `authorization_code`, `refresh_token`, `urn:ietf:params:oauth:grant-type:device_code`. | | +| code | string | Authorization code to be exchanged for access and refresh tokens. Required for `authorization_code` grant type. | | +| refresh_token | string | Refresh token to be exchanged for a new access and refresh tokens. Required for `refresh_token` grant type. | | +| device_code | string | Device code obtained from the device authorization endpoint. Required for `urn:ietf:params:oauth:grant-type:device_code` grant type. | | +| client_id | string | OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. | | +| client_secret | string | OAuth2 client secret. Required for confidential apps. | | +| code_verifier | string | PKCE code verifier. Required for public apps. | | +| redirect_uri | string | Redirect URI. Required for `authorization_code` grant type. | | +| resource | string | RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. | [] | +| audience | string | Compatibility alias for a single OAuth2 resource indicator URI. | | + diff --git a/docs/organization.md b/docs/organization.md index 65a24932..1508fbc8 100644 --- a/docs/organization.md +++ b/docs/organization.md @@ -28,6 +28,74 @@ DELETE https://cloud.appwrite.io/v1/organization ** Delete the current organization. All projects that belong to the organization are deleted as well. ** +```http request +GET https://cloud.appwrite.io/v1/organization/installations +``` + +** List app installations on the organization. Any organization member can read installations. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. | [] | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +POST https://cloud.appwrite.io/v1/organization/installations +``` + +** Install an app on the organization. Only organization members with the owner role can install apps. The installation is granted the scopes the app currently requests. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | Application unique ID. | | +| authorizationDetails | string | Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. The Appwrite Console stores authorized project IDs here. | | + + +```http request +GET https://cloud.appwrite.io/v1/organization/installations/{installationId} +``` + +** Get an app installation on the organization by its unique ID. Any organization member can read installations. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| installationId | string | **Required** Installation unique ID. | | + + +```http request +PUT https://cloud.appwrite.io/v1/organization/installations/{installationId} +``` + +** Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| installationId | string | **Required** Installation unique ID. | | +| authorizationDetails | string | Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/organization/installations/{installationId} +``` + +** Uninstall an app from the organization by its installation ID. Only organization members with the owner role can remove installations. Previously issued installation access tokens are revoked. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| installationId | string | **Required** Installation unique ID. | | + + ```http request GET https://cloud.appwrite.io/v1/organization/keys ``` diff --git a/docs/project.md b/docs/project.md index ca8f7cb6..c98ef4bc 100644 --- a/docs/project.md +++ b/docs/project.md @@ -232,6 +232,7 @@ PUT https://cloud.appwrite.io/v1/project/oauth2-server | refreshTokenDuration | integer | Refresh token duration in seconds for confidential clients (server-side apps that authenticate with a client secret). Leave empty to use default 1 year. | | | publicAccessTokenDuration | integer | Access token duration in seconds for public clients (SPAs, mobile, and native apps that cannot keep a client secret). Leave empty to use default 1 hour. | | | publicRefreshTokenDuration | integer | Refresh token duration in seconds for public clients (SPAs, mobile, and native apps that cannot keep a client secret). Leave empty to use default 30 days. | | +| installationAccessTokenDuration | integer | Access token duration in seconds for app installation access tokens. Leave empty to use default 1 hour. | | | confidentialPkce | boolean | When enabled, PKCE is required for confidential clients (server-side flows using client_secret). PKCE is always required for public clients regardless of this setting. | | | verificationUrl | string | URL to your application page where users enter the device flow user code. Required to enable the Device Authorization Grant. | | | userCodeLength | integer | Number of characters in the device flow user code, excluding the formatting separator. Shorter codes are easier to type but weaker; pair short codes with short expiry. Leave empty to use default 8. | | diff --git a/docs/sites.md b/docs/sites.md index 74c000aa..68f9b7d2 100644 --- a/docs/sites.md +++ b/docs/sites.md @@ -274,6 +274,7 @@ GET https://cloud.appwrite.io/v1/sites/{siteId}/deployments/{deploymentId}/downl | siteId | string | **Required** Site ID. | | | deploymentId | string | **Required** Deployment ID. | | | type | string | Deployment file to download. Can be: "source", "output". | source | +| token | string | Presigned source-download token for accessing this deployment without a session (jobs-service). | | ```http request diff --git a/docs/tablesdb.md b/docs/tablesdb.md index 1df71a2b..eefcfcde 100644 --- a/docs/tablesdb.md +++ b/docs/tablesdb.md @@ -31,6 +31,14 @@ POST https://cloud.appwrite.io/v1/tablesdb | name | string | Database name. Max length: 128 chars. | | | enabled | boolean | Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled. | 1 | | specification | string | Database specification. Defaults to `serverless`, which creates the database on the shared pool. Any other value provisions a dedicated database on that specification. | serverless | +| replicas | integer | Number of high availability replicas (0-5) for the dedicated database backing this database. Requires a dedicated `specification`; must be 0 for a serverless database. High availability is enabled when greater than 0. | 0 | + + +```http request +GET https://cloud.appwrite.io/v1/tablesdb/specifications +``` + +** List the dedicated database specifications available on the current plan. Each specification reports its resource limits, pricing, and whether it is enabled for the organization. ** ```http request @@ -140,6 +148,7 @@ PUT https://cloud.appwrite.io/v1/tablesdb/{databaseId} | databaseId | string | **Required** Database ID. | | | name | string | Database name. Max length: 128 chars. | | | enabled | boolean | Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled. | 1 | +| replicas | integer | Number of high availability replicas (0-5) for the dedicated database backing this database. Only valid when the database is backed by a dedicated specification. High availability is enabled when greater than 0. | | ```http request @@ -155,6 +164,46 @@ DELETE https://cloud.appwrite.io/v1/tablesdb/{databaseId} | databaseId | string | **Required** Database ID. | | +```http request +POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/failovers +``` + +** Trigger a manual failover for a dedicated database with high availability enabled. Promotes a replica to primary. The failover runs asynchronously; poll the database document for status updates. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | +| targetReplicaId | string | Target replica ID to promote. If not specified, the healthiest replica is selected. | | + + +```http request +GET https://cloud.appwrite.io/v1/tablesdb/{databaseId}/replicas +``` + +** Get high availability status for a dedicated database. Returns replica statuses, replication lag, and sync mode. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | + + +```http request +GET https://cloud.appwrite.io/v1/tablesdb/{databaseId}/status +``` + +** Get real-time health and status information for a dedicated database. Returns health status, readiness, uptime, connection info, replica status, and volume information. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | + + ```http request GET https://cloud.appwrite.io/v1/tablesdb/{databaseId}/tables ``` diff --git a/docs/teams.md b/docs/teams.md index 7874cf5d..60315577 100644 --- a/docs/teams.md +++ b/docs/teams.md @@ -71,6 +71,79 @@ DELETE https://cloud.appwrite.io/v1/teams/{teamId} | teamId | string | **Required** Team ID. | | +```http request +GET https://cloud.appwrite.io/v1/teams/{teamId}/installations +``` + +** List app installations on a team. Any team member can read installations. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| teamId | string | **Required** Team ID. | | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. | [] | +| total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | + + +```http request +POST https://cloud.appwrite.io/v1/teams/{teamId}/installations +``` + +** Install an app on a team. When authenticated as a user, only team members with the owner role can install apps. Requests using an API key or in admin mode can install apps on any team. The installation is granted the scopes the app currently requests. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| teamId | string | **Required** Team ID. | | +| appId | string | Application unique ID. | | +| authorizationDetails | string | Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. The Appwrite Console stores authorized project IDs here. | | + + +```http request +GET https://cloud.appwrite.io/v1/teams/{teamId}/installations/{installationId} +``` + +** Get an app installation on a team by its unique ID. Any team member can read installations. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| teamId | string | **Required** Team ID. | | +| installationId | string | **Required** Installation unique ID. | | + + +```http request +PUT https://cloud.appwrite.io/v1/teams/{teamId}/installations/{installationId} +``` + +** Update an app installation on a team. Only team members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| teamId | string | **Required** Team ID. | | +| installationId | string | **Required** Installation unique ID. | | +| authorizationDetails | string | Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/teams/{teamId}/installations/{installationId} +``` + +** Uninstall an app from a team by its installation ID. Only team members with the owner role can remove installations. Previously issued installation access tokens are revoked. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| teamId | string | **Required** Team ID. | | +| installationId | string | **Required** Installation unique ID. | | + + ```http request GET https://cloud.appwrite.io/v1/teams/{teamId}/memberships ``` diff --git a/src/Appwrite/Client.php b/src/Appwrite/Client.php index 9a1a4cd9..23ee27b6 100644 --- a/src/Appwrite/Client.php +++ b/src/Appwrite/Client.php @@ -40,11 +40,11 @@ class Client */ protected array $headers = [ 'content-type' => '', - 'user-agent' => 'AppwritePHPSDK/27.0.0 ()', + 'user-agent' => 'AppwritePHPSDK/27.1.0 ()', 'x-sdk-name'=> 'PHP', 'x-sdk-platform'=> 'server', 'x-sdk-language'=> 'php', - 'x-sdk-version'=> '27.0.0', + 'x-sdk-version'=> '27.1.0', ]; /** diff --git a/src/Appwrite/Enums/DatabaseStatus.php b/src/Appwrite/Enums/DatabaseStatus.php index 0555a062..870c3932 100644 --- a/src/Appwrite/Enums/DatabaseStatus.php +++ b/src/Appwrite/Enums/DatabaseStatus.php @@ -8,7 +8,18 @@ class DatabaseStatus implements JsonSerializable { private static DatabaseStatus $PROVISIONING; private static DatabaseStatus $READY; + private static DatabaseStatus $INACTIVE; + private static DatabaseStatus $PAUSED; private static DatabaseStatus $FAILED; + private static DatabaseStatus $DELETING; + private static DatabaseStatus $DELETED; + private static DatabaseStatus $RESTORING; + private static DatabaseStatus $SCALING; + private static DatabaseStatus $UPGRADING; + private static DatabaseStatus $MIGRATING; + private static DatabaseStatus $PAUSING; + private static DatabaseStatus $RESUMING; + private static DatabaseStatus $FAILINGOVER; private string $value; @@ -41,6 +52,20 @@ public static function READY(): DatabaseStatus } return self::$READY; } + public static function INACTIVE(): DatabaseStatus + { + if (!isset(self::$INACTIVE)) { + self::$INACTIVE = new DatabaseStatus('inactive'); + } + return self::$INACTIVE; + } + public static function PAUSED(): DatabaseStatus + { + if (!isset(self::$PAUSED)) { + self::$PAUSED = new DatabaseStatus('paused'); + } + return self::$PAUSED; + } public static function FAILED(): DatabaseStatus { if (!isset(self::$FAILED)) { @@ -48,13 +73,87 @@ public static function FAILED(): DatabaseStatus } return self::$FAILED; } + public static function DELETING(): DatabaseStatus + { + if (!isset(self::$DELETING)) { + self::$DELETING = new DatabaseStatus('deleting'); + } + return self::$DELETING; + } + public static function DELETED(): DatabaseStatus + { + if (!isset(self::$DELETED)) { + self::$DELETED = new DatabaseStatus('deleted'); + } + return self::$DELETED; + } + public static function RESTORING(): DatabaseStatus + { + if (!isset(self::$RESTORING)) { + self::$RESTORING = new DatabaseStatus('restoring'); + } + return self::$RESTORING; + } + public static function SCALING(): DatabaseStatus + { + if (!isset(self::$SCALING)) { + self::$SCALING = new DatabaseStatus('scaling'); + } + return self::$SCALING; + } + public static function UPGRADING(): DatabaseStatus + { + if (!isset(self::$UPGRADING)) { + self::$UPGRADING = new DatabaseStatus('upgrading'); + } + return self::$UPGRADING; + } + public static function MIGRATING(): DatabaseStatus + { + if (!isset(self::$MIGRATING)) { + self::$MIGRATING = new DatabaseStatus('migrating'); + } + return self::$MIGRATING; + } + public static function PAUSING(): DatabaseStatus + { + if (!isset(self::$PAUSING)) { + self::$PAUSING = new DatabaseStatus('pausing'); + } + return self::$PAUSING; + } + public static function RESUMING(): DatabaseStatus + { + if (!isset(self::$RESUMING)) { + self::$RESUMING = new DatabaseStatus('resuming'); + } + return self::$RESUMING; + } + public static function FAILINGOVER(): DatabaseStatus + { + if (!isset(self::$FAILINGOVER)) { + self::$FAILINGOVER = new DatabaseStatus('failing-over'); + } + return self::$FAILINGOVER; + } public static function from(string $value): self { return match ($value) { 'provisioning' => self::PROVISIONING(), 'ready' => self::READY(), + 'inactive' => self::INACTIVE(), + 'paused' => self::PAUSED(), 'failed' => self::FAILED(), + 'deleting' => self::DELETING(), + 'deleted' => self::DELETED(), + 'restoring' => self::RESTORING(), + 'scaling' => self::SCALING(), + 'upgrading' => self::UPGRADING(), + 'migrating' => self::MIGRATING(), + 'pausing' => self::PAUSING(), + 'resuming' => self::RESUMING(), + 'failing-over' => self::FAILINGOVER(), default => throw new \InvalidArgumentException('Unknown DatabaseStatus value: ' . $value), }; } diff --git a/src/Appwrite/Enums/DatabaseType.php b/src/Appwrite/Enums/DatabaseType.php index e5d7dfe5..56d1cff0 100644 --- a/src/Appwrite/Enums/DatabaseType.php +++ b/src/Appwrite/Enums/DatabaseType.php @@ -10,6 +10,9 @@ class DatabaseType implements JsonSerializable private static DatabaseType $TABLESDB; private static DatabaseType $DOCUMENTSDB; private static DatabaseType $VECTORSDB; + private static DatabaseType $MYSQL; + private static DatabaseType $POSTGRESQL; + private static DatabaseType $MONGODB; private string $value; @@ -56,6 +59,27 @@ public static function VECTORSDB(): DatabaseType } return self::$VECTORSDB; } + public static function MYSQL(): DatabaseType + { + if (!isset(self::$MYSQL)) { + self::$MYSQL = new DatabaseType('mysql'); + } + return self::$MYSQL; + } + public static function POSTGRESQL(): DatabaseType + { + if (!isset(self::$POSTGRESQL)) { + self::$POSTGRESQL = new DatabaseType('postgresql'); + } + return self::$POSTGRESQL; + } + public static function MONGODB(): DatabaseType + { + if (!isset(self::$MONGODB)) { + self::$MONGODB = new DatabaseType('mongodb'); + } + return self::$MONGODB; + } public static function from(string $value): self { @@ -64,6 +88,9 @@ public static function from(string $value): self 'tablesdb' => self::TABLESDB(), 'documentsdb' => self::DOCUMENTSDB(), 'vectorsdb' => self::VECTORSDB(), + 'mysql' => self::MYSQL(), + 'postgresql' => self::POSTGRESQL(), + 'mongodb' => self::MONGODB(), default => throw new \InvalidArgumentException('Unknown DatabaseType value: ' . $value), }; } diff --git a/src/Appwrite/Enums/OrganizationKeyScopes.php b/src/Appwrite/Enums/OrganizationKeyScopes.php index 7bf3987f..2d0e5d85 100644 --- a/src/Appwrite/Enums/OrganizationKeyScopes.php +++ b/src/Appwrite/Enums/OrganizationKeyScopes.php @@ -12,6 +12,8 @@ class OrganizationKeyScopes implements JsonSerializable private static OrganizationKeyScopes $DEVKEYSWRITE; private static OrganizationKeyScopes $ORGANIZATIONKEYSREAD; private static OrganizationKeyScopes $ORGANIZATIONKEYSWRITE; + private static OrganizationKeyScopes $ORGANIZATIONINSTALLATIONSREAD; + private static OrganizationKeyScopes $ORGANIZATIONINSTALLATIONSWRITE; private static OrganizationKeyScopes $ORGANIZATIONMEMBERSHIPSREAD; private static OrganizationKeyScopes $ORGANIZATIONMEMBERSHIPSWRITE; private static OrganizationKeyScopes $ORGANIZATIONREAD; @@ -80,6 +82,20 @@ public static function ORGANIZATIONKEYSWRITE(): OrganizationKeyScopes } return self::$ORGANIZATIONKEYSWRITE; } + public static function ORGANIZATIONINSTALLATIONSREAD(): OrganizationKeyScopes + { + if (!isset(self::$ORGANIZATIONINSTALLATIONSREAD)) { + self::$ORGANIZATIONINSTALLATIONSREAD = new OrganizationKeyScopes('organization.installations.read'); + } + return self::$ORGANIZATIONINSTALLATIONSREAD; + } + public static function ORGANIZATIONINSTALLATIONSWRITE(): OrganizationKeyScopes + { + if (!isset(self::$ORGANIZATIONINSTALLATIONSWRITE)) { + self::$ORGANIZATIONINSTALLATIONSWRITE = new OrganizationKeyScopes('organization.installations.write'); + } + return self::$ORGANIZATIONINSTALLATIONSWRITE; + } public static function ORGANIZATIONMEMBERSHIPSREAD(): OrganizationKeyScopes { if (!isset(self::$ORGANIZATIONMEMBERSHIPSREAD)) { @@ -146,6 +162,8 @@ public static function from(string $value): self 'devKeys.write' => self::DEVKEYSWRITE(), 'organization.keys.read' => self::ORGANIZATIONKEYSREAD(), 'organization.keys.write' => self::ORGANIZATIONKEYSWRITE(), + 'organization.installations.read' => self::ORGANIZATIONINSTALLATIONSREAD(), + 'organization.installations.write' => self::ORGANIZATIONINSTALLATIONSWRITE(), 'organization.memberships.read' => self::ORGANIZATIONMEMBERSHIPSREAD(), 'organization.memberships.write' => self::ORGANIZATIONMEMBERSHIPSWRITE(), 'organization.read' => self::ORGANIZATIONREAD(), diff --git a/src/Appwrite/Enums/ProjectKeyScopes.php b/src/Appwrite/Enums/ProjectKeyScopes.php index c087a037..b7d37a76 100644 --- a/src/Appwrite/Enums/ProjectKeyScopes.php +++ b/src/Appwrite/Enums/ProjectKeyScopes.php @@ -101,11 +101,14 @@ class ProjectKeyScopes implements JsonSerializable private static ProjectKeyScopes $DEDICATEDDATABASESEXECUTE; private static ProjectKeyScopes $DOMAINSREAD; private static ProjectKeyScopes $DOMAINSWRITE; + private static ProjectKeyScopes $WAFRULESREAD; + private static ProjectKeyScopes $WAFRULESWRITE; private static ProjectKeyScopes $EVENTSREAD; private static ProjectKeyScopes $APPSREAD; private static ProjectKeyScopes $APPSWRITE; private static ProjectKeyScopes $OAUTH2READ; private static ProjectKeyScopes $OAUTH2WRITE; + private static ProjectKeyScopes $OAUTH2INTROSPECT; private static ProjectKeyScopes $USAGEREAD; private string $value; @@ -790,6 +793,20 @@ public static function DOMAINSWRITE(): ProjectKeyScopes } return self::$DOMAINSWRITE; } + public static function WAFRULESREAD(): ProjectKeyScopes + { + if (!isset(self::$WAFRULESREAD)) { + self::$WAFRULESREAD = new ProjectKeyScopes('wafRules.read'); + } + return self::$WAFRULESREAD; + } + public static function WAFRULESWRITE(): ProjectKeyScopes + { + if (!isset(self::$WAFRULESWRITE)) { + self::$WAFRULESWRITE = new ProjectKeyScopes('wafRules.write'); + } + return self::$WAFRULESWRITE; + } public static function EVENTSREAD(): ProjectKeyScopes { if (!isset(self::$EVENTSREAD)) { @@ -825,6 +842,13 @@ public static function OAUTH2WRITE(): ProjectKeyScopes } return self::$OAUTH2WRITE; } + public static function OAUTH2INTROSPECT(): ProjectKeyScopes + { + if (!isset(self::$OAUTH2INTROSPECT)) { + self::$OAUTH2INTROSPECT = new ProjectKeyScopes('oauth2.introspect'); + } + return self::$OAUTH2INTROSPECT; + } public static function USAGEREAD(): ProjectKeyScopes { if (!isset(self::$USAGEREAD)) { @@ -931,11 +955,14 @@ public static function from(string $value): self 'dedicatedDatabases.execute' => self::DEDICATEDDATABASESEXECUTE(), 'domains.read' => self::DOMAINSREAD(), 'domains.write' => self::DOMAINSWRITE(), + 'wafRules.read' => self::WAFRULESREAD(), + 'wafRules.write' => self::WAFRULESWRITE(), 'events.read' => self::EVENTSREAD(), 'apps.read' => self::APPSREAD(), 'apps.write' => self::APPSWRITE(), 'oauth2.read' => self::OAUTH2READ(), 'oauth2.write' => self::OAUTH2WRITE(), + 'oauth2.introspect' => self::OAUTH2INTROSPECT(), 'usage.read' => self::USAGEREAD(), default => throw new \InvalidArgumentException('Unknown ProjectKeyScopes value: ' . $value), }; diff --git a/src/Appwrite/Models/ActivityEvent.php b/src/Appwrite/Models/ActivityEvent.php index 5c6429ab..3bb7b87c 100644 --- a/src/Appwrite/Models/ActivityEvent.php +++ b/src/Appwrite/Models/ActivityEvent.php @@ -26,10 +26,21 @@ * @param string $ip ip address. * @param string $mode api mode when event triggered. * @param string $country location. + * @param string $continentCode continent code. + * @param string $city city name. + * @param string $subdivisions region/state chain. + * @param string $isp internet service provider. + * @param string $autonomousSystemNumber autonomous system number (asn). + * @param string $autonomousSystemOrganization organization that owns the asn. + * @param string $connectionType connection type (e.g. cable, cellular, corporate). + * @param string $connectionUsageType user type (e.g. residential, business, hosting). + * @param string $connectionOrganization registered organization of the ip. * @param string $time log creation date in iso 8601 format. * @param string $projectId project id. * @param string $teamId team id. * @param string $hostname hostname. + * @param string $sdk name of the sdk that triggered the event. + * @param string $sdkVersion version of the sdk that triggered the event. */ public function __construct( public string $id, @@ -46,10 +57,21 @@ public function __construct( public string $ip, public string $mode, public string $country, + public string $continentCode, + public string $city, + public string $subdivisions, + public string $isp, + public string $autonomousSystemNumber, + public string $autonomousSystemOrganization, + public string $connectionType, + public string $connectionUsageType, + public string $connectionOrganization, public string $time, public string $projectId, public string $teamId, - public string $hostname + public string $hostname, + public string $sdk, + public string $sdkVersion ) { } @@ -100,6 +122,33 @@ public static function from(array $data): static if (!array_key_exists('country', $data)) { throw new \InvalidArgumentException('Missing required field "country" for ' . static::class . '.'); } + if (!array_key_exists('continentCode', $data)) { + throw new \InvalidArgumentException('Missing required field "continentCode" for ' . static::class . '.'); + } + if (!array_key_exists('city', $data)) { + throw new \InvalidArgumentException('Missing required field "city" for ' . static::class . '.'); + } + if (!array_key_exists('subdivisions', $data)) { + throw new \InvalidArgumentException('Missing required field "subdivisions" for ' . static::class . '.'); + } + if (!array_key_exists('isp', $data)) { + throw new \InvalidArgumentException('Missing required field "isp" for ' . static::class . '.'); + } + if (!array_key_exists('autonomousSystemNumber', $data)) { + throw new \InvalidArgumentException('Missing required field "autonomousSystemNumber" for ' . static::class . '.'); + } + if (!array_key_exists('autonomousSystemOrganization', $data)) { + throw new \InvalidArgumentException('Missing required field "autonomousSystemOrganization" for ' . static::class . '.'); + } + if (!array_key_exists('connectionType', $data)) { + throw new \InvalidArgumentException('Missing required field "connectionType" for ' . static::class . '.'); + } + if (!array_key_exists('connectionUsageType', $data)) { + throw new \InvalidArgumentException('Missing required field "connectionUsageType" for ' . static::class . '.'); + } + if (!array_key_exists('connectionOrganization', $data)) { + throw new \InvalidArgumentException('Missing required field "connectionOrganization" for ' . static::class . '.'); + } if (!array_key_exists('time', $data)) { throw new \InvalidArgumentException('Missing required field "time" for ' . static::class . '.'); } @@ -112,6 +161,12 @@ public static function from(array $data): static if (!array_key_exists('hostname', $data)) { throw new \InvalidArgumentException('Missing required field "hostname" for ' . static::class . '.'); } + if (!array_key_exists('sdk', $data)) { + throw new \InvalidArgumentException('Missing required field "sdk" for ' . static::class . '.'); + } + if (!array_key_exists('sdkVersion', $data)) { + throw new \InvalidArgumentException('Missing required field "sdkVersion" for ' . static::class . '.'); + } return new static( id: $data['$id'], @@ -128,10 +183,21 @@ public static function from(array $data): static ip: $data['ip'], mode: $data['mode'], country: $data['country'], + continentCode: $data['continentCode'], + city: $data['city'], + subdivisions: $data['subdivisions'], + isp: $data['isp'], + autonomousSystemNumber: $data['autonomousSystemNumber'], + autonomousSystemOrganization: $data['autonomousSystemOrganization'], + connectionType: $data['connectionType'], + connectionUsageType: $data['connectionUsageType'], + connectionOrganization: $data['connectionOrganization'], time: $data['time'], projectId: $data['projectId'], teamId: $data['teamId'], - hostname: $data['hostname'] + hostname: $data['hostname'], + sdk: $data['sdk'], + sdkVersion: $data['sdkVersion'] ); } @@ -155,10 +221,21 @@ public function toArray(): array 'ip' => static::serializeValue($this->ip), 'mode' => static::serializeValue($this->mode), 'country' => static::serializeValue($this->country), + 'continentCode' => static::serializeValue($this->continentCode), + 'city' => static::serializeValue($this->city), + 'subdivisions' => static::serializeValue($this->subdivisions), + 'isp' => static::serializeValue($this->isp), + 'autonomousSystemNumber' => static::serializeValue($this->autonomousSystemNumber), + 'autonomousSystemOrganization' => static::serializeValue($this->autonomousSystemOrganization), + 'connectionType' => static::serializeValue($this->connectionType), + 'connectionUsageType' => static::serializeValue($this->connectionUsageType), + 'connectionOrganization' => static::serializeValue($this->connectionOrganization), 'time' => static::serializeValue($this->time), 'projectId' => static::serializeValue($this->projectId), 'teamId' => static::serializeValue($this->teamId), - 'hostname' => static::serializeValue($this->hostname) + 'hostname' => static::serializeValue($this->hostname), + 'sdk' => static::serializeValue($this->sdk), + 'sdkVersion' => static::serializeValue($this->sdkVersion) ]; return $result; diff --git a/src/Appwrite/Models/App.php b/src/Appwrite/Models/App.php new file mode 100644 index 00000000..c6d447ef --- /dev/null +++ b/src/Appwrite/Models/App.php @@ -0,0 +1,227 @@ + $secrets list of application secrets. + */ + public function __construct( + public string $id, + public string $createdAt, + public string $updatedAt, + public string $name, + public string $description, + public string $clientUri, + public string $logoUri, + public string $privacyPolicyUrl, + public string $termsUrl, + public array $contacts, + public string $tagline, + public array $tags, + public array $labels, + public array $images, + public string $supportUrl, + public string $dataDeletionUrl, + public array $redirectUris, + public array $postLogoutRedirectUris, + public bool $enabled, + public string $type, + public bool $deviceFlow, + public string $teamId, + public string $userId, + public array $installationScopes, + public string $installationRedirectUrl, + public array $secrets + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); + } + if (!array_key_exists('description', $data)) { + throw new \InvalidArgumentException('Missing required field "description" for ' . static::class . '.'); + } + if (!array_key_exists('clientUri', $data)) { + throw new \InvalidArgumentException('Missing required field "clientUri" for ' . static::class . '.'); + } + if (!array_key_exists('logoUri', $data)) { + throw new \InvalidArgumentException('Missing required field "logoUri" for ' . static::class . '.'); + } + if (!array_key_exists('privacyPolicyUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "privacyPolicyUrl" for ' . static::class . '.'); + } + if (!array_key_exists('termsUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "termsUrl" for ' . static::class . '.'); + } + if (!array_key_exists('contacts', $data)) { + throw new \InvalidArgumentException('Missing required field "contacts" for ' . static::class . '.'); + } + if (!array_key_exists('tagline', $data)) { + throw new \InvalidArgumentException('Missing required field "tagline" for ' . static::class . '.'); + } + if (!array_key_exists('tags', $data)) { + throw new \InvalidArgumentException('Missing required field "tags" for ' . static::class . '.'); + } + if (!array_key_exists('labels', $data)) { + throw new \InvalidArgumentException('Missing required field "labels" for ' . static::class . '.'); + } + if (!array_key_exists('images', $data)) { + throw new \InvalidArgumentException('Missing required field "images" for ' . static::class . '.'); + } + if (!array_key_exists('supportUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "supportUrl" for ' . static::class . '.'); + } + if (!array_key_exists('dataDeletionUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "dataDeletionUrl" for ' . static::class . '.'); + } + if (!array_key_exists('redirectUris', $data)) { + throw new \InvalidArgumentException('Missing required field "redirectUris" for ' . static::class . '.'); + } + if (!array_key_exists('postLogoutRedirectUris', $data)) { + throw new \InvalidArgumentException('Missing required field "postLogoutRedirectUris" for ' . static::class . '.'); + } + if (!array_key_exists('enabled', $data)) { + throw new \InvalidArgumentException('Missing required field "enabled" for ' . static::class . '.'); + } + if (!array_key_exists('type', $data)) { + throw new \InvalidArgumentException('Missing required field "type" for ' . static::class . '.'); + } + if (!array_key_exists('deviceFlow', $data)) { + throw new \InvalidArgumentException('Missing required field "deviceFlow" for ' . static::class . '.'); + } + if (!array_key_exists('teamId', $data)) { + throw new \InvalidArgumentException('Missing required field "teamId" for ' . static::class . '.'); + } + if (!array_key_exists('userId', $data)) { + throw new \InvalidArgumentException('Missing required field "userId" for ' . static::class . '.'); + } + if (!array_key_exists('installationScopes', $data)) { + throw new \InvalidArgumentException('Missing required field "installationScopes" for ' . static::class . '.'); + } + if (!array_key_exists('installationRedirectUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "installationRedirectUrl" for ' . static::class . '.'); + } + if (!array_key_exists('secrets', $data)) { + throw new \InvalidArgumentException('Missing required field "secrets" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + name: $data['name'], + description: $data['description'], + clientUri: $data['clientUri'], + logoUri: $data['logoUri'], + privacyPolicyUrl: $data['privacyPolicyUrl'], + termsUrl: $data['termsUrl'], + contacts: $data['contacts'], + tagline: $data['tagline'], + tags: $data['tags'], + labels: $data['labels'], + images: $data['images'], + supportUrl: $data['supportUrl'], + dataDeletionUrl: $data['dataDeletionUrl'], + redirectUris: $data['redirectUris'], + postLogoutRedirectUris: $data['postLogoutRedirectUris'], + enabled: $data['enabled'], + type: $data['type'], + deviceFlow: $data['deviceFlow'], + teamId: $data['teamId'], + userId: $data['userId'], + installationScopes: $data['installationScopes'], + installationRedirectUrl: $data['installationRedirectUrl'], + secrets: is_array($data['secrets']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(AppSecret::class, $item), + $data['secrets'] + ) + : $data['secrets'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'name' => static::serializeValue($this->name), + 'description' => static::serializeValue($this->description), + 'clientUri' => static::serializeValue($this->clientUri), + 'logoUri' => static::serializeValue($this->logoUri), + 'privacyPolicyUrl' => static::serializeValue($this->privacyPolicyUrl), + 'termsUrl' => static::serializeValue($this->termsUrl), + 'contacts' => static::serializeValue($this->contacts), + 'tagline' => static::serializeValue($this->tagline), + 'tags' => static::serializeValue($this->tags), + 'labels' => static::serializeValue($this->labels), + 'images' => static::serializeValue($this->images), + 'supportUrl' => static::serializeValue($this->supportUrl), + 'dataDeletionUrl' => static::serializeValue($this->dataDeletionUrl), + 'redirectUris' => static::serializeValue($this->redirectUris), + 'postLogoutRedirectUris' => static::serializeValue($this->postLogoutRedirectUris), + 'enabled' => static::serializeValue($this->enabled), + 'type' => static::serializeValue($this->type), + 'deviceFlow' => static::serializeValue($this->deviceFlow), + 'teamId' => static::serializeValue($this->teamId), + 'userId' => static::serializeValue($this->userId), + 'installationScopes' => static::serializeValue($this->installationScopes), + 'installationRedirectUrl' => static::serializeValue($this->installationRedirectUrl), + 'secrets' => static::serializeValue($this->secrets) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppInstallation.php b/src/Appwrite/Models/AppInstallation.php new file mode 100644 index 00000000..1d13ce2f --- /dev/null +++ b/src/Appwrite/Models/AppInstallation.php @@ -0,0 +1,107 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('appId', $data)) { + throw new \InvalidArgumentException('Missing required field "appId" for ' . static::class . '.'); + } + if (!array_key_exists('teamId', $data)) { + throw new \InvalidArgumentException('Missing required field "teamId" for ' . static::class . '.'); + } + if (!array_key_exists('scopes', $data)) { + throw new \InvalidArgumentException('Missing required field "scopes" for ' . static::class . '.'); + } + if (!array_key_exists('authorizationDetails', $data)) { + throw new \InvalidArgumentException('Missing required field "authorizationDetails" for ' . static::class . '.'); + } + if (!array_key_exists('createdById', $data)) { + throw new \InvalidArgumentException('Missing required field "createdById" for ' . static::class . '.'); + } + if (!array_key_exists('createdByName', $data)) { + throw new \InvalidArgumentException('Missing required field "createdByName" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + appId: $data['appId'], + teamId: $data['teamId'], + scopes: $data['scopes'], + authorizationDetails: $data['authorizationDetails'], + createdById: $data['createdById'], + createdByName: $data['createdByName'], + lastAccessedAt: array_key_exists('lastAccessedAt', $data) ? $data['lastAccessedAt'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'appId' => static::serializeValue($this->appId), + 'teamId' => static::serializeValue($this->teamId), + 'scopes' => static::serializeValue($this->scopes), + 'authorizationDetails' => static::serializeValue($this->authorizationDetails), + 'createdById' => static::serializeValue($this->createdById), + 'createdByName' => static::serializeValue($this->createdByName), + 'lastAccessedAt' => static::serializeValue($this->lastAccessedAt) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppInstallationList.php b/src/Appwrite/Models/AppInstallationList.php new file mode 100644 index 00000000..86a00699 --- /dev/null +++ b/src/Appwrite/Models/AppInstallationList.php @@ -0,0 +1,59 @@ + $installations list of installations. + */ + public function __construct( + public int $total, + public array $installations + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('installations', $data)) { + throw new \InvalidArgumentException('Missing required field "installations" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + installations: is_array($data['installations']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(AppInstallation::class, $item), + $data['installations'] + ) + : $data['installations'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'installations' => static::serializeValue($this->installations) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppKey.php b/src/Appwrite/Models/AppKey.php new file mode 100644 index 00000000..471de01f --- /dev/null +++ b/src/Appwrite/Models/AppKey.php @@ -0,0 +1,100 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('appId', $data)) { + throw new \InvalidArgumentException('Missing required field "appId" for ' . static::class . '.'); + } + if (!array_key_exists('secret', $data)) { + throw new \InvalidArgumentException('Missing required field "secret" for ' . static::class . '.'); + } + if (!array_key_exists('hint', $data)) { + throw new \InvalidArgumentException('Missing required field "hint" for ' . static::class . '.'); + } + if (!array_key_exists('createdById', $data)) { + throw new \InvalidArgumentException('Missing required field "createdById" for ' . static::class . '.'); + } + if (!array_key_exists('createdByName', $data)) { + throw new \InvalidArgumentException('Missing required field "createdByName" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + appId: $data['appId'], + secret: $data['secret'], + hint: $data['hint'], + createdById: $data['createdById'], + createdByName: $data['createdByName'], + lastAccessedAt: array_key_exists('lastAccessedAt', $data) ? $data['lastAccessedAt'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'appId' => static::serializeValue($this->appId), + 'secret' => static::serializeValue($this->secret), + 'hint' => static::serializeValue($this->hint), + 'createdById' => static::serializeValue($this->createdById), + 'createdByName' => static::serializeValue($this->createdByName), + 'lastAccessedAt' => static::serializeValue($this->lastAccessedAt) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppKeyList.php b/src/Appwrite/Models/AppKeyList.php new file mode 100644 index 00000000..a5753ead --- /dev/null +++ b/src/Appwrite/Models/AppKeyList.php @@ -0,0 +1,59 @@ + $keys list of keys. + */ + public function __construct( + public int $total, + public array $keys + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('keys', $data)) { + throw new \InvalidArgumentException('Missing required field "keys" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + keys: is_array($data['keys']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(AppKey::class, $item), + $data['keys'] + ) + : $data['keys'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'keys' => static::serializeValue($this->keys) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppScope.php b/src/Appwrite/Models/AppScope.php new file mode 100644 index 00000000..d0517995 --- /dev/null +++ b/src/Appwrite/Models/AppScope.php @@ -0,0 +1,75 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('value', $data)) { + throw new \InvalidArgumentException('Missing required field "value" for ' . static::class . '.'); + } + if (!array_key_exists('description', $data)) { + throw new \InvalidArgumentException('Missing required field "description" for ' . static::class . '.'); + } + if (!array_key_exists('type', $data)) { + throw new \InvalidArgumentException('Missing required field "type" for ' . static::class . '.'); + } + if (!array_key_exists('category', $data)) { + throw new \InvalidArgumentException('Missing required field "category" for ' . static::class . '.'); + } + if (!array_key_exists('deprecated', $data)) { + throw new \InvalidArgumentException('Missing required field "deprecated" for ' . static::class . '.'); + } + + return new static( + value: $data['value'], + description: $data['description'], + type: $data['type'], + category: $data['category'], + deprecated: $data['deprecated'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'value' => static::serializeValue($this->value), + 'description' => static::serializeValue($this->description), + 'type' => static::serializeValue($this->type), + 'category' => static::serializeValue($this->category), + 'deprecated' => static::serializeValue($this->deprecated) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppScopeList.php b/src/Appwrite/Models/AppScopeList.php new file mode 100644 index 00000000..32090a96 --- /dev/null +++ b/src/Appwrite/Models/AppScopeList.php @@ -0,0 +1,59 @@ + $scopes list of scopes. + */ + public function __construct( + public int $total, + public array $scopes + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('scopes', $data)) { + throw new \InvalidArgumentException('Missing required field "scopes" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + scopes: is_array($data['scopes']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(AppScope::class, $item), + $data['scopes'] + ) + : $data['scopes'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'scopes' => static::serializeValue($this->scopes) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppSecret.php b/src/Appwrite/Models/AppSecret.php new file mode 100644 index 00000000..5308587c --- /dev/null +++ b/src/Appwrite/Models/AppSecret.php @@ -0,0 +1,100 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('appId', $data)) { + throw new \InvalidArgumentException('Missing required field "appId" for ' . static::class . '.'); + } + if (!array_key_exists('secret', $data)) { + throw new \InvalidArgumentException('Missing required field "secret" for ' . static::class . '.'); + } + if (!array_key_exists('hint', $data)) { + throw new \InvalidArgumentException('Missing required field "hint" for ' . static::class . '.'); + } + if (!array_key_exists('createdById', $data)) { + throw new \InvalidArgumentException('Missing required field "createdById" for ' . static::class . '.'); + } + if (!array_key_exists('createdByName', $data)) { + throw new \InvalidArgumentException('Missing required field "createdByName" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + appId: $data['appId'], + secret: $data['secret'], + hint: $data['hint'], + createdById: $data['createdById'], + createdByName: $data['createdByName'], + lastAccessedAt: array_key_exists('lastAccessedAt', $data) ? $data['lastAccessedAt'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'appId' => static::serializeValue($this->appId), + 'secret' => static::serializeValue($this->secret), + 'hint' => static::serializeValue($this->hint), + 'createdById' => static::serializeValue($this->createdById), + 'createdByName' => static::serializeValue($this->createdByName), + 'lastAccessedAt' => static::serializeValue($this->lastAccessedAt) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppSecretList.php b/src/Appwrite/Models/AppSecretList.php new file mode 100644 index 00000000..2568f739 --- /dev/null +++ b/src/Appwrite/Models/AppSecretList.php @@ -0,0 +1,59 @@ + $secrets list of secrets. + */ + public function __construct( + public int $total, + public array $secrets + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('secrets', $data)) { + throw new \InvalidArgumentException('Missing required field "secrets" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + secrets: is_array($data['secrets']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(AppSecret::class, $item), + $data['secrets'] + ) + : $data['secrets'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'secrets' => static::serializeValue($this->secrets) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppSecretPlaintext.php b/src/Appwrite/Models/AppSecretPlaintext.php new file mode 100644 index 00000000..35c321cb --- /dev/null +++ b/src/Appwrite/Models/AppSecretPlaintext.php @@ -0,0 +1,100 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('appId', $data)) { + throw new \InvalidArgumentException('Missing required field "appId" for ' . static::class . '.'); + } + if (!array_key_exists('secret', $data)) { + throw new \InvalidArgumentException('Missing required field "secret" for ' . static::class . '.'); + } + if (!array_key_exists('hint', $data)) { + throw new \InvalidArgumentException('Missing required field "hint" for ' . static::class . '.'); + } + if (!array_key_exists('createdById', $data)) { + throw new \InvalidArgumentException('Missing required field "createdById" for ' . static::class . '.'); + } + if (!array_key_exists('createdByName', $data)) { + throw new \InvalidArgumentException('Missing required field "createdByName" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + appId: $data['appId'], + secret: $data['secret'], + hint: $data['hint'], + createdById: $data['createdById'], + createdByName: $data['createdByName'], + lastAccessedAt: array_key_exists('lastAccessedAt', $data) ? $data['lastAccessedAt'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'appId' => static::serializeValue($this->appId), + 'secret' => static::serializeValue($this->secret), + 'hint' => static::serializeValue($this->hint), + 'createdById' => static::serializeValue($this->createdById), + 'createdByName' => static::serializeValue($this->createdByName), + 'lastAccessedAt' => static::serializeValue($this->lastAccessedAt) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/AppsList.php b/src/Appwrite/Models/AppsList.php new file mode 100644 index 00000000..547ab60d --- /dev/null +++ b/src/Appwrite/Models/AppsList.php @@ -0,0 +1,59 @@ + $apps list of apps. + */ + public function __construct( + public int $total, + public array $apps + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('apps', $data)) { + throw new \InvalidArgumentException('Missing required field "apps" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + apps: is_array($data['apps']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(App::class, $item), + $data['apps'] + ) + : $data['apps'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'apps' => static::serializeValue($this->apps) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/BillingPlan.php b/src/Appwrite/Models/BillingPlan.php index dcfd652e..951b4073 100644 --- a/src/Appwrite/Models/BillingPlan.php +++ b/src/Appwrite/Models/BillingPlan.php @@ -26,6 +26,7 @@ * @param int $screenshotsGenerated screenshots generated * @param int $members members * @param int $webhooks webhooks + * @param int $wafRules maximum waf rules per project * @param int $projects projects * @param int $platforms platforms * @param int $users users @@ -96,6 +97,7 @@ public function __construct( public int $screenshotsGenerated, public int $members, public int $webhooks, + public int $wafRules, public int $projects, public int $platforms, public int $users, @@ -196,6 +198,9 @@ public static function from(array $data): static if (!array_key_exists('webhooks', $data)) { throw new \InvalidArgumentException('Missing required field "webhooks" for ' . static::class . '.'); } + if (!array_key_exists('wafRules', $data)) { + throw new \InvalidArgumentException('Missing required field "wafRules" for ' . static::class . '.'); + } if (!array_key_exists('projects', $data)) { throw new \InvalidArgumentException('Missing required field "projects" for ' . static::class . '.'); } @@ -366,6 +371,7 @@ public static function from(array $data): static screenshotsGenerated: $data['screenshotsGenerated'], members: $data['members'], webhooks: $data['webhooks'], + wafRules: $data['wafRules'], projects: $data['projects'], platforms: $data['platforms'], users: $data['users'], @@ -443,6 +449,7 @@ public function toArray(): array 'screenshotsGenerated' => static::serializeValue($this->screenshotsGenerated), 'members' => static::serializeValue($this->members), 'webhooks' => static::serializeValue($this->webhooks), + 'wafRules' => static::serializeValue($this->wafRules), 'projects' => static::serializeValue($this->projects), 'platforms' => static::serializeValue($this->platforms), 'users' => static::serializeValue($this->users), diff --git a/src/Appwrite/Models/Database.php b/src/Appwrite/Models/Database.php index 6a226440..fb6f77f3 100644 --- a/src/Appwrite/Models/Database.php +++ b/src/Appwrite/Models/Database.php @@ -21,9 +21,12 @@ * @param string $updatedAt database update date in iso 8601 format. * @param bool $enabled if database is enabled. can be 'enabled' or 'disabled'. when disabled, the database is inaccessible to users, but remains accessible to server sdks using api keys. * @param DatabaseType $type database type. - * @param list $policies database backup policies. - * @param list $archives database backup archives. - * @param DatabaseStatus|null $status database status. possible values: `provisioning`, `ready` or `failed` + * @param DatabaseStatus|null $status dedicated database lifecycle status. null when the database has no valid dedicated backing. + * @param string|null $engine underlying engine of the dedicated backing: postgresql, mysql, mariadb, or mongodb. a managed product (tablesdb, documentsdb, vectorsdb) reports the engine it runs on, so its type and engine can differ. null when the database has no dedicated backing. + * @param string|null $specification compute specification identifier of the dedicated backing, e.g. s-2vcpu-2gb. null when the database has no dedicated backing. + * @param int|null $replicas number of secondary high availability replicas, excluding the primary. null when backing configuration is unavailable. + * @param list|null $policies database backup policies. + * @param list|null $archives database backup archives. */ public function __construct( public string $id, @@ -32,9 +35,12 @@ public function __construct( public string $updatedAt, public bool $enabled, public DatabaseType $type, - public array $policies, - public array $archives, - public ?DatabaseStatus $status = null + public ?DatabaseStatus $status = null, + public ?string $engine = null, + public ?string $specification = null, + public ?int $replicas = null, + public ?array $policies = null, + public ?array $archives = null ) { } @@ -61,12 +67,6 @@ public static function from(array $data): static if (!array_key_exists('type', $data)) { throw new \InvalidArgumentException('Missing required field "type" for ' . static::class . '.'); } - if (!array_key_exists('policies', $data)) { - throw new \InvalidArgumentException('Missing required field "policies" for ' . static::class . '.'); - } - if (!array_key_exists('archives', $data)) { - throw new \InvalidArgumentException('Missing required field "archives" for ' . static::class . '.'); - } return new static( id: $data['$id'], @@ -75,19 +75,30 @@ public static function from(array $data): static updatedAt: $data['$updatedAt'], enabled: $data['enabled'], type: static::hydrateTypedValue(DatabaseType::class, $data['type']), - policies: is_array($data['policies']) - ? array_map( - static fn (mixed $item): mixed => static::hydrateTypedValue(BackupPolicy::class, $item), - $data['policies'] + status: array_key_exists('status', $data) ? static::hydrateTypedValue(DatabaseStatus::class, $data['status'], true) : null, + engine: array_key_exists('engine', $data) ? $data['engine'] : null, + specification: array_key_exists('specification', $data) ? $data['specification'] : null, + replicas: array_key_exists('replicas', $data) ? $data['replicas'] : null, + policies: array_key_exists('policies', $data) + ? ( + is_array($data['policies']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(BackupPolicy::class, $item), + $data['policies'] + ) + : $data['policies'] ) - : $data['policies'], - archives: is_array($data['archives']) - ? array_map( - static fn (mixed $item): mixed => static::hydrateTypedValue(BackupArchive::class, $item), - $data['archives'] + : null, + archives: array_key_exists('archives', $data) + ? ( + is_array($data['archives']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(BackupArchive::class, $item), + $data['archives'] + ) + : $data['archives'] ) - : $data['archives'], - status: array_key_exists('status', $data) ? static::hydrateTypedValue(DatabaseStatus::class, $data['status'], true) : null + : null ); } @@ -104,6 +115,9 @@ public function toArray(): array 'enabled' => static::serializeValue($this->enabled), 'type' => static::serializeValue($this->type), 'status' => static::serializeValue($this->status), + 'engine' => static::serializeValue($this->engine), + 'specification' => static::serializeValue($this->specification), + 'replicas' => static::serializeValue($this->replicas), 'policies' => static::serializeValue($this->policies), 'archives' => static::serializeValue($this->archives) ]; diff --git a/src/Appwrite/Models/DatabaseStatus.php b/src/Appwrite/Models/DatabaseStatus.php new file mode 100644 index 00000000..59b30ffd --- /dev/null +++ b/src/Appwrite/Models/DatabaseStatus.php @@ -0,0 +1,106 @@ + $replicas list of database replicas and their status. + * @param list $volumes storage volume information. + */ + public function __construct( + public string $health, + public bool $ready, + public string $engine, + public string $version, + public int $uptime, + public DatabaseStatusConnections $connections, + public array $replicas, + public array $volumes + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('health', $data)) { + throw new \InvalidArgumentException('Missing required field "health" for ' . static::class . '.'); + } + if (!array_key_exists('ready', $data)) { + throw new \InvalidArgumentException('Missing required field "ready" for ' . static::class . '.'); + } + if (!array_key_exists('engine', $data)) { + throw new \InvalidArgumentException('Missing required field "engine" for ' . static::class . '.'); + } + if (!array_key_exists('version', $data)) { + throw new \InvalidArgumentException('Missing required field "version" for ' . static::class . '.'); + } + if (!array_key_exists('uptime', $data)) { + throw new \InvalidArgumentException('Missing required field "uptime" for ' . static::class . '.'); + } + if (!array_key_exists('connections', $data)) { + throw new \InvalidArgumentException('Missing required field "connections" for ' . static::class . '.'); + } + if (!array_key_exists('replicas', $data)) { + throw new \InvalidArgumentException('Missing required field "replicas" for ' . static::class . '.'); + } + if (!array_key_exists('volumes', $data)) { + throw new \InvalidArgumentException('Missing required field "volumes" for ' . static::class . '.'); + } + + return new static( + health: $data['health'], + ready: $data['ready'], + engine: $data['engine'], + version: $data['version'], + uptime: $data['uptime'], + connections: static::hydrateTypedValue(DatabaseStatusConnections::class, $data['connections']), + replicas: is_array($data['replicas']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(DatabaseStatusReplica::class, $item), + $data['replicas'] + ) + : $data['replicas'], + volumes: is_array($data['volumes']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(DatabaseStatusVolume::class, $item), + $data['volumes'] + ) + : $data['volumes'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'health' => static::serializeValue($this->health), + 'ready' => static::serializeValue($this->ready), + 'engine' => static::serializeValue($this->engine), + 'version' => static::serializeValue($this->version), + 'uptime' => static::serializeValue($this->uptime), + 'connections' => static::serializeValue($this->connections), + 'replicas' => static::serializeValue($this->replicas), + 'volumes' => static::serializeValue($this->volumes) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DatabaseStatusConnections.php b/src/Appwrite/Models/DatabaseStatusConnections.php new file mode 100644 index 00000000..b1917238 --- /dev/null +++ b/src/Appwrite/Models/DatabaseStatusConnections.php @@ -0,0 +1,54 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('current', $data)) { + throw new \InvalidArgumentException('Missing required field "current" for ' . static::class . '.'); + } + if (!array_key_exists('max', $data)) { + throw new \InvalidArgumentException('Missing required field "max" for ' . static::class . '.'); + } + + return new static( + current: $data['current'], + max: $data['max'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'current' => static::serializeValue($this->current), + 'max' => static::serializeValue($this->max) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DatabaseStatusReplica.php b/src/Appwrite/Models/DatabaseStatusReplica.php new file mode 100644 index 00000000..acf6559c --- /dev/null +++ b/src/Appwrite/Models/DatabaseStatusReplica.php @@ -0,0 +1,65 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('index', $data)) { + throw new \InvalidArgumentException('Missing required field "index" for ' . static::class . '.'); + } + if (!array_key_exists('role', $data)) { + throw new \InvalidArgumentException('Missing required field "role" for ' . static::class . '.'); + } + if (!array_key_exists('healthy', $data)) { + throw new \InvalidArgumentException('Missing required field "healthy" for ' . static::class . '.'); + } + + return new static( + index: $data['index'], + role: $data['role'], + healthy: $data['healthy'], + lagSeconds: array_key_exists('lagSeconds', $data) ? $data['lagSeconds'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'index' => static::serializeValue($this->index), + 'role' => static::serializeValue($this->role), + 'healthy' => static::serializeValue($this->healthy), + 'lagSeconds' => static::serializeValue($this->lagSeconds) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DatabaseStatusVolume.php b/src/Appwrite/Models/DatabaseStatusVolume.php new file mode 100644 index 00000000..974ce9cf --- /dev/null +++ b/src/Appwrite/Models/DatabaseStatusVolume.php @@ -0,0 +1,68 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('path', $data)) { + throw new \InvalidArgumentException('Missing required field "path" for ' . static::class . '.'); + } + if (!array_key_exists('usedPercent', $data)) { + throw new \InvalidArgumentException('Missing required field "usedPercent" for ' . static::class . '.'); + } + if (!array_key_exists('available', $data)) { + throw new \InvalidArgumentException('Missing required field "available" for ' . static::class . '.'); + } + if (!array_key_exists('mounted', $data)) { + throw new \InvalidArgumentException('Missing required field "mounted" for ' . static::class . '.'); + } + + return new static( + path: $data['path'], + usedPercent: $data['usedPercent'], + available: $data['available'], + mounted: $data['mounted'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'path' => static::serializeValue($this->path), + 'usedPercent' => static::serializeValue($this->usedPercent), + 'available' => static::serializeValue($this->available), + 'mounted' => static::serializeValue($this->mounted) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DedicatedDatabase.php b/src/Appwrite/Models/DedicatedDatabase.php new file mode 100644 index 00000000..963e95fa --- /dev/null +++ b/src/Appwrite/Models/DedicatedDatabase.php @@ -0,0 +1,377 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('projectId', $data)) { + throw new \InvalidArgumentException('Missing required field "projectId" for ' . static::class . '.'); + } + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); + } + if (!array_key_exists('api', $data)) { + throw new \InvalidArgumentException('Missing required field "api" for ' . static::class . '.'); + } + if (!array_key_exists('engine', $data)) { + throw new \InvalidArgumentException('Missing required field "engine" for ' . static::class . '.'); + } + if (!array_key_exists('version', $data)) { + throw new \InvalidArgumentException('Missing required field "version" for ' . static::class . '.'); + } + if (!array_key_exists('specification', $data)) { + throw new \InvalidArgumentException('Missing required field "specification" for ' . static::class . '.'); + } + if (!array_key_exists('backend', $data)) { + throw new \InvalidArgumentException('Missing required field "backend" for ' . static::class . '.'); + } + if (!array_key_exists('hostname', $data)) { + throw new \InvalidArgumentException('Missing required field "hostname" for ' . static::class . '.'); + } + if (!array_key_exists('connectionPort', $data)) { + throw new \InvalidArgumentException('Missing required field "connectionPort" for ' . static::class . '.'); + } + if (!array_key_exists('connectionUser', $data)) { + throw new \InvalidArgumentException('Missing required field "connectionUser" for ' . static::class . '.'); + } + if (!array_key_exists('connectionPassword', $data)) { + throw new \InvalidArgumentException('Missing required field "connectionPassword" for ' . static::class . '.'); + } + if (!array_key_exists('connectionString', $data)) { + throw new \InvalidArgumentException('Missing required field "connectionString" for ' . static::class . '.'); + } + if (!array_key_exists('ssl', $data)) { + throw new \InvalidArgumentException('Missing required field "ssl" for ' . static::class . '.'); + } + if (!array_key_exists('status', $data)) { + throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); + } + if (!array_key_exists('containerStatus', $data)) { + throw new \InvalidArgumentException('Missing required field "containerStatus" for ' . static::class . '.'); + } + if (!array_key_exists('lifecycleState', $data)) { + throw new \InvalidArgumentException('Missing required field "lifecycleState" for ' . static::class . '.'); + } + if (!array_key_exists('idleTimeoutMinutes', $data)) { + throw new \InvalidArgumentException('Missing required field "idleTimeoutMinutes" for ' . static::class . '.'); + } + if (!array_key_exists('cpu', $data)) { + throw new \InvalidArgumentException('Missing required field "cpu" for ' . static::class . '.'); + } + if (!array_key_exists('memory', $data)) { + throw new \InvalidArgumentException('Missing required field "memory" for ' . static::class . '.'); + } + if (!array_key_exists('storage', $data)) { + throw new \InvalidArgumentException('Missing required field "storage" for ' . static::class . '.'); + } + if (!array_key_exists('storageClass', $data)) { + throw new \InvalidArgumentException('Missing required field "storageClass" for ' . static::class . '.'); + } + if (!array_key_exists('storageMaxGb', $data)) { + throw new \InvalidArgumentException('Missing required field "storageMaxGb" for ' . static::class . '.'); + } + if (!array_key_exists('nodePool', $data)) { + throw new \InvalidArgumentException('Missing required field "nodePool" for ' . static::class . '.'); + } + if (!array_key_exists('replicas', $data)) { + throw new \InvalidArgumentException('Missing required field "replicas" for ' . static::class . '.'); + } + if (!array_key_exists('syncMode', $data)) { + throw new \InvalidArgumentException('Missing required field "syncMode" for ' . static::class . '.'); + } + if (!array_key_exists('crossRegionReplicas', $data)) { + throw new \InvalidArgumentException('Missing required field "crossRegionReplicas" for ' . static::class . '.'); + } + if (!array_key_exists('networkMaxConnections', $data)) { + throw new \InvalidArgumentException('Missing required field "networkMaxConnections" for ' . static::class . '.'); + } + if (!array_key_exists('networkIdleTimeoutSeconds', $data)) { + throw new \InvalidArgumentException('Missing required field "networkIdleTimeoutSeconds" for ' . static::class . '.'); + } + if (!array_key_exists('networkIPAllowlist', $data)) { + throw new \InvalidArgumentException('Missing required field "networkIPAllowlist" for ' . static::class . '.'); + } + if (!array_key_exists('backupEnabled', $data)) { + throw new \InvalidArgumentException('Missing required field "backupEnabled" for ' . static::class . '.'); + } + if (!array_key_exists('pitr', $data)) { + throw new \InvalidArgumentException('Missing required field "pitr" for ' . static::class . '.'); + } + if (!array_key_exists('pitrRetentionDays', $data)) { + throw new \InvalidArgumentException('Missing required field "pitrRetentionDays" for ' . static::class . '.'); + } + if (!array_key_exists('storageAutoscaling', $data)) { + throw new \InvalidArgumentException('Missing required field "storageAutoscaling" for ' . static::class . '.'); + } + if (!array_key_exists('storageAutoscalingThresholdPercent', $data)) { + throw new \InvalidArgumentException('Missing required field "storageAutoscalingThresholdPercent" for ' . static::class . '.'); + } + if (!array_key_exists('storageAutoscalingMaxGb', $data)) { + throw new \InvalidArgumentException('Missing required field "storageAutoscalingMaxGb" for ' . static::class . '.'); + } + if (!array_key_exists('maintenanceWindowDay', $data)) { + throw new \InvalidArgumentException('Missing required field "maintenanceWindowDay" for ' . static::class . '.'); + } + if (!array_key_exists('maintenanceWindowHourUtc', $data)) { + throw new \InvalidArgumentException('Missing required field "maintenanceWindowHourUtc" for ' . static::class . '.'); + } + if (!array_key_exists('metricsEnabled', $data)) { + throw new \InvalidArgumentException('Missing required field "metricsEnabled" for ' . static::class . '.'); + } + if (!array_key_exists('sqlApiEnabled', $data)) { + throw new \InvalidArgumentException('Missing required field "sqlApiEnabled" for ' . static::class . '.'); + } + if (!array_key_exists('sqlApiAllowedStatements', $data)) { + throw new \InvalidArgumentException('Missing required field "sqlApiAllowedStatements" for ' . static::class . '.'); + } + if (!array_key_exists('sqlApiMaxRows', $data)) { + throw new \InvalidArgumentException('Missing required field "sqlApiMaxRows" for ' . static::class . '.'); + } + if (!array_key_exists('sqlApiMaxBytes', $data)) { + throw new \InvalidArgumentException('Missing required field "sqlApiMaxBytes" for ' . static::class . '.'); + } + if (!array_key_exists('sqlApiTimeoutSeconds', $data)) { + throw new \InvalidArgumentException('Missing required field "sqlApiTimeoutSeconds" for ' . static::class . '.'); + } + if (!array_key_exists('error', $data)) { + throw new \InvalidArgumentException('Missing required field "error" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + projectId: $data['projectId'], + name: $data['name'], + api: $data['api'], + engine: $data['engine'], + version: $data['version'], + specification: $data['specification'], + backend: $data['backend'], + hostname: $data['hostname'], + connectionPort: $data['connectionPort'], + connectionUser: $data['connectionUser'], + connectionPassword: $data['connectionPassword'], + connectionString: $data['connectionString'], + ssl: $data['ssl'], + status: $data['status'], + containerStatus: $data['containerStatus'], + lifecycleState: $data['lifecycleState'], + idleTimeoutMinutes: $data['idleTimeoutMinutes'], + cpu: $data['cpu'], + memory: $data['memory'], + storage: $data['storage'], + storageClass: $data['storageClass'], + storageMaxGb: $data['storageMaxGb'], + nodePool: $data['nodePool'], + replicas: $data['replicas'], + syncMode: $data['syncMode'], + crossRegionReplicas: $data['crossRegionReplicas'], + networkMaxConnections: $data['networkMaxConnections'], + networkIdleTimeoutSeconds: $data['networkIdleTimeoutSeconds'], + networkIPAllowlist: $data['networkIPAllowlist'], + backupEnabled: $data['backupEnabled'], + pitr: $data['pitr'], + pitrRetentionDays: $data['pitrRetentionDays'], + storageAutoscaling: $data['storageAutoscaling'], + storageAutoscalingThresholdPercent: $data['storageAutoscalingThresholdPercent'], + storageAutoscalingMaxGb: $data['storageAutoscalingMaxGb'], + maintenanceWindowDay: $data['maintenanceWindowDay'], + maintenanceWindowHourUtc: $data['maintenanceWindowHourUtc'], + metricsEnabled: $data['metricsEnabled'], + sqlApiEnabled: $data['sqlApiEnabled'], + sqlApiAllowedStatements: $data['sqlApiAllowedStatements'], + sqlApiMaxRows: $data['sqlApiMaxRows'], + sqlApiMaxBytes: $data['sqlApiMaxBytes'], + sqlApiTimeoutSeconds: $data['sqlApiTimeoutSeconds'], + error: $data['error'], + lastAccessedAt: array_key_exists('lastAccessedAt', $data) ? $data['lastAccessedAt'] : null, + idleUntil: array_key_exists('idleUntil', $data) ? $data['idleUntil'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'projectId' => static::serializeValue($this->projectId), + 'name' => static::serializeValue($this->name), + 'api' => static::serializeValue($this->api), + 'engine' => static::serializeValue($this->engine), + 'version' => static::serializeValue($this->version), + 'specification' => static::serializeValue($this->specification), + 'backend' => static::serializeValue($this->backend), + 'hostname' => static::serializeValue($this->hostname), + 'connectionPort' => static::serializeValue($this->connectionPort), + 'connectionUser' => static::serializeValue($this->connectionUser), + 'connectionPassword' => static::serializeValue($this->connectionPassword), + 'connectionString' => static::serializeValue($this->connectionString), + 'ssl' => static::serializeValue($this->ssl), + 'status' => static::serializeValue($this->status), + 'containerStatus' => static::serializeValue($this->containerStatus), + 'lastAccessedAt' => static::serializeValue($this->lastAccessedAt), + 'idleUntil' => static::serializeValue($this->idleUntil), + 'lifecycleState' => static::serializeValue($this->lifecycleState), + 'idleTimeoutMinutes' => static::serializeValue($this->idleTimeoutMinutes), + 'cpu' => static::serializeValue($this->cpu), + 'memory' => static::serializeValue($this->memory), + 'storage' => static::serializeValue($this->storage), + 'storageClass' => static::serializeValue($this->storageClass), + 'storageMaxGb' => static::serializeValue($this->storageMaxGb), + 'nodePool' => static::serializeValue($this->nodePool), + 'replicas' => static::serializeValue($this->replicas), + 'syncMode' => static::serializeValue($this->syncMode), + 'crossRegionReplicas' => static::serializeValue($this->crossRegionReplicas), + 'networkMaxConnections' => static::serializeValue($this->networkMaxConnections), + 'networkIdleTimeoutSeconds' => static::serializeValue($this->networkIdleTimeoutSeconds), + 'networkIPAllowlist' => static::serializeValue($this->networkIPAllowlist), + 'backupEnabled' => static::serializeValue($this->backupEnabled), + 'pitr' => static::serializeValue($this->pitr), + 'pitrRetentionDays' => static::serializeValue($this->pitrRetentionDays), + 'storageAutoscaling' => static::serializeValue($this->storageAutoscaling), + 'storageAutoscalingThresholdPercent' => static::serializeValue($this->storageAutoscalingThresholdPercent), + 'storageAutoscalingMaxGb' => static::serializeValue($this->storageAutoscalingMaxGb), + 'maintenanceWindowDay' => static::serializeValue($this->maintenanceWindowDay), + 'maintenanceWindowHourUtc' => static::serializeValue($this->maintenanceWindowHourUtc), + 'metricsEnabled' => static::serializeValue($this->metricsEnabled), + 'sqlApiEnabled' => static::serializeValue($this->sqlApiEnabled), + 'sqlApiAllowedStatements' => static::serializeValue($this->sqlApiAllowedStatements), + 'sqlApiMaxRows' => static::serializeValue($this->sqlApiMaxRows), + 'sqlApiMaxBytes' => static::serializeValue($this->sqlApiMaxBytes), + 'sqlApiTimeoutSeconds' => static::serializeValue($this->sqlApiTimeoutSeconds), + 'error' => static::serializeValue($this->error) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DedicatedDatabaseMember.php b/src/Appwrite/Models/DedicatedDatabaseMember.php new file mode 100644 index 00000000..ba44af70 --- /dev/null +++ b/src/Appwrite/Models/DedicatedDatabaseMember.php @@ -0,0 +1,68 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('role', $data)) { + throw new \InvalidArgumentException('Missing required field "role" for ' . static::class . '.'); + } + if (!array_key_exists('status', $data)) { + throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); + } + if (!array_key_exists('lagSeconds', $data)) { + throw new \InvalidArgumentException('Missing required field "lagSeconds" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + role: $data['role'], + status: $data['status'], + lagSeconds: $data['lagSeconds'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + 'role' => static::serializeValue($this->role), + 'status' => static::serializeValue($this->status), + 'lagSeconds' => static::serializeValue($this->lagSeconds) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DedicatedDatabaseReplicas.php b/src/Appwrite/Models/DedicatedDatabaseReplicas.php new file mode 100644 index 00000000..37a760d2 --- /dev/null +++ b/src/Appwrite/Models/DedicatedDatabaseReplicas.php @@ -0,0 +1,66 @@ + $members per-pod statuses for the primary and every replica. + */ + public function __construct( + public int $replicas, + public string $syncMode, + public array $members + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('replicas', $data)) { + throw new \InvalidArgumentException('Missing required field "replicas" for ' . static::class . '.'); + } + if (!array_key_exists('syncMode', $data)) { + throw new \InvalidArgumentException('Missing required field "syncMode" for ' . static::class . '.'); + } + if (!array_key_exists('members', $data)) { + throw new \InvalidArgumentException('Missing required field "members" for ' . static::class . '.'); + } + + return new static( + replicas: $data['replicas'], + syncMode: $data['syncMode'], + members: is_array($data['members']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(DedicatedDatabaseMember::class, $item), + $data['members'] + ) + : $data['members'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'replicas' => static::serializeValue($this->replicas), + 'syncMode' => static::serializeValue($this->syncMode), + 'members' => static::serializeValue($this->members) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DedicatedDatabaseSpecification.php b/src/Appwrite/Models/DedicatedDatabaseSpecification.php new file mode 100644 index 00000000..5a1a5a29 --- /dev/null +++ b/src/Appwrite/Models/DedicatedDatabaseSpecification.php @@ -0,0 +1,103 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('slug', $data)) { + throw new \InvalidArgumentException('Missing required field "slug" for ' . static::class . '.'); + } + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); + } + if (!array_key_exists('price', $data)) { + throw new \InvalidArgumentException('Missing required field "price" for ' . static::class . '.'); + } + if (!array_key_exists('cpu', $data)) { + throw new \InvalidArgumentException('Missing required field "cpu" for ' . static::class . '.'); + } + if (!array_key_exists('memory', $data)) { + throw new \InvalidArgumentException('Missing required field "memory" for ' . static::class . '.'); + } + if (!array_key_exists('maxConnections', $data)) { + throw new \InvalidArgumentException('Missing required field "maxConnections" for ' . static::class . '.'); + } + if (!array_key_exists('includedStorage', $data)) { + throw new \InvalidArgumentException('Missing required field "includedStorage" for ' . static::class . '.'); + } + if (!array_key_exists('includedBandwidth', $data)) { + throw new \InvalidArgumentException('Missing required field "includedBandwidth" for ' . static::class . '.'); + } + if (!array_key_exists('enabled', $data)) { + throw new \InvalidArgumentException('Missing required field "enabled" for ' . static::class . '.'); + } + + return new static( + slug: $data['slug'], + name: $data['name'], + price: $data['price'], + cpu: $data['cpu'], + memory: $data['memory'], + maxConnections: $data['maxConnections'], + includedStorage: $data['includedStorage'], + includedBandwidth: $data['includedBandwidth'], + enabled: $data['enabled'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'slug' => static::serializeValue($this->slug), + 'name' => static::serializeValue($this->name), + 'price' => static::serializeValue($this->price), + 'cpu' => static::serializeValue($this->cpu), + 'memory' => static::serializeValue($this->memory), + 'maxConnections' => static::serializeValue($this->maxConnections), + 'includedStorage' => static::serializeValue($this->includedStorage), + 'includedBandwidth' => static::serializeValue($this->includedBandwidth), + 'enabled' => static::serializeValue($this->enabled) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DedicatedDatabaseSpecificationList.php b/src/Appwrite/Models/DedicatedDatabaseSpecificationList.php new file mode 100644 index 00000000..fb040cd3 --- /dev/null +++ b/src/Appwrite/Models/DedicatedDatabaseSpecificationList.php @@ -0,0 +1,66 @@ + $specifications list of dedicated database specifications. + * @param int $total total number of specifications. + * @param DedicatedDatabaseSpecificationPricing $pricing overage and add-on pricing shared across all specifications. + */ + public function __construct( + public array $specifications, + public int $total, + public DedicatedDatabaseSpecificationPricing $pricing + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('specifications', $data)) { + throw new \InvalidArgumentException('Missing required field "specifications" for ' . static::class . '.'); + } + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('pricing', $data)) { + throw new \InvalidArgumentException('Missing required field "pricing" for ' . static::class . '.'); + } + + return new static( + specifications: is_array($data['specifications']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(DedicatedDatabaseSpecification::class, $item), + $data['specifications'] + ) + : $data['specifications'], + total: $data['total'], + pricing: static::hydrateTypedValue(DedicatedDatabaseSpecificationPricing::class, $data['pricing']) + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'specifications' => static::serializeValue($this->specifications), + 'total' => static::serializeValue($this->total), + 'pricing' => static::serializeValue($this->pricing) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DedicatedDatabaseSpecificationPricing.php b/src/Appwrite/Models/DedicatedDatabaseSpecificationPricing.php new file mode 100644 index 00000000..37a3b4c2 --- /dev/null +++ b/src/Appwrite/Models/DedicatedDatabaseSpecificationPricing.php @@ -0,0 +1,75 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('storageOverageRate', $data)) { + throw new \InvalidArgumentException('Missing required field "storageOverageRate" for ' . static::class . '.'); + } + if (!array_key_exists('bandwidthOverageRate', $data)) { + throw new \InvalidArgumentException('Missing required field "bandwidthOverageRate" for ' . static::class . '.'); + } + if (!array_key_exists('replicaRate', $data)) { + throw new \InvalidArgumentException('Missing required field "replicaRate" for ' . static::class . '.'); + } + if (!array_key_exists('crossRegionReplicaRate', $data)) { + throw new \InvalidArgumentException('Missing required field "crossRegionReplicaRate" for ' . static::class . '.'); + } + if (!array_key_exists('pitrRate', $data)) { + throw new \InvalidArgumentException('Missing required field "pitrRate" for ' . static::class . '.'); + } + + return new static( + storageOverageRate: $data['storageOverageRate'], + bandwidthOverageRate: $data['bandwidthOverageRate'], + replicaRate: $data['replicaRate'], + crossRegionReplicaRate: $data['crossRegionReplicaRate'], + pitrRate: $data['pitrRate'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'storageOverageRate' => static::serializeValue($this->storageOverageRate), + 'bandwidthOverageRate' => static::serializeValue($this->bandwidthOverageRate), + 'replicaRate' => static::serializeValue($this->replicaRate), + 'crossRegionReplicaRate' => static::serializeValue($this->crossRegionReplicaRate), + 'pitrRate' => static::serializeValue($this->pitrRate) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2Approve.php b/src/Appwrite/Models/Oauth2Approve.php new file mode 100644 index 00000000..e4f896d3 --- /dev/null +++ b/src/Appwrite/Models/Oauth2Approve.php @@ -0,0 +1,47 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('redirectUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "redirectUrl" for ' . static::class . '.'); + } + + return new static( + redirectUrl: $data['redirectUrl'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'redirectUrl' => static::serializeValue($this->redirectUrl) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2Authorize.php b/src/Appwrite/Models/Oauth2Authorize.php new file mode 100644 index 00000000..4667084b --- /dev/null +++ b/src/Appwrite/Models/Oauth2Authorize.php @@ -0,0 +1,54 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('grantId', $data)) { + throw new \InvalidArgumentException('Missing required field "grantId" for ' . static::class . '.'); + } + if (!array_key_exists('redirectUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "redirectUrl" for ' . static::class . '.'); + } + + return new static( + grantId: $data['grantId'], + redirectUrl: $data['redirectUrl'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'grantId' => static::serializeValue($this->grantId), + 'redirectUrl' => static::serializeValue($this->redirectUrl) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2Consent.php b/src/Appwrite/Models/Oauth2Consent.php new file mode 100644 index 00000000..248995ec --- /dev/null +++ b/src/Appwrite/Models/Oauth2Consent.php @@ -0,0 +1,110 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('userId', $data)) { + throw new \InvalidArgumentException('Missing required field "userId" for ' . static::class . '.'); + } + if (!array_key_exists('appId', $data)) { + throw new \InvalidArgumentException('Missing required field "appId" for ' . static::class . '.'); + } + if (!array_key_exists('cimdUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "cimdUrl" for ' . static::class . '.'); + } + if (!array_key_exists('scopes', $data)) { + throw new \InvalidArgumentException('Missing required field "scopes" for ' . static::class . '.'); + } + if (!array_key_exists('resources', $data)) { + throw new \InvalidArgumentException('Missing required field "resources" for ' . static::class . '.'); + } + if (!array_key_exists('authorizationDetails', $data)) { + throw new \InvalidArgumentException('Missing required field "authorizationDetails" for ' . static::class . '.'); + } + if (!array_key_exists('expire', $data)) { + throw new \InvalidArgumentException('Missing required field "expire" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + userId: $data['userId'], + appId: $data['appId'], + cimdUrl: $data['cimdUrl'], + scopes: $data['scopes'], + resources: $data['resources'], + authorizationDetails: $data['authorizationDetails'], + expire: $data['expire'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'userId' => static::serializeValue($this->userId), + 'appId' => static::serializeValue($this->appId), + 'cimdUrl' => static::serializeValue($this->cimdUrl), + 'scopes' => static::serializeValue($this->scopes), + 'resources' => static::serializeValue($this->resources), + 'authorizationDetails' => static::serializeValue($this->authorizationDetails), + 'expire' => static::serializeValue($this->expire) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2ConsentList.php b/src/Appwrite/Models/Oauth2ConsentList.php new file mode 100644 index 00000000..e6b0da7b --- /dev/null +++ b/src/Appwrite/Models/Oauth2ConsentList.php @@ -0,0 +1,59 @@ + $consents list of consents. + */ + public function __construct( + public int $total, + public array $consents + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('consents', $data)) { + throw new \InvalidArgumentException('Missing required field "consents" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + consents: is_array($data['consents']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(Oauth2Consent::class, $item), + $data['consents'] + ) + : $data['consents'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'consents' => static::serializeValue($this->consents) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2ConsentToken.php b/src/Appwrite/Models/Oauth2ConsentToken.php new file mode 100644 index 00000000..1c363fb4 --- /dev/null +++ b/src/Appwrite/Models/Oauth2ConsentToken.php @@ -0,0 +1,117 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('consentId', $data)) { + throw new \InvalidArgumentException('Missing required field "consentId" for ' . static::class . '.'); + } + if (!array_key_exists('userId', $data)) { + throw new \InvalidArgumentException('Missing required field "userId" for ' . static::class . '.'); + } + if (!array_key_exists('appId', $data)) { + throw new \InvalidArgumentException('Missing required field "appId" for ' . static::class . '.'); + } + if (!array_key_exists('cimdUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "cimdUrl" for ' . static::class . '.'); + } + if (!array_key_exists('scopes', $data)) { + throw new \InvalidArgumentException('Missing required field "scopes" for ' . static::class . '.'); + } + if (!array_key_exists('resources', $data)) { + throw new \InvalidArgumentException('Missing required field "resources" for ' . static::class . '.'); + } + if (!array_key_exists('authorizationDetails', $data)) { + throw new \InvalidArgumentException('Missing required field "authorizationDetails" for ' . static::class . '.'); + } + if (!array_key_exists('expire', $data)) { + throw new \InvalidArgumentException('Missing required field "expire" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + consentId: $data['consentId'], + userId: $data['userId'], + appId: $data['appId'], + cimdUrl: $data['cimdUrl'], + scopes: $data['scopes'], + resources: $data['resources'], + authorizationDetails: $data['authorizationDetails'], + expire: $data['expire'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'consentId' => static::serializeValue($this->consentId), + 'userId' => static::serializeValue($this->userId), + 'appId' => static::serializeValue($this->appId), + 'cimdUrl' => static::serializeValue($this->cimdUrl), + 'scopes' => static::serializeValue($this->scopes), + 'resources' => static::serializeValue($this->resources), + 'authorizationDetails' => static::serializeValue($this->authorizationDetails), + 'expire' => static::serializeValue($this->expire) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2ConsentTokenList.php b/src/Appwrite/Models/Oauth2ConsentTokenList.php new file mode 100644 index 00000000..d24f6382 --- /dev/null +++ b/src/Appwrite/Models/Oauth2ConsentTokenList.php @@ -0,0 +1,59 @@ + $tokens list of tokens. + */ + public function __construct( + public int $total, + public array $tokens + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('tokens', $data)) { + throw new \InvalidArgumentException('Missing required field "tokens" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + tokens: is_array($data['tokens']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(Oauth2ConsentToken::class, $item), + $data['tokens'] + ) + : $data['tokens'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'tokens' => static::serializeValue($this->tokens) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2DeviceAuthorization.php b/src/Appwrite/Models/Oauth2DeviceAuthorization.php new file mode 100644 index 00000000..6f295a44 --- /dev/null +++ b/src/Appwrite/Models/Oauth2DeviceAuthorization.php @@ -0,0 +1,82 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('device_code', $data)) { + throw new \InvalidArgumentException('Missing required field "device_code" for ' . static::class . '.'); + } + if (!array_key_exists('user_code', $data)) { + throw new \InvalidArgumentException('Missing required field "user_code" for ' . static::class . '.'); + } + if (!array_key_exists('verification_uri', $data)) { + throw new \InvalidArgumentException('Missing required field "verification_uri" for ' . static::class . '.'); + } + if (!array_key_exists('verification_uri_complete', $data)) { + throw new \InvalidArgumentException('Missing required field "verification_uri_complete" for ' . static::class . '.'); + } + if (!array_key_exists('expires_in', $data)) { + throw new \InvalidArgumentException('Missing required field "expires_in" for ' . static::class . '.'); + } + if (!array_key_exists('interval', $data)) { + throw new \InvalidArgumentException('Missing required field "interval" for ' . static::class . '.'); + } + + return new static( + deviceCode: $data['device_code'], + userCode: $data['user_code'], + verificationUri: $data['verification_uri'], + verificationUriComplete: $data['verification_uri_complete'], + expiresIn: $data['expires_in'], + interval: $data['interval'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'device_code' => static::serializeValue($this->deviceCode), + 'user_code' => static::serializeValue($this->userCode), + 'verification_uri' => static::serializeValue($this->verificationUri), + 'verification_uri_complete' => static::serializeValue($this->verificationUriComplete), + 'expires_in' => static::serializeValue($this->expiresIn), + 'interval' => static::serializeValue($this->interval) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2Grant.php b/src/Appwrite/Models/Oauth2Grant.php new file mode 100644 index 00000000..4b8de2f9 --- /dev/null +++ b/src/Appwrite/Models/Oauth2Grant.php @@ -0,0 +1,124 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('userId', $data)) { + throw new \InvalidArgumentException('Missing required field "userId" for ' . static::class . '.'); + } + if (!array_key_exists('appId', $data)) { + throw new \InvalidArgumentException('Missing required field "appId" for ' . static::class . '.'); + } + if (!array_key_exists('scopes', $data)) { + throw new \InvalidArgumentException('Missing required field "scopes" for ' . static::class . '.'); + } + if (!array_key_exists('resources', $data)) { + throw new \InvalidArgumentException('Missing required field "resources" for ' . static::class . '.'); + } + if (!array_key_exists('authorizationDetails', $data)) { + throw new \InvalidArgumentException('Missing required field "authorizationDetails" for ' . static::class . '.'); + } + if (!array_key_exists('prompt', $data)) { + throw new \InvalidArgumentException('Missing required field "prompt" for ' . static::class . '.'); + } + if (!array_key_exists('redirectUri', $data)) { + throw new \InvalidArgumentException('Missing required field "redirectUri" for ' . static::class . '.'); + } + if (!array_key_exists('authTime', $data)) { + throw new \InvalidArgumentException('Missing required field "authTime" for ' . static::class . '.'); + } + if (!array_key_exists('expire', $data)) { + throw new \InvalidArgumentException('Missing required field "expire" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + userId: $data['userId'], + appId: $data['appId'], + scopes: $data['scopes'], + resources: $data['resources'], + authorizationDetails: $data['authorizationDetails'], + prompt: $data['prompt'], + redirectUri: $data['redirectUri'], + authTime: $data['authTime'], + expire: $data['expire'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'userId' => static::serializeValue($this->userId), + 'appId' => static::serializeValue($this->appId), + 'scopes' => static::serializeValue($this->scopes), + 'resources' => static::serializeValue($this->resources), + 'authorizationDetails' => static::serializeValue($this->authorizationDetails), + 'prompt' => static::serializeValue($this->prompt), + 'redirectUri' => static::serializeValue($this->redirectUri), + 'authTime' => static::serializeValue($this->authTime), + 'expire' => static::serializeValue($this->expire) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2Organization.php b/src/Appwrite/Models/Oauth2Organization.php new file mode 100644 index 00000000..25a7dcff --- /dev/null +++ b/src/Appwrite/Models/Oauth2Organization.php @@ -0,0 +1,47 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2OrganizationList.php b/src/Appwrite/Models/Oauth2OrganizationList.php new file mode 100644 index 00000000..2f29ee00 --- /dev/null +++ b/src/Appwrite/Models/Oauth2OrganizationList.php @@ -0,0 +1,59 @@ + $organizations list of organizations. + */ + public function __construct( + public int $total, + public array $organizations + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('organizations', $data)) { + throw new \InvalidArgumentException('Missing required field "organizations" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + organizations: is_array($data['organizations']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(Oauth2Organization::class, $item), + $data['organizations'] + ) + : $data['organizations'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'organizations' => static::serializeValue($this->organizations) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2PAR.php b/src/Appwrite/Models/Oauth2PAR.php new file mode 100644 index 00000000..d6f7d677 --- /dev/null +++ b/src/Appwrite/Models/Oauth2PAR.php @@ -0,0 +1,54 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('request_uri', $data)) { + throw new \InvalidArgumentException('Missing required field "request_uri" for ' . static::class . '.'); + } + if (!array_key_exists('expires_in', $data)) { + throw new \InvalidArgumentException('Missing required field "expires_in" for ' . static::class . '.'); + } + + return new static( + requestUri: $data['request_uri'], + expiresIn: $data['expires_in'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'request_uri' => static::serializeValue($this->requestUri), + 'expires_in' => static::serializeValue($this->expiresIn) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2Project.php b/src/Appwrite/Models/Oauth2Project.php new file mode 100644 index 00000000..e7f9725d --- /dev/null +++ b/src/Appwrite/Models/Oauth2Project.php @@ -0,0 +1,61 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('region', $data)) { + throw new \InvalidArgumentException('Missing required field "region" for ' . static::class . '.'); + } + if (!array_key_exists('endpoint', $data)) { + throw new \InvalidArgumentException('Missing required field "endpoint" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + region: $data['region'], + endpoint: $data['endpoint'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + 'region' => static::serializeValue($this->region), + 'endpoint' => static::serializeValue($this->endpoint) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2ProjectList.php b/src/Appwrite/Models/Oauth2ProjectList.php new file mode 100644 index 00000000..efa948b8 --- /dev/null +++ b/src/Appwrite/Models/Oauth2ProjectList.php @@ -0,0 +1,59 @@ + $projects list of projects. + */ + public function __construct( + public int $total, + public array $projects + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('projects', $data)) { + throw new \InvalidArgumentException('Missing required field "projects" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + projects: is_array($data['projects']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(Oauth2Project::class, $item), + $data['projects'] + ) + : $data['projects'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'projects' => static::serializeValue($this->projects) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2Reject.php b/src/Appwrite/Models/Oauth2Reject.php new file mode 100644 index 00000000..57304a14 --- /dev/null +++ b/src/Appwrite/Models/Oauth2Reject.php @@ -0,0 +1,47 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('redirectUrl', $data)) { + throw new \InvalidArgumentException('Missing required field "redirectUrl" for ' . static::class . '.'); + } + + return new static( + redirectUrl: $data['redirectUrl'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'redirectUrl' => static::serializeValue($this->redirectUrl) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Oauth2Token.php b/src/Appwrite/Models/Oauth2Token.php new file mode 100644 index 00000000..b9bbb593 --- /dev/null +++ b/src/Appwrite/Models/Oauth2Token.php @@ -0,0 +1,83 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('access_token', $data)) { + throw new \InvalidArgumentException('Missing required field "access_token" for ' . static::class . '.'); + } + if (!array_key_exists('token_type', $data)) { + throw new \InvalidArgumentException('Missing required field "token_type" for ' . static::class . '.'); + } + if (!array_key_exists('expires_in', $data)) { + throw new \InvalidArgumentException('Missing required field "expires_in" for ' . static::class . '.'); + } + if (!array_key_exists('refresh_token', $data)) { + throw new \InvalidArgumentException('Missing required field "refresh_token" for ' . static::class . '.'); + } + if (!array_key_exists('scope', $data)) { + throw new \InvalidArgumentException('Missing required field "scope" for ' . static::class . '.'); + } + + return new static( + accessToken: $data['access_token'], + tokenType: $data['token_type'], + expiresIn: $data['expires_in'], + refreshToken: $data['refresh_token'], + scope: $data['scope'], + authorizationDetails: array_key_exists('authorization_details', $data) ? $data['authorization_details'] : null, + idToken: array_key_exists('id_token', $data) ? $data['id_token'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'access_token' => static::serializeValue($this->accessToken), + 'token_type' => static::serializeValue($this->tokenType), + 'expires_in' => static::serializeValue($this->expiresIn), + 'refresh_token' => static::serializeValue($this->refreshToken), + 'scope' => static::serializeValue($this->scope), + 'authorization_details' => static::serializeValue($this->authorizationDetails), + 'id_token' => static::serializeValue($this->idToken) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Project.php b/src/Appwrite/Models/Project.php index f2af24d4..f9013ca9 100644 --- a/src/Appwrite/Models/Project.php +++ b/src/Appwrite/Models/Project.php @@ -39,6 +39,7 @@ * @param list $protocols list of protocols. * @param list $blocks project blocks information * @param string $consoleAccessedAt last time the project was accessed via console. used with plan's projectinactivitydays to determine if project is paused. + * @param bool $wafEnabled whether waf enforcement is enabled for the project. * @param BillingLimits|null $billingLimits billing limits reached * @param bool|null $oAuth2ServerEnabled oauth2 server status * @param string|null $oAuth2ServerAuthorizationUrl oauth2 server authorization url @@ -49,6 +50,7 @@ * @param int|null $oAuth2ServerRefreshTokenDuration oauth2 server refresh token duration in seconds for confidential clients * @param int|null $oAuth2ServerPublicAccessTokenDuration oauth2 server access token duration in seconds for public clients (spas, mobile, native) * @param int|null $oAuth2ServerPublicRefreshTokenDuration oauth2 server refresh token duration in seconds for public clients (spas, mobile, native) + * @param int|null $oAuth2ServerInstallationAccessTokenDuration oauth2 server access token duration in seconds for app installation access tokens * @param bool|null $oAuth2ServerConfidentialPkce when enabled, pkce is required for confidential clients (server-side flows using client_secret). pkce is always required for public clients regardless of this setting. * @param string|null $oAuth2ServerVerificationUrl url to your application page where users enter the device flow user code. empty when the device authorization grant is not configured. * @param int|null $oAuth2ServerUserCodeLength number of characters in the device flow user code, excluding the formatting separator. @@ -84,6 +86,7 @@ public function __construct( public array $protocols, public array $blocks, public string $consoleAccessedAt, + public bool $wafEnabled, public ?BillingLimits $billingLimits = null, public ?bool $oAuth2ServerEnabled = null, public ?string $oAuth2ServerAuthorizationUrl = null, @@ -94,6 +97,7 @@ public function __construct( public ?int $oAuth2ServerRefreshTokenDuration = null, public ?int $oAuth2ServerPublicAccessTokenDuration = null, public ?int $oAuth2ServerPublicRefreshTokenDuration = null, + public ?int $oAuth2ServerInstallationAccessTokenDuration = null, public ?bool $oAuth2ServerConfidentialPkce = null, public ?string $oAuth2ServerVerificationUrl = null, public ?int $oAuth2ServerUserCodeLength = null, @@ -189,6 +193,9 @@ public static function from(array $data): static if (!array_key_exists('consoleAccessedAt', $data)) { throw new \InvalidArgumentException('Missing required field "consoleAccessedAt" for ' . static::class . '.'); } + if (!array_key_exists('wafEnabled', $data)) { + throw new \InvalidArgumentException('Missing required field "wafEnabled" for ' . static::class . '.'); + } return new static( id: $data['$id'], @@ -243,6 +250,7 @@ public static function from(array $data): static ) : $data['blocks'], consoleAccessedAt: $data['consoleAccessedAt'], + wafEnabled: $data['wafEnabled'], billingLimits: array_key_exists('billingLimits', $data) ? static::hydrateTypedValue(BillingLimits::class, $data['billingLimits'], true) : null, oAuth2ServerEnabled: array_key_exists('oAuth2ServerEnabled', $data) ? $data['oAuth2ServerEnabled'] : null, oAuth2ServerAuthorizationUrl: array_key_exists('oAuth2ServerAuthorizationUrl', $data) ? $data['oAuth2ServerAuthorizationUrl'] : null, @@ -253,6 +261,7 @@ public static function from(array $data): static oAuth2ServerRefreshTokenDuration: array_key_exists('oAuth2ServerRefreshTokenDuration', $data) ? $data['oAuth2ServerRefreshTokenDuration'] : null, oAuth2ServerPublicAccessTokenDuration: array_key_exists('oAuth2ServerPublicAccessTokenDuration', $data) ? $data['oAuth2ServerPublicAccessTokenDuration'] : null, oAuth2ServerPublicRefreshTokenDuration: array_key_exists('oAuth2ServerPublicRefreshTokenDuration', $data) ? $data['oAuth2ServerPublicRefreshTokenDuration'] : null, + oAuth2ServerInstallationAccessTokenDuration: array_key_exists('oAuth2ServerInstallationAccessTokenDuration', $data) ? $data['oAuth2ServerInstallationAccessTokenDuration'] : null, oAuth2ServerConfidentialPkce: array_key_exists('oAuth2ServerConfidentialPkce', $data) ? $data['oAuth2ServerConfidentialPkce'] : null, oAuth2ServerVerificationUrl: array_key_exists('oAuth2ServerVerificationUrl', $data) ? $data['oAuth2ServerVerificationUrl'] : null, oAuth2ServerUserCodeLength: array_key_exists('oAuth2ServerUserCodeLength', $data) ? $data['oAuth2ServerUserCodeLength'] : null, @@ -295,6 +304,7 @@ public function toArray(): array 'protocols' => static::serializeValue($this->protocols), 'blocks' => static::serializeValue($this->blocks), 'consoleAccessedAt' => static::serializeValue($this->consoleAccessedAt), + 'wafEnabled' => static::serializeValue($this->wafEnabled), 'billingLimits' => static::serializeValue($this->billingLimits), 'oAuth2ServerEnabled' => static::serializeValue($this->oAuth2ServerEnabled), 'oAuth2ServerAuthorizationUrl' => static::serializeValue($this->oAuth2ServerAuthorizationUrl), @@ -305,6 +315,7 @@ public function toArray(): array 'oAuth2ServerRefreshTokenDuration' => static::serializeValue($this->oAuth2ServerRefreshTokenDuration), 'oAuth2ServerPublicAccessTokenDuration' => static::serializeValue($this->oAuth2ServerPublicAccessTokenDuration), 'oAuth2ServerPublicRefreshTokenDuration' => static::serializeValue($this->oAuth2ServerPublicRefreshTokenDuration), + 'oAuth2ServerInstallationAccessTokenDuration' => static::serializeValue($this->oAuth2ServerInstallationAccessTokenDuration), 'oAuth2ServerConfidentialPkce' => static::serializeValue($this->oAuth2ServerConfidentialPkce), 'oAuth2ServerVerificationUrl' => static::serializeValue($this->oAuth2ServerVerificationUrl), 'oAuth2ServerUserCodeLength' => static::serializeValue($this->oAuth2ServerUserCodeLength), diff --git a/src/Appwrite/Services/Account.php b/src/Appwrite/Services/Account.php index e5b62b63..441e05da 100644 --- a/src/Appwrite/Services/Account.php +++ b/src/Appwrite/Services/Account.php @@ -105,6 +105,253 @@ public function create(string $userId, string $email, string $password, ?string } + /** + * Get a list of the OAuth2 consents the current user has given to third-party + * apps. + * + * @param ?array $queries + * @param ?bool $total + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2ConsentList + */ + public function listConsents(?array $queries = null, ?bool $total = null): \Appwrite\Models\Oauth2ConsentList + { + $apiPath = str_replace( + [], + [], + '/account/consents' + ); + + $apiParams = []; + + if (!is_null($queries)) { + $apiParams['queries'] = $queries; + } + + if (!is_null($total)) { + $apiParams['total'] = $total; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2ConsentList::from($response); + + } + + /** + * Get an OAuth2 consent the current user has given to a third-party app by + * its unique ID. + * + * @param string $consentId + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2Consent + */ + public function getConsent(string $consentId): \Appwrite\Models\Oauth2Consent + { + $apiPath = str_replace( + ['{consentId}'], + [$consentId], + '/account/consents/{consentId}' + ); + + $apiParams = []; + $apiParams['consentId'] = $consentId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Consent::from($response); + + } + + /** + * Delete an OAuth2 consent by its unique ID. All token families issued under + * the consent are revoked, and the app must ask for consent again to regain + * access. + * + * @param string $consentId + * @throws AppwriteException + * @return string + */ + public function deleteConsent(string $consentId): string + { + $apiPath = str_replace( + ['{consentId}'], + [$consentId], + '/account/consents/{consentId}' + ); + + $apiParams = []; + $apiParams['consentId'] = $consentId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + + /** + * Get a list of the token families issued under an OAuth2 consent. Each entry + * represents one authorized device or session; the token secrets themselves + * are never returned. + * + * @param string $consentId + * @param ?array $queries + * @param ?bool $total + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2ConsentTokenList + */ + public function listConsentTokens(string $consentId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\Oauth2ConsentTokenList + { + $apiPath = str_replace( + ['{consentId}'], + [$consentId], + '/account/consents/{consentId}/tokens' + ); + + $apiParams = []; + $apiParams['consentId'] = $consentId; + + if (!is_null($queries)) { + $apiParams['queries'] = $queries; + } + + if (!is_null($total)) { + $apiParams['total'] = $total; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2ConsentTokenList::from($response); + + } + + /** + * Get a token family issued under an OAuth2 consent by its unique ID. The + * token secrets themselves are never returned. + * + * @param string $consentId + * @param string $tokenId + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2ConsentToken + */ + public function getConsentToken(string $consentId, string $tokenId): \Appwrite\Models\Oauth2ConsentToken + { + $apiPath = str_replace( + ['{consentId}', '{tokenId}'], + [$consentId, $tokenId], + '/account/consents/{consentId}/tokens/{tokenId}' + ); + + $apiParams = []; + $apiParams['consentId'] = $consentId; + $apiParams['tokenId'] = $tokenId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2ConsentToken::from($response); + + } + + /** + * Delete a token family issued under an OAuth2 consent by its unique ID. The + * access and refresh tokens of the family stop working immediately; other + * token families and the consent itself are unaffected. + * + * @param string $consentId + * @param string $tokenId + * @throws AppwriteException + * @return string + */ + public function deleteConsentToken(string $consentId, string $tokenId): string + { + $apiPath = str_replace( + ['{consentId}', '{tokenId}'], + [$consentId, $tokenId], + '/account/consents/{consentId}/tokens/{tokenId}' + ); + + $apiParams = []; + $apiParams['consentId'] = $consentId; + $apiParams['tokenId'] = $tokenId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + /** * Update currently logged in user account email address. After changing user * address, the user confirmation status will get reset. A new confirmation diff --git a/src/Appwrite/Services/Apps.php b/src/Appwrite/Services/Apps.php new file mode 100644 index 00000000..d0a9c896 --- /dev/null +++ b/src/Appwrite/Services/Apps.php @@ -0,0 +1,1026 @@ +client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppsList::from($response); + + } + + /** + * Create a new application. + * + * @param string $appId + * @param string $name + * @param array $redirectUris + * @param ?string $description + * @param ?string $clientUri + * @param ?string $logoUri + * @param ?string $privacyPolicyUrl + * @param ?string $termsUrl + * @param ?array $contacts + * @param ?string $tagline + * @param ?array $tags + * @param ?array $images + * @param ?string $supportUrl + * @param ?string $dataDeletionUrl + * @param ?array $postLogoutRedirectUris + * @param ?bool $enabled + * @param ?string $type + * @param ?bool $deviceFlow + * @param ?string $teamId + * @throws AppwriteException + * @return \Appwrite\Models\App + */ + public function create(string $appId, string $name, array $redirectUris, ?string $description = null, ?string $clientUri = null, ?string $logoUri = null, ?string $privacyPolicyUrl = null, ?string $termsUrl = null, ?array $contacts = null, ?string $tagline = null, ?array $tags = null, ?array $images = null, ?string $supportUrl = null, ?string $dataDeletionUrl = null, ?array $postLogoutRedirectUris = null, ?bool $enabled = null, ?string $type = null, ?bool $deviceFlow = null, ?string $teamId = null): \Appwrite\Models\App + { + $apiPath = str_replace( + [], + [], + '/apps' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['name'] = $name; + $apiParams['redirectUris'] = $redirectUris; + + if (!is_null($description)) { + $apiParams['description'] = $description; + } + + if (!is_null($clientUri)) { + $apiParams['clientUri'] = $clientUri; + } + + if (!is_null($logoUri)) { + $apiParams['logoUri'] = $logoUri; + } + + if (!is_null($privacyPolicyUrl)) { + $apiParams['privacyPolicyUrl'] = $privacyPolicyUrl; + } + + if (!is_null($termsUrl)) { + $apiParams['termsUrl'] = $termsUrl; + } + + if (!is_null($contacts)) { + $apiParams['contacts'] = $contacts; + } + + if (!is_null($tagline)) { + $apiParams['tagline'] = $tagline; + } + + if (!is_null($tags)) { + $apiParams['tags'] = $tags; + } + + if (!is_null($images)) { + $apiParams['images'] = $images; + } + + if (!is_null($supportUrl)) { + $apiParams['supportUrl'] = $supportUrl; + } + + if (!is_null($dataDeletionUrl)) { + $apiParams['dataDeletionUrl'] = $dataDeletionUrl; + } + + if (!is_null($postLogoutRedirectUris)) { + $apiParams['postLogoutRedirectUris'] = $postLogoutRedirectUris; + } + + if (!is_null($enabled)) { + $apiParams['enabled'] = $enabled; + } + + if (!is_null($type)) { + $apiParams['type'] = $type; + } + + if (!is_null($deviceFlow)) { + $apiParams['deviceFlow'] = $deviceFlow; + } + + if (!is_null($teamId)) { + $apiParams['teamId'] = $teamId; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\App::from($response); + + } + + /** + * List scopes an application can request when installed on a team. + * + * @throws AppwriteException + * @return \Appwrite\Models\AppScopeList + */ + public function listInstallationScopes(): \Appwrite\Models\AppScopeList + { + $apiPath = str_replace( + [], + [], + '/apps/scopes/installations' + ); + + $apiParams = []; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppScopeList::from($response); + + } + + /** + * List scopes an application can request during the OAuth2 flow. + * + * @throws AppwriteException + * @return \Appwrite\Models\AppScopeList + */ + public function listOAuth2Scopes(): \Appwrite\Models\AppScopeList + { + $apiPath = str_replace( + [], + [], + '/apps/scopes/oauth2' + ); + + $apiParams = []; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppScopeList::from($response); + + } + + /** + * Get an application by its unique ID. + * + * @param string $appId + * @throws AppwriteException + * @return \Appwrite\Models\App + */ + public function get(string $appId): \Appwrite\Models\App + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\App::from($response); + + } + + /** + * Update an application by its unique ID. + * + * @param string $appId + * @param string $name + * @param ?string $description + * @param ?string $clientUri + * @param ?string $logoUri + * @param ?string $privacyPolicyUrl + * @param ?string $termsUrl + * @param ?array $contacts + * @param ?string $tagline + * @param ?array $tags + * @param ?array $images + * @param ?string $supportUrl + * @param ?string $dataDeletionUrl + * @param ?bool $enabled + * @param ?array $redirectUris + * @param ?array $postLogoutRedirectUris + * @param ?string $type + * @param ?bool $deviceFlow + * @param ?array $installationScopes + * @param ?string $installationRedirectUrl + * @throws AppwriteException + * @return \Appwrite\Models\App + */ + public function update(string $appId, string $name, ?string $description = null, ?string $clientUri = null, ?string $logoUri = null, ?string $privacyPolicyUrl = null, ?string $termsUrl = null, ?array $contacts = null, ?string $tagline = null, ?array $tags = null, ?array $images = null, ?string $supportUrl = null, ?string $dataDeletionUrl = null, ?bool $enabled = null, ?array $redirectUris = null, ?array $postLogoutRedirectUris = null, ?string $type = null, ?bool $deviceFlow = null, ?array $installationScopes = null, ?string $installationRedirectUrl = null): \Appwrite\Models\App + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['name'] = $name; + + if (!is_null($description)) { + $apiParams['description'] = $description; + } + + if (!is_null($clientUri)) { + $apiParams['clientUri'] = $clientUri; + } + + if (!is_null($logoUri)) { + $apiParams['logoUri'] = $logoUri; + } + + if (!is_null($privacyPolicyUrl)) { + $apiParams['privacyPolicyUrl'] = $privacyPolicyUrl; + } + + if (!is_null($termsUrl)) { + $apiParams['termsUrl'] = $termsUrl; + } + + if (!is_null($contacts)) { + $apiParams['contacts'] = $contacts; + } + + if (!is_null($tagline)) { + $apiParams['tagline'] = $tagline; + } + + if (!is_null($tags)) { + $apiParams['tags'] = $tags; + } + + if (!is_null($images)) { + $apiParams['images'] = $images; + } + + if (!is_null($supportUrl)) { + $apiParams['supportUrl'] = $supportUrl; + } + + if (!is_null($dataDeletionUrl)) { + $apiParams['dataDeletionUrl'] = $dataDeletionUrl; + } + + if (!is_null($enabled)) { + $apiParams['enabled'] = $enabled; + } + + if (!is_null($redirectUris)) { + $apiParams['redirectUris'] = $redirectUris; + } + + if (!is_null($postLogoutRedirectUris)) { + $apiParams['postLogoutRedirectUris'] = $postLogoutRedirectUris; + } + + if (!is_null($type)) { + $apiParams['type'] = $type; + } + + if (!is_null($deviceFlow)) { + $apiParams['deviceFlow'] = $deviceFlow; + } + + if (!is_null($installationScopes)) { + $apiParams['installationScopes'] = $installationScopes; + } + + if (!is_null($installationRedirectUrl)) { + $apiParams['installationRedirectUrl'] = $installationRedirectUrl; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PUT, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\App::from($response); + + } + + /** + * Delete an application by its unique ID. + * + * @param string $appId + * @throws AppwriteException + * @return string + */ + public function delete(string $appId): string + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + + /** + * List installations of an application. Requires an app key sent in the + * `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. + * + * @param string $appId + * @param ?array $queries + * @param ?bool $total + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallationList + */ + public function listInstallations(string $appId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\AppInstallationList + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}/installations' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + if (!is_null($queries)) { + $apiParams['queries'] = $queries; + } + + if (!is_null($total)) { + $apiParams['total'] = $total; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallationList::from($response); + + } + + /** + * Get an installation of an application by its unique ID. Requires an app key + * sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. + * + * @param string $appId + * @param string $installationId + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallation + */ + public function getInstallation(string $appId, string $installationId): \Appwrite\Models\AppInstallation + { + $apiPath = str_replace( + ['{appId}', '{installationId}'], + [$appId, $installationId], + '/apps/{appId}/installations/{installationId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['installationId'] = $installationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallation::from($response); + + } + + /** + * Create a token for an installation of an application. Requires an app key + * sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. + * The returned token carries the scopes and authorization details granted to + * the installation, and can be used as an `Authorization: Bearer` header + * everywhere OAuth2 access tokens are accepted. Multiple tokens can be active + * for the same installation at once; each token stays valid until it expires + * or the installation is updated or deleted. + * + * @param string $appId + * @param string $installationId + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2Token + */ + public function createInstallationToken(string $appId, string $installationId): \Appwrite\Models\Oauth2Token + { + $apiPath = str_replace( + ['{appId}', '{installationId}'], + [$appId, $installationId], + '/apps/{appId}/installations/{installationId}/tokens' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['installationId'] = $installationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Token::from($response); + + } + + /** + * List app keys for an application. + * + * @param string $appId + * @param ?array $queries + * @param ?bool $total + * @throws AppwriteException + * @return \Appwrite\Models\AppKeyList + */ + public function listKeys(string $appId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\AppKeyList + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}/keys' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + if (!is_null($queries)) { + $apiParams['queries'] = $queries; + } + + if (!is_null($total)) { + $apiParams['total'] = $total; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppKeyList::from($response); + + } + + /** + * Create a new app key for an application. App keys carry no scopes; send one + * in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header to + * list the application's installations and create installation access tokens. + * + * @param string $appId + * @throws AppwriteException + * @return \Appwrite\Models\AppKey + */ + public function createKey(string $appId): \Appwrite\Models\AppKey + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}/keys' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppKey::from($response); + + } + + /** + * Get an app key by its unique ID. + * + * @param string $appId + * @param string $keyId + * @throws AppwriteException + * @return \Appwrite\Models\AppKey + */ + public function getKey(string $appId, string $keyId): \Appwrite\Models\AppKey + { + $apiPath = str_replace( + ['{appId}', '{keyId}'], + [$appId, $keyId], + '/apps/{appId}/keys/{keyId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['keyId'] = $keyId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppKey::from($response); + + } + + /** + * Delete an app key by its unique ID. + * + * @param string $appId + * @param string $keyId + * @throws AppwriteException + * @return string + */ + public function deleteKey(string $appId, string $keyId): string + { + $apiPath = str_replace( + ['{appId}', '{keyId}'], + [$appId, $keyId], + '/apps/{appId}/keys/{keyId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['keyId'] = $keyId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + + /** + * Update the labels of an application. Labels are read-only for clients; only + * a server SDK using a project API key can set them. Replaces the previous + * labels. + * + * @param string $appId + * @param array $labels + * @throws AppwriteException + * @return \Appwrite\Models\App + */ + public function updateLabels(string $appId, array $labels): \Appwrite\Models\App + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}/labels' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['labels'] = $labels; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PUT, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\App::from($response); + + } + + /** + * List client secrets for an application. + * + * @param string $appId + * @param ?array $queries + * @param ?bool $total + * @throws AppwriteException + * @return \Appwrite\Models\AppSecretList + */ + public function listSecrets(string $appId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\AppSecretList + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}/secrets' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + if (!is_null($queries)) { + $apiParams['queries'] = $queries; + } + + if (!is_null($total)) { + $apiParams['total'] = $total; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppSecretList::from($response); + + } + + /** + * Create a new client secret for an application. + * + * @param string $appId + * @throws AppwriteException + * @return \Appwrite\Models\AppSecretPlaintext + */ + public function createSecret(string $appId): \Appwrite\Models\AppSecretPlaintext + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}/secrets' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppSecretPlaintext::from($response); + + } + + /** + * Get an application client secret by its unique ID. + * + * @param string $appId + * @param string $secretId + * @throws AppwriteException + * @return \Appwrite\Models\AppSecret + */ + public function getSecret(string $appId, string $secretId): \Appwrite\Models\AppSecret + { + $apiPath = str_replace( + ['{appId}', '{secretId}'], + [$appId, $secretId], + '/apps/{appId}/secrets/{secretId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['secretId'] = $secretId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppSecret::from($response); + + } + + /** + * Delete an application client secret by its unique ID. + * + * @param string $appId + * @param string $secretId + * @throws AppwriteException + * @return string + */ + public function deleteSecret(string $appId, string $secretId): string + { + $apiPath = str_replace( + ['{appId}', '{secretId}'], + [$appId, $secretId], + '/apps/{appId}/secrets/{secretId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['secretId'] = $secretId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + + /** + * Transfer an application to another team by its unique ID. + * + * @param string $appId + * @param string $teamId + * @throws AppwriteException + * @return \Appwrite\Models\App + */ + public function updateTeam(string $appId, string $teamId): \Appwrite\Models\App + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}/team' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['teamId'] = $teamId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PATCH, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\App::from($response); + + } + + /** + * Revoke all tokens for an application by its unique ID. + * + * @param string $appId + * @throws AppwriteException + * @return string + */ + public function deleteTokens(string $appId): string + { + $apiPath = str_replace( + ['{appId}'], + [$appId], + '/apps/{appId}/tokens' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } +} diff --git a/src/Appwrite/Services/Backups.php b/src/Appwrite/Services/Backups.php index c6cc9542..527176ed 100644 --- a/src/Appwrite/Services/Backups.php +++ b/src/Appwrite/Services/Backups.php @@ -385,25 +385,39 @@ public function deletePolicy(string $policyId): string /** * Create and trigger a new restoration for a backup on a project. * - * When restoring a DocumentsDB or VectorsDB database to a new resource, pass - * `newSpecification` to provision the restored database on a different - * specification than the archived one (for example, restoring onto a larger - * or smaller dedicated database). Use `serverless` to restore onto the shared - * pool, or a dedicated specification slug to restore onto a dedicated - * database of that size. The specification must be permitted by the - * organization's plan. `newSpecification` is not supported for - * legacy/TablesDB databases or for bucket restores. + * For a backup of one database, the restoration resolves its destination + * before it is queued. Pass `newResourceId` to restore into that database ID, + * including the archived database ID to overwrite it. When `newResourceId` is + * omitted, a new database ID is generated and returned in `options`. + * + * The restoration migration records the archived database in `resourceId` and + * `resourceType`, and the resolved database in `destinationResourceId` and + * `destinationResourceType`. Database types are stored canonically as + * `database`, `documentsdb`, or `vectorsdb`. Project-wide restorations leave + * these fields empty because they do not have a single source or destination + * database. + * + * To list every migration related to one database, use its canonical type in + * a nested `OR(AND(...), AND(...), AND(...))` across the root, parent, and + * destination relation pairs: `(resourceType, resourceId)`, + * `(parentResourceType, parentResourceId)`, and `(destinationResourceType, + * destinationResourceId)`. Legacy and TablesDB databases use `database`; the + * operational `resourceType` of a table migration is not rewritten to + * `tablesdb`. + * + * When restoring a DocumentsDB or VectorsDB database to a new resource from a + * dedicated source, the restore provisions a fresh dedicated backing database + * at the source database's own specification. * * * @param string $archiveId * @param array $services * @param ?string $newResourceId * @param ?string $newResourceName - * @param ?string $newSpecification * @throws AppwriteException * @return \Appwrite\Models\BackupRestoration */ - public function createRestoration(string $archiveId, array $services, ?string $newResourceId = null, ?string $newResourceName = null, ?string $newSpecification = null): \Appwrite\Models\BackupRestoration + public function createRestoration(string $archiveId, array $services, ?string $newResourceId = null, ?string $newResourceName = null): \Appwrite\Models\BackupRestoration { $apiPath = str_replace( [], @@ -423,10 +437,6 @@ public function createRestoration(string $archiveId, array $services, ?string $n $apiParams['newResourceName'] = $newResourceName; } - if (!is_null($newSpecification)) { - $apiParams['newSpecification'] = $newSpecification; - } - $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; diff --git a/src/Appwrite/Services/Functions.php b/src/Appwrite/Services/Functions.php index 1db8154c..52531fd8 100644 --- a/src/Appwrite/Services/Functions.php +++ b/src/Appwrite/Services/Functions.php @@ -422,10 +422,7 @@ public function update(string $functionId, string $name, ?Runtime $runtime = nul $apiParams['providerBranches'] = $providerBranches; $apiParams['providerPaths'] = $providerPaths; $apiParams['buildSpecification'] = $buildSpecification; - - if (!is_null($runtimeSpecification)) { - $apiParams['runtimeSpecification'] = $runtimeSpecification; - } + $apiParams['runtimeSpecification'] = $runtimeSpecification; if (!is_null($deploymentRetention)) { $apiParams['deploymentRetention'] = $deploymentRetention; diff --git a/src/Appwrite/Services/Oauth2.php b/src/Appwrite/Services/Oauth2.php new file mode 100644 index 00000000..bc4d8614 --- /dev/null +++ b/src/Appwrite/Services/Oauth2.php @@ -0,0 +1,782 @@ +client->getConfig('project')], + '/oauth2/{project_id}/approve' + ); + + $apiParams = []; + $apiParams['grant_id'] = $grantId; + + if (!is_null($authorizationDetails)) { + $apiParams['authorization_details'] = $authorizationDetails; + } + + if (!is_null($scope)) { + $apiParams['scope'] = $scope; + } + + $apiHeaders = []; + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Approve::from($response); + + } + + /** + * Begin the OAuth2 authorization flow. When called without a session, the + * user is redirected to the consent screen without grant ID. When called with + * a session, the redirect URL includes param for grant ID. You can pass + * Accept header of `application/json` to receive a JSON response instead of a + * redirect. + * + * @param ?string $clientId + * @param ?string $redirectUri + * @param ?string $responseType + * @param ?string $scope + * @param ?string $state + * @param ?string $nonce + * @param ?string $codeChallenge + * @param ?string $codeChallengeMethod + * @param ?string $prompt + * @param ?int $maxAge + * @param ?string $authorizationDetails + * @param ?string $resource + * @param ?string $audience + * @param ?string $requestUri + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2Authorize + */ + public function authorize(?string $clientId = null, ?string $redirectUri = null, ?string $responseType = null, ?string $scope = null, ?string $state = null, ?string $nonce = null, ?string $codeChallenge = null, ?string $codeChallengeMethod = null, ?string $prompt = null, ?int $maxAge = null, ?string $authorizationDetails = null, ?string $resource = null, ?string $audience = null, ?string $requestUri = null): \Appwrite\Models\Oauth2Authorize + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/authorize' + ); + + $apiParams = []; + + if (!is_null($clientId)) { + $apiParams['client_id'] = $clientId; + } + + if (!is_null($redirectUri)) { + $apiParams['redirect_uri'] = $redirectUri; + } + + if (!is_null($responseType)) { + $apiParams['response_type'] = $responseType; + } + + if (!is_null($scope)) { + $apiParams['scope'] = $scope; + } + + if (!is_null($state)) { + $apiParams['state'] = $state; + } + + if (!is_null($nonce)) { + $apiParams['nonce'] = $nonce; + } + + if (!is_null($codeChallenge)) { + $apiParams['code_challenge'] = $codeChallenge; + } + + if (!is_null($codeChallengeMethod)) { + $apiParams['code_challenge_method'] = $codeChallengeMethod; + } + + if (!is_null($prompt)) { + $apiParams['prompt'] = $prompt; + } + + if (!is_null($maxAge)) { + $apiParams['max_age'] = $maxAge; + } + + if (!is_null($authorizationDetails)) { + $apiParams['authorization_details'] = $authorizationDetails; + } + + if (!is_null($resource)) { + $apiParams['resource'] = $resource; + } + + if (!is_null($audience)) { + $apiParams['audience'] = $audience; + } + + if (!is_null($requestUri)) { + $apiParams['request_uri'] = $requestUri; + } + + $apiHeaders = []; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Authorize::from($response); + + } + + /** + * Begin the OAuth2 authorization flow. When called without a session, the + * user is redirected to the consent screen without grant ID. When called with + * a session, the redirect URL includes param for grant ID. You can pass + * Accept header of `application/json` to receive a JSON response instead of a + * redirect. + * + * @param ?string $clientId + * @param ?string $redirectUri + * @param ?string $responseType + * @param ?string $scope + * @param ?string $state + * @param ?string $nonce + * @param ?string $codeChallenge + * @param ?string $codeChallengeMethod + * @param ?string $prompt + * @param ?int $maxAge + * @param ?string $authorizationDetails + * @param ?string $resource + * @param ?string $audience + * @param ?string $requestUri + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2Authorize + */ + public function authorizePost(?string $clientId = null, ?string $redirectUri = null, ?string $responseType = null, ?string $scope = null, ?string $state = null, ?string $nonce = null, ?string $codeChallenge = null, ?string $codeChallengeMethod = null, ?string $prompt = null, ?int $maxAge = null, ?string $authorizationDetails = null, ?string $resource = null, ?string $audience = null, ?string $requestUri = null): \Appwrite\Models\Oauth2Authorize + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/authorize' + ); + + $apiParams = []; + + if (!is_null($clientId)) { + $apiParams['client_id'] = $clientId; + } + + if (!is_null($redirectUri)) { + $apiParams['redirect_uri'] = $redirectUri; + } + + if (!is_null($responseType)) { + $apiParams['response_type'] = $responseType; + } + + if (!is_null($scope)) { + $apiParams['scope'] = $scope; + } + + if (!is_null($state)) { + $apiParams['state'] = $state; + } + + if (!is_null($nonce)) { + $apiParams['nonce'] = $nonce; + } + + if (!is_null($codeChallenge)) { + $apiParams['code_challenge'] = $codeChallenge; + } + + if (!is_null($codeChallengeMethod)) { + $apiParams['code_challenge_method'] = $codeChallengeMethod; + } + + if (!is_null($prompt)) { + $apiParams['prompt'] = $prompt; + } + $apiParams['max_age'] = $maxAge; + + if (!is_null($authorizationDetails)) { + $apiParams['authorization_details'] = $authorizationDetails; + } + + if (!is_null($resource)) { + $apiParams['resource'] = $resource; + } + + if (!is_null($audience)) { + $apiParams['audience'] = $audience; + } + + if (!is_null($requestUri)) { + $apiParams['request_uri'] = $requestUri; + } + + $apiHeaders = []; + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Authorize::from($response); + + } + + /** + * Start the OAuth2 Device Authorization Grant. Returns the device code, user + * code, verification URL, expiration, and polling interval. + * + * @param ?string $clientId + * @param ?string $scope + * @param ?string $authorizationDetails + * @param ?string $resource + * @param ?string $audience + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2DeviceAuthorization + */ + public function createDeviceAuthorization(?string $clientId = null, ?string $scope = null, ?string $authorizationDetails = null, ?string $resource = null, ?string $audience = null): \Appwrite\Models\Oauth2DeviceAuthorization + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/device_authorization' + ); + + $apiParams = []; + + if (!is_null($clientId)) { + $apiParams['client_id'] = $clientId; + } + + if (!is_null($scope)) { + $apiParams['scope'] = $scope; + } + + if (!is_null($authorizationDetails)) { + $apiParams['authorization_details'] = $authorizationDetails; + } + + if (!is_null($resource)) { + $apiParams['resource'] = $resource; + } + + if (!is_null($audience)) { + $apiParams['audience'] = $audience; + } + + $apiHeaders = []; + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2DeviceAuthorization::from($response); + + } + + /** + * Exchange a device flow user code for an OAuth2 grant. The authenticated + * user is bound to the pending grant. Pass the returned grant ID to the get + * grant endpoint to render the consent screen, then to the approve or reject + * endpoint to complete the flow. + * + * @param string $userCode + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2Grant + */ + public function createGrant(string $userCode): \Appwrite\Models\Oauth2Grant + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/grants' + ); + + $apiParams = []; + $apiParams['user_code'] = $userCode; + + $apiHeaders = []; + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Grant::from($response); + + } + + /** + * Get an OAuth2 grant by its ID. Used by the consent screen to display the + * details of the authorization the user is being asked to approve. A grant + * can only be read by the user it belongs to, or by server SDK. + * + * @param string $grantId + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2Grant + */ + public function getGrant(string $grantId): \Appwrite\Models\Oauth2Grant + { + $apiPath = str_replace( + ['{project_id}', '{grant_id}'], + [$this->client->getConfig('project'), $grantId], + '/oauth2/{project_id}/grants/{grant_id}' + ); + + $apiParams = []; + $apiParams['grant_id'] = $grantId; + + $apiHeaders = []; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Grant::from($response); + + } + + /** + * List the organizations the OAuth2 access token can access. Resolves the + * token's `organization` authorization details, expanding the `*` wildcard + * into the concrete set of organizations the user can see. + * + * @param ?int $limit + * @param ?int $offset + * @param ?string $search + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2OrganizationList + */ + public function listOrganizations(?int $limit = null, ?int $offset = null, ?string $search = null): \Appwrite\Models\Oauth2OrganizationList + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/organizations' + ); + + $apiParams = []; + + if (!is_null($limit)) { + $apiParams['limit'] = $limit; + } + + if (!is_null($offset)) { + $apiParams['offset'] = $offset; + } + + if (!is_null($search)) { + $apiParams['search'] = $search; + } + + $apiHeaders = []; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2OrganizationList::from($response); + + } + + /** + * Store an OAuth2 authorization request server-side and receive a short-lived + * request_uri handle for the authorize endpoint. + * + * @param string $clientId + * @param string $redirectUri + * @param string $responseType + * @param ?string $scope + * @param ?string $state + * @param ?string $nonce + * @param ?string $codeChallenge + * @param ?string $codeChallengeMethod + * @param ?string $prompt + * @param ?int $maxAge + * @param ?string $authorizationDetails + * @param ?string $resource + * @param ?string $audience + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2PAR + */ + public function createPAR(string $clientId, string $redirectUri, string $responseType, ?string $scope = null, ?string $state = null, ?string $nonce = null, ?string $codeChallenge = null, ?string $codeChallengeMethod = null, ?string $prompt = null, ?int $maxAge = null, ?string $authorizationDetails = null, ?string $resource = null, ?string $audience = null): \Appwrite\Models\Oauth2PAR + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/par' + ); + + $apiParams = []; + $apiParams['client_id'] = $clientId; + $apiParams['redirect_uri'] = $redirectUri; + $apiParams['response_type'] = $responseType; + + if (!is_null($scope)) { + $apiParams['scope'] = $scope; + } + + if (!is_null($state)) { + $apiParams['state'] = $state; + } + + if (!is_null($nonce)) { + $apiParams['nonce'] = $nonce; + } + + if (!is_null($codeChallenge)) { + $apiParams['code_challenge'] = $codeChallenge; + } + + if (!is_null($codeChallengeMethod)) { + $apiParams['code_challenge_method'] = $codeChallengeMethod; + } + + if (!is_null($prompt)) { + $apiParams['prompt'] = $prompt; + } + $apiParams['max_age'] = $maxAge; + + if (!is_null($authorizationDetails)) { + $apiParams['authorization_details'] = $authorizationDetails; + } + + if (!is_null($resource)) { + $apiParams['resource'] = $resource; + } + + if (!is_null($audience)) { + $apiParams['audience'] = $audience; + } + + $apiHeaders = []; + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2PAR::from($response); + + } + + /** + * List the projects the OAuth2 access token can access. Resolves the token's + * `project` authorization details, expanding the `*` wildcard into the + * concrete set of projects the user can see. + * + * @param ?int $limit + * @param ?int $offset + * @param ?string $search + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2ProjectList + */ + public function listProjects(?int $limit = null, ?int $offset = null, ?string $search = null): \Appwrite\Models\Oauth2ProjectList + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/projects' + ); + + $apiParams = []; + + if (!is_null($limit)) { + $apiParams['limit'] = $limit; + } + + if (!is_null($offset)) { + $apiParams['offset'] = $offset; + } + + if (!is_null($search)) { + $apiParams['search'] = $search; + } + + $apiHeaders = []; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2ProjectList::from($response); + + } + + /** + * Reject an OAuth2 grant when the user denies consent. Returns the + * `redirectUrl` the end user should be sent to with an `access_denied` error. + * You can pass Accept header of `application/json` to receive a JSON response + * instead of a redirect. + * + * @param string $grantId + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2Reject + */ + public function reject(string $grantId): \Appwrite\Models\Oauth2Reject + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/reject' + ); + + $apiParams = []; + $apiParams['grant_id'] = $grantId; + + $apiHeaders = []; + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Reject::from($response); + + } + + /** + * Revoke an OAuth2 access token or refresh token. + * + * @param string $token + * @param ?string $tokenTypeHint + * @param ?string $clientId + * @param ?string $clientSecret + * @throws AppwriteException + * @return array + */ + public function revoke(string $token, ?string $tokenTypeHint = null, ?string $clientId = null, ?string $clientSecret = null): array + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/revoke' + ); + + $apiParams = []; + $apiParams['token'] = $token; + + if (!is_null($tokenTypeHint)) { + $apiParams['token_type_hint'] = $tokenTypeHint; + } + + if (!is_null($clientId)) { + $apiParams['client_id'] = $clientId; + } + + if (!is_null($clientSecret)) { + $apiParams['client_secret'] = $clientSecret; + } + + $apiHeaders = []; + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + + /** + * Exchange an OAuth2 authorization code, refresh token, or device code for + * access and refresh tokens. + * + * @param string $grantType + * @param ?string $code + * @param ?string $refreshToken + * @param ?string $deviceCode + * @param ?string $clientId + * @param ?string $clientSecret + * @param ?string $codeVerifier + * @param ?string $redirectUri + * @param ?string $resource + * @param ?string $audience + * @throws AppwriteException + * @return \Appwrite\Models\Oauth2Token + */ + public function createToken(string $grantType, ?string $code = null, ?string $refreshToken = null, ?string $deviceCode = null, ?string $clientId = null, ?string $clientSecret = null, ?string $codeVerifier = null, ?string $redirectUri = null, ?string $resource = null, ?string $audience = null): \Appwrite\Models\Oauth2Token + { + $apiPath = str_replace( + ['{project_id}'], + [$this->client->getConfig('project')], + '/oauth2/{project_id}/token' + ); + + $apiParams = []; + $apiParams['grant_type'] = $grantType; + + if (!is_null($code)) { + $apiParams['code'] = $code; + } + + if (!is_null($refreshToken)) { + $apiParams['refresh_token'] = $refreshToken; + } + + if (!is_null($deviceCode)) { + $apiParams['device_code'] = $deviceCode; + } + + if (!is_null($clientId)) { + $apiParams['client_id'] = $clientId; + } + + if (!is_null($clientSecret)) { + $apiParams['client_secret'] = $clientSecret; + } + + if (!is_null($codeVerifier)) { + $apiParams['code_verifier'] = $codeVerifier; + } + + if (!is_null($redirectUri)) { + $apiParams['redirect_uri'] = $redirectUri; + } + + if (!is_null($resource)) { + $apiParams['resource'] = $resource; + } + + if (!is_null($audience)) { + $apiParams['audience'] = $audience; + } + + $apiHeaders = []; + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Oauth2Token::from($response); + + } +} diff --git a/src/Appwrite/Services/Organization.php b/src/Appwrite/Services/Organization.php index e50f89f5..7c189a8f 100644 --- a/src/Appwrite/Services/Organization.php +++ b/src/Appwrite/Services/Organization.php @@ -121,6 +121,214 @@ public function delete(): string } + /** + * List app installations on the organization. Any organization member can + * read installations. + * + * @param ?array $queries + * @param ?bool $total + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallationList + */ + public function listInstallations(?array $queries = null, ?bool $total = null): \Appwrite\Models\AppInstallationList + { + $apiPath = str_replace( + [], + [], + '/organization/installations' + ); + + $apiParams = []; + + if (!is_null($queries)) { + $apiParams['queries'] = $queries; + } + + if (!is_null($total)) { + $apiParams['total'] = $total; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallationList::from($response); + + } + + /** + * Install an app on the organization. Only organization members with the + * owner role can install apps. The installation is granted the scopes the app + * currently requests. + * + * @param string $appId + * @param ?string $authorizationDetails + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallation + */ + public function createInstallation(string $appId, ?string $authorizationDetails = null): \Appwrite\Models\AppInstallation + { + $apiPath = str_replace( + [], + [], + '/organization/installations' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + + if (!is_null($authorizationDetails)) { + $apiParams['authorizationDetails'] = $authorizationDetails; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallation::from($response); + + } + + /** + * Get an app installation on the organization by its unique ID. Any + * organization member can read installations. + * + * @param string $installationId + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallation + */ + public function getInstallation(string $installationId): \Appwrite\Models\AppInstallation + { + $apiPath = str_replace( + ['{installationId}'], + [$installationId], + '/organization/installations/{installationId}' + ); + + $apiParams = []; + $apiParams['installationId'] = $installationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallation::from($response); + + } + + /** + * Update an app installation on the organization. Only organization members + * with the owner role can update installations. The installation's granted + * scopes are refreshed to the scopes the app currently requests; previously + * issued installation access tokens are revoked. + * + * @param string $installationId + * @param ?string $authorizationDetails + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallation + */ + public function updateInstallation(string $installationId, ?string $authorizationDetails = null): \Appwrite\Models\AppInstallation + { + $apiPath = str_replace( + ['{installationId}'], + [$installationId], + '/organization/installations/{installationId}' + ); + + $apiParams = []; + $apiParams['installationId'] = $installationId; + $apiParams['authorizationDetails'] = $authorizationDetails; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PUT, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallation::from($response); + + } + + /** + * Uninstall an app from the organization by its installation ID. Only + * organization members with the owner role can remove installations. + * Previously issued installation access tokens are revoked. + * + * @param string $installationId + * @throws AppwriteException + * @return string + */ + public function deleteInstallation(string $installationId): string + { + $apiPath = str_replace( + ['{installationId}'], + [$installationId], + '/organization/installations/{installationId}' + ); + + $apiParams = []; + $apiParams['installationId'] = $installationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + /** * Get a list of all API keys from the current organization. * diff --git a/src/Appwrite/Services/Project.php b/src/Appwrite/Services/Project.php index 475d5f8e..8ba6055b 100644 --- a/src/Appwrite/Services/Project.php +++ b/src/Appwrite/Services/Project.php @@ -681,6 +681,7 @@ public function listOAuth2Providers(?array $queries = null, ?bool $total = null) * @param ?int $refreshTokenDuration * @param ?int $publicAccessTokenDuration * @param ?int $publicRefreshTokenDuration + * @param ?int $installationAccessTokenDuration * @param ?bool $confidentialPkce * @param ?string $verificationUrl * @param ?int $userCodeLength @@ -690,7 +691,7 @@ public function listOAuth2Providers(?array $queries = null, ?bool $total = null) * @throws AppwriteException * @return \Appwrite\Models\Project */ - public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?array $scopes = null, ?array $authorizationDetailsTypes = null, ?int $accessTokenDuration = null, ?int $refreshTokenDuration = null, ?int $publicAccessTokenDuration = null, ?int $publicRefreshTokenDuration = null, ?bool $confidentialPkce = null, ?string $verificationUrl = null, ?int $userCodeLength = null, ?string $userCodeFormat = null, ?int $deviceCodeDuration = null, ?array $defaultScopes = null): \Appwrite\Models\Project + public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?array $scopes = null, ?array $authorizationDetailsTypes = null, ?int $accessTokenDuration = null, ?int $refreshTokenDuration = null, ?int $publicAccessTokenDuration = null, ?int $publicRefreshTokenDuration = null, ?int $installationAccessTokenDuration = null, ?bool $confidentialPkce = null, ?string $verificationUrl = null, ?int $userCodeLength = null, ?string $userCodeFormat = null, ?int $deviceCodeDuration = null, ?array $defaultScopes = null): \Appwrite\Models\Project { $apiPath = str_replace( [], @@ -713,6 +714,7 @@ public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?arr $apiParams['refreshTokenDuration'] = $refreshTokenDuration; $apiParams['publicAccessTokenDuration'] = $publicAccessTokenDuration; $apiParams['publicRefreshTokenDuration'] = $publicRefreshTokenDuration; + $apiParams['installationAccessTokenDuration'] = $installationAccessTokenDuration; $apiParams['confidentialPkce'] = $confidentialPkce; if (!is_null($verificationUrl)) { diff --git a/src/Appwrite/Services/Sites.php b/src/Appwrite/Services/Sites.php index b7e44fdb..0b373273 100644 --- a/src/Appwrite/Services/Sites.php +++ b/src/Appwrite/Services/Sites.php @@ -1114,10 +1114,11 @@ public function deleteDeployment(string $siteId, string $deploymentId): string * @param string $siteId * @param string $deploymentId * @param ?DeploymentDownloadType $type + * @param ?string $token * @throws AppwriteException * @return string */ - public function getDeploymentDownload(string $siteId, string $deploymentId, ?DeploymentDownloadType $type = null): string + public function getDeploymentDownload(string $siteId, string $deploymentId, ?DeploymentDownloadType $type = null, ?string $token = null): string { $apiPath = str_replace( ['{siteId}', '{deploymentId}'], @@ -1133,6 +1134,10 @@ public function getDeploymentDownload(string $siteId, string $deploymentId, ?Dep $apiParams['type'] = $type; } + if (!is_null($token)) { + $apiParams['token'] = $token; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['accept'] = '*/*'; diff --git a/src/Appwrite/Services/TablesDB.php b/src/Appwrite/Services/TablesDB.php index bff7d67b..f2c996ff 100644 --- a/src/Appwrite/Services/TablesDB.php +++ b/src/Appwrite/Services/TablesDB.php @@ -77,10 +77,11 @@ public function list(?array $queries = null, ?string $search = null, ?bool $tota * @param string $name * @param ?bool $enabled * @param ?string $specification + * @param ?int $replicas * @throws AppwriteException * @return \Appwrite\Models\Database */ - public function create(string $databaseId, string $name, ?bool $enabled = null, ?string $specification = null): \Appwrite\Models\Database + public function create(string $databaseId, string $name, ?bool $enabled = null, ?string $specification = null, ?int $replicas = null): \Appwrite\Models\Database { $apiPath = str_replace( [], @@ -100,6 +101,10 @@ public function create(string $databaseId, string $name, ?bool $enabled = null, $apiParams['specification'] = $specification; } + if (!is_null($replicas)) { + $apiParams['replicas'] = $replicas; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; @@ -120,6 +125,43 @@ public function create(string $databaseId, string $name, ?bool $enabled = null, } + /** + * List the dedicated database specifications available on the current plan. + * Each specification reports its resource limits, pricing, and whether it is + * enabled for the organization. + * + * @throws AppwriteException + * @return \Appwrite\Models\DedicatedDatabaseSpecificationList + */ + public function listSpecifications(): \Appwrite\Models\DedicatedDatabaseSpecificationList + { + $apiPath = str_replace( + [], + [], + '/tablesdb/specifications' + ); + + $apiParams = []; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DedicatedDatabaseSpecificationList::from($response); + + } + /** * List transactions across all databases. * @@ -406,10 +448,11 @@ public function get(string $databaseId): \Appwrite\Models\Database * @param string $databaseId * @param ?string $name * @param ?bool $enabled + * @param ?int $replicas * @throws AppwriteException * @return \Appwrite\Models\Database */ - public function update(string $databaseId, ?string $name = null, ?bool $enabled = null): \Appwrite\Models\Database + public function update(string $databaseId, ?string $name = null, ?bool $enabled = null, ?int $replicas = null): \Appwrite\Models\Database { $apiPath = str_replace( ['{databaseId}'], @@ -427,6 +470,7 @@ public function update(string $databaseId, ?string $name = null, ?bool $enabled if (!is_null($enabled)) { $apiParams['enabled'] = $enabled; } + $apiParams['replicas'] = $replicas; $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); @@ -482,6 +526,125 @@ public function delete(string $databaseId): string } + /** + * Trigger a manual failover for a dedicated database with high availability + * enabled. Promotes a replica to primary. The failover runs asynchronously; + * poll the database document for status updates. + * + * @param string $databaseId + * @param ?string $targetReplicaId + * @throws AppwriteException + * @return \Appwrite\Models\DedicatedDatabase + */ + public function createFailover(string $databaseId, ?string $targetReplicaId = null): \Appwrite\Models\DedicatedDatabase + { + $apiPath = str_replace( + ['{databaseId}'], + [$databaseId], + '/tablesdb/{databaseId}/failovers' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + $apiParams['targetReplicaId'] = $targetReplicaId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DedicatedDatabase::from($response); + + } + + /** + * Get high availability status for a dedicated database. Returns replica + * statuses, replication lag, and sync mode. + * + * @param string $databaseId + * @throws AppwriteException + * @return \Appwrite\Models\DedicatedDatabaseReplicas + */ + public function getReplicas(string $databaseId): \Appwrite\Models\DedicatedDatabaseReplicas + { + $apiPath = str_replace( + ['{databaseId}'], + [$databaseId], + '/tablesdb/{databaseId}/replicas' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DedicatedDatabaseReplicas::from($response); + + } + + /** + * Get real-time health and status information for a dedicated database. + * Returns health status, readiness, uptime, connection info, replica status, + * and volume information. + * + * @param string $databaseId + * @throws AppwriteException + * @return \Appwrite\Models\DatabaseStatus + */ + public function getStatus(string $databaseId): \Appwrite\Models\DatabaseStatus + { + $apiPath = str_replace( + ['{databaseId}'], + [$databaseId], + '/tablesdb/{databaseId}/status' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DatabaseStatus::from($response); + + } + /** * Get a list of all tables that belong to the provided databaseId. You can * use the search parameter to filter your results. diff --git a/src/Appwrite/Services/Teams.php b/src/Appwrite/Services/Teams.php index 4c17e3b9..53b32bcb 100644 --- a/src/Appwrite/Services/Teams.php +++ b/src/Appwrite/Services/Teams.php @@ -223,6 +223,224 @@ public function delete(string $teamId): string } + /** + * List app installations on a team. Any team member can read installations. + * + * @param string $teamId + * @param ?array $queries + * @param ?bool $total + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallationList + */ + public function listInstallations(string $teamId, ?array $queries = null, ?bool $total = null): \Appwrite\Models\AppInstallationList + { + $apiPath = str_replace( + ['{teamId}'], + [$teamId], + '/teams/{teamId}/installations' + ); + + $apiParams = []; + $apiParams['teamId'] = $teamId; + + if (!is_null($queries)) { + $apiParams['queries'] = $queries; + } + + if (!is_null($total)) { + $apiParams['total'] = $total; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallationList::from($response); + + } + + /** + * Install an app on a team. When authenticated as a user, only team members + * with the owner role can install apps. Requests using an API key or in admin + * mode can install apps on any team. The installation is granted the scopes + * the app currently requests. + * + * @param string $teamId + * @param string $appId + * @param ?string $authorizationDetails + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallation + */ + public function createInstallation(string $teamId, string $appId, ?string $authorizationDetails = null): \Appwrite\Models\AppInstallation + { + $apiPath = str_replace( + ['{teamId}'], + [$teamId], + '/teams/{teamId}/installations' + ); + + $apiParams = []; + $apiParams['teamId'] = $teamId; + $apiParams['appId'] = $appId; + + if (!is_null($authorizationDetails)) { + $apiParams['authorizationDetails'] = $authorizationDetails; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallation::from($response); + + } + + /** + * Get an app installation on a team by its unique ID. Any team member can + * read installations. + * + * @param string $teamId + * @param string $installationId + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallation + */ + public function getInstallation(string $teamId, string $installationId): \Appwrite\Models\AppInstallation + { + $apiPath = str_replace( + ['{teamId}', '{installationId}'], + [$teamId, $installationId], + '/teams/{teamId}/installations/{installationId}' + ); + + $apiParams = []; + $apiParams['teamId'] = $teamId; + $apiParams['installationId'] = $installationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallation::from($response); + + } + + /** + * Update an app installation on a team. Only team members with the owner role + * can update installations. The installation's granted scopes are refreshed + * to the scopes the app currently requests; previously issued installation + * access tokens are revoked. + * + * @param string $teamId + * @param string $installationId + * @param ?string $authorizationDetails + * @throws AppwriteException + * @return \Appwrite\Models\AppInstallation + */ + public function updateInstallation(string $teamId, string $installationId, ?string $authorizationDetails = null): \Appwrite\Models\AppInstallation + { + $apiPath = str_replace( + ['{teamId}', '{installationId}'], + [$teamId, $installationId], + '/teams/{teamId}/installations/{installationId}' + ); + + $apiParams = []; + $apiParams['teamId'] = $teamId; + $apiParams['installationId'] = $installationId; + $apiParams['authorizationDetails'] = $authorizationDetails; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PUT, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\AppInstallation::from($response); + + } + + /** + * Uninstall an app from a team by its installation ID. Only team members with + * the owner role can remove installations. Previously issued installation + * access tokens are revoked. + * + * @param string $teamId + * @param string $installationId + * @throws AppwriteException + * @return string + */ + public function deleteInstallation(string $teamId, string $installationId): string + { + $apiPath = str_replace( + ['{teamId}', '{installationId}'], + [$teamId, $installationId], + '/teams/{teamId}/installations/{installationId}' + ); + + $apiParams = []; + $apiParams['teamId'] = $teamId; + $apiParams['installationId'] = $installationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + /** * Use this endpoint to list a team's members using the team's ID. All team * members have read access to this endpoint. Hide sensitive attributes from diff --git a/tests/Appwrite/Services/AccountTest.php b/tests/Appwrite/Services/AccountTest.php index b6c0220e..eabfc829 100644 --- a/tests/Appwrite/Services/AccountTest.php +++ b/tests/Appwrite/Services/AccountTest.php @@ -113,6 +113,170 @@ public function testMethodCreate(): void $this->assertInstanceOf(\Appwrite\Models\User::class, $response); } + public function testMethodListConsents(): void + { + $data = array( + "total" => 5, + "consents" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c16897e", + "appId" => "5e5ea5c16897e", + "cimdUrl" => "https://example.com/.well-known/client-metadata.json", + "scopes" => array(), + "resources" => array(), + "authorizationDetails" => "[{\"type\":\"calendar\",\"identifier\":\"primary\",\"actions\":[\"read_events\",\"create_event\"]}]", + "expire" => "2020-10-15T06:38:00.000+00:00" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->account->listConsents(); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2ConsentList::class, $response); + } + + public function testMethodGetConsent(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c16897e", + "appId" => "5e5ea5c16897e", + "cimdUrl" => "https://example.com/.well-known/client-metadata.json", + "scopes" => array(), + "resources" => array(), + "authorizationDetails" => "[{\"type\":\"calendar\",\"identifier\":\"primary\",\"actions\":[\"read_events\",\"create_event\"]}]", + "expire" => "2020-10-15T06:38:00.000+00:00" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->account->getConsent( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Consent::class, $response); + } + + public function testMethodDeleteConsent(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->account->deleteConsent( + "" + ); + + $this->assertSame($data, $response); + } + + public function testMethodListConsentTokens(): void + { + $data = array( + "total" => 5, + "tokens" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "consentId" => "5e5ea5c16897e", + "userId" => "5e5ea5c16897e", + "appId" => "5e5ea5c16897e", + "cimdUrl" => "https://example.com/.well-known/client-metadata.json", + "scopes" => array(), + "resources" => array(), + "authorizationDetails" => "[{\"type\":\"calendar\",\"identifier\":\"primary\",\"actions\":[\"read_events\",\"create_event\"]}]", + "expire" => "2020-10-15T06:38:00.000+00:00" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->account->listConsentTokens( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2ConsentTokenList::class, $response); + } + + public function testMethodGetConsentToken(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "consentId" => "5e5ea5c16897e", + "userId" => "5e5ea5c16897e", + "appId" => "5e5ea5c16897e", + "cimdUrl" => "https://example.com/.well-known/client-metadata.json", + "scopes" => array(), + "resources" => array(), + "authorizationDetails" => "[{\"type\":\"calendar\",\"identifier\":\"primary\",\"actions\":[\"read_events\",\"create_event\"]}]", + "expire" => "2020-10-15T06:38:00.000+00:00" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->account->getConsentToken( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2ConsentToken::class, $response); + } + + public function testMethodDeleteConsentToken(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->account->deleteConsentToken( + "", + "" + ); + + $this->assertSame($data, $response); + } + public function testMethodUpdateEmail(): void { $data = array( diff --git a/tests/Appwrite/Services/ActivitiesTest.php b/tests/Appwrite/Services/ActivitiesTest.php index f4daf521..b1d16072 100644 --- a/tests/Appwrite/Services/ActivitiesTest.php +++ b/tests/Appwrite/Services/ActivitiesTest.php @@ -38,10 +38,21 @@ public function testMethodListEvents(): void "ip" => "127.0.0.1", "mode" => "admin", "country" => "US", + "continentCode" => "NA", + "city" => "Mountain View", + "subdivisions" => "California", + "isp" => "Google", + "autonomousSystemNumber" => "15169", + "autonomousSystemOrganization" => "GOOGLE", + "connectionType" => "cable", + "connectionUsageType" => "residential", + "connectionOrganization" => "Google LLC", "time" => "2020-10-15T06:38:00.000+00:00", "projectId" => "610fc2f985ee0", "teamId" => "610fc2f985ee0", - "hostname" => "appwrite.io" + "hostname" => "appwrite.io", + "sdk" => "web", + "sdkVersion" => "14.0.0" ) ) ); @@ -75,10 +86,21 @@ public function testMethodGetEvent(): void "ip" => "127.0.0.1", "mode" => "admin", "country" => "US", + "continentCode" => "NA", + "city" => "Mountain View", + "subdivisions" => "California", + "isp" => "Google", + "autonomousSystemNumber" => "15169", + "autonomousSystemOrganization" => "GOOGLE", + "connectionType" => "cable", + "connectionUsageType" => "residential", + "connectionOrganization" => "Google LLC", "time" => "2020-10-15T06:38:00.000+00:00", "projectId" => "610fc2f985ee0", "teamId" => "610fc2f985ee0", - "hostname" => "appwrite.io" + "hostname" => "appwrite.io", + "sdk" => "web", + "sdkVersion" => "14.0.0" ); $this->client diff --git a/tests/Appwrite/Services/AppsTest.php b/tests/Appwrite/Services/AppsTest.php new file mode 100644 index 00000000..63767c7a --- /dev/null +++ b/tests/Appwrite/Services/AppsTest.php @@ -0,0 +1,754 @@ +client = Mockery::mock(Client::class); + $this->apps = new Apps($this->client); + } + + public function testMethodList(): void + { + $data = array( + "total" => 5, + "apps" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "My Application", + "description" => "Connect your workspace to My Application.", + "clientUri" => "https://example.com", + "logoUri" => "https://example.com/logo.png", + "privacyPolicyUrl" => "https://example.com/privacy", + "termsUrl" => "https://example.com/terms", + "contacts" => array(), + "tagline" => "Automate your workspace.", + "tags" => array(), + "labels" => array(), + "images" => array(), + "supportUrl" => "https://example.com/support", + "dataDeletionUrl" => "https://example.com/data-deletion", + "redirectUris" => array(), + "postLogoutRedirectUris" => array(), + "enabled" => true, + "type" => "confidential", + "deviceFlow" => true, + "teamId" => "5e5ea5c16897e", + "userId" => "5e5ea5c16897e", + "installationScopes" => array(), + "installationRedirectUrl" => "https://example.com/setup", + "secrets" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "[SECRET]", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->list(); + + $this->assertInstanceOf(\Appwrite\Models\AppsList::class, $response); + } + + public function testMethodCreate(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "My Application", + "description" => "Connect your workspace to My Application.", + "clientUri" => "https://example.com", + "logoUri" => "https://example.com/logo.png", + "privacyPolicyUrl" => "https://example.com/privacy", + "termsUrl" => "https://example.com/terms", + "contacts" => array(), + "tagline" => "Automate your workspace.", + "tags" => array(), + "labels" => array(), + "images" => array(), + "supportUrl" => "https://example.com/support", + "dataDeletionUrl" => "https://example.com/data-deletion", + "redirectUris" => array(), + "postLogoutRedirectUris" => array(), + "enabled" => true, + "type" => "confidential", + "deviceFlow" => true, + "teamId" => "5e5ea5c16897e", + "userId" => "5e5ea5c16897e", + "installationScopes" => array(), + "installationRedirectUrl" => "https://example.com/setup", + "secrets" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "[SECRET]", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->create( + "", + "", + array() + ); + + $this->assertInstanceOf(\Appwrite\Models\App::class, $response); + } + + public function testMethodListInstallationScopes(): void + { + $data = array( + "total" => 5, + "scopes" => array( + array( + "value" => "organization:organization.read", + "description" => "Access to read the organization", + "type" => "organization", + "category" => "Organization", + "deprecated" => true + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->listInstallationScopes(); + + $this->assertInstanceOf(\Appwrite\Models\AppScopeList::class, $response); + } + + public function testMethodListOAuth2Scopes(): void + { + $data = array( + "total" => 5, + "scopes" => array( + array( + "value" => "organization:organization.read", + "description" => "Access to read the organization", + "type" => "organization", + "category" => "Organization", + "deprecated" => true + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->listOAuth2Scopes(); + + $this->assertInstanceOf(\Appwrite\Models\AppScopeList::class, $response); + } + + public function testMethodGet(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "My Application", + "description" => "Connect your workspace to My Application.", + "clientUri" => "https://example.com", + "logoUri" => "https://example.com/logo.png", + "privacyPolicyUrl" => "https://example.com/privacy", + "termsUrl" => "https://example.com/terms", + "contacts" => array(), + "tagline" => "Automate your workspace.", + "tags" => array(), + "labels" => array(), + "images" => array(), + "supportUrl" => "https://example.com/support", + "dataDeletionUrl" => "https://example.com/data-deletion", + "redirectUris" => array(), + "postLogoutRedirectUris" => array(), + "enabled" => true, + "type" => "confidential", + "deviceFlow" => true, + "teamId" => "5e5ea5c16897e", + "userId" => "5e5ea5c16897e", + "installationScopes" => array(), + "installationRedirectUrl" => "https://example.com/setup", + "secrets" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "[SECRET]", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->get( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\App::class, $response); + } + + public function testMethodUpdate(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "My Application", + "description" => "Connect your workspace to My Application.", + "clientUri" => "https://example.com", + "logoUri" => "https://example.com/logo.png", + "privacyPolicyUrl" => "https://example.com/privacy", + "termsUrl" => "https://example.com/terms", + "contacts" => array(), + "tagline" => "Automate your workspace.", + "tags" => array(), + "labels" => array(), + "images" => array(), + "supportUrl" => "https://example.com/support", + "dataDeletionUrl" => "https://example.com/data-deletion", + "redirectUris" => array(), + "postLogoutRedirectUris" => array(), + "enabled" => true, + "type" => "confidential", + "deviceFlow" => true, + "teamId" => "5e5ea5c16897e", + "userId" => "5e5ea5c16897e", + "installationScopes" => array(), + "installationRedirectUrl" => "https://example.com/setup", + "secrets" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "[SECRET]", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->update( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\App::class, $response); + } + + public function testMethodDelete(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->delete( + "" + ); + + $this->assertSame($data, $response); + } + + public function testMethodListInstallations(): void + { + $data = array( + "total" => 5, + "installations" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->listInstallations( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallationList::class, $response); + } + + public function testMethodGetInstallation(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->getInstallation( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallation::class, $response); + } + + public function testMethodCreateInstallationToken(): void + { + $data = array( + "access_token" => "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...", + "token_type" => "Bearer", + "expires_in" => 3600, + "refresh_token" => "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", + "scope" => "openid email profile" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->createInstallationToken( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Token::class, $response); + } + + public function testMethodListKeys(): void + { + $data = array( + "total" => 5, + "keys" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "5f3c8d2a1b9e4f7a6c8b2d1e9f4a7b3c5d8e1f2a9b4c7d6e3f5a8b1c4d7e2f9a", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->listKeys( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppKeyList::class, $response); + } + + public function testMethodCreateKey(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "5f3c8d2a1b9e4f7a6c8b2d1e9f4a7b3c5d8e1f2a9b4c7d6e3f5a8b1c4d7e2f9a", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->createKey( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppKey::class, $response); + } + + public function testMethodGetKey(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "5f3c8d2a1b9e4f7a6c8b2d1e9f4a7b3c5d8e1f2a9b4c7d6e3f5a8b1c4d7e2f9a", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->getKey( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppKey::class, $response); + } + + public function testMethodDeleteKey(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->deleteKey( + "", + "" + ); + + $this->assertSame($data, $response); + } + + public function testMethodUpdateLabels(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "My Application", + "description" => "Connect your workspace to My Application.", + "clientUri" => "https://example.com", + "logoUri" => "https://example.com/logo.png", + "privacyPolicyUrl" => "https://example.com/privacy", + "termsUrl" => "https://example.com/terms", + "contacts" => array(), + "tagline" => "Automate your workspace.", + "tags" => array(), + "labels" => array(), + "images" => array(), + "supportUrl" => "https://example.com/support", + "dataDeletionUrl" => "https://example.com/data-deletion", + "redirectUris" => array(), + "postLogoutRedirectUris" => array(), + "enabled" => true, + "type" => "confidential", + "deviceFlow" => true, + "teamId" => "5e5ea5c16897e", + "userId" => "5e5ea5c16897e", + "installationScopes" => array(), + "installationRedirectUrl" => "https://example.com/setup", + "secrets" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "[SECRET]", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->updateLabels( + "", + array() + ); + + $this->assertInstanceOf(\Appwrite\Models\App::class, $response); + } + + public function testMethodListSecrets(): void + { + $data = array( + "total" => 5, + "secrets" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "[SECRET]", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->listSecrets( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppSecretList::class, $response); + } + + public function testMethodCreateSecret(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "5f3c8d2a1b9e4f7a6c8b2d1e9f4a7b3c5d8e1f2a9b4c7d6e3f5a8b1c4d7e2f9a", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->createSecret( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppSecretPlaintext::class, $response); + } + + public function testMethodGetSecret(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "[SECRET]", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->getSecret( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppSecret::class, $response); + } + + public function testMethodDeleteSecret(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->deleteSecret( + "", + "" + ); + + $this->assertSame($data, $response); + } + + public function testMethodUpdateTeam(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "My Application", + "description" => "Connect your workspace to My Application.", + "clientUri" => "https://example.com", + "logoUri" => "https://example.com/logo.png", + "privacyPolicyUrl" => "https://example.com/privacy", + "termsUrl" => "https://example.com/terms", + "contacts" => array(), + "tagline" => "Automate your workspace.", + "tags" => array(), + "labels" => array(), + "images" => array(), + "supportUrl" => "https://example.com/support", + "dataDeletionUrl" => "https://example.com/data-deletion", + "redirectUris" => array(), + "postLogoutRedirectUris" => array(), + "enabled" => true, + "type" => "confidential", + "deviceFlow" => true, + "teamId" => "5e5ea5c16897e", + "userId" => "5e5ea5c16897e", + "installationScopes" => array(), + "installationRedirectUrl" => "https://example.com/setup", + "secrets" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "secret" => "[SECRET]", + "hint" => "f5c6c7", + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->updateTeam( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\App::class, $response); + } + + public function testMethodDeleteTokens(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->deleteTokens( + "" + ); + + $this->assertSame($data, $response); + } + +} diff --git a/tests/Appwrite/Services/BackupsTest.php b/tests/Appwrite/Services/BackupsTest.php index da100a87..ee9d09d4 100644 --- a/tests/Appwrite/Services/BackupsTest.php +++ b/tests/Appwrite/Services/BackupsTest.php @@ -280,7 +280,7 @@ public function testMethodCreateRestoration(): void "migrationId" => "did8jx6ws45jana098ab7", "services" => array(), "resources" => array(), - "options" => "{databases.database[{oldId, newId, newName, newSpecification}]}" + "options" => "{databases.database[{oldId, newId, newName}]}" ); $this->client @@ -314,7 +314,7 @@ public function testMethodListRestorations(): void "migrationId" => "did8jx6ws45jana098ab7", "services" => array(), "resources" => array(), - "options" => "{databases.database[{oldId, newId, newName, newSpecification}]}" + "options" => "{databases.database[{oldId, newId, newName}]}" ) ) ); @@ -344,7 +344,7 @@ public function testMethodGetRestoration(): void "migrationId" => "did8jx6ws45jana098ab7", "services" => array(), "resources" => array(), - "options" => "{databases.database[{oldId, newId, newName, newSpecification}]}" + "options" => "{databases.database[{oldId, newId, newName}]}" ); $this->client diff --git a/tests/Appwrite/Services/DatabasesTest.php b/tests/Appwrite/Services/DatabasesTest.php index f7a0e312..cacd8583 100644 --- a/tests/Appwrite/Services/DatabasesTest.php +++ b/tests/Appwrite/Services/DatabasesTest.php @@ -33,35 +33,7 @@ public function testMethodList(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "enabled" => true, - "type" => "legacy", - "policies" => array( - array( - "\$id" => "5e5ea5c16897e", - "name" => "Hourly backups", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "services" => array(), - "resources" => array(), - "retention" => 7, - "schedule" => "0 * * * *", - "type" => "full", - "enabled" => true - ) - ), - "archives" => array( - array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "policyId" => "did8jx6ws45jana098ab7", - "size" => 100000, - "status" => "completed", - "startedAt" => "2020-10-15T06:38:00.000+00:00", - "migrationId" => "did8jx6ws45jana098ab7", - "services" => array(), - "resources" => array() - ) - ) + "type" => "legacy" ) ) ); @@ -86,35 +58,7 @@ public function testMethodCreate(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "enabled" => true, - "type" => "legacy", - "policies" => array( - array( - "\$id" => "5e5ea5c16897e", - "name" => "Hourly backups", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "services" => array(), - "resources" => array(), - "retention" => 7, - "schedule" => "0 * * * *", - "type" => "full", - "enabled" => true - ) - ), - "archives" => array( - array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "policyId" => "did8jx6ws45jana098ab7", - "size" => 100000, - "status" => "completed", - "startedAt" => "2020-10-15T06:38:00.000+00:00", - "migrationId" => "did8jx6ws45jana098ab7", - "services" => array(), - "resources" => array() - ) - ) + "type" => "legacy" ); $this->client @@ -284,35 +228,7 @@ public function testMethodGet(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "enabled" => true, - "type" => "legacy", - "policies" => array( - array( - "\$id" => "5e5ea5c16897e", - "name" => "Hourly backups", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "services" => array(), - "resources" => array(), - "retention" => 7, - "schedule" => "0 * * * *", - "type" => "full", - "enabled" => true - ) - ), - "archives" => array( - array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "policyId" => "did8jx6ws45jana098ab7", - "size" => 100000, - "status" => "completed", - "startedAt" => "2020-10-15T06:38:00.000+00:00", - "migrationId" => "did8jx6ws45jana098ab7", - "services" => array(), - "resources" => array() - ) - ) + "type" => "legacy" ); $this->client @@ -337,35 +253,7 @@ public function testMethodUpdate(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "enabled" => true, - "type" => "legacy", - "policies" => array( - array( - "\$id" => "5e5ea5c16897e", - "name" => "Hourly backups", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "services" => array(), - "resources" => array(), - "retention" => 7, - "schedule" => "0 * * * *", - "type" => "full", - "enabled" => true - ) - ), - "archives" => array( - array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "policyId" => "did8jx6ws45jana098ab7", - "size" => 100000, - "status" => "completed", - "startedAt" => "2020-10-15T06:38:00.000+00:00", - "migrationId" => "did8jx6ws45jana098ab7", - "services" => array(), - "resources" => array() - ) - ) + "type" => "legacy" ); $this->client diff --git a/tests/Appwrite/Services/Oauth2Test.php b/tests/Appwrite/Services/Oauth2Test.php new file mode 100644 index 00000000..3bf122fc --- /dev/null +++ b/tests/Appwrite/Services/Oauth2Test.php @@ -0,0 +1,297 @@ +client = Mockery::mock(Client::class); + $this->oauth2 = new Oauth2($this->client); + } + + public function testMethodApprove(): void + { + $data = array( + "redirectUrl" => "https://example.com/callback?code=abcde&state=fghij" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->approve( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Approve::class, $response); + } + + public function testMethodAuthorize(): void + { + $data = array( + "grantId" => "5e5ea5c16897e", + "redirectUrl" => "https://example.com/callback?code=abcde&state=fghij" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->authorize(); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Authorize::class, $response); + } + + public function testMethodAuthorizePost(): void + { + $data = array( + "grantId" => "5e5ea5c16897e", + "redirectUrl" => "https://example.com/callback?code=abcde&state=fghij" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->authorizePost(); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Authorize::class, $response); + } + + public function testMethodCreateDeviceAuthorization(): void + { + $data = array( + "device_code" => "5f3c8d2a1b9e4f7a6c8b2d1e9f4a7b3c5d8e1f2a9b4c7d6e3f5a8b1c4d7e2f9a", + "user_code" => "ABCD-EFGH", + "verification_uri" => "https://cloud.appwrite.io/console/oauth2/device", + "verification_uri_complete" => "https://cloud.appwrite.io/console/oauth2/device?user_code=ABCD-EFGH", + "expires_in" => 900, + "interval" => 5 + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->createDeviceAuthorization(); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2DeviceAuthorization::class, $response); + } + + public function testMethodCreateGrant(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c16897e", + "appId" => "5e5ea5c16897e", + "scopes" => array(), + "resources" => array(), + "authorizationDetails" => "[{\"type\":\"calendar\",\"identifier\":\"primary\",\"actions\":[\"read_events\",\"create_event\"]}]", + "prompt" => "login", + "redirectUri" => "https://example.com/callback", + "authTime" => 1592981250, + "expire" => "2020-10-15T06:38:00.000+00:00" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->createGrant( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Grant::class, $response); + } + + public function testMethodGetGrant(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c16897e", + "appId" => "5e5ea5c16897e", + "scopes" => array(), + "resources" => array(), + "authorizationDetails" => "[{\"type\":\"calendar\",\"identifier\":\"primary\",\"actions\":[\"read_events\",\"create_event\"]}]", + "prompt" => "login", + "redirectUri" => "https://example.com/callback", + "authTime" => 1592981250, + "expire" => "2020-10-15T06:38:00.000+00:00" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->getGrant( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Grant::class, $response); + } + + public function testMethodListOrganizations(): void + { + $data = array( + "total" => 5, + "organizations" => array( + array( + "\$id" => "5e5ea5c16897e" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->listOrganizations(); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2OrganizationList::class, $response); + } + + public function testMethodCreatePAR(): void + { + $data = array( + "request_uri" => "urn:appwrite:oauth2:request:5e5ea5c16897e", + "expires_in" => 600 + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->createPAR( + "", + "https://example.com", + "code" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2PAR::class, $response); + } + + public function testMethodListProjects(): void + { + $data = array( + "total" => 5, + "projects" => array( + array( + "\$id" => "5e5ea5c16897e", + "region" => "fra", + "endpoint" => "https://fra.cloud.appwrite.io/v1" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->listProjects(); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2ProjectList::class, $response); + } + + public function testMethodReject(): void + { + $data = array( + "redirectUrl" => "https://example.com/callback?error=access_denied&state=fghij" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->reject( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Reject::class, $response); + } + + public function testMethodRevoke(): void + { + $data = array(); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->revoke( + "" + ); + + $this->assertSame($data, $response); + } + + public function testMethodCreateToken(): void + { + $data = array( + "access_token" => "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...", + "token_type" => "Bearer", + "expires_in" => 3600, + "refresh_token" => "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", + "scope" => "openid email profile" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->oauth2->createToken( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\Oauth2Token::class, $response); + } + +} diff --git a/tests/Appwrite/Services/OrganizationTest.php b/tests/Appwrite/Services/OrganizationTest.php index 237ef05f..40c2dd57 100644 --- a/tests/Appwrite/Services/OrganizationTest.php +++ b/tests/Appwrite/Services/OrganizationTest.php @@ -46,6 +46,7 @@ public function testMethodGet(): void "screenshotsGenerated" => 50, "members" => 25, "webhooks" => 25, + "wafRules" => 2, "projects" => 2, "platforms" => 3, "users" => 25, @@ -276,6 +277,7 @@ public function testMethodUpdate(): void "screenshotsGenerated" => 50, "members" => 25, "webhooks" => 25, + "wafRules" => 2, "projects" => 2, "platforms" => 3, "users" => 25, @@ -498,6 +500,139 @@ public function testMethodDelete(): void $this->assertSame($data, $response); } + public function testMethodListInstallations(): void + { + $data = array( + "total" => 5, + "installations" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->listInstallations(); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallationList::class, $response); + } + + public function testMethodCreateInstallation(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->createInstallation( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallation::class, $response); + } + + public function testMethodGetInstallation(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->getInstallation( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallation::class, $response); + } + + public function testMethodUpdateInstallation(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->updateInstallation( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallation::class, $response); + } + + public function testMethodDeleteInstallation(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->organization->deleteInstallation( + "" + ); + + $this->assertSame($data, $response); + } + public function testMethodListKeys(): void { $data = array( @@ -863,7 +998,8 @@ public function testMethodListProjects(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ) ) ); @@ -947,7 +1083,8 @@ public function testMethodCreateProject(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -1032,7 +1169,8 @@ public function testMethodGetProject(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -1116,7 +1254,8 @@ public function testMethodUpdateProject(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client diff --git a/tests/Appwrite/Services/ProjectTest.php b/tests/Appwrite/Services/ProjectTest.php index 6cf56662..0213e34c 100644 --- a/tests/Appwrite/Services/ProjectTest.php +++ b/tests/Appwrite/Services/ProjectTest.php @@ -96,7 +96,8 @@ public function testMethodGet(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -194,7 +195,8 @@ public function testMethodUpdateAuthMethod(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -445,7 +447,8 @@ public function testMethodUpdateLabels(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -663,7 +666,8 @@ public function testMethodUpdateOAuth2Server(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2053,7 +2057,8 @@ public function testMethodUpdateDenyAliasedEmailPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2137,7 +2142,8 @@ public function testMethodUpdateDenyCorporateEmailPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2221,7 +2227,8 @@ public function testMethodUpdateDenyDisposableEmailPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2305,7 +2312,8 @@ public function testMethodUpdateDenyFreeEmailPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2389,7 +2397,8 @@ public function testMethodUpdateMembershipPrivacyPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2471,7 +2480,8 @@ public function testMethodUpdatePasswordDictionaryPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2555,7 +2565,8 @@ public function testMethodUpdatePasswordHistoryPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2639,7 +2650,8 @@ public function testMethodUpdatePasswordPersonalDataPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2746,7 +2758,8 @@ public function testMethodUpdateSessionAlertPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2830,7 +2843,8 @@ public function testMethodUpdateSessionDurationPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2914,7 +2928,8 @@ public function testMethodUpdateSessionInvalidationPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -2998,7 +3013,8 @@ public function testMethodUpdateSessionLimitPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -3082,7 +3098,8 @@ public function testMethodUpdateUserLimitPolicy(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -3192,7 +3209,8 @@ public function testMethodUpdateProtocol(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -3277,7 +3295,8 @@ public function testMethodUpdateService(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client @@ -3362,7 +3381,8 @@ public function testMethodUpdateSMTP(): void "billingPlan" => "pro" ) ), - "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00" + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true ); $this->client diff --git a/tests/Appwrite/Services/TablesDBTest.php b/tests/Appwrite/Services/TablesDBTest.php index f298c097..1c75086f 100644 --- a/tests/Appwrite/Services/TablesDBTest.php +++ b/tests/Appwrite/Services/TablesDBTest.php @@ -33,35 +33,7 @@ public function testMethodList(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "enabled" => true, - "type" => "legacy", - "policies" => array( - array( - "\$id" => "5e5ea5c16897e", - "name" => "Hourly backups", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "services" => array(), - "resources" => array(), - "retention" => 7, - "schedule" => "0 * * * *", - "type" => "full", - "enabled" => true - ) - ), - "archives" => array( - array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "policyId" => "did8jx6ws45jana098ab7", - "size" => 100000, - "status" => "completed", - "startedAt" => "2020-10-15T06:38:00.000+00:00", - "migrationId" => "did8jx6ws45jana098ab7", - "services" => array(), - "resources" => array() - ) - ) + "type" => "legacy" ) ) ); @@ -86,35 +58,7 @@ public function testMethodCreate(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "enabled" => true, - "type" => "legacy", - "policies" => array( - array( - "\$id" => "5e5ea5c16897e", - "name" => "Hourly backups", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "services" => array(), - "resources" => array(), - "retention" => 7, - "schedule" => "0 * * * *", - "type" => "full", - "enabled" => true - ) - ), - "archives" => array( - array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "policyId" => "did8jx6ws45jana098ab7", - "size" => 100000, - "status" => "completed", - "startedAt" => "2020-10-15T06:38:00.000+00:00", - "migrationId" => "did8jx6ws45jana098ab7", - "services" => array(), - "resources" => array() - ) - ) + "type" => "legacy" ); $this->client @@ -132,6 +76,44 @@ public function testMethodCreate(): void $this->assertInstanceOf(\Appwrite\Models\Database::class, $response); } + public function testMethodListSpecifications(): void + { + $data = array( + "specifications" => array( + array( + "slug" => "s-2vcpu-2gb", + "name" => "Standard", + "price" => 20, + "cpu" => 2000, + "memory" => 2048, + "maxConnections" => 200, + "includedStorage" => 25, + "includedBandwidth" => 200, + "enabled" => true + ) + ), + "total" => 9, + "pricing" => array( + "storageOverageRate" => 0.125, + "bandwidthOverageRate" => 0.08, + "replicaRate" => 1, + "crossRegionReplicaRate" => 1, + "pitrRate" => 0.2 + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->listSpecifications(); + + $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabaseSpecificationList::class, $response); + } + public function testMethodListTransactions(): void { $data = array( @@ -284,35 +266,7 @@ public function testMethodGet(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "enabled" => true, - "type" => "legacy", - "policies" => array( - array( - "\$id" => "5e5ea5c16897e", - "name" => "Hourly backups", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "services" => array(), - "resources" => array(), - "retention" => 7, - "schedule" => "0 * * * *", - "type" => "full", - "enabled" => true - ) - ), - "archives" => array( - array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "policyId" => "did8jx6ws45jana098ab7", - "size" => 100000, - "status" => "completed", - "startedAt" => "2020-10-15T06:38:00.000+00:00", - "migrationId" => "did8jx6ws45jana098ab7", - "services" => array(), - "resources" => array() - ) - ) + "type" => "legacy" ); $this->client @@ -337,35 +291,7 @@ public function testMethodUpdate(): void "\$createdAt" => "2020-10-15T06:38:00.000+00:00", "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "enabled" => true, - "type" => "legacy", - "policies" => array( - array( - "\$id" => "5e5ea5c16897e", - "name" => "Hourly backups", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "services" => array(), - "resources" => array(), - "retention" => 7, - "schedule" => "0 * * * *", - "type" => "full", - "enabled" => true - ) - ), - "archives" => array( - array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "policyId" => "did8jx6ws45jana098ab7", - "size" => 100000, - "status" => "completed", - "startedAt" => "2020-10-15T06:38:00.000+00:00", - "migrationId" => "did8jx6ws45jana098ab7", - "services" => array(), - "resources" => array() - ) - ) + "type" => "legacy" ); $this->client @@ -400,6 +326,144 @@ public function testMethodDelete(): void $this->assertSame($data, $response); } + public function testMethodCreateFailover(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "projectId" => "5e5ea5c16897e", + "name" => "My Production Database", + "api" => "postgresql", + "engine" => "postgresql", + "version" => "16", + "specification" => "s-2vcpu-2gb", + "backend" => "edge", + "hostname" => "db-myproject-mydb.fra.appwrite.center", + "connectionPort" => 5432, + "connectionUser" => "appwrite_user", + "connectionPassword" => "••••••••", + "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", + "ssl" => true, + "status" => "ready", + "containerStatus" => "active", + "lifecycleState" => "active", + "idleTimeoutMinutes" => 15, + "cpu" => 2000, + "memory" => 4096, + "storage" => 100, + "storageClass" => "ssd", + "storageMaxGb" => 100, + "nodePool" => "db-pool-4vcpu-8gb", + "replicas" => 2, + "syncMode" => "async", + "crossRegionReplicas" => 1, + "networkMaxConnections" => 500, + "networkIdleTimeoutSeconds" => 900, + "networkIPAllowlist" => array(), + "backupEnabled" => true, + "pitr" => true, + "pitrRetentionDays" => 14, + "storageAutoscaling" => true, + "storageAutoscalingThresholdPercent" => 85, + "storageAutoscalingMaxGb" => 500, + "maintenanceWindowDay" => "sun", + "maintenanceWindowHourUtc" => 3, + "metricsEnabled" => true, + "sqlApiEnabled" => true, + "sqlApiAllowedStatements" => array(), + "sqlApiMaxRows" => 10000, + "sqlApiMaxBytes" => 10485760, + "sqlApiTimeoutSeconds" => 30, + "error" => "[ERROR]" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->createFailover( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabase::class, $response); + } + + public function testMethodGetReplicas(): void + { + $data = array( + "replicas" => 2, + "syncMode" => "async", + "members" => array( + array( + "\$id" => "1", + "role" => "replica", + "status" => "active", + "lagSeconds" => 0.5 + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->getReplicas( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabaseReplicas::class, $response); + } + + public function testMethodGetStatus(): void + { + $data = array( + "health" => "healthy", + "ready" => true, + "engine" => "postgresql", + "version" => "17", + "uptime" => 86400, + "connections" => array( + "current" => 12, + "max" => 100 + ), + "replicas" => array( + array( + "index" => 0, + "role" => "primary", + "healthy" => true + ) + ), + "volumes" => array( + array( + "path" => "/var/lib/postgresql/data", + "usedPercent" => "45%", + "available" => "55GB", + "mounted" => true + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->getStatus( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\DatabaseStatus::class, $response); + } + public function testMethodListTables(): void { $data = array( diff --git a/tests/Appwrite/Services/TeamsTest.php b/tests/Appwrite/Services/TeamsTest.php index 1e7fb2ff..376e81d1 100644 --- a/tests/Appwrite/Services/TeamsTest.php +++ b/tests/Appwrite/Services/TeamsTest.php @@ -141,6 +141,145 @@ public function testMethodDelete(): void $this->assertSame($data, $response); } + public function testMethodListInstallations(): void + { + $data = array( + "total" => 5, + "installations" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->teams->listInstallations( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallationList::class, $response); + } + + public function testMethodCreateInstallation(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->teams->createInstallation( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallation::class, $response); + } + + public function testMethodGetInstallation(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->teams->getInstallation( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallation::class, $response); + } + + public function testMethodUpdateInstallation(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "appId" => "5e5ea5c16897e", + "teamId" => "5e5ea5c16897e", + "scopes" => array(), + "authorizationDetails" => array(), + "createdById" => "5e5ea5c16897e", + "createdByName" => "Walter White" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->teams->updateInstallation( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\AppInstallation::class, $response); + } + + public function testMethodDeleteInstallation(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->teams->deleteInstallation( + "", + "" + ); + + $this->assertSame($data, $response); + } + public function testMethodListMemberships(): void { $data = array( From ef36220ae621fe1ea4c7007d84d7c6107ec7b252 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Fri, 14 Aug 2026 13:41:28 +0530 Subject: [PATCH 4/6] chore: update PHP SDK to 28.0.0 --- CHANGELOG.md | 18 ++ README.md | 2 +- docs/account.md | 23 +- docs/activities.md | 2 +- docs/apps.md | 24 +- docs/backups.md | 6 +- docs/databases.md | 8 +- docs/embeddings.md | 17 ++ docs/examples/activities/list-events.md | 2 +- .../apps/create-installation-token.md | 2 +- .../delete-installation.md} | 9 +- docs/examples/apps/get-installation.md | 2 +- docs/examples/apps/list-installations.md | 2 +- .../embeddings/create-text-embeddings.md | 18 ++ ...te-key.md => update-mfa-factors-policy.md} | 11 +- .../project/update-o-auth-2-server.md | 3 +- .../project/update-session-duration-policy.md | 2 +- .../project/update-user-limit-policy.md | 2 +- docs/examples/proxy/create-invalidation.md | 19 ++ docs/examples/storage/create-file.md | 3 +- docs/examples/tablesdb/create-migration.md | 18 ++ docs/examples/tablesdb/create.md | 3 +- docs/examples/tablesdb/cutover-migration.md | 17 ++ docs/examples/tablesdb/delete-migration.md | 17 ++ docs/examples/tablesdb/get-migration.md | 17 ++ docs/examples/tablesdb/list-migrations.md | 16 + docs/examples/tablesdb/list-operations.md | 19 ++ docs/examples/tablesdb/update.md | 4 +- docs/examples/users/get-mfa-challenge.md | 17 ++ docs/functions.md | 2 +- docs/project.md | 45 ++- docs/proxy.md | 17 ++ docs/sites.md | 2 +- docs/storage.md | 3 +- docs/tablesdb.md | 99 ++++++- docs/users.md | 16 +- src/Appwrite/Client.php | 23 +- src/Appwrite/Enums/AuthenticationFactor.php | 9 + src/Appwrite/Enums/BuildRuntime.php | 9 + src/Appwrite/Enums/EmbeddingModel.php | 70 +++++ src/Appwrite/Enums/InvalidationType.php | 61 ++++ src/Appwrite/Enums/ProjectKeyScopes.php | 18 ++ src/Appwrite/Enums/ProjectPolicyId.php | 9 + src/Appwrite/Enums/Runtime.php | 9 + src/Appwrite/Models/BillingPlan.php | 36 +-- src/Appwrite/Models/BillingPlanAddon.php | 18 +- .../Models/BillingPlanAddonDetails.php | 13 +- src/Appwrite/Models/Database.php | 2 +- src/Appwrite/Models/DatabaseMigration.php | 152 ++++++++++ src/Appwrite/Models/DatabaseMigrationList.php | 59 ++++ src/Appwrite/Models/DatabaseStatus.php | 46 ++- .../Models/DatabaseStatusConnections.php | 2 +- src/Appwrite/Models/DatabaseStatusReplica.php | 4 +- src/Appwrite/Models/DedicatedDatabase.php | 13 +- .../Models/DedicatedDatabaseMember.php | 13 +- .../Models/DedicatedDatabaseOperation.php | 108 +++++++ .../Models/DedicatedDatabaseOperationList.php | 59 ++++ .../Models/DedicatedDatabaseReplicas.php | 35 ++- .../DedicatedDatabaseSpecificationPricing.php | 7 - src/Appwrite/Models/Embedding.php | 68 +++++ src/Appwrite/Models/EmbeddingList.php | 59 ++++ src/Appwrite/Models/File.php | 14 + src/Appwrite/Models/MfaChallengeSecret.php | 75 +++++ src/Appwrite/Models/MfaFactors.php | 13 +- src/Appwrite/Models/Organization.php | 112 +++---- src/Appwrite/Models/PolicyMfaFactors.php | 75 +++++ src/Appwrite/Models/Project.php | 4 + src/Appwrite/Models/ProxyInvalidation.php | 68 +++++ src/Appwrite/Models/UsageBillingPlan.php | 27 +- src/Appwrite/Services/Account.php | 45 --- src/Appwrite/Services/Activities.php | 4 +- src/Appwrite/Services/Apps.php | 57 +++- src/Appwrite/Services/Backups.php | 18 +- src/Appwrite/Services/Embeddings.php | 63 ++++ src/Appwrite/Services/Project.php | 127 ++++---- src/Appwrite/Services/Proxy.php | 50 ++++ src/Appwrite/Services/Storage.php | 7 +- src/Appwrite/Services/TablesDB.php | 275 +++++++++++++++++- src/Appwrite/Services/Users.php | 40 +++ tests/Appwrite/Services/AccountTest.php | 21 +- tests/Appwrite/Services/AppsTest.php | 19 ++ tests/Appwrite/Services/EmbeddingsTest.php | 50 ++++ tests/Appwrite/Services/OrganizationTest.php | 126 +------- tests/Appwrite/Services/ProjectTest.php | 113 +++++-- tests/Appwrite/Services/ProxyTest.php | 25 ++ tests/Appwrite/Services/StorageTest.php | 8 + tests/Appwrite/Services/TablesDBTest.php | 211 +++++++++++++- tests/Appwrite/Services/UsersTest.php | 28 +- 88 files changed, 2505 insertions(+), 559 deletions(-) create mode 100644 docs/embeddings.md rename docs/examples/{account/create-jwt.md => apps/delete-installation.md} (63%) create mode 100644 docs/examples/embeddings/create-text-embeddings.md rename docs/examples/project/{create-key.md => update-mfa-factors-policy.md} (60%) create mode 100644 docs/examples/proxy/create-invalidation.md create mode 100644 docs/examples/tablesdb/create-migration.md create mode 100644 docs/examples/tablesdb/cutover-migration.md create mode 100644 docs/examples/tablesdb/delete-migration.md create mode 100644 docs/examples/tablesdb/get-migration.md create mode 100644 docs/examples/tablesdb/list-migrations.md create mode 100644 docs/examples/tablesdb/list-operations.md create mode 100644 docs/examples/users/get-mfa-challenge.md create mode 100644 src/Appwrite/Enums/EmbeddingModel.php create mode 100644 src/Appwrite/Enums/InvalidationType.php create mode 100644 src/Appwrite/Models/DatabaseMigration.php create mode 100644 src/Appwrite/Models/DatabaseMigrationList.php create mode 100644 src/Appwrite/Models/DedicatedDatabaseOperation.php create mode 100644 src/Appwrite/Models/DedicatedDatabaseOperationList.php create mode 100644 src/Appwrite/Models/Embedding.php create mode 100644 src/Appwrite/Models/EmbeddingList.php create mode 100644 src/Appwrite/Models/MfaChallengeSecret.php create mode 100644 src/Appwrite/Models/PolicyMfaFactors.php create mode 100644 src/Appwrite/Models/ProxyInvalidation.php create mode 100644 src/Appwrite/Services/Embeddings.php create mode 100644 tests/Appwrite/Services/EmbeddingsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 099e71cb..6e9345fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Change Log +## 28.0.0 + +* Breaking: removed `account.createJWT`; use `users.createJWT` instead. A leaked JWT could mint further JWTs, letting a credential outlive its own expiry — a session cannot duplicate itself to live forever either +* Breaking: removed `project.createKey`. A leaked key could mint further hidden keys, making a compromise far harder to contain and revoke +* Breaking: `activities.listEvents` `queries` now takes an array instead of a string +* Added: `embeddings` service with `createTextEmbeddings`, plus the `EmbeddingModel` enum +* Added: TablesDB migration methods `listMigrations`, `createMigration`, `getMigration`, `deleteMigration`, `cutoverMigration`, and `listOperations` +* Added: `proxy.createInvalidation` for purging cached edge responses, plus the `InvalidationType` enum +* Added: `apps.deleteInstallation` +* Added: `users.getMFAChallenge` and the `MfaChallengeSecret` model +* Added: `project.updateMFAFactorsPolicy` and the `PolicyMfaFactors` model +* Added: `client.setOrganization` for organization-scoped requests +* Added: `folder` parameter to `storage.createFile` +* Added: `syncMode` parameter to `tablesDB.create` and `tablesDB.update`, and `specification` to `tablesDB.update` +* Added: `installationScopes` parameter to `project.updateOAuth2Server` +* Added: `custom` authentication factor, `node-26` runtime, `mfa-factors` project policy, and the `embeddings.write` and `proxy.invalidations.write` key scopes +* Updated: response format to `1.9.6` + ## 27.1.0 * Added: `Apps` service for managing OAuth2 applications, keys, and installations diff --git a/README.md b/README.md index a47ec4c5..c5c62c7b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Appwrite PHP SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-php.svg?style=flat-square&v=1) -![Version](https://img.shields.io/badge/api%20version-1.9.5-blue.svg?style=flat-square&v=1) +![Version](https://img.shields.io/badge/api%20version-1.9.6-blue.svg?style=flat-square&v=1) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) diff --git a/docs/account.md b/docs/account.md index 7600b611..fcf89b5f 100644 --- a/docs/account.md +++ b/docs/account.md @@ -150,19 +150,6 @@ DELETE https://cloud.appwrite.io/v1/account/identities/{identityId} | identityId | string | **Required** Identity ID. | | -```http request -POST https://cloud.appwrite.io/v1/account/jwts -``` - -** Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| duration | integer | Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds. | 900 | - - ```http request GET https://cloud.appwrite.io/v1/account/logs ``` @@ -280,7 +267,7 @@ POST https://cloud.appwrite.io/v1/account/mfa/challenges | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| factor | string | Factor used for verification. Must be one of following: `email`, `phone`, `totp`, `recoveryCode`. | | +| factor | string | Factor used for verification. Must be one of following: `email`, `phone`, `totp`, `recoveryCode`, `custom`. | | ```http request @@ -293,7 +280,7 @@ POST https://cloud.appwrite.io/v1/account/mfa/challenges | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| factor | string | Factor used for verification. Must be one of following: `email`, `phone`, `totp`, `recoveryCode`. | | +| factor | string | Factor used for verification. Must be one of following: `email`, `phone`, `totp`, `recoveryCode`, `custom`. | | ```http request @@ -561,7 +548,7 @@ GET https://cloud.appwrite.io/v1/account/sessions/{sessionId} | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| sessionId | string | **Required** Session ID. Use the string 'current' to get the current device session. | | +| sessionId | string | **Required** Session ID. Use the string 'current' to get the current device session. | current | ```http request @@ -574,7 +561,7 @@ PATCH https://cloud.appwrite.io/v1/account/sessions/{sessionId} | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| sessionId | string | **Required** Session ID. Use the string 'current' to update the current device session. | | +| sessionId | string | **Required** Session ID. Use the string 'current' to update the current device session. | current | ```http request @@ -587,7 +574,7 @@ DELETE https://cloud.appwrite.io/v1/account/sessions/{sessionId} | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| sessionId | string | **Required** Session ID. Use the string 'current' to delete the current device session. | | +| sessionId | string | **Required** Session ID. Use the string 'current' to delete the current device session. | current | ```http request diff --git a/docs/activities.md b/docs/activities.md index 06b40cb6..cf0d0f6c 100644 --- a/docs/activities.md +++ b/docs/activities.md @@ -11,7 +11,7 @@ GET https://cloud.appwrite.io/v1/activities/events | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| queries | string | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on attributes such as userId, teamId, etc. | [] | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on attributes such as userId, teamId, etc. | [] | ```http request diff --git a/docs/apps.md b/docs/apps.md index a8d9a2e8..436275b2 100644 --- a/docs/apps.md +++ b/docs/apps.md @@ -70,7 +70,7 @@ GET https://cloud.appwrite.io/v1/apps/{appId} | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| appId | string | **Required** Application unique ID or HTTPS client ID metadata document URL. | | +| appId | string | **Required** Application unique ID. | | ```http request @@ -101,7 +101,7 @@ PUT https://cloud.appwrite.io/v1/apps/{appId} | postLogoutRedirectUris | array | Post-logout redirect URIs for OpenID Connect RP-Initiated Logout. Each must be an https URL, an http loopback URL, or a private-use scheme URI, and must not contain a fragment. After ending the user session, the logout endpoint only redirects to URIs in this list. | [] | | type | string | OAuth2 client type. Use `public` for SPAs, mobile, and native apps that cannot keep a `client_secret` — PKCE is then required at the token endpoint. Use `confidential` for server-side clients that present a `client_secret`. Defaults to `confidential`. | confidential | | deviceFlow | boolean | Allow this client to use the OAuth2 Device Authorization Grant (RFC 8628) for input-constrained devices such as TVs and CLIs. Defaults to false. | | -| installationScopes | array | Scopes the application requests when installed on a team. Organization-level and project-level scopes only; use the list scopes endpoint with `type=installation` to discover available values. Maximum of 100 scopes are allowed. | [] | +| installationScopes | array | Scopes the application requests when installed on a team. Only scopes allowed by the project's OAuth2 server installation scopes configuration are accepted; use the list installation scopes endpoint to discover available values. Maximum of 100 scopes are allowed. | [] | | installationRedirectUrl | string | URL users are redirected to after creating or updating an installation of this application. Must be an https URL, an http loopback URL (localhost, 127.0.0.1, [::1]), or a private-use scheme URI, and must not contain a fragment. Leave empty for no redirect. | | @@ -122,7 +122,7 @@ DELETE https://cloud.appwrite.io/v1/apps/{appId} GET https://cloud.appwrite.io/v1/apps/{appId}/installations ``` -** List installations of an application. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. ** +** List installations of an application. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header, or a caller with update access to the app. ** ### Parameters @@ -137,7 +137,21 @@ GET https://cloud.appwrite.io/v1/apps/{appId}/installations GET https://cloud.appwrite.io/v1/apps/{appId}/installations/{installationId} ``` -** Get an installation of an application by its unique ID. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. ** +** Get an installation of an application by its unique ID. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header, or a caller with update access to the app. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| appId | string | **Required** Application unique ID. | | +| installationId | string | **Required** Installation unique ID. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/apps/{appId}/installations/{installationId} +``` + +** Delete an installation of an application by its unique ID. Requires a caller with update access to the app. Previously issued installation access tokens are revoked. ** ### Parameters @@ -151,7 +165,7 @@ GET https://cloud.appwrite.io/v1/apps/{appId}/installations/{installationId} POST https://cloud.appwrite.io/v1/apps/{appId}/installations/{installationId}/tokens ``` -** Create a token for an installation of an application. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. The returned token carries the scopes and authorization details granted to the installation, and can be used as an `Authorization: Bearer` header everywhere OAuth2 access tokens are accepted. Multiple tokens can be active for the same installation at once; each token stays valid until it expires or the installation is updated or deleted. ** +** Create a token for an installation of an application. Requires an app key sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header, or a caller with update access to the app. The returned token carries the scopes and authorization details granted to the installation, and can be used as an `Authorization: Bearer` header everywhere OAuth2 access tokens are accepted. Multiple tokens can be active for the same installation at once; each token stays valid until it expires or the installation is updated or deleted. ** ### Parameters diff --git a/docs/backups.md b/docs/backups.md index 3ba25e1d..24727348 100644 --- a/docs/backups.md +++ b/docs/backups.md @@ -135,13 +135,13 @@ POST https://cloud.appwrite.io/v1/backups/restoration ** Create and trigger a new restoration for a backup on a project. -For a backup of one database, the restoration resolves its destination before it is queued. Pass `newResourceId` to restore into that database ID, including the archived database ID to overwrite it. When `newResourceId` is omitted, a new database ID is generated and returned in `options`. +For a backup of one database, the restoration resolves its destination before it is queued. When `newResourceId` is omitted, the archived database is restored in place and its own ID is returned in `options`. Pass a different `newResourceId` to restore alongside it as a new database instead. The restoration migration records the archived database in `resourceId` and `resourceType`, and the resolved database in `destinationResourceId` and `destinationResourceType`. Database types are stored canonically as `database`, `documentsdb`, or `vectorsdb`. Project-wide restorations leave these fields empty because they do not have a single source or destination database. To list every migration related to one database, use its canonical type in a nested `OR(AND(...), AND(...), AND(...))` across the root, parent, and destination relation pairs: `(resourceType, resourceId)`, `(parentResourceType, parentResourceId)`, and `(destinationResourceType, destinationResourceId)`. Legacy and TablesDB databases use `database`; the operational `resourceType` of a table migration is not rewritten to `tablesdb`. -When restoring a DocumentsDB or VectorsDB database to a new resource from a dedicated source, the restore provisions a fresh dedicated backing database at the source database's own specification. +When restoring a DocumentsDB or VectorsDB database from a dedicated source, the restore provisions a fresh dedicated backing database at the source database's own specification and lands the data there. An in-place restore swaps the database onto that backing only once the restore has succeeded, and retires the backing it displaced only once that swap is confirmed, so the source keeps serving its own data until the restored data is in place and any failure leaves it untouched. A serverless source has no dedicated backing to clone and restores onto the archived database instead. ** ### Parameters @@ -150,7 +150,7 @@ When restoring a DocumentsDB or VectorsDB database to a new resource from a dedi | --- | --- | --- | --- | | archiveId | string | Backup archive ID to restore | | | services | array | Array of services to restore | | -| newResourceId | string | Destination resource ID. Omit to generate a new ID, or pass the archived resource ID to overwrite it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | +| newResourceId | string | Destination resource ID. Omit to restore the archived resource in place, or pass a different ID to restore alongside it as a new resource. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | newResourceName | string | Database name. Max length: 128 chars. | | diff --git a/docs/databases.md b/docs/databases.md index b3435f40..f976fef2 100644 --- a/docs/databases.md +++ b/docs/databases.md @@ -186,7 +186,7 @@ POST https://cloud.appwrite.io/v1/databases/{databaseId}/collections | permissions | array | An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). | | | documentSecurity | boolean | Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions). | | | enabled | boolean | Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled. | 1 | -| attributes | array | Array of attribute definitions to create. Each attribute should contain: key (string), type (string: string, integer, float, boolean, datetime), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options. | [] | +| attributes | array | Array of attribute definitions to create. Each attribute should contain: key (string), type (string: string, varchar, text, mediumtext, longtext, integer, bigint, double, boolean, datetime, point, linestring, polygon, email, url, ip, enum), size (integer, required for string and varchar types), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options. | [] | | indexes | array | Array of index definitions to create. Each index should contain: key (string), type (string: key, fulltext, unique, spatial), attributes (array of attribute keys), orders (array of ASC/DESC, optional), and lengths (array of integers, optional). | [] | @@ -765,11 +765,11 @@ POST https://cloud.appwrite.io/v1/databases/{databaseId}/collections/{collection | databaseId | string | **Required** Database ID. | | | collectionId | string | **Required** Collection ID. | | | relatedCollectionId | string | Related Collection ID. | | -| type | string | Relation type | | +| type | string | Relationship type. Possible values are: oneToOne, oneToMany, manyToOne, manyToMany. | | | twoWay | boolean | Is Two Way? | | | key | string | Attribute Key. | | | twoWayKey | string | Two Way Attribute Key. | | -| onDelete | string | Constraints option | restrict | +| onDelete | string | Delete constraint. Possible values are: cascade, restrict, setNull. | restrict | ```http request @@ -786,7 +786,7 @@ PATCH https://cloud.appwrite.io/v1/databases/{databaseId}/collections/{collectio | databaseId | string | **Required** Database ID. | | | collectionId | string | **Required** Collection ID. | | | key | string | **Required** Attribute Key. | | -| onDelete | string | Constraints option | | +| onDelete | string | Delete constraint. Possible values are: cascade, restrict, setNull. | | | newKey | string | New Attribute Key. | | diff --git a/docs/embeddings.md b/docs/embeddings.md new file mode 100644 index 00000000..50d53b9b --- /dev/null +++ b/docs/embeddings.md @@ -0,0 +1,17 @@ +# Embeddings Service + + +```http request +POST https://cloud.appwrite.io/v1/embeddings/text +``` + +** Generate vector embeddings for an array of text using the selected embedding model. Use the returned vectors to power semantic search and similarity queries against your vector collections. + ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| texts | array | Array of text to generate embeddings. | | +| model | string | The embedding model to use for generating vector embeddings. | nomic-embed-text | + diff --git a/docs/examples/activities/list-events.md b/docs/examples/activities/list-events.md index ef9a9d70..cab59cfc 100644 --- a/docs/examples/activities/list-events.md +++ b/docs/examples/activities/list-events.md @@ -12,5 +12,5 @@ $client = (new Client()) $activities = new Activities($client); $result = $activities->listEvents( - queries: '' // optional + queries: [] // optional );``` diff --git a/docs/examples/apps/create-installation-token.md b/docs/examples/apps/create-installation-token.md index ef4ca380..33d117ae 100644 --- a/docs/examples/apps/create-installation-token.md +++ b/docs/examples/apps/create-installation-token.md @@ -7,7 +7,7 @@ use Appwrite\Services\Apps; $client = (new Client()) ->setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID - ->setKey(''); // Your secret API key + ->setSession(''); // The user session to authenticate with $apps = new Apps($client); diff --git a/docs/examples/account/create-jwt.md b/docs/examples/apps/delete-installation.md similarity index 63% rename from docs/examples/account/create-jwt.md rename to docs/examples/apps/delete-installation.md index 3314407a..e57a12f4 100644 --- a/docs/examples/account/create-jwt.md +++ b/docs/examples/apps/delete-installation.md @@ -2,15 +2,16 @@ setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID ->setSession(''); // The user session to authenticate with -$account = new Account($client); +$apps = new Apps($client); -$result = $account->createJWT( - duration: 0 // optional +$result = $apps->deleteInstallation( + appId: '', + installationId: '' );``` diff --git a/docs/examples/apps/get-installation.md b/docs/examples/apps/get-installation.md index 63de2616..0f7a9bac 100644 --- a/docs/examples/apps/get-installation.md +++ b/docs/examples/apps/get-installation.md @@ -7,7 +7,7 @@ use Appwrite\Services\Apps; $client = (new Client()) ->setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID - ->setKey(''); // Your secret API key + ->setSession(''); // The user session to authenticate with $apps = new Apps($client); diff --git a/docs/examples/apps/list-installations.md b/docs/examples/apps/list-installations.md index fbdff242..0209cd24 100644 --- a/docs/examples/apps/list-installations.md +++ b/docs/examples/apps/list-installations.md @@ -7,7 +7,7 @@ use Appwrite\Services\Apps; $client = (new Client()) ->setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint ->setProject('') // Your project ID - ->setKey(''); // Your secret API key + ->setSession(''); // The user session to authenticate with $apps = new Apps($client); diff --git a/docs/examples/embeddings/create-text-embeddings.md b/docs/examples/embeddings/create-text-embeddings.md new file mode 100644 index 00000000..15f92318 --- /dev/null +++ b/docs/examples/embeddings/create-text-embeddings.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$embeddings = new Embeddings($client); + +$result = $embeddings->createTextEmbeddings( + texts: [], + model: EmbeddingModel::NOMICEMBEDTEXT() // optional +);``` diff --git a/docs/examples/project/create-key.md b/docs/examples/project/update-mfa-factors-policy.md similarity index 60% rename from docs/examples/project/create-key.md rename to docs/examples/project/update-mfa-factors-policy.md index cd3dbfd9..8823cc8f 100644 --- a/docs/examples/project/create-key.md +++ b/docs/examples/project/update-mfa-factors-policy.md @@ -3,7 +3,6 @@ use Appwrite\Client; use Appwrite\Services\Project; -use Appwrite\Enums\ProjectKeyScopes; $client = (new Client()) ->setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -12,9 +11,9 @@ $client = (new Client()) $project = new Project($client); -$result = $project->createKey( - keyId: '', - name: '', - scopes: [ProjectKeyScopes::PROJECTREAD()], - expire: '2020-10-15T06:38:00.000+00:00' // optional +$result = $project->updateMFAFactorsPolicy( + totp: false, // optional + email: false, // optional + phone: false, // optional + custom: false // optional );``` diff --git a/docs/examples/project/update-o-auth-2-server.md b/docs/examples/project/update-o-auth-2-server.md index 4a7782f2..1d06279a 100644 --- a/docs/examples/project/update-o-auth-2-server.md +++ b/docs/examples/project/update-o-auth-2-server.md @@ -26,5 +26,6 @@ $result = $project->updateOAuth2Server( userCodeLength: 6, // optional userCodeFormat: 'numeric', // optional deviceCodeDuration: 60, // optional - defaultScopes: [] // optional + defaultScopes: [], // optional + installationScopes: [] // optional );``` diff --git a/docs/examples/project/update-session-duration-policy.md b/docs/examples/project/update-session-duration-policy.md index 89526e79..882e2b2f 100644 --- a/docs/examples/project/update-session-duration-policy.md +++ b/docs/examples/project/update-session-duration-policy.md @@ -12,5 +12,5 @@ $client = (new Client()) $project = new Project($client); $result = $project->updateSessionDurationPolicy( - duration: 5 + duration: 60 );``` diff --git a/docs/examples/project/update-user-limit-policy.md b/docs/examples/project/update-user-limit-policy.md index bb787e9e..0dc2f1f7 100644 --- a/docs/examples/project/update-user-limit-policy.md +++ b/docs/examples/project/update-user-limit-policy.md @@ -12,5 +12,5 @@ $client = (new Client()) $project = new Project($client); $result = $project->updateUserLimitPolicy( - total: 1 + total: 0 );``` diff --git a/docs/examples/proxy/create-invalidation.md b/docs/examples/proxy/create-invalidation.md new file mode 100644 index 00000000..00ae00ad --- /dev/null +++ b/docs/examples/proxy/create-invalidation.md @@ -0,0 +1,19 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$proxy = new Proxy($client); + +$result = $proxy->createInvalidation( + domain: '', + type: InvalidationType::TAG(), + reference: '' // optional +);``` diff --git a/docs/examples/storage/create-file.md b/docs/examples/storage/create-file.md index 62301b10..19c38797 100644 --- a/docs/examples/storage/create-file.md +++ b/docs/examples/storage/create-file.md @@ -18,5 +18,6 @@ $result = $storage->createFile( bucketId: '', fileId: '', file: InputFile::withPath('file.png'), - permissions: [Permission::read(Role::any())] // optional + permissions: [Permission::read(Role::any())], // optional + folder: '' // optional );``` diff --git a/docs/examples/tablesdb/create-migration.md b/docs/examples/tablesdb/create-migration.md new file mode 100644 index 00000000..37f670fe --- /dev/null +++ b/docs/examples/tablesdb/create-migration.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->createMigration( + databaseId: '', + specification: 's-1vcpu-1gb', + autoCutover: false // optional +);``` diff --git a/docs/examples/tablesdb/create.md b/docs/examples/tablesdb/create.md index 87c81dd2..7df1d49a 100644 --- a/docs/examples/tablesdb/create.md +++ b/docs/examples/tablesdb/create.md @@ -16,5 +16,6 @@ $result = $tablesDB->create( name: '', enabled: false, // optional specification: 'serverless', // optional - replicas: 0 // optional + replicas: 0, // optional + syncMode: 'async' // optional );``` diff --git a/docs/examples/tablesdb/cutover-migration.md b/docs/examples/tablesdb/cutover-migration.md new file mode 100644 index 00000000..71a37d33 --- /dev/null +++ b/docs/examples/tablesdb/cutover-migration.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->cutoverMigration( + databaseId: '', + migrationId: '' +);``` diff --git a/docs/examples/tablesdb/delete-migration.md b/docs/examples/tablesdb/delete-migration.md new file mode 100644 index 00000000..255d6aa8 --- /dev/null +++ b/docs/examples/tablesdb/delete-migration.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->deleteMigration( + databaseId: '', + migrationId: '' +);``` diff --git a/docs/examples/tablesdb/get-migration.md b/docs/examples/tablesdb/get-migration.md new file mode 100644 index 00000000..88d922b1 --- /dev/null +++ b/docs/examples/tablesdb/get-migration.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->getMigration( + databaseId: '', + migrationId: '' +);``` diff --git a/docs/examples/tablesdb/list-migrations.md b/docs/examples/tablesdb/list-migrations.md new file mode 100644 index 00000000..20c8485c --- /dev/null +++ b/docs/examples/tablesdb/list-migrations.md @@ -0,0 +1,16 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->listMigrations( + databaseId: '' +);``` diff --git a/docs/examples/tablesdb/list-operations.md b/docs/examples/tablesdb/list-operations.md new file mode 100644 index 00000000..311b1464 --- /dev/null +++ b/docs/examples/tablesdb/list-operations.md @@ -0,0 +1,19 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$tablesDB = new TablesDB($client); + +$result = $tablesDB->listOperations( + databaseId: '', + status: 'running', // optional + limit: 1, // optional + offset: 0 // optional +);``` diff --git a/docs/examples/tablesdb/update.md b/docs/examples/tablesdb/update.md index e6c703af..c5bafb8d 100644 --- a/docs/examples/tablesdb/update.md +++ b/docs/examples/tablesdb/update.md @@ -15,5 +15,7 @@ $result = $tablesDB->update( databaseId: '', name: '', // optional enabled: false, // optional - replicas: 0 // optional + specification: 'serverless', // optional + replicas: 0, // optional + syncMode: 'async' // optional );``` diff --git a/docs/examples/users/get-mfa-challenge.md b/docs/examples/users/get-mfa-challenge.md new file mode 100644 index 00000000..8ef5c4aa --- /dev/null +++ b/docs/examples/users/get-mfa-challenge.md @@ -0,0 +1,17 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$users = new Users($client); + +$result = $users->getMFAChallenge( + userId: '', + challengeId: '' +);``` diff --git a/docs/functions.md b/docs/functions.md index eb12a051..bc4a62ed 100644 --- a/docs/functions.md +++ b/docs/functions.md @@ -67,7 +67,7 @@ GET https://cloud.appwrite.io/v1/functions/specifications | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| type | string | Specification type to list. Can be one of: runtimes, builds. | runtimes | +| type | string | Specification type to list. Can be one of: runtimes, builds. Defaults to runtimes. | runtimes | ```http request diff --git a/docs/project.md b/docs/project.md index c98ef4bc..39a21349 100644 --- a/docs/project.md +++ b/docs/project.md @@ -43,24 +43,6 @@ GET https://cloud.appwrite.io/v1/project/keys | total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | -```http request -POST https://cloud.appwrite.io/v1/project/keys -``` - -** Create a new API key. It's recommended to have multiple API keys with strict scopes for separate functions within your project. - -You can also create an ephemeral API key if you need a short-lived key instead. ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| keyId | string | Key ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | -| name | string | Key name. Max length: 128 chars. | | -| scopes | array | Key scopes list. Maximum of 200 scopes are allowed. | | -| expire | string | Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. | | - - ```http request POST https://cloud.appwrite.io/v1/project/keys/ephemeral ``` @@ -239,6 +221,7 @@ PUT https://cloud.appwrite.io/v1/project/oauth2-server | userCodeFormat | string | Character set for device flow user codes: `numeric` (digits only — best for numeric keypads and TV remotes), `alphabetic` (letters only), or `alphanumeric` (letters and digits — highest entropy per character). Defaults to `alphanumeric`. | alphanumeric | | deviceCodeDuration | integer | Lifetime in seconds of device flow device codes and user codes. Device codes are intentionally short-lived. Leave empty to use default 600. | | | defaultScopes | array | List of OAuth2 scopes used when an authorization request omits the scope parameter. Every default scope must also be allowed by the OAuth2 server. Maximum of 100 scopes are allowed, each up to 128 characters long. | [] | +| installationScopes | array | List of scopes an application may request when installed on a team. Omitting the parameter clears the list, so no installation scopes can be granted. Maximum of 100 scopes are allowed, each up to 128 characters long. | [] | ```http request @@ -1191,6 +1174,22 @@ PATCH https://cloud.appwrite.io/v1/project/policies/membership-privacy | userAccessedAt | boolean | Set to true if you want make user last access time visible to all team members, or false to hide it. | | +```http request +PATCH https://cloud.appwrite.io/v1/project/policies/mfa-factors +``` + +** Updating this policy allows you to control which factors users can use to complete an MFA challenge. Disabled factors cannot be used to create a challenge and are reported as unavailable when listing factors. The custom factor is disabled by default; enable it to deliver challenge codes through your own channel. Recovery codes always remain available as a fallback. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| totp | boolean | Set to true to allow TOTP to complete an MFA challenge, or false to disable it. | | +| email | boolean | Set to true to allow email to complete an MFA challenge, or false to disable it. | | +| phone | boolean | Set to true to allow phone (SMS) to complete an MFA challenge, or false to disable it. | | +| custom | boolean | Set to true to allow the custom factor to complete an MFA challenge, or false to disable it. | | + + ```http request PATCH https://cloud.appwrite.io/v1/project/policies/password-dictionary ``` @@ -1216,7 +1215,7 @@ Keep in mind, while password history policy is disabled, the history is not bein | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| total | integer | Set the password history length per user. Value can be between 1 and 5000, or null to disable the limit. | | +| total | integer | Set the password history length per user. Value can be between 1 and 20, or null to disable the limit. | | ```http request @@ -1272,7 +1271,7 @@ PATCH https://cloud.appwrite.io/v1/project/policies/session-duration | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| duration | integer | Maximum session length in seconds. Minium allowed value is 5 second, and maximum is 1 year, which is 31536000 seconds. | | +| duration | integer | Maximum session length in seconds. Minium allowed value is 60 seconds, and maximum is 1 year, which is 31536000 seconds. | | ```http request @@ -1298,7 +1297,7 @@ PATCH https://cloud.appwrite.io/v1/project/policies/session-limit | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| total | integer | Set the maximum number of sessions allowed per user. Value can be between 1 and 5000, or null to disable the limit. | | +| total | integer | Set the maximum number of sessions allowed per user. Value can be between 1 and 100. | | ```http request @@ -1311,7 +1310,7 @@ PATCH https://cloud.appwrite.io/v1/project/policies/user-limit | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| total | integer | Set the maximum number of users allowed in the project. Value can be between 1 and 5000, or null to disable the limit. | | +| total | integer | Set the maximum number of users allowed in the project. Value can be between 0 and 10000. Use 0 or null to disable the limit. | | ```http request @@ -1324,7 +1323,7 @@ GET https://cloud.appwrite.io/v1/project/policies/{policyId} | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| policyId | string | **Required** Policy ID. Can be one of: password-dictionary, password-history, password-strength, password-personal-data, session-alert, session-duration, session-invalidation, session-limit, user-limit, membership-privacy, deny-aliased-email, deny-disposable-email, deny-free-email, deny-corporate-email. | | +| policyId | string | **Required** Policy ID. Can be one of: password-dictionary, password-history, password-strength, password-personal-data, session-alert, session-duration, session-invalidation, session-limit, user-limit, membership-privacy, mfa-factors, deny-aliased-email, deny-disposable-email, deny-free-email, deny-corporate-email. | | ```http request diff --git a/docs/proxy.md b/docs/proxy.md index 3c8d9b51..b429411d 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -1,6 +1,23 @@ # Proxy Service +```http request +POST https://cloud.appwrite.io/v1/proxy/invalidations +``` + +** Create a new CDN cache invalidation for a domain. Executes a hard purge of cached content. + +Depending on type, the invalidation purges a single cache tag, a single URL path, or all cached content for the domain. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| domain | string | Domain name. | | +| type | string | Type of reference passed. Allowed values are: tag, path, all | | +| reference | string | Reference to invalidate. Depending on type this can be: cache tag name (up to 128 characters), URL path (up to 2048 characters). Not required when type is all. | | + + ```http request GET https://cloud.appwrite.io/v1/proxy/rules ``` diff --git a/docs/sites.md b/docs/sites.md index 68f9b7d2..dac7de92 100644 --- a/docs/sites.md +++ b/docs/sites.md @@ -68,7 +68,7 @@ GET https://cloud.appwrite.io/v1/sites/specifications | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| type | string | Specification type to list. Can be one of: runtimes, builds. | runtimes | +| type | string | Specification type to list. Can be one of: runtimes, builds. Defaults to runtimes. | runtimes | ```http request diff --git a/docs/storage.md b/docs/storage.md index c051c9b5..86acceb0 100644 --- a/docs/storage.md +++ b/docs/storage.md @@ -99,7 +99,7 @@ GET https://cloud.appwrite.io/v1/storage/buckets/{bucketId}/files | Field Name | Type | Description | Default | | --- | --- | --- | --- | | bucketId | string | **Required** Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket). | | -| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded | [] | +| queries | array | Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, folder, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded | [] | | search | string | Search term to filter your list results. Max length: 256 chars. | | | total | boolean | When set to false, the total count returned will be 0 and will not be calculated. | 1 | @@ -125,6 +125,7 @@ If you're creating a new file using one of the Appwrite SDKs, all the chunk | fileId | string | File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | file | file | Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](https://appwrite.io/docs/products/storage/upload-download#input-file). | | | permissions | array | An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). | | +| folder | string | Virtual folder to place the file in, for example "photos/2026". Nest folders with `/`. Defaults to the bucket root. | | ```http request diff --git a/docs/tablesdb.md b/docs/tablesdb.md index eefcfcde..49f78e2f 100644 --- a/docs/tablesdb.md +++ b/docs/tablesdb.md @@ -32,6 +32,7 @@ POST https://cloud.appwrite.io/v1/tablesdb | enabled | boolean | Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled. | 1 | | specification | string | Database specification. Defaults to `serverless`, which creates the database on the shared pool. Any other value provisions a dedicated database on that specification. | serverless | | replicas | integer | Number of high availability replicas (0-5) for the dedicated database backing this database. Requires a dedicated `specification`; must be 0 for a serverless database. High availability is enabled when greater than 0. | 0 | +| syncMode | string | Replication sync mode for the dedicated database backing this database. Requires a dedicated `specification`; the mode is only in force once there is at least one replica. Allowed values: async, sync, quorum. | | ```http request @@ -148,7 +149,9 @@ PUT https://cloud.appwrite.io/v1/tablesdb/{databaseId} | databaseId | string | **Required** Database ID. | | | name | string | Database name. Max length: 128 chars. | | | enabled | boolean | Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled. | 1 | +| specification | string | Database specification. Resizing between dedicated specifications changes cpu, memory, storage and the connection ceiling via a rolling cutover with zero downtime. Moving a `serverless` database onto a dedicated specification is a data migration, not a resize. | | | replicas | integer | Number of high availability replicas (0-5) for the dedicated database backing this database. Only valid when the database is backed by a dedicated specification. High availability is enabled when greater than 0. | | +| syncMode | string | Replication sync mode for the dedicated database backing this database. Only valid when the database is backed by a dedicated specification; the mode is only in force once there is at least one replica. Allowed values: async, sync, quorum. | | ```http request @@ -168,7 +171,7 @@ DELETE https://cloud.appwrite.io/v1/tablesdb/{databaseId} POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/failovers ``` -** Trigger a manual failover for a dedicated database with high availability enabled. Promotes a replica to primary. The failover runs asynchronously; poll the database document for status updates. ** +** Trigger a manual failover for a dedicated database with high availability enabled. Promotes a replica to primary. The failover runs asynchronously; poll the database document for status updates. A database left mid-operation by a failover that did not finish also accepts this call as a repair, provided `targetReplicaId` names the member to promote. ** ### Parameters @@ -178,6 +181,92 @@ POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/failovers | targetReplicaId | string | Target replica ID to promote. If not specified, the healthiest replica is selected. | | +```http request +GET https://cloud.appwrite.io/v1/tablesdb/{databaseId}/migrations +``` + +** List the dedicated migrations for a TablesDB database. A database has at most one in-flight migration. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | + + +```http request +POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/migrations +``` + +** Start migrating a serverless TablesDB database onto a dedicated MySQL compute. Data is copied to the target while the source stays live, with a brief read-only window during cutover. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | +| specification | string | Dedicated compute specification to provision as the migration target (e.g. s-2vcpu-4gb). The migration always targets a dedicated compute, so `serverless` is not accepted. | | +| autoCutover | boolean | Whether to cut over automatically once the copy is verified. When disabled the migration parks at ready_to_cutover and holds there until the cutover is performed manually. | 1 | + + +```http request +GET https://cloud.appwrite.io/v1/tablesdb/{databaseId}/migrations/{migrationId} +``` + +** Get a single dedicated migration for a TablesDB database by its ID. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | +| migrationId | string | **Required** Migration ID. | | + + +```http request +DELETE https://cloud.appwrite.io/v1/tablesdb/{databaseId}/migrations/{migrationId} +``` + +** Abort an in-flight TablesDB dedicated migration. Only allowed before cutover; once the migration has cut over it cannot be aborted. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | +| migrationId | string | **Required** Migration ID. | | + + +```http request +POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/migrations/{migrationId}/cutover +``` + +** Cut a verified TablesDB migration over to its dedicated compute. Only applies to a migration created with `autoCutover` disabled, which waits at `ready_to_cutover` until this is called. The routing flip happens shortly after this returns, with a brief read-only window. One call buys one attempt: a cutover that fails a check returns the migration to `verifying` and parks it again, so call this once more to retry. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | +| migrationId | string | **Required** Migration ID. | | + + +```http request +GET https://cloud.appwrite.io/v1/tablesdb/{databaseId}/operations +``` + +** List the lifecycle operations recorded for a dedicated database, newest first. Every provision, update, restore, backup and replication action is recorded here with its outcome, including an attempt that was abandoned because another worker took over the database. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| databaseId | string | **Required** Database ID. | | +| status | string | Filter by operation status. | | +| limit | integer | Maximum number of operations to return. | 25 | +| offset | integer | Number of operations to skip. | 0 | + + ```http request GET https://cloud.appwrite.io/v1/tablesdb/{databaseId}/replicas ``` @@ -236,7 +325,7 @@ POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/tables | permissions | array | An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). | | | rowSecurity | boolean | Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a row. [Learn more about permissions](https://appwrite.io/docs/permissions). | | | enabled | boolean | Is table enabled? When set to 'disabled', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled. | 1 | -| columns | array | Array of column definitions to create. Each column should contain: key (string), type (string: string, integer, float, boolean, datetime, relationship), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options. | [] | +| columns | array | Array of column definitions to create. Each column should contain: key (string), type (string: string, varchar, text, mediumtext, longtext, integer, bigint, double, boolean, datetime, point, linestring, polygon, email, url, ip, enum), size (integer, required for string and varchar types), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options. | [] | | indexes | array | Array of index definitions to create. Each index should contain: key (string), type (string: key, fulltext, unique, spatial), attributes (array of column keys), orders (array of ASC/DESC, optional), and lengths (array of integers, optional). | [] | @@ -814,11 +903,11 @@ POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/tables/{tableId}/columns | databaseId | string | **Required** Database ID. | | | tableId | string | **Required** Table ID. | | | relatedTableId | string | Related Table ID. | | -| type | string | Relation type | | +| type | string | Relationship type. Possible values are: oneToOne, oneToMany, manyToOne, manyToMany. | | | twoWay | boolean | Is Two Way? | | | key | string | Column Key. | | | twoWayKey | string | Two Way Column Key. | | -| onDelete | string | Constraints option | restrict | +| onDelete | string | Delete constraint. Possible values are: cascade, restrict, setNull. | restrict | ```http request @@ -1024,7 +1113,7 @@ PATCH https://cloud.appwrite.io/v1/tablesdb/{databaseId}/tables/{tableId}/column | databaseId | string | **Required** Database ID. | | | tableId | string | **Required** Table ID. | | | key | string | **Required** Column Key. | | -| onDelete | string | Constraints option | | +| onDelete | string | Delete constraint. Possible values are: cascade, restrict, setNull. | | | newKey | string | New Column Key. | | diff --git a/docs/users.md b/docs/users.md index 02d1d014..7ded8472 100644 --- a/docs/users.md +++ b/docs/users.md @@ -248,7 +248,7 @@ POST https://cloud.appwrite.io/v1/users/{userId}/jwts | Field Name | Type | Description | Default | | --- | --- | --- | --- | | userId | string | **Required** User ID. | | -| sessionId | string | Session ID. Use the string 'recent' to use the most recent session. Defaults to the most recent session. | | +| sessionId | string | Session ID. Use the string 'recent' to use the most recent session. Defaults to the most recent session. | recent | | duration | integer | Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds. | 900 | @@ -355,6 +355,20 @@ DELETE https://cloud.appwrite.io/v1/users/{userId}/mfa/authenticators/{type} | type | string | **Required** Type of authenticator. | | +```http request +GET https://cloud.appwrite.io/v1/users/{userId}/mfa/challenges/{challengeId} +``` + +** Get a custom MFA challenge for a user, including the code to be delivered through your own channel. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| userId | string | **Required** User ID. | | +| challengeId | string | **Required** ID of the challenge. | | + + ```http request GET https://cloud.appwrite.io/v1/users/{userId}/mfa/factors ``` diff --git a/src/Appwrite/Client.php b/src/Appwrite/Client.php index 23ee27b6..e56b2adc 100644 --- a/src/Appwrite/Client.php +++ b/src/Appwrite/Client.php @@ -40,11 +40,11 @@ class Client */ protected array $headers = [ 'content-type' => '', - 'user-agent' => 'AppwritePHPSDK/27.1.0 ()', + 'user-agent' => 'AppwritePHPSDK/28.0.0 ()', 'x-sdk-name'=> 'PHP', 'x-sdk-platform'=> 'server', 'x-sdk-language'=> 'php', - 'x-sdk-version'=> '27.1.0', + 'x-sdk-version'=> '28.0.0', ]; /** @@ -94,7 +94,7 @@ class Client */ public function __construct() { - $this->headers['X-Appwrite-Response-Format'] = '1.9.5'; + $this->headers['X-Appwrite-Response-Format'] = '1.9.6'; } @@ -131,6 +131,23 @@ public function setKey(string $value): Client return $this; } + /** + * Set Organization + * + * Your organization ID + * + * @param string $value + * + * @return Client + */ + public function setOrganization(string $value): Client + { + $this->addHeader('X-Appwrite-Organization', $value); + $this->config['organization'] = $value; + + return $this; + } + /** * Set JWT * diff --git a/src/Appwrite/Enums/AuthenticationFactor.php b/src/Appwrite/Enums/AuthenticationFactor.php index b3694722..046cf53f 100644 --- a/src/Appwrite/Enums/AuthenticationFactor.php +++ b/src/Appwrite/Enums/AuthenticationFactor.php @@ -10,6 +10,7 @@ class AuthenticationFactor implements JsonSerializable private static AuthenticationFactor $PHONE; private static AuthenticationFactor $TOTP; private static AuthenticationFactor $RECOVERYCODE; + private static AuthenticationFactor $CUSTOM; private string $value; @@ -56,6 +57,13 @@ public static function RECOVERYCODE(): AuthenticationFactor } return self::$RECOVERYCODE; } + public static function CUSTOM(): AuthenticationFactor + { + if (!isset(self::$CUSTOM)) { + self::$CUSTOM = new AuthenticationFactor('custom'); + } + return self::$CUSTOM; + } public static function from(string $value): self { @@ -64,6 +72,7 @@ public static function from(string $value): self 'phone' => self::PHONE(), 'totp' => self::TOTP(), 'recoverycode' => self::RECOVERYCODE(), + 'custom' => self::CUSTOM(), default => throw new \InvalidArgumentException('Unknown AuthenticationFactor value: ' . $value), }; } diff --git a/src/Appwrite/Enums/BuildRuntime.php b/src/Appwrite/Enums/BuildRuntime.php index 186b4de3..ec65bb79 100644 --- a/src/Appwrite/Enums/BuildRuntime.php +++ b/src/Appwrite/Enums/BuildRuntime.php @@ -16,6 +16,7 @@ class BuildRuntime implements JsonSerializable private static BuildRuntime $NODE23; private static BuildRuntime $NODE24; private static BuildRuntime $NODE25; + private static BuildRuntime $NODE26; private static BuildRuntime $PHP80; private static BuildRuntime $PHP81; private static BuildRuntime $PHP82; @@ -185,6 +186,13 @@ public static function NODE25(): BuildRuntime } return self::$NODE25; } + public static function NODE26(): BuildRuntime + { + if (!isset(self::$NODE26)) { + self::$NODE26 = new BuildRuntime('node-26'); + } + return self::$NODE26; + } public static function PHP80(): BuildRuntime { if (!isset(self::$PHP80)) { @@ -766,6 +774,7 @@ public static function from(string $value): self 'node-23' => self::NODE23(), 'node-24' => self::NODE24(), 'node-25' => self::NODE25(), + 'node-26' => self::NODE26(), 'php-8.0' => self::PHP80(), 'php-8.1' => self::PHP81(), 'php-8.2' => self::PHP82(), diff --git a/src/Appwrite/Enums/EmbeddingModel.php b/src/Appwrite/Enums/EmbeddingModel.php new file mode 100644 index 00000000..ec104ce9 --- /dev/null +++ b/src/Appwrite/Enums/EmbeddingModel.php @@ -0,0 +1,70 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } + + public function jsonSerialize(): string + { + return $this->value; + } + + public static function NOMICEMBEDTEXT(): EmbeddingModel + { + if (!isset(self::$NOMICEMBEDTEXT)) { + self::$NOMICEMBEDTEXT = new EmbeddingModel('nomic-embed-text'); + } + return self::$NOMICEMBEDTEXT; + } + public static function EMBEDDINGGEMMA(): EmbeddingModel + { + if (!isset(self::$EMBEDDINGGEMMA)) { + self::$EMBEDDINGGEMMA = new EmbeddingModel('embedding-gemma'); + } + return self::$EMBEDDINGGEMMA; + } + public static function ALLMINILM(): EmbeddingModel + { + if (!isset(self::$ALLMINILM)) { + self::$ALLMINILM = new EmbeddingModel('all-minilm'); + } + return self::$ALLMINILM; + } + public static function BGESMALL(): EmbeddingModel + { + if (!isset(self::$BGESMALL)) { + self::$BGESMALL = new EmbeddingModel('bge-small'); + } + return self::$BGESMALL; + } + + public static function from(string $value): self + { + return match ($value) { + 'nomic-embed-text' => self::NOMICEMBEDTEXT(), + 'embedding-gemma' => self::EMBEDDINGGEMMA(), + 'all-minilm' => self::ALLMINILM(), + 'bge-small' => self::BGESMALL(), + default => throw new \InvalidArgumentException('Unknown EmbeddingModel value: ' . $value), + }; + } +} diff --git a/src/Appwrite/Enums/InvalidationType.php b/src/Appwrite/Enums/InvalidationType.php new file mode 100644 index 00000000..828bd90d --- /dev/null +++ b/src/Appwrite/Enums/InvalidationType.php @@ -0,0 +1,61 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } + + public function jsonSerialize(): string + { + return $this->value; + } + + public static function TAG(): InvalidationType + { + if (!isset(self::$TAG)) { + self::$TAG = new InvalidationType('tag'); + } + return self::$TAG; + } + public static function PATH(): InvalidationType + { + if (!isset(self::$PATH)) { + self::$PATH = new InvalidationType('path'); + } + return self::$PATH; + } + public static function ALL(): InvalidationType + { + if (!isset(self::$ALL)) { + self::$ALL = new InvalidationType('all'); + } + return self::$ALL; + } + + public static function from(string $value): self + { + return match ($value) { + 'tag' => self::TAG(), + 'path' => self::PATH(), + 'all' => self::ALL(), + default => throw new \InvalidArgumentException('Unknown InvalidationType value: ' . $value), + }; + } +} diff --git a/src/Appwrite/Enums/ProjectKeyScopes.php b/src/Appwrite/Enums/ProjectKeyScopes.php index b7d37a76..a0c12987 100644 --- a/src/Appwrite/Enums/ProjectKeyScopes.php +++ b/src/Appwrite/Enums/ProjectKeyScopes.php @@ -40,6 +40,7 @@ class ProjectKeyScopes implements JsonSerializable private static ProjectKeyScopes $INDEXESWRITE; private static ProjectKeyScopes $ROWSREAD; private static ProjectKeyScopes $ROWSWRITE; + private static ProjectKeyScopes $EMBEDDINGSWRITE; private static ProjectKeyScopes $COLLECTIONSREAD; private static ProjectKeyScopes $COLLECTIONSWRITE; private static ProjectKeyScopes $ATTRIBUTESREAD; @@ -104,6 +105,7 @@ class ProjectKeyScopes implements JsonSerializable private static ProjectKeyScopes $WAFRULESREAD; private static ProjectKeyScopes $WAFRULESWRITE; private static ProjectKeyScopes $EVENTSREAD; + private static ProjectKeyScopes $PROXYINVALIDATIONSWRITE; private static ProjectKeyScopes $APPSREAD; private static ProjectKeyScopes $APPSWRITE; private static ProjectKeyScopes $OAUTH2READ; @@ -366,6 +368,13 @@ public static function ROWSWRITE(): ProjectKeyScopes } return self::$ROWSWRITE; } + public static function EMBEDDINGSWRITE(): ProjectKeyScopes + { + if (!isset(self::$EMBEDDINGSWRITE)) { + self::$EMBEDDINGSWRITE = new ProjectKeyScopes('embeddings.write'); + } + return self::$EMBEDDINGSWRITE; + } public static function COLLECTIONSREAD(): ProjectKeyScopes { if (!isset(self::$COLLECTIONSREAD)) { @@ -814,6 +823,13 @@ public static function EVENTSREAD(): ProjectKeyScopes } return self::$EVENTSREAD; } + public static function PROXYINVALIDATIONSWRITE(): ProjectKeyScopes + { + if (!isset(self::$PROXYINVALIDATIONSWRITE)) { + self::$PROXYINVALIDATIONSWRITE = new ProjectKeyScopes('proxy.invalidations.write'); + } + return self::$PROXYINVALIDATIONSWRITE; + } public static function APPSREAD(): ProjectKeyScopes { if (!isset(self::$APPSREAD)) { @@ -894,6 +910,7 @@ public static function from(string $value): self 'indexes.write' => self::INDEXESWRITE(), 'rows.read' => self::ROWSREAD(), 'rows.write' => self::ROWSWRITE(), + 'embeddings.write' => self::EMBEDDINGSWRITE(), 'collections.read' => self::COLLECTIONSREAD(), 'collections.write' => self::COLLECTIONSWRITE(), 'attributes.read' => self::ATTRIBUTESREAD(), @@ -958,6 +975,7 @@ public static function from(string $value): self 'wafRules.read' => self::WAFRULESREAD(), 'wafRules.write' => self::WAFRULESWRITE(), 'events.read' => self::EVENTSREAD(), + 'proxy.invalidations.write' => self::PROXYINVALIDATIONSWRITE(), 'apps.read' => self::APPSREAD(), 'apps.write' => self::APPSWRITE(), 'oauth2.read' => self::OAUTH2READ(), diff --git a/src/Appwrite/Enums/ProjectPolicyId.php b/src/Appwrite/Enums/ProjectPolicyId.php index 64562d88..7ee3c25d 100644 --- a/src/Appwrite/Enums/ProjectPolicyId.php +++ b/src/Appwrite/Enums/ProjectPolicyId.php @@ -16,6 +16,7 @@ class ProjectPolicyId implements JsonSerializable private static ProjectPolicyId $SESSIONLIMIT; private static ProjectPolicyId $USERLIMIT; private static ProjectPolicyId $MEMBERSHIPPRIVACY; + private static ProjectPolicyId $MFAFACTORS; private static ProjectPolicyId $DENYALIASEDEMAIL; private static ProjectPolicyId $DENYDISPOSABLEEMAIL; private static ProjectPolicyId $DENYFREEEMAIL; @@ -108,6 +109,13 @@ public static function MEMBERSHIPPRIVACY(): ProjectPolicyId } return self::$MEMBERSHIPPRIVACY; } + public static function MFAFACTORS(): ProjectPolicyId + { + if (!isset(self::$MFAFACTORS)) { + self::$MFAFACTORS = new ProjectPolicyId('mfa-factors'); + } + return self::$MFAFACTORS; + } public static function DENYALIASEDEMAIL(): ProjectPolicyId { if (!isset(self::$DENYALIASEDEMAIL)) { @@ -150,6 +158,7 @@ public static function from(string $value): self 'session-limit' => self::SESSIONLIMIT(), 'user-limit' => self::USERLIMIT(), 'membership-privacy' => self::MEMBERSHIPPRIVACY(), + 'mfa-factors' => self::MFAFACTORS(), 'deny-aliased-email' => self::DENYALIASEDEMAIL(), 'deny-disposable-email' => self::DENYDISPOSABLEEMAIL(), 'deny-free-email' => self::DENYFREEEMAIL(), diff --git a/src/Appwrite/Enums/Runtime.php b/src/Appwrite/Enums/Runtime.php index e6f9f263..d082cb86 100644 --- a/src/Appwrite/Enums/Runtime.php +++ b/src/Appwrite/Enums/Runtime.php @@ -16,6 +16,7 @@ class Runtime implements JsonSerializable private static Runtime $NODE23; private static Runtime $NODE24; private static Runtime $NODE25; + private static Runtime $NODE26; private static Runtime $PHP80; private static Runtime $PHP81; private static Runtime $PHP82; @@ -185,6 +186,13 @@ public static function NODE25(): Runtime } return self::$NODE25; } + public static function NODE26(): Runtime + { + if (!isset(self::$NODE26)) { + self::$NODE26 = new Runtime('node-26'); + } + return self::$NODE26; + } public static function PHP80(): Runtime { if (!isset(self::$PHP80)) { @@ -766,6 +774,7 @@ public static function from(string $value): self 'node-23' => self::NODE23(), 'node-24' => self::NODE24(), 'node-25' => self::NODE25(), + 'node-26' => self::NODE26(), 'php-8.0' => self::PHP80(), 'php-8.1' => self::PHP81(), 'php-8.2' => self::PHP82(), diff --git a/src/Appwrite/Models/BillingPlan.php b/src/Appwrite/Models/BillingPlan.php index 951b4073..3b7f783a 100644 --- a/src/Appwrite/Models/BillingPlan.php +++ b/src/Appwrite/Models/BillingPlan.php @@ -24,7 +24,6 @@ * @param int $storage storage * @param int $imageTransformations image transformations * @param int $screenshotsGenerated screenshots generated - * @param int $members members * @param int $webhooks webhooks * @param int $wafRules maximum waf rules per project * @param int $projects projects @@ -48,7 +47,6 @@ * @param int $topics topics for messaging * @param int $authPhone sms authentications per month * @param int $domains custom domains - * @param int $activityLogs activity log days * @param int $usageLogs usage history days * @param int $projectInactivityDays number of days of console inactivity before a project is paused. 0 means pausing is disabled. * @param int $alertLimit alert threshold percentage @@ -71,15 +69,17 @@ * @param bool $supportsFreeEmailValidation does plan support blocking free email addresses. * @param bool $supportsCorporateEmailValidation does plan support restricting sign-ups to corporate email addresses only. * @param bool $supportsProjectSpecificRoles does plan support project-specific member roles. - * @param bool $backupsEnabled does plan support backup policies. * @param bool $usagePerProject whether usage addons are calculated per project. * @param BillingPlanSupportedAddons $supportedAddons supported addons for this plan - * @param int $backupPolicies how many policies does plan support * @param int $deploymentSize maximum function and site deployment size in mb * @param int $buildSize maximum function and site deployment size in mb * @param bool $databasesAllowEncrypt does the plan support encrypted string attributes or not. * @param BillingPlanGroup $group group of this billing plan for variants + * @param int|null $members members + * @param int|null $activityLogs activity log days * @param array|null $usageLogsIntervals usage log time intervals allowed for this plan (e.g. 15m, 1h, 1d). + * @param bool|null $backupsEnabled does plan support backup policies. + * @param int|null $backupPolicies how many policies does plan support * @param BillingPlanLimits|null $limits plan specific limits * @param Program|null $program details of the program this plan is a part of. * @param BillingPlanDedicatedDatabaseLimits|null $dedicatedDatabases dedicated database limits available to this plan. @@ -95,7 +95,6 @@ public function __construct( public int $storage, public int $imageTransformations, public int $screenshotsGenerated, - public int $members, public int $webhooks, public int $wafRules, public int $projects, @@ -119,7 +118,6 @@ public function __construct( public int $topics, public int $authPhone, public int $domains, - public int $activityLogs, public int $usageLogs, public int $projectInactivityDays, public int $alertLimit, @@ -142,15 +140,17 @@ public function __construct( public bool $supportsFreeEmailValidation, public bool $supportsCorporateEmailValidation, public bool $supportsProjectSpecificRoles, - public bool $backupsEnabled, public bool $usagePerProject, public BillingPlanSupportedAddons $supportedAddons, - public int $backupPolicies, public int $deploymentSize, public int $buildSize, public bool $databasesAllowEncrypt, public BillingPlanGroup $group, + public ?int $members = null, + public ?int $activityLogs = null, public ?array $usageLogsIntervals = null, + public ?bool $backupsEnabled = null, + public ?int $backupPolicies = null, public ?BillingPlanLimits $limits = null, public ?Program $program = null, public ?BillingPlanDedicatedDatabaseLimits $dedicatedDatabases = null @@ -192,9 +192,6 @@ public static function from(array $data): static if (!array_key_exists('screenshotsGenerated', $data)) { throw new \InvalidArgumentException('Missing required field "screenshotsGenerated" for ' . static::class . '.'); } - if (!array_key_exists('members', $data)) { - throw new \InvalidArgumentException('Missing required field "members" for ' . static::class . '.'); - } if (!array_key_exists('webhooks', $data)) { throw new \InvalidArgumentException('Missing required field "webhooks" for ' . static::class . '.'); } @@ -264,9 +261,6 @@ public static function from(array $data): static if (!array_key_exists('domains', $data)) { throw new \InvalidArgumentException('Missing required field "domains" for ' . static::class . '.'); } - if (!array_key_exists('activityLogs', $data)) { - throw new \InvalidArgumentException('Missing required field "activityLogs" for ' . static::class . '.'); - } if (!array_key_exists('usageLogs', $data)) { throw new \InvalidArgumentException('Missing required field "usageLogs" for ' . static::class . '.'); } @@ -333,18 +327,12 @@ public static function from(array $data): static if (!array_key_exists('supportsProjectSpecificRoles', $data)) { throw new \InvalidArgumentException('Missing required field "supportsProjectSpecificRoles" for ' . static::class . '.'); } - if (!array_key_exists('backupsEnabled', $data)) { - throw new \InvalidArgumentException('Missing required field "backupsEnabled" for ' . static::class . '.'); - } if (!array_key_exists('usagePerProject', $data)) { throw new \InvalidArgumentException('Missing required field "usagePerProject" for ' . static::class . '.'); } if (!array_key_exists('supportedAddons', $data)) { throw new \InvalidArgumentException('Missing required field "supportedAddons" for ' . static::class . '.'); } - if (!array_key_exists('backupPolicies', $data)) { - throw new \InvalidArgumentException('Missing required field "backupPolicies" for ' . static::class . '.'); - } if (!array_key_exists('deploymentSize', $data)) { throw new \InvalidArgumentException('Missing required field "deploymentSize" for ' . static::class . '.'); } @@ -369,7 +357,6 @@ public static function from(array $data): static storage: $data['storage'], imageTransformations: $data['imageTransformations'], screenshotsGenerated: $data['screenshotsGenerated'], - members: $data['members'], webhooks: $data['webhooks'], wafRules: $data['wafRules'], projects: $data['projects'], @@ -393,7 +380,6 @@ functions: $data['functions'], topics: $data['topics'], authPhone: $data['authPhone'], domains: $data['domains'], - activityLogs: $data['activityLogs'], usageLogs: $data['usageLogs'], projectInactivityDays: $data['projectInactivityDays'], alertLimit: $data['alertLimit'], @@ -416,15 +402,17 @@ functions: $data['functions'], supportsFreeEmailValidation: $data['supportsFreeEmailValidation'], supportsCorporateEmailValidation: $data['supportsCorporateEmailValidation'], supportsProjectSpecificRoles: $data['supportsProjectSpecificRoles'], - backupsEnabled: $data['backupsEnabled'], usagePerProject: $data['usagePerProject'], supportedAddons: static::hydrateTypedValue(BillingPlanSupportedAddons::class, $data['supportedAddons']), - backupPolicies: $data['backupPolicies'], deploymentSize: $data['deploymentSize'], buildSize: $data['buildSize'], databasesAllowEncrypt: $data['databasesAllowEncrypt'], group: static::hydrateTypedValue(BillingPlanGroup::class, $data['group']), + members: array_key_exists('members', $data) ? $data['members'] : null, + activityLogs: array_key_exists('activityLogs', $data) ? $data['activityLogs'] : null, usageLogsIntervals: array_key_exists('usageLogsIntervals', $data) ? $data['usageLogsIntervals'] : null, + backupsEnabled: array_key_exists('backupsEnabled', $data) ? $data['backupsEnabled'] : null, + backupPolicies: array_key_exists('backupPolicies', $data) ? $data['backupPolicies'] : null, limits: array_key_exists('limits', $data) ? static::hydrateTypedValue(BillingPlanLimits::class, $data['limits'], true) : null, program: array_key_exists('program', $data) ? static::hydrateTypedValue(Program::class, $data['program'], true) : null, dedicatedDatabases: array_key_exists('dedicatedDatabases', $data) ? static::hydrateTypedValue(BillingPlanDedicatedDatabaseLimits::class, $data['dedicatedDatabases'], true) : null diff --git a/src/Appwrite/Models/BillingPlanAddon.php b/src/Appwrite/Models/BillingPlanAddon.php index 7e79ea14..f34340e5 100644 --- a/src/Appwrite/Models/BillingPlanAddon.php +++ b/src/Appwrite/Models/BillingPlanAddon.php @@ -12,12 +12,12 @@ /** * BillingPlanAddon constructor. * - * @param BillingPlanAddonDetails $seats addon seats - * @param BillingPlanAddonDetails $projects addon projects + * @param BillingPlanAddonDetails|null $seats addon seats + * @param BillingPlanAddonDetails|null $projects addon projects */ public function __construct( - public BillingPlanAddonDetails $seats, - public BillingPlanAddonDetails $projects + public ?BillingPlanAddonDetails $seats = null, + public ?BillingPlanAddonDetails $projects = null ) { } @@ -26,16 +26,10 @@ public function __construct( */ public static function from(array $data): static { - if (!array_key_exists('seats', $data)) { - throw new \InvalidArgumentException('Missing required field "seats" for ' . static::class . '.'); - } - if (!array_key_exists('projects', $data)) { - throw new \InvalidArgumentException('Missing required field "projects" for ' . static::class . '.'); - } return new static( - seats: static::hydrateTypedValue(BillingPlanAddonDetails::class, $data['seats']), - projects: static::hydrateTypedValue(BillingPlanAddonDetails::class, $data['projects']) + seats: array_key_exists('seats', $data) ? static::hydrateTypedValue(BillingPlanAddonDetails::class, $data['seats'], true) : null, + projects: array_key_exists('projects', $data) ? static::hydrateTypedValue(BillingPlanAddonDetails::class, $data['projects'], true) : null ); } diff --git a/src/Appwrite/Models/BillingPlanAddonDetails.php b/src/Appwrite/Models/BillingPlanAddonDetails.php index 60f94449..79b8500c 100644 --- a/src/Appwrite/Models/BillingPlanAddonDetails.php +++ b/src/Appwrite/Models/BillingPlanAddonDetails.php @@ -16,20 +16,20 @@ * @param int $planIncluded addon plan included value * @param int $limit addon limit * @param string $type addon type - * @param string $currency price currency * @param float $price price * @param int $value resource value * @param string $invoiceDesc description on invoice + * @param string|null $currency price currency */ public function __construct( public bool $supported, public int $planIncluded, public int $limit, public string $type, - public string $currency, public float $price, public int $value, - public string $invoiceDesc + public string $invoiceDesc, + public ?string $currency = null ) { } @@ -50,9 +50,6 @@ public static function from(array $data): static if (!array_key_exists('type', $data)) { throw new \InvalidArgumentException('Missing required field "type" for ' . static::class . '.'); } - if (!array_key_exists('currency', $data)) { - throw new \InvalidArgumentException('Missing required field "currency" for ' . static::class . '.'); - } if (!array_key_exists('price', $data)) { throw new \InvalidArgumentException('Missing required field "price" for ' . static::class . '.'); } @@ -68,10 +65,10 @@ public static function from(array $data): static planIncluded: $data['planIncluded'], limit: $data['limit'], type: $data['type'], - currency: $data['currency'], price: $data['price'], value: $data['value'], - invoiceDesc: $data['invoiceDesc'] + invoiceDesc: $data['invoiceDesc'], + currency: array_key_exists('currency', $data) ? $data['currency'] : null ); } diff --git a/src/Appwrite/Models/Database.php b/src/Appwrite/Models/Database.php index fb6f77f3..b5e4baa0 100644 --- a/src/Appwrite/Models/Database.php +++ b/src/Appwrite/Models/Database.php @@ -22,7 +22,7 @@ * @param bool $enabled if database is enabled. can be 'enabled' or 'disabled'. when disabled, the database is inaccessible to users, but remains accessible to server sdks using api keys. * @param DatabaseType $type database type. * @param DatabaseStatus|null $status dedicated database lifecycle status. null when the database has no valid dedicated backing. - * @param string|null $engine underlying engine of the dedicated backing: postgresql, mysql, mariadb, or mongodb. a managed product (tablesdb, documentsdb, vectorsdb) reports the engine it runs on, so its type and engine can differ. null when the database has no dedicated backing. + * @param string|null $engine underlying engine of the dedicated backing: postgresql, mysql, or mongodb. a managed product (tablesdb, documentsdb, vectorsdb) reports the engine it runs on, so its type and engine can differ. null when the database has no dedicated backing. * @param string|null $specification compute specification identifier of the dedicated backing, e.g. s-2vcpu-2gb. null when the database has no dedicated backing. * @param int|null $replicas number of secondary high availability replicas, excluding the primary. null when backing configuration is unavailable. * @param list|null $policies database backup policies. diff --git a/src/Appwrite/Models/DatabaseMigration.php b/src/Appwrite/Models/DatabaseMigration.php new file mode 100644 index 00000000..d8e19ed8 --- /dev/null +++ b/src/Appwrite/Models/DatabaseMigration.php @@ -0,0 +1,152 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('$updatedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$updatedAt" for ' . static::class . '.'); + } + if (!array_key_exists('projectId', $data)) { + throw new \InvalidArgumentException('Missing required field "projectId" for ' . static::class . '.'); + } + if (!array_key_exists('databaseId', $data)) { + throw new \InvalidArgumentException('Missing required field "databaseId" for ' . static::class . '.'); + } + if (!array_key_exists('specification', $data)) { + throw new \InvalidArgumentException('Missing required field "specification" for ' . static::class . '.'); + } + if (!array_key_exists('phase', $data)) { + throw new \InvalidArgumentException('Missing required field "phase" for ' . static::class . '.'); + } + if (!array_key_exists('attempt', $data)) { + throw new \InvalidArgumentException('Missing required field "attempt" for ' . static::class . '.'); + } + if (!array_key_exists('lastError', $data)) { + throw new \InvalidArgumentException('Missing required field "lastError" for ' . static::class . '.'); + } + if (!array_key_exists('lagDocuments', $data)) { + throw new \InvalidArgumentException('Missing required field "lagDocuments" for ' . static::class . '.'); + } + if (!array_key_exists('verifiedAt', $data)) { + throw new \InvalidArgumentException('Missing required field "verifiedAt" for ' . static::class . '.'); + } + if (!array_key_exists('cutoverAt', $data)) { + throw new \InvalidArgumentException('Missing required field "cutoverAt" for ' . static::class . '.'); + } + if (!array_key_exists('soakUntil', $data)) { + throw new \InvalidArgumentException('Missing required field "soakUntil" for ' . static::class . '.'); + } + if (!array_key_exists('autoCutover', $data)) { + throw new \InvalidArgumentException('Missing required field "autoCutover" for ' . static::class . '.'); + } + if (!array_key_exists('cutoverRequested', $data)) { + throw new \InvalidArgumentException('Missing required field "cutoverRequested" for ' . static::class . '.'); + } + if (!array_key_exists('paused', $data)) { + throw new \InvalidArgumentException('Missing required field "paused" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + updatedAt: $data['$updatedAt'], + projectId: $data['projectId'], + databaseId: $data['databaseId'], + specification: $data['specification'], + phase: $data['phase'], + attempt: $data['attempt'], + lastError: $data['lastError'], + lagDocuments: $data['lagDocuments'], + verifiedAt: $data['verifiedAt'], + cutoverAt: $data['cutoverAt'], + soakUntil: $data['soakUntil'], + autoCutover: $data['autoCutover'], + cutoverRequested: $data['cutoverRequested'], + paused: $data['paused'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + '$updatedAt' => static::serializeValue($this->updatedAt), + 'projectId' => static::serializeValue($this->projectId), + 'databaseId' => static::serializeValue($this->databaseId), + 'specification' => static::serializeValue($this->specification), + 'phase' => static::serializeValue($this->phase), + 'attempt' => static::serializeValue($this->attempt), + 'lastError' => static::serializeValue($this->lastError), + 'lagDocuments' => static::serializeValue($this->lagDocuments), + 'verifiedAt' => static::serializeValue($this->verifiedAt), + 'cutoverAt' => static::serializeValue($this->cutoverAt), + 'soakUntil' => static::serializeValue($this->soakUntil), + 'autoCutover' => static::serializeValue($this->autoCutover), + 'cutoverRequested' => static::serializeValue($this->cutoverRequested), + 'paused' => static::serializeValue($this->paused) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DatabaseMigrationList.php b/src/Appwrite/Models/DatabaseMigrationList.php new file mode 100644 index 00000000..d8016eaf --- /dev/null +++ b/src/Appwrite/Models/DatabaseMigrationList.php @@ -0,0 +1,59 @@ + $migrations list of migrations. + */ + public function __construct( + public int $total, + public array $migrations + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('migrations', $data)) { + throw new \InvalidArgumentException('Missing required field "migrations" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + migrations: is_array($data['migrations']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(DatabaseMigration::class, $item), + $data['migrations'] + ) + : $data['migrations'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'migrations' => static::serializeValue($this->migrations) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DatabaseStatus.php b/src/Appwrite/Models/DatabaseStatus.php index 59b30ffd..5408a15e 100644 --- a/src/Appwrite/Models/DatabaseStatus.php +++ b/src/Appwrite/Models/DatabaseStatus.php @@ -12,14 +12,20 @@ /** * DatabaseStatus constructor. * - * @param string $health overall health status: healthy, degraded, or unhealthy. + * @param string $health overall health status: healthy, degraded, unhealthy, or unknown when nothing could be measured. * @param bool $ready whether the database is ready to accept connections. - * @param string $engine database engine: postgresql, mysql, mariadb, or mongodb. + * @param string $engine database engine: postgresql, mysql, or mongodb. * @param string $version database engine version. * @param int $uptime database uptime in seconds. * @param DatabaseStatusConnections $connections connection statistics. - * @param list $replicas list of database replicas and their status. + * @param string $syncMode requested replication sync mode. possible values: async, sync, quorum. compare with effectivesyncmode for what the primary is enforcing. + * @param bool $syncDegraded whether the enforced replication is weaker than the requested syncmode. + * @param int $syncAcknowledgements number of standby acknowledgements the primary waits for before a write is committed. + * @param int $syncStandbyCount number of standbys registered with the primary for synchronous replication. + * @param list $replicas list of database replicas and their status. every configured member appears, including one the backend has not brought up, which is reported as not healthy. * @param list $volumes storage volume information. + * @param string|null $effectiveSyncMode replication sync mode the primary is actually enforcing. null when high availability is disabled or the state could not be read. + * @param bool|null $syncStateConfirmed whether the other sync fields are an engine reading rather than a recorded estimate. true when the primary answered what it is enforcing, including when that answer contradicted the record, in which case the contradicted values are replaced by the ones the engine reports. false when the reading could not be taken: the probe did not answer, there was no engine to ask, or the values describe a configuration change just applied rather than anything measured. absent when no engine was asked at all, so an unprobed database is distinguishable from an unconfirmed one. false never means a standby was found lagging, because it is the absence of a reading rather than a negative one, so draw no conclusion about replication health from it or from a response that omits it. */ public function __construct( public string $health, @@ -28,8 +34,14 @@ public function __construct( public string $version, public int $uptime, public DatabaseStatusConnections $connections, + public string $syncMode, + public bool $syncDegraded, + public int $syncAcknowledgements, + public int $syncStandbyCount, public array $replicas, - public array $volumes + public array $volumes, + public ?string $effectiveSyncMode = null, + public ?bool $syncStateConfirmed = null ) { } @@ -56,6 +68,18 @@ public static function from(array $data): static if (!array_key_exists('connections', $data)) { throw new \InvalidArgumentException('Missing required field "connections" for ' . static::class . '.'); } + if (!array_key_exists('syncMode', $data)) { + throw new \InvalidArgumentException('Missing required field "syncMode" for ' . static::class . '.'); + } + if (!array_key_exists('syncDegraded', $data)) { + throw new \InvalidArgumentException('Missing required field "syncDegraded" for ' . static::class . '.'); + } + if (!array_key_exists('syncAcknowledgements', $data)) { + throw new \InvalidArgumentException('Missing required field "syncAcknowledgements" for ' . static::class . '.'); + } + if (!array_key_exists('syncStandbyCount', $data)) { + throw new \InvalidArgumentException('Missing required field "syncStandbyCount" for ' . static::class . '.'); + } if (!array_key_exists('replicas', $data)) { throw new \InvalidArgumentException('Missing required field "replicas" for ' . static::class . '.'); } @@ -70,6 +94,10 @@ public static function from(array $data): static version: $data['version'], uptime: $data['uptime'], connections: static::hydrateTypedValue(DatabaseStatusConnections::class, $data['connections']), + syncMode: $data['syncMode'], + syncDegraded: $data['syncDegraded'], + syncAcknowledgements: $data['syncAcknowledgements'], + syncStandbyCount: $data['syncStandbyCount'], replicas: is_array($data['replicas']) ? array_map( static fn (mixed $item): mixed => static::hydrateTypedValue(DatabaseStatusReplica::class, $item), @@ -81,7 +109,9 @@ public static function from(array $data): static static fn (mixed $item): mixed => static::hydrateTypedValue(DatabaseStatusVolume::class, $item), $data['volumes'] ) - : $data['volumes'] + : $data['volumes'], + effectiveSyncMode: array_key_exists('effectiveSyncMode', $data) ? $data['effectiveSyncMode'] : null, + syncStateConfirmed: array_key_exists('syncStateConfirmed', $data) ? $data['syncStateConfirmed'] : null ); } @@ -97,6 +127,12 @@ public function toArray(): array 'version' => static::serializeValue($this->version), 'uptime' => static::serializeValue($this->uptime), 'connections' => static::serializeValue($this->connections), + 'syncMode' => static::serializeValue($this->syncMode), + 'effectiveSyncMode' => static::serializeValue($this->effectiveSyncMode), + 'syncDegraded' => static::serializeValue($this->syncDegraded), + 'syncAcknowledgements' => static::serializeValue($this->syncAcknowledgements), + 'syncStandbyCount' => static::serializeValue($this->syncStandbyCount), + 'syncStateConfirmed' => static::serializeValue($this->syncStateConfirmed), 'replicas' => static::serializeValue($this->replicas), 'volumes' => static::serializeValue($this->volumes) ]; diff --git a/src/Appwrite/Models/DatabaseStatusConnections.php b/src/Appwrite/Models/DatabaseStatusConnections.php index b1917238..da68a5b2 100644 --- a/src/Appwrite/Models/DatabaseStatusConnections.php +++ b/src/Appwrite/Models/DatabaseStatusConnections.php @@ -13,7 +13,7 @@ * DatabaseStatusConnections constructor. * * @param int $current current number of active connections. - * @param int $max maximum allowed connections. + * @param int $max the engine's own max_connections. on a pooled database this is the backend limit the pooler multiplexes onto, not the ceiling a client pool may reach — that is networkmaxconnections on the database resource. */ public function __construct( public int $current, diff --git a/src/Appwrite/Models/DatabaseStatusReplica.php b/src/Appwrite/Models/DatabaseStatusReplica.php index acf6559c..8c00b586 100644 --- a/src/Appwrite/Models/DatabaseStatusReplica.php +++ b/src/Appwrite/Models/DatabaseStatusReplica.php @@ -12,8 +12,8 @@ /** * DatabaseStatusReplica constructor. * - * @param int $index statefulset pod index (0 = primary, 1+ = replicas). - * @param string $role replica role: primary or replica. + * @param int $index member index within the database. read `role` for which member accepts writes: a failover moves the primary without renumbering the indexes. + * @param string $role member role. possible values: primary (accepts reads and writes), replica (read-only follower), unknown (placement not established; reported while a transition is moving or restarting the topology, so no member can be named the write target). * @param bool $healthy whether the replica is healthy. * @param float|null $lagSeconds replication lag in seconds (null for primary). */ diff --git a/src/Appwrite/Models/DedicatedDatabase.php b/src/Appwrite/Models/DedicatedDatabase.php index 963e95fa..ce4706f6 100644 --- a/src/Appwrite/Models/DedicatedDatabase.php +++ b/src/Appwrite/Models/DedicatedDatabase.php @@ -18,12 +18,12 @@ * @param string $projectId project id that owns this database. * @param string $name database display name. * @param string $api product api that owns this database: tablesdb, documentsdb, vectorsdb, mysql, postgresql, or mongodb. - * @param string $engine database engine: postgresql, mysql, mariadb, or mongodb. + * @param string $engine database engine: postgresql, mysql, or mongodb. null until the backing reports one. * @param string $version database engine version. * @param string $specification specification identifier. * @param string $backend database backend provider. possible values: prisma, edge. * @param string $hostname database hostname for connections. - * @param int $connectionPort database port for connections. + * @param int $connectionPort database port for connections. derived from the engine when the backing has not reported one yet. * @param string $connectionUser database username for connections. * @param string $connectionPassword database password for connections. * @param string $connectionString full database connection string (uri format). @@ -40,8 +40,7 @@ * @param string $nodePool kubernetes node pool where the database is scheduled. * @param int $replicas number of high availability replicas. high availability is enabled when greater than 0. * @param string $syncMode replication sync mode: async, sync, or quorum. - * @param int $crossRegionReplicas number of cross-region replicas. cross-region availability is enabled when greater than 0. - * @param int $networkMaxConnections maximum concurrent connections. + * @param int $networkMaxConnections maximum concurrent client connections. this is the limit a client pool may reach; the engine's own max_connections reported by the status endpoint is a smaller backend limit the pooler multiplexes onto and does not constrain a client pool. * @param int $networkIdleTimeoutSeconds connection idle timeout in seconds. * @param array $networkIPAllowlist ip addresses/cidr ranges allowed to connect. * @param bool $backupEnabled whether automatic backups are enabled. @@ -91,7 +90,6 @@ public function __construct( public string $nodePool, public int $replicas, public string $syncMode, - public int $crossRegionReplicas, public int $networkMaxConnections, public int $networkIdleTimeoutSeconds, public array $networkIPAllowlist, @@ -204,9 +202,6 @@ public static function from(array $data): static if (!array_key_exists('syncMode', $data)) { throw new \InvalidArgumentException('Missing required field "syncMode" for ' . static::class . '.'); } - if (!array_key_exists('crossRegionReplicas', $data)) { - throw new \InvalidArgumentException('Missing required field "crossRegionReplicas" for ' . static::class . '.'); - } if (!array_key_exists('networkMaxConnections', $data)) { throw new \InvalidArgumentException('Missing required field "networkMaxConnections" for ' . static::class . '.'); } @@ -291,7 +286,6 @@ public static function from(array $data): static nodePool: $data['nodePool'], replicas: $data['replicas'], syncMode: $data['syncMode'], - crossRegionReplicas: $data['crossRegionReplicas'], networkMaxConnections: $data['networkMaxConnections'], networkIdleTimeoutSeconds: $data['networkIdleTimeoutSeconds'], networkIPAllowlist: $data['networkIPAllowlist'], @@ -351,7 +345,6 @@ public function toArray(): array 'nodePool' => static::serializeValue($this->nodePool), 'replicas' => static::serializeValue($this->replicas), 'syncMode' => static::serializeValue($this->syncMode), - 'crossRegionReplicas' => static::serializeValue($this->crossRegionReplicas), 'networkMaxConnections' => static::serializeValue($this->networkMaxConnections), 'networkIdleTimeoutSeconds' => static::serializeValue($this->networkIdleTimeoutSeconds), 'networkIPAllowlist' => static::serializeValue($this->networkIPAllowlist), diff --git a/src/Appwrite/Models/DedicatedDatabaseMember.php b/src/Appwrite/Models/DedicatedDatabaseMember.php index ba44af70..fb6dec1d 100644 --- a/src/Appwrite/Models/DedicatedDatabaseMember.php +++ b/src/Appwrite/Models/DedicatedDatabaseMember.php @@ -13,15 +13,15 @@ * DedicatedDatabaseMember constructor. * * @param string $id member identifier. - * @param string $role member role. possible values: primary (accepts reads and writes), replica (read-only follower). - * @param string $status member pod status. possible values: provisioning (pod missing or pending), starting (running but not ready), active (running and ready), failed (failed phase or crashloopbackoff container), or the lowercased pod phase reported by the cluster. - * @param float $lagSeconds replication lag in seconds. + * @param string $role member role. possible values: primary (accepts reads and writes), replica (read-only follower), unknown (placement not established; reported while a transition is moving or restarting the topology and this member has not been probed, so no member can be named the write target). + * @param string $status member pod status. possible values: pending (configured but absent from the backend topology, so nothing is bringing it up), provisioning (pod missing or pending), starting (running but not ready), active (running and ready), failed (failed phase or crashloopbackoff container), or the lowercased pod phase reported by the cluster. + * @param float|null $lagSeconds replication lag in seconds. null when the lag is not known: a primary has none to report, and a member the backend has not probed has none yet. */ public function __construct( public string $id, public string $role, public string $status, - public float $lagSeconds + public ?float $lagSeconds = null ) { } @@ -39,15 +39,12 @@ public static function from(array $data): static if (!array_key_exists('status', $data)) { throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); } - if (!array_key_exists('lagSeconds', $data)) { - throw new \InvalidArgumentException('Missing required field "lagSeconds" for ' . static::class . '.'); - } return new static( id: $data['$id'], role: $data['role'], status: $data['status'], - lagSeconds: $data['lagSeconds'] + lagSeconds: array_key_exists('lagSeconds', $data) ? $data['lagSeconds'] : null ); } diff --git a/src/Appwrite/Models/DedicatedDatabaseOperation.php b/src/Appwrite/Models/DedicatedDatabaseOperation.php new file mode 100644 index 00000000..628b96a7 --- /dev/null +++ b/src/Appwrite/Models/DedicatedDatabaseOperation.php @@ -0,0 +1,108 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('databaseId', $data)) { + throw new \InvalidArgumentException('Missing required field "databaseId" for ' . static::class . '.'); + } + if (!array_key_exists('type', $data)) { + throw new \InvalidArgumentException('Missing required field "type" for ' . static::class . '.'); + } + if (!array_key_exists('status', $data)) { + throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); + } + if (!array_key_exists('attempts', $data)) { + throw new \InvalidArgumentException('Missing required field "attempts" for ' . static::class . '.'); + } + if (!array_key_exists('errorCode', $data)) { + throw new \InvalidArgumentException('Missing required field "errorCode" for ' . static::class . '.'); + } + if (!array_key_exists('errorMessage', $data)) { + throw new \InvalidArgumentException('Missing required field "errorMessage" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + databaseId: $data['databaseId'], + type: $data['type'], + status: $data['status'], + attempts: $data['attempts'], + errorCode: $data['errorCode'], + errorMessage: $data['errorMessage'], + requestedAt: array_key_exists('requestedAt', $data) ? $data['requestedAt'] : null, + startedAt: array_key_exists('startedAt', $data) ? $data['startedAt'] : null, + completedAt: array_key_exists('completedAt', $data) ? $data['completedAt'] : null + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + 'databaseId' => static::serializeValue($this->databaseId), + 'type' => static::serializeValue($this->type), + 'status' => static::serializeValue($this->status), + 'attempts' => static::serializeValue($this->attempts), + 'requestedAt' => static::serializeValue($this->requestedAt), + 'startedAt' => static::serializeValue($this->startedAt), + 'completedAt' => static::serializeValue($this->completedAt), + 'errorCode' => static::serializeValue($this->errorCode), + 'errorMessage' => static::serializeValue($this->errorMessage) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DedicatedDatabaseOperationList.php b/src/Appwrite/Models/DedicatedDatabaseOperationList.php new file mode 100644 index 00000000..0ee0c79d --- /dev/null +++ b/src/Appwrite/Models/DedicatedDatabaseOperationList.php @@ -0,0 +1,59 @@ + $operations list of operations. + */ + public function __construct( + public int $total, + public array $operations + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('operations', $data)) { + throw new \InvalidArgumentException('Missing required field "operations" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + operations: is_array($data['operations']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(DedicatedDatabaseOperation::class, $item), + $data['operations'] + ) + : $data['operations'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'operations' => static::serializeValue($this->operations) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/DedicatedDatabaseReplicas.php b/src/Appwrite/Models/DedicatedDatabaseReplicas.php index 37a760d2..f3728359 100644 --- a/src/Appwrite/Models/DedicatedDatabaseReplicas.php +++ b/src/Appwrite/Models/DedicatedDatabaseReplicas.php @@ -13,13 +13,23 @@ * DedicatedDatabaseReplicas constructor. * * @param int $replicas number of configured replicas. zero means high availability is disabled. - * @param string $syncMode replication sync mode. possible values: async (asynchronous, fastest), sync (synchronous, strong consistency), quorum (quorum-based, majority of replicas must confirm). + * @param string $syncMode requested replication sync mode. possible values: async (asynchronous, fastest), sync (synchronous, strong consistency), quorum (quorum-based, majority of replicas must confirm). this is what was asked for; compare it with effectivesyncmode for what the primary is enforcing. + * @param bool $syncDegraded whether the enforced replication is weaker than the requested syncmode. + * @param int $syncAcknowledgements number of standby acknowledgements the primary waits for before a write is committed. zero means writes are acknowledged locally. + * @param int $syncStandbyCount number of standbys registered with the primary for synchronous replication. * @param list $members per-pod statuses for the primary and every replica. + * @param string|null $effectiveSyncMode replication sync mode the primary is actually enforcing. null when high availability is disabled or the state could not be read. a value below the requested syncmode means writes are being acknowledged with weaker durability than configured. + * @param bool|null $syncStateConfirmed whether the other sync fields are an engine reading rather than a recorded estimate. true when the primary answered what it is enforcing, including when that answer contradicted the record, in which case the contradicted values are replaced by the ones the engine reports. false when the reading could not be taken: the probe did not answer, there was no engine to ask, or the values describe a configuration change just applied rather than anything measured. absent when no engine was asked at all, so an unprobed database is distinguishable from an unconfirmed one. false never means a standby was found lagging, because it is the absence of a reading rather than a negative one, so draw no conclusion about replication health from it or from a response that omits it. */ public function __construct( public int $replicas, public string $syncMode, - public array $members + public bool $syncDegraded, + public int $syncAcknowledgements, + public int $syncStandbyCount, + public array $members, + public ?string $effectiveSyncMode = null, + public ?bool $syncStateConfirmed = null ) { } @@ -34,6 +44,15 @@ public static function from(array $data): static if (!array_key_exists('syncMode', $data)) { throw new \InvalidArgumentException('Missing required field "syncMode" for ' . static::class . '.'); } + if (!array_key_exists('syncDegraded', $data)) { + throw new \InvalidArgumentException('Missing required field "syncDegraded" for ' . static::class . '.'); + } + if (!array_key_exists('syncAcknowledgements', $data)) { + throw new \InvalidArgumentException('Missing required field "syncAcknowledgements" for ' . static::class . '.'); + } + if (!array_key_exists('syncStandbyCount', $data)) { + throw new \InvalidArgumentException('Missing required field "syncStandbyCount" for ' . static::class . '.'); + } if (!array_key_exists('members', $data)) { throw new \InvalidArgumentException('Missing required field "members" for ' . static::class . '.'); } @@ -41,12 +60,17 @@ public static function from(array $data): static return new static( replicas: $data['replicas'], syncMode: $data['syncMode'], + syncDegraded: $data['syncDegraded'], + syncAcknowledgements: $data['syncAcknowledgements'], + syncStandbyCount: $data['syncStandbyCount'], members: is_array($data['members']) ? array_map( static fn (mixed $item): mixed => static::hydrateTypedValue(DedicatedDatabaseMember::class, $item), $data['members'] ) - : $data['members'] + : $data['members'], + effectiveSyncMode: array_key_exists('effectiveSyncMode', $data) ? $data['effectiveSyncMode'] : null, + syncStateConfirmed: array_key_exists('syncStateConfirmed', $data) ? $data['syncStateConfirmed'] : null ); } @@ -58,6 +82,11 @@ public function toArray(): array $result = [ 'replicas' => static::serializeValue($this->replicas), 'syncMode' => static::serializeValue($this->syncMode), + 'effectiveSyncMode' => static::serializeValue($this->effectiveSyncMode), + 'syncDegraded' => static::serializeValue($this->syncDegraded), + 'syncAcknowledgements' => static::serializeValue($this->syncAcknowledgements), + 'syncStandbyCount' => static::serializeValue($this->syncStandbyCount), + 'syncStateConfirmed' => static::serializeValue($this->syncStateConfirmed), 'members' => static::serializeValue($this->members) ]; diff --git a/src/Appwrite/Models/DedicatedDatabaseSpecificationPricing.php b/src/Appwrite/Models/DedicatedDatabaseSpecificationPricing.php index 37a3b4c2..815757e2 100644 --- a/src/Appwrite/Models/DedicatedDatabaseSpecificationPricing.php +++ b/src/Appwrite/Models/DedicatedDatabaseSpecificationPricing.php @@ -15,14 +15,12 @@ * @param float $storageOverageRate price per gb of storage above the included amount, per month, in usd. * @param float $bandwidthOverageRate price per gb of bandwidth above the included amount, per month, in usd. * @param float $replicaRate high availability replica price as a fraction of the specification cost. - * @param float $crossRegionReplicaRate cross-region replica price as a fraction of the specification cost. * @param float $pitrRate point-in-time recovery price as a fraction of the specification cost. */ public function __construct( public float $storageOverageRate, public float $bandwidthOverageRate, public float $replicaRate, - public float $crossRegionReplicaRate, public float $pitrRate ) { } @@ -41,9 +39,6 @@ public static function from(array $data): static if (!array_key_exists('replicaRate', $data)) { throw new \InvalidArgumentException('Missing required field "replicaRate" for ' . static::class . '.'); } - if (!array_key_exists('crossRegionReplicaRate', $data)) { - throw new \InvalidArgumentException('Missing required field "crossRegionReplicaRate" for ' . static::class . '.'); - } if (!array_key_exists('pitrRate', $data)) { throw new \InvalidArgumentException('Missing required field "pitrRate" for ' . static::class . '.'); } @@ -52,7 +47,6 @@ public static function from(array $data): static storageOverageRate: $data['storageOverageRate'], bandwidthOverageRate: $data['bandwidthOverageRate'], replicaRate: $data['replicaRate'], - crossRegionReplicaRate: $data['crossRegionReplicaRate'], pitrRate: $data['pitrRate'] ); } @@ -66,7 +60,6 @@ public function toArray(): array 'storageOverageRate' => static::serializeValue($this->storageOverageRate), 'bandwidthOverageRate' => static::serializeValue($this->bandwidthOverageRate), 'replicaRate' => static::serializeValue($this->replicaRate), - 'crossRegionReplicaRate' => static::serializeValue($this->crossRegionReplicaRate), 'pitrRate' => static::serializeValue($this->pitrRate) ]; diff --git a/src/Appwrite/Models/Embedding.php b/src/Appwrite/Models/Embedding.php new file mode 100644 index 00000000..c38c4787 --- /dev/null +++ b/src/Appwrite/Models/Embedding.php @@ -0,0 +1,68 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('model', $data)) { + throw new \InvalidArgumentException('Missing required field "model" for ' . static::class . '.'); + } + if (!array_key_exists('dimension', $data)) { + throw new \InvalidArgumentException('Missing required field "dimension" for ' . static::class . '.'); + } + if (!array_key_exists('embedding', $data)) { + throw new \InvalidArgumentException('Missing required field "embedding" for ' . static::class . '.'); + } + if (!array_key_exists('error', $data)) { + throw new \InvalidArgumentException('Missing required field "error" for ' . static::class . '.'); + } + + return new static( + model: $data['model'], + dimension: $data['dimension'], + embedding: $data['embedding'], + error: $data['error'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'model' => static::serializeValue($this->model), + 'dimension' => static::serializeValue($this->dimension), + 'embedding' => static::serializeValue($this->embedding), + 'error' => static::serializeValue($this->error) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/EmbeddingList.php b/src/Appwrite/Models/EmbeddingList.php new file mode 100644 index 00000000..d666e5d5 --- /dev/null +++ b/src/Appwrite/Models/EmbeddingList.php @@ -0,0 +1,59 @@ + $embeddings list of embeddings. + */ + public function __construct( + public int $total, + public array $embeddings + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('embeddings', $data)) { + throw new \InvalidArgumentException('Missing required field "embeddings" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + embeddings: is_array($data['embeddings']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(Embedding::class, $item), + $data['embeddings'] + ) + : $data['embeddings'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'embeddings' => static::serializeValue($this->embeddings) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/File.php b/src/Appwrite/Models/File.php index 0853e506..4ce7c537 100644 --- a/src/Appwrite/Models/File.php +++ b/src/Appwrite/Models/File.php @@ -18,6 +18,8 @@ * @param string $updatedAt file update date in iso 8601 format. * @param array $permissions file permissions. [learn more about permissions](https://appwrite.io/docs/permissions). * @param string $name file name. + * @param string $folder virtual folder containing the file, with a trailing slash. empty for the bucket root. + * @param string $key full virtual path of the file: the folder followed by the file name. * @param string $signature file md5 signature. * @param string $mimeType file mime type. * @param int $sizeOriginal file original size in bytes. @@ -34,6 +36,8 @@ public function __construct( public string $updatedAt, public array $permissions, public string $name, + public string $folder, + public string $key, public string $signature, public string $mimeType, public int $sizeOriginal, @@ -68,6 +72,12 @@ public static function from(array $data): static if (!array_key_exists('name', $data)) { throw new \InvalidArgumentException('Missing required field "name" for ' . static::class . '.'); } + if (!array_key_exists('folder', $data)) { + throw new \InvalidArgumentException('Missing required field "folder" for ' . static::class . '.'); + } + if (!array_key_exists('key', $data)) { + throw new \InvalidArgumentException('Missing required field "key" for ' . static::class . '.'); + } if (!array_key_exists('signature', $data)) { throw new \InvalidArgumentException('Missing required field "signature" for ' . static::class . '.'); } @@ -100,6 +110,8 @@ public static function from(array $data): static updatedAt: $data['$updatedAt'], permissions: $data['$permissions'], name: $data['name'], + folder: $data['folder'], + key: $data['key'], signature: $data['signature'], mimeType: $data['mimeType'], sizeOriginal: $data['sizeOriginal'], @@ -123,6 +135,8 @@ public function toArray(): array '$updatedAt' => static::serializeValue($this->updatedAt), '$permissions' => static::serializeValue($this->permissions), 'name' => static::serializeValue($this->name), + 'folder' => static::serializeValue($this->folder), + 'key' => static::serializeValue($this->key), 'signature' => static::serializeValue($this->signature), 'mimeType' => static::serializeValue($this->mimeType), 'sizeOriginal' => static::serializeValue($this->sizeOriginal), diff --git a/src/Appwrite/Models/MfaChallengeSecret.php b/src/Appwrite/Models/MfaChallengeSecret.php new file mode 100644 index 00000000..579080ae --- /dev/null +++ b/src/Appwrite/Models/MfaChallengeSecret.php @@ -0,0 +1,75 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('$createdAt', $data)) { + throw new \InvalidArgumentException('Missing required field "$createdAt" for ' . static::class . '.'); + } + if (!array_key_exists('userId', $data)) { + throw new \InvalidArgumentException('Missing required field "userId" for ' . static::class . '.'); + } + if (!array_key_exists('expire', $data)) { + throw new \InvalidArgumentException('Missing required field "expire" for ' . static::class . '.'); + } + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException('Missing required field "code" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + createdAt: $data['$createdAt'], + userId: $data['userId'], + expire: $data['expire'], + code: $data['code'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + '$createdAt' => static::serializeValue($this->createdAt), + 'userId' => static::serializeValue($this->userId), + 'expire' => static::serializeValue($this->expire), + 'code' => static::serializeValue($this->code) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/MfaFactors.php b/src/Appwrite/Models/MfaFactors.php index bdfd41a7..eca5d042 100644 --- a/src/Appwrite/Models/MfaFactors.php +++ b/src/Appwrite/Models/MfaFactors.php @@ -16,12 +16,14 @@ * @param bool $phone can phone (sms) be used for mfa challenge for this account. * @param bool $email can email be used for mfa challenge for this account. * @param bool $recoveryCode can recovery code be used for mfa challenge for this account. + * @param bool $custom can custom factor be used for mfa challenge for this account. */ public function __construct( public bool $totp, public bool $phone, public bool $email, - public bool $recoveryCode + public bool $recoveryCode, + public bool $custom ) { } @@ -42,12 +44,16 @@ public static function from(array $data): static if (!array_key_exists('recoveryCode', $data)) { throw new \InvalidArgumentException('Missing required field "recoveryCode" for ' . static::class . '.'); } + if (!array_key_exists('custom', $data)) { + throw new \InvalidArgumentException('Missing required field "custom" for ' . static::class . '.'); + } return new static( totp: $data['totp'], phone: $data['phone'], email: $data['email'], - recoveryCode: $data['recoveryCode'] + recoveryCode: $data['recoveryCode'], + custom: $data['custom'] ); } @@ -60,7 +66,8 @@ public function toArray(): array 'totp' => static::serializeValue($this->totp), 'phone' => static::serializeValue($this->phone), 'email' => static::serializeValue($this->email), - 'recoveryCode' => static::serializeValue($this->recoveryCode) + 'recoveryCode' => static::serializeValue($this->recoveryCode), + 'custom' => static::serializeValue($this->custom) ]; return $result; diff --git a/src/Appwrite/Models/Organization.php b/src/Appwrite/Models/Organization.php index 8842b34f..5eeef10d 100644 --- a/src/Appwrite/Models/Organization.php +++ b/src/Appwrite/Models/Organization.php @@ -18,7 +18,6 @@ * @param string $name team name. * @param int $total total number of team members. * @param Preferences $prefs team preferences as a key-value object - * @param int $billingBudget project budget limit * @param array $budgetAlerts project budget limit * @param string $billingPlan organization's billing plan id. * @param string $billingPlanId organization's billing plan id. @@ -27,26 +26,27 @@ * @param string $billingStartDate billing cycle start date. * @param string $billingCurrentInvoiceDate current invoice cycle start date. * @param string $billingNextInvoiceDate next invoice cycle start date. - * @param string $billingTrialStartDate start date of trial. * @param int $billingTrialDays number of trial days. * @param string $billingAggregationId current active aggregation id. * @param string $billingInvoiceId current active aggregation id. * @param string $paymentMethodId default payment method. - * @param string $billingAddressId default payment method. - * @param string $backupPaymentMethodId backup payment method. * @param string $status team status. - * @param string $remarks remarks on team status. - * @param string $agreementBAA organization agreements - * @param string $programManagerName program manager's name. - * @param string $programManagerCalendar program manager's calendar link. - * @param string $programDiscordChannelName program's discord channel name. - * @param string $programDiscordChannelUrl program's discord channel url. - * @param string $billingPlanDowngrade billing plan selected for downgrade. - * @param string $billingTaxId tax id * @param bool $markedForDeletion marked for deletion * @param string $platform product with which the organization is associated (appwrite or imagine) * @param array $projects selected projects + * @param int|null $billingBudget project budget limit. null when no budget is set. + * @param string|null $billingTrialStartDate start date of trial. + * @param string|null $billingAddressId default payment method. + * @param string|null $backupPaymentMethodId backup payment method. + * @param string|null $remarks remarks on team status. + * @param string|null $agreementBAA organization agreements + * @param string|null $programManagerName program manager's name. + * @param string|null $programManagerCalendar program manager's calendar link. + * @param string|null $programDiscordChannelName program's discord channel name. + * @param string|null $programDiscordChannelUrl program's discord channel url. * @param BillingLimits|null $billingLimits billing limits reached + * @param string|null $billingPlanDowngrade billing plan selected for downgrade. + * @param string|null $billingTaxId tax id */ public function __construct( public string $id, @@ -55,7 +55,6 @@ public function __construct( public string $name, public int $total, public Preferences $prefs, - public int $billingBudget, public array $budgetAlerts, public string $billingPlan, public string $billingPlanId, @@ -64,26 +63,27 @@ public function __construct( public string $billingStartDate, public string $billingCurrentInvoiceDate, public string $billingNextInvoiceDate, - public string $billingTrialStartDate, public int $billingTrialDays, public string $billingAggregationId, public string $billingInvoiceId, public string $paymentMethodId, - public string $billingAddressId, - public string $backupPaymentMethodId, public string $status, - public string $remarks, - public string $agreementBAA, - public string $programManagerName, - public string $programManagerCalendar, - public string $programDiscordChannelName, - public string $programDiscordChannelUrl, - public string $billingPlanDowngrade, - public string $billingTaxId, public bool $markedForDeletion, public string $platform, public array $projects, - public ?BillingLimits $billingLimits = null + public ?int $billingBudget = null, + public ?string $billingTrialStartDate = null, + public ?string $billingAddressId = null, + public ?string $backupPaymentMethodId = null, + public ?string $remarks = null, + public ?string $agreementBAA = null, + public ?string $programManagerName = null, + public ?string $programManagerCalendar = null, + public ?string $programDiscordChannelName = null, + public ?string $programDiscordChannelUrl = null, + public ?BillingLimits $billingLimits = null, + public ?string $billingPlanDowngrade = null, + public ?string $billingTaxId = null ) { } @@ -110,9 +110,6 @@ public static function from(array $data): static if (!array_key_exists('prefs', $data)) { throw new \InvalidArgumentException('Missing required field "prefs" for ' . static::class . '.'); } - if (!array_key_exists('billingBudget', $data)) { - throw new \InvalidArgumentException('Missing required field "billingBudget" for ' . static::class . '.'); - } if (!array_key_exists('budgetAlerts', $data)) { throw new \InvalidArgumentException('Missing required field "budgetAlerts" for ' . static::class . '.'); } @@ -137,9 +134,6 @@ public static function from(array $data): static if (!array_key_exists('billingNextInvoiceDate', $data)) { throw new \InvalidArgumentException('Missing required field "billingNextInvoiceDate" for ' . static::class . '.'); } - if (!array_key_exists('billingTrialStartDate', $data)) { - throw new \InvalidArgumentException('Missing required field "billingTrialStartDate" for ' . static::class . '.'); - } if (!array_key_exists('billingTrialDays', $data)) { throw new \InvalidArgumentException('Missing required field "billingTrialDays" for ' . static::class . '.'); } @@ -152,39 +146,9 @@ public static function from(array $data): static if (!array_key_exists('paymentMethodId', $data)) { throw new \InvalidArgumentException('Missing required field "paymentMethodId" for ' . static::class . '.'); } - if (!array_key_exists('billingAddressId', $data)) { - throw new \InvalidArgumentException('Missing required field "billingAddressId" for ' . static::class . '.'); - } - if (!array_key_exists('backupPaymentMethodId', $data)) { - throw new \InvalidArgumentException('Missing required field "backupPaymentMethodId" for ' . static::class . '.'); - } if (!array_key_exists('status', $data)) { throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); } - if (!array_key_exists('remarks', $data)) { - throw new \InvalidArgumentException('Missing required field "remarks" for ' . static::class . '.'); - } - if (!array_key_exists('agreementBAA', $data)) { - throw new \InvalidArgumentException('Missing required field "agreementBAA" for ' . static::class . '.'); - } - if (!array_key_exists('programManagerName', $data)) { - throw new \InvalidArgumentException('Missing required field "programManagerName" for ' . static::class . '.'); - } - if (!array_key_exists('programManagerCalendar', $data)) { - throw new \InvalidArgumentException('Missing required field "programManagerCalendar" for ' . static::class . '.'); - } - if (!array_key_exists('programDiscordChannelName', $data)) { - throw new \InvalidArgumentException('Missing required field "programDiscordChannelName" for ' . static::class . '.'); - } - if (!array_key_exists('programDiscordChannelUrl', $data)) { - throw new \InvalidArgumentException('Missing required field "programDiscordChannelUrl" for ' . static::class . '.'); - } - if (!array_key_exists('billingPlanDowngrade', $data)) { - throw new \InvalidArgumentException('Missing required field "billingPlanDowngrade" for ' . static::class . '.'); - } - if (!array_key_exists('billingTaxId', $data)) { - throw new \InvalidArgumentException('Missing required field "billingTaxId" for ' . static::class . '.'); - } if (!array_key_exists('markedForDeletion', $data)) { throw new \InvalidArgumentException('Missing required field "markedForDeletion" for ' . static::class . '.'); } @@ -202,7 +166,6 @@ public static function from(array $data): static name: $data['name'], total: $data['total'], prefs: static::hydrateTypedValue(Preferences::class, $data['prefs']), - billingBudget: $data['billingBudget'], budgetAlerts: $data['budgetAlerts'], billingPlan: $data['billingPlan'], billingPlanId: $data['billingPlanId'], @@ -211,26 +174,27 @@ public static function from(array $data): static billingStartDate: $data['billingStartDate'], billingCurrentInvoiceDate: $data['billingCurrentInvoiceDate'], billingNextInvoiceDate: $data['billingNextInvoiceDate'], - billingTrialStartDate: $data['billingTrialStartDate'], billingTrialDays: $data['billingTrialDays'], billingAggregationId: $data['billingAggregationId'], billingInvoiceId: $data['billingInvoiceId'], paymentMethodId: $data['paymentMethodId'], - billingAddressId: $data['billingAddressId'], - backupPaymentMethodId: $data['backupPaymentMethodId'], status: $data['status'], - remarks: $data['remarks'], - agreementBAA: $data['agreementBAA'], - programManagerName: $data['programManagerName'], - programManagerCalendar: $data['programManagerCalendar'], - programDiscordChannelName: $data['programDiscordChannelName'], - programDiscordChannelUrl: $data['programDiscordChannelUrl'], - billingPlanDowngrade: $data['billingPlanDowngrade'], - billingTaxId: $data['billingTaxId'], markedForDeletion: $data['markedForDeletion'], platform: $data['platform'], projects: $data['projects'], - billingLimits: array_key_exists('billingLimits', $data) ? static::hydrateTypedValue(BillingLimits::class, $data['billingLimits'], true) : null + billingBudget: array_key_exists('billingBudget', $data) ? $data['billingBudget'] : null, + billingTrialStartDate: array_key_exists('billingTrialStartDate', $data) ? $data['billingTrialStartDate'] : null, + billingAddressId: array_key_exists('billingAddressId', $data) ? $data['billingAddressId'] : null, + backupPaymentMethodId: array_key_exists('backupPaymentMethodId', $data) ? $data['backupPaymentMethodId'] : null, + remarks: array_key_exists('remarks', $data) ? $data['remarks'] : null, + agreementBAA: array_key_exists('agreementBAA', $data) ? $data['agreementBAA'] : null, + programManagerName: array_key_exists('programManagerName', $data) ? $data['programManagerName'] : null, + programManagerCalendar: array_key_exists('programManagerCalendar', $data) ? $data['programManagerCalendar'] : null, + programDiscordChannelName: array_key_exists('programDiscordChannelName', $data) ? $data['programDiscordChannelName'] : null, + programDiscordChannelUrl: array_key_exists('programDiscordChannelUrl', $data) ? $data['programDiscordChannelUrl'] : null, + billingLimits: array_key_exists('billingLimits', $data) ? static::hydrateTypedValue(BillingLimits::class, $data['billingLimits'], true) : null, + billingPlanDowngrade: array_key_exists('billingPlanDowngrade', $data) ? $data['billingPlanDowngrade'] : null, + billingTaxId: array_key_exists('billingTaxId', $data) ? $data['billingTaxId'] : null ); } diff --git a/src/Appwrite/Models/PolicyMfaFactors.php b/src/Appwrite/Models/PolicyMfaFactors.php new file mode 100644 index 00000000..89b49271 --- /dev/null +++ b/src/Appwrite/Models/PolicyMfaFactors.php @@ -0,0 +1,75 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('totp', $data)) { + throw new \InvalidArgumentException('Missing required field "totp" for ' . static::class . '.'); + } + if (!array_key_exists('email', $data)) { + throw new \InvalidArgumentException('Missing required field "email" for ' . static::class . '.'); + } + if (!array_key_exists('phone', $data)) { + throw new \InvalidArgumentException('Missing required field "phone" for ' . static::class . '.'); + } + if (!array_key_exists('custom', $data)) { + throw new \InvalidArgumentException('Missing required field "custom" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + totp: $data['totp'], + email: $data['email'], + phone: $data['phone'], + custom: $data['custom'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + '$id' => static::serializeValue($this->id), + 'totp' => static::serializeValue($this->totp), + 'email' => static::serializeValue($this->email), + 'phone' => static::serializeValue($this->phone), + 'custom' => static::serializeValue($this->custom) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/Project.php b/src/Appwrite/Models/Project.php index f9013ca9..c63ab5bb 100644 --- a/src/Appwrite/Models/Project.php +++ b/src/Appwrite/Models/Project.php @@ -45,6 +45,7 @@ * @param string|null $oAuth2ServerAuthorizationUrl oauth2 server authorization url * @param array|null $oAuth2ServerScopes oauth2 server allowed scopes * @param array|null $oAuth2ServerDefaultScopes oauth2 server scopes used when an authorization request omits the scope parameter + * @param array|null $oAuth2ServerInstallationScopes scopes an application may request when installed on a team * @param array|null $oAuth2ServerAuthorizationDetailsTypes oauth2 server accepted rfc 9396 authorization_details types * @param int|null $oAuth2ServerAccessTokenDuration oauth2 server access token duration in seconds for confidential clients * @param int|null $oAuth2ServerRefreshTokenDuration oauth2 server refresh token duration in seconds for confidential clients @@ -92,6 +93,7 @@ public function __construct( public ?string $oAuth2ServerAuthorizationUrl = null, public ?array $oAuth2ServerScopes = null, public ?array $oAuth2ServerDefaultScopes = null, + public ?array $oAuth2ServerInstallationScopes = null, public ?array $oAuth2ServerAuthorizationDetailsTypes = null, public ?int $oAuth2ServerAccessTokenDuration = null, public ?int $oAuth2ServerRefreshTokenDuration = null, @@ -256,6 +258,7 @@ public static function from(array $data): static oAuth2ServerAuthorizationUrl: array_key_exists('oAuth2ServerAuthorizationUrl', $data) ? $data['oAuth2ServerAuthorizationUrl'] : null, oAuth2ServerScopes: array_key_exists('oAuth2ServerScopes', $data) ? $data['oAuth2ServerScopes'] : null, oAuth2ServerDefaultScopes: array_key_exists('oAuth2ServerDefaultScopes', $data) ? $data['oAuth2ServerDefaultScopes'] : null, + oAuth2ServerInstallationScopes: array_key_exists('oAuth2ServerInstallationScopes', $data) ? $data['oAuth2ServerInstallationScopes'] : null, oAuth2ServerAuthorizationDetailsTypes: array_key_exists('oAuth2ServerAuthorizationDetailsTypes', $data) ? $data['oAuth2ServerAuthorizationDetailsTypes'] : null, oAuth2ServerAccessTokenDuration: array_key_exists('oAuth2ServerAccessTokenDuration', $data) ? $data['oAuth2ServerAccessTokenDuration'] : null, oAuth2ServerRefreshTokenDuration: array_key_exists('oAuth2ServerRefreshTokenDuration', $data) ? $data['oAuth2ServerRefreshTokenDuration'] : null, @@ -310,6 +313,7 @@ public function toArray(): array 'oAuth2ServerAuthorizationUrl' => static::serializeValue($this->oAuth2ServerAuthorizationUrl), 'oAuth2ServerScopes' => static::serializeValue($this->oAuth2ServerScopes), 'oAuth2ServerDefaultScopes' => static::serializeValue($this->oAuth2ServerDefaultScopes), + 'oAuth2ServerInstallationScopes' => static::serializeValue($this->oAuth2ServerInstallationScopes), 'oAuth2ServerAuthorizationDetailsTypes' => static::serializeValue($this->oAuth2ServerAuthorizationDetailsTypes), 'oAuth2ServerAccessTokenDuration' => static::serializeValue($this->oAuth2ServerAccessTokenDuration), 'oAuth2ServerRefreshTokenDuration' => static::serializeValue($this->oAuth2ServerRefreshTokenDuration), diff --git a/src/Appwrite/Models/ProxyInvalidation.php b/src/Appwrite/Models/ProxyInvalidation.php new file mode 100644 index 00000000..6b35dfeb --- /dev/null +++ b/src/Appwrite/Models/ProxyInvalidation.php @@ -0,0 +1,68 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('domain', $data)) { + throw new \InvalidArgumentException('Missing required field "domain" for ' . static::class . '.'); + } + if (!array_key_exists('type', $data)) { + throw new \InvalidArgumentException('Missing required field "type" for ' . static::class . '.'); + } + if (!array_key_exists('reference', $data)) { + throw new \InvalidArgumentException('Missing required field "reference" for ' . static::class . '.'); + } + if (!array_key_exists('status', $data)) { + throw new \InvalidArgumentException('Missing required field "status" for ' . static::class . '.'); + } + + return new static( + domain: $data['domain'], + type: $data['type'], + reference: $data['reference'], + status: $data['status'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'domain' => static::serializeValue($this->domain), + 'type' => static::serializeValue($this->type), + 'reference' => static::serializeValue($this->reference), + 'status' => static::serializeValue($this->status) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/UsageBillingPlan.php b/src/Appwrite/Models/UsageBillingPlan.php index 790e95f0..827e4d60 100644 --- a/src/Appwrite/Models/UsageBillingPlan.php +++ b/src/Appwrite/Models/UsageBillingPlan.php @@ -14,28 +14,28 @@ * * @param AdditionalResource $bandwidth bandwidth additional resources * @param AdditionalResource $executions executions additional resources - * @param AdditionalResource $member member additional resources * @param AdditionalResource $realtime realtime additional resources * @param AdditionalResource $realtimeMessages realtime messages additional resources - * @param AdditionalResource $realtimeBandwidth realtime bandwidth additional resources * @param AdditionalResource $storage storage additional resources * @param AdditionalResource $users user additional resources * @param AdditionalResource $gBHours gbhour additional resources * @param AdditionalResource $imageTransformations image transformation additional resources - * @param AdditionalResource $credits credits additional resources + * @param AdditionalResource|null $member member additional resources + * @param AdditionalResource|null $realtimeBandwidth realtime bandwidth additional resources + * @param AdditionalResource|null $credits credits additional resources */ public function __construct( public AdditionalResource $bandwidth, public AdditionalResource $executions, - public AdditionalResource $member, public AdditionalResource $realtime, public AdditionalResource $realtimeMessages, - public AdditionalResource $realtimeBandwidth, public AdditionalResource $storage, public AdditionalResource $users, public AdditionalResource $gBHours, public AdditionalResource $imageTransformations, - public AdditionalResource $credits + public ?AdditionalResource $member = null, + public ?AdditionalResource $realtimeBandwidth = null, + public ?AdditionalResource $credits = null ) { } @@ -50,18 +50,12 @@ public static function from(array $data): static if (!array_key_exists('executions', $data)) { throw new \InvalidArgumentException('Missing required field "executions" for ' . static::class . '.'); } - if (!array_key_exists('member', $data)) { - throw new \InvalidArgumentException('Missing required field "member" for ' . static::class . '.'); - } if (!array_key_exists('realtime', $data)) { throw new \InvalidArgumentException('Missing required field "realtime" for ' . static::class . '.'); } if (!array_key_exists('realtimeMessages', $data)) { throw new \InvalidArgumentException('Missing required field "realtimeMessages" for ' . static::class . '.'); } - if (!array_key_exists('realtimeBandwidth', $data)) { - throw new \InvalidArgumentException('Missing required field "realtimeBandwidth" for ' . static::class . '.'); - } if (!array_key_exists('storage', $data)) { throw new \InvalidArgumentException('Missing required field "storage" for ' . static::class . '.'); } @@ -74,22 +68,19 @@ public static function from(array $data): static if (!array_key_exists('imageTransformations', $data)) { throw new \InvalidArgumentException('Missing required field "imageTransformations" for ' . static::class . '.'); } - if (!array_key_exists('credits', $data)) { - throw new \InvalidArgumentException('Missing required field "credits" for ' . static::class . '.'); - } return new static( bandwidth: static::hydrateTypedValue(AdditionalResource::class, $data['bandwidth']), executions: static::hydrateTypedValue(AdditionalResource::class, $data['executions']), - member: static::hydrateTypedValue(AdditionalResource::class, $data['member']), realtime: static::hydrateTypedValue(AdditionalResource::class, $data['realtime']), realtimeMessages: static::hydrateTypedValue(AdditionalResource::class, $data['realtimeMessages']), - realtimeBandwidth: static::hydrateTypedValue(AdditionalResource::class, $data['realtimeBandwidth']), storage: static::hydrateTypedValue(AdditionalResource::class, $data['storage']), users: static::hydrateTypedValue(AdditionalResource::class, $data['users']), gBHours: static::hydrateTypedValue(AdditionalResource::class, $data['GBHours']), imageTransformations: static::hydrateTypedValue(AdditionalResource::class, $data['imageTransformations']), - credits: static::hydrateTypedValue(AdditionalResource::class, $data['credits']) + member: array_key_exists('member', $data) ? static::hydrateTypedValue(AdditionalResource::class, $data['member'], true) : null, + realtimeBandwidth: array_key_exists('realtimeBandwidth', $data) ? static::hydrateTypedValue(AdditionalResource::class, $data['realtimeBandwidth'], true) : null, + credits: array_key_exists('credits', $data) ? static::hydrateTypedValue(AdditionalResource::class, $data['credits'], true) : null ); } diff --git a/src/Appwrite/Services/Account.php b/src/Appwrite/Services/Account.php index 441e05da..fb80d415 100644 --- a/src/Appwrite/Services/Account.php +++ b/src/Appwrite/Services/Account.php @@ -477,51 +477,6 @@ public function deleteIdentity(string $identityId): string } - /** - * Use this endpoint to create a JSON Web Token. You can use the resulting JWT - * to authenticate on behalf of the current user when working with the - * Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes - * from its creation and will be invalid if the user will logout in that time - * frame. - * - * @param ?int $duration - * @throws AppwriteException - * @return \Appwrite\Models\Jwt - */ - public function createJWT(?int $duration = null): \Appwrite\Models\Jwt - { - $apiPath = str_replace( - [], - [], - '/account/jwts' - ); - - $apiParams = []; - - if (!is_null($duration)) { - $apiParams['duration'] = $duration; - } - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['content-type'] = 'application/json'; - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_POST, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\Jwt::from($response); - - } - /** * Get the list of latest security activity logs for the currently logged in * user. Each log returns user IP address, location and date and time of log. diff --git a/src/Appwrite/Services/Activities.php b/src/Appwrite/Services/Activities.php index 9111586a..925c4c23 100644 --- a/src/Appwrite/Services/Activities.php +++ b/src/Appwrite/Services/Activities.php @@ -17,11 +17,11 @@ public function __construct(Client $client) /** * List all events for selected filters. * - * @param ?string $queries + * @param ?array $queries * @throws AppwriteException * @return \Appwrite\Models\ActivityEventList */ - public function listEvents(?string $queries = null): \Appwrite\Models\ActivityEventList + public function listEvents(?array $queries = null): \Appwrite\Models\ActivityEventList { $apiPath = str_replace( [], diff --git a/src/Appwrite/Services/Apps.php b/src/Appwrite/Services/Apps.php index d0a9c896..69b47975 100644 --- a/src/Appwrite/Services/Apps.php +++ b/src/Appwrite/Services/Apps.php @@ -454,7 +454,8 @@ public function delete(string $appId): string /** * List installations of an application. Requires an app key sent in the - * `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. + * `X-Appwrite-Key` header alongside the `X-Appwrite-App` header, or a caller + * with update access to the app. * * @param string $appId * @param ?array $queries @@ -502,7 +503,8 @@ public function listInstallations(string $appId, ?array $queries = null, ?bool $ /** * Get an installation of an application by its unique ID. Requires an app key - * sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. + * sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header, + * or a caller with update access to the app. * * @param string $appId * @param string $installationId @@ -540,14 +542,53 @@ public function getInstallation(string $appId, string $installationId): \Appwrit } + /** + * Delete an installation of an application by its unique ID. Requires a + * caller with update access to the app. Previously issued installation access + * tokens are revoked. + * + * @param string $appId + * @param string $installationId + * @throws AppwriteException + * @return string + */ + public function deleteInstallation(string $appId, string $installationId): string + { + $apiPath = str_replace( + ['{appId}', '{installationId}'], + [$appId, $installationId], + '/apps/{appId}/installations/{installationId}' + ); + + $apiParams = []; + $apiParams['appId'] = $appId; + $apiParams['installationId'] = $installationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + /** * Create a token for an installation of an application. Requires an app key - * sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header. - * The returned token carries the scopes and authorization details granted to - * the installation, and can be used as an `Authorization: Bearer` header - * everywhere OAuth2 access tokens are accepted. Multiple tokens can be active - * for the same installation at once; each token stays valid until it expires - * or the installation is updated or deleted. + * sent in the `X-Appwrite-Key` header alongside the `X-Appwrite-App` header, + * or a caller with update access to the app. The returned token carries the + * scopes and authorization details granted to the installation, and can be + * used as an `Authorization: Bearer` header everywhere OAuth2 access tokens + * are accepted. Multiple tokens can be active for the same installation at + * once; each token stays valid until it expires or the installation is + * updated or deleted. * * @param string $appId * @param string $installationId diff --git a/src/Appwrite/Services/Backups.php b/src/Appwrite/Services/Backups.php index 527176ed..ce513ff4 100644 --- a/src/Appwrite/Services/Backups.php +++ b/src/Appwrite/Services/Backups.php @@ -386,9 +386,10 @@ public function deletePolicy(string $policyId): string * Create and trigger a new restoration for a backup on a project. * * For a backup of one database, the restoration resolves its destination - * before it is queued. Pass `newResourceId` to restore into that database ID, - * including the archived database ID to overwrite it. When `newResourceId` is - * omitted, a new database ID is generated and returned in `options`. + * before it is queued. When `newResourceId` is omitted, the archived database + * is restored in place and its own ID is returned in `options`. Pass a + * different `newResourceId` to restore alongside it as a new database + * instead. * * The restoration migration records the archived database in `resourceId` and * `resourceType`, and the resolved database in `destinationResourceId` and @@ -405,9 +406,14 @@ public function deletePolicy(string $policyId): string * operational `resourceType` of a table migration is not rewritten to * `tablesdb`. * - * When restoring a DocumentsDB or VectorsDB database to a new resource from a - * dedicated source, the restore provisions a fresh dedicated backing database - * at the source database's own specification. + * When restoring a DocumentsDB or VectorsDB database from a dedicated source, + * the restore provisions a fresh dedicated backing database at the source + * database's own specification and lands the data there. An in-place restore + * swaps the database onto that backing only once the restore has succeeded, + * and retires the backing it displaced only once that swap is confirmed, so + * the source keeps serving its own data until the restored data is in place + * and any failure leaves it untouched. A serverless source has no dedicated + * backing to clone and restores onto the archived database instead. * * * @param string $archiveId diff --git a/src/Appwrite/Services/Embeddings.php b/src/Appwrite/Services/Embeddings.php new file mode 100644 index 00000000..f1f65d2c --- /dev/null +++ b/src/Appwrite/Services/Embeddings.php @@ -0,0 +1,63 @@ +client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\EmbeddingList::from($response); + + } +} diff --git a/src/Appwrite/Services/Project.php b/src/Appwrite/Services/Project.php index 8ba6055b..e398c92e 100644 --- a/src/Appwrite/Services/Project.php +++ b/src/Appwrite/Services/Project.php @@ -176,54 +176,6 @@ public function listKeys(?array $queries = null, ?bool $total = null): \Appwrite } - /** - * Create a new API key. It's recommended to have multiple API keys with - * strict scopes for separate functions within your project. - * - * You can also create an ephemeral API key if you need a short-lived key - * instead. - * - * @param string $keyId - * @param string $name - * @param array $scopes - * @param ?string $expire - * @throws AppwriteException - * @return \Appwrite\Models\Key - */ - public function createKey(string $keyId, string $name, array $scopes, ?string $expire = null): \Appwrite\Models\Key - { - $apiPath = str_replace( - [], - [], - '/project/keys' - ); - - $apiParams = []; - $apiParams['keyId'] = $keyId; - $apiParams['name'] = $name; - $apiParams['scopes'] = $scopes; - $apiParams['expire'] = $expire; - - $apiHeaders = []; - $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); - $apiHeaders['content-type'] = 'application/json'; - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_POST, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\Key::from($response); - - } - /** * Create a new ephemeral API key. It's recommended to have multiple API keys * with strict scopes for separate functions within your project. @@ -688,10 +640,11 @@ public function listOAuth2Providers(?array $queries = null, ?bool $total = null) * @param ?string $userCodeFormat * @param ?int $deviceCodeDuration * @param ?array $defaultScopes + * @param ?array $installationScopes * @throws AppwriteException * @return \Appwrite\Models\Project */ - public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?array $scopes = null, ?array $authorizationDetailsTypes = null, ?int $accessTokenDuration = null, ?int $refreshTokenDuration = null, ?int $publicAccessTokenDuration = null, ?int $publicRefreshTokenDuration = null, ?int $installationAccessTokenDuration = null, ?bool $confidentialPkce = null, ?string $verificationUrl = null, ?int $userCodeLength = null, ?string $userCodeFormat = null, ?int $deviceCodeDuration = null, ?array $defaultScopes = null): \Appwrite\Models\Project + public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?array $scopes = null, ?array $authorizationDetailsTypes = null, ?int $accessTokenDuration = null, ?int $refreshTokenDuration = null, ?int $publicAccessTokenDuration = null, ?int $publicRefreshTokenDuration = null, ?int $installationAccessTokenDuration = null, ?bool $confidentialPkce = null, ?string $verificationUrl = null, ?int $userCodeLength = null, ?string $userCodeFormat = null, ?int $deviceCodeDuration = null, ?array $defaultScopes = null, ?array $installationScopes = null): \Appwrite\Models\Project { $apiPath = str_replace( [], @@ -731,6 +684,10 @@ public function updateOAuth2Server(bool $enabled, string $authorizationUrl, ?arr $apiParams['defaultScopes'] = $defaultScopes; } + if (!is_null($installationScopes)) { + $apiParams['installationScopes'] = $installationScopes; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; @@ -3633,6 +3590,66 @@ public function updateMembershipPrivacyPolicy(?bool $userId = null, ?bool $userE } + /** + * Updating this policy allows you to control which factors users can use to + * complete an MFA challenge. Disabled factors cannot be used to create a + * challenge and are reported as unavailable when listing factors. The custom + * factor is disabled by default; enable it to deliver challenge codes through + * your own channel. Recovery codes always remain available as a fallback. + * + * @param ?bool $totp + * @param ?bool $email + * @param ?bool $phone + * @param ?bool $custom + * @throws AppwriteException + * @return \Appwrite\Models\Project + */ + public function updateMFAFactorsPolicy(?bool $totp = null, ?bool $email = null, ?bool $phone = null, ?bool $custom = null): \Appwrite\Models\Project + { + $apiPath = str_replace( + [], + [], + '/project/policies/mfa-factors' + ); + + $apiParams = []; + + if (!is_null($totp)) { + $apiParams['totp'] = $totp; + } + + if (!is_null($email)) { + $apiParams['email'] = $email; + } + + if (!is_null($phone)) { + $apiParams['phone'] = $phone; + } + + if (!is_null($custom)) { + $apiParams['custom'] = $custom; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PATCH, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\Project::from($response); + + } + /** * Updating this policy allows you to control if new passwords are checked * against most common passwords dictionary. When enabled, and user changes @@ -3946,11 +3963,11 @@ public function updateSessionInvalidationPolicy(bool $enabled): \Appwrite\Models * Update the maximum number of sessions allowed per user. When the limit is * hit, the oldest session will be deleted to make room for new one. * - * @param ?int $total + * @param int $total * @throws AppwriteException * @return \Appwrite\Models\Project */ - public function updateSessionLimitPolicy(?int $total): \Appwrite\Models\Project + public function updateSessionLimitPolicy(int $total): \Appwrite\Models\Project { $apiPath = str_replace( [], @@ -4027,9 +4044,9 @@ public function updateUserLimitPolicy(?int $total): \Appwrite\Models\Project * * @param ProjectPolicyId $policyId * @throws AppwriteException - * @return \Appwrite\Models\PolicyPasswordDictionary|\Appwrite\Models\PolicyPasswordHistory|\Appwrite\Models\PolicyPasswordStrength|\Appwrite\Models\PolicyPasswordPersonalData|\Appwrite\Models\PolicySessionAlert|\Appwrite\Models\PolicySessionDuration|\Appwrite\Models\PolicySessionInvalidation|\Appwrite\Models\PolicySessionLimit|\Appwrite\Models\PolicyUserLimit|\Appwrite\Models\PolicyMembershipPrivacy|\Appwrite\Models\PolicyDenyAliasedEmail|\Appwrite\Models\PolicyDenyDisposableEmail|\Appwrite\Models\PolicyDenyFreeEmail|\Appwrite\Models\PolicyDenyCorporateEmail + * @return \Appwrite\Models\PolicyPasswordDictionary|\Appwrite\Models\PolicyPasswordHistory|\Appwrite\Models\PolicyPasswordStrength|\Appwrite\Models\PolicyPasswordPersonalData|\Appwrite\Models\PolicySessionAlert|\Appwrite\Models\PolicySessionDuration|\Appwrite\Models\PolicySessionInvalidation|\Appwrite\Models\PolicySessionLimit|\Appwrite\Models\PolicyUserLimit|\Appwrite\Models\PolicyMembershipPrivacy|\Appwrite\Models\PolicyMfaFactors|\Appwrite\Models\PolicyDenyAliasedEmail|\Appwrite\Models\PolicyDenyDisposableEmail|\Appwrite\Models\PolicyDenyFreeEmail|\Appwrite\Models\PolicyDenyCorporateEmail */ - public function getPolicy(ProjectPolicyId $policyId): \Appwrite\Models\PolicyPasswordDictionary|\Appwrite\Models\PolicyPasswordHistory|\Appwrite\Models\PolicyPasswordStrength|\Appwrite\Models\PolicyPasswordPersonalData|\Appwrite\Models\PolicySessionAlert|\Appwrite\Models\PolicySessionDuration|\Appwrite\Models\PolicySessionInvalidation|\Appwrite\Models\PolicySessionLimit|\Appwrite\Models\PolicyUserLimit|\Appwrite\Models\PolicyMembershipPrivacy|\Appwrite\Models\PolicyDenyAliasedEmail|\Appwrite\Models\PolicyDenyDisposableEmail|\Appwrite\Models\PolicyDenyFreeEmail|\Appwrite\Models\PolicyDenyCorporateEmail + public function getPolicy(ProjectPolicyId $policyId): \Appwrite\Models\PolicyPasswordDictionary|\Appwrite\Models\PolicyPasswordHistory|\Appwrite\Models\PolicyPasswordStrength|\Appwrite\Models\PolicyPasswordPersonalData|\Appwrite\Models\PolicySessionAlert|\Appwrite\Models\PolicySessionDuration|\Appwrite\Models\PolicySessionInvalidation|\Appwrite\Models\PolicySessionLimit|\Appwrite\Models\PolicyUserLimit|\Appwrite\Models\PolicyMembershipPrivacy|\Appwrite\Models\PolicyMfaFactors|\Appwrite\Models\PolicyDenyAliasedEmail|\Appwrite\Models\PolicyDenyDisposableEmail|\Appwrite\Models\PolicyDenyFreeEmail|\Appwrite\Models\PolicyDenyCorporateEmail { $apiPath = str_replace( ['{policyId}'], @@ -4095,6 +4112,10 @@ public function getPolicy(ProjectPolicyId $policyId): \Appwrite\Models\PolicyPas return \Appwrite\Models\PolicyMembershipPrivacy::from($response); } + if (($response['$id'] ?? null) === 'mfa-factors') { + return \Appwrite\Models\PolicyMfaFactors::from($response); + } + if (($response['$id'] ?? null) === 'deny-aliased-email') { return \Appwrite\Models\PolicyDenyAliasedEmail::from($response); } diff --git a/src/Appwrite/Services/Proxy.php b/src/Appwrite/Services/Proxy.php index 074f7fa9..691efb29 100644 --- a/src/Appwrite/Services/Proxy.php +++ b/src/Appwrite/Services/Proxy.php @@ -6,6 +6,7 @@ use Appwrite\Client; use Appwrite\Service; use Appwrite\InputFile; +use Appwrite\Enums\InvalidationType; use Appwrite\Enums\StatusCode; use Appwrite\Enums\ProxyResourceType; @@ -16,6 +17,55 @@ public function __construct(Client $client) parent::__construct($client); } + /** + * Create a new CDN cache invalidation for a domain. Executes a hard purge of + * cached content. + * + * Depending on type, the invalidation purges a single cache tag, a single URL + * path, or all cached content for the domain. + * + * @param string $domain + * @param InvalidationType $type + * @param ?string $reference + * @throws AppwriteException + * @return \Appwrite\Models\ProxyInvalidation + */ + public function createInvalidation(string $domain, InvalidationType $type, ?string $reference = null): \Appwrite\Models\ProxyInvalidation + { + $apiPath = str_replace( + [], + [], + '/proxy/invalidations' + ); + + $apiParams = []; + $apiParams['domain'] = $domain; + $apiParams['type'] = $type; + + if (!is_null($reference)) { + $apiParams['reference'] = $reference; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\ProxyInvalidation::from($response); + + } + /** * Get a list of all the proxy rules. You can use the query params to filter * your results. diff --git a/src/Appwrite/Services/Storage.php b/src/Appwrite/Services/Storage.php index b71fff62..1c273971 100644 --- a/src/Appwrite/Services/Storage.php +++ b/src/Appwrite/Services/Storage.php @@ -380,10 +380,11 @@ public function listFiles(string $bucketId, ?array $queries = null, ?string $sea * @param string $fileId * @param InputFile $file * @param ?array $permissions + * @param ?string $folder * @throws AppwriteException * @return \Appwrite\Models\File */ - public function createFile(string $bucketId, string $fileId, InputFile $file, ?array $permissions = null, ?callable $onProgress = null): \Appwrite\Models\File + public function createFile(string $bucketId, string $fileId, InputFile $file, ?array $permissions = null, ?string $folder = null, ?callable $onProgress = null): \Appwrite\Models\File { $apiPath = str_replace( ['{bucketId}'], @@ -400,6 +401,10 @@ public function createFile(string $bucketId, string $fileId, InputFile $file, ?a $apiParams['permissions'] = $permissions; } + if (!is_null($folder)) { + $apiParams['folder'] = $folder; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'multipart/form-data'; diff --git a/src/Appwrite/Services/TablesDB.php b/src/Appwrite/Services/TablesDB.php index f2c996ff..c8a8d30e 100644 --- a/src/Appwrite/Services/TablesDB.php +++ b/src/Appwrite/Services/TablesDB.php @@ -78,10 +78,11 @@ public function list(?array $queries = null, ?string $search = null, ?bool $tota * @param ?bool $enabled * @param ?string $specification * @param ?int $replicas + * @param ?string $syncMode * @throws AppwriteException * @return \Appwrite\Models\Database */ - public function create(string $databaseId, string $name, ?bool $enabled = null, ?string $specification = null, ?int $replicas = null): \Appwrite\Models\Database + public function create(string $databaseId, string $name, ?bool $enabled = null, ?string $specification = null, ?int $replicas = null, ?string $syncMode = null): \Appwrite\Models\Database { $apiPath = str_replace( [], @@ -104,6 +105,7 @@ public function create(string $databaseId, string $name, ?bool $enabled = null, if (!is_null($replicas)) { $apiParams['replicas'] = $replicas; } + $apiParams['syncMode'] = $syncMode; $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); @@ -448,11 +450,13 @@ public function get(string $databaseId): \Appwrite\Models\Database * @param string $databaseId * @param ?string $name * @param ?bool $enabled + * @param ?string $specification * @param ?int $replicas + * @param ?string $syncMode * @throws AppwriteException * @return \Appwrite\Models\Database */ - public function update(string $databaseId, ?string $name = null, ?bool $enabled = null, ?int $replicas = null): \Appwrite\Models\Database + public function update(string $databaseId, ?string $name = null, ?bool $enabled = null, ?string $specification = null, ?int $replicas = null, ?string $syncMode = null): \Appwrite\Models\Database { $apiPath = str_replace( ['{databaseId}'], @@ -470,7 +474,9 @@ public function update(string $databaseId, ?string $name = null, ?bool $enabled if (!is_null($enabled)) { $apiParams['enabled'] = $enabled; } + $apiParams['specification'] = $specification; $apiParams['replicas'] = $replicas; + $apiParams['syncMode'] = $syncMode; $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); @@ -529,7 +535,9 @@ public function delete(string $databaseId): string /** * Trigger a manual failover for a dedicated database with high availability * enabled. Promotes a replica to primary. The failover runs asynchronously; - * poll the database document for status updates. + * poll the database document for status updates. A database left + * mid-operation by a failover that did not finish also accepts this call as a + * repair, provided `targetReplicaId` names the member to promote. * * @param string $databaseId * @param ?string $targetReplicaId @@ -568,6 +576,267 @@ public function createFailover(string $databaseId, ?string $targetReplicaId = nu } + /** + * List the dedicated migrations for a TablesDB database. A database has at + * most one in-flight migration. + * + * @param string $databaseId + * @throws AppwriteException + * @return \Appwrite\Models\DatabaseMigrationList + */ + public function listMigrations(string $databaseId): \Appwrite\Models\DatabaseMigrationList + { + $apiPath = str_replace( + ['{databaseId}'], + [$databaseId], + '/tablesdb/{databaseId}/migrations' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DatabaseMigrationList::from($response); + + } + + /** + * Start migrating a serverless TablesDB database onto a dedicated MySQL + * compute. Data is copied to the target while the source stays live, with a + * brief read-only window during cutover. + * + * @param string $databaseId + * @param string $specification + * @param ?bool $autoCutover + * @throws AppwriteException + * @return \Appwrite\Models\DatabaseMigration + */ + public function createMigration(string $databaseId, string $specification, ?bool $autoCutover = null): \Appwrite\Models\DatabaseMigration + { + $apiPath = str_replace( + ['{databaseId}'], + [$databaseId], + '/tablesdb/{databaseId}/migrations' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + $apiParams['specification'] = $specification; + + if (!is_null($autoCutover)) { + $apiParams['autoCutover'] = $autoCutover; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DatabaseMigration::from($response); + + } + + /** + * Get a single dedicated migration for a TablesDB database by its ID. + * + * @param string $databaseId + * @param string $migrationId + * @throws AppwriteException + * @return \Appwrite\Models\DatabaseMigration + */ + public function getMigration(string $databaseId, string $migrationId): \Appwrite\Models\DatabaseMigration + { + $apiPath = str_replace( + ['{databaseId}', '{migrationId}'], + [$databaseId, $migrationId], + '/tablesdb/{databaseId}/migrations/{migrationId}' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + $apiParams['migrationId'] = $migrationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DatabaseMigration::from($response); + + } + + /** + * Abort an in-flight TablesDB dedicated migration. Only allowed before + * cutover; once the migration has cut over it cannot be aborted. + * + * @param string $databaseId + * @param string $migrationId + * @throws AppwriteException + * @return string + */ + public function deleteMigration(string $databaseId, string $migrationId): string + { + $apiPath = str_replace( + ['{databaseId}', '{migrationId}'], + [$databaseId, $migrationId], + '/tablesdb/{databaseId}/migrations/{migrationId}' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + $apiParams['migrationId'] = $migrationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_DELETE, + $apiPath, + $apiHeaders, + $apiParams + ); + + return $response; + + } + + /** + * Cut a verified TablesDB migration over to its dedicated compute. Only + * applies to a migration created with `autoCutover` disabled, which waits at + * `ready_to_cutover` until this is called. The routing flip happens shortly + * after this returns, with a brief read-only window. One call buys one + * attempt: a cutover that fails a check returns the migration to `verifying` + * and parks it again, so call this once more to retry. + * + * @param string $databaseId + * @param string $migrationId + * @throws AppwriteException + * @return \Appwrite\Models\DatabaseMigration + */ + public function cutoverMigration(string $databaseId, string $migrationId): \Appwrite\Models\DatabaseMigration + { + $apiPath = str_replace( + ['{databaseId}', '{migrationId}'], + [$databaseId, $migrationId], + '/tablesdb/{databaseId}/migrations/{migrationId}/cutover' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + $apiParams['migrationId'] = $migrationId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DatabaseMigration::from($response); + + } + + /** + * List the lifecycle operations recorded for a dedicated database, newest + * first. Every provision, update, restore, backup and replication action is + * recorded here with its outcome, including an attempt that was abandoned + * because another worker took over the database. + * + * @param string $databaseId + * @param ?string $status + * @param ?int $limit + * @param ?int $offset + * @throws AppwriteException + * @return \Appwrite\Models\DedicatedDatabaseOperationList + */ + public function listOperations(string $databaseId, ?string $status = null, ?int $limit = null, ?int $offset = null): \Appwrite\Models\DedicatedDatabaseOperationList + { + $apiPath = str_replace( + ['{databaseId}'], + [$databaseId], + '/tablesdb/{databaseId}/operations' + ); + + $apiParams = []; + $apiParams['databaseId'] = $databaseId; + + if (!is_null($status)) { + $apiParams['status'] = $status; + } + + if (!is_null($limit)) { + $apiParams['limit'] = $limit; + } + + if (!is_null($offset)) { + $apiParams['offset'] = $offset; + } + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\DedicatedDatabaseOperationList::from($response); + + } + /** * Get high availability status for a dedicated database. Returns replica * statuses, replication lag, and sync mode. diff --git a/src/Appwrite/Services/Users.php b/src/Appwrite/Services/Users.php index 81e7f97f..a7ee2eda 100644 --- a/src/Appwrite/Services/Users.php +++ b/src/Appwrite/Services/Users.php @@ -1004,6 +1004,46 @@ public function deleteMFAAuthenticator(string $userId, AuthenticatorType $type): } + /** + * Get a custom MFA challenge for a user, including the code to be delivered + * through your own channel. + * + * @param string $userId + * @param string $challengeId + * @throws AppwriteException + * @return \Appwrite\Models\MfaChallengeSecret + */ + public function getMFAChallenge(string $userId, string $challengeId): \Appwrite\Models\MfaChallengeSecret + { + $apiPath = str_replace( + ['{userId}', '{challengeId}'], + [$userId, $challengeId], + '/users/{userId}/mfa/challenges/{challengeId}' + ); + + $apiParams = []; + $apiParams['userId'] = $userId; + $apiParams['challengeId'] = $challengeId; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_GET, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\MfaChallengeSecret::from($response); + + } + /** * List the factors available on the account to be used as a MFA challange. * diff --git a/tests/Appwrite/Services/AccountTest.php b/tests/Appwrite/Services/AccountTest.php index eabfc829..28c9db86 100644 --- a/tests/Appwrite/Services/AccountTest.php +++ b/tests/Appwrite/Services/AccountTest.php @@ -374,24 +374,6 @@ public function testMethodDeleteIdentity(): void $this->assertSame($data, $response); } - public function testMethodCreateJWT(): void - { - $data = array( - "jwt" => "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->account->createJWT(); - - $this->assertInstanceOf(\Appwrite\Models\Jwt::class, $response); - } - public function testMethodListLogs(): void { $data = array( @@ -646,7 +628,8 @@ public function testMethodListMFAFactors(): void "totp" => true, "phone" => true, "email" => true, - "recoveryCode" => true + "recoveryCode" => true, + "custom" => true ); $this->client diff --git a/tests/Appwrite/Services/AppsTest.php b/tests/Appwrite/Services/AppsTest.php index 63767c7a..2e29a9d9 100644 --- a/tests/Appwrite/Services/AppsTest.php +++ b/tests/Appwrite/Services/AppsTest.php @@ -382,6 +382,25 @@ public function testMethodGetInstallation(): void $this->assertInstanceOf(\Appwrite\Models\AppInstallation::class, $response); } + public function testMethodDeleteInstallation(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->apps->deleteInstallation( + "", + "" + ); + + $this->assertSame($data, $response); + } + public function testMethodCreateInstallationToken(): void { $data = array( diff --git a/tests/Appwrite/Services/EmbeddingsTest.php b/tests/Appwrite/Services/EmbeddingsTest.php new file mode 100644 index 00000000..e7717667 --- /dev/null +++ b/tests/Appwrite/Services/EmbeddingsTest.php @@ -0,0 +1,50 @@ +client = Mockery::mock(Client::class); + $this->embeddings = new Embeddings($this->client); + } + + public function testMethodCreateTextEmbeddings(): void + { + $data = array( + "total" => 5, + "embeddings" => array( + array( + "model" => "nomic-embed-text", + "dimension" => 768, + "embedding" => array(), + "error" => "Error message" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->embeddings->createTextEmbeddings( + array() + ); + + $this->assertInstanceOf(\Appwrite\Models\EmbeddingList::class, $response); + } + +} diff --git a/tests/Appwrite/Services/OrganizationTest.php b/tests/Appwrite/Services/OrganizationTest.php index 40c2dd57..9d24d59c 100644 --- a/tests/Appwrite/Services/OrganizationTest.php +++ b/tests/Appwrite/Services/OrganizationTest.php @@ -29,7 +29,6 @@ public function testMethodGet(): void "name" => "VIP", "total" => 7, "prefs" => array(), - "billingBudget" => 50, "budgetAlerts" => array(), "billingPlan" => "tier-1", "billingPlanId" => "tier-1", @@ -44,7 +43,6 @@ public function testMethodGet(): void "storage" => 25, "imageTransformations" => 100, "screenshotsGenerated" => 50, - "members" => 25, "webhooks" => 25, "wafRules" => 2, "projects" => 2, @@ -68,7 +66,6 @@ public function testMethodGet(): void "topics" => 1, "authPhone" => 10, "domains" => 5, - "activityLogs" => 7, "usageLogs" => 30, "projectInactivityDays" => 7, "alertLimit" => 80, @@ -89,14 +86,6 @@ public function testMethodGet(): void "value" => 25, "invoiceDesc" => "[INVOICEDESC]" ), - "member" => array( - "name" => "[NAME]", - "unit" => "GB", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" - ), "realtime" => array( "name" => "[NAME]", "unit" => "GB", @@ -113,14 +102,6 @@ public function testMethodGet(): void "value" => 25, "invoiceDesc" => "[INVOICEDESC]" ), - "realtimeBandwidth" => array( - "name" => "[NAME]", - "unit" => "GB", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" - ), "storage" => array( "name" => "[NAME]", "unit" => "GB", @@ -152,38 +133,9 @@ public function testMethodGet(): void "price" => 5, "value" => 25, "invoiceDesc" => "[INVOICEDESC]" - ), - "credits" => array( - "name" => "[NAME]", - "unit" => "GB", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" - ) - ), - "addons" => array( - "seats" => array( - "supported" => true, - "planIncluded" => 1, - "limit" => 5, - "type" => "numeric", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" - ), - "projects" => array( - "supported" => true, - "planIncluded" => 1, - "limit" => 5, - "type" => "numeric", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" ) ), + "addons" => array(), "budgetCapEnabled" => true, "customSmtp" => true, "emailBranding" => true, @@ -201,14 +153,12 @@ public function testMethodGet(): void "supportsFreeEmailValidation" => true, "supportsCorporateEmailValidation" => true, "supportsProjectSpecificRoles" => true, - "backupsEnabled" => true, "usagePerProject" => true, "supportedAddons" => array( "baa" => true, "premiumGeoDB" => true, "premiumGeoDBOrg" => true ), - "backupPolicies" => true, "deploymentSize" => 30, "buildSize" => 2000, "databasesAllowEncrypt" => true, @@ -218,22 +168,11 @@ public function testMethodGet(): void "billingStartDate" => "2020-10-15T06:38:00.000+00:00", "billingCurrentInvoiceDate" => "2020-10-15T06:38:00.000+00:00", "billingNextInvoiceDate" => "2020-10-15T06:38:00.000+00:00", - "billingTrialStartDate" => "2020-10-15T06:38:00.000+00:00", "billingTrialDays" => 14, "billingAggregationId" => "adbc3de4rddfsd", "billingInvoiceId" => "adbc3de4rddfsd", "paymentMethodId" => "adbc3de4rddfsd", - "billingAddressId" => "adbc3de4rddfsd", - "backupPaymentMethodId" => "adbc3de4rddfsd", "status" => "active", - "remarks" => "Pending initial payment", - "agreementBAA" => "[AGREEMENTBAA]", - "programManagerName" => "[PROGRAMMANAGERNAME]", - "programManagerCalendar" => "[PROGRAMMANAGERCALENDAR]", - "programDiscordChannelName" => "[PROGRAMDISCORDCHANNELNAME]", - "programDiscordChannelUrl" => "[PROGRAMDISCORDCHANNELURL]", - "billingPlanDowngrade" => "tier-1", - "billingTaxId" => "[BILLINGTAXID]", "markedForDeletion" => true, "platform" => "imagine", "projects" => array() @@ -260,7 +199,6 @@ public function testMethodUpdate(): void "name" => "VIP", "total" => 7, "prefs" => array(), - "billingBudget" => 50, "budgetAlerts" => array(), "billingPlan" => "tier-1", "billingPlanId" => "tier-1", @@ -275,7 +213,6 @@ public function testMethodUpdate(): void "storage" => 25, "imageTransformations" => 100, "screenshotsGenerated" => 50, - "members" => 25, "webhooks" => 25, "wafRules" => 2, "projects" => 2, @@ -299,7 +236,6 @@ public function testMethodUpdate(): void "topics" => 1, "authPhone" => 10, "domains" => 5, - "activityLogs" => 7, "usageLogs" => 30, "projectInactivityDays" => 7, "alertLimit" => 80, @@ -320,14 +256,6 @@ public function testMethodUpdate(): void "value" => 25, "invoiceDesc" => "[INVOICEDESC]" ), - "member" => array( - "name" => "[NAME]", - "unit" => "GB", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" - ), "realtime" => array( "name" => "[NAME]", "unit" => "GB", @@ -344,14 +272,6 @@ public function testMethodUpdate(): void "value" => 25, "invoiceDesc" => "[INVOICEDESC]" ), - "realtimeBandwidth" => array( - "name" => "[NAME]", - "unit" => "GB", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" - ), "storage" => array( "name" => "[NAME]", "unit" => "GB", @@ -383,38 +303,9 @@ public function testMethodUpdate(): void "price" => 5, "value" => 25, "invoiceDesc" => "[INVOICEDESC]" - ), - "credits" => array( - "name" => "[NAME]", - "unit" => "GB", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" - ) - ), - "addons" => array( - "seats" => array( - "supported" => true, - "planIncluded" => 1, - "limit" => 5, - "type" => "numeric", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" - ), - "projects" => array( - "supported" => true, - "planIncluded" => 1, - "limit" => 5, - "type" => "numeric", - "currency" => "USD", - "price" => 5, - "value" => 25, - "invoiceDesc" => "[INVOICEDESC]" ) ), + "addons" => array(), "budgetCapEnabled" => true, "customSmtp" => true, "emailBranding" => true, @@ -432,14 +323,12 @@ public function testMethodUpdate(): void "supportsFreeEmailValidation" => true, "supportsCorporateEmailValidation" => true, "supportsProjectSpecificRoles" => true, - "backupsEnabled" => true, "usagePerProject" => true, "supportedAddons" => array( "baa" => true, "premiumGeoDB" => true, "premiumGeoDBOrg" => true ), - "backupPolicies" => true, "deploymentSize" => 30, "buildSize" => 2000, "databasesAllowEncrypt" => true, @@ -449,22 +338,11 @@ public function testMethodUpdate(): void "billingStartDate" => "2020-10-15T06:38:00.000+00:00", "billingCurrentInvoiceDate" => "2020-10-15T06:38:00.000+00:00", "billingNextInvoiceDate" => "2020-10-15T06:38:00.000+00:00", - "billingTrialStartDate" => "2020-10-15T06:38:00.000+00:00", "billingTrialDays" => 14, "billingAggregationId" => "adbc3de4rddfsd", "billingInvoiceId" => "adbc3de4rddfsd", "paymentMethodId" => "adbc3de4rddfsd", - "billingAddressId" => "adbc3de4rddfsd", - "backupPaymentMethodId" => "adbc3de4rddfsd", "status" => "active", - "remarks" => "Pending initial payment", - "agreementBAA" => "[AGREEMENTBAA]", - "programManagerName" => "[PROGRAMMANAGERNAME]", - "programManagerCalendar" => "[PROGRAMMANAGERCALENDAR]", - "programDiscordChannelName" => "[PROGRAMDISCORDCHANNELNAME]", - "programDiscordChannelUrl" => "[PROGRAMDISCORDCHANNELURL]", - "billingPlanDowngrade" => "tier-1", - "billingTaxId" => "[BILLINGTAXID]", "markedForDeletion" => true, "platform" => "imagine", "projects" => array() diff --git a/tests/Appwrite/Services/ProjectTest.php b/tests/Appwrite/Services/ProjectTest.php index 0213e34c..deb9bf61 100644 --- a/tests/Appwrite/Services/ProjectTest.php +++ b/tests/Appwrite/Services/ProjectTest.php @@ -245,36 +245,6 @@ public function testMethodListKeys(): void $this->assertInstanceOf(\Appwrite\Models\KeyList::class, $response); } - public function testMethodCreateKey(): void - { - $data = array( - "\$id" => "5e5ea5c16897e", - "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "name" => "My API Key", - "expire" => "2020-10-15T06:38:00.000+00:00", - "scopes" => array(), - "secret" => "919c2d18fb5d4...a2ae413da83346ad2", - "accessedAt" => "2020-10-15T06:38:00.000+00:00", - "sdks" => array() - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->project->createKey( - "", - "", - array(ProjectKeyScopes::PROJECTREAD()) - ); - - $this->assertInstanceOf(\Appwrite\Models\Key::class, $response); - } - public function testMethodCreateEphemeralKey(): void { $data = array( @@ -2413,6 +2383,89 @@ public function testMethodUpdateMembershipPrivacyPolicy(): void $this->assertInstanceOf(\Appwrite\Models\Project::class, $response); } + public function testMethodUpdateMFAFactorsPolicy(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "New Project", + "teamId" => "1592981250", + "region" => "fra", + "devKeys" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "name" => "Dev API Key", + "expire" => "2020-10-15T06:38:00.000+00:00", + "secret" => "919c2d18fb5d4...a2ae413da83346ad2", + "accessedAt" => "2020-10-15T06:38:00.000+00:00", + "sdks" => array() + ) + ), + "smtpEnabled" => true, + "smtpSenderName" => "John Appwrite", + "smtpSenderEmail" => "john@appwrite.io", + "smtpReplyToName" => "Support Team", + "smtpReplyToEmail" => "support@appwrite.io", + "smtpHost" => "mail.appwrite.io", + "smtpPort" => 25, + "smtpUsername" => "emailuser", + "smtpPassword" => "smtp-password", + "smtpSecure" => "tls", + "pingCount" => 1, + "pingedAt" => "2020-10-15T06:38:00.000+00:00", + "labels" => array(), + "status" => "active", + "onboarding" => array(), + "authMethods" => array( + array( + "\$id" => "email-password", + "enabled" => true + ) + ), + "services" => array( + array( + "\$id" => "account", + "enabled" => true + ) + ), + "protocols" => array( + array( + "\$id" => "rest", + "enabled" => true + ) + ), + "blocks" => array( + array( + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "resourceType" => "project", + "resourceId" => "5e5ea5c16897e", + "mode" => "readOnly", + "projectName" => "My Project", + "region" => "fra", + "organizationName" => "Acme Inc.", + "organizationId" => "5e5ea5c16897e", + "billingPlan" => "pro" + ) + ), + "consoleAccessedAt" => "2020-10-15T06:38:00.000+00:00", + "wafEnabled" => true + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->project->updateMFAFactorsPolicy(); + + $this->assertInstanceOf(\Appwrite\Models\Project::class, $response); + } + public function testMethodUpdatePasswordDictionaryPolicy(): void { $data = array( diff --git a/tests/Appwrite/Services/ProxyTest.php b/tests/Appwrite/Services/ProxyTest.php index a7c27ae8..d4b3eab1 100644 --- a/tests/Appwrite/Services/ProxyTest.php +++ b/tests/Appwrite/Services/ProxyTest.php @@ -6,6 +6,7 @@ use Appwrite\InputFile; use Mockery; use PHPUnit\Framework\TestCase; +use Appwrite\Enums\InvalidationType; use Appwrite\Enums\StatusCode; use Appwrite\Enums\ProxyResourceType; @@ -20,6 +21,30 @@ protected function setUp(): void $this->proxy = new Proxy($this->client); } + public function testMethodCreateInvalidation(): void + { + $data = array( + "domain" => "appwrite.company.com", + "type" => "tag", + "reference" => "products", + "status" => "success" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->proxy->createInvalidation( + "", + InvalidationType::TAG() + ); + + $this->assertInstanceOf(\Appwrite\Models\ProxyInvalidation::class, $response); + } + public function testMethodListRules(): void { $data = array( diff --git a/tests/Appwrite/Services/StorageTest.php b/tests/Appwrite/Services/StorageTest.php index 95c1ea7e..3fd5a6f6 100644 --- a/tests/Appwrite/Services/StorageTest.php +++ b/tests/Appwrite/Services/StorageTest.php @@ -188,6 +188,8 @@ public function testMethodListFiles(): void "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "\$permissions" => array(), "name" => "Pink.png", + "folder" => "photos/2026/", + "key" => "photos/2026/Pink.png", "signature" => "5d529fd02b544198ae075bd57c1762bb", "mimeType" => "image/png", "sizeOriginal" => 17890, @@ -223,6 +225,8 @@ public function testMethodCreateFile(): void "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "\$permissions" => array(), "name" => "Pink.png", + "folder" => "photos/2026/", + "key" => "photos/2026/Pink.png", "signature" => "5d529fd02b544198ae075bd57c1762bb", "mimeType" => "image/png", "sizeOriginal" => 17890, @@ -258,6 +262,8 @@ public function testMethodGetFile(): void "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "\$permissions" => array(), "name" => "Pink.png", + "folder" => "photos/2026/", + "key" => "photos/2026/Pink.png", "signature" => "5d529fd02b544198ae075bd57c1762bb", "mimeType" => "image/png", "sizeOriginal" => 17890, @@ -292,6 +298,8 @@ public function testMethodUpdateFile(): void "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", "\$permissions" => array(), "name" => "Pink.png", + "folder" => "photos/2026/", + "key" => "photos/2026/Pink.png", "signature" => "5d529fd02b544198ae075bd57c1762bb", "mimeType" => "image/png", "sizeOriginal" => 17890, diff --git a/tests/Appwrite/Services/TablesDBTest.php b/tests/Appwrite/Services/TablesDBTest.php index 1c75086f..31b4e262 100644 --- a/tests/Appwrite/Services/TablesDBTest.php +++ b/tests/Appwrite/Services/TablesDBTest.php @@ -97,7 +97,6 @@ public function testMethodListSpecifications(): void "storageOverageRate" => 0.125, "bandwidthOverageRate" => 0.08, "replicaRate" => 1, - "crossRegionReplicaRate" => 1, "pitrRate" => 0.2 ) ); @@ -357,7 +356,6 @@ public function testMethodCreateFailover(): void "nodePool" => "db-pool-4vcpu-8gb", "replicas" => 2, "syncMode" => "async", - "crossRegionReplicas" => 1, "networkMaxConnections" => 500, "networkIdleTimeoutSeconds" => 900, "networkIPAllowlist" => array(), @@ -392,17 +390,218 @@ public function testMethodCreateFailover(): void $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabase::class, $response); } + public function testMethodListMigrations(): void + { + $data = array( + "total" => 5, + "migrations" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "projectId" => "5e5ea5c16897e", + "databaseId" => "5e5ea5c16897e", + "specification" => "s-2vcpu-4gb", + "phase" => "pending", + "attempt" => 0, + "lastError" => "[LASTERROR]", + "lagDocuments" => 0, + "verifiedAt" => "2020-10-15T06:38:00.000+00:00", + "cutoverAt" => "2020-10-15T06:38:00.000+00:00", + "soakUntil" => "2020-10-15T06:38:00.000+00:00", + "autoCutover" => true, + "cutoverRequested" => true, + "paused" => true + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->listMigrations( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\DatabaseMigrationList::class, $response); + } + + public function testMethodCreateMigration(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "projectId" => "5e5ea5c16897e", + "databaseId" => "5e5ea5c16897e", + "specification" => "s-2vcpu-4gb", + "phase" => "pending", + "attempt" => 0, + "lastError" => "[LASTERROR]", + "lagDocuments" => 0, + "verifiedAt" => "2020-10-15T06:38:00.000+00:00", + "cutoverAt" => "2020-10-15T06:38:00.000+00:00", + "soakUntil" => "2020-10-15T06:38:00.000+00:00", + "autoCutover" => true, + "cutoverRequested" => true, + "paused" => true + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->createMigration( + "", + "s-1vcpu-1gb" + ); + + $this->assertInstanceOf(\Appwrite\Models\DatabaseMigration::class, $response); + } + + public function testMethodGetMigration(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "projectId" => "5e5ea5c16897e", + "databaseId" => "5e5ea5c16897e", + "specification" => "s-2vcpu-4gb", + "phase" => "pending", + "attempt" => 0, + "lastError" => "[LASTERROR]", + "lagDocuments" => 0, + "verifiedAt" => "2020-10-15T06:38:00.000+00:00", + "cutoverAt" => "2020-10-15T06:38:00.000+00:00", + "soakUntil" => "2020-10-15T06:38:00.000+00:00", + "autoCutover" => true, + "cutoverRequested" => true, + "paused" => true + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->getMigration( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\DatabaseMigration::class, $response); + } + + public function testMethodDeleteMigration(): void + { + $data = ''; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->deleteMigration( + "", + "" + ); + + $this->assertSame($data, $response); + } + + public function testMethodCutoverMigration(): void + { + $data = array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", + "projectId" => "5e5ea5c16897e", + "databaseId" => "5e5ea5c16897e", + "specification" => "s-2vcpu-4gb", + "phase" => "pending", + "attempt" => 0, + "lastError" => "[LASTERROR]", + "lagDocuments" => 0, + "verifiedAt" => "2020-10-15T06:38:00.000+00:00", + "cutoverAt" => "2020-10-15T06:38:00.000+00:00", + "soakUntil" => "2020-10-15T06:38:00.000+00:00", + "autoCutover" => true, + "cutoverRequested" => true, + "paused" => true + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->cutoverMigration( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\DatabaseMigration::class, $response); + } + + public function testMethodListOperations(): void + { + $data = array( + "total" => 5, + "operations" => array( + array( + "\$id" => "5e5ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "databaseId" => "5e5ea5c16897e", + "type" => "update", + "status" => "completed", + "attempts" => 1, + "errorCode" => "Interrupted", + "errorMessage" => "[ERRORMESSAGE]" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->tablesDB->listOperations( + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabaseOperationList::class, $response); + } + public function testMethodGetReplicas(): void { $data = array( "replicas" => 2, "syncMode" => "async", + "syncDegraded" => true, + "syncAcknowledgements" => 1, + "syncStandbyCount" => 2, "members" => array( array( "\$id" => "1", "role" => "replica", - "status" => "active", - "lagSeconds" => 0.5 + "status" => "active" ) ) ); @@ -433,6 +632,10 @@ public function testMethodGetStatus(): void "current" => 12, "max" => 100 ), + "syncMode" => "async", + "syncDegraded" => true, + "syncAcknowledgements" => 1, + "syncStandbyCount" => 2, "replicas" => array( array( "index" => 0, diff --git a/tests/Appwrite/Services/UsersTest.php b/tests/Appwrite/Services/UsersTest.php index 9f9b0171..6206a767 100644 --- a/tests/Appwrite/Services/UsersTest.php +++ b/tests/Appwrite/Services/UsersTest.php @@ -886,13 +886,39 @@ public function testMethodDeleteMFAAuthenticator(): void $this->assertSame($data, $response); } + public function testMethodGetMFAChallenge(): void + { + $data = array( + "\$id" => "bb8ea5c16897e", + "\$createdAt" => "2020-10-15T06:38:00.000+00:00", + "userId" => "5e5ea5c168bb8", + "expire" => "2020-10-15T06:38:00.000+00:00", + "code" => "446372" + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->users->getMFAChallenge( + "", + "" + ); + + $this->assertInstanceOf(\Appwrite\Models\MfaChallengeSecret::class, $response); + } + public function testMethodListMFAFactors(): void { $data = array( "totp" => true, "phone" => true, "email" => true, - "recoveryCode" => true + "recoveryCode" => true, + "custom" => true ); $this->client From a2e76234e9151b0e7df64e81d4e179a1c7618e2d Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Fri, 14 Aug 2026 13:50:23 +0530 Subject: [PATCH 5/6] chore: update PHP SDK to 28.0.0 --- CHANGELOG.md | 1 - docs/embeddings.md | 17 ----- .../embeddings/create-text-embeddings.md | 18 ----- src/Appwrite/Enums/EmbeddingModel.php | 70 ------------------- src/Appwrite/Models/Embedding.php | 68 ------------------ src/Appwrite/Models/EmbeddingList.php | 59 ---------------- src/Appwrite/Services/Embeddings.php | 63 ----------------- tests/Appwrite/Services/EmbeddingsTest.php | 50 ------------- 8 files changed, 346 deletions(-) delete mode 100644 docs/embeddings.md delete mode 100644 docs/examples/embeddings/create-text-embeddings.md delete mode 100644 src/Appwrite/Enums/EmbeddingModel.php delete mode 100644 src/Appwrite/Models/Embedding.php delete mode 100644 src/Appwrite/Models/EmbeddingList.php delete mode 100644 src/Appwrite/Services/Embeddings.php delete mode 100644 tests/Appwrite/Services/EmbeddingsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e9345fa..af282346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,6 @@ * Breaking: removed `account.createJWT`; use `users.createJWT` instead. A leaked JWT could mint further JWTs, letting a credential outlive its own expiry — a session cannot duplicate itself to live forever either * Breaking: removed `project.createKey`. A leaked key could mint further hidden keys, making a compromise far harder to contain and revoke * Breaking: `activities.listEvents` `queries` now takes an array instead of a string -* Added: `embeddings` service with `createTextEmbeddings`, plus the `EmbeddingModel` enum * Added: TablesDB migration methods `listMigrations`, `createMigration`, `getMigration`, `deleteMigration`, `cutoverMigration`, and `listOperations` * Added: `proxy.createInvalidation` for purging cached edge responses, plus the `InvalidationType` enum * Added: `apps.deleteInstallation` diff --git a/docs/embeddings.md b/docs/embeddings.md deleted file mode 100644 index 50d53b9b..00000000 --- a/docs/embeddings.md +++ /dev/null @@ -1,17 +0,0 @@ -# Embeddings Service - - -```http request -POST https://cloud.appwrite.io/v1/embeddings/text -``` - -** Generate vector embeddings for an array of text using the selected embedding model. Use the returned vectors to power semantic search and similarity queries against your vector collections. - ** - -### Parameters - -| Field Name | Type | Description | Default | -| --- | --- | --- | --- | -| texts | array | Array of text to generate embeddings. | | -| model | string | The embedding model to use for generating vector embeddings. | nomic-embed-text | - diff --git a/docs/examples/embeddings/create-text-embeddings.md b/docs/examples/embeddings/create-text-embeddings.md deleted file mode 100644 index 15f92318..00000000 --- a/docs/examples/embeddings/create-text-embeddings.md +++ /dev/null @@ -1,18 +0,0 @@ -```php -setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setProject('') // Your project ID - ->setKey(''); // Your secret API key - -$embeddings = new Embeddings($client); - -$result = $embeddings->createTextEmbeddings( - texts: [], - model: EmbeddingModel::NOMICEMBEDTEXT() // optional -);``` diff --git a/src/Appwrite/Enums/EmbeddingModel.php b/src/Appwrite/Enums/EmbeddingModel.php deleted file mode 100644 index ec104ce9..00000000 --- a/src/Appwrite/Enums/EmbeddingModel.php +++ /dev/null @@ -1,70 +0,0 @@ -value = $value; - } - - public function __toString(): string - { - return $this->value; - } - - public function jsonSerialize(): string - { - return $this->value; - } - - public static function NOMICEMBEDTEXT(): EmbeddingModel - { - if (!isset(self::$NOMICEMBEDTEXT)) { - self::$NOMICEMBEDTEXT = new EmbeddingModel('nomic-embed-text'); - } - return self::$NOMICEMBEDTEXT; - } - public static function EMBEDDINGGEMMA(): EmbeddingModel - { - if (!isset(self::$EMBEDDINGGEMMA)) { - self::$EMBEDDINGGEMMA = new EmbeddingModel('embedding-gemma'); - } - return self::$EMBEDDINGGEMMA; - } - public static function ALLMINILM(): EmbeddingModel - { - if (!isset(self::$ALLMINILM)) { - self::$ALLMINILM = new EmbeddingModel('all-minilm'); - } - return self::$ALLMINILM; - } - public static function BGESMALL(): EmbeddingModel - { - if (!isset(self::$BGESMALL)) { - self::$BGESMALL = new EmbeddingModel('bge-small'); - } - return self::$BGESMALL; - } - - public static function from(string $value): self - { - return match ($value) { - 'nomic-embed-text' => self::NOMICEMBEDTEXT(), - 'embedding-gemma' => self::EMBEDDINGGEMMA(), - 'all-minilm' => self::ALLMINILM(), - 'bge-small' => self::BGESMALL(), - default => throw new \InvalidArgumentException('Unknown EmbeddingModel value: ' . $value), - }; - } -} diff --git a/src/Appwrite/Models/Embedding.php b/src/Appwrite/Models/Embedding.php deleted file mode 100644 index c38c4787..00000000 --- a/src/Appwrite/Models/Embedding.php +++ /dev/null @@ -1,68 +0,0 @@ - $data - */ - public static function from(array $data): static - { - if (!array_key_exists('model', $data)) { - throw new \InvalidArgumentException('Missing required field "model" for ' . static::class . '.'); - } - if (!array_key_exists('dimension', $data)) { - throw new \InvalidArgumentException('Missing required field "dimension" for ' . static::class . '.'); - } - if (!array_key_exists('embedding', $data)) { - throw new \InvalidArgumentException('Missing required field "embedding" for ' . static::class . '.'); - } - if (!array_key_exists('error', $data)) { - throw new \InvalidArgumentException('Missing required field "error" for ' . static::class . '.'); - } - - return new static( - model: $data['model'], - dimension: $data['dimension'], - embedding: $data['embedding'], - error: $data['error'] - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'model' => static::serializeValue($this->model), - 'dimension' => static::serializeValue($this->dimension), - 'embedding' => static::serializeValue($this->embedding), - 'error' => static::serializeValue($this->error) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Models/EmbeddingList.php b/src/Appwrite/Models/EmbeddingList.php deleted file mode 100644 index d666e5d5..00000000 --- a/src/Appwrite/Models/EmbeddingList.php +++ /dev/null @@ -1,59 +0,0 @@ - $embeddings list of embeddings. - */ - public function __construct( - public int $total, - public array $embeddings - ) { - } - - /** - * @param array $data - */ - public static function from(array $data): static - { - if (!array_key_exists('total', $data)) { - throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); - } - if (!array_key_exists('embeddings', $data)) { - throw new \InvalidArgumentException('Missing required field "embeddings" for ' . static::class . '.'); - } - - return new static( - total: $data['total'], - embeddings: is_array($data['embeddings']) - ? array_map( - static fn (mixed $item): mixed => static::hydrateTypedValue(Embedding::class, $item), - $data['embeddings'] - ) - : $data['embeddings'] - ); - } - - /** - * @return array - */ - public function toArray(): array - { - $result = [ - 'total' => static::serializeValue($this->total), - 'embeddings' => static::serializeValue($this->embeddings) - ]; - - return $result; - } -} diff --git a/src/Appwrite/Services/Embeddings.php b/src/Appwrite/Services/Embeddings.php deleted file mode 100644 index f1f65d2c..00000000 --- a/src/Appwrite/Services/Embeddings.php +++ /dev/null @@ -1,63 +0,0 @@ -client->getConfig('project'); - $apiHeaders['content-type'] = 'application/json'; - $apiHeaders['accept'] = 'application/json'; - - $response = $this->client->call( - Client::METHOD_POST, - $apiPath, - $apiHeaders, - $apiParams - ); - - if (!is_array($response)) { - throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); - } - - return \Appwrite\Models\EmbeddingList::from($response); - - } -} diff --git a/tests/Appwrite/Services/EmbeddingsTest.php b/tests/Appwrite/Services/EmbeddingsTest.php deleted file mode 100644 index e7717667..00000000 --- a/tests/Appwrite/Services/EmbeddingsTest.php +++ /dev/null @@ -1,50 +0,0 @@ -client = Mockery::mock(Client::class); - $this->embeddings = new Embeddings($this->client); - } - - public function testMethodCreateTextEmbeddings(): void - { - $data = array( - "total" => 5, - "embeddings" => array( - array( - "model" => "nomic-embed-text", - "dimension" => 768, - "embedding" => array(), - "error" => "Error message" - ) - ) - ); - - $this->client - ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) - ->andReturn($data); - $this->client - ->allows()->getConfig(Mockery::any()) - ->andReturn(''); - - $response = $this->embeddings->createTextEmbeddings( - array() - ); - - $this->assertInstanceOf(\Appwrite\Models\EmbeddingList::class, $response); - } - -} From f7adeea9252b21ca68106e5286e049ec193ad50a Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Fri, 14 Aug 2026 14:00:08 +0530 Subject: [PATCH 6/6] chore: update PHP SDK to 28.0.0 --- CHANGELOG.md | 1 + docs/embeddings.md | 17 +++++ .../embeddings/create-text-embeddings.md | 18 +++++ src/Appwrite/Enums/EmbeddingModel.php | 70 +++++++++++++++++++ src/Appwrite/Models/Embedding.php | 68 ++++++++++++++++++ src/Appwrite/Models/EmbeddingList.php | 59 ++++++++++++++++ src/Appwrite/Services/Embeddings.php | 63 +++++++++++++++++ tests/Appwrite/Services/EmbeddingsTest.php | 50 +++++++++++++ 8 files changed, 346 insertions(+) create mode 100644 docs/embeddings.md create mode 100644 docs/examples/embeddings/create-text-embeddings.md create mode 100644 src/Appwrite/Enums/EmbeddingModel.php create mode 100644 src/Appwrite/Models/Embedding.php create mode 100644 src/Appwrite/Models/EmbeddingList.php create mode 100644 src/Appwrite/Services/Embeddings.php create mode 100644 tests/Appwrite/Services/EmbeddingsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index af282346..6e9345fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Breaking: removed `account.createJWT`; use `users.createJWT` instead. A leaked JWT could mint further JWTs, letting a credential outlive its own expiry — a session cannot duplicate itself to live forever either * Breaking: removed `project.createKey`. A leaked key could mint further hidden keys, making a compromise far harder to contain and revoke * Breaking: `activities.listEvents` `queries` now takes an array instead of a string +* Added: `embeddings` service with `createTextEmbeddings`, plus the `EmbeddingModel` enum * Added: TablesDB migration methods `listMigrations`, `createMigration`, `getMigration`, `deleteMigration`, `cutoverMigration`, and `listOperations` * Added: `proxy.createInvalidation` for purging cached edge responses, plus the `InvalidationType` enum * Added: `apps.deleteInstallation` diff --git a/docs/embeddings.md b/docs/embeddings.md new file mode 100644 index 00000000..50d53b9b --- /dev/null +++ b/docs/embeddings.md @@ -0,0 +1,17 @@ +# Embeddings Service + + +```http request +POST https://cloud.appwrite.io/v1/embeddings/text +``` + +** Generate vector embeddings for an array of text using the selected embedding model. Use the returned vectors to power semantic search and similarity queries against your vector collections. + ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| texts | array | Array of text to generate embeddings. | | +| model | string | The embedding model to use for generating vector embeddings. | nomic-embed-text | + diff --git a/docs/examples/embeddings/create-text-embeddings.md b/docs/examples/embeddings/create-text-embeddings.md new file mode 100644 index 00000000..15f92318 --- /dev/null +++ b/docs/examples/embeddings/create-text-embeddings.md @@ -0,0 +1,18 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$embeddings = new Embeddings($client); + +$result = $embeddings->createTextEmbeddings( + texts: [], + model: EmbeddingModel::NOMICEMBEDTEXT() // optional +);``` diff --git a/src/Appwrite/Enums/EmbeddingModel.php b/src/Appwrite/Enums/EmbeddingModel.php new file mode 100644 index 00000000..ec104ce9 --- /dev/null +++ b/src/Appwrite/Enums/EmbeddingModel.php @@ -0,0 +1,70 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } + + public function jsonSerialize(): string + { + return $this->value; + } + + public static function NOMICEMBEDTEXT(): EmbeddingModel + { + if (!isset(self::$NOMICEMBEDTEXT)) { + self::$NOMICEMBEDTEXT = new EmbeddingModel('nomic-embed-text'); + } + return self::$NOMICEMBEDTEXT; + } + public static function EMBEDDINGGEMMA(): EmbeddingModel + { + if (!isset(self::$EMBEDDINGGEMMA)) { + self::$EMBEDDINGGEMMA = new EmbeddingModel('embedding-gemma'); + } + return self::$EMBEDDINGGEMMA; + } + public static function ALLMINILM(): EmbeddingModel + { + if (!isset(self::$ALLMINILM)) { + self::$ALLMINILM = new EmbeddingModel('all-minilm'); + } + return self::$ALLMINILM; + } + public static function BGESMALL(): EmbeddingModel + { + if (!isset(self::$BGESMALL)) { + self::$BGESMALL = new EmbeddingModel('bge-small'); + } + return self::$BGESMALL; + } + + public static function from(string $value): self + { + return match ($value) { + 'nomic-embed-text' => self::NOMICEMBEDTEXT(), + 'embedding-gemma' => self::EMBEDDINGGEMMA(), + 'all-minilm' => self::ALLMINILM(), + 'bge-small' => self::BGESMALL(), + default => throw new \InvalidArgumentException('Unknown EmbeddingModel value: ' . $value), + }; + } +} diff --git a/src/Appwrite/Models/Embedding.php b/src/Appwrite/Models/Embedding.php new file mode 100644 index 00000000..c38c4787 --- /dev/null +++ b/src/Appwrite/Models/Embedding.php @@ -0,0 +1,68 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('model', $data)) { + throw new \InvalidArgumentException('Missing required field "model" for ' . static::class . '.'); + } + if (!array_key_exists('dimension', $data)) { + throw new \InvalidArgumentException('Missing required field "dimension" for ' . static::class . '.'); + } + if (!array_key_exists('embedding', $data)) { + throw new \InvalidArgumentException('Missing required field "embedding" for ' . static::class . '.'); + } + if (!array_key_exists('error', $data)) { + throw new \InvalidArgumentException('Missing required field "error" for ' . static::class . '.'); + } + + return new static( + model: $data['model'], + dimension: $data['dimension'], + embedding: $data['embedding'], + error: $data['error'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'model' => static::serializeValue($this->model), + 'dimension' => static::serializeValue($this->dimension), + 'embedding' => static::serializeValue($this->embedding), + 'error' => static::serializeValue($this->error) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Models/EmbeddingList.php b/src/Appwrite/Models/EmbeddingList.php new file mode 100644 index 00000000..d666e5d5 --- /dev/null +++ b/src/Appwrite/Models/EmbeddingList.php @@ -0,0 +1,59 @@ + $embeddings list of embeddings. + */ + public function __construct( + public int $total, + public array $embeddings + ) { + } + + /** + * @param array $data + */ + public static function from(array $data): static + { + if (!array_key_exists('total', $data)) { + throw new \InvalidArgumentException('Missing required field "total" for ' . static::class . '.'); + } + if (!array_key_exists('embeddings', $data)) { + throw new \InvalidArgumentException('Missing required field "embeddings" for ' . static::class . '.'); + } + + return new static( + total: $data['total'], + embeddings: is_array($data['embeddings']) + ? array_map( + static fn (mixed $item): mixed => static::hydrateTypedValue(Embedding::class, $item), + $data['embeddings'] + ) + : $data['embeddings'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + $result = [ + 'total' => static::serializeValue($this->total), + 'embeddings' => static::serializeValue($this->embeddings) + ]; + + return $result; + } +} diff --git a/src/Appwrite/Services/Embeddings.php b/src/Appwrite/Services/Embeddings.php new file mode 100644 index 00000000..f1f65d2c --- /dev/null +++ b/src/Appwrite/Services/Embeddings.php @@ -0,0 +1,63 @@ +client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_POST, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\EmbeddingList::from($response); + + } +} diff --git a/tests/Appwrite/Services/EmbeddingsTest.php b/tests/Appwrite/Services/EmbeddingsTest.php new file mode 100644 index 00000000..e7717667 --- /dev/null +++ b/tests/Appwrite/Services/EmbeddingsTest.php @@ -0,0 +1,50 @@ +client = Mockery::mock(Client::class); + $this->embeddings = new Embeddings($this->client); + } + + public function testMethodCreateTextEmbeddings(): void + { + $data = array( + "total" => 5, + "embeddings" => array( + array( + "model" => "nomic-embed-text", + "dimension" => 768, + "embedding" => array(), + "error" => "Error message" + ) + ) + ); + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->embeddings->createTextEmbeddings( + array() + ); + + $this->assertInstanceOf(\Appwrite\Models\EmbeddingList::class, $response); + } + +}