From 14eca58b684dd999650283c4aa952dfd11a3d80c Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 12 Oct 2026 16:51:48 +0100 Subject: [PATCH] chore: update Python SDK to 25.0.0 --- CHANGELOG.md | 36 + README.md | 4 +- appwrite/client.py | 43 +- appwrite/encoders/value_class_encoder.py | 84 +- appwrite/enums/billing_plan_group.py | 3 +- appwrite/enums/build_runtime.py | 2 + appwrite/enums/domain_registration_type.py | 8 + appwrite/enums/domain_transfer_status_enum.py | 12 + appwrite/enums/framework.py | 1 + appwrite/enums/id_token_provider.py | 6 + appwrite/enums/image_gravity.py | 1 + appwrite/enums/o_auth2_auth0_prompt.py | 7 + appwrite/enums/o_auth2_discord_prompt.py | 6 + appwrite/enums/o_auth2_github_prompt.py | 5 + appwrite/enums/o_auth2_kakao_prompt.py | 8 + appwrite/enums/o_auth2_microsoft_prompt.py | 8 + appwrite/enums/o_auth2_okta_prompt.py | 7 + appwrite/enums/o_auth2_salesforce_prompt.py | 6 + appwrite/enums/o_auth2_zoho_prompt.py | 5 + appwrite/enums/o_auth_provider.py | 3 + appwrite/enums/organization_key_scopes.py | 20 - appwrite/enums/project_auth_method_id.py | 1 + appwrite/enums/project_email_template_id.py | 2 + appwrite/enums/project_key_scopes.py | 4 + .../enums/project_o_auth2_auth0_prompt.py | 7 + .../enums/project_o_auth2_discord_prompt.py | 6 + .../enums/project_o_auth2_git_hub_prompt.py | 5 + .../enums/project_o_auth2_kakao_prompt.py | 8 + .../enums/project_o_auth2_microsoft_prompt.py | 8 + appwrite/enums/project_o_auth2_okta_prompt.py | 7 + .../project_o_auth2_salesforce_prompt.py | 6 + appwrite/enums/project_o_auth2_zoho_prompt.py | 5 + appwrite/enums/project_o_auth_provider_id.py | 3 + appwrite/enums/project_policy_id.py | 3 + .../proxy_rule_deployment_resource_type.py | 1 + appwrite/enums/runtime.py | 2 + appwrite/enums/waf_rule_action.py | 9 + appwrite/models/__init__.py | 74 +- appwrite/models/account.py | 135 + appwrite/models/activity_event.py | 69 +- appwrite/models/activity_event_list.py | 13 +- appwrite/models/additional_resource.py | 23 +- appwrite/models/algo_argon2.py | 19 +- appwrite/models/algo_bcrypt.py | 13 +- appwrite/models/algo_md5.py | 13 +- appwrite/models/algo_phpass.py | 13 +- appwrite/models/algo_scrypt.py | 21 +- appwrite/models/algo_scrypt_modified.py | 19 +- appwrite/models/algo_sha.py | 13 +- appwrite/models/app.py | 61 +- appwrite/models/app_installation.py | 29 +- appwrite/models/app_installation_list.py | 13 +- appwrite/models/app_key.py | 27 +- appwrite/models/app_key_list.py | 13 +- appwrite/models/app_scope.py | 21 +- appwrite/models/app_scope_list.py | 13 +- appwrite/models/app_secret.py | 27 +- appwrite/models/app_secret_list.py | 13 +- appwrite/models/app_secret_plaintext.py | 27 +- appwrite/models/apps_list.py | 13 +- appwrite/models/attribute_bigint.py | 23 +- appwrite/models/attribute_boolean.py | 23 +- appwrite/models/attribute_datetime.py | 23 +- appwrite/models/attribute_email.py | 25 +- appwrite/models/attribute_enum.py | 25 +- appwrite/models/attribute_float.py | 23 +- appwrite/models/attribute_integer.py | 23 +- appwrite/models/attribute_ip.py | 25 +- appwrite/models/attribute_line.py | 23 +- appwrite/models/attribute_list.py | 13 +- appwrite/models/attribute_longtext.py | 23 +- appwrite/models/attribute_mediumtext.py | 23 +- appwrite/models/attribute_object.py | 23 +- appwrite/models/attribute_point.py | 23 +- appwrite/models/attribute_polygon.py | 23 +- appwrite/models/attribute_relationship.py | 33 +- appwrite/models/attribute_string.py | 25 +- appwrite/models/attribute_text.py | 23 +- appwrite/models/attribute_url.py | 25 +- appwrite/models/attribute_varchar.py | 25 +- appwrite/models/attribute_vector.py | 25 +- appwrite/models/backup_archive.py | 35 +- appwrite/models/backup_archive_list.py | 13 +- appwrite/models/backup_policy.py | 27 +- appwrite/models/backup_policy_list.py | 13 +- appwrite/models/backup_restoration.py | 39 +- appwrite/models/backup_restoration_list.py | 13 +- appwrite/models/billing_plan.py | 140 +- appwrite/models/billing_plan_addon_details.py | 25 +- .../models/billing_plan_supported_addons.py | 17 +- appwrite/models/block.py | 37 +- appwrite/models/bucket.py | 39 +- appwrite/models/bucket_list.py | 13 +- appwrite/models/collection.py | 29 +- appwrite/models/collection_list.py | 13 +- appwrite/models/column_bigint.py | 23 +- appwrite/models/column_boolean.py | 23 +- appwrite/models/column_datetime.py | 23 +- appwrite/models/column_email.py | 25 +- appwrite/models/column_enum.py | 25 +- appwrite/models/column_float.py | 23 +- appwrite/models/column_index.py | 29 +- appwrite/models/column_index_list.py | 13 +- appwrite/models/column_integer.py | 23 +- appwrite/models/column_ip.py | 25 +- appwrite/models/column_line.py | 23 +- appwrite/models/column_list.py | 13 +- appwrite/models/column_longtext.py | 23 +- appwrite/models/column_mediumtext.py | 23 +- appwrite/models/column_point.py | 23 +- appwrite/models/column_polygon.py | 23 +- appwrite/models/column_relationship.py | 33 +- appwrite/models/column_string.py | 25 +- appwrite/models/column_text.py | 23 +- appwrite/models/column_url.py | 25 +- appwrite/models/column_varchar.py | 25 +- appwrite/models/continent.py | 15 +- appwrite/models/continent_list.py | 13 +- appwrite/models/country.py | 15 +- appwrite/models/country_list.py | 13 +- appwrite/models/currency.py | 25 +- appwrite/models/currency_list.py | 13 +- appwrite/models/database.py | 25 +- appwrite/models/database_list.py | 13 +- appwrite/models/database_migration.py | 45 +- appwrite/models/database_migration_list.py | 13 +- appwrite/models/database_status.py | 35 +- .../models/database_status_connections.py | 15 +- appwrite/models/database_status_replica.py | 17 +- appwrite/models/database_status_volume.py | 19 +- appwrite/models/dedicated_database.py | 130 +- appwrite/models/dedicated_database_backup.py | 35 +- .../models/dedicated_database_backup_list.py | 13 +- .../dedicated_database_backup_storage.py | 21 +- appwrite/models/dedicated_database_branch.py | 37 +- .../models/dedicated_database_branch_list.py | 13 +- .../models/dedicated_database_execution.py | 21 +- .../dedicated_database_execution_column.py | 15 +- .../models/dedicated_database_extensions.py | 15 +- appwrite/models/dedicated_database_list.py | 13 +- appwrite/models/dedicated_database_member.py | 17 +- .../models/dedicated_database_operation.py | 27 +- .../dedicated_database_operation_list.py | 13 +- .../models/dedicated_database_pitr_windows.py | 15 +- appwrite/models/dedicated_database_pooler.py | 31 +- .../models/dedicated_database_replicas.py | 21 +- .../models/dedicated_database_restoration.py | 45 +- .../dedicated_database_restoration_list.py | 13 +- .../dedicated_database_specification.py | 49 +- .../dedicated_database_specification_list.py | 17 +- ...edicated_database_specification_pricing.py | 26 - appwrite/models/deployment.py | 63 +- appwrite/models/deployment_list.py | 13 +- appwrite/models/dev_key.py | 38 - appwrite/models/dns_record.py | 83 + appwrite/models/dns_records_list.py | 32 + appwrite/models/document.py | 23 +- appwrite/models/document_list.py | 13 +- appwrite/models/domain.py | 86 + appwrite/models/domain_price.py | 59 + appwrite/models/domain_prices_list.py | 32 + appwrite/models/domain_transfer_status.py | 39 + appwrite/models/domains_list.py | 32 + appwrite/models/email_template.py | 27 +- appwrite/models/email_template_list.py | 13 +- appwrite/models/embedding.py | 19 +- appwrite/models/embedding_list.py | 13 +- appwrite/models/ephemeral_key.py | 27 +- appwrite/models/execution.py | 39 +- appwrite/models/execution_list.py | 13 +- appwrite/models/file.py | 43 +- appwrite/models/file_list.py | 13 +- appwrite/models/framework.py | 17 +- appwrite/models/framework_adapter.py | 19 +- appwrite/models/framework_list.py | 13 +- appwrite/models/function.py | 73 +- appwrite/models/function_list.py | 13 +- appwrite/models/headers.py | 15 +- appwrite/models/identity.py | 36 +- appwrite/models/identity_list.py | 13 +- appwrite/models/index.py | 27 +- appwrite/models/index_list.py | 13 +- appwrite/models/insight.py | 37 +- appwrite/models/insight_cta.py | 19 +- appwrite/models/insight_list.py | 13 +- appwrite/models/jwt.py | 13 +- appwrite/models/key.py | 27 +- appwrite/models/key_list.py | 13 +- appwrite/models/language.py | 17 +- appwrite/models/language_list.py | 13 +- appwrite/models/locale.py | 25 +- appwrite/models/locale_code.py | 15 +- appwrite/models/locale_code_list.py | 13 +- appwrite/models/log.py | 80 - appwrite/models/log_list.py | 21 - appwrite/models/membership.py | 41 +- appwrite/models/membership_list.py | 13 +- appwrite/models/message.py | 25 +- appwrite/models/message_list.py | 13 +- appwrite/models/mfa_challenge.py | 19 +- appwrite/models/mfa_challenge_secret.py | 21 +- appwrite/models/mfa_factors.py | 21 +- appwrite/models/mfa_recovery_codes.py | 13 +- appwrite/models/mfa_type.py | 15 +- appwrite/models/mock_number.py | 19 +- appwrite/models/mock_number_list.py | 13 +- appwrite/models/o_auth2_amazon.py | 19 +- appwrite/models/o_auth2_apple.py | 33 +- appwrite/models/o_auth2_appwrite.py | 19 +- appwrite/models/o_auth2_auth0.py | 27 +- appwrite/models/o_auth2_authentik.py | 21 +- appwrite/models/o_auth2_autodesk.py | 19 +- appwrite/models/o_auth2_bitbucket.py | 19 +- appwrite/models/o_auth2_bitly.py | 19 +- appwrite/models/o_auth2_box.py | 19 +- appwrite/models/o_auth2_cloudflare.py | 19 +- appwrite/models/o_auth2_dailymotion.py | 19 +- appwrite/models/o_auth2_discord.py | 25 +- appwrite/models/o_auth2_disqus.py | 19 +- appwrite/models/o_auth2_dropbox.py | 19 +- appwrite/models/o_auth2_etsy.py | 19 +- appwrite/models/o_auth2_facebook.py | 19 +- appwrite/models/o_auth2_figma.py | 19 +- appwrite/models/o_auth2_fusion_auth.py | 21 +- appwrite/models/o_auth2_github.py | 25 +- appwrite/models/o_auth2_gitlab.py | 21 +- appwrite/models/o_auth2_google.py | 31 +- appwrite/models/o_auth2_hugging_face.py | 19 +- appwrite/models/o_auth2_kakao.py | 49 + appwrite/models/o_auth2_keycloak.py | 23 +- appwrite/models/o_auth2_kick.py | 19 +- appwrite/models/o_auth2_linkedin.py | 19 +- appwrite/models/o_auth2_microsoft.py | 27 +- appwrite/models/o_auth2_notion.py | 19 +- appwrite/models/o_auth2_oidc.py | 35 +- appwrite/models/o_auth2_okta.py | 29 +- appwrite/models/o_auth2_paypal.py | 19 +- appwrite/models/o_auth2_podio.py | 19 +- appwrite/models/o_auth2_provider_list.py | 21 +- appwrite/models/o_auth2_resend.py | 19 +- appwrite/models/o_auth2_salesforce.py | 25 +- appwrite/models/o_auth2_slack.py | 19 +- appwrite/models/o_auth2_spotify.py | 19 +- appwrite/models/o_auth2_stripe.py | 19 +- appwrite/models/o_auth2_tik_tok.py | 43 + appwrite/models/o_auth2_tradeshift.py | 19 +- appwrite/models/o_auth2_twitch.py | 19 +- appwrite/models/o_auth2_webflow.py | 43 + appwrite/models/o_auth2_word_press.py | 19 +- appwrite/models/o_auth2_x.py | 19 +- appwrite/models/o_auth2_yahoo.py | 19 +- appwrite/models/o_auth2_yandex.py | 19 +- appwrite/models/o_auth2_zoho.py | 25 +- appwrite/models/o_auth2_zoom.py | 19 +- appwrite/models/oauth2_approve.py | 13 +- appwrite/models/oauth2_authorize.py | 15 +- appwrite/models/oauth2_consent.py | 31 +- appwrite/models/oauth2_consent_list.py | 13 +- appwrite/models/oauth2_consent_token.py | 33 +- appwrite/models/oauth2_consent_token_list.py | 13 +- .../models/oauth2_device_authorization.py | 23 +- appwrite/models/oauth2_grant.py | 35 +- appwrite/models/oauth2_introspection.py | 61 + appwrite/models/oauth2_organization.py | 13 +- appwrite/models/oauth2_organization_list.py | 13 +- appwrite/models/oauth2_par.py | 15 +- appwrite/models/oauth2_project.py | 17 +- appwrite/models/oauth2_project_list.py | 13 +- appwrite/models/oauth2_reject.py | 13 +- appwrite/models/oauth2_token.py | 21 +- appwrite/models/organization.py | 65 +- appwrite/models/passkey.py | 48 + appwrite/models/passkey_challenge.py | 48 + appwrite/models/passkey_list.py | 32 + appwrite/models/phone.py | 17 +- appwrite/models/phone_list.py | 13 +- appwrite/models/platform_android.py | 26 +- appwrite/models/platform_apple.py | 21 +- appwrite/models/platform_linux.py | 21 +- appwrite/models/platform_list.py | 13 +- appwrite/models/platform_web.py | 21 +- appwrite/models/platform_windows.py | 21 +- appwrite/models/policy_deny_aliased_email.py | 15 +- .../models/policy_deny_corporate_email.py | 15 +- .../models/policy_deny_disposable_email.py | 15 +- appwrite/models/policy_deny_free_email.py | 15 +- appwrite/models/policy_list.py | 21 +- appwrite/models/policy_membership_privacy.py | 25 +- appwrite/models/policy_mfa_factors.py | 21 +- appwrite/models/policy_passkey.py | 38 + appwrite/models/policy_password_dictionary.py | 15 +- appwrite/models/policy_password_history.py | 15 +- .../models/policy_password_personal_data.py | 15 +- appwrite/models/policy_password_pwned.py | 43 + appwrite/models/policy_password_rotation.py | 38 + appwrite/models/policy_password_strength.py | 23 +- appwrite/models/policy_session_alert.py | 15 +- appwrite/models/policy_session_duration.py | 15 +- .../models/policy_session_invalidation.py | 15 +- appwrite/models/policy_session_limit.py | 15 +- appwrite/models/policy_user_limit.py | 15 +- appwrite/models/postgres_extension.py | 19 +- appwrite/models/presence.py | 21 +- appwrite/models/presence_list.py | 13 +- appwrite/models/program.py | 29 +- appwrite/models/project.py | 65 +- appwrite/models/project_auth_method.py | 13 +- appwrite/models/project_list.py | 13 +- appwrite/models/project_protocol.py | 13 +- appwrite/models/project_service.py | 13 +- appwrite/models/provider.py | 27 +- appwrite/models/provider_list.py | 13 +- appwrite/models/proxy_invalidation.py | 19 +- appwrite/models/proxy_rule.py | 39 +- appwrite/models/proxy_rule_list.py | 13 +- appwrite/models/report.py | 31 +- appwrite/models/report_list.py | 13 +- appwrite/models/resource_token.py | 25 +- appwrite/models/resource_token_list.py | 13 +- appwrite/models/row.py | 23 +- appwrite/models/row_list.py | 13 +- appwrite/models/runtime.py | 25 +- appwrite/models/runtime_list.py | 13 +- appwrite/models/session.py | 69 +- appwrite/models/session_list.py | 13 +- appwrite/models/site.py | 75 +- appwrite/models/site_list.py | 13 +- appwrite/models/specification.py | 19 +- appwrite/models/specification_list.py | 13 +- appwrite/models/subscriber.py | 27 +- appwrite/models/subscriber_list.py | 13 +- appwrite/models/table.py | 29 +- appwrite/models/table_list.py | 13 +- appwrite/models/target.py | 27 +- appwrite/models/target_list.py | 13 +- appwrite/models/team.py | 21 +- appwrite/models/team_list.py | 13 +- appwrite/models/token.py | 23 +- appwrite/models/token_secret.py | 53 + appwrite/models/topic.py | 33 +- appwrite/models/topic_list.py | 13 +- appwrite/models/transaction.py | 23 +- appwrite/models/transaction_list.py | 13 +- appwrite/models/usage_billing_plan.py | 32 +- appwrite/models/user.py | 42 +- appwrite/models/user_list.py | 13 +- appwrite/models/variable.py | 27 +- appwrite/models/variable_list.py | 13 +- appwrite/models/vectorsdb_collection.py | 31 +- appwrite/models/vectorsdb_collection_list.py | 13 +- appwrite/models/waf_rule_bypass.py | 92 + appwrite/models/waf_rule_challenge.py | 107 + appwrite/models/waf_rule_deny.py | 92 + appwrite/models/waf_rule_list.py | 44 + appwrite/models/waf_rule_rate_limit.py | 117 + appwrite/models/waf_rule_redirect.py | 102 + appwrite/models/webhook.py | 39 +- appwrite/models/webhook_list.py | 13 +- appwrite/services/account.py | 771 ++++- appwrite/services/activities.py | 2 +- appwrite/services/advisor.py | 11 +- appwrite/services/apps.py | 52 +- appwrite/services/avatars.py | 98 +- appwrite/services/backups.py | 12 +- appwrite/services/databases.py | 355 ++- appwrite/services/documents_db.py | 134 +- appwrite/services/domains.py | 2638 +++++++++++++++++ appwrite/services/functions.py | 80 +- appwrite/services/locale.py | 56 + appwrite/services/messaging.py | 321 +- appwrite/services/mongo.py | 74 +- appwrite/services/mysql.py | 80 +- appwrite/services/oauth2.py | 79 +- appwrite/services/organization.py | 483 +-- appwrite/services/postgresql.py | 88 +- appwrite/services/presences.py | 9 +- appwrite/services/project.py | 451 ++- appwrite/services/proxy.py | 9 +- appwrite/services/sites.py | 77 +- appwrite/services/storage.py | 39 +- appwrite/services/tables_db.py | 501 ++-- appwrite/services/teams.py | 55 +- appwrite/services/tokens.py | 15 +- appwrite/services/users.py | 335 ++- appwrite/services/vectors_db.py | 122 +- appwrite/services/waf.py | 1039 +++++++ appwrite/services/webhooks.py | 17 +- appwrite/topic.py | 106 + .../account/create-email-password-session.md | 3 +- .../account/create-email-verification-otp.md | 18 + .../account/create-id-token-session.md | 24 + .../account/create-mfa-authenticator.md | 2 +- docs/examples/account/create-mfa-challenge.md | 2 +- .../examples/account/create-o-auth-2-token.md | 2 +- docs/examples/account/create-passkey-token.md | 16 + docs/examples/account/create-passkey.md | 19 + docs/examples/account/create-recovery-otp.md | 19 + .../account/delete-mfa-authenticator.md | 2 +- docs/examples/account/delete-passkey.md | 15 + docs/examples/account/delete-sessions.md | 4 +- docs/examples/account/get-passkey.md | 18 + .../{list-logs.md => list-passkeys.md} | 4 +- docs/examples/account/list-sessions.md | 4 +- .../account/update-email-verification-otp.md | 19 + .../account/update-mfa-authenticator.md | 2 +- docs/examples/account/update-passkey-token.md | 19 + .../account/update-passkey-verification.md | 19 + docs/examples/account/update-passkey.md | 19 + docs/examples/account/update-recovery-otp.md | 20 + docs/examples/avatars/delete-photo.md | 13 + docs/examples/avatars/get-browser.md | 2 +- docs/examples/avatars/get-credit-card.md | 2 +- docs/examples/avatars/get-flag.md | 2 +- docs/examples/avatars/get-screenshot.md | 11 +- docs/examples/avatars/update-photo.md | 19 + docs/examples/backups/create-archive.md | 2 +- docs/examples/backups/create-policy.md | 2 +- docs/examples/backups/create-restoration.md | 2 +- docs/examples/databases/create-documents.md | 11 +- docs/examples/databases/create-index.md | 6 +- .../create-relationship-attribute.md | 4 +- docs/examples/databases/delete-documents.md | 2 +- docs/examples/databases/get-attribute.md | 10 +- docs/examples/databases/list-transactions.md | 3 +- .../update-relationship-attribute.md | 2 +- docs/examples/databases/upsert-documents.md | 11 +- docs/examples/documentsdb/create-documents.md | 11 +- docs/examples/documentsdb/create-index.md | 6 +- docs/examples/documentsdb/delete-documents.md | 2 +- .../examples/documentsdb/list-transactions.md | 3 +- docs/examples/documentsdb/upsert-documents.md | 11 +- .../domains/create-preset-google-workspace.md | 18 + .../examples/domains/create-preset-i-cloud.md | 18 + .../examples/domains/create-preset-mailgun.md | 18 + .../examples/domains/create-preset-outlook.md | 18 + .../domains/create-preset-proton-mail.md | 18 + docs/examples/domains/create-preset-zoho.md | 18 + docs/examples/domains/create-record-a.md | 22 + docs/examples/domains/create-record-aaaa.md | 22 + docs/examples/domains/create-record-alias.md | 22 + docs/examples/domains/create-record-caa.md | 22 + docs/examples/domains/create-record-cname.md | 22 + docs/examples/domains/create-record-https.md | 22 + docs/examples/domains/create-record-mx.md | 23 + docs/examples/domains/create-record-ns.md | 22 + docs/examples/domains/create-record-srv.md | 25 + docs/examples/domains/create-record-txt.md | 22 + docs/examples/domains/create.md | 19 + docs/examples/domains/delete-record.md | 16 + docs/examples/domains/delete.md | 15 + .../domains/get-preset-google-workspace.md | 18 + docs/examples/domains/get-preset-i-cloud.md | 18 + docs/examples/domains/get-preset-mailgun.md | 18 + docs/examples/domains/get-preset-outlook.md | 18 + .../domains/get-preset-proton-mail.md | 18 + docs/examples/domains/get-preset-zoho.md | 18 + docs/examples/domains/get-price.md | 21 + docs/examples/domains/get-record.md | 19 + docs/examples/domains/get-transfer-status.md | 18 + docs/examples/domains/get-zone.md | 15 + docs/examples/domains/get.md | 18 + docs/examples/domains/list-prices.md | 21 + docs/examples/domains/list-records.md | 19 + docs/examples/domains/list.md | 19 + docs/examples/domains/update-nameservers.md | 19 + docs/examples/domains/update-record-a.md | 23 + docs/examples/domains/update-record-aaaa.md | 23 + docs/examples/domains/update-record-alias.md | 23 + docs/examples/domains/update-record-caa.md | 23 + docs/examples/domains/update-record-cname.md | 23 + docs/examples/domains/update-record-https.md | 23 + docs/examples/domains/update-record-mx.md | 24 + docs/examples/domains/update-record-ns.md | 23 + docs/examples/domains/update-record-srv.md | 26 + docs/examples/domains/update-record-txt.md | 23 + docs/examples/domains/update-team.md | 19 + docs/examples/domains/update-zone.md | 19 + docs/examples/domains/verify-nameservers.md | 18 + .../embeddings/create-text-embeddings.md | 4 +- docs/examples/functions/create-execution.md | 2 +- .../functions/create-template-deployment.md | 2 +- .../functions/create-vcs-deployment.md | 2 +- docs/examples/functions/create.md | 4 +- .../functions/get-deployment-download.md | 2 +- docs/examples/functions/list-runtimes.md | 4 +- .../examples/functions/list-specifications.md | 3 +- docs/examples/functions/update.md | 4 +- docs/examples/graphql/mutation.md | 4 +- docs/examples/graphql/query.md | 4 +- docs/examples/locale/list-codes.md | 4 +- docs/examples/locale/list-continents.md | 4 +- docs/examples/locale/list-countries-eu.md | 4 +- docs/examples/locale/list-countries-phones.md | 4 +- docs/examples/locale/list-countries.md | 4 +- docs/examples/locale/list-currencies.md | 4 +- docs/examples/locale/list-languages.md | 4 +- .../messaging/create-appwrite-provider.md | 22 + docs/examples/messaging/create-email.md | 2 + docs/examples/messaging/create-push.md | 5 +- .../messaging/create-smtp-provider.md | 2 +- docs/examples/messaging/create-topic.md | 4 +- .../messaging/create-twilio-provider.md | 2 +- .../messaging/update-appwrite-provider.md | 22 + docs/examples/messaging/update-email.md | 14 +- docs/examples/messaging/update-push.md | 9 +- docs/examples/messaging/update-sms.md | 2 +- .../messaging/update-smtp-provider.md | 2 +- docs/examples/messaging/update-topic.md | 4 +- docs/examples/oauth2/approve.md | 2 +- docs/examples/oauth2/authorize-post.md | 4 +- docs/examples/oauth2/authorize.md | 4 +- .../oauth2/create-device-authorization.md | 4 +- docs/examples/oauth2/create-grant.md | 2 +- docs/examples/oauth2/create-par.md | 4 +- docs/examples/oauth2/create-token.md | 4 +- docs/examples/oauth2/get-grant.md | 2 +- docs/examples/oauth2/introspect.md | 21 + docs/examples/oauth2/list-organizations.md | 2 +- docs/examples/oauth2/list-projects.md | 2 +- docs/examples/oauth2/reject.md | 2 +- docs/examples/oauth2/revoke.md | 2 +- ...key.md => create-ephemeral-project-key.md} | 13 +- docs/examples/organization/create-project.md | 2 +- .../{delete-key.md => delete-project-key.md} | 3 +- .../{get-key.md => get-project-key.md} | 3 +- .../{list-keys.md => list-project-keys.md} | 3 +- .../{update-key.md => update-project-key.md} | 7 +- .../project/create-android-platform.md | 3 +- docs/examples/project/create-ephemeral-key.md | 4 +- docs/examples/project/create-smtp-test.md | 2 +- docs/examples/project/get-email-template.md | 4 +- .../examples/project/get-o-auth-2-provider.md | 7 +- docs/examples/project/get-policy.md | 7 +- .../project/update-android-platform.md | 3 +- docs/examples/project/update-auth-method.md | 2 +- .../examples/project/update-email-template.md | 4 +- docs/examples/project/update-key.md | 4 +- docs/examples/project/update-labels.md | 2 +- .../examples/project/update-o-auth-2-apple.md | 4 +- .../project/update-o-auth-2-auth-0.md | 2 + .../project/update-o-auth-2-discord.md | 2 + .../project/update-o-auth-2-git-hub.md | 2 + .../project/update-o-auth-2-google.md | 6 +- .../examples/project/update-o-auth-2-kakao.md | 22 + .../project/update-o-auth-2-microsoft.md | 2 + docs/examples/project/update-o-auth-2-oidc.md | 2 +- docs/examples/project/update-o-auth-2-okta.md | 2 + .../project/update-o-auth-2-salesforce.md | 2 + .../project/update-o-auth-2-tik-tok.md | 20 + .../project/update-o-auth-2-webflow.md | 20 + docs/examples/project/update-o-auth-2-zoho.md | 2 + .../examples/project/update-passkey-policy.md | 18 + .../project/update-password-pwned-policy.md | 20 + .../update-password-rotation-policy.md | 19 + docs/examples/project/update-protocol.md | 2 +- docs/examples/project/update-service.md | 2 +- docs/examples/project/update-smtp.md | 2 +- docs/examples/proxy/create-invalidation.md | 2 +- docs/examples/proxy/create-redirect-rule.md | 4 +- .../sites/create-template-deployment.md | 2 +- docs/examples/sites/create-vcs-deployment.md | 2 +- docs/examples/sites/create.md | 8 +- .../examples/sites/get-deployment-download.md | 2 +- docs/examples/sites/list-frameworks.md | 4 +- docs/examples/sites/list-specifications.md | 3 +- docs/examples/sites/update.md | 8 +- docs/examples/storage/create-bucket.md | 2 +- docs/examples/storage/get-file-preview.md | 6 +- docs/examples/storage/update-bucket.md | 2 +- docs/examples/tablesdb/create-index.md | 6 +- .../tablesdb/create-relationship-column.md | 4 +- docs/examples/tablesdb/create-rows.md | 11 +- docs/examples/tablesdb/delete-rows.md | 2 +- docs/examples/tablesdb/get-column.md | 10 +- docs/examples/tablesdb/list-transactions.md | 3 +- .../tablesdb/update-relationship-column.md | 2 +- docs/examples/tablesdb/upsert-rows.md | 11 +- docs/examples/teams/create-membership.md | 3 +- docs/examples/teams/update-membership.md | 2 +- docs/examples/users/create-sha-user.md | 2 +- docs/examples/users/create-target.md | 2 +- .../users/delete-mfa-authenticator.md | 2 +- docs/examples/users/delete-passkey.md | 16 + docs/examples/users/get-passkey.md | 19 + .../users/{list-logs.md => list-passkeys.md} | 4 +- docs/examples/users/update-labels.md | 2 +- docs/examples/users/update-passkey.md | 20 + docs/examples/vectorsdb/create-collection.md | 2 +- docs/examples/vectorsdb/create-documents.md | 15 +- docs/examples/vectorsdb/create-index.md | 6 +- docs/examples/vectorsdb/create-operations.md | 10 +- docs/examples/vectorsdb/delete-documents.md | 2 +- docs/examples/vectorsdb/list-transactions.md | 3 +- docs/examples/vectorsdb/update-collection.md | 2 +- docs/examples/vectorsdb/upsert-documents.md | 15 +- docs/examples/waf/create-bypass-rule.md | 25 + docs/examples/waf/create-challenge-rule.md | 28 + docs/examples/waf/create-deny-rule.md | 25 + docs/examples/waf/create-rate-limit-rule.md | 30 + docs/examples/waf/create-redirect-rule.md | 27 + docs/examples/waf/delete-rule.md | 15 + docs/examples/waf/get-rule.md | 23 + docs/examples/waf/list-rules.md | 20 + docs/examples/waf/update-bypass-rule.md | 25 + docs/examples/waf/update-challenge-rule.md | 28 + docs/examples/waf/update-deny-rule.md | 25 + docs/examples/waf/update-rate-limit-rule.md | 29 + docs/examples/waf/update-redirect-rule.md | 27 + docs/examples/webhooks/create.md | 2 +- docs/examples/webhooks/update.md | 2 +- pyproject.toml | 2 +- setup.py | 4 +- test/services/test_account.py | 308 +- test/services/test_avatars.py | 45 + test/services/test_backups.py | 12 +- test/services/test_documents_db.py | 18 +- test/services/test_domains.py | 1207 ++++++++ test/services/test_functions.py | 4 +- test/services/test_messaging.py | 49 + test/services/test_mongo.py | 94 +- test/services/test_mysql.py | 94 +- test/services/test_oauth2.py | 21 +- test/services/test_organization.py | 374 +-- test/services/test_postgresql.py | 110 +- test/services/test_project.py | 214 +- test/services/test_sites.py | 2 +- test/services/test_tables_db.py | 80 +- test/services/test_users.py | 97 +- test/services/test_vectors_db.py | 18 +- test/services/test_waf.py | 410 +++ test/test_topic.py | 45 + 631 files changed, 19659 insertions(+), 2724 deletions(-) create mode 100644 appwrite/enums/domain_registration_type.py create mode 100644 appwrite/enums/domain_transfer_status_enum.py create mode 100644 appwrite/enums/id_token_provider.py create mode 100644 appwrite/enums/o_auth2_auth0_prompt.py create mode 100644 appwrite/enums/o_auth2_discord_prompt.py create mode 100644 appwrite/enums/o_auth2_github_prompt.py create mode 100644 appwrite/enums/o_auth2_kakao_prompt.py create mode 100644 appwrite/enums/o_auth2_microsoft_prompt.py create mode 100644 appwrite/enums/o_auth2_okta_prompt.py create mode 100644 appwrite/enums/o_auth2_salesforce_prompt.py create mode 100644 appwrite/enums/o_auth2_zoho_prompt.py delete mode 100644 appwrite/enums/organization_key_scopes.py create mode 100644 appwrite/enums/project_o_auth2_auth0_prompt.py create mode 100644 appwrite/enums/project_o_auth2_discord_prompt.py create mode 100644 appwrite/enums/project_o_auth2_git_hub_prompt.py create mode 100644 appwrite/enums/project_o_auth2_kakao_prompt.py create mode 100644 appwrite/enums/project_o_auth2_microsoft_prompt.py create mode 100644 appwrite/enums/project_o_auth2_okta_prompt.py create mode 100644 appwrite/enums/project_o_auth2_salesforce_prompt.py create mode 100644 appwrite/enums/project_o_auth2_zoho_prompt.py create mode 100644 appwrite/enums/waf_rule_action.py create mode 100644 appwrite/models/account.py delete mode 100644 appwrite/models/dedicated_database_specification_pricing.py delete mode 100644 appwrite/models/dev_key.py create mode 100644 appwrite/models/dns_record.py create mode 100644 appwrite/models/dns_records_list.py create mode 100644 appwrite/models/domain.py create mode 100644 appwrite/models/domain_price.py create mode 100644 appwrite/models/domain_prices_list.py create mode 100644 appwrite/models/domain_transfer_status.py create mode 100644 appwrite/models/domains_list.py delete mode 100644 appwrite/models/log.py delete mode 100644 appwrite/models/log_list.py create mode 100644 appwrite/models/o_auth2_kakao.py create mode 100644 appwrite/models/o_auth2_tik_tok.py create mode 100644 appwrite/models/o_auth2_webflow.py create mode 100644 appwrite/models/oauth2_introspection.py create mode 100644 appwrite/models/passkey.py create mode 100644 appwrite/models/passkey_challenge.py create mode 100644 appwrite/models/passkey_list.py create mode 100644 appwrite/models/policy_passkey.py create mode 100644 appwrite/models/policy_password_pwned.py create mode 100644 appwrite/models/policy_password_rotation.py create mode 100644 appwrite/models/token_secret.py create mode 100644 appwrite/models/waf_rule_bypass.py create mode 100644 appwrite/models/waf_rule_challenge.py create mode 100644 appwrite/models/waf_rule_deny.py create mode 100644 appwrite/models/waf_rule_list.py create mode 100644 appwrite/models/waf_rule_rate_limit.py create mode 100644 appwrite/models/waf_rule_redirect.py create mode 100644 appwrite/services/domains.py create mode 100644 appwrite/services/waf.py create mode 100644 appwrite/topic.py create mode 100644 docs/examples/account/create-email-verification-otp.md create mode 100644 docs/examples/account/create-id-token-session.md create mode 100644 docs/examples/account/create-passkey-token.md create mode 100644 docs/examples/account/create-passkey.md create mode 100644 docs/examples/account/create-recovery-otp.md create mode 100644 docs/examples/account/delete-passkey.md create mode 100644 docs/examples/account/get-passkey.md rename docs/examples/account/{list-logs.md => list-passkeys.md} (83%) create mode 100644 docs/examples/account/update-email-verification-otp.md create mode 100644 docs/examples/account/update-passkey-token.md create mode 100644 docs/examples/account/update-passkey-verification.md create mode 100644 docs/examples/account/update-passkey.md create mode 100644 docs/examples/account/update-recovery-otp.md create mode 100644 docs/examples/avatars/delete-photo.md create mode 100644 docs/examples/avatars/update-photo.md create mode 100644 docs/examples/domains/create-preset-google-workspace.md create mode 100644 docs/examples/domains/create-preset-i-cloud.md create mode 100644 docs/examples/domains/create-preset-mailgun.md create mode 100644 docs/examples/domains/create-preset-outlook.md create mode 100644 docs/examples/domains/create-preset-proton-mail.md create mode 100644 docs/examples/domains/create-preset-zoho.md create mode 100644 docs/examples/domains/create-record-a.md create mode 100644 docs/examples/domains/create-record-aaaa.md create mode 100644 docs/examples/domains/create-record-alias.md create mode 100644 docs/examples/domains/create-record-caa.md create mode 100644 docs/examples/domains/create-record-cname.md create mode 100644 docs/examples/domains/create-record-https.md create mode 100644 docs/examples/domains/create-record-mx.md create mode 100644 docs/examples/domains/create-record-ns.md create mode 100644 docs/examples/domains/create-record-srv.md create mode 100644 docs/examples/domains/create-record-txt.md create mode 100644 docs/examples/domains/create.md create mode 100644 docs/examples/domains/delete-record.md create mode 100644 docs/examples/domains/delete.md create mode 100644 docs/examples/domains/get-preset-google-workspace.md create mode 100644 docs/examples/domains/get-preset-i-cloud.md create mode 100644 docs/examples/domains/get-preset-mailgun.md create mode 100644 docs/examples/domains/get-preset-outlook.md create mode 100644 docs/examples/domains/get-preset-proton-mail.md create mode 100644 docs/examples/domains/get-preset-zoho.md create mode 100644 docs/examples/domains/get-price.md create mode 100644 docs/examples/domains/get-record.md create mode 100644 docs/examples/domains/get-transfer-status.md create mode 100644 docs/examples/domains/get-zone.md create mode 100644 docs/examples/domains/get.md create mode 100644 docs/examples/domains/list-prices.md create mode 100644 docs/examples/domains/list-records.md create mode 100644 docs/examples/domains/list.md create mode 100644 docs/examples/domains/update-nameservers.md create mode 100644 docs/examples/domains/update-record-a.md create mode 100644 docs/examples/domains/update-record-aaaa.md create mode 100644 docs/examples/domains/update-record-alias.md create mode 100644 docs/examples/domains/update-record-caa.md create mode 100644 docs/examples/domains/update-record-cname.md create mode 100644 docs/examples/domains/update-record-https.md create mode 100644 docs/examples/domains/update-record-mx.md create mode 100644 docs/examples/domains/update-record-ns.md create mode 100644 docs/examples/domains/update-record-srv.md create mode 100644 docs/examples/domains/update-record-txt.md create mode 100644 docs/examples/domains/update-team.md create mode 100644 docs/examples/domains/update-zone.md create mode 100644 docs/examples/domains/verify-nameservers.md create mode 100644 docs/examples/messaging/create-appwrite-provider.md create mode 100644 docs/examples/messaging/update-appwrite-provider.md create mode 100644 docs/examples/oauth2/introspect.md rename docs/examples/organization/{create-key.md => create-ephemeral-project-key.md} (58%) rename docs/examples/organization/{delete-key.md => delete-project-key.md} (83%) rename docs/examples/organization/{get-key.md => get-project-key.md} (85%) rename docs/examples/organization/{list-keys.md => list-project-keys.md} (85%) rename docs/examples/organization/{update-key.md => update-project-key.md} (73%) create mode 100644 docs/examples/project/update-o-auth-2-kakao.md create mode 100644 docs/examples/project/update-o-auth-2-tik-tok.md create mode 100644 docs/examples/project/update-o-auth-2-webflow.md create mode 100644 docs/examples/project/update-passkey-policy.md create mode 100644 docs/examples/project/update-password-pwned-policy.md create mode 100644 docs/examples/project/update-password-rotation-policy.md create mode 100644 docs/examples/users/delete-passkey.md create mode 100644 docs/examples/users/get-passkey.md rename docs/examples/users/{list-logs.md => list-passkeys.md} (84%) create mode 100644 docs/examples/users/update-passkey.md create mode 100644 docs/examples/waf/create-bypass-rule.md create mode 100644 docs/examples/waf/create-challenge-rule.md create mode 100644 docs/examples/waf/create-deny-rule.md create mode 100644 docs/examples/waf/create-rate-limit-rule.md create mode 100644 docs/examples/waf/create-redirect-rule.md create mode 100644 docs/examples/waf/delete-rule.md create mode 100644 docs/examples/waf/get-rule.md create mode 100644 docs/examples/waf/list-rules.md create mode 100644 docs/examples/waf/update-bypass-rule.md create mode 100644 docs/examples/waf/update-challenge-rule.md create mode 100644 docs/examples/waf/update-deny-rule.md create mode 100644 docs/examples/waf/update-rate-limit-rule.md create mode 100644 docs/examples/waf/update-redirect-rule.md create mode 100644 test/services/test_domains.py create mode 100644 test/services/test_waf.py create mode 100644 test/test_topic.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ff97ad9..76ace887 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,41 @@ # Change Log +## 25.0.0 + +* Breaking: `account.list_logs`, `users.list_logs`, `Log` and `LogList` removed +* Breaking: `organization` key methods renamed to `create_ephemeral_project_key`, `get_project_key`, `list_project_keys`, `update_project_key` and `delete_project_key`; `OrganizationKeyScopes` removed +* Breaking: `set_dev_key` client method, `DevKey` model and `Project.devKeys` removed +* Breaking: `projectName`, `region`, `organizationId`, `organizationName`, `billingPlan` and `reason` removed from `Block` +* Breaking: `DedicatedDatabaseSpecificationList.pricing` and `DedicatedDatabaseSpecificationPricing` removed; rates now live on `DedicatedDatabaseSpecification` +* Breaking: `BillingPlanGroup` `starter` replaced by `free` and `start` +* Breaking: `resource` is now an array on `oauth2.authorize`, `oauth2.create_par`, `oauth2.create_token` and `oauth2.create_device_authorization` +* Breaking: `BackupRestoration.options` is now a key-value object instead of a string +* Breaking: optional parameters reordered in `messaging.update_email`, `messaging.update_push` and `messaging.update_sms`; new ones inserted mid-list in `messaging.create_email`, `teams.create_membership` and `project` OAuth2 provider updates; use named arguments +* Added: passkey methods `account.list_passkeys`, `account.create_passkey`, `account.get_passkey`, `account.update_passkey`, `account.delete_passkey`, `account.update_passkey_verification`, `account.create_passkey_token` and `account.update_passkey_token` +* Added: `users.list_passkeys`, `users.get_passkey`, `users.update_passkey`, `users.delete_passkey`, plus `project.update_passkey_policy` +* Added: `Passkey`, `PasskeyList`, `PasskeyChallenge`, `PolicyPasskey` and `TokenSecret` models +* Added: `fingerprints` on Android platforms for passkeys +* Added: `domains` service for domains, DNS records, email presets, prices and transfers +* Added: `waf` service for bypass, challenge, deny, rate-limit and redirect rules +* Added: `account.create_id_token_session` for native Apple and Google sign-in, with native client IDs on those providers +* Added: email verification and recovery OTP methods on `account` +* Added: `oauth2.introspect` for RFC 7662 token introspection, returning `Oauth2Introspection` +* Added: `avatars.update_photo` and `avatars.delete_photo` +* Added: `messaging.create_appwrite_provider` and `messaging.update_appwrite_provider` +* Added: `project.update_password_pwned_policy`, `PolicyPasswordPwned` model and `User.passwordPwned` +* Added: Kakao, TikTok and Webflow OAuth2 providers +* Added: `prompt` on Auth0, Discord, GitHub, Microsoft, Okta, Salesforce and Zoho providers, with prompt enums +* Added: `Topic` and `ResolvedTopic` helpers for building MQTT push topics +* Added: reply-to on email messages, `channelId` on push messages, `qos` and `expiry` on topics +* Added: `membershipId` on `teams.create_membership`, and `total` on locale and other list endpoints +* Added: `storageStatus` and `storageTargetGb` on `DedicatedDatabase`; `eligibleCountries` on `BillingPlan` +* Added: `auto` image gravity, `jaspr` framework, `dart-3.13` and `flutter-3.47` runtimes +* Added: `project.update_password_rotation_policy` and the `PolicyPasswordRotation` model +* Fixed: response models fill missing fields from spec defaults instead of throwing +* Fixed: multipart requests without a file are sent as multipart instead of URL-encoded +* Updated: several model fields are now optional and may be `None`, e.g. `DedicatedDatabase.engine`, `Organization.billingStartDate`, `BillingPlan.usage`, `BackupArchive.size` +* Updated: requests send `X-Appwrite-Response-Format` `2.4.0` + ## 24.2.0 * Added: optional `interval` parameter on `functions.create` and `functions.update` to run a function every N minutes diff --git a/README.md b/README.md index e7644a3a..47896502 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite Python SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-python.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-2.0.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-2.4.0-blue.svg?style=flat-square) [![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) -**This SDK targets Appwrite server version 1.9.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-python/releases) when APIs differ. +**This SDK targets Appwrite server version 2.4.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-python/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Python SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) diff --git a/appwrite/client.py b/appwrite/client.py index 470508a4..14772a67 100644 --- a/appwrite/client.py +++ b/appwrite/client.py @@ -18,12 +18,12 @@ def __init__(self): self._endpoint = 'https://cloud.appwrite.io/v1' self._global_headers = { 'content-type': '', - 'user-agent': f'AppwritePythonSDK/24.2.0 ({platform.uname().system}; {platform.uname().version}; {platform.uname().machine})', + 'user-agent': f'AppwritePythonSDK/25.0.0 ({platform.uname().system}; {platform.uname().version}; {platform.uname().machine})', 'x-sdk-name': 'Python', 'x-sdk-platform': 'server', 'x-sdk-language': 'python', - 'x-sdk-version': '24.2.0', - 'X-Appwrite-Response-Format': '2.0.0', + 'x-sdk-version': '25.0.0', + 'X-Appwrite-Response-Format': '2.4.0', } self._config = {} @@ -101,13 +101,6 @@ def set_forwarded_user_agent(self, value): self._config['forwardeduseragent'] = value return self - def set_dev_key(self, value): - """Your secret dev API key""" - - self._global_headers['x-appwrite-dev-key'] = value - self._config['devkey'] = value - return self - def set_cookie(self, value): """The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes.""" @@ -164,6 +157,15 @@ def call(self, method, path='', headers=None, params=None, response_type='json') files[key] = (data[key].filename, data[key].data) del data[key] data = self.flatten(data, stringify=stringify) + if not files and data: + # Without a file, requests would fall back to a URL-encoded body. + files = {key: (None, value) for key, value in data.items()} + data = {} + elif not files: + # With no parts at all, requests would send a bare body, so close an empty multipart one. + boundary = os.urandom(16).hex() + headers['content-type'] = f'multipart/form-data; boundary={boundary}' + data = f'--{boundary}--\r\n' response = None try: @@ -190,6 +192,9 @@ def call(self, method, path='', headers=None, params=None, response_type='json') if response_type == 'location': return response.headers.get('Location') + if response_type == 'text': + return response.content.decode('utf-8') + if content_type.startswith('application/json'): return response.json() @@ -214,7 +219,12 @@ def chunked_upload( param_name='', on_progress=None, upload_id='', + response_type='json', + method='post', ): + if params.get(param_name) is None: + return self.call(method, path, headers, params, response_type=response_type) + input_file = params[param_name] if input_file.source_type == 'path': @@ -224,13 +234,13 @@ def chunked_upload( size = len(input_file.data) input = input_file.data - if size < self._chunk_size: + if size <= self._chunk_size or response_type == 'text': if input_file.source_type == 'path': with open(input_file.path, 'rb') as input: input_file.data = input.read() params[param_name] = input_file - return self.call('post', path, headers, params) + return self.call(method, path, headers, params, response_type=response_type) offset = 0 counter = 0 @@ -277,6 +287,8 @@ def read_chunk(start, end): final_result = None def is_upload_complete(chunk_result): + if not isinstance(chunk_result, dict): + return False chunks_uploaded = chunk_result.get('chunksUploaded') if chunks_uploaded is None: return False @@ -296,15 +308,16 @@ def upload_chunk(chunk, current_upload_id): chunk_headers["x-appwrite-id"] = current_upload_id return self.call( - 'post', + method, path, chunk_headers, chunk_params, + response_type=response_type, ) result = upload_chunk(chunks[0], upload_id_header) last_result = result - if "$id" in result: + if isinstance(result, dict) and "$id" in result: upload_id_header = result["$id"] completed_count = chunks[0]['index'] + 1 @@ -313,7 +326,7 @@ def upload_chunk(chunk, current_upload_id): if on_progress is not None: on_progress( { - "$id": result.get("$id"), + "$id": result.get("$id") if isinstance(result, dict) else None, "progress": uploaded_size / size * 100, "sizeUploaded": uploaded_size, "chunksTotal": total_chunks, diff --git a/appwrite/encoders/value_class_encoder.py b/appwrite/encoders/value_class_encoder.py index 96f558d2..709be3f8 100644 --- a/appwrite/encoders/value_class_encoder.py +++ b/appwrite/encoders/value_class_encoder.py @@ -2,6 +2,7 @@ from ..models.base_model import AppwriteModel from ..enums.authenticator_type import AuthenticatorType from ..enums.authentication_factor import AuthenticationFactor +from ..enums.id_token_provider import IdTokenProvider from ..enums.o_auth_provider import OAuthProvider from ..enums.browser import Browser from ..enums.credit_card import CreditCard @@ -16,6 +17,7 @@ from ..enums.databases_index_type import DatabasesIndexType from ..enums.order_by import OrderBy from ..enums.documents_db_index_type import DocumentsDBIndexType +from ..enums.domain_registration_type import DomainRegistrationType from ..enums.embedding_model import EmbeddingModel from ..enums.runtime import Runtime from ..enums.project_key_scopes import ProjectKeyScopes @@ -25,11 +27,18 @@ from ..enums.execution_method import ExecutionMethod from ..enums.message_priority import MessagePriority from ..enums.smtp_encryption import SmtpEncryption -from ..enums.organization_key_scopes import OrganizationKeyScopes from ..enums.region import Region from ..enums.project_auth_method_id import ProjectAuthMethodId +from ..enums.project_o_auth2_auth0_prompt import ProjectOAuth2Auth0Prompt +from ..enums.project_o_auth2_discord_prompt import ProjectOAuth2DiscordPrompt +from ..enums.project_o_auth2_git_hub_prompt import ProjectOAuth2GitHubPrompt from ..enums.project_o_auth2_google_prompt import ProjectOAuth2GooglePrompt +from ..enums.project_o_auth2_kakao_prompt import ProjectOAuth2KakaoPrompt +from ..enums.project_o_auth2_microsoft_prompt import ProjectOAuth2MicrosoftPrompt from ..enums.project_o_auth2_oidc_prompt import ProjectOAuth2OidcPrompt +from ..enums.project_o_auth2_okta_prompt import ProjectOAuth2OktaPrompt +from ..enums.project_o_auth2_salesforce_prompt import ProjectOAuth2SalesforcePrompt +from ..enums.project_o_auth2_zoho_prompt import ProjectOAuth2ZohoPrompt from ..enums.project_o_auth_provider_id import ProjectOAuthProviderId from ..enums.project_policy_id import ProjectPolicyId from ..enums.project_protocol_id import ProjectProtocolId @@ -58,13 +67,23 @@ from ..enums.execution_resource_type import ExecutionResourceType from ..enums.execution_trigger import ExecutionTrigger from ..enums.execution_status import ExecutionStatus +from ..enums.o_auth2_github_prompt import OAuth2GithubPrompt +from ..enums.o_auth2_discord_prompt import OAuth2DiscordPrompt from ..enums.o_auth2_google_prompt import OAuth2GooglePrompt +from ..enums.o_auth2_zoho_prompt import OAuth2ZohoPrompt +from ..enums.o_auth2_salesforce_prompt import OAuth2SalesforcePrompt +from ..enums.o_auth2_auth0_prompt import OAuth2Auth0Prompt from ..enums.o_auth2_oidc_prompt import OAuth2OidcPrompt +from ..enums.o_auth2_okta_prompt import OAuth2OktaPrompt +from ..enums.o_auth2_microsoft_prompt import OAuth2MicrosoftPrompt +from ..enums.o_auth2_kakao_prompt import OAuth2KakaoPrompt from ..enums.platform_type import PlatformType from ..enums.proxy_rule_deployment_resource_type import ProxyRuleDeploymentResourceType from ..enums.proxy_rule_status import ProxyRuleStatus from ..enums.message_status import MessageStatus from ..enums.billing_plan_group import BillingPlanGroup +from ..enums.domain_transfer_status_enum import DomainTransferStatusEnum +from ..enums.waf_rule_action import WafRuleAction class ValueClassEncoder(json.JSONEncoder): @@ -78,6 +97,9 @@ def default(self, o): if isinstance(o, AuthenticationFactor): return o.value + if isinstance(o, IdTokenProvider): + return o.value + if isinstance(o, OAuthProvider): return o.value @@ -120,6 +142,9 @@ def default(self, o): if isinstance(o, DocumentsDBIndexType): return o.value + if isinstance(o, DomainRegistrationType): + return o.value + if isinstance(o, EmbeddingModel): return o.value @@ -147,21 +172,42 @@ def default(self, o): if isinstance(o, SmtpEncryption): return o.value - if isinstance(o, OrganizationKeyScopes): - return o.value - if isinstance(o, Region): return o.value if isinstance(o, ProjectAuthMethodId): return o.value + if isinstance(o, ProjectOAuth2Auth0Prompt): + return o.value + + if isinstance(o, ProjectOAuth2DiscordPrompt): + return o.value + + if isinstance(o, ProjectOAuth2GitHubPrompt): + return o.value + if isinstance(o, ProjectOAuth2GooglePrompt): return o.value + if isinstance(o, ProjectOAuth2KakaoPrompt): + return o.value + + if isinstance(o, ProjectOAuth2MicrosoftPrompt): + return o.value + if isinstance(o, ProjectOAuth2OidcPrompt): return o.value + if isinstance(o, ProjectOAuth2OktaPrompt): + return o.value + + if isinstance(o, ProjectOAuth2SalesforcePrompt): + return o.value + + if isinstance(o, ProjectOAuth2ZohoPrompt): + return o.value + if isinstance(o, ProjectOAuthProviderId): return o.value @@ -246,12 +292,36 @@ def default(self, o): if isinstance(o, ExecutionStatus): return o.value + if isinstance(o, OAuth2GithubPrompt): + return o.value + + if isinstance(o, OAuth2DiscordPrompt): + return o.value + if isinstance(o, OAuth2GooglePrompt): return o.value + if isinstance(o, OAuth2ZohoPrompt): + return o.value + + if isinstance(o, OAuth2SalesforcePrompt): + return o.value + + if isinstance(o, OAuth2Auth0Prompt): + return o.value + if isinstance(o, OAuth2OidcPrompt): return o.value + if isinstance(o, OAuth2OktaPrompt): + return o.value + + if isinstance(o, OAuth2MicrosoftPrompt): + return o.value + + if isinstance(o, OAuth2KakaoPrompt): + return o.value + if isinstance(o, PlatformType): return o.value @@ -267,4 +337,10 @@ def default(self, o): if isinstance(o, BillingPlanGroup): return o.value + if isinstance(o, DomainTransferStatusEnum): + return o.value + + if isinstance(o, WafRuleAction): + return o.value + return super().default(o) diff --git a/appwrite/enums/billing_plan_group.py b/appwrite/enums/billing_plan_group.py index 356139e8..b2b23a29 100644 --- a/appwrite/enums/billing_plan_group.py +++ b/appwrite/enums/billing_plan_group.py @@ -2,6 +2,7 @@ class BillingPlanGroup(Enum): - STARTER = "starter" + FREE = "free" + START = "start" PRO = "pro" SCALE = "scale" diff --git a/appwrite/enums/build_runtime.py b/appwrite/enums/build_runtime.py index 08aacade..4bf67543 100644 --- a/appwrite/enums/build_runtime.py +++ b/appwrite/enums/build_runtime.py @@ -53,6 +53,7 @@ class BuildRuntime(Enum): DART_3_10 = "dart-3.10" DART_3_11 = "dart-3.11" DART_3_12 = "dart-3.12" + DART_3_13 = "dart-3.13" DOTNET_6_0 = "dotnet-6.0" DOTNET_7_0 = "dotnet-7.0" DOTNET_8_0 = "dotnet-8.0" @@ -95,3 +96,4 @@ class BuildRuntime(Enum): FLUTTER_3_38 = "flutter-3.38" FLUTTER_3_41 = "flutter-3.41" FLUTTER_3_44 = "flutter-3.44" + FLUTTER_3_47 = "flutter-3.47" diff --git a/appwrite/enums/domain_registration_type.py b/appwrite/enums/domain_registration_type.py new file mode 100644 index 00000000..cb6f6e57 --- /dev/null +++ b/appwrite/enums/domain_registration_type.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class DomainRegistrationType(Enum): + NEW = "new" + TRANSFER = "transfer" + RENEWAL = "renewal" + TRADE = "trade" diff --git a/appwrite/enums/domain_transfer_status_enum.py b/appwrite/enums/domain_transfer_status_enum.py new file mode 100644 index 00000000..298de29a --- /dev/null +++ b/appwrite/enums/domain_transfer_status_enum.py @@ -0,0 +1,12 @@ +from enum import Enum + + +class DomainTransferStatusEnum(Enum): + TRANSFERRABLE = "transferrable" + NOT_TRANSFERRABLE = "not_transferrable" + PENDING_OWNER = "pending_owner" + PENDING_ADMIN = "pending_admin" + PENDING_REGISTRY = "pending_registry" + COMPLETED = "completed" + CANCELLED = "cancelled" + SERVICE_UNAVAILABLE = "service_unavailable" diff --git a/appwrite/enums/framework.py b/appwrite/enums/framework.py index 013d71c4..b16cb5d2 100644 --- a/appwrite/enums/framework.py +++ b/appwrite/enums/framework.py @@ -14,6 +14,7 @@ class Framework(Enum): REMIX = "remix" LYNX = "lynx" FLUTTER = "flutter" + JASPR = "jaspr" REACT_NATIVE = "react-native" VITE = "vite" OTHER = "other" diff --git a/appwrite/enums/id_token_provider.py b/appwrite/enums/id_token_provider.py new file mode 100644 index 00000000..707566f4 --- /dev/null +++ b/appwrite/enums/id_token_provider.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class IdTokenProvider(Enum): + APPLE = "apple" + GOOGLE = "google" diff --git a/appwrite/enums/image_gravity.py b/appwrite/enums/image_gravity.py index 57c13887..c34176fa 100644 --- a/appwrite/enums/image_gravity.py +++ b/appwrite/enums/image_gravity.py @@ -2,6 +2,7 @@ class ImageGravity(Enum): + AUTO = "auto" CENTER = "center" TOP_LEFT = "top-left" TOP = "top" diff --git a/appwrite/enums/o_auth2_auth0_prompt.py b/appwrite/enums/o_auth2_auth0_prompt.py new file mode 100644 index 00000000..8acbbfe7 --- /dev/null +++ b/appwrite/enums/o_auth2_auth0_prompt.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class OAuth2Auth0Prompt(Enum): + NONE = "none" + LOGIN = "login" + CONSENT = "consent" diff --git a/appwrite/enums/o_auth2_discord_prompt.py b/appwrite/enums/o_auth2_discord_prompt.py new file mode 100644 index 00000000..38e3725f --- /dev/null +++ b/appwrite/enums/o_auth2_discord_prompt.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class OAuth2DiscordPrompt(Enum): + NONE = "none" + CONSENT = "consent" diff --git a/appwrite/enums/o_auth2_github_prompt.py b/appwrite/enums/o_auth2_github_prompt.py new file mode 100644 index 00000000..1cc47a0b --- /dev/null +++ b/appwrite/enums/o_auth2_github_prompt.py @@ -0,0 +1,5 @@ +from enum import Enum + + +class OAuth2GithubPrompt(Enum): + SELECT_ACCOUNT = "select_account" diff --git a/appwrite/enums/o_auth2_kakao_prompt.py b/appwrite/enums/o_auth2_kakao_prompt.py new file mode 100644 index 00000000..7460a528 --- /dev/null +++ b/appwrite/enums/o_auth2_kakao_prompt.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class OAuth2KakaoPrompt(Enum): + NONE = "none" + LOGIN = "login" + CREATE = "create" + SELECT_ACCOUNT = "select_account" diff --git a/appwrite/enums/o_auth2_microsoft_prompt.py b/appwrite/enums/o_auth2_microsoft_prompt.py new file mode 100644 index 00000000..d237f4ec --- /dev/null +++ b/appwrite/enums/o_auth2_microsoft_prompt.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class OAuth2MicrosoftPrompt(Enum): + NONE = "none" + LOGIN = "login" + CONSENT = "consent" + SELECT_ACCOUNT = "select_account" diff --git a/appwrite/enums/o_auth2_okta_prompt.py b/appwrite/enums/o_auth2_okta_prompt.py new file mode 100644 index 00000000..fb2b16c3 --- /dev/null +++ b/appwrite/enums/o_auth2_okta_prompt.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class OAuth2OktaPrompt(Enum): + NONE = "none" + LOGIN = "login" + CONSENT = "consent" diff --git a/appwrite/enums/o_auth2_salesforce_prompt.py b/appwrite/enums/o_auth2_salesforce_prompt.py new file mode 100644 index 00000000..64833a05 --- /dev/null +++ b/appwrite/enums/o_auth2_salesforce_prompt.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class OAuth2SalesforcePrompt(Enum): + LOGIN = "login" + CONSENT = "consent" diff --git a/appwrite/enums/o_auth2_zoho_prompt.py b/appwrite/enums/o_auth2_zoho_prompt.py new file mode 100644 index 00000000..bd6a30b3 --- /dev/null +++ b/appwrite/enums/o_auth2_zoho_prompt.py @@ -0,0 +1,5 @@ +from enum import Enum + + +class OAuth2ZohoPrompt(Enum): + CONSENT = "consent" diff --git a/appwrite/enums/o_auth_provider.py b/appwrite/enums/o_auth_provider.py index 8656b596..87c6ed02 100644 --- a/appwrite/enums/o_auth_provider.py +++ b/appwrite/enums/o_auth_provider.py @@ -24,6 +24,7 @@ class OAuthProvider(Enum): GITLAB = "gitlab" GOOGLE = "google" HUGGINGFACE = "huggingface" + KAKAO = "kakao" KEYCLOAK = "keycloak" KICK = "kick" LINKEDIN = "linkedin" @@ -39,9 +40,11 @@ class OAuthProvider(Enum): SLACK = "slack" SPOTIFY = "spotify" STRIPE = "stripe" + TIKTOK = "tiktok" TRADESHIFT = "tradeshift" TRADESHIFTBOX = "tradeshiftBox" TWITCH = "twitch" + WEBFLOW = "webflow" WORDPRESS = "wordpress" X = "x" YAHOO = "yahoo" diff --git a/appwrite/enums/organization_key_scopes.py b/appwrite/enums/organization_key_scopes.py deleted file mode 100644 index ffa6e6a6..00000000 --- a/appwrite/enums/organization_key_scopes.py +++ /dev/null @@ -1,20 +0,0 @@ -from enum import Enum - - -class OrganizationKeyScopes(Enum): - PROJECTS_READ = "projects.read" - PROJECTS_WRITE = "projects.write" - DEVKEYS_READ = "devKeys.read" - DEVKEYS_WRITE = "devKeys.write" - ORGANIZATION_KEYS_READ = "organization.keys.read" - ORGANIZATION_KEYS_WRITE = "organization.keys.write" - ORGANIZATION_INSTALLATIONS_READ = "organization.installations.read" - ORGANIZATION_INSTALLATIONS_WRITE = "organization.installations.write" - ORGANIZATION_MEMBERSHIPS_READ = "organization.memberships.read" - ORGANIZATION_MEMBERSHIPS_WRITE = "organization.memberships.write" - ORGANIZATION_READ = "organization.read" - ORGANIZATION_WRITE = "organization.write" - DOMAINS_READ = "domains.read" - DOMAINS_WRITE = "domains.write" - KEYS_READ = "keys.read" - KEYS_WRITE = "keys.write" diff --git a/appwrite/enums/project_auth_method_id.py b/appwrite/enums/project_auth_method_id.py index 8ebb7fb3..834fe51c 100644 --- a/appwrite/enums/project_auth_method_id.py +++ b/appwrite/enums/project_auth_method_id.py @@ -9,3 +9,4 @@ class ProjectAuthMethodId(Enum): INVITES = "invites" JWT = "jwt" PHONE = "phone" + PASSKEY = "passkey" diff --git a/appwrite/enums/project_email_template_id.py b/appwrite/enums/project_email_template_id.py index c2b97a29..c6c940d6 100644 --- a/appwrite/enums/project_email_template_id.py +++ b/appwrite/enums/project_email_template_id.py @@ -9,3 +9,5 @@ class ProjectEmailTemplateId(Enum): MFACHALLENGE = "mfaChallenge" SESSIONALERT = "sessionAlert" OTPSESSION = "otpSession" + OTPVERIFICATION = "otpVerification" + OTPRECOVERY = "otpRecovery" diff --git a/appwrite/enums/project_key_scopes.py b/appwrite/enums/project_key_scopes.py index 57710319..9168740c 100644 --- a/appwrite/enums/project_key_scopes.py +++ b/appwrite/enums/project_key_scopes.py @@ -92,6 +92,7 @@ class ProjectKeyScopes(Enum): WEBHOOKS_WRITE = "webhooks.write" LOCALE_READ = "locale.read" AVATARS_READ = "avatars.read" + AVATARS_WRITE = "avatars.write" HEALTH_READ = "health.read" ASSISTANT_READ = "assistant.read" MIGRATIONS_READ = "migrations.read" @@ -106,6 +107,7 @@ class ProjectKeyScopes(Enum): REPORTS_WRITE = "reports.write" PRESENCES_READ = "presences.read" PRESENCES_WRITE = "presences.write" + DEDICATEDDATABASES_EXECUTE = "dedicatedDatabases.execute" BACKUPS_POLICIES_READ = "backups.policies.read" BACKUPS_POLICIES_WRITE = "backups.policies.write" ARCHIVES_READ = "archives.read" @@ -123,3 +125,5 @@ class ProjectKeyScopes(Enum): OAUTH2_READ = "oauth2.read" OAUTH2_WRITE = "oauth2.write" OAUTH2_INTROSPECT = "oauth2.introspect" + ANALYTICS_READ = "analytics.read" + ANALYTICS_WRITE = "analytics.write" diff --git a/appwrite/enums/project_o_auth2_auth0_prompt.py b/appwrite/enums/project_o_auth2_auth0_prompt.py new file mode 100644 index 00000000..166ec632 --- /dev/null +++ b/appwrite/enums/project_o_auth2_auth0_prompt.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class ProjectOAuth2Auth0Prompt(Enum): + NONE = "none" + LOGIN = "login" + CONSENT = "consent" diff --git a/appwrite/enums/project_o_auth2_discord_prompt.py b/appwrite/enums/project_o_auth2_discord_prompt.py new file mode 100644 index 00000000..7caebc14 --- /dev/null +++ b/appwrite/enums/project_o_auth2_discord_prompt.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class ProjectOAuth2DiscordPrompt(Enum): + NONE = "none" + CONSENT = "consent" diff --git a/appwrite/enums/project_o_auth2_git_hub_prompt.py b/appwrite/enums/project_o_auth2_git_hub_prompt.py new file mode 100644 index 00000000..ba8e9530 --- /dev/null +++ b/appwrite/enums/project_o_auth2_git_hub_prompt.py @@ -0,0 +1,5 @@ +from enum import Enum + + +class ProjectOAuth2GitHubPrompt(Enum): + SELECT_ACCOUNT = "select_account" diff --git a/appwrite/enums/project_o_auth2_kakao_prompt.py b/appwrite/enums/project_o_auth2_kakao_prompt.py new file mode 100644 index 00000000..9805b060 --- /dev/null +++ b/appwrite/enums/project_o_auth2_kakao_prompt.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class ProjectOAuth2KakaoPrompt(Enum): + NONE = "none" + LOGIN = "login" + CREATE = "create" + SELECT_ACCOUNT = "select_account" diff --git a/appwrite/enums/project_o_auth2_microsoft_prompt.py b/appwrite/enums/project_o_auth2_microsoft_prompt.py new file mode 100644 index 00000000..2714e351 --- /dev/null +++ b/appwrite/enums/project_o_auth2_microsoft_prompt.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class ProjectOAuth2MicrosoftPrompt(Enum): + NONE = "none" + LOGIN = "login" + CONSENT = "consent" + SELECT_ACCOUNT = "select_account" diff --git a/appwrite/enums/project_o_auth2_okta_prompt.py b/appwrite/enums/project_o_auth2_okta_prompt.py new file mode 100644 index 00000000..59f35a04 --- /dev/null +++ b/appwrite/enums/project_o_auth2_okta_prompt.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class ProjectOAuth2OktaPrompt(Enum): + NONE = "none" + LOGIN = "login" + CONSENT = "consent" diff --git a/appwrite/enums/project_o_auth2_salesforce_prompt.py b/appwrite/enums/project_o_auth2_salesforce_prompt.py new file mode 100644 index 00000000..f0b43f9a --- /dev/null +++ b/appwrite/enums/project_o_auth2_salesforce_prompt.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class ProjectOAuth2SalesforcePrompt(Enum): + LOGIN = "login" + CONSENT = "consent" diff --git a/appwrite/enums/project_o_auth2_zoho_prompt.py b/appwrite/enums/project_o_auth2_zoho_prompt.py new file mode 100644 index 00000000..c866a245 --- /dev/null +++ b/appwrite/enums/project_o_auth2_zoho_prompt.py @@ -0,0 +1,5 @@ +from enum import Enum + + +class ProjectOAuth2ZohoPrompt(Enum): + CONSENT = "consent" diff --git a/appwrite/enums/project_o_auth_provider_id.py b/appwrite/enums/project_o_auth_provider_id.py index ad47c234..7757a41a 100644 --- a/appwrite/enums/project_o_auth_provider_id.py +++ b/appwrite/enums/project_o_auth_provider_id.py @@ -24,6 +24,7 @@ class ProjectOAuthProviderId(Enum): GITLAB = "gitlab" GOOGLE = "google" HUGGINGFACE = "huggingface" + KAKAO = "kakao" KEYCLOAK = "keycloak" KICK = "kick" LINKEDIN = "linkedin" @@ -39,9 +40,11 @@ class ProjectOAuthProviderId(Enum): SLACK = "slack" SPOTIFY = "spotify" STRIPE = "stripe" + TIKTOK = "tiktok" TRADESHIFT = "tradeshift" TRADESHIFTBOX = "tradeshiftBox" TWITCH = "twitch" + WEBFLOW = "webflow" WORDPRESS = "wordpress" X = "x" YAHOO = "yahoo" diff --git a/appwrite/enums/project_policy_id.py b/appwrite/enums/project_policy_id.py index a3f06435..bc2ce903 100644 --- a/appwrite/enums/project_policy_id.py +++ b/appwrite/enums/project_policy_id.py @@ -6,6 +6,8 @@ class ProjectPolicyId(Enum): PASSWORD_HISTORY = "password-history" PASSWORD_STRENGTH = "password-strength" PASSWORD_PERSONAL_DATA = "password-personal-data" + PASSWORD_PWNED = "password-pwned" + PASSWORD_ROTATION = "password-rotation" SESSION_ALERT = "session-alert" SESSION_DURATION = "session-duration" SESSION_INVALIDATION = "session-invalidation" @@ -17,3 +19,4 @@ class ProjectPolicyId(Enum): DENY_DISPOSABLE_EMAIL = "deny-disposable-email" DENY_FREE_EMAIL = "deny-free-email" DENY_CORPORATE_EMAIL = "deny-corporate-email" + PASSKEY = "passkey" diff --git a/appwrite/enums/proxy_rule_deployment_resource_type.py b/appwrite/enums/proxy_rule_deployment_resource_type.py index 8d525d0c..b0589232 100644 --- a/appwrite/enums/proxy_rule_deployment_resource_type.py +++ b/appwrite/enums/proxy_rule_deployment_resource_type.py @@ -4,3 +4,4 @@ class ProxyRuleDeploymentResourceType(Enum): FUNCTION = "function" SITE = "site" + DEDICATEDDATABASE = "dedicatedDatabase" diff --git a/appwrite/enums/runtime.py b/appwrite/enums/runtime.py index e543e3bb..c7f29dd5 100644 --- a/appwrite/enums/runtime.py +++ b/appwrite/enums/runtime.py @@ -53,6 +53,7 @@ class Runtime(Enum): DART_3_10 = "dart-3.10" DART_3_11 = "dart-3.11" DART_3_12 = "dart-3.12" + DART_3_13 = "dart-3.13" DOTNET_6_0 = "dotnet-6.0" DOTNET_7_0 = "dotnet-7.0" DOTNET_8_0 = "dotnet-8.0" @@ -95,3 +96,4 @@ class Runtime(Enum): FLUTTER_3_38 = "flutter-3.38" FLUTTER_3_41 = "flutter-3.41" FLUTTER_3_44 = "flutter-3.44" + FLUTTER_3_47 = "flutter-3.47" diff --git a/appwrite/enums/waf_rule_action.py b/appwrite/enums/waf_rule_action.py new file mode 100644 index 00000000..516f60e1 --- /dev/null +++ b/appwrite/enums/waf_rule_action.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class WafRuleAction(Enum): + BYPASS = "bypass" + DENY = "deny" + CHALLENGE = "challenge" + RATELIMIT = "rateLimit" + REDIRECT = "redirect" diff --git a/appwrite/models/__init__.py b/appwrite/models/__init__.py index 80ced38d..a38ce820 100644 --- a/appwrite/models/__init__.py +++ b/appwrite/models/__init__.py @@ -10,7 +10,6 @@ from .user_list import UserList from .session_list import SessionList from .identity_list import IdentityList -from .log_list import LogList from .file_list import FileList from .bucket_list import BucketList from .resource_token_list import ResourceTokenList @@ -97,7 +96,6 @@ from .row import Row from .document import Document from .presence import Presence -from .log import Log from .user import User from .algo_md5 import AlgoMd5 from .algo_sha import AlgoSha @@ -106,6 +104,7 @@ from .algo_scrypt import AlgoScrypt from .algo_scrypt_modified import AlgoScryptModified from .algo_argon2 import AlgoArgon2 +from .account import Account from .preferences import Preferences from .session import Session from .identity import Identity @@ -132,7 +131,6 @@ from .webhook import Webhook from .key import Key from .ephemeral_key import EphemeralKey -from .dev_key import DevKey from .mock_number import MockNumber from .o_auth2_github import OAuth2Github from .o_auth2_discord import OAuth2Discord @@ -149,6 +147,7 @@ from .o_auth2_yandex import OAuth2Yandex from .o_auth2_x import OAuth2X from .o_auth2_word_press import OAuth2WordPress +from .o_auth2_webflow import OAuth2Webflow from .o_auth2_twitch import OAuth2Twitch from .o_auth2_stripe import OAuth2Stripe from .o_auth2_spotify import OAuth2Spotify @@ -178,11 +177,15 @@ from .o_auth2_apple import OAuth2Apple from .o_auth2_microsoft import OAuth2Microsoft from .o_auth2_resend import OAuth2Resend +from .o_auth2_tik_tok import OAuth2TikTok +from .o_auth2_kakao import OAuth2Kakao from .o_auth2_provider_list import OAuth2ProviderList from .policy_password_dictionary import PolicyPasswordDictionary from .policy_password_history import PolicyPasswordHistory from .policy_password_strength import PolicyPasswordStrength from .policy_password_personal_data import PolicyPasswordPersonalData +from .policy_password_pwned import PolicyPasswordPwned +from .policy_password_rotation import PolicyPasswordRotation from .policy_session_alert import PolicySessionAlert from .policy_session_duration import PolicySessionDuration from .policy_session_invalidation import PolicySessionInvalidation @@ -190,6 +193,11 @@ from .policy_user_limit import PolicyUserLimit from .policy_membership_privacy import PolicyMembershipPrivacy from .policy_mfa_factors import PolicyMfaFactors +from .policy_passkey import PolicyPasskey +from .policy_deny_aliased_email import PolicyDenyAliasedEmail +from .policy_deny_disposable_email import PolicyDenyDisposableEmail +from .policy_deny_free_email import PolicyDenyFreeEmail +from .policy_deny_corporate_email import PolicyDenyCorporateEmail from .platform_web import PlatformWeb from .platform_apple import PlatformApple from .platform_android import PlatformAndroid @@ -208,6 +216,10 @@ from .email_template import EmailTemplate from .mfa_challenge import MfaChallenge from .mfa_challenge_secret import MfaChallengeSecret +from .token_secret import TokenSecret +from .passkey import Passkey +from .passkey_challenge import PasskeyChallenge +from .passkey_list import PasskeyList from .mfa_recovery_codes import MfaRecoveryCodes from .mfa_type import MfaType from .mfa_factors import MfaFactors @@ -242,6 +254,10 @@ from .dedicated_database_execution_column import DedicatedDatabaseExecutionColumn from .dedicated_database_restoration import DedicatedDatabaseRestoration from .database_status import DatabaseStatus +from .dns_record import DnsRecord +from .domain import Domain +from .domain_price import DomainPrice +from .domain_transfer_status import DomainTransferStatus from .dedicated_database_extensions import DedicatedDatabaseExtensions from .dedicated_database_member import DedicatedDatabaseMember from .dedicated_database_operation import DedicatedDatabaseOperation @@ -251,10 +267,6 @@ from .organization import Organization from .dedicated_database_pitr_windows import DedicatedDatabasePITRWindows from .backup_policy import BackupPolicy -from .policy_deny_aliased_email import PolicyDenyAliasedEmail -from .policy_deny_disposable_email import PolicyDenyDisposableEmail -from .policy_deny_free_email import PolicyDenyFreeEmail -from .policy_deny_corporate_email import PolicyDenyCorporateEmail from .dedicated_database_pooler import DedicatedDatabasePooler from .postgres_extension import PostgresExtension from .program import Program @@ -262,7 +274,6 @@ from .dedicated_database_restoration_list import DedicatedDatabaseRestorationList from .dedicated_database_specification import DedicatedDatabaseSpecification from .dedicated_database_specification_list import DedicatedDatabaseSpecificationList -from .dedicated_database_specification_pricing import DedicatedDatabaseSpecificationPricing from .database_status_connections import DatabaseStatusConnections from .database_status_replica import DatabaseStatusReplica from .database_status_volume import DatabaseStatusVolume @@ -280,8 +291,15 @@ from .oauth2_device_authorization import Oauth2DeviceAuthorization from .oauth2_par import Oauth2PAR from .oauth2_token import Oauth2Token +from .oauth2_introspection import Oauth2Introspection from .oauth2_consent import Oauth2Consent from .oauth2_consent_token import Oauth2ConsentToken +from .waf_rule_bypass import WafRuleBypass +from .waf_rule_deny import WafRuleDeny +from .waf_rule_challenge import WafRuleChallenge +from .waf_rule_rate_limit import WafRuleRateLimit +from .waf_rule_redirect import WafRuleRedirect +from .waf_rule_list import WafRuleList from .oauth2_project import Oauth2Project from .oauth2_organization import Oauth2Organization from .oauth2_project_list import Oauth2ProjectList @@ -294,6 +312,9 @@ from .backup_restoration_list import BackupRestorationList from .database_migration_list import DatabaseMigrationList from .dedicated_database_list import DedicatedDatabaseList +from .dns_records_list import DnsRecordsList +from .domain_prices_list import DomainPricesList +from .domains_list import DomainsList from .apps_list import AppsList from .app_secret_list import AppSecretList from .app_scope_list import AppScopeList @@ -313,7 +334,6 @@ 'UserList', 'SessionList', 'IdentityList', - 'LogList', 'FileList', 'BucketList', 'ResourceTokenList', @@ -400,7 +420,6 @@ 'Row', 'Document', 'Presence', - 'Log', 'User', 'AlgoMd5', 'AlgoSha', @@ -409,6 +428,7 @@ 'AlgoScrypt', 'AlgoScryptModified', 'AlgoArgon2', + 'Account', 'Preferences', 'Session', 'Identity', @@ -435,7 +455,6 @@ 'Webhook', 'Key', 'EphemeralKey', - 'DevKey', 'MockNumber', 'OAuth2Github', 'OAuth2Discord', @@ -452,6 +471,7 @@ 'OAuth2Yandex', 'OAuth2X', 'OAuth2WordPress', + 'OAuth2Webflow', 'OAuth2Twitch', 'OAuth2Stripe', 'OAuth2Spotify', @@ -481,11 +501,15 @@ 'OAuth2Apple', 'OAuth2Microsoft', 'OAuth2Resend', + 'OAuth2TikTok', + 'OAuth2Kakao', 'OAuth2ProviderList', 'PolicyPasswordDictionary', 'PolicyPasswordHistory', 'PolicyPasswordStrength', 'PolicyPasswordPersonalData', + 'PolicyPasswordPwned', + 'PolicyPasswordRotation', 'PolicySessionAlert', 'PolicySessionDuration', 'PolicySessionInvalidation', @@ -493,6 +517,11 @@ 'PolicyUserLimit', 'PolicyMembershipPrivacy', 'PolicyMfaFactors', + 'PolicyPasskey', + 'PolicyDenyAliasedEmail', + 'PolicyDenyDisposableEmail', + 'PolicyDenyFreeEmail', + 'PolicyDenyCorporateEmail', 'PlatformWeb', 'PlatformApple', 'PlatformAndroid', @@ -511,6 +540,10 @@ 'EmailTemplate', 'MfaChallenge', 'MfaChallengeSecret', + 'TokenSecret', + 'Passkey', + 'PasskeyChallenge', + 'PasskeyList', 'MfaRecoveryCodes', 'MfaType', 'MfaFactors', @@ -545,6 +578,10 @@ 'DedicatedDatabaseExecutionColumn', 'DedicatedDatabaseRestoration', 'DatabaseStatus', + 'DnsRecord', + 'Domain', + 'DomainPrice', + 'DomainTransferStatus', 'DedicatedDatabaseExtensions', 'DedicatedDatabaseMember', 'DedicatedDatabaseOperation', @@ -554,10 +591,6 @@ 'Organization', 'DedicatedDatabasePITRWindows', 'BackupPolicy', - 'PolicyDenyAliasedEmail', - 'PolicyDenyDisposableEmail', - 'PolicyDenyFreeEmail', - 'PolicyDenyCorporateEmail', 'DedicatedDatabasePooler', 'PostgresExtension', 'Program', @@ -565,7 +598,6 @@ 'DedicatedDatabaseRestorationList', 'DedicatedDatabaseSpecification', 'DedicatedDatabaseSpecificationList', - 'DedicatedDatabaseSpecificationPricing', 'DatabaseStatusConnections', 'DatabaseStatusReplica', 'DatabaseStatusVolume', @@ -583,8 +615,15 @@ 'Oauth2DeviceAuthorization', 'Oauth2PAR', 'Oauth2Token', + 'Oauth2Introspection', 'Oauth2Consent', 'Oauth2ConsentToken', + 'WafRuleBypass', + 'WafRuleDeny', + 'WafRuleChallenge', + 'WafRuleRateLimit', + 'WafRuleRedirect', + 'WafRuleList', 'Oauth2Project', 'Oauth2Organization', 'Oauth2ProjectList', @@ -597,6 +636,9 @@ 'BackupRestorationList', 'DatabaseMigrationList', 'DedicatedDatabaseList', + 'DnsRecordsList', + 'DomainPricesList', + 'DomainsList', 'AppsList', 'AppSecretList', 'AppScopeList', diff --git a/appwrite/models/account.py b/appwrite/models/account.py new file mode 100644 index 00000000..22c061c2 --- /dev/null +++ b/appwrite/models/account.py @@ -0,0 +1,135 @@ +from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from .preferences import Preferences +from .target import Target + +T = TypeVar('T') + + +class Account(AppwriteModel, Generic[T]): + """ + Account + + Attributes + ---------- + id : str + User ID. + createdat : str + User creation date in ISO 8601 format. + updatedat : str + User update date in ISO 8601 format. + name : str + User name. + registration : str + User registration date in ISO 8601 format. + status : bool + User status. Pass `true` for enabled and `false` for disabled. + labels : List[Any] + Labels for the user. + passwordupdate : str + Password update time in ISO 8601 format. + email : str + User email address. + phone : str + User phone number in E.164 format. + emailverification : bool + Email verification status. + emailcanonical : Optional[str] + Canonical form of the user email address. + emailisfree : Optional[bool] + Whether the user email is from a free email provider. + emailisdisposable : Optional[bool] + Whether the user email is from a disposable email provider. + emailiscorporate : Optional[bool] + Whether the user email is from a corporate domain. + emailiscanonical : Optional[bool] + Whether the user email is in its canonical form. + passwordpwned : Optional[bool] + Whether the password was found in a known data breach the last time it was checked. Null when the password has never been checked. + phoneverification : bool + Phone verification status. + mfa : bool + Multi factor authentication status. + prefs : Preferences[T] + User preferences as a key-value object + targets : List[Target] + A user-owned message receiver. A single user may have multiple e.g. emails, phones, and a browser. Each target is registered with a single provider. + accessedat : str + Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours. + impersonator : Optional[bool] + Whether the user can impersonate other users. + impersonatoruserid : Optional[str] + ID of the original actor performing the impersonation. Present only when the current request is impersonating another user. Internal audit logs attribute the action to this user, while the impersonated target is recorded only in internal audit payload data. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + name: str = Field(..., alias='name') + registration: str = Field(..., alias='registration') + status: bool = Field(..., alias='status') + labels: List[Any] = Field(..., alias='labels') + passwordupdate: str = Field(..., alias='passwordUpdate') + email: str = Field(..., alias='email') + phone: str = Field(..., alias='phone') + emailverification: bool = Field(..., alias='emailVerification') + emailcanonical: Optional[str] = Field(default=None, alias='emailCanonical') + emailisfree: Optional[bool] = Field(default=None, alias='emailIsFree') + emailisdisposable: Optional[bool] = Field(default=None, alias='emailIsDisposable') + emailiscorporate: Optional[bool] = Field(default=None, alias='emailIsCorporate') + emailiscanonical: Optional[bool] = Field(default=None, alias='emailIsCanonical') + passwordpwned: Optional[bool] = Field(default=None, alias='passwordPwned') + phoneverification: bool = Field(..., alias='phoneVerification') + mfa: bool = Field(..., alias='mfa') + prefs: Preferences[T] = Field(..., alias='prefs') + targets: List[Target] = Field(..., alias='targets') + accessedat: str = Field(..., alias='accessedAt') + impersonator: Optional[bool] = Field(default=None, alias='impersonator') + impersonatoruserid: Optional[str] = Field(default=None, alias='impersonatorUserId') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'registration' not in data: + data['registration'] = '' + if 'status' not in data: + data['status'] = True + if 'labels' not in data: + data['labels'] = [] + if 'passwordUpdate' not in data and 'passwordupdate' not in data: + data['passwordUpdate'] = '' + if 'email' not in data: + data['email'] = '' + if 'phone' not in data: + data['phone'] = '' + if 'emailVerification' not in data and 'emailverification' not in data: + data['emailVerification'] = False + if 'phoneVerification' not in data and 'phoneverification' not in data: + data['phoneVerification'] = False + if 'mfa' not in data: + data['mfa'] = False + if 'accessedAt' not in data and 'accessedat' not in data: + data['accessedAt'] = '' + return data + + @classmethod + def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'Account[T]': + """Create Account instance with typed data.""" + instance = cls.model_validate(data) + if 'prefs' in data and data['prefs'] is not None: + instance.prefs = Preferences.with_data(data['prefs'], model_type) + return instance diff --git a/appwrite/models/activity_event.py b/appwrite/models/activity_event.py index d94a171c..69f3b03e 100644 --- a/appwrite/models/activity_event.py +++ b/appwrite/models/activity_event.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -99,3 +99,70 @@ class ActivityEvent(AppwriteModel): hostname: str = Field(..., alias='hostname') sdk: str = Field(..., alias='sdk') sdkversion: str = Field(..., alias='sdkVersion') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'actorType' not in data and 'actortype' not in data: + data['actorType'] = '' + if 'actorId' not in data and 'actorid' not in data: + data['actorId'] = '' + if 'actorEmail' not in data and 'actoremail' not in data: + data['actorEmail'] = '' + if 'actorName' not in data and 'actorname' not in data: + data['actorName'] = '' + if 'resourceParent' not in data and 'resourceparent' not in data: + data['resourceParent'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = '' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'resource' not in data: + data['resource'] = '' + if 'event' not in data: + data['event'] = '' + if 'userAgent' not in data and 'useragent' not in data: + data['userAgent'] = '' + if 'ip' not in data: + data['ip'] = '' + if 'mode' not in data: + data['mode'] = '' + if 'country' not in data: + data['country'] = '' + if 'continentCode' not in data and 'continentcode' not in data: + data['continentCode'] = '' + if 'city' not in data: + data['city'] = '' + if 'subdivisions' not in data: + data['subdivisions'] = '' + if 'isp' not in data: + data['isp'] = '' + if 'autonomousSystemNumber' not in data and 'autonomoussystemnumber' not in data: + data['autonomousSystemNumber'] = '' + if 'autonomousSystemOrganization' not in data and 'autonomoussystemorganization' not in data: + data['autonomousSystemOrganization'] = '' + if 'connectionType' not in data and 'connectiontype' not in data: + data['connectionType'] = '' + if 'connectionUsageType' not in data and 'connectionusagetype' not in data: + data['connectionUsageType'] = '' + if 'connectionOrganization' not in data and 'connectionorganization' not in data: + data['connectionOrganization'] = '' + if 'time' not in data: + data['time'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'hostname' not in data: + data['hostname'] = '' + if 'sdk' not in data: + data['sdk'] = '' + if 'sdkVersion' not in data and 'sdkversion' not in data: + data['sdkVersion'] = '' + return data diff --git a/appwrite/models/activity_event_list.py b/appwrite/models/activity_event_list.py index 017b6ed0..3ac0aaa7 100644 --- a/appwrite/models/activity_event_list.py +++ b/appwrite/models/activity_event_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .activity_event import ActivityEvent @@ -19,3 +19,14 @@ class ActivityEventList(AppwriteModel): total: float = Field(..., alias='total') events: List[ActivityEvent] = Field(..., alias='events') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/additional_resource.py b/appwrite/models/additional_resource.py index 4fc5c0e1..8f51ca8d 100644 --- a/appwrite/models/additional_resource.py +++ b/appwrite/models/additional_resource.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -30,3 +30,24 @@ class AdditionalResource(AppwriteModel): price: float = Field(..., alias='price') value: float = Field(..., alias='value') invoicedesc: str = Field(..., alias='invoiceDesc') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'name' not in data: + data['name'] = '' + if 'unit' not in data: + data['unit'] = '' + if 'currency' not in data: + data['currency'] = '' + if 'price' not in data: + data['price'] = 0 + if 'value' not in data: + data['value'] = 0 + if 'invoiceDesc' not in data and 'invoicedesc' not in data: + data['invoiceDesc'] = '' + return data diff --git a/appwrite/models/algo_argon2.py b/appwrite/models/algo_argon2.py index f219224e..5b87e9e7 100644 --- a/appwrite/models/algo_argon2.py +++ b/appwrite/models/algo_argon2.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class AlgoArgon2(AppwriteModel): memorycost: float = Field(..., alias='memoryCost') timecost: float = Field(..., alias='timeCost') threads: float = Field(..., alias='threads') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'type' not in data: + data['type'] = 'argon2' + if 'memoryCost' not in data and 'memorycost' not in data: + data['memoryCost'] = 0 + if 'timeCost' not in data and 'timecost' not in data: + data['timeCost'] = 0 + if 'threads' not in data: + data['threads'] = 0 + return data diff --git a/appwrite/models/algo_bcrypt.py b/appwrite/models/algo_bcrypt.py index 4fd4c9e3..25a78997 100644 --- a/appwrite/models/algo_bcrypt.py +++ b/appwrite/models/algo_bcrypt.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class AlgoBcrypt(AppwriteModel): """ type: str = Field(..., alias='type') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'type' not in data: + data['type'] = 'bcrypt' + return data diff --git a/appwrite/models/algo_md5.py b/appwrite/models/algo_md5.py index aa7df63f..94c05b5b 100644 --- a/appwrite/models/algo_md5.py +++ b/appwrite/models/algo_md5.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class AlgoMd5(AppwriteModel): """ type: str = Field(..., alias='type') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'type' not in data: + data['type'] = 'md5' + return data diff --git a/appwrite/models/algo_phpass.py b/appwrite/models/algo_phpass.py index 3c55ac51..9006a2c9 100644 --- a/appwrite/models/algo_phpass.py +++ b/appwrite/models/algo_phpass.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class AlgoPhpass(AppwriteModel): """ type: str = Field(..., alias='type') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'type' not in data: + data['type'] = 'phpass' + return data diff --git a/appwrite/models/algo_scrypt.py b/appwrite/models/algo_scrypt.py index 1eb89f7c..9aa8bc05 100644 --- a/appwrite/models/algo_scrypt.py +++ b/appwrite/models/algo_scrypt.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class AlgoScrypt(AppwriteModel): costmemory: float = Field(..., alias='costMemory') costparallel: float = Field(..., alias='costParallel') length: float = Field(..., alias='length') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'type' not in data: + data['type'] = 'scrypt' + if 'costCpu' not in data and 'costcpu' not in data: + data['costCpu'] = 8 + if 'costMemory' not in data and 'costmemory' not in data: + data['costMemory'] = 14 + if 'costParallel' not in data and 'costparallel' not in data: + data['costParallel'] = 1 + if 'length' not in data: + data['length'] = 64 + return data diff --git a/appwrite/models/algo_scrypt_modified.py b/appwrite/models/algo_scrypt_modified.py index 76f96b48..708491ed 100644 --- a/appwrite/models/algo_scrypt_modified.py +++ b/appwrite/models/algo_scrypt_modified.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class AlgoScryptModified(AppwriteModel): salt: str = Field(..., alias='salt') saltseparator: str = Field(..., alias='saltSeparator') signerkey: str = Field(..., alias='signerKey') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'type' not in data: + data['type'] = 'scryptMod' + if 'salt' not in data: + data['salt'] = '' + if 'saltSeparator' not in data and 'saltseparator' not in data: + data['saltSeparator'] = '' + if 'signerKey' not in data and 'signerkey' not in data: + data['signerKey'] = '' + return data diff --git a/appwrite/models/algo_sha.py b/appwrite/models/algo_sha.py index e091c43f..af10ef96 100644 --- a/appwrite/models/algo_sha.py +++ b/appwrite/models/algo_sha.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class AlgoSha(AppwriteModel): """ type: str = Field(..., alias='type') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'type' not in data: + data['type'] = 'sha' + return data diff --git a/appwrite/models/app.py b/appwrite/models/app.py index 570d8681..594c4315 100644 --- a/appwrite/models/app.py +++ b/appwrite/models/app.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .app_secret import AppSecret @@ -91,3 +91,62 @@ class App(AppwriteModel): installationscopes: List[Any] = Field(..., alias='installationScopes') installationredirecturl: str = Field(..., alias='installationRedirectUrl') secrets: List[AppSecret] = Field(..., alias='secrets') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'description' not in data: + data['description'] = '' + if 'clientUri' not in data and 'clienturi' not in data: + data['clientUri'] = '' + if 'logoUri' not in data and 'logouri' not in data: + data['logoUri'] = '' + if 'privacyPolicyUrl' not in data and 'privacypolicyurl' not in data: + data['privacyPolicyUrl'] = '' + if 'termsUrl' not in data and 'termsurl' not in data: + data['termsUrl'] = '' + if 'contacts' not in data: + data['contacts'] = [] + if 'tagline' not in data: + data['tagline'] = '' + if 'tags' not in data: + data['tags'] = [] + if 'labels' not in data: + data['labels'] = [] + if 'images' not in data: + data['images'] = [] + if 'supportUrl' not in data and 'supporturl' not in data: + data['supportUrl'] = '' + if 'dataDeletionUrl' not in data and 'datadeletionurl' not in data: + data['dataDeletionUrl'] = '' + if 'redirectUris' not in data and 'redirecturis' not in data: + data['redirectUris'] = [] + if 'postLogoutRedirectUris' not in data and 'postlogoutredirecturis' not in data: + data['postLogoutRedirectUris'] = [] + if 'enabled' not in data: + data['enabled'] = True + if 'type' not in data: + data['type'] = 'confidential' + if 'deviceFlow' not in data and 'deviceflow' not in data: + data['deviceFlow'] = False + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'installationScopes' not in data and 'installationscopes' not in data: + data['installationScopes'] = [] + if 'installationRedirectUrl' not in data and 'installationredirecturl' not in data: + data['installationRedirectUrl'] = '' + return data diff --git a/appwrite/models/app_installation.py b/appwrite/models/app_installation.py index 5dbfab42..c22e51d4 100644 --- a/appwrite/models/app_installation.py +++ b/appwrite/models/app_installation.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -42,3 +42,30 @@ class AppInstallation(AppwriteModel): createdbyid: str = Field(..., alias='createdById') createdbyname: str = Field(..., alias='createdByName') lastaccessedat: Optional[str] = Field(default=None, alias='lastAccessedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'scopes' not in data: + data['scopes'] = [] + if 'authorizationDetails' not in data and 'authorizationdetails' not in data: + data['authorizationDetails'] = [] + if 'createdById' not in data and 'createdbyid' not in data: + data['createdById'] = '' + if 'createdByName' not in data and 'createdbyname' not in data: + data['createdByName'] = '' + return data diff --git a/appwrite/models/app_installation_list.py b/appwrite/models/app_installation_list.py index eb06054c..b868991e 100644 --- a/appwrite/models/app_installation_list.py +++ b/appwrite/models/app_installation_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .app_installation import AppInstallation @@ -19,3 +19,14 @@ class AppInstallationList(AppwriteModel): total: float = Field(..., alias='total') installations: List[AppInstallation] = Field(..., alias='installations') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/app_key.py b/appwrite/models/app_key.py index 8221aa10..fd4caccd 100644 --- a/appwrite/models/app_key.py +++ b/appwrite/models/app_key.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,28 @@ class AppKey(AppwriteModel): createdbyid: str = Field(..., alias='createdById') createdbyname: str = Field(..., alias='createdByName') lastaccessedat: Optional[str] = Field(default=None, alias='lastAccessedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'secret' not in data: + data['secret'] = '' + if 'hint' not in data: + data['hint'] = '' + if 'createdById' not in data and 'createdbyid' not in data: + data['createdById'] = '' + if 'createdByName' not in data and 'createdbyname' not in data: + data['createdByName'] = '' + return data diff --git a/appwrite/models/app_key_list.py b/appwrite/models/app_key_list.py index 32ecb90c..7388b378 100644 --- a/appwrite/models/app_key_list.py +++ b/appwrite/models/app_key_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .app_key import AppKey @@ -19,3 +19,14 @@ class AppKeyList(AppwriteModel): total: float = Field(..., alias='total') keys: List[AppKey] = Field(..., alias='keys') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/app_scope.py b/appwrite/models/app_scope.py index ee295c5e..fa198925 100644 --- a/appwrite/models/app_scope.py +++ b/appwrite/models/app_scope.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class AppScope(AppwriteModel): type: str = Field(..., alias='type') category: str = Field(..., alias='category') deprecated: bool = Field(..., alias='deprecated') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'value' not in data: + data['value'] = '' + if 'description' not in data: + data['description'] = '' + if 'type' not in data: + data['type'] = '' + if 'category' not in data: + data['category'] = '' + if 'deprecated' not in data: + data['deprecated'] = False + return data diff --git a/appwrite/models/app_scope_list.py b/appwrite/models/app_scope_list.py index ef9484d4..d39e330e 100644 --- a/appwrite/models/app_scope_list.py +++ b/appwrite/models/app_scope_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .app_scope import AppScope @@ -19,3 +19,14 @@ class AppScopeList(AppwriteModel): total: float = Field(..., alias='total') scopes: List[AppScope] = Field(..., alias='scopes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/app_secret.py b/appwrite/models/app_secret.py index 2e2b8d49..41c1052f 100644 --- a/appwrite/models/app_secret.py +++ b/appwrite/models/app_secret.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,28 @@ class AppSecret(AppwriteModel): createdbyid: str = Field(..., alias='createdById') createdbyname: str = Field(..., alias='createdByName') lastaccessedat: Optional[str] = Field(default=None, alias='lastAccessedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'secret' not in data: + data['secret'] = '' + if 'hint' not in data: + data['hint'] = '' + if 'createdById' not in data and 'createdbyid' not in data: + data['createdById'] = '' + if 'createdByName' not in data and 'createdbyname' not in data: + data['createdByName'] = '' + return data diff --git a/appwrite/models/app_secret_list.py b/appwrite/models/app_secret_list.py index 6b248dba..a4ae14cd 100644 --- a/appwrite/models/app_secret_list.py +++ b/appwrite/models/app_secret_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .app_secret import AppSecret @@ -19,3 +19,14 @@ class AppSecretList(AppwriteModel): total: float = Field(..., alias='total') secrets: List[AppSecret] = Field(..., alias='secrets') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/app_secret_plaintext.py b/appwrite/models/app_secret_plaintext.py index 6b7299b2..0b06766c 100644 --- a/appwrite/models/app_secret_plaintext.py +++ b/appwrite/models/app_secret_plaintext.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,28 @@ class AppSecretPlaintext(AppwriteModel): createdbyid: str = Field(..., alias='createdById') createdbyname: str = Field(..., alias='createdByName') lastaccessedat: Optional[str] = Field(default=None, alias='lastAccessedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'secret' not in data: + data['secret'] = '' + if 'hint' not in data: + data['hint'] = '' + if 'createdById' not in data and 'createdbyid' not in data: + data['createdById'] = '' + if 'createdByName' not in data and 'createdbyname' not in data: + data['createdByName'] = '' + return data diff --git a/appwrite/models/apps_list.py b/appwrite/models/apps_list.py index 965805a6..319c6662 100644 --- a/appwrite/models/apps_list.py +++ b/appwrite/models/apps_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .app import App @@ -19,3 +19,14 @@ class AppsList(AppwriteModel): total: float = Field(..., alias='total') apps: List[App] = Field(..., alias='apps') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/attribute_bigint.py b/appwrite/models/attribute_bigint.py index 5ceedae3..474812db 100644 --- a/appwrite/models/attribute_bigint.py +++ b/appwrite/models/attribute_bigint.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -46,3 +46,24 @@ class AttributeBigint(AppwriteModel): min: Optional[float] = Field(default=None, alias='min') max: Optional[float] = Field(default=None, alias='max') default: Optional[float] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_boolean.py b/appwrite/models/attribute_boolean.py index bca29adc..7ce326cb 100644 --- a/appwrite/models/attribute_boolean.py +++ b/appwrite/models/attribute_boolean.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -40,3 +40,24 @@ class AttributeBoolean(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') default: Optional[bool] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_datetime.py b/appwrite/models/attribute_datetime.py index 40c7d492..cad6726b 100644 --- a/appwrite/models/attribute_datetime.py +++ b/appwrite/models/attribute_datetime.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -43,3 +43,24 @@ class AttributeDatetime(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_email.py b/appwrite/models/attribute_email.py index 15a5dcd8..4e3c33f6 100644 --- a/appwrite/models/attribute_email.py +++ b/appwrite/models/attribute_email.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -43,3 +43,26 @@ class AttributeEmail(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'format' not in data: + data['format'] = 'email' + return data diff --git a/appwrite/models/attribute_enum.py b/appwrite/models/attribute_enum.py index 275abd2f..8b406137 100644 --- a/appwrite/models/attribute_enum.py +++ b/appwrite/models/attribute_enum.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -46,3 +46,26 @@ class AttributeEnum(AppwriteModel): elements: List[Any] = Field(..., alias='elements') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'format' not in data: + data['format'] = 'enum' + return data diff --git a/appwrite/models/attribute_float.py b/appwrite/models/attribute_float.py index 5b989c16..209b42e8 100644 --- a/appwrite/models/attribute_float.py +++ b/appwrite/models/attribute_float.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -46,3 +46,24 @@ class AttributeFloat(AppwriteModel): min: Optional[float] = Field(default=None, alias='min') max: Optional[float] = Field(default=None, alias='max') default: Optional[float] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_integer.py b/appwrite/models/attribute_integer.py index 586d41b5..f268bb23 100644 --- a/appwrite/models/attribute_integer.py +++ b/appwrite/models/attribute_integer.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -46,3 +46,24 @@ class AttributeInteger(AppwriteModel): min: Optional[float] = Field(default=None, alias='min') max: Optional[float] = Field(default=None, alias='max') default: Optional[float] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_ip.py b/appwrite/models/attribute_ip.py index 13737149..9b334968 100644 --- a/appwrite/models/attribute_ip.py +++ b/appwrite/models/attribute_ip.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -43,3 +43,26 @@ class AttributeIp(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'format' not in data: + data['format'] = 'ip' + return data diff --git a/appwrite/models/attribute_line.py b/appwrite/models/attribute_line.py index 4e0982d4..4fbcba35 100644 --- a/appwrite/models/attribute_line.py +++ b/appwrite/models/attribute_line.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -40,3 +40,24 @@ class AttributeLine(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') default: Optional[List[Any]] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_list.py b/appwrite/models/attribute_list.py index b631a4d6..f26f0ce5 100644 --- a/appwrite/models/attribute_list.py +++ b/appwrite/models/attribute_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .attribute_boolean import AttributeBoolean @@ -57,3 +57,14 @@ class AttributeList(AppwriteModel): AttributeString, ] ] = Field(..., alias='attributes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/attribute_longtext.py b/appwrite/models/attribute_longtext.py index cc03d9cf..fa45bfc5 100644 --- a/appwrite/models/attribute_longtext.py +++ b/appwrite/models/attribute_longtext.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -43,3 +43,24 @@ class AttributeLongtext(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_mediumtext.py b/appwrite/models/attribute_mediumtext.py index 40404d23..59c8ee3f 100644 --- a/appwrite/models/attribute_mediumtext.py +++ b/appwrite/models/attribute_mediumtext.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -43,3 +43,24 @@ class AttributeMediumtext(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_object.py b/appwrite/models/attribute_object.py index c79160bf..16e736dd 100644 --- a/appwrite/models/attribute_object.py +++ b/appwrite/models/attribute_object.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -37,3 +37,24 @@ class AttributeObject(AppwriteModel): array: Optional[bool] = Field(default=None, alias='array') createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_point.py b/appwrite/models/attribute_point.py index c658fdf4..15c1d931 100644 --- a/appwrite/models/attribute_point.py +++ b/appwrite/models/attribute_point.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -40,3 +40,24 @@ class AttributePoint(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') default: Optional[List[Any]] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_polygon.py b/appwrite/models/attribute_polygon.py index 79ca2978..7d669d70 100644 --- a/appwrite/models/attribute_polygon.py +++ b/appwrite/models/attribute_polygon.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -40,3 +40,24 @@ class AttributePolygon(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') default: Optional[List[Any]] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_relationship.py b/appwrite/models/attribute_relationship.py index 540e6e88..fc549373 100644 --- a/appwrite/models/attribute_relationship.py +++ b/appwrite/models/attribute_relationship.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -55,3 +55,34 @@ class AttributeRelationship(AppwriteModel): twowaykey: str = Field(..., alias='twoWayKey') ondelete: str = Field(..., alias='onDelete') side: str = Field(..., alias='side') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'relationType' not in data and 'relationtype' not in data: + data['relationType'] = '' + if 'twoWay' not in data and 'twoway' not in data: + data['twoWay'] = False + if 'twoWayKey' not in data and 'twowaykey' not in data: + data['twoWayKey'] = '' + if 'onDelete' not in data and 'ondelete' not in data: + data['onDelete'] = 'restrict' + if 'side' not in data: + data['side'] = '' + return data diff --git a/appwrite/models/attribute_string.py b/appwrite/models/attribute_string.py index e1d101a7..7cca07a0 100644 --- a/appwrite/models/attribute_string.py +++ b/appwrite/models/attribute_string.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -46,3 +46,26 @@ class AttributeString(AppwriteModel): size: float = Field(..., alias='size') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'size' not in data: + data['size'] = 0 + return data diff --git a/appwrite/models/attribute_text.py b/appwrite/models/attribute_text.py index e819094d..b66f2a50 100644 --- a/appwrite/models/attribute_text.py +++ b/appwrite/models/attribute_text.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -43,3 +43,24 @@ class AttributeText(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/attribute_url.py b/appwrite/models/attribute_url.py index eb4fe4f6..50ad0ffe 100644 --- a/appwrite/models/attribute_url.py +++ b/appwrite/models/attribute_url.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -43,3 +43,26 @@ class AttributeUrl(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'format' not in data: + data['format'] = 'url' + return data diff --git a/appwrite/models/attribute_varchar.py b/appwrite/models/attribute_varchar.py index 47fdb2fb..65b806c2 100644 --- a/appwrite/models/attribute_varchar.py +++ b/appwrite/models/attribute_varchar.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -46,3 +46,26 @@ class AttributeVarchar(AppwriteModel): size: float = Field(..., alias='size') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'size' not in data: + data['size'] = 0 + return data diff --git a/appwrite/models/attribute_vector.py b/appwrite/models/attribute_vector.py index 4bcac94c..1b1d921d 100644 --- a/appwrite/models/attribute_vector.py +++ b/appwrite/models/attribute_vector.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.attribute_status import AttributeStatus @@ -40,3 +40,26 @@ class AttributeVector(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') size: float = Field(..., alias='size') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'size' not in data: + data['size'] = 0 + return data diff --git a/appwrite/models/backup_archive.py b/appwrite/models/backup_archive.py index 060ea93c..00c1f235 100644 --- a/appwrite/models/backup_archive.py +++ b/appwrite/models/backup_archive.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,12 +18,12 @@ class BackupArchive(AppwriteModel): Archive update date in ISO 8601 format. policyid : str Archive policy ID. - size : float - Archive size in bytes. + size : Optional[float] + Archive size in bytes. Null until the size is known. status : str The status of the archive creation. Possible values: pending, processing, uploading, completed, failed, skipped. - startedat : str - The backup start time. + startedat : Optional[str] + The backup start time. Null until the backup starts. migrationid : str Migration ID. services : List[Any] @@ -40,11 +40,32 @@ class BackupArchive(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') policyid: str = Field(..., alias='policyId') - size: float = Field(..., alias='size') + size: Optional[float] = Field(default=None, alias='size') status: str = Field(..., alias='status') - startedat: str = Field(..., alias='startedAt') + startedat: Optional[str] = Field(default=None, alias='startedAt') migrationid: str = Field(..., alias='migrationId') services: List[Any] = Field(..., alias='services') resources: List[Any] = Field(..., alias='resources') resourceid: Optional[str] = Field(default=None, alias='resourceId') resourcetype: Optional[str] = Field(default=None, alias='resourceType') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'policyId' not in data and 'policyid' not in data: + data['policyId'] = '' + if 'status' not in data: + data['status'] = '' + if 'migrationId' not in data and 'migrationid' not in data: + data['migrationId'] = '' + return data diff --git a/appwrite/models/backup_archive_list.py b/appwrite/models/backup_archive_list.py index da2f9f2b..32ee0cf3 100644 --- a/appwrite/models/backup_archive_list.py +++ b/appwrite/models/backup_archive_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .backup_archive import BackupArchive @@ -19,3 +19,14 @@ class BackupArchiveList(AppwriteModel): total: float = Field(..., alias='total') archives: List[BackupArchive] = Field(..., alias='archives') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/backup_policy.py b/appwrite/models/backup_policy.py index b98ecf27..ce1c9f28 100644 --- a/appwrite/models/backup_policy.py +++ b/appwrite/models/backup_policy.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -48,3 +48,28 @@ class BackupPolicy(AppwriteModel): schedule: str = Field(..., alias='schedule') type: str = Field(..., alias='type') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'name' not in data: + data['name'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'retention' not in data: + data['retention'] = 1 + if 'schedule' not in data: + data['schedule'] = '0 * * * *' + if 'type' not in data: + data['type'] = 'full' + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/backup_policy_list.py b/appwrite/models/backup_policy_list.py index 3e6901a6..a5ba03d4 100644 --- a/appwrite/models/backup_policy_list.py +++ b/appwrite/models/backup_policy_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .backup_policy import BackupPolicy @@ -19,3 +19,14 @@ class BackupPolicyList(AppwriteModel): total: float = Field(..., alias='total') policies: List[BackupPolicy] = Field(..., alias='policies') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/backup_restoration.py b/appwrite/models/backup_restoration.py index c00fe712..e4e1ffe1 100644 --- a/appwrite/models/backup_restoration.py +++ b/appwrite/models/backup_restoration.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -22,16 +22,16 @@ class BackupRestoration(AppwriteModel): Backup policy ID. status : str The status of the restoration. Possible values: pending, downloading, processing, completed, failed. - startedat : str - The backup start time. + startedat : Optional[str] + The restoration start time. Null until the restoration starts. migrationid : str Migration ID. services : List[Any] The services that are backed up by this policy. resources : List[Any] The resources that are backed up by this policy. - options : str - Optional data in key-value object. + options : Dict[str, Any] + Restoration options as a key-value object. """ id: str = Field(..., alias='$id') @@ -40,8 +40,33 @@ class BackupRestoration(AppwriteModel): archiveid: str = Field(..., alias='archiveId') policyid: str = Field(..., alias='policyId') status: str = Field(..., alias='status') - startedat: str = Field(..., alias='startedAt') + startedat: Optional[str] = Field(default=None, alias='startedAt') migrationid: str = Field(..., alias='migrationId') services: List[Any] = Field(..., alias='services') resources: List[Any] = Field(..., alias='resources') - options: str = Field(..., alias='options') + options: Dict[str, Any] = Field(..., alias='options') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'archiveId' not in data and 'archiveid' not in data: + data['archiveId'] = '' + if 'policyId' not in data and 'policyid' not in data: + data['policyId'] = '' + if 'status' not in data: + data['status'] = '' + if 'migrationId' not in data and 'migrationid' not in data: + data['migrationId'] = '' + if 'options' not in data: + data['options'] = [] + return data diff --git a/appwrite/models/backup_restoration_list.py b/appwrite/models/backup_restoration_list.py index 53e57497..0a1cb45b 100644 --- a/appwrite/models/backup_restoration_list.py +++ b/appwrite/models/backup_restoration_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .backup_restoration import BackupRestoration @@ -19,3 +19,14 @@ class BackupRestorationList(AppwriteModel): total: float = Field(..., alias='total') restorations: List[BackupRestoration] = Field(..., alias='restorations') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/billing_plan.py b/appwrite/models/billing_plan.py index a167b8e6..9960a58b 100644 --- a/appwrite/models/billing_plan.py +++ b/appwrite/models/billing_plan.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .usage_billing_plan import UsageBillingPlan @@ -97,8 +97,8 @@ class BillingPlan(AppwriteModel): Number of days of console inactivity before a project is paused. 0 means pausing is disabled. alertlimit : float Alert threshold percentage - usage : UsageBillingPlan - Additional resources + usage : Optional[UsageBillingPlan] + Additional resources. Null when the plan does not support usage billing. addons : BillingPlanAddon Addons budgetcapenabled : bool @@ -111,6 +111,8 @@ class BillingPlan(AppwriteModel): Does plan require payment method requiresbillingaddress : bool Does plan require billing address + eligiblecountries : Optional[List[Any]] + ISO country codes eligible for this regional plan. Empty means no restriction. isavailable : bool Is the billing plan available selfservice : bool @@ -205,13 +207,14 @@ class BillingPlan(AppwriteModel): usageaggregateonlymetrics: Optional[List[Any]] = Field(default=None, alias='usageAggregateOnlyMetrics') projectinactivitydays: float = Field(..., alias='projectInactivityDays') alertlimit: float = Field(..., alias='alertLimit') - usage: UsageBillingPlan = Field(..., alias='usage') + usage: Optional[UsageBillingPlan] = Field(default=None, alias='usage') addons: BillingPlanAddon = Field(..., alias='addons') budgetcapenabled: bool = Field(..., alias='budgetCapEnabled') customsmtp: bool = Field(..., alias='customSmtp') emailbranding: bool = Field(..., alias='emailBranding') requirespaymentmethod: bool = Field(..., alias='requiresPaymentMethod') requiresbillingaddress: bool = Field(..., alias='requiresBillingAddress') + eligiblecountries: Optional[List[Any]] = Field(default=None, alias='eligibleCountries') isavailable: bool = Field(..., alias='isAvailable') selfservice: bool = Field(..., alias='selfService') premiumsupport: bool = Field(..., alias='premiumSupport') @@ -238,3 +241,132 @@ class BillingPlan(AppwriteModel): program: Optional[Program] = Field(default=None, alias='program') databasecomputecredit: float = Field(..., alias='databaseComputeCredit') dedicateddatabases: Optional[BillingPlanDedicatedDatabaseLimits] = Field(default=None, alias='dedicatedDatabases') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'name' not in data: + data['name'] = '' + if 'desc' not in data: + data['desc'] = '' + if 'order' not in data: + data['order'] = 0 + if 'price' not in data: + data['price'] = 0 + if 'trial' not in data: + data['trial'] = 0 + if 'bandwidth' not in data: + data['bandwidth'] = 0 + if 'storage' not in data: + data['storage'] = 0 + if 'imageTransformations' not in data and 'imagetransformations' not in data: + data['imageTransformations'] = 0 + if 'screenshotsGenerated' not in data and 'screenshotsgenerated' not in data: + data['screenshotsGenerated'] = 0 + if 'webhooks' not in data: + data['webhooks'] = 0 + if 'wafRules' not in data and 'wafrules' not in data: + data['wafRules'] = 0 + if 'projects' not in data: + data['projects'] = 0 + if 'platforms' not in data: + data['platforms'] = 0 + if 'users' not in data: + data['users'] = 0 + if 'teams' not in data: + data['teams'] = 0 + if 'databases' not in data: + data['databases'] = 0 + if 'databasesReads' not in data and 'databasesreads' not in data: + data['databasesReads'] = 0 + if 'databasesWrites' not in data and 'databaseswrites' not in data: + data['databasesWrites'] = 0 + if 'databasesBatchSize' not in data and 'databasesbatchsize' not in data: + data['databasesBatchSize'] = 0 + if 'buckets' not in data: + data['buckets'] = 0 + if 'fileSize' not in data and 'filesize' not in data: + data['fileSize'] = 0 + if 'functions' not in data: + data['functions'] = 0 + if 'sites' not in data: + data['sites'] = 0 + if 'executions' not in data: + data['executions'] = 0 + if 'executionsRetentionCount' not in data and 'executionsretentioncount' not in data: + data['executionsRetentionCount'] = 1000 + if 'GBHours' not in data and 'gbhours' not in data: + data['GBHours'] = 0 + if 'realtime' not in data: + data['realtime'] = 0 + if 'realtimeMessages' not in data and 'realtimemessages' not in data: + data['realtimeMessages'] = 0 + if 'messages' not in data: + data['messages'] = 0 + if 'topics' not in data: + data['topics'] = 0 + if 'authPhone' not in data and 'authphone' not in data: + data['authPhone'] = 0 + if 'domains' not in data: + data['domains'] = 0 + if 'usageLogs' not in data and 'usagelogs' not in data: + data['usageLogs'] = 0 + if 'projectInactivityDays' not in data and 'projectinactivitydays' not in data: + data['projectInactivityDays'] = 0 + if 'alertLimit' not in data and 'alertlimit' not in data: + data['alertLimit'] = 80 + if 'budgetCapEnabled' not in data and 'budgetcapenabled' not in data: + data['budgetCapEnabled'] = False + if 'customSmtp' not in data and 'customsmtp' not in data: + data['customSmtp'] = False + if 'emailBranding' not in data and 'emailbranding' not in data: + data['emailBranding'] = False + if 'requiresPaymentMethod' not in data and 'requirespaymentmethod' not in data: + data['requiresPaymentMethod'] = True + if 'requiresBillingAddress' not in data and 'requiresbillingaddress' not in data: + data['requiresBillingAddress'] = False + if 'isAvailable' not in data and 'isavailable' not in data: + data['isAvailable'] = True + if 'selfService' not in data and 'selfservice' not in data: + data['selfService'] = True + if 'premiumSupport' not in data and 'premiumsupport' not in data: + data['premiumSupport'] = True + if 'budgeting' not in data: + data['budgeting'] = True + if 'supportsMockNumbers' not in data and 'supportsmocknumbers' not in data: + data['supportsMockNumbers'] = True + if 'supportsOrganizationRoles' not in data and 'supportsorganizationroles' not in data: + data['supportsOrganizationRoles'] = True + if 'supportsCredits' not in data and 'supportscredits' not in data: + data['supportsCredits'] = False + if 'supportsDedicatedDatabases' not in data and 'supportsdedicateddatabases' not in data: + data['supportsDedicatedDatabases'] = False + if 'supportsDisposableEmailValidation' not in data and 'supportsdisposableemailvalidation' not in data: + data['supportsDisposableEmailValidation'] = False + if 'supportsCanonicalEmailValidation' not in data and 'supportscanonicalemailvalidation' not in data: + data['supportsCanonicalEmailValidation'] = False + if 'supportsFreeEmailValidation' not in data and 'supportsfreeemailvalidation' not in data: + data['supportsFreeEmailValidation'] = False + if 'supportsCorporateEmailValidation' not in data and 'supportscorporateemailvalidation' not in data: + data['supportsCorporateEmailValidation'] = False + if 'supportsProjectSpecificRoles' not in data and 'supportsprojectspecificroles' not in data: + data['supportsProjectSpecificRoles'] = False + if 'usagePerProject' not in data and 'usageperproject' not in data: + data['usagePerProject'] = True + if 'deploymentSize' not in data and 'deploymentsize' not in data: + data['deploymentSize'] = 0 + if 'buildSize' not in data and 'buildsize' not in data: + data['buildSize'] = 0 + if 'functionsIntervalMinimum' not in data and 'functionsintervalminimum' not in data: + data['functionsIntervalMinimum'] = 0 + if 'databasesAllowEncrypt' not in data and 'databasesallowencrypt' not in data: + data['databasesAllowEncrypt'] = False + if 'databaseComputeCredit' not in data and 'databasecomputecredit' not in data: + data['databaseComputeCredit'] = 0 + return data diff --git a/appwrite/models/billing_plan_addon_details.py b/appwrite/models/billing_plan_addon_details.py index 8d7591f1..e499f40c 100644 --- a/appwrite/models/billing_plan_addon_details.py +++ b/appwrite/models/billing_plan_addon_details.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -36,3 +36,26 @@ class BillingPlanAddonDetails(AppwriteModel): price: float = Field(..., alias='price') value: float = Field(..., alias='value') invoicedesc: str = Field(..., alias='invoiceDesc') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'supported' not in data: + data['supported'] = False + if 'planIncluded' not in data and 'planincluded' not in data: + data['planIncluded'] = 0 + if 'limit' not in data: + data['limit'] = 0 + if 'type' not in data: + data['type'] = 'numeric' + if 'price' not in data: + data['price'] = 0 + if 'value' not in data: + data['value'] = 0 + if 'invoiceDesc' not in data and 'invoicedesc' not in data: + data['invoiceDesc'] = '' + return data diff --git a/appwrite/models/billing_plan_supported_addons.py b/appwrite/models/billing_plan_supported_addons.py index 756a37e1..39ef9544 100644 --- a/appwrite/models/billing_plan_supported_addons.py +++ b/appwrite/models/billing_plan_supported_addons.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -21,3 +21,18 @@ class BillingPlanSupportedAddons(AppwriteModel): baa: bool = Field(..., alias='baa') premiumgeodb: bool = Field(..., alias='premiumGeoDB') premiumgeodborg: bool = Field(..., alias='premiumGeoDBOrg') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'baa' not in data: + data['baa'] = False + if 'premiumGeoDB' not in data and 'premiumgeodb' not in data: + data['premiumGeoDB'] = False + if 'premiumGeoDBOrg' not in data and 'premiumgeodborg' not in data: + data['premiumGeoDBOrg'] = False + return data diff --git a/appwrite/models/block.py b/appwrite/models/block.py index fdc801cc..94669353 100644 --- a/appwrite/models/block.py +++ b/appwrite/models/block.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,30 +18,29 @@ class Block(AppwriteModel): Resource identifier that is blocked mode : str Block mode. full blocks reads and writes; readOnly blocks writes only. - reason : Optional[str] - Reason for the block. Can be null if no reason was provided. expiredat : Optional[str] Block expiration date in ISO 8601 format. Can be null if the block does not expire. - projectname : str - Name of the project this block applies to. - region : str - Region of the project this block applies to. - organizationname : str - Name of the organization that owns the project. - organizationid : str - ID of the organization that owns the project. - billingplan : str - Billing plan of the organization that owns the project. """ createdat: str = Field(..., alias='$createdAt') resourcetype: str = Field(..., alias='resourceType') resourceid: str = Field(..., alias='resourceId') mode: str = Field(..., alias='mode') - reason: Optional[str] = Field(default=None, alias='reason') expiredat: Optional[str] = Field(default=None, alias='expiredAt') - projectname: str = Field(..., alias='projectName') - region: str = Field(..., alias='region') - organizationname: str = Field(..., alias='organizationName') - organizationid: str = Field(..., alias='organizationId') - billingplan: str = Field(..., alias='billingPlan') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = '' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'mode' not in data: + data['mode'] = 'full' + return data diff --git a/appwrite/models/bucket.py b/appwrite/models/bucket.py index 7aafabf8..7718a57d 100644 --- a/appwrite/models/bucket.py +++ b/appwrite/models/bucket.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -54,3 +54,40 @@ class Bucket(AppwriteModel): antivirus: bool = Field(..., alias='antivirus') transformations: bool = Field(..., alias='transformations') totalsize: float = Field(..., alias='totalSize') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if '$permissions' not in data and 'permissions' not in data: + data['$permissions'] = [] + if 'fileSecurity' not in data and 'filesecurity' not in data: + data['fileSecurity'] = False + if 'name' not in data: + data['name'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'maximumFileSize' not in data and 'maximumfilesize' not in data: + data['maximumFileSize'] = 0 + if 'allowedFileExtensions' not in data and 'allowedfileextensions' not in data: + data['allowedFileExtensions'] = [] + if 'compression' not in data: + data['compression'] = '' + if 'encryption' not in data: + data['encryption'] = True + if 'antivirus' not in data: + data['antivirus'] = True + if 'transformations' not in data: + data['transformations'] = True + if 'totalSize' not in data and 'totalsize' not in data: + data['totalSize'] = 0 + return data diff --git a/appwrite/models/bucket_list.py b/appwrite/models/bucket_list.py index 3191bd45..b41de0e5 100644 --- a/appwrite/models/bucket_list.py +++ b/appwrite/models/bucket_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .bucket import Bucket @@ -19,3 +19,14 @@ class BucketList(AppwriteModel): total: float = Field(..., alias='total') buckets: List[Bucket] = Field(..., alias='buckets') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/collection.py b/appwrite/models/collection.py index ab344ebc..c2d58e9a 100644 --- a/appwrite/models/collection.py +++ b/appwrite/models/collection.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .attribute_boolean import AttributeBoolean @@ -88,3 +88,30 @@ class Collection(AppwriteModel): indexes: List[Index] = Field(..., alias='indexes') bytesmax: float = Field(..., alias='bytesMax') bytesused: float = Field(..., alias='bytesUsed') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'databaseId' not in data and 'databaseid' not in data: + data['databaseId'] = '' + if 'name' not in data: + data['name'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'documentSecurity' not in data and 'documentsecurity' not in data: + data['documentSecurity'] = False + if 'bytesMax' not in data and 'bytesmax' not in data: + data['bytesMax'] = 0 + if 'bytesUsed' not in data and 'bytesused' not in data: + data['bytesUsed'] = 0 + return data diff --git a/appwrite/models/collection_list.py b/appwrite/models/collection_list.py index 87db81ed..a7c0f3bf 100644 --- a/appwrite/models/collection_list.py +++ b/appwrite/models/collection_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .collection import Collection @@ -19,3 +19,14 @@ class CollectionList(AppwriteModel): total: float = Field(..., alias='total') collections: List[Collection] = Field(..., alias='collections') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/column_bigint.py b/appwrite/models/column_bigint.py index e69b46f3..b2fa8225 100644 --- a/appwrite/models/column_bigint.py +++ b/appwrite/models/column_bigint.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -46,3 +46,24 @@ class ColumnBigint(AppwriteModel): min: Optional[float] = Field(default=None, alias='min') max: Optional[float] = Field(default=None, alias='max') default: Optional[float] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_boolean.py b/appwrite/models/column_boolean.py index 0c760ff3..33ebd132 100644 --- a/appwrite/models/column_boolean.py +++ b/appwrite/models/column_boolean.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -40,3 +40,24 @@ class ColumnBoolean(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') default: Optional[bool] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_datetime.py b/appwrite/models/column_datetime.py index eb06acff..46c1d04a 100644 --- a/appwrite/models/column_datetime.py +++ b/appwrite/models/column_datetime.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -43,3 +43,24 @@ class ColumnDatetime(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_email.py b/appwrite/models/column_email.py index 2cb80040..68094615 100644 --- a/appwrite/models/column_email.py +++ b/appwrite/models/column_email.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -43,3 +43,26 @@ class ColumnEmail(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'format' not in data: + data['format'] = 'email' + return data diff --git a/appwrite/models/column_enum.py b/appwrite/models/column_enum.py index cd3a3348..571fae02 100644 --- a/appwrite/models/column_enum.py +++ b/appwrite/models/column_enum.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -46,3 +46,26 @@ class ColumnEnum(AppwriteModel): elements: List[Any] = Field(..., alias='elements') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'format' not in data: + data['format'] = 'enum' + return data diff --git a/appwrite/models/column_float.py b/appwrite/models/column_float.py index c229043c..aa089000 100644 --- a/appwrite/models/column_float.py +++ b/appwrite/models/column_float.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -46,3 +46,24 @@ class ColumnFloat(AppwriteModel): min: Optional[float] = Field(default=None, alias='min') max: Optional[float] = Field(default=None, alias='max') default: Optional[float] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_index.py b/appwrite/models/column_index.py index 91ba84b7..54419edf 100644 --- a/appwrite/models/column_index.py +++ b/appwrite/models/column_index.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -42,3 +42,30 @@ class ColumnIndex(AppwriteModel): columns: List[Any] = Field(..., alias='columns') lengths: List[Any] = Field(..., alias='lengths') orders: Optional[List[Any]] = Field(default=None, alias='orders') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'status' not in data: + data['status'] = '' + if 'error' not in data: + data['error'] = '' + if 'columns' not in data: + data['columns'] = [] + if 'lengths' not in data: + data['lengths'] = [] + return data diff --git a/appwrite/models/column_index_list.py b/appwrite/models/column_index_list.py index 3e3cdfdb..8106f5c4 100644 --- a/appwrite/models/column_index_list.py +++ b/appwrite/models/column_index_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .column_index import ColumnIndex @@ -19,3 +19,14 @@ class ColumnIndexList(AppwriteModel): total: float = Field(..., alias='total') indexes: List[ColumnIndex] = Field(..., alias='indexes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/column_integer.py b/appwrite/models/column_integer.py index f5282bc7..9ad8fbd4 100644 --- a/appwrite/models/column_integer.py +++ b/appwrite/models/column_integer.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -46,3 +46,24 @@ class ColumnInteger(AppwriteModel): min: Optional[float] = Field(default=None, alias='min') max: Optional[float] = Field(default=None, alias='max') default: Optional[float] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_ip.py b/appwrite/models/column_ip.py index d9c006ae..fe5de6b6 100644 --- a/appwrite/models/column_ip.py +++ b/appwrite/models/column_ip.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -43,3 +43,26 @@ class ColumnIp(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'format' not in data: + data['format'] = 'ip' + return data diff --git a/appwrite/models/column_line.py b/appwrite/models/column_line.py index a7451f5d..0216047f 100644 --- a/appwrite/models/column_line.py +++ b/appwrite/models/column_line.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -40,3 +40,24 @@ class ColumnLine(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') default: Optional[List[Any]] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_list.py b/appwrite/models/column_list.py index bc464e88..996fdfb2 100644 --- a/appwrite/models/column_list.py +++ b/appwrite/models/column_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .column_boolean import ColumnBoolean @@ -57,3 +57,14 @@ class ColumnList(AppwriteModel): ColumnString, ] ] = Field(..., alias='columns') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/column_longtext.py b/appwrite/models/column_longtext.py index 6df8a506..ce3585fd 100644 --- a/appwrite/models/column_longtext.py +++ b/appwrite/models/column_longtext.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -43,3 +43,24 @@ class ColumnLongtext(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_mediumtext.py b/appwrite/models/column_mediumtext.py index 6c6f0235..31717475 100644 --- a/appwrite/models/column_mediumtext.py +++ b/appwrite/models/column_mediumtext.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -43,3 +43,24 @@ class ColumnMediumtext(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_point.py b/appwrite/models/column_point.py index 3ca81d01..0217c08e 100644 --- a/appwrite/models/column_point.py +++ b/appwrite/models/column_point.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -40,3 +40,24 @@ class ColumnPoint(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') default: Optional[List[Any]] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_polygon.py b/appwrite/models/column_polygon.py index 172d7628..3bcc61c9 100644 --- a/appwrite/models/column_polygon.py +++ b/appwrite/models/column_polygon.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -40,3 +40,24 @@ class ColumnPolygon(AppwriteModel): createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') default: Optional[List[Any]] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_relationship.py b/appwrite/models/column_relationship.py index 32a6da3a..5b1f96b9 100644 --- a/appwrite/models/column_relationship.py +++ b/appwrite/models/column_relationship.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -55,3 +55,34 @@ class ColumnRelationship(AppwriteModel): twowaykey: str = Field(..., alias='twoWayKey') ondelete: str = Field(..., alias='onDelete') side: str = Field(..., alias='side') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'relationType' not in data and 'relationtype' not in data: + data['relationType'] = '' + if 'twoWay' not in data and 'twoway' not in data: + data['twoWay'] = False + if 'twoWayKey' not in data and 'twowaykey' not in data: + data['twoWayKey'] = '' + if 'onDelete' not in data and 'ondelete' not in data: + data['onDelete'] = 'restrict' + if 'side' not in data: + data['side'] = '' + return data diff --git a/appwrite/models/column_string.py b/appwrite/models/column_string.py index 664904d2..c8d5efcb 100644 --- a/appwrite/models/column_string.py +++ b/appwrite/models/column_string.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -46,3 +46,26 @@ class ColumnString(AppwriteModel): size: float = Field(..., alias='size') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'size' not in data: + data['size'] = 0 + return data diff --git a/appwrite/models/column_text.py b/appwrite/models/column_text.py index a171fe08..29ea6f5b 100644 --- a/appwrite/models/column_text.py +++ b/appwrite/models/column_text.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -43,3 +43,24 @@ class ColumnText(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/column_url.py b/appwrite/models/column_url.py index fb1269c0..bb51776b 100644 --- a/appwrite/models/column_url.py +++ b/appwrite/models/column_url.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -43,3 +43,26 @@ class ColumnUrl(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') format: str = Field(..., alias='format') default: Optional[str] = Field(default=None, alias='default') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'format' not in data: + data['format'] = 'url' + return data diff --git a/appwrite/models/column_varchar.py b/appwrite/models/column_varchar.py index c6ec96c5..113ca34f 100644 --- a/appwrite/models/column_varchar.py +++ b/appwrite/models/column_varchar.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.column_status import ColumnStatus @@ -46,3 +46,26 @@ class ColumnVarchar(AppwriteModel): size: float = Field(..., alias='size') default: Optional[str] = Field(default=None, alias='default') encrypt: Optional[bool] = Field(default=None, alias='encrypt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'required' not in data: + data['required'] = False + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'size' not in data: + data['size'] = 0 + return data diff --git a/appwrite/models/continent.py b/appwrite/models/continent.py index ebc9026c..81dc6132 100644 --- a/appwrite/models/continent.py +++ b/appwrite/models/continent.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class Continent(AppwriteModel): name: str = Field(..., alias='name') code: str = Field(..., alias='code') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'name' not in data: + data['name'] = '' + if 'code' not in data: + data['code'] = '' + return data diff --git a/appwrite/models/continent_list.py b/appwrite/models/continent_list.py index a6f30050..cfa13414 100644 --- a/appwrite/models/continent_list.py +++ b/appwrite/models/continent_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .continent import Continent @@ -19,3 +19,14 @@ class ContinentList(AppwriteModel): total: float = Field(..., alias='total') continents: List[Continent] = Field(..., alias='continents') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/country.py b/appwrite/models/country.py index 5c40de11..5938df75 100644 --- a/appwrite/models/country.py +++ b/appwrite/models/country.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class Country(AppwriteModel): name: str = Field(..., alias='name') code: str = Field(..., alias='code') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'name' not in data: + data['name'] = '' + if 'code' not in data: + data['code'] = '' + return data diff --git a/appwrite/models/country_list.py b/appwrite/models/country_list.py index 73dda289..5b972b3a 100644 --- a/appwrite/models/country_list.py +++ b/appwrite/models/country_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .country import Country @@ -19,3 +19,14 @@ class CountryList(AppwriteModel): total: float = Field(..., alias='total') countries: List[Country] = Field(..., alias='countries') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/currency.py b/appwrite/models/currency.py index 52eacdda..83f45e3b 100644 --- a/appwrite/models/currency.py +++ b/appwrite/models/currency.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -33,3 +33,26 @@ class Currency(AppwriteModel): rounding: float = Field(..., alias='rounding') code: str = Field(..., alias='code') nameplural: str = Field(..., alias='namePlural') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'symbol' not in data: + data['symbol'] = '' + if 'name' not in data: + data['name'] = '' + if 'symbolNative' not in data and 'symbolnative' not in data: + data['symbolNative'] = '' + if 'decimalDigits' not in data and 'decimaldigits' not in data: + data['decimalDigits'] = 0 + if 'rounding' not in data: + data['rounding'] = 0 + if 'code' not in data: + data['code'] = '' + if 'namePlural' not in data and 'nameplural' not in data: + data['namePlural'] = '' + return data diff --git a/appwrite/models/currency_list.py b/appwrite/models/currency_list.py index c4022da6..17c3b839 100644 --- a/appwrite/models/currency_list.py +++ b/appwrite/models/currency_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .currency import Currency @@ -19,3 +19,14 @@ class CurrencyList(AppwriteModel): total: float = Field(..., alias='total') currencies: List[Currency] = Field(..., alias='currencies') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/database.py b/appwrite/models/database.py index 031d2e6c..931cb68d 100644 --- a/appwrite/models/database.py +++ b/appwrite/models/database.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.database_type import DatabaseType @@ -37,7 +37,7 @@ class Database(AppwriteModel): error : Optional[str] Error message when the dedicated backing failed. Null when the database has no dedicated backing or has not failed. containerstatus : Optional[str] - Container status of the dedicated backing: active or inactive. Null when the database has no dedicated backing or the runtime has not reported one. + Container status of the dedicated backing: active, inactive, or failed (a wake was declined because the backing namespace is gone). Null when the database has no dedicated backing or the runtime has not reported one. lifecyclestate : Optional[str] Idle-lifecycle state of the dedicated backing: active, warm, cold, or hibernated. Null when the database has no dedicated backing or the runtime has not reported one. policies : Optional[List[BackupPolicy]] @@ -61,3 +61,24 @@ class Database(AppwriteModel): lifecyclestate: Optional[str] = Field(default=None, alias='lifecycleState') policies: Optional[List[BackupPolicy]] = Field(default=None, alias='policies') archives: Optional[List[BackupArchive]] = Field(default=None, alias='archives') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'name' not in data: + data['name'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'type' not in data: + data['type'] = 'legacy' + return data diff --git a/appwrite/models/database_list.py b/appwrite/models/database_list.py index a7d726c2..6d85e4c3 100644 --- a/appwrite/models/database_list.py +++ b/appwrite/models/database_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .database import Database @@ -19,3 +19,14 @@ class DatabaseList(AppwriteModel): total: float = Field(..., alias='total') databases: List[Database] = Field(..., alias='databases') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/database_migration.py b/appwrite/models/database_migration.py index a0acc2f2..9342c20b 100644 --- a/appwrite/models/database_migration.py +++ b/appwrite/models/database_migration.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -63,3 +63,46 @@ class DatabaseMigration(AppwriteModel): autocutover: bool = Field(..., alias='autoCutover') cutoverrequested: bool = Field(..., alias='cutoverRequested') paused: bool = Field(..., alias='paused') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'databaseId' not in data and 'databaseid' not in data: + data['databaseId'] = '' + if 'specification' not in data: + data['specification'] = '' + if 'phase' not in data: + data['phase'] = 'pending' + if 'attempt' not in data: + data['attempt'] = 0 + if 'lastError' not in data and 'lasterror' not in data: + data['lastError'] = '' + if 'lagDocuments' not in data and 'lagdocuments' not in data: + data['lagDocuments'] = 0 + if 'changelogWatermark' not in data and 'changelogwatermark' not in data: + data['changelogWatermark'] = 0 + if 'verifiedAt' not in data and 'verifiedat' not in data: + data['verifiedAt'] = '' + if 'cutoverAt' not in data and 'cutoverat' not in data: + data['cutoverAt'] = '' + if 'soakUntil' not in data and 'soakuntil' not in data: + data['soakUntil'] = '' + if 'autoCutover' not in data and 'autocutover' not in data: + data['autoCutover'] = True + if 'cutoverRequested' not in data and 'cutoverrequested' not in data: + data['cutoverRequested'] = False + if 'paused' not in data: + data['paused'] = False + return data diff --git a/appwrite/models/database_migration_list.py b/appwrite/models/database_migration_list.py index a8b956c4..5fdb454c 100644 --- a/appwrite/models/database_migration_list.py +++ b/appwrite/models/database_migration_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .database_migration import DatabaseMigration @@ -19,3 +19,14 @@ class DatabaseMigrationList(AppwriteModel): total: float = Field(..., alias='total') migrations: List[DatabaseMigration] = Field(..., alias='migrations') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/database_status.py b/appwrite/models/database_status.py index 06a7cfd4..8fd03e0a 100644 --- a/appwrite/models/database_status.py +++ b/appwrite/models/database_status.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .database_status_connections import DatabaseStatusConnections @@ -23,8 +23,8 @@ class DatabaseStatus(AppwriteModel): Database engine version. uptime : float Database uptime in seconds. - connections : DatabaseStatusConnections - Connection statistics. + connections : Optional[DatabaseStatusConnections] + Connection statistics. Null when the database has not been probed. syncmode : str Requested replication sync mode. Possible values: async, sync, quorum. Compare with effectiveSyncMode for what the primary is enforcing. effectivesyncmode : Optional[str] @@ -48,7 +48,7 @@ class DatabaseStatus(AppwriteModel): engine: str = Field(..., alias='engine') version: str = Field(..., alias='version') uptime: float = Field(..., alias='uptime') - connections: DatabaseStatusConnections = Field(..., alias='connections') + connections: Optional[DatabaseStatusConnections] = Field(default=None, alias='connections') syncmode: str = Field(..., alias='syncMode') effectivesyncmode: Optional[str] = Field(default=None, alias='effectiveSyncMode') syncdegraded: bool = Field(..., alias='syncDegraded') @@ -57,3 +57,30 @@ class DatabaseStatus(AppwriteModel): syncstateconfirmed: Optional[bool] = Field(default=None, alias='syncStateConfirmed') replicas: List[DatabaseStatusReplica] = Field(..., alias='replicas') volumes: List[DatabaseStatusVolume] = Field(..., alias='volumes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'health' not in data: + data['health'] = 'unknown' + if 'ready' not in data: + data['ready'] = False + if 'engine' not in data: + data['engine'] = 'postgresql' + if 'version' not in data: + data['version'] = '' + if 'uptime' not in data: + data['uptime'] = 0 + if 'syncMode' not in data and 'syncmode' not in data: + data['syncMode'] = 'async' + if 'syncDegraded' not in data and 'syncdegraded' not in data: + data['syncDegraded'] = False + if 'syncAcknowledgements' not in data and 'syncacknowledgements' not in data: + data['syncAcknowledgements'] = 0 + if 'syncStandbyCount' not in data and 'syncstandbycount' not in data: + data['syncStandbyCount'] = 0 + return data diff --git a/appwrite/models/database_status_connections.py b/appwrite/models/database_status_connections.py index 1cce2821..caf927ce 100644 --- a/appwrite/models/database_status_connections.py +++ b/appwrite/models/database_status_connections.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class DatabaseStatusConnections(AppwriteModel): current: float = Field(..., alias='current') max: float = Field(..., alias='max') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'current' not in data: + data['current'] = 0 + if 'max' not in data: + data['max'] = 100 + return data diff --git a/appwrite/models/database_status_replica.py b/appwrite/models/database_status_replica.py index cab729db..4f480433 100644 --- a/appwrite/models/database_status_replica.py +++ b/appwrite/models/database_status_replica.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,18 @@ class DatabaseStatusReplica(AppwriteModel): healthy: bool = Field(..., alias='healthy') replicating: Optional[bool] = Field(default=None, alias='replicating') lagseconds: Optional[float] = Field(default=None, alias='lagSeconds') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'index' not in data: + data['index'] = 0 + if 'role' not in data: + data['role'] = 'unknown' + if 'healthy' not in data: + data['healthy'] = False + return data diff --git a/appwrite/models/database_status_volume.py b/appwrite/models/database_status_volume.py index 654b089a..80a2286e 100644 --- a/appwrite/models/database_status_volume.py +++ b/appwrite/models/database_status_volume.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class DatabaseStatusVolume(AppwriteModel): usedpercent: str = Field(..., alias='usedPercent') available: str = Field(..., alias='available') mounted: bool = Field(..., alias='mounted') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'path' not in data: + data['path'] = '' + if 'usedPercent' not in data and 'usedpercent' not in data: + data['usedPercent'] = '0%' + if 'available' not in data: + data['available'] = '0GB' + if 'mounted' not in data: + data['mounted'] = False + return data diff --git a/appwrite/models/dedicated_database.py b/appwrite/models/dedicated_database.py index 45c49d03..69aea701 100644 --- a/appwrite/models/dedicated_database.py +++ b/appwrite/models/dedicated_database.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -20,9 +20,9 @@ class DedicatedDatabase(AppwriteModel): Project ID that owns this database. name : str Database display name. - api : str + api : Optional[str] Product API that owns this database: tablesdb, documentsdb, vectorsdb, mysql, postgresql, or mongodb. - engine : str + engine : Optional[str] Database engine: postgresql, mysql, or mongodb. Null until the backing reports one. version : str Database engine version. @@ -32,13 +32,13 @@ class DedicatedDatabase(AppwriteModel): Database backend provider. Possible values: edge. hostname : str Database hostname for connections. - connectionport : float + connectionport : Optional[float] Database port for connections. Derived from the engine when the backing has not reported one yet. connectionuser : str Database username for connections. connectionpassword : str Database password for connections. - credentialgeneration : float + credentialgeneration : Optional[float] Committed generation of the primary connection credentials. Null until the rotation contract has been initialized. connectionstring : str Full database connection string (URI format). @@ -47,7 +47,7 @@ class DedicatedDatabase(AppwriteModel): status : str Database status. Possible values: provisioning, ready, inactive, paused, failed, deleted, restoring, scaling. containerstatus : str - Container status for lifecycle-managed database runtimes: active or inactive. + Container status for lifecycle-managed database runtimes: active, inactive, or failed (a wake was declined because the backing namespace is gone). lastaccessedat : Optional[str] Last activity timestamp in ISO 8601 format. idleuntil : Optional[str] @@ -62,6 +62,12 @@ class DedicatedDatabase(AppwriteModel): Memory allocated in MB. storage : float Storage allocated in GB. + storagestatus : str + Storage resize status. Possible values: idle (no resize in flight), resizing (the volume is growing towards storageTargetGb). + storagetargetgb : float + Size in GB the volume is growing towards while storageStatus is resizing. 0 when no resize is in flight. + storageresizestartedat : Optional[str] + Time the in-flight storage resize started, in ISO 8601 format. storageclass : str Storage class. Currently always 'ssd'; DigitalOcean exposes a single block-storage class. storagemaxgb : float @@ -89,7 +95,7 @@ class DedicatedDatabase(AppwriteModel): storageautoscalingthresholdpercent : float Storage usage percentage that triggers automatic expansion. storageautoscalingmaxgb : float - Maximum storage size in GB for autoscaling. 0 means no limit. + Maximum storage size in GB for autoscaling. Defaults to 3 times the specification's storage. 0 means no limit. maintenancewindowday : str Day of the week for the maintenance window. Possible values: sun, mon, tue, wed, thu, fri, sat. maintenancewindowhourutc : float @@ -115,16 +121,16 @@ class DedicatedDatabase(AppwriteModel): updatedat: str = Field(..., alias='$updatedAt') projectid: str = Field(..., alias='projectId') name: str = Field(..., alias='name') - api: str = Field(..., alias='api') - engine: str = Field(..., alias='engine') + api: Optional[str] = Field(default=None, alias='api') + engine: Optional[str] = Field(default=None, alias='engine') version: str = Field(..., alias='version') specification: str = Field(..., alias='specification') backend: str = Field(..., alias='backend') hostname: str = Field(..., alias='hostname') - connectionport: float = Field(..., alias='connectionPort') + connectionport: Optional[float] = Field(default=None, alias='connectionPort') connectionuser: str = Field(..., alias='connectionUser') connectionpassword: str = Field(..., alias='connectionPassword') - credentialgeneration: float = Field(..., alias='credentialGeneration') + credentialgeneration: Optional[float] = Field(default=None, alias='credentialGeneration') connectionstring: str = Field(..., alias='connectionString') ssl: bool = Field(..., alias='ssl') status: str = Field(..., alias='status') @@ -136,6 +142,9 @@ class DedicatedDatabase(AppwriteModel): cpu: float = Field(..., alias='cpu') memory: float = Field(..., alias='memory') storage: float = Field(..., alias='storage') + storagestatus: str = Field(..., alias='storageStatus') + storagetargetgb: float = Field(..., alias='storageTargetGb') + storageresizestartedat: Optional[str] = Field(default=None, alias='storageResizeStartedAt') storageclass: str = Field(..., alias='storageClass') storagemaxgb: float = Field(..., alias='storageMaxGb') nodepool: str = Field(..., alias='nodePool') @@ -159,3 +168,102 @@ class DedicatedDatabase(AppwriteModel): sqlapimaxbytes: float = Field(..., alias='sqlApiMaxBytes') sqlapitimeoutseconds: float = Field(..., alias='sqlApiTimeoutSeconds') error: str = Field(..., alias='error') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'name' not in data: + data['name'] = '' + if 'version' not in data: + data['version'] = '' + if 'specification' not in data: + data['specification'] = '' + if 'backend' not in data: + data['backend'] = '' + if 'hostname' not in data: + data['hostname'] = '' + if 'connectionUser' not in data and 'connectionuser' not in data: + data['connectionUser'] = '' + if 'connectionPassword' not in data and 'connectionpassword' not in data: + data['connectionPassword'] = '' + if 'connectionString' not in data and 'connectionstring' not in data: + data['connectionString'] = '' + if 'ssl' not in data: + data['ssl'] = False + if 'status' not in data: + data['status'] = 'provisioning' + if 'containerStatus' not in data and 'containerstatus' not in data: + data['containerStatus'] = '' + if 'lifecycleState' not in data and 'lifecyclestate' not in data: + data['lifecycleState'] = '' + if 'idleTimeoutMinutes' not in data and 'idletimeoutminutes' not in data: + data['idleTimeoutMinutes'] = 15 + if 'cpu' not in data: + data['cpu'] = 500 + if 'memory' not in data: + data['memory'] = 512 + if 'storage' not in data: + data['storage'] = 10 + if 'storageStatus' not in data and 'storagestatus' not in data: + data['storageStatus'] = 'idle' + if 'storageTargetGb' not in data and 'storagetargetgb' not in data: + data['storageTargetGb'] = 0 + if 'storageClass' not in data and 'storageclass' not in data: + data['storageClass'] = 'ssd' + if 'storageMaxGb' not in data and 'storagemaxgb' not in data: + data['storageMaxGb'] = 0 + if 'nodePool' not in data and 'nodepool' not in data: + data['nodePool'] = '' + if 'replicas' not in data: + data['replicas'] = 0 + if 'syncMode' not in data and 'syncmode' not in data: + data['syncMode'] = '' + if 'networkMaxConnections' not in data and 'networkmaxconnections' not in data: + data['networkMaxConnections'] = 100 + if 'networkIdleTimeoutSeconds' not in data and 'networkidletimeoutseconds' not in data: + data['networkIdleTimeoutSeconds'] = 900 + if 'networkIPAllowlist' not in data and 'networkipallowlist' not in data: + data['networkIPAllowlist'] = [] + if 'backupEnabled' not in data and 'backupenabled' not in data: + data['backupEnabled'] = True + if 'pitr' not in data: + data['pitr'] = True + if 'pitrRetentionDays' not in data and 'pitrretentiondays' not in data: + data['pitrRetentionDays'] = 7 + if 'storageAutoscaling' not in data and 'storageautoscaling' not in data: + data['storageAutoscaling'] = True + if 'storageAutoscalingThresholdPercent' not in data and 'storageautoscalingthresholdpercent' not in data: + data['storageAutoscalingThresholdPercent'] = 85 + if 'storageAutoscalingMaxGb' not in data and 'storageautoscalingmaxgb' not in data: + data['storageAutoscalingMaxGb'] = 0 + if 'maintenanceWindowDay' not in data and 'maintenancewindowday' not in data: + data['maintenanceWindowDay'] = 'sun' + if 'maintenanceWindowHourUtc' not in data and 'maintenancewindowhourutc' not in data: + data['maintenanceWindowHourUtc'] = 3 + if 'metricsEnabled' not in data and 'metricsenabled' not in data: + data['metricsEnabled'] = False + if 'sqlApiEnabled' not in data and 'sqlapienabled' not in data: + data['sqlApiEnabled'] = True + if 'sqlApiAllowedStatements' not in data and 'sqlapiallowedstatements' not in data: + data['sqlApiAllowedStatements'] = ['SELECT', 'INSERT', 'UPDATE', 'DELETE'] + if 'sqlApiMaxRows' not in data and 'sqlapimaxrows' not in data: + data['sqlApiMaxRows'] = 10000 + if 'sqlApiMaxBytes' not in data and 'sqlapimaxbytes' not in data: + data['sqlApiMaxBytes'] = 10485760 + if 'sqlApiTimeoutSeconds' not in data and 'sqlapitimeoutseconds' not in data: + data['sqlApiTimeoutSeconds'] = 30 + if 'error' not in data: + data['error'] = '' + return data diff --git a/appwrite/models/dedicated_database_backup.py b/appwrite/models/dedicated_database_backup.py index 40d47365..1c823b37 100644 --- a/appwrite/models/dedicated_database_backup.py +++ b/appwrite/models/dedicated_database_backup.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -63,3 +63,36 @@ class DedicatedDatabaseBackup(AppwriteModel): expiresat: Optional[str] = Field(default=None, alias='expiresAt') logposition: Optional[str] = Field(default=None, alias='logPosition') error: str = Field(..., alias='error') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'databaseId' not in data and 'databaseid' not in data: + data['databaseId'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'policyId' not in data and 'policyid' not in data: + data['policyId'] = '' + if 'trigger' not in data: + data['trigger'] = 'manual' + if 'type' not in data: + data['type'] = 'full' + if 'requestedType' not in data and 'requestedtype' not in data: + data['requestedType'] = '' + if 'fallbackReason' not in data and 'fallbackreason' not in data: + data['fallbackReason'] = '' + if 'status' not in data: + data['status'] = 'pending' + if 'sizeBytes' not in data and 'sizebytes' not in data: + data['sizeBytes'] = 0 + if 'error' not in data: + data['error'] = '' + return data diff --git a/appwrite/models/dedicated_database_backup_list.py b/appwrite/models/dedicated_database_backup_list.py index d8d98696..c2febc1c 100644 --- a/appwrite/models/dedicated_database_backup_list.py +++ b/appwrite/models/dedicated_database_backup_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .dedicated_database_backup import DedicatedDatabaseBackup @@ -19,3 +19,14 @@ class DedicatedDatabaseBackupList(AppwriteModel): total: float = Field(..., alias='total') backups: List[DedicatedDatabaseBackup] = Field(..., alias='backups') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/dedicated_database_backup_storage.py b/appwrite/models/dedicated_database_backup_storage.py index 039750c7..358720e4 100644 --- a/appwrite/models/dedicated_database_backup_storage.py +++ b/appwrite/models/dedicated_database_backup_storage.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class DedicatedDatabaseBackupStorage(AppwriteModel): region: str = Field(..., alias='region') prefix: str = Field(..., alias='prefix') endpoint: str = Field(..., alias='endpoint') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'provider' not in data: + data['provider'] = '' + if 'bucket' not in data: + data['bucket'] = '' + if 'region' not in data: + data['region'] = '' + if 'prefix' not in data: + data['prefix'] = 'backups/' + if 'endpoint' not in data: + data['endpoint'] = '' + return data diff --git a/appwrite/models/dedicated_database_branch.py b/appwrite/models/dedicated_database_branch.py index 4699ab6a..76b02b70 100644 --- a/appwrite/models/dedicated_database_branch.py +++ b/appwrite/models/dedicated_database_branch.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -20,7 +20,7 @@ class DedicatedDatabaseBranch(AppwriteModel): Unix timestamp when the branch expires. host : str Branch hostname for direct connections. - port : float + port : Optional[float] Branch port. Null until the backing reports one. database : str Advertised catalog the client connects to. MySQL/MariaDB use default; Postgres uses the routing label. @@ -41,10 +41,41 @@ class DedicatedDatabaseBranch(AppwriteModel): namespace: str = Field(..., alias='namespace') expiresat: float = Field(..., alias='expiresAt') host: str = Field(..., alias='host') - port: float = Field(..., alias='port') + port: Optional[float] = Field(default=None, alias='port') database: str = Field(..., alias='database') username: str = Field(..., alias='username') password: str = Field(..., alias='password') ssl: bool = Field(..., alias='ssl') engine: str = Field(..., alias='engine') connectionstring: str = Field(..., alias='connectionString') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'branchId' not in data and 'branchid' not in data: + data['branchId'] = '' + if 'branchName' not in data and 'branchname' not in data: + data['branchName'] = '' + if 'namespace' not in data: + data['namespace'] = '' + if 'expiresAt' not in data and 'expiresat' not in data: + data['expiresAt'] = 0 + if 'host' not in data: + data['host'] = '' + if 'database' not in data: + data['database'] = '' + if 'username' not in data: + data['username'] = '' + if 'password' not in data: + data['password'] = '' + if 'ssl' not in data: + data['ssl'] = False + if 'engine' not in data: + data['engine'] = '' + if 'connectionString' not in data and 'connectionstring' not in data: + data['connectionString'] = '' + return data diff --git a/appwrite/models/dedicated_database_branch_list.py b/appwrite/models/dedicated_database_branch_list.py index 9966ba57..8fc04535 100644 --- a/appwrite/models/dedicated_database_branch_list.py +++ b/appwrite/models/dedicated_database_branch_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .dedicated_database_branch import DedicatedDatabaseBranch @@ -19,3 +19,14 @@ class DedicatedDatabaseBranchList(AppwriteModel): total: float = Field(..., alias='total') branches: List[DedicatedDatabaseBranch] = Field(..., alias='branches') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/dedicated_database_execution.py b/appwrite/models/dedicated_database_execution.py index 4a9a5eda..e7e4d0d5 100644 --- a/appwrite/models/dedicated_database_execution.py +++ b/appwrite/models/dedicated_database_execution.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .dedicated_database_execution_column import DedicatedDatabaseExecutionColumn @@ -31,3 +31,22 @@ class DedicatedDatabaseExecution(AppwriteModel): durationms: float = Field(..., alias='durationMs') truncated: bool = Field(..., alias='truncated') bytes: float = Field(..., alias='bytes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'rows' not in data: + data['rows'] = [] + if 'rowCount' not in data and 'rowcount' not in data: + data['rowCount'] = 0 + if 'durationMs' not in data and 'durationms' not in data: + data['durationMs'] = 0 + if 'truncated' not in data: + data['truncated'] = False + if 'bytes' not in data: + data['bytes'] = 0 + return data diff --git a/appwrite/models/dedicated_database_execution_column.py b/appwrite/models/dedicated_database_execution_column.py index 095e7e59..a0adce80 100644 --- a/appwrite/models/dedicated_database_execution_column.py +++ b/appwrite/models/dedicated_database_execution_column.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class DedicatedDatabaseExecutionColumn(AppwriteModel): name: str = Field(..., alias='name') type: str = Field(..., alias='type') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'name' not in data: + data['name'] = '' + if 'type' not in data: + data['type'] = '' + return data diff --git a/appwrite/models/dedicated_database_extensions.py b/appwrite/models/dedicated_database_extensions.py index 363e6374..c07d5b6f 100644 --- a/appwrite/models/dedicated_database_extensions.py +++ b/appwrite/models/dedicated_database_extensions.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .postgres_extension import PostgresExtension @@ -22,3 +22,16 @@ class DedicatedDatabaseExtensions(AppwriteModel): installed: List[Any] = Field(..., alias='installed') available: List[Any] = Field(..., alias='available') metadata: List[PostgresExtension] = Field(..., alias='metadata') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'installed' not in data: + data['installed'] = [] + if 'available' not in data: + data['available'] = [] + return data diff --git a/appwrite/models/dedicated_database_list.py b/appwrite/models/dedicated_database_list.py index f7e50415..a6fa3f4d 100644 --- a/appwrite/models/dedicated_database_list.py +++ b/appwrite/models/dedicated_database_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .dedicated_database import DedicatedDatabase @@ -19,3 +19,14 @@ class DedicatedDatabaseList(AppwriteModel): total: float = Field(..., alias='total') databases: List[DedicatedDatabase] = Field(..., alias='databases') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/dedicated_database_member.py b/appwrite/models/dedicated_database_member.py index 55426f3f..91a8aaad 100644 --- a/appwrite/models/dedicated_database_member.py +++ b/appwrite/models/dedicated_database_member.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,18 @@ class DedicatedDatabaseMember(AppwriteModel): status: str = Field(..., alias='status') replicating: Optional[bool] = Field(default=None, alias='replicating') lagseconds: Optional[float] = Field(default=None, alias='lagSeconds') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'role' not in data: + data['role'] = 'unknown' + if 'status' not in data: + data['status'] = '' + return data diff --git a/appwrite/models/dedicated_database_operation.py b/appwrite/models/dedicated_database_operation.py index d9814c58..af80395d 100644 --- a/appwrite/models/dedicated_database_operation.py +++ b/appwrite/models/dedicated_database_operation.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -45,3 +45,28 @@ class DedicatedDatabaseOperation(AppwriteModel): completedat: Optional[str] = Field(default=None, alias='completedAt') errorcode: str = Field(..., alias='errorCode') errormessage: str = Field(..., alias='errorMessage') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'databaseId' not in data and 'databaseid' not in data: + data['databaseId'] = '' + if 'type' not in data: + data['type'] = '' + if 'status' not in data: + data['status'] = '' + if 'attempts' not in data: + data['attempts'] = 0 + if 'errorCode' not in data and 'errorcode' not in data: + data['errorCode'] = '' + if 'errorMessage' not in data and 'errormessage' not in data: + data['errorMessage'] = '' + return data diff --git a/appwrite/models/dedicated_database_operation_list.py b/appwrite/models/dedicated_database_operation_list.py index 30d2cc8c..eb364200 100644 --- a/appwrite/models/dedicated_database_operation_list.py +++ b/appwrite/models/dedicated_database_operation_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .dedicated_database_operation import DedicatedDatabaseOperation @@ -19,3 +19,14 @@ class DedicatedDatabaseOperationList(AppwriteModel): total: float = Field(..., alias='total') operations: List[DedicatedDatabaseOperation] = Field(..., alias='operations') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/dedicated_database_pitr_windows.py b/appwrite/models/dedicated_database_pitr_windows.py index 243710e6..4d35ccf5 100644 --- a/appwrite/models/dedicated_database_pitr_windows.py +++ b/appwrite/models/dedicated_database_pitr_windows.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class DedicatedDatabasePITRWindows(AppwriteModel): earliest: str = Field(..., alias='earliest') latest: str = Field(..., alias='latest') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'earliest' not in data: + data['earliest'] = '' + if 'latest' not in data: + data['latest'] = '' + return data diff --git a/appwrite/models/dedicated_database_pooler.py b/appwrite/models/dedicated_database_pooler.py index 3316d96f..3c6b221b 100644 --- a/appwrite/models/dedicated_database_pooler.py +++ b/appwrite/models/dedicated_database_pooler.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -42,3 +42,32 @@ class DedicatedDatabasePooler(AppwriteModel): poolercpulimit: str = Field(..., alias='poolerCpuLimit') poolermemoryrequest: str = Field(..., alias='poolerMemoryRequest') poolermemorylimit: str = Field(..., alias='poolerMemoryLimit') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'enabled' not in data: + data['enabled'] = False + if 'mode' not in data: + data['mode'] = 'transaction' + if 'maxConnections' not in data and 'maxconnections' not in data: + data['maxConnections'] = 100 + if 'defaultPoolSize' not in data and 'defaultpoolsize' not in data: + data['defaultPoolSize'] = 20 + if 'port' not in data: + data['port'] = 6432 + if 'readWriteSplitting' not in data and 'readwritesplitting' not in data: + data['readWriteSplitting'] = False + if 'poolerCpuRequest' not in data and 'poolercpurequest' not in data: + data['poolerCpuRequest'] = '' + if 'poolerCpuLimit' not in data and 'poolercpulimit' not in data: + data['poolerCpuLimit'] = '' + if 'poolerMemoryRequest' not in data and 'poolermemoryrequest' not in data: + data['poolerMemoryRequest'] = '' + if 'poolerMemoryLimit' not in data and 'poolermemorylimit' not in data: + data['poolerMemoryLimit'] = '' + return data diff --git a/appwrite/models/dedicated_database_replicas.py b/appwrite/models/dedicated_database_replicas.py index fc035b2b..f7246ba4 100644 --- a/appwrite/models/dedicated_database_replicas.py +++ b/appwrite/models/dedicated_database_replicas.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .dedicated_database_member import DedicatedDatabaseMember @@ -37,3 +37,22 @@ class DedicatedDatabaseReplicas(AppwriteModel): syncstandbycount: float = Field(..., alias='syncStandbyCount') syncstateconfirmed: Optional[bool] = Field(default=None, alias='syncStateConfirmed') members: List[DedicatedDatabaseMember] = Field(..., alias='members') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'replicas' not in data: + data['replicas'] = 0 + if 'syncMode' not in data and 'syncmode' not in data: + data['syncMode'] = 'async' + if 'syncDegraded' not in data and 'syncdegraded' not in data: + data['syncDegraded'] = False + if 'syncAcknowledgements' not in data and 'syncacknowledgements' not in data: + data['syncAcknowledgements'] = 0 + if 'syncStandbyCount' not in data and 'syncstandbycount' not in data: + data['syncStandbyCount'] = 0 + return data diff --git a/appwrite/models/dedicated_database_restoration.py b/appwrite/models/dedicated_database_restoration.py index 7965c50d..a346c3da 100644 --- a/appwrite/models/dedicated_database_restoration.py +++ b/appwrite/models/dedicated_database_restoration.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -16,21 +16,21 @@ class DedicatedDatabaseRestoration(AppwriteModel): Restoration creation time in ISO 8601 format. databaseid : str Database ID being restored into. - sourcedatabaseid : str + sourcedatabaseid : Optional[str] Source database ID when restoring a backup into another database. projectid : str Project ID. - backupid : str + backupid : Optional[str] Backup ID used for restoration (null for PITR). type : str Restoration type. Possible values: backup (restore from a specific backup snapshot), pitr (point-in-time recovery to a specific timestamp). status : str Restoration status. Possible values: pending (queued for processing), running (currently in progress), completed (successfully finished), failed (encountered an error). - targettime : str + targettime : Optional[str] Target time for PITR restoration in ISO 8601 format. - startedat : str + startedat : Optional[str] Restoration start time in ISO 8601 format. - completedat : str + completedat : Optional[str] Restoration completion time in ISO 8601 format. error : str Error message if restoration failed. @@ -39,12 +39,35 @@ class DedicatedDatabaseRestoration(AppwriteModel): id: str = Field(..., alias='$id') createdat: str = Field(..., alias='$createdAt') databaseid: str = Field(..., alias='databaseId') - sourcedatabaseid: str = Field(..., alias='sourceDatabaseId') + sourcedatabaseid: Optional[str] = Field(default=None, alias='sourceDatabaseId') projectid: str = Field(..., alias='projectId') - backupid: str = Field(..., alias='backupId') + backupid: Optional[str] = Field(default=None, alias='backupId') type: str = Field(..., alias='type') status: str = Field(..., alias='status') - targettime: str = Field(..., alias='targetTime') - startedat: str = Field(..., alias='startedAt') - completedat: str = Field(..., alias='completedAt') + targettime: Optional[str] = Field(default=None, alias='targetTime') + startedat: Optional[str] = Field(default=None, alias='startedAt') + completedat: Optional[str] = Field(default=None, alias='completedAt') error: str = Field(..., alias='error') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'databaseId' not in data and 'databaseid' not in data: + data['databaseId'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'type' not in data: + data['type'] = 'backup' + if 'status' not in data: + data['status'] = 'pending' + if 'error' not in data: + data['error'] = '' + return data diff --git a/appwrite/models/dedicated_database_restoration_list.py b/appwrite/models/dedicated_database_restoration_list.py index 8eac8c70..3ffcdf5b 100644 --- a/appwrite/models/dedicated_database_restoration_list.py +++ b/appwrite/models/dedicated_database_restoration_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .dedicated_database_restoration import DedicatedDatabaseRestoration @@ -19,3 +19,14 @@ class DedicatedDatabaseRestorationList(AppwriteModel): total: float = Field(..., alias='total') restorations: List[DedicatedDatabaseRestoration] = Field(..., alias='restorations') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/dedicated_database_specification.py b/appwrite/models/dedicated_database_specification.py index 71cf58fa..1bc7af29 100644 --- a/appwrite/models/dedicated_database_specification.py +++ b/appwrite/models/dedicated_database_specification.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -16,6 +16,14 @@ class DedicatedDatabaseSpecification(AppwriteModel): Human readable specification name. price : float Monthly price of the specification in USD. + storageoveragerate : float + Price per GB of storage above the included amount, per month, in USD. + bandwidthoveragerate : float + Price per GB of bandwidth above the included amount, per month, in USD. + replicarate : float + High availability replica price as a fraction of the specification price. + pitrrate : float + Point-in-time recovery price as a fraction of the specification price. cpu : float Allocated CPU in millicores. memory : float @@ -33,9 +41,48 @@ class DedicatedDatabaseSpecification(AppwriteModel): slug: str = Field(..., alias='slug') name: str = Field(..., alias='name') price: float = Field(..., alias='price') + storageoveragerate: float = Field(..., alias='storageOverageRate') + bandwidthoveragerate: float = Field(..., alias='bandwidthOverageRate') + replicarate: float = Field(..., alias='replicaRate') + pitrrate: float = Field(..., alias='pitrRate') cpu: float = Field(..., alias='cpu') memory: float = Field(..., alias='memory') maxconnections: float = Field(..., alias='maxConnections') includedstorage: float = Field(..., alias='includedStorage') includedbandwidth: float = Field(..., alias='includedBandwidth') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'slug' not in data: + data['slug'] = '' + if 'name' not in data: + data['name'] = '' + if 'price' not in data: + data['price'] = 0 + if 'storageOverageRate' not in data and 'storageoveragerate' not in data: + data['storageOverageRate'] = 0 + if 'bandwidthOverageRate' not in data and 'bandwidthoveragerate' not in data: + data['bandwidthOverageRate'] = 0 + if 'replicaRate' not in data and 'replicarate' not in data: + data['replicaRate'] = 0 + if 'pitrRate' not in data and 'pitrrate' not in data: + data['pitrRate'] = 0 + if 'cpu' not in data: + data['cpu'] = 0 + if 'memory' not in data: + data['memory'] = 0 + if 'maxConnections' not in data and 'maxconnections' not in data: + data['maxConnections'] = 0 + if 'includedStorage' not in data and 'includedstorage' not in data: + data['includedStorage'] = 0 + if 'includedBandwidth' not in data and 'includedbandwidth' not in data: + data['includedBandwidth'] = 0 + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/dedicated_database_specification_list.py b/appwrite/models/dedicated_database_specification_list.py index 92c0b23f..b0088ded 100644 --- a/appwrite/models/dedicated_database_specification_list.py +++ b/appwrite/models/dedicated_database_specification_list.py @@ -1,9 +1,8 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .dedicated_database_specification import DedicatedDatabaseSpecification -from .dedicated_database_specification_pricing import DedicatedDatabaseSpecificationPricing class DedicatedDatabaseSpecificationList(AppwriteModel): @@ -16,10 +15,18 @@ class DedicatedDatabaseSpecificationList(AppwriteModel): List of dedicated database specifications. total : float Total number of specifications. - pricing : DedicatedDatabaseSpecificationPricing - Overage and add-on pricing shared across all specifications. """ specifications: List[DedicatedDatabaseSpecification] = Field(..., alias='specifications') total: float = Field(..., alias='total') - pricing: DedicatedDatabaseSpecificationPricing = Field(..., alias='pricing') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/dedicated_database_specification_pricing.py b/appwrite/models/dedicated_database_specification_pricing.py deleted file mode 100644 index 83b03a6a..00000000 --- a/appwrite/models/dedicated_database_specification_pricing.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr - -from .base_model import AppwriteModel - - -class DedicatedDatabaseSpecificationPricing(AppwriteModel): - """ - SpecificationPricing - - Attributes - ---------- - storageoveragerate : float - Price per GB of storage above the included amount, per month, in USD. - bandwidthoveragerate : float - Price per GB of bandwidth above the included amount, per month, in USD. - replicarate : float - High availability replica price as a fraction of the specification cost. - pitrrate : float - Point-in-time recovery price as a fraction of the specification cost. - """ - - storageoveragerate: float = Field(..., alias='storageOverageRate') - bandwidthoveragerate: float = Field(..., alias='bandwidthOverageRate') - replicarate: float = Field(..., alias='replicaRate') - pitrrate: float = Field(..., alias='pitrRate') diff --git a/appwrite/models/deployment.py b/appwrite/models/deployment.py index f4baf0c9..56e36cb4 100644 --- a/appwrite/models/deployment.py +++ b/appwrite/models/deployment.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.deployment_status import DeploymentStatus @@ -94,3 +94,64 @@ class Deployment(AppwriteModel): providercommiturl: str = Field(..., alias='providerCommitUrl') providerbranch: str = Field(..., alias='providerBranch') providerbranchurl: str = Field(..., alias='providerBranchUrl') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'type' not in data: + data['type'] = '' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = '' + if 'entrypoint' not in data: + data['entrypoint'] = '' + if 'sourceSize' not in data and 'sourcesize' not in data: + data['sourceSize'] = 0 + if 'buildSize' not in data and 'buildsize' not in data: + data['buildSize'] = 0 + if 'totalSize' not in data and 'totalsize' not in data: + data['totalSize'] = 0 + if 'buildId' not in data and 'buildid' not in data: + data['buildId'] = '' + if 'activate' not in data: + data['activate'] = False + if 'screenshotLight' not in data and 'screenshotlight' not in data: + data['screenshotLight'] = '' + if 'screenshotDark' not in data and 'screenshotdark' not in data: + data['screenshotDark'] = '' + if 'buildLogs' not in data and 'buildlogs' not in data: + data['buildLogs'] = '' + if 'buildDuration' not in data and 'buildduration' not in data: + data['buildDuration'] = 0 + if 'providerRepositoryName' not in data and 'providerrepositoryname' not in data: + data['providerRepositoryName'] = '' + if 'providerRepositoryOwner' not in data and 'providerrepositoryowner' not in data: + data['providerRepositoryOwner'] = '' + if 'providerRepositoryUrl' not in data and 'providerrepositoryurl' not in data: + data['providerRepositoryUrl'] = '' + if 'providerCommitHash' not in data and 'providercommithash' not in data: + data['providerCommitHash'] = '' + if 'providerCommitAuthorUrl' not in data and 'providercommitauthorurl' not in data: + data['providerCommitAuthorUrl'] = '' + if 'providerCommitAuthor' not in data and 'providercommitauthor' not in data: + data['providerCommitAuthor'] = '' + if 'providerCommitMessage' not in data and 'providercommitmessage' not in data: + data['providerCommitMessage'] = '' + if 'providerCommitUrl' not in data and 'providercommiturl' not in data: + data['providerCommitUrl'] = '' + if 'providerBranch' not in data and 'providerbranch' not in data: + data['providerBranch'] = '' + if 'providerBranchUrl' not in data and 'providerbranchurl' not in data: + data['providerBranchUrl'] = '' + return data diff --git a/appwrite/models/deployment_list.py b/appwrite/models/deployment_list.py index d3c435d9..8c70a956 100644 --- a/appwrite/models/deployment_list.py +++ b/appwrite/models/deployment_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .deployment import Deployment @@ -19,3 +19,14 @@ class DeploymentList(AppwriteModel): total: float = Field(..., alias='total') deployments: List[Deployment] = Field(..., alias='deployments') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/dev_key.py b/appwrite/models/dev_key.py deleted file mode 100644 index c36cf0f6..00000000 --- a/appwrite/models/dev_key.py +++ /dev/null @@ -1,38 +0,0 @@ -from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr - -from .base_model import AppwriteModel - - -class DevKey(AppwriteModel): - """ - DevKey - - Attributes - ---------- - id : str - Key ID. - createdat : str - Key creation date in ISO 8601 format. - updatedat : str - Key update date in ISO 8601 format. - name : str - Key name. - expire : str - Key expiration date in ISO 8601 format. - secret : str - Secret key. - accessedat : str - Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours. - sdks : List[Any] - List of SDK user agents that used this key. - """ - - id: str = Field(..., alias='$id') - createdat: str = Field(..., alias='$createdAt') - updatedat: str = Field(..., alias='$updatedAt') - name: str = Field(..., alias='name') - expire: str = Field(..., alias='expire') - secret: str = Field(..., alias='secret') - accessedat: str = Field(..., alias='accessedAt') - sdks: List[Any] = Field(..., alias='sdks') diff --git a/appwrite/models/dns_record.py b/appwrite/models/dns_record.py new file mode 100644 index 00000000..612c896b --- /dev/null +++ b/appwrite/models/dns_record.py @@ -0,0 +1,83 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class DnsRecord(AppwriteModel): + """ + DNSRecord + + Attributes + ---------- + id : str + DNS Record ID. + createdat : str + DNS Record creation time in ISO 8601 format. + updatedat : str + DNS Record update date in ISO 8601 format. + type : str + DNS record type (e.g. A, CNAME, MX). + name : str + Record name or subdomain. + value : str + Value of the record (IP address, domain, etc.). + ttl : float + Time to live (in seconds). + priority : float + Record priority (commonly used for MX). + lock : bool + Whether this record is locked (read-only). + weight : float + Record weight (used for SRV records). + port : float + Target port (used for SRV records). + comment : str + Comment for the DNS record. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + type: str = Field(..., alias='type') + name: str = Field(..., alias='name') + value: str = Field(..., alias='value') + ttl: float = Field(..., alias='ttl') + priority: float = Field(..., alias='priority') + lock: bool = Field(..., alias='lock') + weight: float = Field(..., alias='weight') + port: float = Field(..., alias='port') + comment: str = Field(..., alias='comment') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'type' not in data: + data['type'] = '' + if 'name' not in data: + data['name'] = '' + if 'value' not in data: + data['value'] = '' + if 'ttl' not in data: + data['ttl'] = 3600 + if 'priority' not in data: + data['priority'] = 0 + if 'lock' not in data: + data['lock'] = False + if 'weight' not in data: + data['weight'] = 0 + if 'port' not in data: + data['port'] = 0 + if 'comment' not in data: + data['comment'] = '' + return data diff --git a/appwrite/models/dns_records_list.py b/appwrite/models/dns_records_list.py new file mode 100644 index 00000000..34fd1a57 --- /dev/null +++ b/appwrite/models/dns_records_list.py @@ -0,0 +1,32 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from .dns_record import DnsRecord + + +class DnsRecordsList(AppwriteModel): + """ + DNS records list + + Attributes + ---------- + total : float + Total number of dnsRecords that matched your query. + dnsrecords : List[DnsRecord] + List of dnsRecords. + """ + + total: float = Field(..., alias='total') + dnsrecords: List[DnsRecord] = Field(..., alias='dnsRecords') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/document.py b/appwrite/models/document.py index f59435f1..1dce711b 100644 --- a/appwrite/models/document.py +++ b/appwrite/models/document.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr, TypeAdapter, model_serializer +from pydantic import Field, PrivateAttr, TypeAdapter, model_validator, model_serializer from .base_model import AppwriteModel @@ -38,6 +38,27 @@ class Document(AppwriteModel, Generic[T]): updatedat: str = Field(..., alias='$updatedAt') permissions: List[Any] = Field(..., alias='$permissions') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$sequence' not in data and 'sequence' not in data: + data['$sequence'] = '' + if '$collectionId' not in data and 'collectionid' not in data: + data['$collectionId'] = '' + if '$databaseId' not in data and 'databaseid' not in data: + data['$databaseId'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'Document[T]': """Create Document instance with typed data.""" diff --git a/appwrite/models/document_list.py b/appwrite/models/document_list.py index ff2045dc..28894bd6 100644 --- a/appwrite/models/document_list.py +++ b/appwrite/models/document_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .document import Document @@ -22,6 +22,17 @@ class DocumentList(AppwriteModel, Generic[T]): total: float = Field(..., alias='total') documents: List[Document[T]] = Field(..., alias='documents') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'DocumentList[T]': """Create DocumentList instance with typed data.""" diff --git a/appwrite/models/domain.py b/appwrite/models/domain.py new file mode 100644 index 00000000..c5e891c0 --- /dev/null +++ b/appwrite/models/domain.py @@ -0,0 +1,86 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from ..enums.domain_transfer_status_enum import DomainTransferStatusEnum +from .dns_record import DnsRecord + + +class Domain(AppwriteModel): + """ + Domain + + Attributes + ---------- + id : str + Domain ID. + createdat : str + Domain creation time in ISO 8601 format. + updatedat : str + Domain update date in ISO 8601 format. + domain : str + Domain name. + registrar : str + Domain registrar (e.g. "appwrite" or "third_party"). + nameservers : str + Nameservers setting. "Appwrite" or empty string. + expire : str + Domain expiry date in ISO 8601 format. + renewal : str + Domain renewal date in ISO 8601 format. + autorenewal : bool + If set to true, the domain will automatically renew. + renewalprice : float + Renewal price (in cents). + transferstatus : Optional[DomainTransferStatusEnum] + Transfer status for domains being transferred in. Null when the domain is not being transferred. + teamid : str + Team ID. + dnsrecords : List[DnsRecord] + Dns records + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + domain: str = Field(..., alias='domain') + registrar: str = Field(..., alias='registrar') + nameservers: str = Field(..., alias='nameservers') + expire: str = Field(..., alias='expire') + renewal: str = Field(..., alias='renewal') + autorenewal: bool = Field(..., alias='autoRenewal') + renewalprice: float = Field(..., alias='renewalPrice') + transferstatus: Optional[DomainTransferStatusEnum] = Field(default=None, alias='transferStatus') + teamid: str = Field(..., alias='teamId') + dnsrecords: List[DnsRecord] = Field(..., alias='dnsRecords') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'domain' not in data: + data['domain'] = '' + if 'registrar' not in data: + data['registrar'] = '' + if 'nameservers' not in data: + data['nameservers'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'renewal' not in data: + data['renewal'] = '' + if 'autoRenewal' not in data and 'autorenewal' not in data: + data['autoRenewal'] = False + if 'renewalPrice' not in data and 'renewalprice' not in data: + data['renewalPrice'] = 0 + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + return data diff --git a/appwrite/models/domain_price.py b/appwrite/models/domain_price.py new file mode 100644 index 00000000..6ab77ae3 --- /dev/null +++ b/appwrite/models/domain_price.py @@ -0,0 +1,59 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class DomainPrice(AppwriteModel): + """ + DomainPrice + + Attributes + ---------- + domain : str + Domain name. + tld : str + Top-level domain for the requested domain. + available : bool + Whether the domain is currently available for registration. + price : Optional[float] + Domain registration price. Null when the price could not be resolved, for example for an unsupported TLD. + periodyears : float + Price period in years. + premium : bool + Whether the domain is a premium domain. + renewalprice : Optional[float] + Domain renewal price for the same period. Null when the domain was not priced or the registrar has no renewal price for it. + renewalperiodyears : float + Renewal price period in years. + """ + + domain: str = Field(..., alias='domain') + tld: str = Field(..., alias='tld') + available: bool = Field(..., alias='available') + price: Optional[float] = Field(default=None, alias='price') + periodyears: float = Field(..., alias='periodYears') + premium: bool = Field(..., alias='premium') + renewalprice: Optional[float] = Field(default=None, alias='renewalPrice') + renewalperiodyears: float = Field(..., alias='renewalPeriodYears') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'domain' not in data: + data['domain'] = '' + if 'tld' not in data: + data['tld'] = '' + if 'available' not in data: + data['available'] = False + if 'periodYears' not in data and 'periodyears' not in data: + data['periodYears'] = 1 + if 'premium' not in data: + data['premium'] = False + if 'renewalPeriodYears' not in data and 'renewalperiodyears' not in data: + data['renewalPeriodYears'] = 1 + return data diff --git a/appwrite/models/domain_prices_list.py b/appwrite/models/domain_prices_list.py new file mode 100644 index 00000000..ccaca2b9 --- /dev/null +++ b/appwrite/models/domain_prices_list.py @@ -0,0 +1,32 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from .domain_price import DomainPrice + + +class DomainPricesList(AppwriteModel): + """ + Domain prices list + + Attributes + ---------- + total : float + Total number of prices that matched your query. + prices : List[DomainPrice] + List of prices. + """ + + total: float = Field(..., alias='total') + prices: List[DomainPrice] = Field(..., alias='prices') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/domain_transfer_status.py b/appwrite/models/domain_transfer_status.py new file mode 100644 index 00000000..c7a6df77 --- /dev/null +++ b/appwrite/models/domain_transfer_status.py @@ -0,0 +1,39 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from ..enums.domain_transfer_status_enum import DomainTransferStatusEnum + + +class DomainTransferStatus(AppwriteModel): + """ + domainTransferStatus + + Attributes + ---------- + status : DomainTransferStatusEnum + Transfer status. + reason : str + Additional transfer status information. + timestamp : str + Transfer status timestamp in ISO 8601 format. + """ + + status: DomainTransferStatusEnum = Field(..., alias='status') + reason: str = Field(..., alias='reason') + timestamp: str = Field(..., alias='timestamp') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'status' not in data: + data['status'] = 'pending_registry' + if 'reason' not in data: + data['reason'] = '' + if 'timestamp' not in data: + data['timestamp'] = '' + return data diff --git a/appwrite/models/domains_list.py b/appwrite/models/domains_list.py new file mode 100644 index 00000000..ad924b27 --- /dev/null +++ b/appwrite/models/domains_list.py @@ -0,0 +1,32 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from .domain import Domain + + +class DomainsList(AppwriteModel): + """ + Domains list + + Attributes + ---------- + total : float + Total number of domains that matched your query. + domains : List[Domain] + List of domains. + """ + + total: float = Field(..., alias='total') + domains: List[Domain] = Field(..., alias='domains') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/email_template.py b/appwrite/models/email_template.py index 302173e9..ebb62bfd 100644 --- a/appwrite/models/email_template.py +++ b/appwrite/models/email_template.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -36,3 +36,28 @@ class EmailTemplate(AppwriteModel): replytoemail: str = Field(..., alias='replyToEmail') replytoname: str = Field(..., alias='replyToName') subject: str = Field(..., alias='subject') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'templateId' not in data and 'templateid' not in data: + data['templateId'] = '' + if 'locale' not in data: + data['locale'] = '' + if 'message' not in data: + data['message'] = '' + if 'senderName' not in data and 'sendername' not in data: + data['senderName'] = '' + if 'senderEmail' not in data and 'senderemail' not in data: + data['senderEmail'] = '' + if 'replyToEmail' not in data and 'replytoemail' not in data: + data['replyToEmail'] = '' + if 'replyToName' not in data and 'replytoname' not in data: + data['replyToName'] = '' + if 'subject' not in data: + data['subject'] = '' + return data diff --git a/appwrite/models/email_template_list.py b/appwrite/models/email_template_list.py index 3a601e4a..e15c938e 100644 --- a/appwrite/models/email_template_list.py +++ b/appwrite/models/email_template_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .email_template import EmailTemplate @@ -19,3 +19,14 @@ class EmailTemplateList(AppwriteModel): total: float = Field(..., alias='total') templates: List[EmailTemplate] = Field(..., alias='templates') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/embedding.py b/appwrite/models/embedding.py index c308479a..e6ccbe94 100644 --- a/appwrite/models/embedding.py +++ b/appwrite/models/embedding.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class Embedding(AppwriteModel): dimension: float = Field(..., alias='dimension') embedding: List[Any] = Field(..., alias='embedding') error: str = Field(..., alias='error') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'model' not in data: + data['model'] = '' + if 'dimension' not in data: + data['dimension'] = 0 + if 'embedding' not in data: + data['embedding'] = [] + if 'error' not in data: + data['error'] = '' + return data diff --git a/appwrite/models/embedding_list.py b/appwrite/models/embedding_list.py index afa3a12e..1a6ceea2 100644 --- a/appwrite/models/embedding_list.py +++ b/appwrite/models/embedding_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .embedding import Embedding @@ -19,3 +19,14 @@ class EmbeddingList(AppwriteModel): total: float = Field(..., alias='total') embeddings: List[Embedding] = Field(..., alias='embeddings') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/ephemeral_key.py b/appwrite/models/ephemeral_key.py index ed21e512..96c7f7a5 100644 --- a/appwrite/models/ephemeral_key.py +++ b/appwrite/models/ephemeral_key.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,28 @@ class EphemeralKey(AppwriteModel): secret: str = Field(..., alias='secret') accessedat: str = Field(..., alias='accessedAt') sdks: List[Any] = Field(..., alias='sdks') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'scopes' not in data: + data['scopes'] = [] + if 'secret' not in data: + data['secret'] = '' + if 'accessedAt' not in data and 'accessedat' not in data: + data['accessedAt'] = '' + return data diff --git a/appwrite/models/execution.py b/appwrite/models/execution.py index 37706152..c29be85e 100644 --- a/appwrite/models/execution.py +++ b/appwrite/models/execution.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.execution_resource_type import ExecutionResourceType @@ -49,7 +49,7 @@ class Execution(AppwriteModel): errors : str Resource errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload. duration : float - Resource(function/site) execution duration in seconds. + Total time the resource(function/site) took to respond, in seconds. scheduledat : Optional[str] The scheduled time for execution. If left empty, execution will be queued immediately. """ @@ -73,3 +73,38 @@ class Execution(AppwriteModel): errors: str = Field(..., alias='errors') duration: float = Field(..., alias='duration') scheduledat: Optional[str] = Field(default=None, alias='scheduledAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = 'functions' + if 'deploymentId' not in data and 'deploymentid' not in data: + data['deploymentId'] = '' + if 'requestMethod' not in data and 'requestmethod' not in data: + data['requestMethod'] = '' + if 'requestPath' not in data and 'requestpath' not in data: + data['requestPath'] = '' + if 'responseStatusCode' not in data and 'responsestatuscode' not in data: + data['responseStatusCode'] = 0 + if 'responseBody' not in data and 'responsebody' not in data: + data['responseBody'] = '' + if 'logs' not in data: + data['logs'] = '' + if 'errors' not in data: + data['errors'] = '' + if 'duration' not in data: + data['duration'] = 0 + return data diff --git a/appwrite/models/execution_list.py b/appwrite/models/execution_list.py index a3adbe24..35a05206 100644 --- a/appwrite/models/execution_list.py +++ b/appwrite/models/execution_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .execution import Execution @@ -19,3 +19,14 @@ class ExecutionList(AppwriteModel): total: float = Field(..., alias='total') executions: List[Execution] = Field(..., alias='executions') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/file.py b/appwrite/models/file.py index dbf040c8..997d6cef 100644 --- a/appwrite/models/file.py +++ b/appwrite/models/file.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -60,3 +60,44 @@ class File(AppwriteModel): chunksuploaded: float = Field(..., alias='chunksUploaded') encryption: bool = Field(..., alias='encryption') compression: str = Field(..., alias='compression') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'bucketId' not in data and 'bucketid' not in data: + data['bucketId'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if '$permissions' not in data and 'permissions' not in data: + data['$permissions'] = [] + if 'name' not in data: + data['name'] = '' + if 'folder' not in data: + data['folder'] = '' + if 'key' not in data: + data['key'] = '' + if 'signature' not in data: + data['signature'] = '' + if 'mimeType' not in data and 'mimetype' not in data: + data['mimeType'] = '' + if 'sizeOriginal' not in data and 'sizeoriginal' not in data: + data['sizeOriginal'] = 0 + if 'sizeActual' not in data and 'sizeactual' not in data: + data['sizeActual'] = 0 + if 'chunksTotal' not in data and 'chunkstotal' not in data: + data['chunksTotal'] = 0 + if 'chunksUploaded' not in data and 'chunksuploaded' not in data: + data['chunksUploaded'] = 0 + if 'encryption' not in data: + data['encryption'] = False + if 'compression' not in data: + data['compression'] = 'none' + return data diff --git a/appwrite/models/file_list.py b/appwrite/models/file_list.py index c5166525..e4f7abad 100644 --- a/appwrite/models/file_list.py +++ b/appwrite/models/file_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .file import File @@ -19,3 +19,14 @@ class FileList(AppwriteModel): total: float = Field(..., alias='total') files: List[File] = Field(..., alias='files') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/framework.py b/appwrite/models/framework.py index f9fc73d2..fe735feb 100644 --- a/appwrite/models/framework.py +++ b/appwrite/models/framework.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .framework_adapter import FrameworkAdapter @@ -28,3 +28,18 @@ class Framework(AppwriteModel): buildruntime: str = Field(..., alias='buildRuntime') runtimes: List[Any] = Field(..., alias='runtimes') adapters: List[FrameworkAdapter] = Field(..., alias='adapters') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'name' not in data: + data['name'] = '' + if 'buildRuntime' not in data and 'buildruntime' not in data: + data['buildRuntime'] = '' + return data diff --git a/appwrite/models/framework_adapter.py b/appwrite/models/framework_adapter.py index 1cfac625..5a2a3743 100644 --- a/appwrite/models/framework_adapter.py +++ b/appwrite/models/framework_adapter.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,20 @@ class FrameworkAdapter(AppwriteModel): buildcommand: str = Field(..., alias='buildCommand') outputdirectory: str = Field(..., alias='outputDirectory') fallbackfile: Optional[str] = Field(default=None, alias='fallbackFile') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'installCommand' not in data and 'installcommand' not in data: + data['installCommand'] = '' + if 'buildCommand' not in data and 'buildcommand' not in data: + data['buildCommand'] = '' + if 'outputDirectory' not in data and 'outputdirectory' not in data: + data['outputDirectory'] = '' + return data diff --git a/appwrite/models/framework_list.py b/appwrite/models/framework_list.py index 47ab1244..ca39b1f5 100644 --- a/appwrite/models/framework_list.py +++ b/appwrite/models/framework_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .framework import Framework @@ -19,3 +19,14 @@ class FrameworkList(AppwriteModel): total: float = Field(..., alias='total') frameworks: List[Framework] = Field(..., alias='frameworks') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/function.py b/appwrite/models/function.py index c080c4bc..ba2cb5e9 100644 --- a/appwrite/models/function.py +++ b/appwrite/models/function.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .variable import Variable @@ -112,3 +112,74 @@ class Function(AppwriteModel): providerpaths: List[Any] = Field(..., alias='providerPaths') buildspecification: str = Field(..., alias='buildSpecification') runtimespecification: str = Field(..., alias='runtimeSpecification') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'execute' not in data: + data['execute'] = [] + if 'name' not in data: + data['name'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'live' not in data: + data['live'] = True + if 'logging' not in data: + data['logging'] = True + if 'runtime' not in data: + data['runtime'] = '' + if 'deploymentRetention' not in data and 'deploymentretention' not in data: + data['deploymentRetention'] = 0 + if 'deploymentId' not in data and 'deploymentid' not in data: + data['deploymentId'] = '' + if 'deploymentCreatedAt' not in data and 'deploymentcreatedat' not in data: + data['deploymentCreatedAt'] = '' + if 'latestDeploymentId' not in data and 'latestdeploymentid' not in data: + data['latestDeploymentId'] = '' + if 'latestDeploymentCreatedAt' not in data and 'latestdeploymentcreatedat' not in data: + data['latestDeploymentCreatedAt'] = '' + if 'latestDeploymentStatus' not in data and 'latestdeploymentstatus' not in data: + data['latestDeploymentStatus'] = '' + if 'scopes' not in data: + data['scopes'] = [] + if 'events' not in data: + data['events'] = [] + if 'schedule' not in data: + data['schedule'] = '' + if 'timeout' not in data: + data['timeout'] = 15 + if 'entrypoint' not in data: + data['entrypoint'] = '' + if 'commands' not in data: + data['commands'] = '' + if 'version' not in data: + data['version'] = 'v5' + if 'installationId' not in data and 'installationid' not in data: + data['installationId'] = '' + if 'providerRepositoryId' not in data and 'providerrepositoryid' not in data: + data['providerRepositoryId'] = '' + if 'providerBranch' not in data and 'providerbranch' not in data: + data['providerBranch'] = '' + if 'providerRootDirectory' not in data and 'providerrootdirectory' not in data: + data['providerRootDirectory'] = '' + if 'providerSilentMode' not in data and 'providersilentmode' not in data: + data['providerSilentMode'] = False + if 'providerBranches' not in data and 'providerbranches' not in data: + data['providerBranches'] = [] + if 'providerPaths' not in data and 'providerpaths' not in data: + data['providerPaths'] = [] + if 'buildSpecification' not in data and 'buildspecification' not in data: + data['buildSpecification'] = 's-1vcpu-512mb' + if 'runtimeSpecification' not in data and 'runtimespecification' not in data: + data['runtimeSpecification'] = 's-1vcpu-512mb' + return data diff --git a/appwrite/models/function_list.py b/appwrite/models/function_list.py index ec302b07..ccc67fd5 100644 --- a/appwrite/models/function_list.py +++ b/appwrite/models/function_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .function import Function @@ -19,3 +19,14 @@ class FunctionList(AppwriteModel): total: float = Field(..., alias='total') functions: List[Function] = Field(..., alias='functions') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/headers.py b/appwrite/models/headers.py index 569f2e9f..301dc02a 100644 --- a/appwrite/models/headers.py +++ b/appwrite/models/headers.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class Headers(AppwriteModel): name: str = Field(..., alias='name') value: str = Field(..., alias='value') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'name' not in data: + data['name'] = '' + if 'value' not in data: + data['value'] = '' + return data diff --git a/appwrite/models/identity.py b/appwrite/models/identity.py index c5ff2655..5366f7dd 100644 --- a/appwrite/models/identity.py +++ b/appwrite/models/identity.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -30,6 +30,8 @@ class Identity(AppwriteModel): The date of when the access token expires in ISO 8601 format. providerrefreshtoken : str Identity Provider Refresh Token. + provideridtoken : str + Identity Provider ID token (JWT) from the most recent native sign-in. Empty for identities created through the browser OAuth2 flow. """ id: str = Field(..., alias='$id') @@ -42,3 +44,35 @@ class Identity(AppwriteModel): provideraccesstoken: str = Field(..., alias='providerAccessToken') provideraccesstokenexpiry: str = Field(..., alias='providerAccessTokenExpiry') providerrefreshtoken: str = Field(..., alias='providerRefreshToken') + provideridtoken: str = Field(..., alias='providerIdToken') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'provider' not in data: + data['provider'] = '' + if 'providerUid' not in data and 'provideruid' not in data: + data['providerUid'] = '' + if 'providerEmail' not in data and 'provideremail' not in data: + data['providerEmail'] = '' + if 'providerAccessToken' not in data and 'provideraccesstoken' not in data: + data['providerAccessToken'] = '' + if 'providerAccessTokenExpiry' not in data and 'provideraccesstokenexpiry' not in data: + data['providerAccessTokenExpiry'] = '' + if 'providerRefreshToken' not in data and 'providerrefreshtoken' not in data: + data['providerRefreshToken'] = '' + if 'providerIdToken' not in data and 'provideridtoken' not in data: + data['providerIdToken'] = '' + return data diff --git a/appwrite/models/identity_list.py b/appwrite/models/identity_list.py index ced73450..847763a7 100644 --- a/appwrite/models/identity_list.py +++ b/appwrite/models/identity_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .identity import Identity @@ -19,3 +19,14 @@ class IdentityList(AppwriteModel): total: float = Field(..., alias='total') identities: List[Identity] = Field(..., alias='identities') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/index.py b/appwrite/models/index.py index aea86c9f..21613a19 100644 --- a/appwrite/models/index.py +++ b/appwrite/models/index.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.index_status import IndexStatus @@ -43,3 +43,28 @@ class Index(AppwriteModel): attributes: List[Any] = Field(..., alias='attributes') lengths: List[Any] = Field(..., alias='lengths') orders: Optional[List[Any]] = Field(default=None, alias='orders') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'key' not in data: + data['key'] = '' + if 'type' not in data: + data['type'] = '' + if 'error' not in data: + data['error'] = '' + if 'attributes' not in data: + data['attributes'] = [] + if 'lengths' not in data: + data['lengths'] = [] + return data diff --git a/appwrite/models/index_list.py b/appwrite/models/index_list.py index b9eeab2c..bd4385a0 100644 --- a/appwrite/models/index_list.py +++ b/appwrite/models/index_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .index import Index @@ -19,3 +19,14 @@ class IndexList(AppwriteModel): total: float = Field(..., alias='total') indexes: List[Index] = Field(..., alias='indexes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/insight.py b/appwrite/models/insight.py index 8c561228..0bca9ecf 100644 --- a/appwrite/models/insight.py +++ b/appwrite/models/insight.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .insight_cta import InsightCTA @@ -64,3 +64,38 @@ class Insight(AppwriteModel): analyzedat: Optional[str] = Field(default=None, alias='analyzedAt') dismissedat: Optional[str] = Field(default=None, alias='dismissedAt') dismissedby: Optional[str] = Field(default=None, alias='dismissedBy') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'reportId' not in data and 'reportid' not in data: + data['reportId'] = '' + if 'type' not in data: + data['type'] = '' + if 'severity' not in data: + data['severity'] = 'info' + if 'status' not in data: + data['status'] = 'active' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = '' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'parentResourceType' not in data and 'parentresourcetype' not in data: + data['parentResourceType'] = '' + if 'parentResourceId' not in data and 'parentresourceid' not in data: + data['parentResourceId'] = '' + if 'title' not in data: + data['title'] = '' + if 'summary' not in data: + data['summary'] = '' + return data diff --git a/appwrite/models/insight_cta.py b/appwrite/models/insight_cta.py index bc4144f7..8daed55e 100644 --- a/appwrite/models/insight_cta.py +++ b/appwrite/models/insight_cta.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class InsightCTA(AppwriteModel): service: str = Field(..., alias='service') method: str = Field(..., alias='method') params: Dict[str, Any] = Field(..., alias='params') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'label' not in data: + data['label'] = '' + if 'service' not in data: + data['service'] = '' + if 'method' not in data: + data['method'] = '' + if 'params' not in data: + data['params'] = [] + return data diff --git a/appwrite/models/insight_list.py b/appwrite/models/insight_list.py index 1ac76409..2e46e70a 100644 --- a/appwrite/models/insight_list.py +++ b/appwrite/models/insight_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .insight import Insight @@ -19,3 +19,14 @@ class InsightList(AppwriteModel): total: float = Field(..., alias='total') insights: List[Insight] = Field(..., alias='insights') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/jwt.py b/appwrite/models/jwt.py index 4887d305..f51ad977 100644 --- a/appwrite/models/jwt.py +++ b/appwrite/models/jwt.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class Jwt(AppwriteModel): """ jwt: str = Field(..., alias='jwt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'jwt' not in data: + data['jwt'] = '' + return data diff --git a/appwrite/models/key.py b/appwrite/models/key.py index b47526d9..766ec467 100644 --- a/appwrite/models/key.py +++ b/appwrite/models/key.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,28 @@ class Key(AppwriteModel): secret: str = Field(..., alias='secret') accessedat: str = Field(..., alias='accessedAt') sdks: List[Any] = Field(..., alias='sdks') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'scopes' not in data: + data['scopes'] = [] + if 'secret' not in data: + data['secret'] = '' + if 'accessedAt' not in data and 'accessedat' not in data: + data['accessedAt'] = '' + return data diff --git a/appwrite/models/key_list.py b/appwrite/models/key_list.py index 067da645..c5c649e0 100644 --- a/appwrite/models/key_list.py +++ b/appwrite/models/key_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .key import Key @@ -19,3 +19,14 @@ class KeyList(AppwriteModel): total: float = Field(..., alias='total') keys: List[Key] = Field(..., alias='keys') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/language.py b/appwrite/models/language.py index 15f23e53..2be89174 100644 --- a/appwrite/models/language.py +++ b/appwrite/models/language.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -21,3 +21,18 @@ class Language(AppwriteModel): name: str = Field(..., alias='name') code: str = Field(..., alias='code') nativename: str = Field(..., alias='nativeName') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'name' not in data: + data['name'] = '' + if 'code' not in data: + data['code'] = '' + if 'nativeName' not in data and 'nativename' not in data: + data['nativeName'] = '' + return data diff --git a/appwrite/models/language_list.py b/appwrite/models/language_list.py index 2e3ff697..cf9ece10 100644 --- a/appwrite/models/language_list.py +++ b/appwrite/models/language_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .language import Language @@ -19,3 +19,14 @@ class LanguageList(AppwriteModel): total: float = Field(..., alias='total') languages: List[Language] = Field(..., alias='languages') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/locale.py b/appwrite/models/locale.py index 8d9cef21..42767681 100644 --- a/appwrite/models/locale.py +++ b/appwrite/models/locale.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -66,3 +66,26 @@ class Locale(AppwriteModel): connectiontype: Optional[str] = Field(default=None, alias='connectionType') connectionusagetype: Optional[str] = Field(default=None, alias='connectionUsageType') connectionorganization: Optional[str] = Field(default=None, alias='connectionOrganization') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'ip' not in data: + data['ip'] = '' + if 'countryCode' not in data and 'countrycode' not in data: + data['countryCode'] = '' + if 'country' not in data: + data['country'] = '' + if 'continentCode' not in data and 'continentcode' not in data: + data['continentCode'] = '' + if 'continent' not in data: + data['continent'] = '' + if 'eu' not in data: + data['eu'] = False + if 'currency' not in data: + data['currency'] = '' + return data diff --git a/appwrite/models/locale_code.py b/appwrite/models/locale_code.py index 5381c5ec..6656f684 100644 --- a/appwrite/models/locale_code.py +++ b/appwrite/models/locale_code.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class LocaleCode(AppwriteModel): code: str = Field(..., alias='code') name: str = Field(..., alias='name') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'code' not in data: + data['code'] = '' + if 'name' not in data: + data['name'] = '' + return data diff --git a/appwrite/models/locale_code_list.py b/appwrite/models/locale_code_list.py index c80ce4ad..abdf6d5e 100644 --- a/appwrite/models/locale_code_list.py +++ b/appwrite/models/locale_code_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .locale_code import LocaleCode @@ -19,3 +19,14 @@ class LocaleCodeList(AppwriteModel): total: float = Field(..., alias='total') localecodes: List[LocaleCode] = Field(..., alias='localeCodes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/log.py b/appwrite/models/log.py deleted file mode 100644 index a3b74c15..00000000 --- a/appwrite/models/log.py +++ /dev/null @@ -1,80 +0,0 @@ -from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr - -from .base_model import AppwriteModel - - -class Log(AppwriteModel): - """ - Log - - Attributes - ---------- - event : str - Event name. - userid : str - User ID of the actor recorded for this log. During impersonation, this is the original impersonator, not the impersonated target user. - useremail : str - User email of the actor recorded for this log. During impersonation, this is the original impersonator. - username : str - User name of the actor recorded for this log. During impersonation, this is the original impersonator. - mode : str - API mode when event triggered. - usertype : str - User type who triggered the audit log. Possible values: user, admin, guest, hidden, keyProject, keyAccount, keyOrganization. - ip : str - IP session in use when the session was created. - time : str - Log creation date in ISO 8601 format. - oscode : str - Operating system code name. View list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/os.json). - osname : str - Operating system name. - osversion : str - Operating system version. - clienttype : str - Client type. - clientcode : str - Client code name. View list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/clients.json). - clientname : str - Client name. - clientversion : str - Client version. - clientengine : str - Client engine name. - clientengineversion : str - Client engine name. - devicename : str - Device name. - devicebrand : str - Device brand name. - devicemodel : str - Device model name. - countrycode : str - Country two-character ISO 3166-1 alpha code. - countryname : str - Country name. - """ - - event: str = Field(..., alias='event') - userid: str = Field(..., alias='userId') - useremail: str = Field(..., alias='userEmail') - username: str = Field(..., alias='userName') - mode: str = Field(..., alias='mode') - usertype: str = Field(..., alias='userType') - ip: str = Field(..., alias='ip') - time: str = Field(..., alias='time') - oscode: str = Field(..., alias='osCode') - osname: str = Field(..., alias='osName') - osversion: str = Field(..., alias='osVersion') - clienttype: str = Field(..., alias='clientType') - clientcode: str = Field(..., alias='clientCode') - clientname: str = Field(..., alias='clientName') - clientversion: str = Field(..., alias='clientVersion') - clientengine: str = Field(..., alias='clientEngine') - clientengineversion: str = Field(..., alias='clientEngineVersion') - devicename: str = Field(..., alias='deviceName') - devicebrand: str = Field(..., alias='deviceBrand') - devicemodel: str = Field(..., alias='deviceModel') - countrycode: str = Field(..., alias='countryCode') - countryname: str = Field(..., alias='countryName') diff --git a/appwrite/models/log_list.py b/appwrite/models/log_list.py deleted file mode 100644 index 33ff6c77..00000000 --- a/appwrite/models/log_list.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr - -from .base_model import AppwriteModel -from .log import Log - - -class LogList(AppwriteModel): - """ - Logs List - - Attributes - ---------- - total : float - Total number of logs that matched your query. - logs : List[Log] - List of logs. - """ - - total: float = Field(..., alias='total') - logs: List[Log] = Field(..., alias='logs') diff --git a/appwrite/models/membership.py b/appwrite/models/membership.py index 173096ce..810aad13 100644 --- a/appwrite/models/membership.py +++ b/appwrite/models/membership.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -57,3 +57,42 @@ class Membership(AppwriteModel): mfa: bool = Field(..., alias='mfa') useraccessedat: str = Field(..., alias='userAccessedAt') roles: List[Any] = Field(..., alias='roles') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'userName' not in data and 'username' not in data: + data['userName'] = '' + if 'userEmail' not in data and 'useremail' not in data: + data['userEmail'] = '' + if 'userPhone' not in data and 'userphone' not in data: + data['userPhone'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'teamName' not in data and 'teamname' not in data: + data['teamName'] = '' + if 'invited' not in data: + data['invited'] = '' + if 'joined' not in data: + data['joined'] = '' + if 'confirm' not in data: + data['confirm'] = False + if 'mfa' not in data: + data['mfa'] = False + if 'userAccessedAt' not in data and 'useraccessedat' not in data: + data['userAccessedAt'] = '' + if 'roles' not in data: + data['roles'] = [] + return data diff --git a/appwrite/models/membership_list.py b/appwrite/models/membership_list.py index 19f23189..9ac2732e 100644 --- a/appwrite/models/membership_list.py +++ b/appwrite/models/membership_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .membership import Membership @@ -19,3 +19,14 @@ class MembershipList(AppwriteModel): total: float = Field(..., alias='total') memberships: List[Membership] = Field(..., alias='memberships') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/message.py b/appwrite/models/message.py index 6662583f..aacbf86a 100644 --- a/appwrite/models/message.py +++ b/appwrite/models/message.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.message_status import MessageStatus @@ -52,3 +52,26 @@ class Message(AppwriteModel): deliveredtotal: float = Field(..., alias='deliveredTotal') data: Dict[str, Any] = Field(..., alias='data') status: MessageStatus = Field(..., alias='status') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'providerType' not in data and 'providertype' not in data: + data['providerType'] = '' + if 'deliveredTotal' not in data and 'deliveredtotal' not in data: + data['deliveredTotal'] = 0 + if 'data' not in data: + data['data'] = [] + if 'status' not in data: + data['status'] = 'draft' + return data diff --git a/appwrite/models/message_list.py b/appwrite/models/message_list.py index ffea3f8f..ef8c9db5 100644 --- a/appwrite/models/message_list.py +++ b/appwrite/models/message_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .message import Message @@ -19,3 +19,14 @@ class MessageList(AppwriteModel): total: float = Field(..., alias='total') messages: List[Message] = Field(..., alias='messages') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/mfa_challenge.py b/appwrite/models/mfa_challenge.py index 5ad1ec9c..6602c6b5 100644 --- a/appwrite/models/mfa_challenge.py +++ b/appwrite/models/mfa_challenge.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class MfaChallenge(AppwriteModel): createdat: str = Field(..., alias='$createdAt') userid: str = Field(..., alias='userId') expire: str = Field(..., alias='expire') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'expire' not in data: + data['expire'] = '' + return data diff --git a/appwrite/models/mfa_challenge_secret.py b/appwrite/models/mfa_challenge_secret.py index e9a03fb1..2eab2511 100644 --- a/appwrite/models/mfa_challenge_secret.py +++ b/appwrite/models/mfa_challenge_secret.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class MfaChallengeSecret(AppwriteModel): userid: str = Field(..., alias='userId') expire: str = Field(..., alias='expire') code: str = Field(..., alias='code') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'code' not in data: + data['code'] = '' + return data diff --git a/appwrite/models/mfa_factors.py b/appwrite/models/mfa_factors.py index 24810f03..a11ca15a 100644 --- a/appwrite/models/mfa_factors.py +++ b/appwrite/models/mfa_factors.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class MfaFactors(AppwriteModel): email: bool = Field(..., alias='email') recoverycode: bool = Field(..., alias='recoveryCode') custom: bool = Field(..., alias='custom') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'totp' not in data: + data['totp'] = False + if 'phone' not in data: + data['phone'] = False + if 'email' not in data: + data['email'] = False + if 'recoveryCode' not in data and 'recoverycode' not in data: + data['recoveryCode'] = False + if 'custom' not in data: + data['custom'] = False + return data diff --git a/appwrite/models/mfa_recovery_codes.py b/appwrite/models/mfa_recovery_codes.py index e64bf853..52ff1d66 100644 --- a/appwrite/models/mfa_recovery_codes.py +++ b/appwrite/models/mfa_recovery_codes.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class MfaRecoveryCodes(AppwriteModel): """ recoverycodes: List[Any] = Field(..., alias='recoveryCodes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'recoveryCodes' not in data and 'recoverycodes' not in data: + data['recoveryCodes'] = [] + return data diff --git a/appwrite/models/mfa_type.py b/appwrite/models/mfa_type.py index 5d6bb5e9..1afba454 100644 --- a/appwrite/models/mfa_type.py +++ b/appwrite/models/mfa_type.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class MfaType(AppwriteModel): secret: str = Field(..., alias='secret') uri: str = Field(..., alias='uri') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'secret' not in data: + data['secret'] = '' + if 'uri' not in data: + data['uri'] = '' + return data diff --git a/appwrite/models/mock_number.py b/appwrite/models/mock_number.py index 9e6f09cc..5e63da1b 100644 --- a/appwrite/models/mock_number.py +++ b/appwrite/models/mock_number.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class MockNumber(AppwriteModel): otp: str = Field(..., alias='otp') createdat: str = Field(..., alias='$createdAt') updatedat: str = Field(..., alias='$updatedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'number' not in data: + data['number'] = '' + if 'otp' not in data: + data['otp'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data diff --git a/appwrite/models/mock_number_list.py b/appwrite/models/mock_number_list.py index ae29efe9..e3b73db9 100644 --- a/appwrite/models/mock_number_list.py +++ b/appwrite/models/mock_number_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .mock_number import MockNumber @@ -19,3 +19,14 @@ class MockNumberList(AppwriteModel): total: float = Field(..., alias='total') mocknumbers: List[MockNumber] = Field(..., alias='mockNumbers') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/o_auth2_amazon.py b/appwrite/models/o_auth2_amazon.py index aad2ebb3..4d7b7b9a 100644 --- a/appwrite/models/o_auth2_amazon.py +++ b/appwrite/models/o_auth2_amazon.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Amazon(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_apple.py b/appwrite/models/o_auth2_apple.py index e5f2e488..4acb8fbc 100644 --- a/appwrite/models/o_auth2_apple.py +++ b/appwrite/models/o_auth2_apple.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -22,6 +22,10 @@ class OAuth2Apple(AppwriteModel): Apple OAuth2 team ID. p8file : str Apple OAuth2 .p8 private key file contents. The secret key wrapped by the PEM markers is 200 characters long. + nativeenabled : bool + Native Sign in with Apple is active and can be used to create sessions from an ID token. Independent of enabled, which only controls the browser-based flow. + nativeclientids : List[Any] + App bundle IDs accepted as ID token audiences for native Sign in with Apple, next to the Services ID. """ id: str = Field(..., alias='$id') @@ -30,3 +34,30 @@ class OAuth2Apple(AppwriteModel): keyid: str = Field(..., alias='keyId') teamid: str = Field(..., alias='teamId') p8file: str = Field(..., alias='p8File') + nativeenabled: bool = Field(..., alias='nativeEnabled') + nativeclientids: List[Any] = Field(..., alias='nativeClientIds') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'serviceId' not in data and 'serviceid' not in data: + data['serviceId'] = '' + if 'keyId' not in data and 'keyid' not in data: + data['keyId'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'p8File' not in data and 'p8file' not in data: + data['p8File'] = '' + if 'nativeEnabled' not in data and 'nativeenabled' not in data: + data['nativeEnabled'] = False + if 'nativeClientIds' not in data and 'nativeclientids' not in data: + data['nativeClientIds'] = [] + return data diff --git a/appwrite/models/o_auth2_appwrite.py b/appwrite/models/o_auth2_appwrite.py index 7d5f4a34..f80a0bb8 100644 --- a/appwrite/models/o_auth2_appwrite.py +++ b/appwrite/models/o_auth2_appwrite.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Appwrite(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_auth0.py b/appwrite/models/o_auth2_auth0.py index d3d95e2f..d27f4797 100644 --- a/appwrite/models/o_auth2_auth0.py +++ b/appwrite/models/o_auth2_auth0.py @@ -1,7 +1,8 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel +from ..enums.o_auth2_auth0_prompt import OAuth2Auth0Prompt class OAuth2Auth0(AppwriteModel): @@ -18,6 +19,8 @@ class OAuth2Auth0(AppwriteModel): Auth0 OAuth2 client ID. clientsecret : str Auth0 OAuth2 client secret. + prompt : List[OAuth2Auth0Prompt] + Auth0 OAuth2 prompt values. endpoint : str Auth0 OAuth2 endpoint domain. """ @@ -26,4 +29,26 @@ class OAuth2Auth0(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + prompt: List[OAuth2Auth0Prompt] = Field(..., alias='prompt') endpoint: str = Field(..., alias='endpoint') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + if 'endpoint' not in data: + data['endpoint'] = '' + return data diff --git a/appwrite/models/o_auth2_authentik.py b/appwrite/models/o_auth2_authentik.py index 917c67eb..12e29212 100644 --- a/appwrite/models/o_auth2_authentik.py +++ b/appwrite/models/o_auth2_authentik.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class OAuth2Authentik(AppwriteModel): clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') endpoint: str = Field(..., alias='endpoint') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'endpoint' not in data: + data['endpoint'] = '' + return data diff --git a/appwrite/models/o_auth2_autodesk.py b/appwrite/models/o_auth2_autodesk.py index 69bf0aba..d58de659 100644 --- a/appwrite/models/o_auth2_autodesk.py +++ b/appwrite/models/o_auth2_autodesk.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Autodesk(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_bitbucket.py b/appwrite/models/o_auth2_bitbucket.py index a62d0979..247f3b9c 100644 --- a/appwrite/models/o_auth2_bitbucket.py +++ b/appwrite/models/o_auth2_bitbucket.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Bitbucket(AppwriteModel): enabled: bool = Field(..., alias='enabled') key: str = Field(..., alias='key') secret: str = Field(..., alias='secret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'key' not in data: + data['key'] = '' + if 'secret' not in data: + data['secret'] = '' + return data diff --git a/appwrite/models/o_auth2_bitly.py b/appwrite/models/o_auth2_bitly.py index f3284f4b..00e893ed 100644 --- a/appwrite/models/o_auth2_bitly.py +++ b/appwrite/models/o_auth2_bitly.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Bitly(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_box.py b/appwrite/models/o_auth2_box.py index f64f0140..492bc38d 100644 --- a/appwrite/models/o_auth2_box.py +++ b/appwrite/models/o_auth2_box.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Box(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_cloudflare.py b/appwrite/models/o_auth2_cloudflare.py index 5099f214..5d977c6e 100644 --- a/appwrite/models/o_auth2_cloudflare.py +++ b/appwrite/models/o_auth2_cloudflare.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Cloudflare(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_dailymotion.py b/appwrite/models/o_auth2_dailymotion.py index fa1836c3..d8e3ece8 100644 --- a/appwrite/models/o_auth2_dailymotion.py +++ b/appwrite/models/o_auth2_dailymotion.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Dailymotion(AppwriteModel): enabled: bool = Field(..., alias='enabled') apikey: str = Field(..., alias='apiKey') apisecret: str = Field(..., alias='apiSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'apiKey' not in data and 'apikey' not in data: + data['apiKey'] = '' + if 'apiSecret' not in data and 'apisecret' not in data: + data['apiSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_discord.py b/appwrite/models/o_auth2_discord.py index 8516e192..0921e557 100644 --- a/appwrite/models/o_auth2_discord.py +++ b/appwrite/models/o_auth2_discord.py @@ -1,7 +1,8 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel +from ..enums.o_auth2_discord_prompt import OAuth2DiscordPrompt class OAuth2Discord(AppwriteModel): @@ -18,9 +19,31 @@ class OAuth2Discord(AppwriteModel): Discord OAuth2 client ID. clientsecret : str Discord OAuth2 client secret. + prompt : List[OAuth2DiscordPrompt] + Discord OAuth2 prompt values. """ id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + prompt: List[OAuth2DiscordPrompt] = Field(..., alias='prompt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + return data diff --git a/appwrite/models/o_auth2_disqus.py b/appwrite/models/o_auth2_disqus.py index 302fc486..f534f160 100644 --- a/appwrite/models/o_auth2_disqus.py +++ b/appwrite/models/o_auth2_disqus.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Disqus(AppwriteModel): enabled: bool = Field(..., alias='enabled') publickey: str = Field(..., alias='publicKey') secretkey: str = Field(..., alias='secretKey') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'publicKey' not in data and 'publickey' not in data: + data['publicKey'] = '' + if 'secretKey' not in data and 'secretkey' not in data: + data['secretKey'] = '' + return data diff --git a/appwrite/models/o_auth2_dropbox.py b/appwrite/models/o_auth2_dropbox.py index d8b980f8..1e598082 100644 --- a/appwrite/models/o_auth2_dropbox.py +++ b/appwrite/models/o_auth2_dropbox.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Dropbox(AppwriteModel): enabled: bool = Field(..., alias='enabled') appkey: str = Field(..., alias='appKey') appsecret: str = Field(..., alias='appSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'appKey' not in data and 'appkey' not in data: + data['appKey'] = '' + if 'appSecret' not in data and 'appsecret' not in data: + data['appSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_etsy.py b/appwrite/models/o_auth2_etsy.py index 9b3b7480..8226ae65 100644 --- a/appwrite/models/o_auth2_etsy.py +++ b/appwrite/models/o_auth2_etsy.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Etsy(AppwriteModel): enabled: bool = Field(..., alias='enabled') keystring: str = Field(..., alias='keyString') sharedsecret: str = Field(..., alias='sharedSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'keyString' not in data and 'keystring' not in data: + data['keyString'] = '' + if 'sharedSecret' not in data and 'sharedsecret' not in data: + data['sharedSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_facebook.py b/appwrite/models/o_auth2_facebook.py index 83e72aa5..640ca559 100644 --- a/appwrite/models/o_auth2_facebook.py +++ b/appwrite/models/o_auth2_facebook.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Facebook(AppwriteModel): enabled: bool = Field(..., alias='enabled') appid: str = Field(..., alias='appId') appsecret: str = Field(..., alias='appSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'appSecret' not in data and 'appsecret' not in data: + data['appSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_figma.py b/appwrite/models/o_auth2_figma.py index 3ad1bb66..5c650b1b 100644 --- a/appwrite/models/o_auth2_figma.py +++ b/appwrite/models/o_auth2_figma.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Figma(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_fusion_auth.py b/appwrite/models/o_auth2_fusion_auth.py index b38e63a3..25d57023 100644 --- a/appwrite/models/o_auth2_fusion_auth.py +++ b/appwrite/models/o_auth2_fusion_auth.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class OAuth2FusionAuth(AppwriteModel): clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') endpoint: str = Field(..., alias='endpoint') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'endpoint' not in data: + data['endpoint'] = '' + return data diff --git a/appwrite/models/o_auth2_github.py b/appwrite/models/o_auth2_github.py index d436fa70..e8305891 100644 --- a/appwrite/models/o_auth2_github.py +++ b/appwrite/models/o_auth2_github.py @@ -1,7 +1,8 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel +from ..enums.o_auth2_github_prompt import OAuth2GithubPrompt class OAuth2Github(AppwriteModel): @@ -18,9 +19,31 @@ class OAuth2Github(AppwriteModel): GitHub OAuth2 client ID. For GitHub Apps, use the "App ID" when both an App ID and client ID are available. clientsecret : str GitHub OAuth2 client secret. + prompt : List[OAuth2GithubPrompt] + GitHub OAuth2 prompt values. """ id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + prompt: List[OAuth2GithubPrompt] = Field(..., alias='prompt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + return data diff --git a/appwrite/models/o_auth2_gitlab.py b/appwrite/models/o_auth2_gitlab.py index 3014d836..2c61563f 100644 --- a/appwrite/models/o_auth2_gitlab.py +++ b/appwrite/models/o_auth2_gitlab.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class OAuth2Gitlab(AppwriteModel): applicationid: str = Field(..., alias='applicationId') secret: str = Field(..., alias='secret') endpoint: str = Field(..., alias='endpoint') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'applicationId' not in data and 'applicationid' not in data: + data['applicationId'] = '' + if 'secret' not in data: + data['secret'] = '' + if 'endpoint' not in data: + data['endpoint'] = '' + return data diff --git a/appwrite/models/o_auth2_google.py b/appwrite/models/o_auth2_google.py index 7d815ef2..8a77adf6 100644 --- a/appwrite/models/o_auth2_google.py +++ b/appwrite/models/o_auth2_google.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.o_auth2_google_prompt import OAuth2GooglePrompt @@ -21,6 +21,10 @@ class OAuth2Google(AppwriteModel): Google OAuth2 client secret. prompt : List[OAuth2GooglePrompt] Google OAuth2 prompt values. + nativeenabled : bool + Native Google sign-in is active and can be used to create sessions from an ID token. Independent of enabled, which only controls the browser-based flow. + nativeclientids : List[Any] + Additional OAuth2 client IDs accepted as ID token audiences for native sign-in, next to the client ID. """ id: str = Field(..., alias='$id') @@ -28,3 +32,28 @@ class OAuth2Google(AppwriteModel): clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') prompt: List[OAuth2GooglePrompt] = Field(..., alias='prompt') + nativeenabled: bool = Field(..., alias='nativeEnabled') + nativeclientids: List[Any] = Field(..., alias='nativeClientIds') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'prompt' not in data: + data['prompt'] = ['consent'] + if 'nativeEnabled' not in data and 'nativeenabled' not in data: + data['nativeEnabled'] = False + if 'nativeClientIds' not in data and 'nativeclientids' not in data: + data['nativeClientIds'] = [] + return data diff --git a/appwrite/models/o_auth2_hugging_face.py b/appwrite/models/o_auth2_hugging_face.py index d35f9946..80dd65ad 100644 --- a/appwrite/models/o_auth2_hugging_face.py +++ b/appwrite/models/o_auth2_hugging_face.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2HuggingFace(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_kakao.py b/appwrite/models/o_auth2_kakao.py new file mode 100644 index 00000000..0277a6e7 --- /dev/null +++ b/appwrite/models/o_auth2_kakao.py @@ -0,0 +1,49 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from ..enums.o_auth2_kakao_prompt import OAuth2KakaoPrompt + + +class OAuth2Kakao(AppwriteModel): + """ + OAuth2Kakao + + Attributes + ---------- + id : str + OAuth2 provider ID. + enabled : bool + OAuth2 provider is active and can be used to create sessions. + clientid : str + Kakao OAuth2 REST API key. + clientsecret : str + Kakao OAuth2 client secret. + prompt : List[OAuth2KakaoPrompt] + Kakao OAuth2 prompt values. + """ + + id: str = Field(..., alias='$id') + enabled: bool = Field(..., alias='enabled') + clientid: str = Field(..., alias='clientId') + clientsecret: str = Field(..., alias='clientSecret') + prompt: List[OAuth2KakaoPrompt] = Field(..., alias='prompt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + return data diff --git a/appwrite/models/o_auth2_keycloak.py b/appwrite/models/o_auth2_keycloak.py index 674cfae4..941e44ca 100644 --- a/appwrite/models/o_auth2_keycloak.py +++ b/appwrite/models/o_auth2_keycloak.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -30,3 +30,24 @@ class OAuth2Keycloak(AppwriteModel): clientsecret: str = Field(..., alias='clientSecret') endpoint: str = Field(..., alias='endpoint') realmname: str = Field(..., alias='realmName') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'endpoint' not in data: + data['endpoint'] = '' + if 'realmName' not in data and 'realmname' not in data: + data['realmName'] = '' + return data diff --git a/appwrite/models/o_auth2_kick.py b/appwrite/models/o_auth2_kick.py index 2ef797ed..1615abac 100644 --- a/appwrite/models/o_auth2_kick.py +++ b/appwrite/models/o_auth2_kick.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Kick(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_linkedin.py b/appwrite/models/o_auth2_linkedin.py index 62bc6d11..7ebf1b76 100644 --- a/appwrite/models/o_auth2_linkedin.py +++ b/appwrite/models/o_auth2_linkedin.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Linkedin(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') primaryclientsecret: str = Field(..., alias='primaryClientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'primaryClientSecret' not in data and 'primaryclientsecret' not in data: + data['primaryClientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_microsoft.py b/appwrite/models/o_auth2_microsoft.py index 50cbdd56..5b3461cf 100644 --- a/appwrite/models/o_auth2_microsoft.py +++ b/appwrite/models/o_auth2_microsoft.py @@ -1,7 +1,8 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel +from ..enums.o_auth2_microsoft_prompt import OAuth2MicrosoftPrompt class OAuth2Microsoft(AppwriteModel): @@ -18,6 +19,8 @@ class OAuth2Microsoft(AppwriteModel): Microsoft OAuth2 application ID. applicationsecret : str Microsoft OAuth2 application secret. + prompt : List[OAuth2MicrosoftPrompt] + Microsoft OAuth2 prompt values. tenant : str Microsoft Entra ID tenant identifier. Use 'common', 'organizations', 'consumers' or a specific tenant ID. """ @@ -26,4 +29,26 @@ class OAuth2Microsoft(AppwriteModel): enabled: bool = Field(..., alias='enabled') applicationid: str = Field(..., alias='applicationId') applicationsecret: str = Field(..., alias='applicationSecret') + prompt: List[OAuth2MicrosoftPrompt] = Field(..., alias='prompt') tenant: str = Field(..., alias='tenant') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'applicationId' not in data and 'applicationid' not in data: + data['applicationId'] = '' + if 'applicationSecret' not in data and 'applicationsecret' not in data: + data['applicationSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + if 'tenant' not in data: + data['tenant'] = '' + return data diff --git a/appwrite/models/o_auth2_notion.py b/appwrite/models/o_auth2_notion.py index 8ce2bad2..d36eced4 100644 --- a/appwrite/models/o_auth2_notion.py +++ b/appwrite/models/o_auth2_notion.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Notion(AppwriteModel): enabled: bool = Field(..., alias='enabled') oauthclientid: str = Field(..., alias='oauthClientId') oauthclientsecret: str = Field(..., alias='oauthClientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'oauthClientId' not in data and 'oauthclientid' not in data: + data['oauthClientId'] = '' + if 'oauthClientSecret' not in data and 'oauthclientsecret' not in data: + data['oauthClientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_oidc.py b/appwrite/models/o_auth2_oidc.py index d2b65571..0024b934 100644 --- a/appwrite/models/o_auth2_oidc.py +++ b/appwrite/models/o_auth2_oidc.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.o_auth2_oidc_prompt import OAuth2OidcPrompt @@ -19,6 +19,8 @@ class OAuth2Oidc(AppwriteModel): OpenID Connect OAuth2 client ID. clientsecret : str OpenID Connect OAuth2 client secret. + prompt : List[OAuth2OidcPrompt] + OpenID Connect prompt values controlling the authentication and consent screens. wellknownurl : str OpenID Connect well-known configuration URL. When set, authorization, token, and user info endpoints can be discovered automatically. authorizationurl : str @@ -27,8 +29,6 @@ class OAuth2Oidc(AppwriteModel): OpenID Connect token endpoint URL. userinfourl : str OpenID Connect user info endpoint URL. - prompt : List[OAuth2OidcPrompt] - OpenID Connect prompt values controlling the authentication and consent screens. maxage : Optional[float] Maximum authentication age in seconds. When set, the user must have authenticated within this many seconds. """ @@ -37,9 +37,36 @@ class OAuth2Oidc(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + prompt: List[OAuth2OidcPrompt] = Field(..., alias='prompt') wellknownurl: str = Field(..., alias='wellKnownURL') authorizationurl: str = Field(..., alias='authorizationURL') tokenurl: str = Field(..., alias='tokenURL') userinfourl: str = Field(..., alias='userInfoURL') - prompt: List[OAuth2OidcPrompt] = Field(..., alias='prompt') maxage: Optional[float] = Field(default=None, alias='maxAge') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + if 'wellKnownURL' not in data and 'wellknownurl' not in data: + data['wellKnownURL'] = '' + if 'authorizationURL' not in data and 'authorizationurl' not in data: + data['authorizationURL'] = '' + if 'tokenURL' not in data and 'tokenurl' not in data: + data['tokenURL'] = '' + if 'userInfoURL' not in data and 'userinfourl' not in data: + data['userInfoURL'] = '' + return data diff --git a/appwrite/models/o_auth2_okta.py b/appwrite/models/o_auth2_okta.py index 4ecdd0b5..d07ff410 100644 --- a/appwrite/models/o_auth2_okta.py +++ b/appwrite/models/o_auth2_okta.py @@ -1,7 +1,8 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel +from ..enums.o_auth2_okta_prompt import OAuth2OktaPrompt class OAuth2Okta(AppwriteModel): @@ -18,6 +19,8 @@ class OAuth2Okta(AppwriteModel): Okta OAuth2 client ID. clientsecret : str Okta OAuth2 client secret. + prompt : List[OAuth2OktaPrompt] + Okta OAuth2 prompt values. domain : str Okta OAuth2 domain. authorizationserverid : str @@ -28,5 +31,29 @@ class OAuth2Okta(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + prompt: List[OAuth2OktaPrompt] = Field(..., alias='prompt') domain: str = Field(..., alias='domain') authorizationserverid: str = Field(..., alias='authorizationServerId') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + if 'domain' not in data: + data['domain'] = '' + if 'authorizationServerId' not in data and 'authorizationserverid' not in data: + data['authorizationServerId'] = '' + return data diff --git a/appwrite/models/o_auth2_paypal.py b/appwrite/models/o_auth2_paypal.py index a87cb0f8..d5fda507 100644 --- a/appwrite/models/o_auth2_paypal.py +++ b/appwrite/models/o_auth2_paypal.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Paypal(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') secretkey: str = Field(..., alias='secretKey') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'secretKey' not in data and 'secretkey' not in data: + data['secretKey'] = '' + return data diff --git a/appwrite/models/o_auth2_podio.py b/appwrite/models/o_auth2_podio.py index 79b256c7..f533a4a6 100644 --- a/appwrite/models/o_auth2_podio.py +++ b/appwrite/models/o_auth2_podio.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Podio(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_provider_list.py b/appwrite/models/o_auth2_provider_list.py index 09e97009..7ec14cb6 100644 --- a/appwrite/models/o_auth2_provider_list.py +++ b/appwrite/models/o_auth2_provider_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .o_auth2_github import OAuth2Github @@ -17,6 +17,7 @@ from .o_auth2_yandex import OAuth2Yandex from .o_auth2_x import OAuth2X from .o_auth2_word_press import OAuth2WordPress +from .o_auth2_webflow import OAuth2Webflow from .o_auth2_twitch import OAuth2Twitch from .o_auth2_stripe import OAuth2Stripe from .o_auth2_spotify import OAuth2Spotify @@ -46,6 +47,8 @@ from .o_auth2_hugging_face import OAuth2HuggingFace from .o_auth2_resend import OAuth2Resend from .o_auth2_cloudflare import OAuth2Cloudflare +from .o_auth2_tik_tok import OAuth2TikTok +from .o_auth2_kakao import OAuth2Kakao class OAuth2ProviderList(AppwriteModel): @@ -56,7 +59,7 @@ class OAuth2ProviderList(AppwriteModel): ---------- total : float Total number of OAuth2 providers in the given project. - providers : List[Union[OAuth2Github, OAuth2Discord, OAuth2Figma, OAuth2Dropbox, OAuth2Dailymotion, OAuth2Bitbucket, OAuth2Bitly, OAuth2Box, OAuth2Autodesk, OAuth2Google, OAuth2Zoom, OAuth2Zoho, OAuth2Yandex, OAuth2X, OAuth2WordPress, OAuth2Twitch, OAuth2Stripe, OAuth2Spotify, OAuth2Slack, OAuth2Podio, OAuth2Notion, OAuth2Salesforce, OAuth2Yahoo, OAuth2Linkedin, OAuth2Disqus, OAuth2Amazon, OAuth2Etsy, OAuth2Facebook, OAuth2Tradeshift, OAuth2Paypal, OAuth2Gitlab, OAuth2Appwrite, OAuth2Authentik, OAuth2Auth0, OAuth2FusionAuth, OAuth2Keycloak, OAuth2Oidc, OAuth2Apple, OAuth2Okta, OAuth2Kick, OAuth2Microsoft, OAuth2HuggingFace, OAuth2Resend, OAuth2Cloudflare]] + providers : List[Union[OAuth2Github, OAuth2Discord, OAuth2Figma, OAuth2Dropbox, OAuth2Dailymotion, OAuth2Bitbucket, OAuth2Bitly, OAuth2Box, OAuth2Autodesk, OAuth2Google, OAuth2Zoom, OAuth2Zoho, OAuth2Yandex, OAuth2X, OAuth2WordPress, OAuth2Webflow, OAuth2Twitch, OAuth2Stripe, OAuth2Spotify, OAuth2Slack, OAuth2Podio, OAuth2Notion, OAuth2Salesforce, OAuth2Yahoo, OAuth2Linkedin, OAuth2Disqus, OAuth2Amazon, OAuth2Etsy, OAuth2Facebook, OAuth2Tradeshift, OAuth2Paypal, OAuth2Gitlab, OAuth2Appwrite, OAuth2Authentik, OAuth2Auth0, OAuth2FusionAuth, OAuth2Keycloak, OAuth2Oidc, OAuth2Apple, OAuth2Okta, OAuth2Kick, OAuth2Microsoft, OAuth2HuggingFace, OAuth2Resend, OAuth2Cloudflare, OAuth2TikTok, OAuth2Kakao]] List of OAuth2 providers. """ @@ -78,6 +81,7 @@ class OAuth2ProviderList(AppwriteModel): OAuth2Yandex, OAuth2X, OAuth2WordPress, + OAuth2Webflow, OAuth2Twitch, OAuth2Stripe, OAuth2Spotify, @@ -107,5 +111,18 @@ class OAuth2ProviderList(AppwriteModel): OAuth2HuggingFace, OAuth2Resend, OAuth2Cloudflare, + OAuth2TikTok, + OAuth2Kakao, ] ] = Field(..., alias='providers') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/o_auth2_resend.py b/appwrite/models/o_auth2_resend.py index 0c3efb05..6209c774 100644 --- a/appwrite/models/o_auth2_resend.py +++ b/appwrite/models/o_auth2_resend.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Resend(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_salesforce.py b/appwrite/models/o_auth2_salesforce.py index e1170360..fde028a4 100644 --- a/appwrite/models/o_auth2_salesforce.py +++ b/appwrite/models/o_auth2_salesforce.py @@ -1,7 +1,8 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel +from ..enums.o_auth2_salesforce_prompt import OAuth2SalesforcePrompt class OAuth2Salesforce(AppwriteModel): @@ -18,9 +19,31 @@ class OAuth2Salesforce(AppwriteModel): Salesforce OAuth2 consumer key. customersecret : str Salesforce OAuth2 consumer secret. + prompt : List[OAuth2SalesforcePrompt] + Salesforce OAuth2 prompt values. """ id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') customerkey: str = Field(..., alias='customerKey') customersecret: str = Field(..., alias='customerSecret') + prompt: List[OAuth2SalesforcePrompt] = Field(..., alias='prompt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'customerKey' not in data and 'customerkey' not in data: + data['customerKey'] = '' + if 'customerSecret' not in data and 'customersecret' not in data: + data['customerSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + return data diff --git a/appwrite/models/o_auth2_slack.py b/appwrite/models/o_auth2_slack.py index 220df0cc..b5a0bb58 100644 --- a/appwrite/models/o_auth2_slack.py +++ b/appwrite/models/o_auth2_slack.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Slack(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_spotify.py b/appwrite/models/o_auth2_spotify.py index e46d9355..17108a75 100644 --- a/appwrite/models/o_auth2_spotify.py +++ b/appwrite/models/o_auth2_spotify.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Spotify(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_stripe.py b/appwrite/models/o_auth2_stripe.py index c44a8727..bedfef2d 100644 --- a/appwrite/models/o_auth2_stripe.py +++ b/appwrite/models/o_auth2_stripe.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Stripe(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') apisecretkey: str = Field(..., alias='apiSecretKey') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'apiSecretKey' not in data and 'apisecretkey' not in data: + data['apiSecretKey'] = '' + return data diff --git a/appwrite/models/o_auth2_tik_tok.py b/appwrite/models/o_auth2_tik_tok.py new file mode 100644 index 00000000..8a35b76b --- /dev/null +++ b/appwrite/models/o_auth2_tik_tok.py @@ -0,0 +1,43 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class OAuth2TikTok(AppwriteModel): + """ + OAuth2TikTok + + Attributes + ---------- + id : str + OAuth2 provider ID. + enabled : bool + OAuth2 provider is active and can be used to create sessions. + clientid : str + TikTok OAuth2 client key. + clientsecret : str + TikTok OAuth2 client secret. + """ + + id: str = Field(..., alias='$id') + enabled: bool = Field(..., alias='enabled') + clientid: str = Field(..., alias='clientId') + clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_tradeshift.py b/appwrite/models/o_auth2_tradeshift.py index 284c2764..834f81f7 100644 --- a/appwrite/models/o_auth2_tradeshift.py +++ b/appwrite/models/o_auth2_tradeshift.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Tradeshift(AppwriteModel): enabled: bool = Field(..., alias='enabled') oauth2clientid: str = Field(..., alias='oauth2ClientId') oauth2clientsecret: str = Field(..., alias='oauth2ClientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'oauth2ClientId' not in data and 'oauth2clientid' not in data: + data['oauth2ClientId'] = '' + if 'oauth2ClientSecret' not in data and 'oauth2clientsecret' not in data: + data['oauth2ClientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_twitch.py b/appwrite/models/o_auth2_twitch.py index 41b51d14..35188582 100644 --- a/appwrite/models/o_auth2_twitch.py +++ b/appwrite/models/o_auth2_twitch.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Twitch(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_webflow.py b/appwrite/models/o_auth2_webflow.py new file mode 100644 index 00000000..b1e2fe02 --- /dev/null +++ b/appwrite/models/o_auth2_webflow.py @@ -0,0 +1,43 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class OAuth2Webflow(AppwriteModel): + """ + OAuth2Webflow + + Attributes + ---------- + id : str + OAuth2 provider ID. + enabled : bool + OAuth2 provider is active and can be used to create sessions. + clientid : str + Webflow OAuth2 client ID. + clientsecret : str + Webflow OAuth2 client secret. + """ + + id: str = Field(..., alias='$id') + enabled: bool = Field(..., alias='enabled') + clientid: str = Field(..., alias='clientId') + clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_word_press.py b/appwrite/models/o_auth2_word_press.py index 64abedaf..5b289c19 100644 --- a/appwrite/models/o_auth2_word_press.py +++ b/appwrite/models/o_auth2_word_press.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2WordPress(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_x.py b/appwrite/models/o_auth2_x.py index 8dfeb6d3..f4299708 100644 --- a/appwrite/models/o_auth2_x.py +++ b/appwrite/models/o_auth2_x.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2X(AppwriteModel): enabled: bool = Field(..., alias='enabled') customerkey: str = Field(..., alias='customerKey') secretkey: str = Field(..., alias='secretKey') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'customerKey' not in data and 'customerkey' not in data: + data['customerKey'] = '' + if 'secretKey' not in data and 'secretkey' not in data: + data['secretKey'] = '' + return data diff --git a/appwrite/models/o_auth2_yahoo.py b/appwrite/models/o_auth2_yahoo.py index f1c4a518..0c0f8be9 100644 --- a/appwrite/models/o_auth2_yahoo.py +++ b/appwrite/models/o_auth2_yahoo.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Yahoo(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_yandex.py b/appwrite/models/o_auth2_yandex.py index c0c93f1a..de65d949 100644 --- a/appwrite/models/o_auth2_yandex.py +++ b/appwrite/models/o_auth2_yandex.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Yandex(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/o_auth2_zoho.py b/appwrite/models/o_auth2_zoho.py index 249420f2..f1ecd743 100644 --- a/appwrite/models/o_auth2_zoho.py +++ b/appwrite/models/o_auth2_zoho.py @@ -1,7 +1,8 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel +from ..enums.o_auth2_zoho_prompt import OAuth2ZohoPrompt class OAuth2Zoho(AppwriteModel): @@ -18,9 +19,31 @@ class OAuth2Zoho(AppwriteModel): Zoho OAuth2 client ID. clientsecret : str Zoho OAuth2 client secret. + prompt : List[OAuth2ZohoPrompt] + Zoho OAuth2 prompt values. """ id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + prompt: List[OAuth2ZohoPrompt] = Field(..., alias='prompt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + if 'prompt' not in data: + data['prompt'] = [] + return data diff --git a/appwrite/models/o_auth2_zoom.py b/appwrite/models/o_auth2_zoom.py index 4770761e..384e019d 100644 --- a/appwrite/models/o_auth2_zoom.py +++ b/appwrite/models/o_auth2_zoom.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class OAuth2Zoom(AppwriteModel): enabled: bool = Field(..., alias='enabled') clientid: str = Field(..., alias='clientId') clientsecret: str = Field(..., alias='clientSecret') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'clientId' not in data and 'clientid' not in data: + data['clientId'] = '' + if 'clientSecret' not in data and 'clientsecret' not in data: + data['clientSecret'] = '' + return data diff --git a/appwrite/models/oauth2_approve.py b/appwrite/models/oauth2_approve.py index 48b41a9f..fe22f795 100644 --- a/appwrite/models/oauth2_approve.py +++ b/appwrite/models/oauth2_approve.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class Oauth2Approve(AppwriteModel): """ redirecturl: str = Field(..., alias='redirectUrl') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'redirectUrl' not in data and 'redirecturl' not in data: + data['redirectUrl'] = '' + return data diff --git a/appwrite/models/oauth2_authorize.py b/appwrite/models/oauth2_authorize.py index 34c09c30..4cd1200e 100644 --- a/appwrite/models/oauth2_authorize.py +++ b/appwrite/models/oauth2_authorize.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class Oauth2Authorize(AppwriteModel): grantid: str = Field(..., alias='grantId') redirecturl: str = Field(..., alias='redirectUrl') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'grantId' not in data and 'grantid' not in data: + data['grantId'] = '' + if 'redirectUrl' not in data and 'redirecturl' not in data: + data['redirectUrl'] = '' + return data diff --git a/appwrite/models/oauth2_consent.py b/appwrite/models/oauth2_consent.py index 22b5805a..71f31bfb 100644 --- a/appwrite/models/oauth2_consent.py +++ b/appwrite/models/oauth2_consent.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -42,3 +42,32 @@ class Oauth2Consent(AppwriteModel): resources: List[Any] = Field(..., alias='resources') authorizationdetails: str = Field(..., alias='authorizationDetails') expire: str = Field(..., alias='expire') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'cimdUrl' not in data and 'cimdurl' not in data: + data['cimdUrl'] = '' + if 'scopes' not in data: + data['scopes'] = [] + if 'resources' not in data: + data['resources'] = [] + if 'authorizationDetails' not in data and 'authorizationdetails' not in data: + data['authorizationDetails'] = '[]' + if 'expire' not in data: + data['expire'] = '' + return data diff --git a/appwrite/models/oauth2_consent_list.py b/appwrite/models/oauth2_consent_list.py index cf1ded74..3ccd0e1c 100644 --- a/appwrite/models/oauth2_consent_list.py +++ b/appwrite/models/oauth2_consent_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .oauth2_consent import Oauth2Consent @@ -19,3 +19,14 @@ class Oauth2ConsentList(AppwriteModel): total: float = Field(..., alias='total') consents: List[Oauth2Consent] = Field(..., alias='consents') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/oauth2_consent_token.py b/appwrite/models/oauth2_consent_token.py index 022d826d..ae91a095 100644 --- a/appwrite/models/oauth2_consent_token.py +++ b/appwrite/models/oauth2_consent_token.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -45,3 +45,34 @@ class Oauth2ConsentToken(AppwriteModel): resources: List[Any] = Field(..., alias='resources') authorizationdetails: str = Field(..., alias='authorizationDetails') expire: str = Field(..., alias='expire') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'consentId' not in data and 'consentid' not in data: + data['consentId'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'cimdUrl' not in data and 'cimdurl' not in data: + data['cimdUrl'] = '' + if 'scopes' not in data: + data['scopes'] = [] + if 'resources' not in data: + data['resources'] = [] + if 'authorizationDetails' not in data and 'authorizationdetails' not in data: + data['authorizationDetails'] = '[]' + if 'expire' not in data: + data['expire'] = '' + return data diff --git a/appwrite/models/oauth2_consent_token_list.py b/appwrite/models/oauth2_consent_token_list.py index d64c366d..eaca2a01 100644 --- a/appwrite/models/oauth2_consent_token_list.py +++ b/appwrite/models/oauth2_consent_token_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .oauth2_consent_token import Oauth2ConsentToken @@ -19,3 +19,14 @@ class Oauth2ConsentTokenList(AppwriteModel): total: float = Field(..., alias='total') tokens: List[Oauth2ConsentToken] = Field(..., alias='tokens') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/oauth2_device_authorization.py b/appwrite/models/oauth2_device_authorization.py index 4d423857..df9f9d30 100644 --- a/appwrite/models/oauth2_device_authorization.py +++ b/appwrite/models/oauth2_device_authorization.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -30,3 +30,24 @@ class Oauth2DeviceAuthorization(AppwriteModel): verification_uri_complete: str = Field(..., alias='verification_uri_complete') expires_in: float = Field(..., alias='expires_in') interval: float = Field(..., alias='interval') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'device_code' not in data: + data['device_code'] = '' + if 'user_code' not in data: + data['user_code'] = '' + if 'verification_uri' not in data: + data['verification_uri'] = '' + if 'verification_uri_complete' not in data: + data['verification_uri_complete'] = '' + if 'expires_in' not in data: + data['expires_in'] = 0 + if 'interval' not in data: + data['interval'] = 0 + return data diff --git a/appwrite/models/oauth2_grant.py b/appwrite/models/oauth2_grant.py index ffa000d9..1ff0a4a1 100644 --- a/appwrite/models/oauth2_grant.py +++ b/appwrite/models/oauth2_grant.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -48,3 +48,36 @@ class Oauth2Grant(AppwriteModel): redirecturi: str = Field(..., alias='redirectUri') authtime: float = Field(..., alias='authTime') expire: str = Field(..., alias='expire') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'scopes' not in data: + data['scopes'] = [] + if 'resources' not in data: + data['resources'] = [] + if 'authorizationDetails' not in data and 'authorizationdetails' not in data: + data['authorizationDetails'] = '[]' + if 'prompt' not in data: + data['prompt'] = '' + if 'redirectUri' not in data and 'redirecturi' not in data: + data['redirectUri'] = '' + if 'authTime' not in data and 'authtime' not in data: + data['authTime'] = 0 + if 'expire' not in data: + data['expire'] = '' + return data diff --git a/appwrite/models/oauth2_introspection.py b/appwrite/models/oauth2_introspection.py new file mode 100644 index 00000000..8e176511 --- /dev/null +++ b/appwrite/models/oauth2_introspection.py @@ -0,0 +1,61 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class Oauth2Introspection(AppwriteModel): + """ + OAuth2 Introspection + + Attributes + ---------- + active : bool + Whether the token is currently active. An inactive token carries no other claims (RFC 7662). + token_use : Optional[str] + Kind of token that was introspected. Can be one of: `access_token` or `refresh_token`. + token_type : Optional[str] + OAuth2 token type. + scope : Optional[str] + Space-separated scopes granted to the token. + client_id : Optional[str] + OAuth2 client ID the token was issued to. + sub : Optional[str] + ID of the user who authorized the token. + aud : Optional[List[Any]] + Audiences the token is intended for. The first entry is the project API base URL; any further entries are the resource indicators requested at authorization time (RFC 8707). + iss : Optional[str] + Issuer URL of the token. + exp : Optional[float] + Expiration time as a Unix timestamp in seconds. + iat : Optional[float] + Issued-at time as a Unix timestamp in seconds. + jti : Optional[str] + Unique identifier of the token. + authorization_details : Optional[List[Any]] + Granted RFC 9396 authorization details, restricted to what the user can currently access. + """ + + active: bool = Field(..., alias='active') + token_use: Optional[str] = Field(default=None, alias='token_use') + token_type: Optional[str] = Field(default=None, alias='token_type') + scope: Optional[str] = Field(default=None, alias='scope') + client_id: Optional[str] = Field(default=None, alias='client_id') + sub: Optional[str] = Field(default=None, alias='sub') + aud: Optional[List[Any]] = Field(default=None, alias='aud') + iss: Optional[str] = Field(default=None, alias='iss') + exp: Optional[float] = Field(default=None, alias='exp') + iat: Optional[float] = Field(default=None, alias='iat') + jti: Optional[str] = Field(default=None, alias='jti') + authorization_details: Optional[List[Any]] = Field(default=None, alias='authorization_details') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'active' not in data: + data['active'] = False + return data diff --git a/appwrite/models/oauth2_organization.py b/appwrite/models/oauth2_organization.py index 4df5b972..72f5f02d 100644 --- a/appwrite/models/oauth2_organization.py +++ b/appwrite/models/oauth2_organization.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class Oauth2Organization(AppwriteModel): """ id: str = Field(..., alias='$id') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + return data diff --git a/appwrite/models/oauth2_organization_list.py b/appwrite/models/oauth2_organization_list.py index b1dbba39..84f0dd28 100644 --- a/appwrite/models/oauth2_organization_list.py +++ b/appwrite/models/oauth2_organization_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .oauth2_organization import Oauth2Organization @@ -19,3 +19,14 @@ class Oauth2OrganizationList(AppwriteModel): total: float = Field(..., alias='total') organizations: List[Oauth2Organization] = Field(..., alias='organizations') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/oauth2_par.py b/appwrite/models/oauth2_par.py index 49d8b20b..e1b70686 100644 --- a/appwrite/models/oauth2_par.py +++ b/appwrite/models/oauth2_par.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class Oauth2PAR(AppwriteModel): request_uri: str = Field(..., alias='request_uri') expires_in: float = Field(..., alias='expires_in') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'request_uri' not in data: + data['request_uri'] = '' + if 'expires_in' not in data: + data['expires_in'] = 0 + return data diff --git a/appwrite/models/oauth2_project.py b/appwrite/models/oauth2_project.py index 0c06806a..a290119a 100644 --- a/appwrite/models/oauth2_project.py +++ b/appwrite/models/oauth2_project.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -21,3 +21,18 @@ class Oauth2Project(AppwriteModel): id: str = Field(..., alias='$id') region: str = Field(..., alias='region') endpoint: str = Field(..., alias='endpoint') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'region' not in data: + data['region'] = '' + if 'endpoint' not in data: + data['endpoint'] = '' + return data diff --git a/appwrite/models/oauth2_project_list.py b/appwrite/models/oauth2_project_list.py index 03864e13..c1622c11 100644 --- a/appwrite/models/oauth2_project_list.py +++ b/appwrite/models/oauth2_project_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .oauth2_project import Oauth2Project @@ -19,3 +19,14 @@ class Oauth2ProjectList(AppwriteModel): total: float = Field(..., alias='total') projects: List[Oauth2Project] = Field(..., alias='projects') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/oauth2_reject.py b/appwrite/models/oauth2_reject.py index 148df6df..d2e8270a 100644 --- a/appwrite/models/oauth2_reject.py +++ b/appwrite/models/oauth2_reject.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -15,3 +15,14 @@ class Oauth2Reject(AppwriteModel): """ redirecturl: str = Field(..., alias='redirectUrl') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'redirectUrl' not in data and 'redirecturl' not in data: + data['redirectUrl'] = '' + return data diff --git a/appwrite/models/oauth2_token.py b/appwrite/models/oauth2_token.py index 81f7e851..f57d8995 100644 --- a/appwrite/models/oauth2_token.py +++ b/appwrite/models/oauth2_token.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -33,3 +33,22 @@ class Oauth2Token(AppwriteModel): scope: str = Field(..., alias='scope') authorization_details: Optional[str] = Field(default=None, alias='authorization_details') id_token: Optional[str] = Field(default=None, alias='id_token') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'access_token' not in data: + data['access_token'] = '' + if 'token_type' not in data: + data['token_type'] = 'Bearer' + if 'expires_in' not in data: + data['expires_in'] = 0 + if 'refresh_token' not in data: + data['refresh_token'] = '' + if 'scope' not in data: + data['scope'] = '' + return data diff --git a/appwrite/models/organization.py b/appwrite/models/organization.py index cb1a59b6..b70f83f2 100644 --- a/appwrite/models/organization.py +++ b/appwrite/models/organization.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .preferences import Preferences @@ -39,21 +39,21 @@ class Organization(AppwriteModel, Generic[T]): Organization's billing plan. billingemail : str Billing email set for the organization. - billingstartdate : str + billingstartdate : Optional[str] Billing cycle start date. - billingcurrentinvoicedate : str + billingcurrentinvoicedate : Optional[str] Current invoice cycle start date. - billingnextinvoicedate : str + billingnextinvoicedate : Optional[str] Next invoice cycle start date. billingtrialstartdate : Optional[str] Start date of trial. - billingtrialdays : float + billingtrialdays : Optional[float] Number of trial days. - billingaggregationid : str + billingaggregationid : Optional[str] Current active aggregation id. - billinginvoiceid : str + billinginvoiceid : Optional[str] Current active aggregation id. - paymentmethodid : str + paymentmethodid : Optional[str] Default payment method. billingaddressid : Optional[str] Default payment method. @@ -99,14 +99,14 @@ class Organization(AppwriteModel, Generic[T]): billingplanid: str = Field(..., alias='billingPlanId') billingplandetails: BillingPlan = Field(..., alias='billingPlanDetails') billingemail: str = Field(..., alias='billingEmail') - billingstartdate: str = Field(..., alias='billingStartDate') - billingcurrentinvoicedate: str = Field(..., alias='billingCurrentInvoiceDate') - billingnextinvoicedate: str = Field(..., alias='billingNextInvoiceDate') + billingstartdate: Optional[str] = Field(default=None, alias='billingStartDate') + billingcurrentinvoicedate: Optional[str] = Field(default=None, alias='billingCurrentInvoiceDate') + billingnextinvoicedate: Optional[str] = Field(default=None, alias='billingNextInvoiceDate') billingtrialstartdate: Optional[str] = Field(default=None, alias='billingTrialStartDate') - billingtrialdays: float = Field(..., alias='billingTrialDays') - billingaggregationid: str = Field(..., alias='billingAggregationId') - billinginvoiceid: str = Field(..., alias='billingInvoiceId') - paymentmethodid: str = Field(..., alias='paymentMethodId') + billingtrialdays: Optional[float] = Field(default=None, alias='billingTrialDays') + billingaggregationid: Optional[str] = Field(default=None, alias='billingAggregationId') + billinginvoiceid: Optional[str] = Field(default=None, alias='billingInvoiceId') + paymentmethodid: Optional[str] = Field(default=None, alias='paymentMethodId') billingaddressid: Optional[str] = Field(default=None, alias='billingAddressId') backuppaymentmethodid: Optional[str] = Field(default=None, alias='backupPaymentMethodId') status: str = Field(..., alias='status') @@ -123,6 +123,41 @@ class Organization(AppwriteModel, Generic[T]): platform: str = Field(..., alias='platform') projects: List[Any] = Field(..., alias='projects') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'total' not in data: + data['total'] = 0 + if 'budgetAlerts' not in data and 'budgetalerts' not in data: + data['budgetAlerts'] = [75] + if 'billingPlan' not in data and 'billingplan' not in data: + data['billingPlan'] = 'tier-0' + if 'billingPlanId' not in data and 'billingplanid' not in data: + data['billingPlanId'] = 'tier-0' + if 'billingEmail' not in data and 'billingemail' not in data: + data['billingEmail'] = '' + if 'status' not in data: + data['status'] = 'draft' + if 'markedForDeletion' not in data and 'markedfordeletion' not in data: + data['markedForDeletion'] = False + if 'platform' not in data: + data['platform'] = 'appwrite' + if 'projects' not in data: + data['projects'] = [] + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'Organization[T]': """Create Organization instance with typed data.""" diff --git a/appwrite/models/passkey.py b/appwrite/models/passkey.py new file mode 100644 index 00000000..a35e5235 --- /dev/null +++ b/appwrite/models/passkey.py @@ -0,0 +1,48 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class Passkey(AppwriteModel): + """ + Passkey + + Attributes + ---------- + id : str + Passkey ID. + createdat : str + Passkey creation date in ISO 8601 format. + updatedat : str + Passkey update date in ISO 8601 format. + name : str + Passkey name. + accessedat : str + Most recent sign-in with this passkey in ISO 8601 format. Empty until the passkey is used to sign in. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + name: str = Field(..., alias='name') + accessedat: str = Field(..., alias='accessedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'accessedAt' not in data and 'accessedat' not in data: + data['accessedAt'] = '' + return data diff --git a/appwrite/models/passkey_challenge.py b/appwrite/models/passkey_challenge.py new file mode 100644 index 00000000..67c7bbc6 --- /dev/null +++ b/appwrite/models/passkey_challenge.py @@ -0,0 +1,48 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class PasskeyChallenge(AppwriteModel): + """ + Passkey Challenge + + Attributes + ---------- + id : str + Challenge ID. When signing in, pass it back with the credential to receive a token. + createdat : str + Challenge creation date in ISO 8601 format. + passkeyid : str + ID of the passkey being registered. Empty for sign-in challenges. + expire : str + Challenge expiration date in ISO 8601 format. + publickey : Dict[str, Any] + WebAuthn options in JSON form. Pass them to `PublicKeyCredential.parseCreationOptionsFromJSON()` when registering, or `PublicKeyCredential.parseRequestOptionsFromJSON()` when signing in. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + passkeyid: str = Field(..., alias='passkeyId') + expire: str = Field(..., alias='expire') + publickey: Dict[str, Any] = Field(..., alias='publicKey') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'passkeyId' not in data and 'passkeyid' not in data: + data['passkeyId'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'publicKey' not in data and 'publickey' not in data: + data['publicKey'] = [] + return data diff --git a/appwrite/models/passkey_list.py b/appwrite/models/passkey_list.py new file mode 100644 index 00000000..01e5abfd --- /dev/null +++ b/appwrite/models/passkey_list.py @@ -0,0 +1,32 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from .passkey import Passkey + + +class PasskeyList(AppwriteModel): + """ + Passkeys List + + Attributes + ---------- + total : float + Total number of passkeys that matched your query. + passkeys : List[Passkey] + List of passkeys. + """ + + total: float = Field(..., alias='total') + passkeys: List[Passkey] = Field(..., alias='passkeys') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/phone.py b/appwrite/models/phone.py index 9df4f3e2..19a8b06a 100644 --- a/appwrite/models/phone.py +++ b/appwrite/models/phone.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -21,3 +21,18 @@ class Phone(AppwriteModel): code: str = Field(..., alias='code') countrycode: str = Field(..., alias='countryCode') countryname: str = Field(..., alias='countryName') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'code' not in data: + data['code'] = '' + if 'countryCode' not in data and 'countrycode' not in data: + data['countryCode'] = '' + if 'countryName' not in data and 'countryname' not in data: + data['countryName'] = '' + return data diff --git a/appwrite/models/phone_list.py b/appwrite/models/phone_list.py index e9cc2679..09012403 100644 --- a/appwrite/models/phone_list.py +++ b/appwrite/models/phone_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .phone import Phone @@ -19,3 +19,14 @@ class PhoneList(AppwriteModel): total: float = Field(..., alias='total') phones: List[Phone] = Field(..., alias='phones') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/platform_android.py b/appwrite/models/platform_android.py index ade36f3f..c2de838e 100644 --- a/appwrite/models/platform_android.py +++ b/appwrite/models/platform_android.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.platform_type import PlatformType @@ -23,6 +23,8 @@ class PlatformAndroid(AppwriteModel): Platform type. Possible values are: windows, apple, android, linux, web. applicationid : str Android application ID. + fingerprints : List[Any] + SHA-256 fingerprints of the certificates the app is signed with. Passkeys created in the app are accepted when its signature matches one. """ id: str = Field(..., alias='$id') @@ -31,3 +33,25 @@ class PlatformAndroid(AppwriteModel): name: str = Field(..., alias='name') type: PlatformType = Field(..., alias='type') applicationid: str = Field(..., alias='applicationId') + fingerprints: List[Any] = Field(..., alias='fingerprints') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'applicationId' not in data and 'applicationid' not in data: + data['applicationId'] = '' + if 'fingerprints' not in data: + data['fingerprints'] = [] + return data diff --git a/appwrite/models/platform_apple.py b/appwrite/models/platform_apple.py index 1d1cb315..627c6aab 100644 --- a/appwrite/models/platform_apple.py +++ b/appwrite/models/platform_apple.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.platform_type import PlatformType @@ -31,3 +31,22 @@ class PlatformApple(AppwriteModel): name: str = Field(..., alias='name') type: PlatformType = Field(..., alias='type') bundleidentifier: str = Field(..., alias='bundleIdentifier') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'bundleIdentifier' not in data and 'bundleidentifier' not in data: + data['bundleIdentifier'] = '' + return data diff --git a/appwrite/models/platform_linux.py b/appwrite/models/platform_linux.py index 82958e80..01ea9b78 100644 --- a/appwrite/models/platform_linux.py +++ b/appwrite/models/platform_linux.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.platform_type import PlatformType @@ -31,3 +31,22 @@ class PlatformLinux(AppwriteModel): name: str = Field(..., alias='name') type: PlatformType = Field(..., alias='type') packagename: str = Field(..., alias='packageName') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'packageName' not in data and 'packagename' not in data: + data['packageName'] = '' + return data diff --git a/appwrite/models/platform_list.py b/appwrite/models/platform_list.py index eb30c63f..2f064456 100644 --- a/appwrite/models/platform_list.py +++ b/appwrite/models/platform_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .platform_web import PlatformWeb @@ -31,3 +31,14 @@ class PlatformList(AppwriteModel): PlatformLinux, ] ] = Field(..., alias='platforms') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/platform_web.py b/appwrite/models/platform_web.py index 4e69b96f..9c40ebd4 100644 --- a/appwrite/models/platform_web.py +++ b/appwrite/models/platform_web.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.platform_type import PlatformType @@ -31,3 +31,22 @@ class PlatformWeb(AppwriteModel): name: str = Field(..., alias='name') type: PlatformType = Field(..., alias='type') hostname: str = Field(..., alias='hostname') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'hostname' not in data: + data['hostname'] = '' + return data diff --git a/appwrite/models/platform_windows.py b/appwrite/models/platform_windows.py index fdabffb2..915877b8 100644 --- a/appwrite/models/platform_windows.py +++ b/appwrite/models/platform_windows.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.platform_type import PlatformType @@ -31,3 +31,22 @@ class PlatformWindows(AppwriteModel): name: str = Field(..., alias='name') type: PlatformType = Field(..., alias='type') packageidentifiername: str = Field(..., alias='packageIdentifierName') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'packageIdentifierName' not in data and 'packageidentifiername' not in data: + data['packageIdentifierName'] = '' + return data diff --git a/appwrite/models/policy_deny_aliased_email.py b/appwrite/models/policy_deny_aliased_email.py index 64e65644..fe78898e 100644 --- a/appwrite/models/policy_deny_aliased_email.py +++ b/appwrite/models/policy_deny_aliased_email.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicyDenyAliasedEmail(AppwriteModel): id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/policy_deny_corporate_email.py b/appwrite/models/policy_deny_corporate_email.py index b56e12fb..d6e6b5f5 100644 --- a/appwrite/models/policy_deny_corporate_email.py +++ b/appwrite/models/policy_deny_corporate_email.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicyDenyCorporateEmail(AppwriteModel): id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/policy_deny_disposable_email.py b/appwrite/models/policy_deny_disposable_email.py index 4f571733..481923ec 100644 --- a/appwrite/models/policy_deny_disposable_email.py +++ b/appwrite/models/policy_deny_disposable_email.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicyDenyDisposableEmail(AppwriteModel): id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/policy_deny_free_email.py b/appwrite/models/policy_deny_free_email.py index 1eb610ee..122cec77 100644 --- a/appwrite/models/policy_deny_free_email.py +++ b/appwrite/models/policy_deny_free_email.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicyDenyFreeEmail(AppwriteModel): id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/policy_list.py b/appwrite/models/policy_list.py index 79e8802c..0302144e 100644 --- a/appwrite/models/policy_list.py +++ b/appwrite/models/policy_list.py @@ -1,11 +1,13 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .policy_password_dictionary import PolicyPasswordDictionary from .policy_password_history import PolicyPasswordHistory from .policy_password_strength import PolicyPasswordStrength from .policy_password_personal_data import PolicyPasswordPersonalData +from .policy_password_pwned import PolicyPasswordPwned +from .policy_password_rotation import PolicyPasswordRotation from .policy_session_alert import PolicySessionAlert from .policy_session_duration import PolicySessionDuration from .policy_session_invalidation import PolicySessionInvalidation @@ -17,6 +19,7 @@ from .policy_deny_disposable_email import PolicyDenyDisposableEmail from .policy_deny_free_email import PolicyDenyFreeEmail from .policy_deny_corporate_email import PolicyDenyCorporateEmail +from .policy_passkey import PolicyPasskey class PolicyList(AppwriteModel): @@ -27,7 +30,7 @@ class PolicyList(AppwriteModel): ---------- total : float Total number of policies in the given project. - policies : List[Union[PolicyPasswordDictionary, PolicyPasswordHistory, PolicyPasswordStrength, PolicyPasswordPersonalData, PolicySessionAlert, PolicySessionDuration, PolicySessionInvalidation, PolicySessionLimit, PolicyUserLimit, PolicyMembershipPrivacy, PolicyMfaFactors, PolicyDenyAliasedEmail, PolicyDenyDisposableEmail, PolicyDenyFreeEmail, PolicyDenyCorporateEmail]] + policies : List[Union[PolicyPasswordDictionary, PolicyPasswordHistory, PolicyPasswordStrength, PolicyPasswordPersonalData, PolicyPasswordPwned, PolicyPasswordRotation, PolicySessionAlert, PolicySessionDuration, PolicySessionInvalidation, PolicySessionLimit, PolicyUserLimit, PolicyMembershipPrivacy, PolicyMfaFactors, PolicyDenyAliasedEmail, PolicyDenyDisposableEmail, PolicyDenyFreeEmail, PolicyDenyCorporateEmail, PolicyPasskey]] List of policies. """ @@ -38,6 +41,8 @@ class PolicyList(AppwriteModel): PolicyPasswordHistory, PolicyPasswordStrength, PolicyPasswordPersonalData, + PolicyPasswordPwned, + PolicyPasswordRotation, PolicySessionAlert, PolicySessionDuration, PolicySessionInvalidation, @@ -49,5 +54,17 @@ class PolicyList(AppwriteModel): PolicyDenyDisposableEmail, PolicyDenyFreeEmail, PolicyDenyCorporateEmail, + PolicyPasskey, ] ] = Field(..., alias='policies') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/policy_membership_privacy.py b/appwrite/models/policy_membership_privacy.py index 157913ac..bbc215ff 100644 --- a/appwrite/models/policy_membership_privacy.py +++ b/appwrite/models/policy_membership_privacy.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -33,3 +33,26 @@ class PolicyMembershipPrivacy(AppwriteModel): username: bool = Field(..., alias='userName') usermfa: bool = Field(..., alias='userMFA') useraccessedat: bool = Field(..., alias='userAccessedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = False + if 'userEmail' not in data and 'useremail' not in data: + data['userEmail'] = False + if 'userPhone' not in data and 'userphone' not in data: + data['userPhone'] = False + if 'userName' not in data and 'username' not in data: + data['userName'] = False + if 'userMFA' not in data and 'usermfa' not in data: + data['userMFA'] = False + if 'userAccessedAt' not in data and 'useraccessedat' not in data: + data['userAccessedAt'] = False + return data diff --git a/appwrite/models/policy_mfa_factors.py b/appwrite/models/policy_mfa_factors.py index 12b5b20b..202891e8 100644 --- a/appwrite/models/policy_mfa_factors.py +++ b/appwrite/models/policy_mfa_factors.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,3 +27,22 @@ class PolicyMfaFactors(AppwriteModel): email: bool = Field(..., alias='email') phone: bool = Field(..., alias='phone') custom: bool = Field(..., alias='custom') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'totp' not in data: + data['totp'] = True + if 'email' not in data: + data['email'] = True + if 'phone' not in data: + data['phone'] = True + if 'custom' not in data: + data['custom'] = False + return data diff --git a/appwrite/models/policy_passkey.py b/appwrite/models/policy_passkey.py new file mode 100644 index 00000000..488e5f5b --- /dev/null +++ b/appwrite/models/policy_passkey.py @@ -0,0 +1,38 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class PolicyPasskey(AppwriteModel): + """ + Policy Passkey + + Attributes + ---------- + id : str + Policy ID. + rpid : str + Relying party ID passkeys are bound to. Empty until configured. + origins : List[Any] + Web origins passkeys work on, from the project's platforms on the relying party ID and a localhost web platform. Read-only. + """ + + id: str = Field(..., alias='$id') + rpid: str = Field(..., alias='rpId') + origins: List[Any] = Field(..., alias='origins') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'rpId' not in data and 'rpid' not in data: + data['rpId'] = '' + if 'origins' not in data: + data['origins'] = [] + return data diff --git a/appwrite/models/policy_password_dictionary.py b/appwrite/models/policy_password_dictionary.py index e5046106..37bbbeeb 100644 --- a/appwrite/models/policy_password_dictionary.py +++ b/appwrite/models/policy_password_dictionary.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicyPasswordDictionary(AppwriteModel): id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/policy_password_history.py b/appwrite/models/policy_password_history.py index f8eff9a7..26e50c4d 100644 --- a/appwrite/models/policy_password_history.py +++ b/appwrite/models/policy_password_history.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicyPasswordHistory(AppwriteModel): id: str = Field(..., alias='$id') total: float = Field(..., alias='total') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/policy_password_personal_data.py b/appwrite/models/policy_password_personal_data.py index 92710579..64f12c7c 100644 --- a/appwrite/models/policy_password_personal_data.py +++ b/appwrite/models/policy_password_personal_data.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicyPasswordPersonalData(AppwriteModel): id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/policy_password_pwned.py b/appwrite/models/policy_password_pwned.py new file mode 100644 index 00000000..06d4a1bc --- /dev/null +++ b/appwrite/models/policy_password_pwned.py @@ -0,0 +1,43 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class PolicyPasswordPwned(AppwriteModel): + """ + Policy Password Pwned + + Attributes + ---------- + id : str + Policy ID. + enabled : bool + Whether passwords are checked against known data breaches and the result recorded on the user. + sessions : bool + Whether a sign-in with a breached password is refused until the password is reset. + users : bool + Whether a breached password is rejected when a user signs up or sets a new password. + """ + + id: str = Field(..., alias='$id') + enabled: bool = Field(..., alias='enabled') + sessions: bool = Field(..., alias='sessions') + users: bool = Field(..., alias='users') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'sessions' not in data: + data['sessions'] = False + if 'users' not in data: + data['users'] = False + return data diff --git a/appwrite/models/policy_password_rotation.py b/appwrite/models/policy_password_rotation.py new file mode 100644 index 00000000..118fffc0 --- /dev/null +++ b/appwrite/models/policy_password_rotation.py @@ -0,0 +1,38 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class PolicyPasswordRotation(AppwriteModel): + """ + Policy Password Rotation + + Attributes + ---------- + id : str + Policy ID. + enabled : bool + Whether expired passwords require a reset before email/password sign-in. + maxage : float + Maximum password age in seconds. + """ + + id: str = Field(..., alias='$id') + enabled: bool = Field(..., alias='enabled') + maxage: float = Field(..., alias='maxAge') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + if 'maxAge' not in data and 'maxage' not in data: + data['maxAge'] = 31536000 + return data diff --git a/appwrite/models/policy_password_strength.py b/appwrite/models/policy_password_strength.py index db9b6bc6..3a01bca2 100644 --- a/appwrite/models/policy_password_strength.py +++ b/appwrite/models/policy_password_strength.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -30,3 +30,24 @@ class PolicyPasswordStrength(AppwriteModel): lowercase: bool = Field(..., alias='lowercase') number: bool = Field(..., alias='number') symbols: bool = Field(..., alias='symbols') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'min' not in data: + data['min'] = 8 + if 'uppercase' not in data: + data['uppercase'] = False + if 'lowercase' not in data: + data['lowercase'] = False + if 'number' not in data: + data['number'] = False + if 'symbols' not in data: + data['symbols'] = False + return data diff --git a/appwrite/models/policy_session_alert.py b/appwrite/models/policy_session_alert.py index f8f87a4d..90c62081 100644 --- a/appwrite/models/policy_session_alert.py +++ b/appwrite/models/policy_session_alert.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicySessionAlert(AppwriteModel): id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = False + return data diff --git a/appwrite/models/policy_session_duration.py b/appwrite/models/policy_session_duration.py index 7b688476..49a362bf 100644 --- a/appwrite/models/policy_session_duration.py +++ b/appwrite/models/policy_session_duration.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicySessionDuration(AppwriteModel): id: str = Field(..., alias='$id') duration: float = Field(..., alias='duration') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'duration' not in data: + data['duration'] = 31536000 + return data diff --git a/appwrite/models/policy_session_invalidation.py b/appwrite/models/policy_session_invalidation.py index ffce62db..6c71d822 100644 --- a/appwrite/models/policy_session_invalidation.py +++ b/appwrite/models/policy_session_invalidation.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicySessionInvalidation(AppwriteModel): id: str = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'enabled' not in data: + data['enabled'] = True + return data diff --git a/appwrite/models/policy_session_limit.py b/appwrite/models/policy_session_limit.py index 36590466..18eca7ce 100644 --- a/appwrite/models/policy_session_limit.py +++ b/appwrite/models/policy_session_limit.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicySessionLimit(AppwriteModel): id: str = Field(..., alias='$id') total: float = Field(..., alias='total') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/policy_user_limit.py b/appwrite/models/policy_user_limit.py index 485879fd..d3757ff4 100644 --- a/appwrite/models/policy_user_limit.py +++ b/appwrite/models/policy_user_limit.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -18,3 +18,16 @@ class PolicyUserLimit(AppwriteModel): id: str = Field(..., alias='$id') total: float = Field(..., alias='total') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/postgres_extension.py b/appwrite/models/postgres_extension.py index 9f8cfdc7..5c1ab950 100644 --- a/appwrite/models/postgres_extension.py +++ b/appwrite/models/postgres_extension.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class PostgresExtension(AppwriteModel): name: str = Field(..., alias='name') description: str = Field(..., alias='description') category: str = Field(..., alias='category') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'key' not in data: + data['key'] = '' + if 'name' not in data: + data['name'] = '' + if 'description' not in data: + data['description'] = '' + if 'category' not in data: + data['category'] = '' + return data diff --git a/appwrite/models/presence.py b/appwrite/models/presence.py index 79556f7a..0717a58d 100644 --- a/appwrite/models/presence.py +++ b/appwrite/models/presence.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,22 @@ class Presence(AppwriteModel): source: str = Field(..., alias='source') expiresat: Optional[str] = Field(default=None, alias='expiresAt') metadata: Optional[Dict[str, Any]] = Field(default=None, alias='metadata') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'source' not in data: + data['source'] = '' + return data diff --git a/appwrite/models/presence_list.py b/appwrite/models/presence_list.py index 1d8752a6..e2a7dbfb 100644 --- a/appwrite/models/presence_list.py +++ b/appwrite/models/presence_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .presence import Presence @@ -19,3 +19,14 @@ class PresenceList(AppwriteModel): total: float = Field(..., alias='total') presences: List[Presence] = Field(..., alias='presences') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/program.py b/appwrite/models/program.py index e2f5b081..204b91a9 100644 --- a/appwrite/models/program.py +++ b/appwrite/models/program.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,30 @@ class Program(AppwriteModel): active: bool = Field(..., alias='active') external: bool = Field(..., alias='external') billingplanid: str = Field(..., alias='billingPlanId') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'title' not in data: + data['title'] = '' + if 'description' not in data: + data['description'] = '' + if 'tag' not in data: + data['tag'] = '' + if 'icon' not in data: + data['icon'] = '' + if 'url' not in data: + data['url'] = '' + if 'active' not in data: + data['active'] = True + if 'external' not in data: + data['external'] = True + if 'billingPlanId' not in data and 'billingplanid' not in data: + data['billingPlanId'] = '' + return data diff --git a/appwrite/models/project.py b/appwrite/models/project.py index 08721a9b..bec09e0e 100644 --- a/appwrite/models/project.py +++ b/appwrite/models/project.py @@ -1,8 +1,7 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel -from .dev_key import DevKey from .project_auth_method import ProjectAuthMethod from .project_service import ProjectService from .project_protocol import ProjectProtocol @@ -28,8 +27,6 @@ class Project(AppwriteModel): Project team ID. region : str Project region - devkeys : List[DevKey] - Deprecated since 1.9.5: List of dev keys. smtpenabled : bool Status for custom SMTP smtpsendername : str @@ -74,6 +71,10 @@ class Project(AppwriteModel): Whether WAF enforcement is enabled for the project. billinglimits : Optional[BillingLimits] Billing limits reached + firstaccessedat : Optional[str] + First time the project received a non-console API request. Empty until the project is used. + mcpaccessedat : Optional[str] + Last time the project was accessed through the MCP server. Empty if it was never accessed via MCP. oauth2serverenabled : Optional[bool] OAuth2 server status oauth2serverauthorizationurl : Optional[str] @@ -116,7 +117,6 @@ class Project(AppwriteModel): name: str = Field(..., alias='name') teamid: str = Field(..., alias='teamId') region: str = Field(..., alias='region') - devkeys: List[DevKey] = Field(..., alias='devKeys') smtpenabled: bool = Field(..., alias='smtpEnabled') smtpsendername: str = Field(..., alias='smtpSenderName') smtpsenderemail: str = Field(..., alias='smtpSenderEmail') @@ -139,6 +139,8 @@ class Project(AppwriteModel): consoleaccessedat: str = Field(..., alias='consoleAccessedAt') wafenabled: Optional[bool] = Field(default=None, alias='wafEnabled') billinglimits: Optional[BillingLimits] = Field(default=None, alias='billingLimits') + firstaccessedat: Optional[str] = Field(default=None, alias='firstAccessedAt') + mcpaccessedat: Optional[str] = Field(default=None, alias='mcpAccessedAt') oauth2serverenabled: Optional[bool] = Field(default=None, alias='oAuth2ServerEnabled') oauth2serverauthorizationurl: Optional[str] = Field(default=None, alias='oAuth2ServerAuthorizationUrl') oauth2serverscopes: Optional[List[Any]] = Field(default=None, alias='oAuth2ServerScopes') @@ -168,3 +170,56 @@ class Project(AppwriteModel): oauth2serverusercodeformat: Optional[str] = Field(default=None, alias='oAuth2ServerUserCodeFormat') oauth2serverdevicecodeduration: Optional[float] = Field(default=None, alias='oAuth2ServerDeviceCodeDuration') oauth2serverdiscoveryurl: Optional[str] = Field(default=None, alias='oAuth2ServerDiscoveryUrl') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'region' not in data: + data['region'] = 'fra' + if 'smtpEnabled' not in data and 'smtpenabled' not in data: + data['smtpEnabled'] = False + if 'smtpSenderName' not in data and 'smtpsendername' not in data: + data['smtpSenderName'] = '' + if 'smtpSenderEmail' not in data and 'smtpsenderemail' not in data: + data['smtpSenderEmail'] = '' + if 'smtpReplyToName' not in data and 'smtpreplytoname' not in data: + data['smtpReplyToName'] = '' + if 'smtpReplyToEmail' not in data and 'smtpreplytoemail' not in data: + data['smtpReplyToEmail'] = '' + if 'smtpHost' not in data and 'smtphost' not in data: + data['smtpHost'] = '' + if 'smtpPort' not in data and 'smtpport' not in data: + data['smtpPort'] = 0 + if 'smtpUsername' not in data and 'smtpusername' not in data: + data['smtpUsername'] = '' + if 'smtpPassword' not in data and 'smtppassword' not in data: + data['smtpPassword'] = '' + if 'smtpSecure' not in data and 'smtpsecure' not in data: + data['smtpSecure'] = '' + if 'pingCount' not in data and 'pingcount' not in data: + data['pingCount'] = 0 + if 'pingedAt' not in data and 'pingedat' not in data: + data['pingedAt'] = '' + if 'labels' not in data: + data['labels'] = [] + if 'status' not in data: + data['status'] = 'active' + if 'onboarding' not in data: + data['onboarding'] = [] + if 'consoleAccessedAt' not in data and 'consoleaccessedat' not in data: + data['consoleAccessedAt'] = '' + return data diff --git a/appwrite/models/project_auth_method.py b/appwrite/models/project_auth_method.py index 76df540b..14df4090 100644 --- a/appwrite/models/project_auth_method.py +++ b/appwrite/models/project_auth_method.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.project_auth_method_id import ProjectAuthMethodId @@ -19,3 +19,14 @@ class ProjectAuthMethod(AppwriteModel): id: ProjectAuthMethodId = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'enabled' not in data: + data['enabled'] = True + return data diff --git a/appwrite/models/project_list.py b/appwrite/models/project_list.py index 31cc5425..540a5b04 100644 --- a/appwrite/models/project_list.py +++ b/appwrite/models/project_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .project import Project @@ -19,3 +19,14 @@ class ProjectList(AppwriteModel): total: float = Field(..., alias='total') projects: List[Project] = Field(..., alias='projects') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/project_protocol.py b/appwrite/models/project_protocol.py index 8be9c7e7..202b8668 100644 --- a/appwrite/models/project_protocol.py +++ b/appwrite/models/project_protocol.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.project_protocol_id import ProjectProtocolId @@ -19,3 +19,14 @@ class ProjectProtocol(AppwriteModel): id: ProjectProtocolId = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'enabled' not in data: + data['enabled'] = True + return data diff --git a/appwrite/models/project_service.py b/appwrite/models/project_service.py index da1d0df4..05ab6bee 100644 --- a/appwrite/models/project_service.py +++ b/appwrite/models/project_service.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.project_service_id import ProjectServiceId @@ -19,3 +19,14 @@ class ProjectService(AppwriteModel): id: ProjectServiceId = Field(..., alias='$id') enabled: bool = Field(..., alias='enabled') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'enabled' not in data: + data['enabled'] = True + return data diff --git a/appwrite/models/provider.py b/appwrite/models/provider.py index b08954cd..acdede66 100644 --- a/appwrite/models/provider.py +++ b/appwrite/models/provider.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,28 @@ class Provider(AppwriteModel): type: str = Field(..., alias='type') credentials: Dict[str, Any] = Field(..., alias='credentials') options: Optional[Dict[str, Any]] = Field(default=None, alias='options') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'provider' not in data: + data['provider'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'type' not in data: + data['type'] = '' + if 'credentials' not in data: + data['credentials'] = [] + return data diff --git a/appwrite/models/provider_list.py b/appwrite/models/provider_list.py index c6265653..b34ec7e6 100644 --- a/appwrite/models/provider_list.py +++ b/appwrite/models/provider_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .provider import Provider @@ -19,3 +19,14 @@ class ProviderList(AppwriteModel): total: float = Field(..., alias='total') providers: List[Provider] = Field(..., alias='providers') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/proxy_invalidation.py b/appwrite/models/proxy_invalidation.py index 586ba9e3..b0e08da9 100644 --- a/appwrite/models/proxy_invalidation.py +++ b/appwrite/models/proxy_invalidation.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class ProxyInvalidation(AppwriteModel): type: str = Field(..., alias='type') reference: str = Field(..., alias='reference') status: str = Field(..., alias='status') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'domain' not in data: + data['domain'] = '' + if 'type' not in data: + data['type'] = '' + if 'reference' not in data: + data['reference'] = '' + if 'status' not in data: + data['status'] = '' + return data diff --git a/appwrite/models/proxy_rule.py b/appwrite/models/proxy_rule.py index 53a3d0d8..1e7325c8 100644 --- a/appwrite/models/proxy_rule.py +++ b/appwrite/models/proxy_rule.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from ..enums.proxy_rule_deployment_resource_type import ProxyRuleDeploymentResourceType @@ -31,7 +31,7 @@ class ProxyRule(AppwriteModel): deploymentid : str ID of deployment. Used if type is "deployment" deploymentresourcetype : Optional[ProxyRuleDeploymentResourceType] - Type of deployment. Possible values are "function", "site". Used if rule's type is "deployment". + Type of deployment resource: function, site, or dedicatedDatabase. deploymentresourceid : str ID of deployment's resource (site or function ID). Used if type is "deployment" deploymentvcsproviderbranch : str @@ -62,3 +62,38 @@ class ProxyRule(AppwriteModel): status: ProxyRuleStatus = Field(..., alias='status') logs: str = Field(..., alias='logs') renewat: str = Field(..., alias='renewAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'domain' not in data: + data['domain'] = '' + if 'type' not in data: + data['type'] = '' + if 'trigger' not in data: + data['trigger'] = '' + if 'redirectUrl' not in data and 'redirecturl' not in data: + data['redirectUrl'] = '' + if 'redirectStatusCode' not in data and 'redirectstatuscode' not in data: + data['redirectStatusCode'] = 301 + if 'deploymentId' not in data and 'deploymentid' not in data: + data['deploymentId'] = '' + if 'deploymentResourceId' not in data and 'deploymentresourceid' not in data: + data['deploymentResourceId'] = '' + if 'deploymentVcsProviderBranch' not in data and 'deploymentvcsproviderbranch' not in data: + data['deploymentVcsProviderBranch'] = '' + if 'status' not in data: + data['status'] = 'unverified' + if 'logs' not in data: + data['logs'] = '' + return data diff --git a/appwrite/models/proxy_rule_list.py b/appwrite/models/proxy_rule_list.py index 8c266224..d34bdc37 100644 --- a/appwrite/models/proxy_rule_list.py +++ b/appwrite/models/proxy_rule_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .proxy_rule import ProxyRule @@ -19,3 +19,14 @@ class ProxyRuleList(AppwriteModel): total: float = Field(..., alias='total') rules: List[ProxyRule] = Field(..., alias='rules') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/report.py b/appwrite/models/report.py index 88241b4f..41b914ad 100644 --- a/appwrite/models/report.py +++ b/appwrite/models/report.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .insight import Insight @@ -49,3 +49,32 @@ class Report(AppwriteModel): categories: List[Any] = Field(..., alias='categories') insights: List[Insight] = Field(..., alias='insights') analyzedat: Optional[str] = Field(default=None, alias='analyzedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'appId' not in data and 'appid' not in data: + data['appId'] = '' + if 'type' not in data: + data['type'] = '' + if 'title' not in data: + data['title'] = '' + if 'summary' not in data: + data['summary'] = '' + if 'targetType' not in data and 'targettype' not in data: + data['targetType'] = '' + if 'target' not in data: + data['target'] = '' + if 'categories' not in data: + data['categories'] = [] + return data diff --git a/appwrite/models/report_list.py b/appwrite/models/report_list.py index 3edfb434..881bf7e7 100644 --- a/appwrite/models/report_list.py +++ b/appwrite/models/report_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .report import Report @@ -19,3 +19,14 @@ class ReportList(AppwriteModel): total: float = Field(..., alias='total') reports: List[Report] = Field(..., alias='reports') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/resource_token.py b/appwrite/models/resource_token.py index c8b9ec05..12fbd31a 100644 --- a/appwrite/models/resource_token.py +++ b/appwrite/models/resource_token.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -33,3 +33,26 @@ class ResourceToken(AppwriteModel): expire: str = Field(..., alias='expire') secret: str = Field(..., alias='secret') accessedat: str = Field(..., alias='accessedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'secret' not in data: + data['secret'] = '' + if 'accessedAt' not in data and 'accessedat' not in data: + data['accessedAt'] = '' + return data diff --git a/appwrite/models/resource_token_list.py b/appwrite/models/resource_token_list.py index b1ee177e..0bf0f8a7 100644 --- a/appwrite/models/resource_token_list.py +++ b/appwrite/models/resource_token_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .resource_token import ResourceToken @@ -19,3 +19,14 @@ class ResourceTokenList(AppwriteModel): total: float = Field(..., alias='total') tokens: List[ResourceToken] = Field(..., alias='tokens') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/row.py b/appwrite/models/row.py index 5a8aa39e..86b637b6 100644 --- a/appwrite/models/row.py +++ b/appwrite/models/row.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr, TypeAdapter, model_serializer +from pydantic import Field, PrivateAttr, TypeAdapter, model_validator, model_serializer from .base_model import AppwriteModel @@ -38,6 +38,27 @@ class Row(AppwriteModel, Generic[T]): updatedat: str = Field(..., alias='$updatedAt') permissions: List[Any] = Field(..., alias='$permissions') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$sequence' not in data and 'sequence' not in data: + data['$sequence'] = '' + if '$tableId' not in data and 'tableid' not in data: + data['$tableId'] = '' + if '$databaseId' not in data and 'databaseid' not in data: + data['$databaseId'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'Row[T]': """Create Row instance with typed data.""" diff --git a/appwrite/models/row_list.py b/appwrite/models/row_list.py index 174b973d..ba009168 100644 --- a/appwrite/models/row_list.py +++ b/appwrite/models/row_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .row import Row @@ -22,6 +22,17 @@ class RowList(AppwriteModel, Generic[T]): total: float = Field(..., alias='total') rows: List[Row[T]] = Field(..., alias='rows') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'RowList[T]': """Create RowList instance with typed data.""" diff --git a/appwrite/models/runtime.py b/appwrite/models/runtime.py index debc5e8a..c8908c00 100644 --- a/appwrite/models/runtime.py +++ b/appwrite/models/runtime.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -36,3 +36,26 @@ class Runtime(AppwriteModel): image: str = Field(..., alias='image') logo: str = Field(..., alias='logo') supports: List[Any] = Field(..., alias='supports') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if 'key' not in data: + data['key'] = '' + if 'name' not in data: + data['name'] = '' + if 'version' not in data: + data['version'] = '' + if 'base' not in data: + data['base'] = '' + if 'image' not in data: + data['image'] = '' + if 'logo' not in data: + data['logo'] = '' + return data diff --git a/appwrite/models/runtime_list.py b/appwrite/models/runtime_list.py index 18121a93..783f2fc8 100644 --- a/appwrite/models/runtime_list.py +++ b/appwrite/models/runtime_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .runtime import Runtime @@ -19,3 +19,14 @@ class RuntimeList(AppwriteModel): total: float = Field(..., alias='total') runtimes: List[Runtime] = Field(..., alias='runtimes') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/session.py b/appwrite/models/session.py index 01f10bfa..ffcf6b5b 100644 --- a/appwrite/models/session.py +++ b/appwrite/models/session.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -99,3 +99,70 @@ class Session(AppwriteModel): factors: List[Any] = Field(..., alias='factors') secret: str = Field(..., alias='secret') mfaupdatedat: str = Field(..., alias='mfaUpdatedAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'provider' not in data: + data['provider'] = '' + if 'providerUid' not in data and 'provideruid' not in data: + data['providerUid'] = '' + if 'providerAccessToken' not in data and 'provideraccesstoken' not in data: + data['providerAccessToken'] = '' + if 'providerAccessTokenExpiry' not in data and 'provideraccesstokenexpiry' not in data: + data['providerAccessTokenExpiry'] = '' + if 'providerRefreshToken' not in data and 'providerrefreshtoken' not in data: + data['providerRefreshToken'] = '' + if 'ip' not in data: + data['ip'] = '' + if 'osCode' not in data and 'oscode' not in data: + data['osCode'] = '' + if 'osName' not in data and 'osname' not in data: + data['osName'] = '' + if 'osVersion' not in data and 'osversion' not in data: + data['osVersion'] = '' + if 'clientType' not in data and 'clienttype' not in data: + data['clientType'] = '' + if 'clientCode' not in data and 'clientcode' not in data: + data['clientCode'] = '' + if 'clientName' not in data and 'clientname' not in data: + data['clientName'] = '' + if 'clientVersion' not in data and 'clientversion' not in data: + data['clientVersion'] = '' + if 'clientEngine' not in data and 'clientengine' not in data: + data['clientEngine'] = '' + if 'clientEngineVersion' not in data and 'clientengineversion' not in data: + data['clientEngineVersion'] = '' + if 'deviceName' not in data and 'devicename' not in data: + data['deviceName'] = '' + if 'deviceBrand' not in data and 'devicebrand' not in data: + data['deviceBrand'] = '' + if 'deviceModel' not in data and 'devicemodel' not in data: + data['deviceModel'] = '' + if 'countryCode' not in data and 'countrycode' not in data: + data['countryCode'] = '' + if 'countryName' not in data and 'countryname' not in data: + data['countryName'] = '' + if 'current' not in data: + data['current'] = False + if 'factors' not in data: + data['factors'] = [] + if 'secret' not in data: + data['secret'] = '' + if 'mfaUpdatedAt' not in data and 'mfaupdatedat' not in data: + data['mfaUpdatedAt'] = '' + return data diff --git a/appwrite/models/session_list.py b/appwrite/models/session_list.py index 7518f56a..eee669a3 100644 --- a/appwrite/models/session_list.py +++ b/appwrite/models/session_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .session import Session @@ -19,3 +19,14 @@ class SessionList(AppwriteModel): total: float = Field(..., alias='total') sessions: List[Session] = Field(..., alias='sessions') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/site.py b/appwrite/models/site.py index b6f2aad6..11e5549e 100644 --- a/appwrite/models/site.py +++ b/appwrite/models/site.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .variable import Variable @@ -118,3 +118,76 @@ class Site(AppwriteModel): buildruntime: str = Field(..., alias='buildRuntime') adapter: str = Field(..., alias='adapter') fallbackfile: str = Field(..., alias='fallbackFile') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'live' not in data: + data['live'] = True + if 'logging' not in data: + data['logging'] = True + if 'framework' not in data: + data['framework'] = '' + if 'deploymentRetention' not in data and 'deploymentretention' not in data: + data['deploymentRetention'] = 0 + if 'deploymentId' not in data and 'deploymentid' not in data: + data['deploymentId'] = '' + if 'deploymentCreatedAt' not in data and 'deploymentcreatedat' not in data: + data['deploymentCreatedAt'] = '' + if 'deploymentScreenshotLight' not in data and 'deploymentscreenshotlight' not in data: + data['deploymentScreenshotLight'] = '' + if 'deploymentScreenshotDark' not in data and 'deploymentscreenshotdark' not in data: + data['deploymentScreenshotDark'] = '' + if 'latestDeploymentId' not in data and 'latestdeploymentid' not in data: + data['latestDeploymentId'] = '' + if 'latestDeploymentCreatedAt' not in data and 'latestdeploymentcreatedat' not in data: + data['latestDeploymentCreatedAt'] = '' + if 'latestDeploymentStatus' not in data and 'latestdeploymentstatus' not in data: + data['latestDeploymentStatus'] = '' + if 'scopes' not in data: + data['scopes'] = [] + if 'timeout' not in data: + data['timeout'] = 15 + if 'installCommand' not in data and 'installcommand' not in data: + data['installCommand'] = '' + if 'buildCommand' not in data and 'buildcommand' not in data: + data['buildCommand'] = '' + if 'startCommand' not in data and 'startcommand' not in data: + data['startCommand'] = '' + if 'outputDirectory' not in data and 'outputdirectory' not in data: + data['outputDirectory'] = '' + if 'installationId' not in data and 'installationid' not in data: + data['installationId'] = '' + if 'providerRepositoryId' not in data and 'providerrepositoryid' not in data: + data['providerRepositoryId'] = '' + if 'providerBranch' not in data and 'providerbranch' not in data: + data['providerBranch'] = '' + if 'providerRootDirectory' not in data and 'providerrootdirectory' not in data: + data['providerRootDirectory'] = '' + if 'providerSilentMode' not in data and 'providersilentmode' not in data: + data['providerSilentMode'] = False + if 'providerBranches' not in data and 'providerbranches' not in data: + data['providerBranches'] = [] + if 'providerPaths' not in data and 'providerpaths' not in data: + data['providerPaths'] = [] + if 'buildSpecification' not in data and 'buildspecification' not in data: + data['buildSpecification'] = 's-1vcpu-512mb' + if 'runtimeSpecification' not in data and 'runtimespecification' not in data: + data['runtimeSpecification'] = 's-1vcpu-512mb' + if 'buildRuntime' not in data and 'buildruntime' not in data: + data['buildRuntime'] = '' + return data diff --git a/appwrite/models/site_list.py b/appwrite/models/site_list.py index cd60234d..05050252 100644 --- a/appwrite/models/site_list.py +++ b/appwrite/models/site_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .site import Site @@ -19,3 +19,14 @@ class SiteList(AppwriteModel): total: float = Field(..., alias='total') sites: List[Site] = Field(..., alias='sites') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/specification.py b/appwrite/models/specification.py index 6f65491f..1b0fc393 100644 --- a/appwrite/models/specification.py +++ b/appwrite/models/specification.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -24,3 +24,20 @@ class Specification(AppwriteModel): cpus: float = Field(..., alias='cpus') enabled: bool = Field(..., alias='enabled') slug: str = Field(..., alias='slug') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'memory' not in data: + data['memory'] = 0 + if 'cpus' not in data: + data['cpus'] = 0 + if 'enabled' not in data: + data['enabled'] = False + if 'slug' not in data: + data['slug'] = '' + return data diff --git a/appwrite/models/specification_list.py b/appwrite/models/specification_list.py index e05ad6db..2d82e14b 100644 --- a/appwrite/models/specification_list.py +++ b/appwrite/models/specification_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .specification import Specification @@ -19,3 +19,14 @@ class SpecificationList(AppwriteModel): total: float = Field(..., alias='total') specifications: List[Specification] = Field(..., alias='specifications') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/subscriber.py b/appwrite/models/subscriber.py index 80d8e390..707d5b52 100644 --- a/appwrite/models/subscriber.py +++ b/appwrite/models/subscriber.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .target import Target @@ -40,3 +40,28 @@ class Subscriber(AppwriteModel): username: str = Field(..., alias='userName') topicid: str = Field(..., alias='topicId') providertype: str = Field(..., alias='providerType') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'targetId' not in data and 'targetid' not in data: + data['targetId'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'userName' not in data and 'username' not in data: + data['userName'] = '' + if 'topicId' not in data and 'topicid' not in data: + data['topicId'] = '' + if 'providerType' not in data and 'providertype' not in data: + data['providerType'] = '' + return data diff --git a/appwrite/models/subscriber_list.py b/appwrite/models/subscriber_list.py index cb346700..064f7c7d 100644 --- a/appwrite/models/subscriber_list.py +++ b/appwrite/models/subscriber_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .subscriber import Subscriber @@ -19,3 +19,14 @@ class SubscriberList(AppwriteModel): total: float = Field(..., alias='total') subscribers: List[Subscriber] = Field(..., alias='subscribers') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/table.py b/appwrite/models/table.py index 6e4a5cbf..d085c562 100644 --- a/appwrite/models/table.py +++ b/appwrite/models/table.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .column_boolean import ColumnBoolean @@ -88,3 +88,30 @@ class Table(AppwriteModel): indexes: List[ColumnIndex] = Field(..., alias='indexes') bytesmax: float = Field(..., alias='bytesMax') bytesused: float = Field(..., alias='bytesUsed') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'databaseId' not in data and 'databaseid' not in data: + data['databaseId'] = '' + if 'name' not in data: + data['name'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'rowSecurity' not in data and 'rowsecurity' not in data: + data['rowSecurity'] = False + if 'bytesMax' not in data and 'bytesmax' not in data: + data['bytesMax'] = 0 + if 'bytesUsed' not in data and 'bytesused' not in data: + data['bytesUsed'] = 0 + return data diff --git a/appwrite/models/table_list.py b/appwrite/models/table_list.py index 9d8b29f2..4654f47e 100644 --- a/appwrite/models/table_list.py +++ b/appwrite/models/table_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .table import Table @@ -19,3 +19,14 @@ class TableList(AppwriteModel): total: float = Field(..., alias='total') tables: List[Table] = Field(..., alias='tables') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/target.py b/appwrite/models/target.py index de38e227..8377844f 100644 --- a/appwrite/models/target.py +++ b/appwrite/models/target.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -39,3 +39,28 @@ class Target(AppwriteModel): providertype: str = Field(..., alias='providerType') identifier: str = Field(..., alias='identifier') expired: bool = Field(..., alias='expired') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'providerType' not in data and 'providertype' not in data: + data['providerType'] = '' + if 'identifier' not in data: + data['identifier'] = '' + if 'expired' not in data: + data['expired'] = False + return data diff --git a/appwrite/models/target_list.py b/appwrite/models/target_list.py index 095aa9bf..88622d81 100644 --- a/appwrite/models/target_list.py +++ b/appwrite/models/target_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .target import Target @@ -19,3 +19,14 @@ class TargetList(AppwriteModel): total: float = Field(..., alias='total') targets: List[Target] = Field(..., alias='targets') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/team.py b/appwrite/models/team.py index c1f13ab4..8b2b7209 100644 --- a/appwrite/models/team.py +++ b/appwrite/models/team.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .preferences import Preferences @@ -34,6 +34,25 @@ class Team(AppwriteModel, Generic[T]): total: float = Field(..., alias='total') prefs: Preferences[T] = Field(..., alias='prefs') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'total' not in data: + data['total'] = 0 + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'Team[T]': """Create Team instance with typed data.""" diff --git a/appwrite/models/team_list.py b/appwrite/models/team_list.py index 682e09d7..d55512cc 100644 --- a/appwrite/models/team_list.py +++ b/appwrite/models/team_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .team import Team @@ -22,6 +22,17 @@ class TeamList(AppwriteModel, Generic[T]): total: float = Field(..., alias='total') teams: List[Team[T]] = Field(..., alias='teams') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'TeamList[T]': """Create TeamList instance with typed data.""" diff --git a/appwrite/models/token.py b/appwrite/models/token.py index b99233d2..614b43c6 100644 --- a/appwrite/models/token.py +++ b/appwrite/models/token.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -30,3 +30,24 @@ class Token(AppwriteModel): secret: str = Field(..., alias='secret') expire: str = Field(..., alias='expire') phrase: str = Field(..., alias='phrase') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'secret' not in data: + data['secret'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'phrase' not in data: + data['phrase'] = '' + return data diff --git a/appwrite/models/token_secret.py b/appwrite/models/token_secret.py new file mode 100644 index 00000000..c745ea11 --- /dev/null +++ b/appwrite/models/token_secret.py @@ -0,0 +1,53 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel + + +class TokenSecret(AppwriteModel): + """ + Token Secret + + Attributes + ---------- + id : str + Token ID. + createdat : str + Token creation date in ISO 8601 format. + userid : str + User ID. + secret : str + Token secret key. Exchange it for a session with the create session endpoint. + expire : str + Token expiration date in ISO 8601 format. + phrase : str + Security phrase of a token. Empty if security phrase was not requested when creating a token. It includes randomly generated phrase which is also sent in the external resource such as email. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + userid: str = Field(..., alias='userId') + secret: str = Field(..., alias='secret') + expire: str = Field(..., alias='expire') + phrase: str = Field(..., alias='phrase') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if 'userId' not in data and 'userid' not in data: + data['userId'] = '' + if 'secret' not in data: + data['secret'] = '' + if 'expire' not in data: + data['expire'] = '' + if 'phrase' not in data: + data['phrase'] = '' + return data diff --git a/appwrite/models/topic.py b/appwrite/models/topic.py index ee1005b1..7870288f 100644 --- a/appwrite/models/topic.py +++ b/appwrite/models/topic.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -26,6 +26,10 @@ class Topic(AppwriteModel): Total count of push subscribers subscribed to the topic. subscribe : List[Any] Subscribe permissions. + qos : Optional[float] + MQTT QoS for delivery on this topic. Null lets the subscriber choose their level. + expiry : Optional[float] + Message retention in seconds for offline delivery. """ id: str = Field(..., alias='$id') @@ -36,3 +40,30 @@ class Topic(AppwriteModel): smstotal: float = Field(..., alias='smsTotal') pushtotal: float = Field(..., alias='pushTotal') subscribe: List[Any] = Field(..., alias='subscribe') + qos: Optional[float] = Field(default=None, alias='qos') + expiry: Optional[float] = Field(default=None, alias='expiry') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'emailTotal' not in data and 'emailtotal' not in data: + data['emailTotal'] = 0 + if 'smsTotal' not in data and 'smstotal' not in data: + data['smsTotal'] = 0 + if 'pushTotal' not in data and 'pushtotal' not in data: + data['pushTotal'] = 0 + if 'subscribe' not in data: + data['subscribe'] = ['users'] + return data diff --git a/appwrite/models/topic_list.py b/appwrite/models/topic_list.py index e739ccb5..4113e905 100644 --- a/appwrite/models/topic_list.py +++ b/appwrite/models/topic_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .topic import Topic @@ -19,3 +19,14 @@ class TopicList(AppwriteModel): total: float = Field(..., alias='total') topics: List[Topic] = Field(..., alias='topics') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/transaction.py b/appwrite/models/transaction.py index 03461ab3..6936d7eb 100644 --- a/appwrite/models/transaction.py +++ b/appwrite/models/transaction.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -30,3 +30,24 @@ class Transaction(AppwriteModel): status: str = Field(..., alias='status') operations: float = Field(..., alias='operations') expiresat: str = Field(..., alias='expiresAt') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'status' not in data: + data['status'] = 'pending' + if 'operations' not in data: + data['operations'] = 0 + if 'expiresAt' not in data and 'expiresat' not in data: + data['expiresAt'] = '' + return data diff --git a/appwrite/models/transaction_list.py b/appwrite/models/transaction_list.py index a6c7184d..402d2341 100644 --- a/appwrite/models/transaction_list.py +++ b/appwrite/models/transaction_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .transaction import Transaction @@ -19,3 +19,14 @@ class TransactionList(AppwriteModel): total: float = Field(..., alias='total') transactions: List[Transaction] = Field(..., alias='transactions') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/usage_billing_plan.py b/appwrite/models/usage_billing_plan.py index 1951161a..cca5b806 100644 --- a/appwrite/models/usage_billing_plan.py +++ b/appwrite/models/usage_billing_plan.py @@ -11,38 +11,38 @@ class UsageBillingPlan(AppwriteModel): Attributes ---------- - bandwidth : AdditionalResource + bandwidth : Optional[AdditionalResource] Bandwidth additional resources - executions : AdditionalResource + executions : Optional[AdditionalResource] Executions additional resources member : Optional[AdditionalResource] Member additional resources - realtime : AdditionalResource + realtime : Optional[AdditionalResource] Realtime additional resources - realtimemessages : AdditionalResource + realtimemessages : Optional[AdditionalResource] Realtime messages additional resources realtimebandwidth : Optional[AdditionalResource] Realtime bandwidth additional resources - storage : AdditionalResource + storage : Optional[AdditionalResource] Storage additional resources - users : AdditionalResource + users : Optional[AdditionalResource] User additional resources - gbhours : AdditionalResource + gbhours : Optional[AdditionalResource] GBHour additional resources - imagetransformations : AdditionalResource + imagetransformations : Optional[AdditionalResource] Image transformation additional resources credits : Optional[AdditionalResource] Credits additional resources """ - bandwidth: AdditionalResource = Field(..., alias='bandwidth') - executions: AdditionalResource = Field(..., alias='executions') + bandwidth: Optional[AdditionalResource] = Field(default=None, alias='bandwidth') + executions: Optional[AdditionalResource] = Field(default=None, alias='executions') member: Optional[AdditionalResource] = Field(default=None, alias='member') - realtime: AdditionalResource = Field(..., alias='realtime') - realtimemessages: AdditionalResource = Field(..., alias='realtimeMessages') + realtime: Optional[AdditionalResource] = Field(default=None, alias='realtime') + realtimemessages: Optional[AdditionalResource] = Field(default=None, alias='realtimeMessages') realtimebandwidth: Optional[AdditionalResource] = Field(default=None, alias='realtimeBandwidth') - storage: AdditionalResource = Field(..., alias='storage') - users: AdditionalResource = Field(..., alias='users') - gbhours: AdditionalResource = Field(..., alias='GBHours') - imagetransformations: AdditionalResource = Field(..., alias='imageTransformations') + storage: Optional[AdditionalResource] = Field(default=None, alias='storage') + users: Optional[AdditionalResource] = Field(default=None, alias='users') + gbhours: Optional[AdditionalResource] = Field(default=None, alias='GBHours') + imagetransformations: Optional[AdditionalResource] = Field(default=None, alias='imageTransformations') credits: Optional[AdditionalResource] = Field(default=None, alias='credits') diff --git a/appwrite/models/user.py b/appwrite/models/user.py index c3891c04..79d9761d 100644 --- a/appwrite/models/user.py +++ b/appwrite/models/user.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .algo_argon2 import AlgoArgon2 @@ -59,6 +59,8 @@ class User(AppwriteModel, Generic[T]): Whether the user email is from a corporate domain. emailiscanonical : Optional[bool] Whether the user email is in its canonical form. + passwordpwned : Optional[bool] + Whether the password was found in a known data breach the last time it was checked. Null when the password has never been checked. phoneverification : bool Phone verification status. mfa : bool @@ -104,6 +106,7 @@ class User(AppwriteModel, Generic[T]): emailisdisposable: Optional[bool] = Field(default=None, alias='emailIsDisposable') emailiscorporate: Optional[bool] = Field(default=None, alias='emailIsCorporate') emailiscanonical: Optional[bool] = Field(default=None, alias='emailIsCanonical') + passwordpwned: Optional[bool] = Field(default=None, alias='passwordPwned') phoneverification: bool = Field(..., alias='phoneVerification') mfa: bool = Field(..., alias='mfa') prefs: Preferences[T] = Field(..., alias='prefs') @@ -112,6 +115,43 @@ class User(AppwriteModel, Generic[T]): impersonator: Optional[bool] = Field(default=None, alias='impersonator') impersonatoruserid: Optional[str] = Field(default=None, alias='impersonatorUserId') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'registration' not in data: + data['registration'] = '' + if 'status' not in data: + data['status'] = True + if 'labels' not in data: + data['labels'] = [] + if 'passwordUpdate' not in data and 'passwordupdate' not in data: + data['passwordUpdate'] = '' + if 'email' not in data: + data['email'] = '' + if 'phone' not in data: + data['phone'] = '' + if 'emailVerification' not in data and 'emailverification' not in data: + data['emailVerification'] = False + if 'phoneVerification' not in data and 'phoneverification' not in data: + data['phoneVerification'] = False + if 'mfa' not in data: + data['mfa'] = False + if 'accessedAt' not in data and 'accessedat' not in data: + data['accessedAt'] = '' + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'User[T]': """Create User instance with typed data.""" diff --git a/appwrite/models/user_list.py b/appwrite/models/user_list.py index 7c6c7a2d..138e0b2a 100644 --- a/appwrite/models/user_list.py +++ b/appwrite/models/user_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast, Generic, TypeVar, Type -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .user import User @@ -22,6 +22,17 @@ class UserList(AppwriteModel, Generic[T]): total: float = Field(..., alias='total') users: List[User[T]] = Field(..., alias='users') + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data + @classmethod def with_data(cls, data: Dict[str, Any], model_type: Type[T] = dict) -> 'UserList[T]': """Create UserList instance with typed data.""" diff --git a/appwrite/models/variable.py b/appwrite/models/variable.py index c89b1cbc..a50d58f0 100644 --- a/appwrite/models/variable.py +++ b/appwrite/models/variable.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -36,3 +36,28 @@ class Variable(AppwriteModel): secret: bool = Field(..., alias='secret') resourcetype: str = Field(..., alias='resourceType') resourceid: str = Field(..., alias='resourceId') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'key' not in data: + data['key'] = '' + if 'value' not in data: + data['value'] = '' + if 'secret' not in data: + data['secret'] = False + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = '' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + return data diff --git a/appwrite/models/variable_list.py b/appwrite/models/variable_list.py index 9307112e..f8ad929b 100644 --- a/appwrite/models/variable_list.py +++ b/appwrite/models/variable_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .variable import Variable @@ -19,3 +19,14 @@ class VariableList(AppwriteModel): total: float = Field(..., alias='total') variables: List[Variable] = Field(..., alias='variables') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/vectorsdb_collection.py b/appwrite/models/vectorsdb_collection.py index bfdae1d9..5795e45e 100644 --- a/appwrite/models/vectorsdb_collection.py +++ b/appwrite/models/vectorsdb_collection.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .attribute_object import AttributeObject @@ -59,3 +59,32 @@ class VectorsdbCollection(AppwriteModel): bytesmax: float = Field(..., alias='bytesMax') bytesused: float = Field(..., alias='bytesUsed') dimension: float = Field(..., alias='dimension') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'databaseId' not in data and 'databaseid' not in data: + data['databaseId'] = '' + if 'name' not in data: + data['name'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'documentSecurity' not in data and 'documentsecurity' not in data: + data['documentSecurity'] = False + if 'bytesMax' not in data and 'bytesmax' not in data: + data['bytesMax'] = 0 + if 'bytesUsed' not in data and 'bytesused' not in data: + data['bytesUsed'] = 0 + if 'dimension' not in data: + data['dimension'] = 0 + return data diff --git a/appwrite/models/vectorsdb_collection_list.py b/appwrite/models/vectorsdb_collection_list.py index 2e930e8d..b88688f8 100644 --- a/appwrite/models/vectorsdb_collection_list.py +++ b/appwrite/models/vectorsdb_collection_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .vectorsdb_collection import VectorsdbCollection @@ -19,3 +19,14 @@ class VectorsdbCollectionList(AppwriteModel): total: float = Field(..., alias='total') collections: List[VectorsdbCollection] = Field(..., alias='collections') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/waf_rule_bypass.py b/appwrite/models/waf_rule_bypass.py new file mode 100644 index 00000000..3ea5053d --- /dev/null +++ b/appwrite/models/waf_rule_bypass.py @@ -0,0 +1,92 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from ..enums.waf_rule_action import WafRuleAction + + +class WafRuleBypass(AppwriteModel): + """ + WafRuleBypass + + Attributes + ---------- + id : str + Rule ID. + createdat : str + WAF rule creation time in ISO 8601 format. + updatedat : str + WAF rule last update time in ISO 8601 format. + name : str + Human friendly rule name. + description : str + Optional description for the rule. + teamid : str + Team ID. + projectid : str + Project ID. + resourcetype : str + Resource type the rule is scoped to. + resourceid : str + Resource identifier. Empty for API-wide rules. + action : WafRuleAction + Action performed when the rule matches. + priority : float + Evaluation priority. Lower values execute earlier. + enabled : bool + Whether the rule is active. + conditions : List[Any] + List of conditions evaluated for this rule. + config : Dict[str, Any] + Action specific configuration. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + name: str = Field(..., alias='name') + description: str = Field(..., alias='description') + teamid: str = Field(..., alias='teamId') + projectid: str = Field(..., alias='projectId') + resourcetype: str = Field(..., alias='resourceType') + resourceid: str = Field(..., alias='resourceId') + action: WafRuleAction = Field(..., alias='action') + priority: float = Field(..., alias='priority') + enabled: bool = Field(..., alias='enabled') + conditions: List[Any] = Field(..., alias='conditions') + config: Dict[str, Any] = Field(..., alias='config') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'description' not in data: + data['description'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = 'api' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'priority' not in data: + data['priority'] = 0 + if 'enabled' not in data: + data['enabled'] = True + if 'conditions' not in data: + data['conditions'] = [] + if 'config' not in data: + data['config'] = [] + return data diff --git a/appwrite/models/waf_rule_challenge.py b/appwrite/models/waf_rule_challenge.py new file mode 100644 index 00000000..f07f518d --- /dev/null +++ b/appwrite/models/waf_rule_challenge.py @@ -0,0 +1,107 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from ..enums.waf_rule_action import WafRuleAction + + +class WafRuleChallenge(AppwriteModel): + """ + WafRuleChallenge + + Attributes + ---------- + id : str + Rule ID. + createdat : str + WAF rule creation time in ISO 8601 format. + updatedat : str + WAF rule last update time in ISO 8601 format. + name : str + Human friendly rule name. + description : str + Optional description for the rule. + teamid : str + Team ID. + projectid : str + Project ID. + resourcetype : str + Resource type the rule is scoped to. + resourceid : str + Resource identifier. Empty for API-wide rules. + action : WafRuleAction + Action performed when the rule matches. + priority : float + Evaluation priority. Lower values execute earlier. + enabled : bool + Whether the rule is active. + conditions : List[Any] + List of conditions evaluated for this rule. + config : Dict[str, Any] + Action specific configuration. + challengetype : str + Challenge type enforced when the rule matches. + difficulty : float + Challenge difficulty from 1 (easiest) to 5 (hardest) enforced when the rule matches. + ttl : float + Seconds a visitor stays cleared after passing the challenge before being challenged again. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + name: str = Field(..., alias='name') + description: str = Field(..., alias='description') + teamid: str = Field(..., alias='teamId') + projectid: str = Field(..., alias='projectId') + resourcetype: str = Field(..., alias='resourceType') + resourceid: str = Field(..., alias='resourceId') + action: WafRuleAction = Field(..., alias='action') + priority: float = Field(..., alias='priority') + enabled: bool = Field(..., alias='enabled') + conditions: List[Any] = Field(..., alias='conditions') + config: Dict[str, Any] = Field(..., alias='config') + challengetype: str = Field(..., alias='challengeType') + difficulty: float = Field(..., alias='difficulty') + ttl: float = Field(..., alias='ttl') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'description' not in data: + data['description'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = 'api' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'priority' not in data: + data['priority'] = 0 + if 'enabled' not in data: + data['enabled'] = True + if 'conditions' not in data: + data['conditions'] = [] + if 'config' not in data: + data['config'] = [] + if 'challengeType' not in data and 'challengetype' not in data: + data['challengeType'] = 'compute' + if 'difficulty' not in data: + data['difficulty'] = 3 + if 'ttl' not in data: + data['ttl'] = 1800 + return data diff --git a/appwrite/models/waf_rule_deny.py b/appwrite/models/waf_rule_deny.py new file mode 100644 index 00000000..90f9ba89 --- /dev/null +++ b/appwrite/models/waf_rule_deny.py @@ -0,0 +1,92 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from ..enums.waf_rule_action import WafRuleAction + + +class WafRuleDeny(AppwriteModel): + """ + WafRuleDeny + + Attributes + ---------- + id : str + Rule ID. + createdat : str + WAF rule creation time in ISO 8601 format. + updatedat : str + WAF rule last update time in ISO 8601 format. + name : str + Human friendly rule name. + description : str + Optional description for the rule. + teamid : str + Team ID. + projectid : str + Project ID. + resourcetype : str + Resource type the rule is scoped to. + resourceid : str + Resource identifier. Empty for API-wide rules. + action : WafRuleAction + Action performed when the rule matches. + priority : float + Evaluation priority. Lower values execute earlier. + enabled : bool + Whether the rule is active. + conditions : List[Any] + List of conditions evaluated for this rule. + config : Dict[str, Any] + Action specific configuration. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + name: str = Field(..., alias='name') + description: str = Field(..., alias='description') + teamid: str = Field(..., alias='teamId') + projectid: str = Field(..., alias='projectId') + resourcetype: str = Field(..., alias='resourceType') + resourceid: str = Field(..., alias='resourceId') + action: WafRuleAction = Field(..., alias='action') + priority: float = Field(..., alias='priority') + enabled: bool = Field(..., alias='enabled') + conditions: List[Any] = Field(..., alias='conditions') + config: Dict[str, Any] = Field(..., alias='config') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'description' not in data: + data['description'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = 'api' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'priority' not in data: + data['priority'] = 0 + if 'enabled' not in data: + data['enabled'] = True + if 'conditions' not in data: + data['conditions'] = [] + if 'config' not in data: + data['config'] = [] + return data diff --git a/appwrite/models/waf_rule_list.py b/appwrite/models/waf_rule_list.py new file mode 100644 index 00000000..3817ada6 --- /dev/null +++ b/appwrite/models/waf_rule_list.py @@ -0,0 +1,44 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from .waf_rule_bypass import WafRuleBypass +from .waf_rule_deny import WafRuleDeny +from .waf_rule_challenge import WafRuleChallenge +from .waf_rule_rate_limit import WafRuleRateLimit +from .waf_rule_redirect import WafRuleRedirect + + +class WafRuleList(AppwriteModel): + """ + WAF rule list + + Attributes + ---------- + total : float + Total number of rules that matched your query. + rules : List[Union[WafRuleBypass, WafRuleDeny, WafRuleChallenge, WafRuleRateLimit, WafRuleRedirect]] + List of rules. + """ + + total: float = Field(..., alias='total') + rules: List[ + Union[ + WafRuleBypass, + WafRuleDeny, + WafRuleChallenge, + WafRuleRateLimit, + WafRuleRedirect, + ] + ] = Field(..., alias='rules') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/models/waf_rule_rate_limit.py b/appwrite/models/waf_rule_rate_limit.py new file mode 100644 index 00000000..f0b6884d --- /dev/null +++ b/appwrite/models/waf_rule_rate_limit.py @@ -0,0 +1,117 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from ..enums.waf_rule_action import WafRuleAction + + +class WafRuleRateLimit(AppwriteModel): + """ + WafRuleRateLimit + + Attributes + ---------- + id : str + Rule ID. + createdat : str + WAF rule creation time in ISO 8601 format. + updatedat : str + WAF rule last update time in ISO 8601 format. + name : str + Human friendly rule name. + description : str + Optional description for the rule. + teamid : str + Team ID. + projectid : str + Project ID. + resourcetype : str + Resource type the rule is scoped to. + resourceid : str + Resource identifier. Empty for API-wide rules. + action : WafRuleAction + Action performed when the rule matches. + priority : float + Evaluation priority. Lower values execute earlier. + enabled : bool + Whether the rule is active. + conditions : List[Any] + List of conditions evaluated for this rule. + config : Dict[str, Any] + Action specific configuration. + limit : float + Maximum number of matching requests allowed for the given interval. + interval : float + Interval in seconds for the rate limit window. + key : str + Rate limit key: `ip` limits per client IP, `userId` limits per authenticated user. + strategy : str + Rate limit strategy: `fixedWindow`, `slidingWindow`, or `tokenBucket`. + maxbucketsize : float + Maximum burst capacity in tokens, applied by the `tokenBucket` strategy. The sustained refill rate is `limit / interval`. Defaults to `limit`. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + name: str = Field(..., alias='name') + description: str = Field(..., alias='description') + teamid: str = Field(..., alias='teamId') + projectid: str = Field(..., alias='projectId') + resourcetype: str = Field(..., alias='resourceType') + resourceid: str = Field(..., alias='resourceId') + action: WafRuleAction = Field(..., alias='action') + priority: float = Field(..., alias='priority') + enabled: bool = Field(..., alias='enabled') + conditions: List[Any] = Field(..., alias='conditions') + config: Dict[str, Any] = Field(..., alias='config') + limit: float = Field(..., alias='limit') + interval: float = Field(..., alias='interval') + key: str = Field(..., alias='key') + strategy: str = Field(..., alias='strategy') + maxbucketsize: float = Field(..., alias='maxBucketSize') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'description' not in data: + data['description'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = 'api' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'priority' not in data: + data['priority'] = 0 + if 'enabled' not in data: + data['enabled'] = True + if 'conditions' not in data: + data['conditions'] = [] + if 'config' not in data: + data['config'] = [] + if 'limit' not in data: + data['limit'] = 100 + if 'interval' not in data: + data['interval'] = 3600 + if 'key' not in data: + data['key'] = 'ip' + if 'strategy' not in data: + data['strategy'] = 'fixedWindow' + if 'maxBucketSize' not in data and 'maxbucketsize' not in data: + data['maxBucketSize'] = 0 + return data diff --git a/appwrite/models/waf_rule_redirect.py b/appwrite/models/waf_rule_redirect.py new file mode 100644 index 00000000..53774939 --- /dev/null +++ b/appwrite/models/waf_rule_redirect.py @@ -0,0 +1,102 @@ +from typing import Any, Dict, List, Optional, Union, cast +from pydantic import Field, PrivateAttr, model_validator + +from .base_model import AppwriteModel +from ..enums.waf_rule_action import WafRuleAction + + +class WafRuleRedirect(AppwriteModel): + """ + WafRuleRedirect + + Attributes + ---------- + id : str + Rule ID. + createdat : str + WAF rule creation time in ISO 8601 format. + updatedat : str + WAF rule last update time in ISO 8601 format. + name : str + Human friendly rule name. + description : str + Optional description for the rule. + teamid : str + Team ID. + projectid : str + Project ID. + resourcetype : str + Resource type the rule is scoped to. + resourceid : str + Resource identifier. Empty for API-wide rules. + action : WafRuleAction + Action performed when the rule matches. + priority : float + Evaluation priority. Lower values execute earlier. + enabled : bool + Whether the rule is active. + conditions : List[Any] + List of conditions evaluated for this rule. + config : Dict[str, Any] + Action specific configuration. + location : str + Target location for the redirect. + statuscode : float + HTTP status code used for the redirect. + """ + + id: str = Field(..., alias='$id') + createdat: str = Field(..., alias='$createdAt') + updatedat: str = Field(..., alias='$updatedAt') + name: str = Field(..., alias='name') + description: str = Field(..., alias='description') + teamid: str = Field(..., alias='teamId') + projectid: str = Field(..., alias='projectId') + resourcetype: str = Field(..., alias='resourceType') + resourceid: str = Field(..., alias='resourceId') + action: WafRuleAction = Field(..., alias='action') + priority: float = Field(..., alias='priority') + enabled: bool = Field(..., alias='enabled') + conditions: List[Any] = Field(..., alias='conditions') + config: Dict[str, Any] = Field(..., alias='config') + location: str = Field(..., alias='location') + statuscode: float = Field(..., alias='statusCode') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'description' not in data: + data['description'] = '' + if 'teamId' not in data and 'teamid' not in data: + data['teamId'] = '' + if 'projectId' not in data and 'projectid' not in data: + data['projectId'] = '' + if 'resourceType' not in data and 'resourcetype' not in data: + data['resourceType'] = 'api' + if 'resourceId' not in data and 'resourceid' not in data: + data['resourceId'] = '' + if 'priority' not in data: + data['priority'] = 0 + if 'enabled' not in data: + data['enabled'] = True + if 'conditions' not in data: + data['conditions'] = [] + if 'config' not in data: + data['config'] = [] + if 'location' not in data: + data['location'] = '/' + if 'statusCode' not in data and 'statuscode' not in data: + data['statusCode'] = 302 + return data diff --git a/appwrite/models/webhook.py b/appwrite/models/webhook.py index ede2e0ad..3114336d 100644 --- a/appwrite/models/webhook.py +++ b/appwrite/models/webhook.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel @@ -27,7 +27,7 @@ class Webhook(AppwriteModel): authusername : str HTTP basic authentication username. authpassword : str - HTTP basic authentication password. + HTTP basic authentication password. Write-only: always returned empty. secret : str Signature key which can be used to validate incoming webhook payloads. Only returned on creation and secret rotation. enabled : bool @@ -51,3 +51,38 @@ class Webhook(AppwriteModel): enabled: bool = Field(..., alias='enabled') logs: str = Field(..., alias='logs') attempts: float = Field(..., alias='attempts') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if '$id' not in data and 'id' not in data: + data['$id'] = '' + if '$createdAt' not in data and 'createdat' not in data: + data['$createdAt'] = '' + if '$updatedAt' not in data and 'updatedat' not in data: + data['$updatedAt'] = '' + if 'name' not in data: + data['name'] = '' + if 'url' not in data: + data['url'] = '' + if 'events' not in data: + data['events'] = [] + if 'tls' not in data: + data['tls'] = True + if 'authUsername' not in data and 'authusername' not in data: + data['authUsername'] = '' + if 'authPassword' not in data and 'authpassword' not in data: + data['authPassword'] = '' + if 'secret' not in data: + data['secret'] = '' + if 'enabled' not in data: + data['enabled'] = True + if 'logs' not in data: + data['logs'] = '' + if 'attempts' not in data: + data['attempts'] = 0 + return data diff --git a/appwrite/models/webhook_list.py b/appwrite/models/webhook_list.py index 537ea090..7f68e1ed 100644 --- a/appwrite/models/webhook_list.py +++ b/appwrite/models/webhook_list.py @@ -1,5 +1,5 @@ from typing import Any, Dict, List, Optional, Union, cast -from pydantic import Field, PrivateAttr +from pydantic import Field, PrivateAttr, model_validator from .base_model import AppwriteModel from .webhook import Webhook @@ -19,3 +19,14 @@ class WebhookList(AppwriteModel): total: float = Field(..., alias='total') webhooks: List[Webhook] = Field(..., alias='webhooks') + + @model_validator(mode='before') + @classmethod + def _apply_defaults(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + + data = dict(data) + if 'total' not in data: + data['total'] = 0 + return data diff --git a/appwrite/services/account.py b/appwrite/services/account.py index 03c7bc39..6891e202 100644 --- a/appwrite/services/account.py +++ b/appwrite/services/account.py @@ -9,7 +9,6 @@ from ..models.oauth2_consent_token_list import Oauth2ConsentTokenList from ..models.oauth2_consent_token import Oauth2ConsentToken from ..models.identity_list import IdentityList -from ..models.log_list import LogList from ..enums.authenticator_type import AuthenticatorType from ..models.mfa_type import MfaType from ..enums.authentication_factor import AuthenticationFactor @@ -17,10 +16,15 @@ from ..models.session import Session from ..models.mfa_factors import MfaFactors from ..models.mfa_recovery_codes import MfaRecoveryCodes +from ..models.passkey_list import PasskeyList +from ..models.passkey_challenge import PasskeyChallenge +from ..models.passkey import Passkey from ..models.preferences import Preferences from ..models.token import Token from ..models.session_list import SessionList +from ..enums.id_token_provider import IdTokenProvider from ..enums.o_auth_provider import OAuthProvider +from ..models.token_secret import TokenSecret T = TypeVar('T') @@ -198,7 +202,7 @@ def get_consent( api_path = '/account/consents/{consentId}' api_params = {} - if consent_id is None: + if consent_id is None or consent_id == '': raise AppwriteException('Missing required parameter: "consent_id"') api_path = api_path.replace('{consentId}', str(self._normalize_value(consent_id))) @@ -238,7 +242,7 @@ def delete_consent( api_path = '/account/consents/{consentId}' api_params = {} - if consent_id is None: + if consent_id is None or consent_id == '': raise AppwriteException('Missing required parameter: "consent_id"') api_path = api_path.replace('{consentId}', str(self._normalize_value(consent_id))) @@ -285,7 +289,7 @@ def list_consent_tokens( api_path = '/account/consents/{consentId}/tokens' api_params = {} - if consent_id is None: + if consent_id is None or consent_id == '': raise AppwriteException('Missing required parameter: "consent_id"') api_path = api_path.replace('{consentId}', str(self._normalize_value(consent_id))) if queries is not None: @@ -332,9 +336,9 @@ def get_consent_token( api_path = '/account/consents/{consentId}/tokens/{tokenId}' api_params = {} - if consent_id is None: + if consent_id is None or consent_id == '': raise AppwriteException('Missing required parameter: "consent_id"') - if token_id is None: + if token_id is None or token_id == '': raise AppwriteException('Missing required parameter: "token_id"') api_path = api_path.replace('{consentId}', str(self._normalize_value(consent_id))) api_path = api_path.replace('{tokenId}', str(self._normalize_value(token_id))) @@ -378,9 +382,9 @@ def delete_consent_token( api_path = '/account/consents/{consentId}/tokens/{tokenId}' api_params = {} - if consent_id is None: + if consent_id is None or consent_id == '': raise AppwriteException('Missing required parameter: "consent_id"') - if token_id is None: + if token_id is None or token_id == '': raise AppwriteException('Missing required parameter: "token_id"') api_path = api_path.replace('{consentId}', str(self._normalize_value(consent_id))) api_path = api_path.replace('{tokenId}', str(self._normalize_value(token_id))) @@ -518,7 +522,7 @@ def delete_identity( api_path = '/account/identities/{identityId}' api_params = {} - if identity_id is None: + if identity_id is None or identity_id == '': raise AppwriteException('Missing required parameter: "identity_id"') api_path = api_path.replace('{identityId}', str(self._normalize_value(identity_id))) @@ -528,55 +532,12 @@ def delete_identity( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', - }, - api_params, - ) - - return response - - def list_logs( - self, - queries: Optional[List[str]] = None, - total: Optional[bool] = None, - ) -> LogList: - """ - 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. - - Parameters - ---------- - queries : Optional[List[str]] - 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 : Optional[bool] - When set to false, the total count returned will be 0 and will not be calculated. - Returns - ------- - LogList - API response as a typed Pydantic model - - Raises - ------ - AppwriteException - If API request fails - """ - - api_path = '/account/logs' - api_params = {} - if queries is not None: - api_params['queries'] = self._normalize_value(queries) - if total is not None: - api_params['total'] = self._normalize_value(total) - - response = self.client.call( - 'get', - api_path, - { - 'X-Appwrite-Project': self.client.get_config('project'), 'accept': 'application/json', }, api_params, ) - return self._parse_response(response, model=LogList) + return response def update_mfa( self, @@ -749,6 +710,7 @@ def delete_mfa_authenticator( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1014,6 +976,270 @@ def update_name( return User.with_data(response, model_type) + def list_passkeys( + self, + queries: Optional[List[str]] = None, + total: Optional[bool] = None, + ) -> PasskeyList: + """ + Get the list of verified passkeys registered by the currently logged in user. + + Parameters + ---------- + queries : Optional[List[str]] + 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 and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. + Returns + ------- + PasskeyList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/passkeys' + api_params = {} + if queries is not None: + api_params['queries'] = self._normalize_value(queries) + if total is not None: + api_params['total'] = self._normalize_value(total) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=PasskeyList) + + def create_passkey( + self, + passkey_id: Optional[str] = None, + name: Optional[str] = None, + ) -> PasskeyChallenge: + """ + Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + + Parameters + ---------- + passkey_id : Optional[str] + Passkey 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 : Optional[str] + Passkey name, shown when listing passkeys. Max length: 128 chars. + Returns + ------- + PasskeyChallenge + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/passkeys' + api_params = {} + if passkey_id is not None: + api_params['passkeyId'] = self._normalize_value(passkey_id) + if name is not None: + api_params['name'] = self._normalize_value(name) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=PasskeyChallenge) + + def get_passkey( + self, + passkey_id: str, + ) -> Passkey: + """ + Get a verified passkey of the currently logged in user by its unique ID. + + Parameters + ---------- + passkey_id : str + Passkey ID. + Returns + ------- + Passkey + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/passkeys/{passkeyId}' + api_params = {} + if passkey_id is None or passkey_id == '': + raise AppwriteException('Missing required parameter: "passkey_id"') + api_path = api_path.replace('{passkeyId}', str(self._normalize_value(passkey_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Passkey) + + def update_passkey( + self, + passkey_id: str, + name: str, + ) -> Passkey: + """ + Rename a passkey of the currently logged in user. + + Parameters + ---------- + passkey_id : str + Passkey ID. + name : str + Passkey name. Max length: 128 chars. + Returns + ------- + Passkey + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/passkeys/{passkeyId}' + api_params = {} + if passkey_id is None or passkey_id == '': + raise AppwriteException('Missing required parameter: "passkey_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + api_path = api_path.replace('{passkeyId}', str(self._normalize_value(passkey_id))) + api_params['name'] = self._normalize_value(name) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Passkey) + + def delete_passkey( + self, + passkey_id: str, + ) -> Dict[str, Any]: + """ + Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + + Parameters + ---------- + passkey_id : str + Passkey ID. + Returns + ------- + Dict[str, Any] + API response as a dictionary + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/passkeys/{passkeyId}' + api_params = {} + if passkey_id is None or passkey_id == '': + raise AppwriteException('Missing required parameter: "passkey_id"') + api_path = api_path.replace('{passkeyId}', str(self._normalize_value(passkey_id))) + + response = self.client.call( + 'delete', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return response + + def update_passkey_verification( + self, + passkey_id: str, + credential: Dict[str, Any], + ) -> Passkey: + """ + Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. + + Parameters + ---------- + passkey_id : str + Passkey ID. + credential : Dict[str, Any] + Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + Returns + ------- + Passkey + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/passkeys/{passkeyId}/verification' + api_params = {} + if passkey_id is None or passkey_id == '': + raise AppwriteException('Missing required parameter: "passkey_id"') + if credential is None: + raise AppwriteException('Missing required parameter: "credential"') + api_path = api_path.replace('{passkeyId}', str(self._normalize_value(passkey_id))) + api_params['credential'] = self._normalize_value(credential) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Passkey) + def update_password( self, password: str, @@ -1159,18 +1385,114 @@ def update_prefs( model_type: Type[T] = dict, ) -> User[T]: """ - Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded. + Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded. + + Parameters + ---------- + prefs : Dict[str, Any] + Prefs key-value JSON object. + model_type : Type[T], optional + Pydantic model class for the user-defined data. Defaults to dict for backward compatibility. + + Returns + ------- + User[T] + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/prefs' + api_params = {} + if prefs is None: + raise AppwriteException('Missing required parameter: "prefs"') + api_params['prefs'] = self._normalize_value(prefs) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return User.with_data(response, model_type) + + def create_recovery( + self, + email: str, + url: str, + ) -> Token: + """ + Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT /account/recovery](https://appwrite.io/docs/references/cloud/client-web/account#updateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour. + + Parameters + ---------- + email : str + User email. + url : str + URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project 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. + Returns + ------- + Token + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/recovery' + api_params = {} + if email is None: + raise AppwriteException('Missing required parameter: "email"') + if url is None: + raise AppwriteException('Missing required parameter: "url"') + api_params['email'] = self._normalize_value(email) + api_params['url'] = self._normalize_value(url) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Token) + + def update_recovery( + self, + user_id: str, + secret: str, + password: str, + ) -> Token: + """ + Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST /account/recovery](https://appwrite.io/docs/references/cloud/client-web/account#createRecovery) endpoint. + + Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface. Parameters ---------- - prefs : Dict[str, Any] - Prefs key-value JSON object. - model_type : Type[T], optional - Pydantic model class for the user-defined data. Defaults to dict for backward compatibility. - + user_id : str + User ID. + secret : str + Valid reset token. + password : str + New user password. Must be between 8 and 256 chars. Returns ------- - User[T] + Token API response as a typed Pydantic model Raises @@ -1179,14 +1501,20 @@ def update_prefs( If API request fails """ - api_path = '/account/prefs' + api_path = '/account/recovery' api_params = {} - if prefs is None: - raise AppwriteException('Missing required parameter: "prefs"') - api_params['prefs'] = self._normalize_value(prefs) + if user_id is None: + raise AppwriteException('Missing required parameter: "user_id"') + if secret is None: + raise AppwriteException('Missing required parameter: "secret"') + if password is None: + raise AppwriteException('Missing required parameter: "password"') + api_params['userId'] = self._normalize_value(user_id) + api_params['secret'] = self._normalize_value(secret) + api_params['password'] = self._normalize_value(password) response = self.client.call( - 'patch', + 'put', api_path, { 'X-Appwrite-Project': self.client.get_config('project'), @@ -1196,22 +1524,24 @@ def update_prefs( api_params, ) - return User.with_data(response, model_type) + return self._parse_response(response, model=Token) - def create_recovery( + def create_recovery_otp( self, email: str, - url: str, + phrase: Optional[bool] = None, ) -> Token: """ - Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT /account/recovery](https://appwrite.io/docs/references/cloud/client-web/account#updateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour. + Use this endpoint to send a 6-digit password recovery code to the user's email address. Unlike [createRecovery](https://appwrite.io/docs/references/cloud/client-web/account#createRecovery), this method requires no redirect URL, which makes it suitable for mobile and desktop apps that cannot host a recovery page. Learn more about how to [complete the recovery process](https://appwrite.io/docs/references/cloud/client-web/account#updateRecoveryOTP). The code sent to the user's email address is valid for 15 minutes. + + Enable the **phrase** parameter to include a randomly generated security phrase in both the email and the response. Showing that phrase in your app lets the user confirm the email genuinely came from your request, which helps protect against phishing. Parameters ---------- email : str User email. - url : str - URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project 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. + phrase : Optional[bool] + Toggle for security phrase. If enabled, email will be sent with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow. Returns ------- Token @@ -1223,14 +1553,13 @@ def create_recovery( If API request fails """ - api_path = '/account/recovery' + api_path = '/account/recovery/otp' api_params = {} if email is None: raise AppwriteException('Missing required parameter: "email"') - if url is None: - raise AppwriteException('Missing required parameter: "url"') api_params['email'] = self._normalize_value(email) - api_params['url'] = self._normalize_value(url) + if phrase is not None: + api_params['phrase'] = self._normalize_value(phrase) response = self.client.call( 'post', @@ -1245,23 +1574,21 @@ def create_recovery( return self._parse_response(response, model=Token) - def update_recovery( + def update_recovery_otp( self, user_id: str, secret: str, password: str, ) -> Token: """ - Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST /account/recovery](https://appwrite.io/docs/references/cloud/client-web/account#createRecovery) endpoint. - - Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface. + Use this endpoint to complete the user password recovery process using the 6-digit code that was emailed by [createRecoveryOTP](https://appwrite.io/docs/references/cloud/client-web/account#createRecoveryOTP). Pass the **userId** of the user along with the **secret** code from the email and the new **password** to set. If confirmed, this route will return a 200 status code, the code is consumed and the user's password is updated. Parameters ---------- user_id : str User ID. secret : str - Valid reset token. + Valid recovery OTP code. password : str New user password. Must be between 8 and 256 chars. Returns @@ -1275,7 +1602,7 @@ def update_recovery( If API request fails """ - api_path = '/account/recovery' + api_path = '/account/recovery/otp' api_params = {} if user_id is None: raise AppwriteException('Missing required parameter: "user_id"') @@ -1302,9 +1629,15 @@ def update_recovery( def list_sessions( self, + total: Optional[bool] = None, ) -> SessionList: """ Get the list of active sessions across different devices for the currently logged in user. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- SessionList @@ -1318,6 +1651,8 @@ def list_sessions( api_path = '/account/sessions' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -1333,9 +1668,15 @@ def list_sessions( def delete_sessions( self, + current: Optional[bool] = None, ) -> Dict[str, Any]: """ - Delete all sessions from the user account and remove any sessions cookies from the end client. + Delete all sessions from the user account and remove any sessions cookies from the end client. Pass `current` as false to keep the session making the request and sign out of every other session. + + Parameters + ---------- + current : Optional[bool] + Delete the current session too. Use false to sign out of every other session while staying signed in on this one. Returns ------- Dict[str, Any] @@ -1349,6 +1690,8 @@ def delete_sessions( api_path = '/account/sessions' api_params = {} + if current is not None: + api_params['current'] = self._normalize_value(current) response = self.client.call( 'delete', @@ -1356,6 +1699,7 @@ def delete_sessions( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1398,9 +1742,10 @@ def create_email_password_session( self, email: str, password: str, + duration: Optional[float] = None, ) -> Session: """ - Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user. + Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user. Use the optional `duration` parameter to create a shorter session, for example when the user doesn't choose "remember me". It must be at least 60 seconds and cannot exceed the project maximum session length. A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). @@ -1410,6 +1755,8 @@ def create_email_password_session( User email. password : str User password. Must be at least 8 chars. + duration : Optional[float] + Session length in seconds. Minimum is 60 seconds, and it cannot exceed the project maximum session length. Defaults to the project maximum session length. Returns ------- Session @@ -1429,6 +1776,85 @@ def create_email_password_session( raise AppwriteException('Missing required parameter: "password"') api_params['email'] = self._normalize_value(email) api_params['password'] = self._normalize_value(password) + if duration is not None: + api_params['duration'] = self._normalize_value(duration) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Session) + + def create_id_token_session( + self, + provider: IdTokenProvider, + id_token: str, + nonce: Optional[str] = None, + access_token: Optional[str] = None, + access_token_expiry: Optional[float] = None, + name: Optional[str] = None, + ) -> Session: + """ + Allow the user to login to their account using an OpenID Connect ID token obtained natively from the OAuth2 provider, for example via Google Credential Manager on Android or Sign in with Apple on iOS. No browser or redirect is involved: the ID token is verified against the provider's published signing keys and a session is created in a single request. + + Native sign-in is switched on per provider with its nativeEnabled setting. It is independent of the browser-based flow's enabled setting, which has no effect on this endpoint. The token's audience must match the provider's configured client ID or one of its native client IDs; tokens issued for any other client ID are rejected. For Sign in with Apple, register your app's bundle ID as a native client ID. For Google, the web client ID used by Credential Manager is usually the configured client ID; add your Android and iOS client IDs as native client IDs if your app requests tokens for them. + + Pass the raw nonce used when requesting the ID token so it can be validated against the token's nonce claim. When signing in with Apple, the nonce is required: hash it with SHA-256 before passing it to the Apple SDK, and send the raw value here - Apple tokens requested without a nonce are rejected. For Google the nonce is optional: it is validated whenever the token carries one, and ignored when the provider issued the token without one. Apple only returns the user's name on the first authorization, and never inside the ID token - capture it on the client and pass it via the name parameter. + + If there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the verified email received from the provider and attach the new session to the existing user. If no matching user is found - the server will create a new user. + + This flow does not return provider refresh tokens. You may pass an access token the provider handed your client, along with its lifetime, to store it on the session - but Appwrite cannot renew it once it expires. If your app needs long-lived access to provider APIs, use the browser-based OAuth2 flow instead. + + A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). + + Parameters + ---------- + provider : IdTokenProvider + OAuth2 provider that issued the ID token. Currently, supported providers are: apple, google. + id_token : str + OpenID Connect ID token (JWT) obtained natively from the provider, for example via Google Credential Manager or Sign in with Apple. + nonce : Optional[str] + Raw nonce used when requesting the ID token. Required for Apple, and whenever the token carries a nonce claim, which must match it. Ignored when the provider issued the token without a nonce. + access_token : Optional[str] + Provider access token to store alongside the session for calling provider APIs. Never used for authentication. + access_token_expiry : Optional[float] + Seconds until the provider access token expires, as reported by the provider. Stored so clients can tell when the stored token goes stale. + name : Optional[str] + User name. Only used when creating a new user and the ID token has no name claim, such as on the first Sign in with Apple authorization. + Returns + ------- + Session + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/sessions/id-token' + api_params = {} + if provider is None: + raise AppwriteException('Missing required parameter: "provider"') + if id_token is None: + raise AppwriteException('Missing required parameter: "id_token"') + api_params['provider'] = self._normalize_value(provider) + api_params['idToken'] = self._normalize_value(id_token) + if nonce is not None: + api_params['nonce'] = self._normalize_value(nonce) + if access_token is not None: + api_params['accessToken'] = self._normalize_value(access_token) + if access_token_expiry is not None: + api_params['accessTokenExpiry'] = self._normalize_value(access_token_expiry) + if name is not None: + api_params['name'] = self._normalize_value(name) response = self.client.call( 'post', @@ -1614,7 +2040,7 @@ def get_session( api_path = '/account/sessions/{sessionId}' api_params = {} - if session_id is None: + if session_id is None or session_id == '': raise AppwriteException('Missing required parameter: "session_id"') api_path = api_path.replace('{sessionId}', str(self._normalize_value(session_id))) @@ -1654,7 +2080,7 @@ def update_session( api_path = '/account/sessions/{sessionId}' api_params = {} - if session_id is None: + if session_id is None or session_id == '': raise AppwriteException('Missing required parameter: "session_id"') api_path = api_path.replace('{sessionId}', str(self._normalize_value(session_id))) @@ -1695,7 +2121,7 @@ def delete_session( api_path = '/account/sessions/{sessionId}' api_params = {} - if session_id is None: + if session_id is None or session_id == '': raise AppwriteException('Missing required parameter: "session_id"') api_path = api_path.replace('{sessionId}', str(self._normalize_value(session_id))) @@ -1705,6 +2131,7 @@ def delete_session( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1876,12 +2303,14 @@ def create_o_auth2_token( If authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint. + If there is already an active session, the OAuth2 identity is attached to the logged-in account and that session stays active until the token is exchanged for a new one. + A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). Parameters ---------- provider : OAuthProvider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. + OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, webflow, wordpress, x, yahoo, yammer, yandex, zoho, zoom. success : Optional[str] 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 : Optional[str] @@ -1928,6 +2357,85 @@ def create_o_auth2_token( return response + def create_passkey_token( + self, + ) -> PasskeyChallenge: + """ + Start signing in with a passkey. No email or user ID is needed: pass the returned `publicKey` options to `navigator.credentials.get()` and the user picks one of their passkeys. Then call [Update passkey token](/docs/references/cloud/client-web/account#updatePasskeyToken) with the credential to receive a token, and exchange it with [Create session](/docs/references/cloud/client-web/account#createSession). The challenge expires after 5 minutes. + Returns + ------- + PasskeyChallenge + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/tokens/passkey' + api_params = {} + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=PasskeyChallenge) + + def update_passkey_token( + self, + challenge_id: str, + credential: Dict[str, Any], + ) -> TokenSecret: + """ + Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + + Parameters + ---------- + challenge_id : str + Challenge ID returned by createPasskeyToken. + credential : Dict[str, Any] + Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + Returns + ------- + TokenSecret + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/tokens/passkey' + api_params = {} + if challenge_id is None: + raise AppwriteException('Missing required parameter: "challenge_id"') + if credential is None: + raise AppwriteException('Missing required parameter: "credential"') + api_params['challengeId'] = self._normalize_value(challenge_id) + api_params['credential'] = self._normalize_value(credential) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=TokenSecret) + def create_phone_token( self, user_id: str, @@ -2163,6 +2671,95 @@ def update_verification( return self._parse_response(response, model=Token) + def create_email_verification_otp( + self, + phrase: Optional[bool] = None, + ) -> Token: + """ + Use this endpoint to send a 6-digit verification code to the currently logged in user's email address. Unlike [createEmailVerification](https://appwrite.io/docs/references/cloud/client-web/account#createEmailVerification), this method requires no redirect URL, which makes it suitable for mobile and desktop apps that cannot host a verification page. Learn more about how to [complete the verification process](https://appwrite.io/docs/references/cloud/client-web/account#updateEmailVerificationOTP). The code sent to the user's email address is valid for 15 minutes. + + Enable the **phrase** parameter to include a randomly generated security phrase in both the email and the response. Showing that phrase in your app lets the user confirm the email genuinely came from your request, which helps protect against phishing. + + Parameters + ---------- + phrase : Optional[bool] + Toggle for security phrase. If enabled, email will be sent with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow. + Returns + ------- + Token + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/verifications/email/otp' + api_params = {} + if phrase is not None: + api_params['phrase'] = self._normalize_value(phrase) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Token) + + def update_email_verification_otp( + self, + user_id: str, + secret: str, + ) -> Token: + """ + Use this endpoint to complete the user email verification process using the 6-digit code that was emailed by [createEmailVerificationOTP](https://appwrite.io/docs/references/cloud/client-web/account#createEmailVerificationOTP). Pass the **userId** of the user being verified along with the **secret** code from the email. If confirmed, this route will return a 200 status code and the code is consumed. + + Parameters + ---------- + user_id : str + User ID. + secret : str + Valid verification OTP code. + Returns + ------- + Token + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/account/verifications/email/otp' + api_params = {} + if user_id is None: + raise AppwriteException('Missing required parameter: "user_id"') + if secret is None: + raise AppwriteException('Missing required parameter: "secret"') + api_params['userId'] = self._normalize_value(user_id) + api_params['secret'] = self._normalize_value(secret) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Token) + def create_phone_verification( self, ) -> Token: diff --git a/appwrite/services/activities.py b/appwrite/services/activities.py index 9ef1b8d8..1c33eeef 100644 --- a/appwrite/services/activities.py +++ b/appwrite/services/activities.py @@ -75,7 +75,7 @@ def get_event( api_path = '/activities/events/{eventId}' api_params = {} - if event_id is None: + if event_id is None or event_id == '': raise AppwriteException('Missing required parameter: "event_id"') api_path = api_path.replace('{eventId}', str(self._normalize_value(event_id))) diff --git a/appwrite/services/advisor.py b/appwrite/services/advisor.py index 4afa6aa6..194d0b7a 100644 --- a/appwrite/services/advisor.py +++ b/appwrite/services/advisor.py @@ -82,7 +82,7 @@ def get_report( api_path = '/reports/{reportId}' api_params = {} - if report_id is None: + if report_id is None or report_id == '': raise AppwriteException('Missing required parameter: "report_id"') api_path = api_path.replace('{reportId}', str(self._normalize_value(report_id))) @@ -122,7 +122,7 @@ def delete_report( api_path = '/reports/{reportId}' api_params = {} - if report_id is None: + if report_id is None or report_id == '': raise AppwriteException('Missing required parameter: "report_id"') api_path = api_path.replace('{reportId}', str(self._normalize_value(report_id))) @@ -132,6 +132,7 @@ def delete_report( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -168,7 +169,7 @@ def list_insights( api_path = '/reports/{reportId}/insights' api_params = {} - if report_id is None: + if report_id is None or report_id == '': raise AppwriteException('Missing required parameter: "report_id"') api_path = api_path.replace('{reportId}', str(self._normalize_value(report_id))) if queries is not None: @@ -215,9 +216,9 @@ def get_insight( api_path = '/reports/{reportId}/insights/{insightId}' api_params = {} - if report_id is None: + if report_id is None or report_id == '': raise AppwriteException('Missing required parameter: "report_id"') - if insight_id is None: + if insight_id is None or insight_id == '': raise AppwriteException('Missing required parameter: "insight_id"') api_path = api_path.replace('{reportId}', str(self._normalize_value(report_id))) api_path = api_path.replace('{insightId}', str(self._normalize_value(insight_id))) diff --git a/appwrite/services/apps.py b/appwrite/services/apps.py index 71b5b2ca..6a3439a6 100644 --- a/appwrite/services/apps.py +++ b/appwrite/services/apps.py @@ -284,7 +284,7 @@ def get( api_path = '/apps/{appId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) @@ -381,7 +381,7 @@ def update( api_path = '/apps/{appId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -461,7 +461,7 @@ def delete( api_path = '/apps/{appId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) @@ -508,7 +508,7 @@ def list_installations( api_path = '/apps/{appId}/installations' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) if queries is not None: @@ -555,9 +555,9 @@ def get_installation( api_path = '/apps/{appId}/installations/{installationId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) @@ -601,9 +601,9 @@ def delete_installation( api_path = '/apps/{appId}/installations/{installationId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) @@ -648,9 +648,9 @@ def create_installation_token( api_path = '/apps/{appId}/installations/{installationId}/tokens' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) @@ -698,7 +698,7 @@ def list_keys( api_path = '/apps/{appId}/keys' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) if queries is not None: @@ -742,7 +742,7 @@ def create_key( api_path = '/apps/{appId}/keys' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) @@ -786,9 +786,9 @@ def get_key( api_path = '/apps/{appId}/keys/{keyId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') - if key_id is None: + if key_id is None or key_id == '': raise AppwriteException('Missing required parameter: "key_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) @@ -832,9 +832,9 @@ def delete_key( api_path = '/apps/{appId}/keys/{keyId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') - if key_id is None: + if key_id is None or key_id == '': raise AppwriteException('Missing required parameter: "key_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) @@ -865,7 +865,7 @@ def update_labels( app_id : str Application unique ID. labels : List[str] - Array of application labels. Replaces the previous labels. Maximum of 1000 labels are allowed, each up to 36 alphanumeric characters long. + Array of application labels. Replaces the previous labels. Maximum of 1000 labels are allowed, each up to 36 alphanumeric characters long. Reserved labels are rejected. Returns ------- App @@ -879,7 +879,7 @@ def update_labels( api_path = '/apps/{appId}/labels' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') if labels is None: raise AppwriteException('Missing required parameter: "labels"') @@ -929,7 +929,7 @@ def list_secrets( api_path = '/apps/{appId}/secrets' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) if queries is not None: @@ -973,7 +973,7 @@ def create_secret( api_path = '/apps/{appId}/secrets' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) @@ -1017,9 +1017,9 @@ def get_secret( api_path = '/apps/{appId}/secrets/{secretId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') - if secret_id is None: + if secret_id is None or secret_id == '': raise AppwriteException('Missing required parameter: "secret_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) api_path = api_path.replace('{secretId}', str(self._normalize_value(secret_id))) @@ -1063,9 +1063,9 @@ def delete_secret( api_path = '/apps/{appId}/secrets/{secretId}' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') - if secret_id is None: + if secret_id is None or secret_id == '': raise AppwriteException('Missing required parameter: "secret_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) api_path = api_path.replace('{secretId}', str(self._normalize_value(secret_id))) @@ -1110,7 +1110,7 @@ def update_team( api_path = '/apps/{appId}/team' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') if team_id is None: raise AppwriteException('Missing required parameter: "team_id"') @@ -1154,7 +1154,7 @@ def delete_tokens( api_path = '/apps/{appId}/tokens' api_params = {} - if app_id is None: + if app_id is None or app_id == '': raise AppwriteException('Missing required parameter: "app_id"') api_path = api_path.replace('{appId}', str(self._normalize_value(app_id))) diff --git a/appwrite/services/avatars.py b/appwrite/services/avatars.py index 27d11785..a01b4baf 100644 --- a/appwrite/services/avatars.py +++ b/appwrite/services/avatars.py @@ -1,16 +1,20 @@ from ..service import Service from urllib.parse import quote -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Union, Type, TypeVar from ..exception import AppwriteException from appwrite.utils.deprecated import deprecated from ..enums.browser import Browser from ..enums.credit_card import CreditCard from ..enums.flag import Flag +from ..input_file import InputFile +from ..models.account import Account from ..enums.browser_theme import BrowserTheme from ..enums.timezone import Timezone from ..enums.browser_permission import BrowserPermission from ..enums.image_format import ImageFormat +T = TypeVar('T') + class Avatars(Service): @@ -354,7 +358,7 @@ def get_photo( name: Optional[str] = None, ) -> bytes: """ - Returns the best available profile photo for a user. The endpoint tries each source in priority order and returns the first successful result: OAuth2 identity photo, Gravatar, Libravatar, Appwrite Initials, built-in static fallback. + Returns the best available profile photo for a user. The endpoint tries each source in priority order and returns the first successful result: a custom uploaded photo (see avatars.updatePhoto), OAuth2 identity photo, Gravatar, Libravatar, Appwrite Initials, built-in static fallback. Passing `userId` — `current()` for the authenticated user — resolves the photo from everything known about that user: identity photos, email, and name. An explicit `emailHash` or `name` then overrides just that value, and the user's remaining sources stay in the chain. Without `userId`, passing `emailHash` and/or `name` resolves the avatar from those values alone: the hash is looked up on Gravatar and Libravatar, the name is rendered as initials, and the session user stays out of the chain so their own photo never shadows the avatar being asked for. When nothing is passed, the photo resolves for the currently authenticated user. Emails are only ever accepted pre-hashed, so no address ends up in a URL. @@ -418,6 +422,94 @@ def get_photo( return response + def update_photo( + self, + file: InputFile, + on_progress=None, + model_type: Type[T] = dict, + ) -> Account[T]: + """ + Update the profile photo of the currently authenticated user. The uploaded image takes priority over every other photo source, including OAuth2 identity photos, Gravatar, and Libravatar. Updating an already customized photo replaces it. The image must be at most 5MB and is sent in a single request. + + Parameters + ---------- + file : InputFile + Binary image file of at most 5MB. Allowed file types are png, jpg, jpeg, and webp. + on_progress : callable, optional + Optional callback for upload progress + + model_type : Type[T], optional + Pydantic model class for the user-defined data. Defaults to dict for backward compatibility. + + Returns + ------- + Account[T] + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/avatars/photo' + api_params = {} + if file is None: + raise AppwriteException('Missing required parameter: "file"') + api_params['file'] = self._normalize_value(file) + + param_name = 'file' + + upload_id = '' + + response = self.client.chunked_upload( + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'multipart/form-data', + 'accept': 'application/json', + }, + api_params, + param_name, + on_progress, + upload_id, + method='put', + ) + + return Account.with_data(response, model_type) + + def delete_photo( + self, + ) -> Dict[str, Any]: + """ + Delete the profile photo of the currently authenticated user and store the built-in static placeholder in its place. The placeholder is the user's photo from then on, so it takes priority over every other photo source — OAuth2 identity photos, Gravatar, Libravatar, and initials — until a new photo is uploaded with avatars.updatePhoto. + Returns + ------- + Dict[str, Any] + API response as a dictionary + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/avatars/photo' + api_params = {} + + response = self.client.call( + 'delete', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return response + def get_qr( self, text: str, @@ -508,7 +600,7 @@ def get_screenshot( url : str Website URL which you want to capture. headers : Optional[Dict[str, Any]] - HTTP headers to send with the browser request. Defaults to empty. + HTTP headers to send with the browser request. Only Accept and Accept-Language are allowed. Defaults to empty. viewport_width : Optional[float] Browser viewport width. Pass an integer between 1 to 1920. Defaults to 1280. viewport_height : Optional[float] diff --git a/appwrite/services/backups.py b/appwrite/services/backups.py index 4d40755e..c6e75e98 100644 --- a/appwrite/services/backups.py +++ b/appwrite/services/backups.py @@ -126,7 +126,7 @@ def get_archive( api_path = '/backups/archives/{archiveId}' api_params = {} - if archive_id is None: + if archive_id is None or archive_id == '': raise AppwriteException('Missing required parameter: "archive_id"') api_path = api_path.replace('{archiveId}', str(self._normalize_value(archive_id))) @@ -166,7 +166,7 @@ def delete_archive( api_path = '/backups/archives/{archiveId}' api_params = {} - if archive_id is None: + if archive_id is None or archive_id == '': raise AppwriteException('Missing required parameter: "archive_id"') api_path = api_path.replace('{archiveId}', str(self._normalize_value(archive_id))) @@ -320,7 +320,7 @@ def get_policy( api_path = '/backups/policies/{policyId}' api_params = {} - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -372,7 +372,7 @@ def update_policy( api_path = '/backups/policies/{policyId}' api_params = {} - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) if name is not None: @@ -421,7 +421,7 @@ def delete_policy( api_path = '/backups/policies/{policyId}' api_params = {} - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -566,7 +566,7 @@ def get_restoration( api_path = '/backups/restorations/{restorationId}' api_params = {} - if restoration_id is None: + if restoration_id is None or restoration_id == '': raise AppwriteException('Missing required parameter: "restoration_id"') api_path = api_path.replace('{restorationId}', str(self._normalize_value(restoration_id))) diff --git a/appwrite/services/databases.py b/appwrite/services/databases.py index dde65c10..f4f1c7f8 100644 --- a/appwrite/services/databases.py +++ b/appwrite/services/databases.py @@ -156,6 +156,7 @@ def create( def list_transactions( self, queries: Optional[List[str]] = None, + total: Optional[bool] = None, ) -> TransactionList: """ List transactions across all databases. @@ -166,6 +167,8 @@ def list_transactions( ---------- queries : Optional[List[str]] Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- TransactionList @@ -181,6 +184,8 @@ def list_transactions( api_params = {} if queries is not None: api_params['queries'] = self._normalize_value(queries) + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -264,7 +269,7 @@ def get_transaction( api_path = '/databases/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) @@ -313,7 +318,7 @@ def update_transaction( api_path = '/databases/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) if commit is not None: @@ -361,7 +366,7 @@ def delete_transaction( api_path = '/databases/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) @@ -371,6 +376,7 @@ def delete_transaction( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -407,7 +413,7 @@ def create_operations( api_path = '/databases/transactions/{transactionId}/operations' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) if operations is not None: @@ -453,7 +459,7 @@ def get( api_path = '/databases/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -502,7 +508,7 @@ def update( api_path = '/databases/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if name is not None: @@ -550,7 +556,7 @@ def delete( api_path = '/databases/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -560,6 +566,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -602,7 +609,7 @@ def list_collections( api_path = '/databases/{databaseId}/collections' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -672,7 +679,7 @@ def create_collection( api_path = '/databases/{databaseId}/collections' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if collection_id is None: raise AppwriteException('Missing required parameter: "collection_id"') @@ -735,9 +742,9 @@ def get_collection( api_path = '/databases/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -799,9 +806,9 @@ def update_collection( api_path = '/databases/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -859,9 +866,9 @@ def delete_collection( api_path = '/databases/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -872,6 +879,7 @@ def delete_collection( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -914,9 +922,9 @@ def list_attributes( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -985,9 +993,9 @@ def create_big_int_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/bigint' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1067,11 +1075,11 @@ def update_big_int_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/bigint/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1142,9 +1150,9 @@ def create_boolean_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/boolean' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1214,11 +1222,11 @@ def update_boolean_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/boolean/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1285,9 +1293,9 @@ def create_datetime_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/datetime' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1357,11 +1365,11 @@ def update_datetime_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/datetime/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1428,9 +1436,9 @@ def create_email_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/email' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1500,11 +1508,11 @@ def update_email_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/email/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1574,9 +1582,9 @@ def create_enum_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/enum' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1652,11 +1660,11 @@ def update_enum_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/enum/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if elements is None: raise AppwriteException('Missing required parameter: "elements"') @@ -1732,9 +1740,9 @@ def create_float_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/float' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1814,11 +1822,11 @@ def update_float_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/float/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1895,9 +1903,9 @@ def create_integer_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/integer' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1977,11 +1985,11 @@ def update_integer_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/integer/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2052,9 +2060,9 @@ def create_ip_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/ip' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2124,11 +2132,11 @@ def update_ip_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/ip/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2192,9 +2200,9 @@ def create_line_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/line' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2262,11 +2270,11 @@ def update_line_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/line/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2337,9 +2345,9 @@ def create_longtext_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/longtext' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2411,11 +2419,11 @@ def update_longtext_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/longtext/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2485,9 +2493,9 @@ def create_mediumtext_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/mediumtext' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2559,11 +2567,11 @@ def update_mediumtext_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/mediumtext/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2627,9 +2635,9 @@ def create_point_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/point' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2697,11 +2705,11 @@ def update_point_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/point/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2766,9 +2774,9 @@ def create_polygon_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/polygon' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2836,11 +2844,11 @@ def update_polygon_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/polygon/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2914,9 +2922,9 @@ def create_relationship_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/relationship' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if related_collection_id is None: raise AppwriteException('Missing required parameter: "related_collection_id"') @@ -2987,11 +2995,11 @@ def update_relationship_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/relationship/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -3062,9 +3070,9 @@ def create_string_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/string' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3142,11 +3150,11 @@ def update_string_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/string/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3218,9 +3226,9 @@ def create_text_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/text' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3292,11 +3300,11 @@ def update_text_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/text/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3363,9 +3371,9 @@ def create_url_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/url' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3435,11 +3443,11 @@ def update_url_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/url/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3512,9 +3520,9 @@ def create_varchar_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/varchar' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3592,11 +3600,11 @@ def update_varchar_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/varchar/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3631,6 +3639,7 @@ def get_attribute( key: str, ) -> Union[ AttributeBoolean, + AttributeBigint, AttributeInteger, AttributeFloat, AttributeEmail, @@ -3639,6 +3648,13 @@ def get_attribute( AttributeIp, AttributeDatetime, AttributeRelationship, + AttributePoint, + AttributeLine, + AttributePolygon, + AttributeVarchar, + AttributeText, + AttributeMediumtext, + AttributeLongtext, AttributeString, ]: """ @@ -3656,7 +3672,7 @@ def get_attribute( Attribute Key. Returns ------- - Union[AttributeBoolean, AttributeInteger, AttributeFloat, AttributeEmail, AttributeEnum, AttributeUrl, AttributeIp, AttributeDatetime, AttributeRelationship, AttributeString] + Union[AttributeBoolean, AttributeBigint, AttributeInteger, AttributeFloat, AttributeEmail, AttributeEnum, AttributeUrl, AttributeIp, AttributeDatetime, AttributeRelationship, AttributePoint, AttributeLine, AttributePolygon, AttributeVarchar, AttributeText, AttributeMediumtext, AttributeLongtext, AttributeString] API response as one of the typed response models Raises @@ -3667,11 +3683,11 @@ def get_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -3704,6 +3720,9 @@ def get_attribute( if response.get('type') == 'boolean': return self._parse_response(response, model=AttributeBoolean) + if response.get('type') == 'bigint': + return self._parse_response(response, model=AttributeBigint) + if response.get('type') == 'integer': return self._parse_response(response, model=AttributeInteger) @@ -3716,6 +3735,27 @@ def get_attribute( if response.get('type') == 'relationship': return self._parse_response(response, model=AttributeRelationship) + if response.get('type') == 'point': + return self._parse_response(response, model=AttributePoint) + + if response.get('type') == 'linestring': + return self._parse_response(response, model=AttributeLine) + + if response.get('type') == 'polygon': + return self._parse_response(response, model=AttributePolygon) + + if response.get('type') == 'varchar': + return self._parse_response(response, model=AttributeVarchar) + + if response.get('type') == 'text': + return self._parse_response(response, model=AttributeText) + + if response.get('type') == 'mediumtext': + return self._parse_response(response, model=AttributeMediumtext) + + if response.get('type') == 'longtext': + return self._parse_response(response, model=AttributeLongtext) + if response.get('type') == 'string': return self._parse_response(response, model=AttributeString) @@ -3754,11 +3794,11 @@ def delete_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/attributes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -3770,6 +3810,7 @@ def delete_attribute( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -3822,9 +3863,9 @@ def list_documents( api_path = '/databases/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -3895,9 +3936,9 @@ def create_document( api_path = '/databases/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if document_id is None: raise AppwriteException('Missing required parameter: "document_id"') @@ -3965,9 +4006,9 @@ def create_documents( api_path = '/databases/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if documents is None: raise AppwriteException('Missing required parameter: "documents"') @@ -4030,9 +4071,9 @@ def upsert_documents( api_path = '/databases/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if documents is None: raise AppwriteException('Missing required parameter: "documents"') @@ -4098,9 +4139,9 @@ def update_documents( api_path = '/databases/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4164,9 +4205,9 @@ def delete_documents( api_path = '/databases/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4231,11 +4272,11 @@ def get_document( api_path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4303,11 +4344,11 @@ def upsert_document( api_path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4378,11 +4419,11 @@ def update_document( api_path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4443,11 +4484,11 @@ def delete_document( api_path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4461,6 +4502,7 @@ def delete_document( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -4516,13 +4558,13 @@ def decrement_document_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/decrement' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') - if attribute is None: + if attribute is None or attribute == '': raise AppwriteException('Missing required parameter: "attribute"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4597,13 +4639,13 @@ def increment_document_attribute( api_path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/increment' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') - if attribute is None: + if attribute is None or attribute == '': raise AppwriteException('Missing required parameter: "attribute"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4665,9 +4707,9 @@ def list_indexes( api_path = '/databases/{databaseId}/collections/{collectionId}/indexes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4734,9 +4776,9 @@ def create_index( api_path = '/databases/{databaseId}/collections/{collectionId}/indexes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -4800,11 +4842,11 @@ def get_index( api_path = '/databases/{databaseId}/collections/{collectionId}/indexes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4855,11 +4897,11 @@ def delete_index( api_path = '/databases/{databaseId}/collections/{collectionId}/indexes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -4871,6 +4913,7 @@ def delete_index( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) diff --git a/appwrite/services/documents_db.py b/appwrite/services/documents_db.py index d11632b2..ecef7255 100644 --- a/appwrite/services/documents_db.py +++ b/appwrite/services/documents_db.py @@ -144,7 +144,7 @@ def list_specifications( self, ) -> DedicatedDatabaseSpecificationList: """ - 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. + List the dedicated database specifications available on the current plan. Each specification reports its resource limits, its own prices and overage rates, and whether it is enabled for the organization. Returns ------- DedicatedDatabaseSpecificationList @@ -174,6 +174,7 @@ def list_specifications( def list_transactions( self, queries: Optional[List[str]] = None, + total: Optional[bool] = None, ) -> TransactionList: """ List transactions across all databases. @@ -182,6 +183,8 @@ def list_transactions( ---------- queries : Optional[List[str]] Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- TransactionList @@ -197,6 +200,8 @@ def list_transactions( api_params = {} if queries is not None: api_params['queries'] = self._normalize_value(queries) + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -274,7 +279,7 @@ def get_transaction( api_path = '/documentsdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) @@ -320,7 +325,7 @@ def update_transaction( api_path = '/documentsdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) if commit is not None: @@ -365,7 +370,7 @@ def delete_transaction( api_path = '/documentsdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) @@ -375,6 +380,7 @@ def delete_transaction( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -408,7 +414,7 @@ def create_operations( api_path = '/documentsdb/transactions/{transactionId}/operations' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) if operations is not None: @@ -451,7 +457,7 @@ def get( api_path = '/documentsdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -506,7 +512,7 @@ def update( api_path = '/documentsdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -558,7 +564,7 @@ def delete( api_path = '/documentsdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -568,6 +574,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -607,7 +614,7 @@ def list_collections( api_path = '/documentsdb/{databaseId}/collections' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -674,7 +681,7 @@ def create_collection( api_path = '/documentsdb/{databaseId}/collections' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if collection_id is None: raise AppwriteException('Missing required parameter: "collection_id"') @@ -734,9 +741,9 @@ def get_collection( api_path = '/documentsdb/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -795,9 +802,9 @@ def update_collection( api_path = '/documentsdb/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -853,9 +860,9 @@ def delete_collection( api_path = '/documentsdb/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -866,6 +873,7 @@ def delete_collection( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -915,9 +923,9 @@ def list_documents( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -985,9 +993,9 @@ def create_document( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if document_id is None: raise AppwriteException('Missing required parameter: "document_id"') @@ -1052,9 +1060,9 @@ def create_documents( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if documents is None: raise AppwriteException('Missing required parameter: "documents"') @@ -1114,9 +1122,9 @@ def upsert_documents( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if documents is None: raise AppwriteException('Missing required parameter: "documents"') @@ -1179,9 +1187,9 @@ def update_documents( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1242,9 +1250,9 @@ def delete_documents( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1306,11 +1314,11 @@ def get_document( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1375,11 +1383,11 @@ def upsert_document( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1447,11 +1455,11 @@ def update_document( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1509,11 +1517,11 @@ def delete_document( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1527,6 +1535,7 @@ def delete_document( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1579,13 +1588,13 @@ def decrement_document_attribute( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/decrement' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') - if attribute is None: + if attribute is None or attribute == '': raise AppwriteException('Missing required parameter: "attribute"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1657,13 +1666,13 @@ def increment_document_attribute( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/increment' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') - if attribute is None: + if attribute is None or attribute == '': raise AppwriteException('Missing required parameter: "attribute"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1722,9 +1731,9 @@ def list_indexes( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/indexes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1788,9 +1797,9 @@ def create_index( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/indexes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1851,11 +1860,11 @@ def get_index( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/indexes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1903,11 +1912,11 @@ def delete_index( api_path = '/documentsdb/{databaseId}/collections/{collectionId}/indexes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1919,6 +1928,7 @@ def delete_index( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1952,7 +1962,7 @@ def create_failover( api_path = '/documentsdb/{databaseId}/failovers' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if target_replica_id is not None: @@ -2004,7 +2014,7 @@ def list_operations( api_path = '/documentsdb/{databaseId}/operations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -2050,7 +2060,7 @@ def get_replicas( api_path = '/documentsdb/{databaseId}/replicas' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -2090,7 +2100,7 @@ def get_status( api_path = '/documentsdb/{databaseId}/status' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) diff --git a/appwrite/services/domains.py b/appwrite/services/domains.py new file mode 100644 index 00000000..6ca12b76 --- /dev/null +++ b/appwrite/services/domains.py @@ -0,0 +1,2638 @@ +from ..service import Service +from urllib.parse import quote +from typing import Any, Dict, List, Optional, Union +from ..exception import AppwriteException +from appwrite.utils.deprecated import deprecated +from ..models.domains_list import DomainsList +from ..models.domain import Domain +from ..enums.domain_registration_type import DomainRegistrationType +from ..models.domain_price import DomainPrice +from ..models.domain_prices_list import DomainPricesList +from ..models.dns_records_list import DnsRecordsList +from ..models.dns_record import DnsRecord +from ..models.domain_transfer_status import DomainTransferStatus + + +class Domains(Service): + + def __init__(self, client) -> None: + super(Domains, self).__init__(client) + + def list( + self, + queries: Optional[List[str]] = None, + search: Optional[str] = None, + ) -> DomainsList: + """ + List all domains registered for this project. This endpoint supports pagination. + + Parameters + ---------- + queries : Optional[List[str]] + 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 domain name, teamInternalId, expiration, etc. + search : Optional[str] + Search term to filter your list results. Max length: 256 chars. + Returns + ------- + DomainsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains' + api_params = {} + if queries is not None: + api_params['queries'] = self._normalize_value(queries) + if search is not None: + api_params['search'] = self._normalize_value(search) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DomainsList) + + def create( + self, + team_id: str, + domain: str, + ) -> Domain: + """ + Create a new domain. Before creating a domain, you need to ensure that your DNS provider is properly configured. After creating the domain, you can use the verification endpoint to check if the domain is ready to be used. + + Parameters + ---------- + team_id : str + Team unique ID. + domain : str + Domain name (e.g. "example.com"). + Returns + ------- + Domain + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains' + api_params = {} + if team_id is None: + raise AppwriteException('Missing required parameter: "team_id"') + if domain is None: + raise AppwriteException('Missing required parameter: "domain"') + api_params['teamId'] = self._normalize_value(team_id) + api_params['domain'] = self._normalize_value(domain) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Domain) + + @deprecated("This API has been deprecated since 2.0.0. Please use `domains.list_prices` instead.") + def get_price( + self, + domain: str, + period_years: Optional[float] = None, + registration_type: Optional[DomainRegistrationType] = None, + ) -> DomainPrice: + """ + Get the registration price for a domain name. + + .. deprecated::2.0.0 + This API has been deprecated since 2.0.0. Please use `domains.list_prices` instead. + Parameters + ---------- + domain : str + Domain name to get price for. + period_years : Optional[float] + Number of years to calculate the domain price for. Must be at least 1. + registration_type : Optional[DomainRegistrationType] + Type of registration pricing to fetch. Allowed values: new, transfer, renewal, trade. + Returns + ------- + DomainPrice + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/price' + api_params = {} + if domain is None: + raise AppwriteException('Missing required parameter: "domain"') + api_params['domain'] = self._normalize_value(domain) + if period_years is not None: + api_params['periodYears'] = self._normalize_value(period_years) + if registration_type is not None: + api_params['registrationType'] = self._normalize_value(registration_type) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DomainPrice) + + def list_prices( + self, + domains: List[str], + period_years: Optional[float] = None, + registration_type: Optional[DomainRegistrationType] = None, + ) -> DomainPricesList: + """ + Check availability and get the requested registration price for one or more domain names. Availability is resolved for all domains in a single registrar lookup. Unavailable domains have a null price for new registrations, but can still be priced for renewal, transfer, or trade. Every priced domain also carries its renewal price for the same period, so a separate renewal lookup is not needed. A domain whose price could not be resolved, for example because its TLD is not supported, is returned with a null price. + + Parameters + ---------- + domains : List[str] + Domain names to check availability and price for. Maximum of 50 domains per request. + period_years : Optional[float] + Number of years to calculate the domain price for. Must be at least 1. + registration_type : Optional[DomainRegistrationType] + Type of registration pricing to fetch. Allowed values: new, transfer, renewal, trade. + Returns + ------- + DomainPricesList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/prices' + api_params = {} + if domains is None: + raise AppwriteException('Missing required parameter: "domains"') + api_params['domains'] = self._normalize_value(domains) + if period_years is not None: + api_params['periodYears'] = self._normalize_value(period_years) + if registration_type is not None: + api_params['registrationType'] = self._normalize_value(registration_type) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DomainPricesList) + + def get( + self, + domain_id: str, + ) -> Domain: + """ + Get a domain by its unique ID. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + Domain + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Domain) + + def delete( + self, + domain_id: str, + ) -> Dict[str, Any]: + """ + Delete a domain by its unique ID. This endpoint can be used to delete a domain from your project. + Once deleted, the domain will no longer be available for use and all associated resources will be removed. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + Dict[str, Any] + API response as a dictionary + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'delete', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return response + + def update_nameservers( + self, + domain_id: str, + nameservers: Optional[List[str]] = None, + ) -> Domain: + """ + Update the registrar nameservers for the given domain. When nameservers are not provided, + the domain will be updated to use Appwrite nameservers. + + Parameters + ---------- + domain_id : str + Domain unique ID. + nameservers : Optional[List[str]] + Nameservers to set for the domain. Defaults to Appwrite nameservers when omitted. + Returns + ------- + Domain + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/nameservers' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + if nameservers is not None: + api_params['nameservers'] = self._normalize_value(nameservers) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Domain) + + def verify_nameservers( + self, + domain_id: str, + ) -> Domain: + """ + Verify which NS records are used and update the domain accordingly. This will check the domain's + nameservers and update the domain's status based on whether the nameservers match the expected + Appwrite nameservers. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + Domain + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/nameservers/verification' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Domain) + + def get_preset_google_workspace( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + List Google Workspace DNS records. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/google-workspace' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def create_preset_google_workspace( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + Add Google Workspace DNS records to the domain. This will create the required MX records + for Google Workspace email hosting. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/google-workspace' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def get_preset_i_cloud( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + List iCloud DNS records. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/icloud' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def create_preset_i_cloud( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + Add iCloud DNS records to the domain. This will create the required MX and SPF records + for using iCloud email services with your domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/icloud' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def get_preset_mailgun( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + List Mailgun DNS records. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/mailgun' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def create_preset_mailgun( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + Add Mailgun DNS records to the domain. This endpoint will create the required DNS records + for Mailgun in the specified domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/mailgun' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def get_preset_outlook( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + List Outlook DNS records. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/outlook' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def create_preset_outlook( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + Add Outlook DNS records to the domain. This will create the required MX records + for setting up Outlook email hosting for your domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/outlook' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def get_preset_proton_mail( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + List ProtonMail DNS records. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/proton-mail' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def create_preset_proton_mail( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + Add ProtonMail DNS records to the domain. This will create the required MX records + for using ProtonMail with your custom domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/proton-mail' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def get_preset_zoho( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + List Zoho DNS records. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/zoho' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def create_preset_zoho( + self, + domain_id: str, + ) -> DnsRecordsList: + """ + Add Zoho Mail DNS records to the domain. This will create the required MX records + for setting up Zoho Mail on your domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/presets/zoho' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def list_records( + self, + domain_id: str, + queries: Optional[List[str]] = None, + ) -> DnsRecordsList: + """ + List DNS records for a given domain. You can use this endpoint to list all the DNS records + associated with your domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + queries : Optional[List[str]] + Array of query strings generated using the Query class provided by the SDK. You may filter on attributes such as type, name, value, etc. Maximum of 100 queries are allowed, each 4096 characters long. + Returns + ------- + DnsRecordsList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + if queries is not None: + api_params['queries'] = self._normalize_value(queries) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecordsList) + + def create_record_a( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new A record for the given domain. A records are used to point a domain name + to an IPv4 address. The record value should be a valid IPv4 address. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name (subdomain). + value : str + IPv4 address for this A record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment explaining what this record is for. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/a' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_a( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing A record for the given domain. This endpoint allows you to modify + the properties of an A record including its name (subdomain), IPv4 address, TTL, + and optional comment. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name (subdomain). + value : str + IPv4 address for this A record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment explaining what this record is for. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/a/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_aaaa( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new AAAA record for the given domain. This endpoint allows you to add a new IPv6 DNS record + to your domain. The record will be used to point a hostname to an IPv6 address. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name (subdomain). + value : str + IPv6 address for this AAAA record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment explaining what this record is for. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/aaaa' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_aaaa( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing AAAA record for the given domain. This endpoint allows you to modify + the properties of an existing AAAA record, including its name (subdomain), IPv6 address, + TTL, and optional comment. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name (subdomain). + value : str + IPv6 address for this AAAA record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/aaaa/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_alias( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new ALIAS record for the given domain. This record type can be used to point your domain + to another domain name that will serve as an alias. This is particularly useful when you want to + map your domain to a target domain that may change its IP address. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name. + value : str + Target domain for this ALIAS record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/alias' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_alias( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing ALIAS record for the specified domain. This endpoint allows you to modify + the properties of an existing ALIAS record including its name, target domain, TTL, and comment. + + The ALIAS record type is similar to a CNAME record but can be used at the zone apex (root domain). + It provides a way to map one domain name to another. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name. + value : str + Target domain for this ALIAS record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/alias/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_caa( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new CAA record for the given domain. CAA records are used to specify which + Certificate Authorities (CAs) are allowed to issue SSL/TLS certificates for your domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name. + value : str + CAA value (e.g. issuer domain). + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/caa' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_caa( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing CAA record for the given domain. A CAA (Certification Authority Authorization) + record is used to specify which certificate authorities (CAs) are authorized to issue certificates + for a domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name. + value : str + CAA value (e.g. issuer domain). + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/caa/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_cname( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new CNAME record for the given domain. + + A CNAME record maps a subdomain to another domain name, allowing you to create aliases + for your domain. For example, you can create a CNAME record to point 'blog.example.com' + to 'example.wordpress.com'. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name (subdomain). + value : str + Canonical target for this CNAME record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/cname' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_cname( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing CNAME record for the given domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name (subdomain). + value : str + Canonical target for this CNAME record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/cname/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_https( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new HTTPS record for the given domain. This record is used to configure HTTPS + settings for your domain, enabling secure communication over SSL/TLS. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name (subdomain). + value : str + Target for the HTTPS record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/https' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_https( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing HTTPS record for the given domain. This endpoint allows you to modify + the properties of an HTTPS record associated with your domain, including the name (subdomain), + target value, TTL, and optional comment. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name (subdomain). + value : str + Target for the HTTPS record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/https/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_mx( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + priority: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new MX record for the given domain. MX records are used to define the mail servers responsible + for accepting email messages for the domain. Multiple MX records can be created with different priorities. + The priority parameter determines the order in which mail servers are used, with lower values indicating + higher priority. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name (subdomain). + value : str + Mail server domain for this MX record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + priority : float + MX priority. Lower values are tried first. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/mx' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + if priority is None: + raise AppwriteException('Missing required parameter: "priority"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + api_params['priority'] = self._normalize_value(priority) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_mx( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + priority: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing MX record for the given domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name (subdomain). + value : str + Mail server domain for this MX record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + priority : float + MX priority. Lower values are tried first. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/mx/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + if priority is None: + raise AppwriteException('Missing required parameter: "priority"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + api_params['priority'] = self._normalize_value(priority) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_ns( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new NS record for the given domain. NS records specify the nameservers that are used + to resolve the domain name to IP addresses. Each domain can have multiple NS records. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name (subdomain). + value : str + Nameserver target for this NS record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/ns' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_ns( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing NS record for the given domain. This endpoint allows you to modify + the properties of an NS (nameserver) record associated with your domain. You can update + the record name (subdomain), target nameserver value, TTL, and add or modify comments + for better record management. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name (subdomain). + value : str + Nameserver target for this NS record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/ns/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_srv( + self, + domain_id: str, + name: str, + value: str, + ttl: float, + priority: float, + weight: float, + port: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new SRV record for the given domain. SRV records are used to define the location + of servers for specific services. For example, they can be used to specify which server + handles a specific service like SIP or XMPP for the domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name (service name). + value : str + Target hostname for this SRV record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + priority : float + Record priority. Lower values are tried first. + weight : float + Record weight, used to share load between targets of equal priority. + port : float + Port number for the service. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/srv' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + if priority is None: + raise AppwriteException('Missing required parameter: "priority"') + if weight is None: + raise AppwriteException('Missing required parameter: "weight"') + if port is None: + raise AppwriteException('Missing required parameter: "port"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + api_params['priority'] = self._normalize_value(priority) + api_params['weight'] = self._normalize_value(weight) + api_params['port'] = self._normalize_value(port) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_srv( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + priority: float, + weight: float, + port: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing SRV record for the given domain. + + Required parameters: + - domainId: Domain unique ID + - recordId: DNS record unique ID + - name: Record name (service name) + - value: Target hostname for this SRV record + - ttl: Time to live, in seconds + - priority: Record priority + - weight: Record weight + - port: Port number for the service + + Optional parameters: + - comment: A comment for this record + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name (service name). + value : str + Target hostname for this SRV record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + priority : float + Record priority. Lower values are tried first. + weight : float + Record weight, used to share load between targets of equal priority. + port : float + Port number for the service. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/srv/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + if priority is None: + raise AppwriteException('Missing required parameter: "priority"') + if weight is None: + raise AppwriteException('Missing required parameter: "weight"') + if port is None: + raise AppwriteException('Missing required parameter: "port"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + api_params['priority'] = self._normalize_value(priority) + api_params['weight'] = self._normalize_value(weight) + api_params['port'] = self._normalize_value(port) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def create_record_txt( + self, + domain_id: str, + name: str, + ttl: float, + value: Optional[str] = None, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Create a new TXT record for the given domain. TXT records can be used + to provide additional information about your domain, such as domain + verification records, SPF records, or DKIM records. + + Parameters + ---------- + domain_id : str + Domain unique ID. + name : str + Record name (subdomain) for the TXT record. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + value : Optional[str] + TXT record value. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/txt' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['name'] = self._normalize_value(name) + if value is not None: + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def update_record_txt( + self, + domain_id: str, + record_id: str, + name: str, + value: str, + ttl: float, + comment: Optional[str] = None, + ) -> DnsRecord: + """ + Update an existing TXT record for the given domain. + + Update the TXT record details for a specific domain by providing the domain ID, + record ID, and the new record configuration including name, value, TTL, and an optional comment. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + name : str + Record name (subdomain) for the TXT record. + value : str + TXT record value. + ttl : float + Time to live, in seconds. Must be between 1 and 2147483647. + comment : Optional[str] + A comment for this record. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/txt/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if value is None: + raise AppwriteException('Missing required parameter: "value"') + if ttl is None: + raise AppwriteException('Missing required parameter: "ttl"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + api_params['name'] = self._normalize_value(name) + api_params['value'] = self._normalize_value(value) + api_params['ttl'] = self._normalize_value(ttl) + if comment is not None: + api_params['comment'] = self._normalize_value(comment) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def get_record( + self, + domain_id: str, + record_id: str, + ) -> DnsRecord: + """ + Get a single DNS record for a given domain by record ID. + + This endpoint allows you to retrieve a specific DNS record associated with a domain + using its unique identifier. The record contains information about the DNS configuration + such as type, value, and TTL settings. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + Returns + ------- + DnsRecord + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DnsRecord) + + def delete_record( + self, + domain_id: str, + record_id: str, + ) -> Dict[str, Any]: + """ + Delete a DNS record for the given domain. This endpoint allows you to delete an existing DNS record + from a specific domain. + + Parameters + ---------- + domain_id : str + Domain unique ID. + record_id : str + DNS record unique ID. + Returns + ------- + Dict[str, Any] + API response as a dictionary + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/records/{recordId}' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if record_id is None or record_id == '': + raise AppwriteException('Missing required parameter: "record_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_path = api_path.replace('{recordId}', str(self._normalize_value(record_id))) + + response = self.client.call( + 'delete', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return response + + def update_team( + self, + domain_id: str, + team_id: str, + ) -> Domain: + """ + Update the team ID for a specific domain. The caller must administer the current + team and be an owner of the destination team. + + Updating the team ID will transfer ownership and access control of the domain + and all its DNS records to the new team. + + Parameters + ---------- + domain_id : str + Domain unique ID. + team_id : str + New team unique ID. + Returns + ------- + Domain + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/team' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if team_id is None: + raise AppwriteException('Missing required parameter: "team_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['teamId'] = self._normalize_value(team_id) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Domain) + + def get_transfer_status( + self, + domain_id: str, + ) -> DomainTransferStatus: + """ + Retrieve the current transfer status for a domain. Returns the status, an optional reason, and a timestamp of the last status change. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + DomainTransferStatus + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/transfers/status' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=DomainTransferStatus) + + def get_zone( + self, + domain_id: str, + ) -> str: + """ + Retrieve the DNS zone file for the given domain. This endpoint will return the DNS + zone file in a standardized format that can be used to configure DNS servers. + + Parameters + ---------- + domain_id : str + Domain unique ID. + Returns + ------- + str + Response body as text + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/zone' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'text/plain', + }, + api_params, + response_type='text', + ) + + return response + + def update_zone( + self, + domain_id: str, + content: str, + ) -> Domain: + """ + Update the DNS zone for the given domain using the provided zone file content. + All parsed records are imported and then the main domain document is returned. + + Parameters + ---------- + domain_id : str + Domain unique ID. + content : str + DNS zone file content as a string. + Returns + ------- + Domain + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/domains/{domainId}/zone' + api_params = {} + if domain_id is None or domain_id == '': + raise AppwriteException('Missing required parameter: "domain_id"') + if content is None: + raise AppwriteException('Missing required parameter: "content"') + api_path = api_path.replace('{domainId}', str(self._normalize_value(domain_id))) + api_params['content'] = self._normalize_value(content) + + response = self.client.call( + 'put', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Domain) diff --git a/appwrite/services/functions.py b/appwrite/services/functions.py index b42734fa..308c4c26 100644 --- a/appwrite/services/functions.py +++ b/appwrite/services/functions.py @@ -231,9 +231,15 @@ def create( def list_runtimes( self, + total: Optional[bool] = None, ) -> RuntimeList: """ Get a list of all runtimes that are currently active on your instance. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- RuntimeList @@ -247,6 +253,8 @@ def list_runtimes( api_path = '/functions/runtimes' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -263,6 +271,7 @@ def list_runtimes( def list_specifications( self, type: Optional[str] = None, + total: Optional[bool] = None, ) -> SpecificationList: """ List allowed function specifications for this instance. @@ -271,6 +280,8 @@ def list_specifications( ---------- type : Optional[str] Specification type to list. Can be one of: runtimes, builds. Defaults to runtimes. + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- SpecificationList @@ -286,6 +297,8 @@ def list_specifications( api_params = {} if type is not None: api_params['type'] = self._normalize_value(type) + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -323,7 +336,7 @@ def get( api_path = '/functions/{functionId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) @@ -429,7 +442,7 @@ def update( api_path = '/functions/{functionId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -515,7 +528,7 @@ def delete( api_path = '/functions/{functionId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) @@ -525,6 +538,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -558,7 +572,7 @@ def update_function_deployment( api_path = '/functions/{functionId}/deployment' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') if deployment_id is None: raise AppwriteException('Missing required parameter: "deployment_id"') @@ -611,7 +625,7 @@ def list_deployments( api_path = '/functions/{functionId}/deployments' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) if queries is not None: @@ -677,7 +691,7 @@ def create_deployment( api_path = '/functions/{functionId}/deployments' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') if code is None: raise AppwriteException('Missing required parameter: "code"') @@ -706,6 +720,7 @@ def create_deployment( param_name, on_progress, upload_id, + method='post', ) return self._parse_response(response, model=Deployment) @@ -740,7 +755,7 @@ def create_duplicate_deployment( api_path = '/functions/{functionId}/deployments/duplicate' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') if deployment_id is None: raise AppwriteException('Missing required parameter: "deployment_id"') @@ -806,7 +821,7 @@ def create_template_deployment( api_path = '/functions/{functionId}/deployments/template' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') if repository is None: raise AppwriteException('Missing required parameter: "repository"') @@ -875,7 +890,7 @@ def create_vcs_deployment( api_path = '/functions/{functionId}/deployments/vcs' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') if type is None: raise AppwriteException('Missing required parameter: "type"') @@ -927,9 +942,9 @@ def get_deployment( api_path = '/functions/{functionId}/deployments/{deploymentId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if deployment_id is None: + if deployment_id is None or deployment_id == '': raise AppwriteException('Missing required parameter: "deployment_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{deploymentId}', str(self._normalize_value(deployment_id))) @@ -973,9 +988,9 @@ def delete_deployment( api_path = '/functions/{functionId}/deployments/{deploymentId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if deployment_id is None: + if deployment_id is None or deployment_id == '': raise AppwriteException('Missing required parameter: "deployment_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{deploymentId}', str(self._normalize_value(deployment_id))) @@ -986,6 +1001,7 @@ def delete_deployment( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1025,9 +1041,9 @@ def get_deployment_download( api_path = '/functions/{functionId}/deployments/{deploymentId}/download' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if deployment_id is None: + if deployment_id is None or deployment_id == '': raise AppwriteException('Missing required parameter: "deployment_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{deploymentId}', str(self._normalize_value(deployment_id))) @@ -1075,9 +1091,9 @@ def update_deployment_status( api_path = '/functions/{functionId}/deployments/{deploymentId}/status' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if deployment_id is None: + if deployment_id is None or deployment_id == '': raise AppwriteException('Missing required parameter: "deployment_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{deploymentId}', str(self._normalize_value(deployment_id))) @@ -1125,7 +1141,7 @@ def list_executions( api_path = '/functions/{functionId}/executions' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) if queries is not None: @@ -1187,7 +1203,7 @@ def create_execution( api_path = '/functions/{functionId}/executions' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) if body is not None: @@ -1243,9 +1259,9 @@ def get_execution( api_path = '/functions/{functionId}/executions/{executionId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if execution_id is None: + if execution_id is None or execution_id == '': raise AppwriteException('Missing required parameter: "execution_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{executionId}', str(self._normalize_value(execution_id))) @@ -1289,9 +1305,9 @@ def delete_execution( api_path = '/functions/{functionId}/executions/{executionId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if execution_id is None: + if execution_id is None or execution_id == '': raise AppwriteException('Missing required parameter: "execution_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{executionId}', str(self._normalize_value(execution_id))) @@ -1302,6 +1318,7 @@ def delete_execution( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1338,7 +1355,7 @@ def list_variables( api_path = '/functions/{functionId}/variables' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) if queries is not None: @@ -1394,7 +1411,7 @@ def create_variable( api_path = '/functions/{functionId}/variables' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') if variable_id is None: raise AppwriteException('Missing required parameter: "variable_id"') @@ -1449,9 +1466,9 @@ def get_variable( api_path = '/functions/{functionId}/variables/{variableId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) @@ -1504,9 +1521,9 @@ def update_variable( api_path = '/functions/{functionId}/variables/{variableId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) @@ -1557,9 +1574,9 @@ def delete_variable( api_path = '/functions/{functionId}/variables/{variableId}' api_params = {} - if function_id is None: + if function_id is None or function_id == '': raise AppwriteException('Missing required parameter: "function_id"') - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{functionId}', str(self._normalize_value(function_id))) api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) @@ -1570,6 +1587,7 @@ def delete_variable( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) diff --git a/appwrite/services/locale.py b/appwrite/services/locale.py index 4a3c96f0..e0e69e70 100644 --- a/appwrite/services/locale.py +++ b/appwrite/services/locale.py @@ -52,9 +52,15 @@ def get( def list_codes( self, + total: Optional[bool] = None, ) -> LocaleCodeList: """ List of all locale codes in [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- LocaleCodeList @@ -68,6 +74,8 @@ def list_codes( api_path = '/locale/codes' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -83,9 +91,15 @@ def list_codes( def list_continents( self, + total: Optional[bool] = None, ) -> ContinentList: """ List of all continents. You can use the locale header to get the data in a supported language. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- ContinentList @@ -99,6 +113,8 @@ def list_continents( api_path = '/locale/continents' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -114,9 +130,15 @@ def list_continents( def list_countries( self, + total: Optional[bool] = None, ) -> CountryList: """ List of all countries. You can use the locale header to get the data in a supported language. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- CountryList @@ -130,6 +152,8 @@ def list_countries( api_path = '/locale/countries' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -145,9 +169,15 @@ def list_countries( def list_countries_eu( self, + total: Optional[bool] = None, ) -> CountryList: """ List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- CountryList @@ -161,6 +191,8 @@ def list_countries_eu( api_path = '/locale/countries/eu' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -176,9 +208,15 @@ def list_countries_eu( def list_countries_phones( self, + total: Optional[bool] = None, ) -> PhoneList: """ List of all countries phone codes. You can use the locale header to get the data in a supported language. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- PhoneList @@ -192,6 +230,8 @@ def list_countries_phones( api_path = '/locale/countries/phones' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -207,9 +247,15 @@ def list_countries_phones( def list_currencies( self, + total: Optional[bool] = None, ) -> CurrencyList: """ List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- CurrencyList @@ -223,6 +269,8 @@ def list_currencies( api_path = '/locale/currencies' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -238,9 +286,15 @@ def list_currencies( def list_languages( self, + total: Optional[bool] = None, ) -> LanguageList: """ List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- LanguageList @@ -254,6 +308,8 @@ def list_languages( api_path = '/locale/languages' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', diff --git a/appwrite/services/messaging.py b/appwrite/services/messaging.py index 29a37285..ca89d1b8 100644 --- a/appwrite/services/messaging.py +++ b/appwrite/services/messaging.py @@ -33,7 +33,7 @@ def list_messages( Parameters ---------- queries : Optional[List[str]] - 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: scheduledAt, deliveredAt, deliveredTotal, status, description, providerType + 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: scheduledAt, deliveredAt, deliveredTotal, status, description, providerType, users, targets search : Optional[str] Search term to filter your list results. Max length: 256 chars. total : Optional[bool] @@ -81,6 +81,8 @@ def create_email( cc: Optional[List[str]] = None, bcc: Optional[List[str]] = None, attachments: Optional[List[str]] = None, + reply_to_email: Optional[str] = None, + reply_to_name: Optional[str] = None, draft: Optional[bool] = None, html: Optional[bool] = None, scheduled_at: Optional[str] = None, @@ -108,6 +110,10 @@ def create_email( Array of target IDs to be added as BCC. attachments : Optional[List[str]] Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as :. + reply_to_email : Optional[str] + Email address to reply to. If not set, defaults to the sender email address. + reply_to_name : Optional[str] + Name of the reply to recipient. If not set, defaults to the sender name. draft : Optional[bool] Is message a draft html : Optional[bool] @@ -148,6 +154,10 @@ def create_email( api_params['bcc'] = self._normalize_value(bcc) if attachments is not None: api_params['attachments'] = self._normalize_value(attachments) + if reply_to_email is not None: + api_params['replyToEmail'] = self._normalize_value(reply_to_email) + if reply_to_name is not None: + api_params['replyToName'] = self._normalize_value(reply_to_name) if draft is not None: api_params['draft'] = self._normalize_value(draft) if html is not None: @@ -171,17 +181,19 @@ def create_email( def update_email( self, message_id: str, + subject: Optional[str] = None, + content: Optional[str] = None, topics: Optional[List[str]] = None, users: Optional[List[str]] = None, targets: Optional[List[str]] = None, - subject: Optional[str] = None, - content: Optional[str] = None, - draft: Optional[bool] = None, - html: Optional[bool] = None, cc: Optional[List[str]] = None, bcc: Optional[List[str]] = None, - scheduled_at: Optional[str] = None, attachments: Optional[List[str]] = None, + reply_to_email: Optional[str] = None, + reply_to_name: Optional[str] = None, + draft: Optional[bool] = None, + html: Optional[bool] = None, + scheduled_at: Optional[str] = None, ) -> Message: """ Update an email message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated. @@ -190,28 +202,32 @@ def update_email( ---------- message_id : str Message ID. + subject : Optional[str] + Email Subject. + content : Optional[str] + Email Content. topics : Optional[List[str]] List of Topic IDs. users : Optional[List[str]] List of User IDs. targets : Optional[List[str]] List of Targets IDs. - subject : Optional[str] - Email Subject. - content : Optional[str] - Email Content. - draft : Optional[bool] - Is message a draft - html : Optional[bool] - Is content of type HTML cc : Optional[List[str]] Array of target IDs to be added as CC. bcc : Optional[List[str]] Array of target IDs to be added as BCC. - scheduled_at : Optional[str] - Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future. attachments : Optional[List[str]] Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as :. + reply_to_email : Optional[str] + Email address to reply to. Pass an empty string to restore the provider or sender default. + reply_to_name : Optional[str] + Name of the reply to recipient. Pass an empty string to restore the provider or sender default. + draft : Optional[bool] + Is message a draft + html : Optional[bool] + Is content of type HTML + scheduled_at : Optional[str] + Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future. Returns ------- Message @@ -225,31 +241,35 @@ def update_email( api_path = '/messaging/messages/email/{messageId}' api_params = {} - if message_id is None: + if message_id is None or message_id == '': raise AppwriteException('Missing required parameter: "message_id"') api_path = api_path.replace('{messageId}', str(self._normalize_value(message_id))) + if subject is not None: + api_params['subject'] = self._normalize_value(subject) + if content is not None: + api_params['content'] = self._normalize_value(content) if topics is not None: api_params['topics'] = self._normalize_value(topics) if users is not None: api_params['users'] = self._normalize_value(users) if targets is not None: api_params['targets'] = self._normalize_value(targets) - if subject is not None: - api_params['subject'] = self._normalize_value(subject) - if content is not None: - api_params['content'] = self._normalize_value(content) - if draft is not None: - api_params['draft'] = self._normalize_value(draft) - if html is not None: - api_params['html'] = self._normalize_value(html) if cc is not None: api_params['cc'] = self._normalize_value(cc) if bcc is not None: api_params['bcc'] = self._normalize_value(bcc) - if scheduled_at is not None: - api_params['scheduledAt'] = self._normalize_value(scheduled_at) if attachments is not None: api_params['attachments'] = self._normalize_value(attachments) + if reply_to_email is not None: + api_params['replyToEmail'] = self._normalize_value(reply_to_email) + if reply_to_name is not None: + api_params['replyToName'] = self._normalize_value(reply_to_name) + if draft is not None: + api_params['draft'] = self._normalize_value(draft) + if html is not None: + api_params['html'] = self._normalize_value(html) + if scheduled_at is not None: + api_params['scheduledAt'] = self._normalize_value(scheduled_at) response = self.client.call( 'patch', @@ -285,6 +305,7 @@ def create_push( content_available: Optional[bool] = None, critical: Optional[bool] = None, priority: Optional[MessagePriority] = None, + channel_id: Optional[str] = None, ) -> Message: """ Create a new push notification. @@ -329,6 +350,8 @@ def create_push( If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform. priority : Optional[MessagePriority] Set the notification priority. "normal" will consider device state and may not deliver notifications immediately. "high" will always attempt to immediately deliver the notification. + channel_id : Optional[str] + ID of the notification channel to deliver the notification on. The app must have already created a channel with this ID, otherwise the channel from the app manifest is used. Available only for Android Platform. Returns ------- Message @@ -381,6 +404,8 @@ def create_push( api_params['critical'] = self._normalize_value(critical) if priority is not None: api_params['priority'] = self._normalize_value(priority) + if channel_id is not None: + api_params['channelId'] = self._normalize_value(channel_id) response = self.client.call( 'post', @@ -398,11 +423,11 @@ def create_push( def update_push( self, message_id: str, + title: Optional[str] = None, + body: Optional[str] = None, topics: Optional[List[str]] = None, users: Optional[List[str]] = None, targets: Optional[List[str]] = None, - title: Optional[str] = None, - body: Optional[str] = None, data: Optional[Dict[str, Any]] = None, action: Optional[str] = None, image: Optional[str] = None, @@ -416,6 +441,7 @@ def update_push( content_available: Optional[bool] = None, critical: Optional[bool] = None, priority: Optional[MessagePriority] = None, + channel_id: Optional[str] = None, ) -> Message: """ Update a push notification by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated. @@ -424,16 +450,16 @@ def update_push( ---------- message_id : str Message ID. + title : Optional[str] + Title for push notification. + body : Optional[str] + Body for push notification. topics : Optional[List[str]] List of Topic IDs. users : Optional[List[str]] List of User IDs. targets : Optional[List[str]] List of Targets IDs. - title : Optional[str] - Title for push notification. - body : Optional[str] - Body for push notification. data : Optional[Dict[str, Any]] Additional Data for push notification. action : Optional[str] @@ -460,6 +486,8 @@ def update_push( If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform. priority : Optional[MessagePriority] Set the notification priority. "normal" will consider device battery state and may send notifications later. "high" will always attempt to immediately deliver the notification. + channel_id : Optional[str] + ID of the notification channel to deliver the notification on. The app must have already created a channel with this ID, otherwise the channel from the app manifest is used. Pass an empty string to clear it. Available only for Android platforms. Returns ------- Message @@ -473,19 +501,19 @@ def update_push( api_path = '/messaging/messages/push/{messageId}' api_params = {} - if message_id is None: + if message_id is None or message_id == '': raise AppwriteException('Missing required parameter: "message_id"') api_path = api_path.replace('{messageId}', str(self._normalize_value(message_id))) + if title is not None: + api_params['title'] = self._normalize_value(title) + if body is not None: + api_params['body'] = self._normalize_value(body) if topics is not None: api_params['topics'] = self._normalize_value(topics) if users is not None: api_params['users'] = self._normalize_value(users) if targets is not None: api_params['targets'] = self._normalize_value(targets) - if title is not None: - api_params['title'] = self._normalize_value(title) - if body is not None: - api_params['body'] = self._normalize_value(body) if data is not None: api_params['data'] = self._normalize_value(data) if action is not None: @@ -512,6 +540,8 @@ def update_push( api_params['critical'] = self._normalize_value(critical) if priority is not None: api_params['priority'] = self._normalize_value(priority) + if channel_id is not None: + api_params['channelId'] = self._normalize_value(channel_id) response = self.client.call( 'patch', @@ -601,10 +631,10 @@ def create_sms( def update_sms( self, message_id: str, + content: Optional[str] = None, topics: Optional[List[str]] = None, users: Optional[List[str]] = None, targets: Optional[List[str]] = None, - content: Optional[str] = None, draft: Optional[bool] = None, scheduled_at: Optional[str] = None, ) -> Message: @@ -615,14 +645,14 @@ def update_sms( ---------- message_id : str Message ID. + content : Optional[str] + Email Content. topics : Optional[List[str]] List of Topic IDs. users : Optional[List[str]] List of User IDs. targets : Optional[List[str]] List of Targets IDs. - content : Optional[str] - Email Content. draft : Optional[bool] Is message a draft scheduled_at : Optional[str] @@ -640,17 +670,17 @@ def update_sms( api_path = '/messaging/messages/sms/{messageId}' api_params = {} - if message_id is None: + if message_id is None or message_id == '': raise AppwriteException('Missing required parameter: "message_id"') api_path = api_path.replace('{messageId}', str(self._normalize_value(message_id))) + if content is not None: + api_params['content'] = self._normalize_value(content) if topics is not None: api_params['topics'] = self._normalize_value(topics) if users is not None: api_params['users'] = self._normalize_value(users) if targets is not None: api_params['targets'] = self._normalize_value(targets) - if content is not None: - api_params['content'] = self._normalize_value(content) if draft is not None: api_params['draft'] = self._normalize_value(draft) if scheduled_at is not None: @@ -693,7 +723,7 @@ def get_message( api_path = '/messaging/messages/{messageId}' api_params = {} - if message_id is None: + if message_id is None or message_id == '': raise AppwriteException('Missing required parameter: "message_id"') api_path = api_path.replace('{messageId}', str(self._normalize_value(message_id))) @@ -733,7 +763,7 @@ def delete( api_path = '/messaging/messages/{messageId}' api_params = {} - if message_id is None: + if message_id is None or message_id == '': raise AppwriteException('Missing required parameter: "message_id"') api_path = api_path.replace('{messageId}', str(self._normalize_value(message_id))) @@ -743,6 +773,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -779,7 +810,7 @@ def list_targets( api_path = '/messaging/messages/{messageId}/targets' api_params = {} - if message_id is None: + if message_id is None or message_id == '': raise AppwriteException('Missing required parameter: "message_id"') api_path = api_path.replace('{messageId}', str(self._normalize_value(message_id))) if queries is not None: @@ -970,7 +1001,7 @@ def update_apns_provider( api_path = '/messaging/providers/apns/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -1001,6 +1032,129 @@ def update_apns_provider( return self._parse_response(response, model=Provider) + def create_appwrite_provider( + self, + provider_id: str, + name: str, + enabled: Optional[bool] = None, + qos: Optional[float] = None, + expiry: Optional[float] = None, + ) -> Provider: + """ + Create a new Appwrite push provider. + + Parameters + ---------- + provider_id : str + Provider 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 : str + Provider name. + enabled : Optional[bool] + Set as enabled. + qos : Optional[float] + Default QoS for topics on this provider (0 or 1). Null lets the subscriber choose. + expiry : Optional[float] + Default message retention in seconds for offline delivery. Max 7 days (604800). + Returns + ------- + Provider + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/messaging/providers/appwrite' + api_params = {} + if provider_id is None: + raise AppwriteException('Missing required parameter: "provider_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + api_params['providerId'] = self._normalize_value(provider_id) + api_params['name'] = self._normalize_value(name) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if qos is not None: + api_params['qos'] = self._normalize_value(qos) + if expiry is not None: + api_params['expiry'] = self._normalize_value(expiry) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Provider) + + def update_appwrite_provider( + self, + provider_id: str, + name: Optional[str] = None, + enabled: Optional[bool] = None, + qos: Optional[float] = None, + expiry: Optional[float] = None, + ) -> Provider: + """ + Update an Appwrite push provider by its unique ID. + + Parameters + ---------- + provider_id : str + Provider ID. + name : Optional[str] + Provider name. + enabled : Optional[bool] + Set as enabled. + qos : Optional[float] + Default QoS for topics on this provider (0 or 1). Null lets the subscriber choose. + expiry : Optional[float] + Default message retention in seconds for offline delivery. Max 7 days (604800). + Returns + ------- + Provider + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/messaging/providers/appwrite/{providerId}' + api_params = {} + if provider_id is None or provider_id == '': + raise AppwriteException('Missing required parameter: "provider_id"') + api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) + if name is not None: + api_params['name'] = self._normalize_value(name) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if qos is not None: + api_params['qos'] = self._normalize_value(qos) + if expiry is not None: + api_params['expiry'] = self._normalize_value(expiry) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Provider) + def create_fcm_provider( self, provider_id: str, @@ -1091,7 +1245,7 @@ def update_fcm_provider( api_path = '/messaging/providers/fcm/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -1252,7 +1406,7 @@ def update_mailgun_provider( api_path = '/messaging/providers/mailgun/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -1393,7 +1547,7 @@ def update_msg91_provider( api_path = '/messaging/providers/msg91/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -1542,7 +1696,7 @@ def update_resend_provider( api_path = '/messaging/providers/resend/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -1695,7 +1849,7 @@ def update_sendgrid_provider( api_path = '/messaging/providers/sendgrid/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -1864,7 +2018,7 @@ def update_ses_provider( api_path = '/messaging/providers/ses/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -2070,7 +2224,7 @@ def update_smtp_provider( api_path = '/messaging/providers/smtp/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -2219,7 +2373,7 @@ def update_telesign_provider( api_path = '/messaging/providers/telesign/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -2352,7 +2506,7 @@ def update_textmagic_provider( api_path = '/messaging/providers/textmagic/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -2398,7 +2552,7 @@ def create_twilio_provider( name : str Provider name. xfrom : Optional[str] - Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. + Sender phone number or alphanumeric sender ID. Format phone numbers with a leading '+' and a country code, e.g., +16175551212. account_sid : Optional[str] Twilio account secret ID. auth_token : Optional[str] @@ -2471,7 +2625,7 @@ def update_twilio_provider( auth_token : Optional[str] Twilio authentication token. xfrom : Optional[str] - Sender number. + Sender phone number or alphanumeric sender ID. Format phone numbers with a leading '+' and a country code, e.g., +16175551212. Returns ------- Provider @@ -2485,7 +2639,7 @@ def update_twilio_provider( api_path = '/messaging/providers/twilio/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -2618,7 +2772,7 @@ def update_vonage_provider( api_path = '/messaging/providers/vonage/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) if name is not None: @@ -2669,7 +2823,7 @@ def get_provider( api_path = '/messaging/providers/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) @@ -2709,7 +2863,7 @@ def delete_provider( api_path = '/messaging/providers/{providerId}' api_params = {} - if provider_id is None: + if provider_id is None or provider_id == '': raise AppwriteException('Missing required parameter: "provider_id"') api_path = api_path.replace('{providerId}', str(self._normalize_value(provider_id))) @@ -2719,6 +2873,7 @@ def delete_provider( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -2779,6 +2934,8 @@ def create_topic( topic_id: str, name: str, subscribe: Optional[List[str]] = None, + qos: Optional[float] = None, + expiry: Optional[float] = None, ) -> Topic: """ Create a new topic. @@ -2791,6 +2948,10 @@ def create_topic( Topic Name. subscribe : Optional[List[str]] An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long. + qos : Optional[float] + MQTT delivery quality of service for this topic. 0 is fire-and-forget (delivered only to clients connected at publish time). 1 persists each message and replays it when a client reconnects without having acknowledged it. Null lets the subscriber choose. + expiry : Optional[float] + Message retention in seconds for offline delivery. Max 7 days (604800). Returns ------- Topic @@ -2812,6 +2973,10 @@ def create_topic( api_params['name'] = self._normalize_value(name) if subscribe is not None: api_params['subscribe'] = self._normalize_value(subscribe) + if qos is not None: + api_params['qos'] = self._normalize_value(qos) + if expiry is not None: + api_params['expiry'] = self._normalize_value(expiry) response = self.client.call( 'post', @@ -2850,7 +3015,7 @@ def get_topic( api_path = '/messaging/topics/{topicId}' api_params = {} - if topic_id is None: + if topic_id is None or topic_id == '': raise AppwriteException('Missing required parameter: "topic_id"') api_path = api_path.replace('{topicId}', str(self._normalize_value(topic_id))) @@ -2871,6 +3036,8 @@ def update_topic( topic_id: str, name: Optional[str] = None, subscribe: Optional[List[str]] = None, + qos: Optional[float] = None, + expiry: Optional[float] = None, ) -> Topic: """ Update a topic by its unique ID. @@ -2883,6 +3050,10 @@ def update_topic( Topic Name. subscribe : Optional[List[str]] An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long. + qos : Optional[float] + MQTT delivery quality of service for this topic. 0 is fire-and-forget (delivered only to clients connected at publish time). 1 persists each message and replays it when a client reconnects without having acknowledged it. Null lets the subscriber choose. + expiry : Optional[float] + Message retention in seconds for offline delivery. Max 7 days (604800). Returns ------- Topic @@ -2896,13 +3067,17 @@ def update_topic( api_path = '/messaging/topics/{topicId}' api_params = {} - if topic_id is None: + if topic_id is None or topic_id == '': raise AppwriteException('Missing required parameter: "topic_id"') api_path = api_path.replace('{topicId}', str(self._normalize_value(topic_id))) if name is not None: api_params['name'] = self._normalize_value(name) if subscribe is not None: api_params['subscribe'] = self._normalize_value(subscribe) + if qos is not None: + api_params['qos'] = self._normalize_value(qos) + if expiry is not None: + api_params['expiry'] = self._normalize_value(expiry) response = self.client.call( 'patch', @@ -2941,7 +3116,7 @@ def delete_topic( api_path = '/messaging/topics/{topicId}' api_params = {} - if topic_id is None: + if topic_id is None or topic_id == '': raise AppwriteException('Missing required parameter: "topic_id"') api_path = api_path.replace('{topicId}', str(self._normalize_value(topic_id))) @@ -2951,6 +3126,7 @@ def delete_topic( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -2990,7 +3166,7 @@ def list_subscribers( api_path = '/messaging/topics/{topicId}/subscribers' api_params = {} - if topic_id is None: + if topic_id is None or topic_id == '': raise AppwriteException('Missing required parameter: "topic_id"') api_path = api_path.replace('{topicId}', str(self._normalize_value(topic_id))) if queries is not None: @@ -3042,7 +3218,7 @@ def create_subscriber( api_path = '/messaging/topics/{topicId}/subscribers' api_params = {} - if topic_id is None: + if topic_id is None or topic_id == '': raise AppwriteException('Missing required parameter: "topic_id"') if subscriber_id is None: raise AppwriteException('Missing required parameter: "subscriber_id"') @@ -3092,9 +3268,9 @@ def get_subscriber( api_path = '/messaging/topics/{topicId}/subscribers/{subscriberId}' api_params = {} - if topic_id is None: + if topic_id is None or topic_id == '': raise AppwriteException('Missing required parameter: "topic_id"') - if subscriber_id is None: + if subscriber_id is None or subscriber_id == '': raise AppwriteException('Missing required parameter: "subscriber_id"') api_path = api_path.replace('{topicId}', str(self._normalize_value(topic_id))) api_path = api_path.replace('{subscriberId}', str(self._normalize_value(subscriber_id))) @@ -3138,9 +3314,9 @@ def delete_subscriber( api_path = '/messaging/topics/{topicId}/subscribers/{subscriberId}' api_params = {} - if topic_id is None: + if topic_id is None or topic_id == '': raise AppwriteException('Missing required parameter: "topic_id"') - if subscriber_id is None: + if subscriber_id is None or subscriber_id == '': raise AppwriteException('Missing required parameter: "subscriber_id"') api_path = api_path.replace('{topicId}', str(self._normalize_value(topic_id))) api_path = api_path.replace('{subscriberId}', str(self._normalize_value(subscriber_id))) @@ -3151,6 +3327,7 @@ def delete_subscriber( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) diff --git a/appwrite/services/mongo.py b/appwrite/services/mongo.py index 4fb19898..0f632c16 100644 --- a/appwrite/services/mongo.py +++ b/appwrite/services/mongo.py @@ -114,7 +114,7 @@ def create( storage_autoscaling_threshold_percent : Optional[float] Storage usage percentage (50-95) that triggers automatic expansion. storage_autoscaling_max_gb : Optional[float] - Maximum storage size in GB for autoscaling. 0 means no limit. + Maximum storage size in GB for autoscaling. Defaults to 3 times the specification's storage. 0 means no limit. Returns ------- DedicatedDatabase @@ -178,7 +178,7 @@ def list_specifications( self, ) -> DedicatedDatabaseSpecificationList: """ - 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. + List the dedicated database specifications available on the current plan. Each specification reports its resource limits, its own prices and overage rates, and whether it is enabled for the organization. Returns ------- DedicatedDatabaseSpecificationList @@ -229,7 +229,7 @@ def get( api_path = '/mongo/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -329,7 +329,7 @@ def update( api_path = '/mongo/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if name is not None: @@ -412,7 +412,7 @@ def delete( api_path = '/mongo/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -456,7 +456,7 @@ def list_backups( api_path = '/mongo/{databaseId}/backups' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -501,7 +501,7 @@ def create_backup( api_path = '/mongo/{databaseId}/backups' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if type is not None: @@ -547,7 +547,7 @@ def list_backup_policies( api_path = '/mongo/{databaseId}/backups/policies' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -607,7 +607,7 @@ def create_backup_policy( api_path = '/mongo/{databaseId}/backups/policies' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if policy_id is None: raise AppwriteException('Missing required parameter: "policy_id"') @@ -667,9 +667,9 @@ def get_backup_policy( api_path = '/mongo/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -725,9 +725,9 @@ def update_backup_policy( api_path = '/mongo/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -780,9 +780,9 @@ def delete_backup_policy( api_path = '/mongo/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -845,7 +845,7 @@ def update_backup_storage( api_path = '/mongo/{databaseId}/backups/storage' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if provider is None: raise AppwriteException('Missing required parameter: "provider"') @@ -907,9 +907,9 @@ def get_backup( api_path = '/mongo/{databaseId}/backups/{backupId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if backup_id is None: + if backup_id is None or backup_id == '': raise AppwriteException('Missing required parameter: "backup_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{backupId}', str(self._normalize_value(backup_id))) @@ -953,9 +953,9 @@ def delete_backup( api_path = '/mongo/{databaseId}/backups/{backupId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if backup_id is None: + if backup_id is None or backup_id == '': raise AppwriteException('Missing required parameter: "backup_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{backupId}', str(self._normalize_value(backup_id))) @@ -997,7 +997,7 @@ def list_branches( api_path = '/mongo/{databaseId}/branches' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1043,7 +1043,7 @@ def create_branch( api_path = '/mongo/{databaseId}/branches' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if branch_id is not None: @@ -1091,9 +1091,9 @@ def delete_branch( api_path = '/mongo/{databaseId}/branches/{branchId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if branch_id is None: + if branch_id is None or branch_id == '': raise AppwriteException('Missing required parameter: "branch_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{branchId}', str(self._normalize_value(branch_id))) @@ -1135,7 +1135,7 @@ def update_credentials( api_path = '/mongo/{databaseId}/credentials' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1179,7 +1179,7 @@ def create_failover( api_path = '/mongo/{databaseId}/failovers' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if target_replica_id is not None: @@ -1228,7 +1228,7 @@ def update_maintenance( api_path = '/mongo/{databaseId}/maintenance' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if day is None: raise AppwriteException('Missing required parameter: "day"') @@ -1281,7 +1281,7 @@ def create_migration( api_path = '/mongo/{databaseId}/migrations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if target_type is None: raise AppwriteException('Missing required parameter: "target_type"') @@ -1336,7 +1336,7 @@ def list_operations( api_path = '/mongo/{databaseId}/operations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -1382,7 +1382,7 @@ def get_pitr( api_path = '/mongo/{databaseId}/pitr' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1422,7 +1422,7 @@ def get_replicas( api_path = '/mongo/{databaseId}/replicas' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1474,7 +1474,7 @@ def list_restorations( api_path = '/mongo/{databaseId}/restorations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -1534,7 +1534,7 @@ def create_restoration( api_path = '/mongo/{databaseId}/restorations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if type is not None: @@ -1586,9 +1586,9 @@ def get_restoration( api_path = '/mongo/{databaseId}/restorations/{restorationId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if restoration_id is None: + if restoration_id is None or restoration_id == '': raise AppwriteException('Missing required parameter: "restoration_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{restorationId}', str(self._normalize_value(restoration_id))) @@ -1629,7 +1629,7 @@ def get_status( api_path = '/mongo/{databaseId}/status' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1672,7 +1672,7 @@ def create_upgrade( api_path = '/mongo/{databaseId}/upgrades' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if target_version is None: raise AppwriteException('Missing required parameter: "target_version"') diff --git a/appwrite/services/mysql.py b/appwrite/services/mysql.py index a40b04c1..f47a2bb7 100644 --- a/appwrite/services/mysql.py +++ b/appwrite/services/mysql.py @@ -116,7 +116,7 @@ def create( storage_autoscaling_threshold_percent : Optional[float] Storage usage percentage (50-95) that triggers automatic expansion. storage_autoscaling_max_gb : Optional[float] - Maximum storage size in GB for autoscaling. 0 means no limit. + Maximum storage size in GB for autoscaling. Defaults to 3 times the specification's storage. 0 means no limit. Returns ------- DedicatedDatabase @@ -180,7 +180,7 @@ def list_specifications( self, ) -> DedicatedDatabaseSpecificationList: """ - 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. + List the dedicated database specifications available on the current plan. Each specification reports its resource limits, its own prices and overage rates, and whether it is enabled for the organization. Returns ------- DedicatedDatabaseSpecificationList @@ -231,7 +231,7 @@ def get( api_path = '/mysql/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -331,7 +331,7 @@ def update( api_path = '/mysql/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if name is not None: @@ -414,7 +414,7 @@ def delete( api_path = '/mysql/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -458,7 +458,7 @@ def list_backups( api_path = '/mysql/{databaseId}/backups' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -503,7 +503,7 @@ def create_backup( api_path = '/mysql/{databaseId}/backups' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if type is not None: @@ -549,7 +549,7 @@ def list_backup_policies( api_path = '/mysql/{databaseId}/backups/policies' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -609,7 +609,7 @@ def create_backup_policy( api_path = '/mysql/{databaseId}/backups/policies' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if policy_id is None: raise AppwriteException('Missing required parameter: "policy_id"') @@ -669,9 +669,9 @@ def get_backup_policy( api_path = '/mysql/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -727,9 +727,9 @@ def update_backup_policy( api_path = '/mysql/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -782,9 +782,9 @@ def delete_backup_policy( api_path = '/mysql/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -847,7 +847,7 @@ def update_backup_storage( api_path = '/mysql/{databaseId}/backups/storage' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if provider is None: raise AppwriteException('Missing required parameter: "provider"') @@ -909,9 +909,9 @@ def get_backup( api_path = '/mysql/{databaseId}/backups/{backupId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if backup_id is None: + if backup_id is None or backup_id == '': raise AppwriteException('Missing required parameter: "backup_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{backupId}', str(self._normalize_value(backup_id))) @@ -955,9 +955,9 @@ def delete_backup( api_path = '/mysql/{databaseId}/backups/{backupId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if backup_id is None: + if backup_id is None or backup_id == '': raise AppwriteException('Missing required parameter: "backup_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{backupId}', str(self._normalize_value(backup_id))) @@ -999,7 +999,7 @@ def list_branches( api_path = '/mysql/{databaseId}/branches' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1045,7 +1045,7 @@ def create_branch( api_path = '/mysql/{databaseId}/branches' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if branch_id is not None: @@ -1093,9 +1093,9 @@ def delete_branch( api_path = '/mysql/{databaseId}/branches/{branchId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if branch_id is None: + if branch_id is None or branch_id == '': raise AppwriteException('Missing required parameter: "branch_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{branchId}', str(self._normalize_value(branch_id))) @@ -1137,7 +1137,7 @@ def update_credentials( api_path = '/mysql/{databaseId}/credentials' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1187,7 +1187,7 @@ def create_execution( api_path = '/mysql/{databaseId}/executions' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if sql is None: raise AppwriteException('Missing required parameter: "sql"') @@ -1238,7 +1238,7 @@ def create_failover( api_path = '/mysql/{databaseId}/failovers' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if target_replica_id is not None: @@ -1287,7 +1287,7 @@ def update_maintenance( api_path = '/mysql/{databaseId}/maintenance' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if day is None: raise AppwriteException('Missing required parameter: "day"') @@ -1340,7 +1340,7 @@ def create_migration( api_path = '/mysql/{databaseId}/migrations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if target_type is None: raise AppwriteException('Missing required parameter: "target_type"') @@ -1395,7 +1395,7 @@ def list_operations( api_path = '/mysql/{databaseId}/operations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -1441,7 +1441,7 @@ def get_pitr( api_path = '/mysql/{databaseId}/pitr' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1481,7 +1481,7 @@ def get_pooler( api_path = '/mysql/{databaseId}/pooler' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1545,7 +1545,7 @@ def update_pooler( api_path = '/mysql/{databaseId}/pooler' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if mode is not None: @@ -1602,7 +1602,7 @@ def get_replicas( api_path = '/mysql/{databaseId}/replicas' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1654,7 +1654,7 @@ def list_restorations( api_path = '/mysql/{databaseId}/restorations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -1714,7 +1714,7 @@ def create_restoration( api_path = '/mysql/{databaseId}/restorations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if type is not None: @@ -1766,9 +1766,9 @@ def get_restoration( api_path = '/mysql/{databaseId}/restorations/{restorationId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if restoration_id is None: + if restoration_id is None or restoration_id == '': raise AppwriteException('Missing required parameter: "restoration_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{restorationId}', str(self._normalize_value(restoration_id))) @@ -1809,7 +1809,7 @@ def get_status( api_path = '/mysql/{databaseId}/status' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1852,7 +1852,7 @@ def create_upgrade( api_path = '/mysql/{databaseId}/upgrades' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if target_version is None: raise AppwriteException('Missing required parameter: "target_version"') diff --git a/appwrite/services/oauth2.py b/appwrite/services/oauth2.py index 31489fef..774dcf2c 100644 --- a/appwrite/services/oauth2.py +++ b/appwrite/services/oauth2.py @@ -7,6 +7,7 @@ from ..models.oauth2_authorize import Oauth2Authorize from ..models.oauth2_device_authorization import Oauth2DeviceAuthorization from ..models.oauth2_grant import Oauth2Grant +from ..models.oauth2_introspection import Oauth2Introspection from ..models.oauth2_organization_list import Oauth2OrganizationList from ..models.oauth2_par import Oauth2PAR from ..models.oauth2_project_list import Oauth2ProjectList @@ -83,7 +84,7 @@ def authorize( prompt: Optional[str] = None, max_age: Optional[float] = None, authorization_details: Optional[str] = None, - resource: Optional[str] = None, + resource: Optional[List[str]] = None, audience: Optional[str] = None, request_uri: Optional[str] = None, ) -> Oauth2Authorize: @@ -114,7 +115,7 @@ def authorize( 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 : Optional[str] Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - resource : Optional[str] + resource : Optional[List[str]] RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. audience : Optional[str] Compatibility alias for a single OAuth2 resource indicator URI. @@ -187,7 +188,7 @@ def authorize_post( prompt: Optional[str] = None, max_age: Optional[float] = None, authorization_details: Optional[str] = None, - resource: Optional[str] = None, + resource: Optional[List[str]] = None, audience: Optional[str] = None, request_uri: Optional[str] = None, ) -> Oauth2Authorize: @@ -218,7 +219,7 @@ def authorize_post( 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 : Optional[str] Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - resource : Optional[str] + resource : Optional[List[str]] RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. audience : Optional[str] Compatibility alias for a single OAuth2 resource indicator URI. @@ -284,7 +285,7 @@ def create_device_authorization( client_id: Optional[str] = None, scope: Optional[str] = None, authorization_details: Optional[str] = None, - resource: Optional[str] = None, + resource: Optional[List[str]] = None, audience: Optional[str] = None, ) -> Oauth2DeviceAuthorization: """ @@ -298,7 +299,7 @@ def create_device_authorization( Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. authorization_details : Optional[str] Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - resource : Optional[str] + resource : Optional[List[str]] RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. audience : Optional[str] Compatibility alias for a single OAuth2 resource indicator URI. @@ -404,7 +405,7 @@ def get_grant( api_path = '/oauth2/{project_id}/grants/{grant_id}' api_params = {} - if grant_id is None: + if grant_id is None or grant_id == '': raise AppwriteException('Missing required parameter: "grant_id"') api_path = api_path.replace('{project_id}', str(self._normalize_value(self.client.get_config('project')))) api_path = api_path.replace('{grant_id}', str(self._normalize_value(grant_id))) @@ -420,6 +421,62 @@ def get_grant( return self._parse_response(response, model=Oauth2Grant) + def introspect( + self, + token: str, + token_type_hint: Optional[str] = None, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + ) -> Oauth2Introspection: + """ + Introspect an OAuth2 access token or refresh token. Authenticate with an API key holding the `oauth2.introspect` scope to introspect any token in the project, or with the client credentials of the app the token was issued to. + + Parameters + ---------- + token : str + The access token or refresh token to introspect. + token_type_hint : Optional[str] + Type of token to introspect. Can be one of: `access_token` or `refresh_token`. + client_id : Optional[str] + OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. + client_secret : Optional[str] + OAuth2 client secret. + Returns + ------- + Oauth2Introspection + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/oauth2/{project_id}/introspect' + api_params = {} + if token is None: + raise AppwriteException('Missing required parameter: "token"') + api_path = api_path.replace('{project_id}', str(self._normalize_value(self.client.get_config('project')))) + api_params['token'] = self._normalize_value(token) + if token_type_hint is not None: + api_params['token_type_hint'] = self._normalize_value(token_type_hint) + if client_id is not None: + api_params['client_id'] = self._normalize_value(client_id) + if client_secret is not None: + api_params['client_secret'] = self._normalize_value(client_secret) + + response = self.client.call( + 'post', + api_path, + { + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Oauth2Introspection) + def list_organizations( self, limit: Optional[float] = None, @@ -482,7 +539,7 @@ def create_par( prompt: Optional[str] = None, max_age: Optional[float] = None, authorization_details: Optional[str] = None, - resource: Optional[str] = None, + resource: Optional[List[str]] = None, audience: Optional[str] = None, ) -> Oauth2PAR: """ @@ -512,7 +569,7 @@ def create_par( OIDC max_age parameter for customization of consent screen. authorization_details : Optional[str] Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - resource : Optional[str] + resource : Optional[List[str]] RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. audience : Optional[str] Compatibility alias for a single OAuth2 resource indicator URI. @@ -728,7 +785,7 @@ def create_token( client_secret: Optional[str] = None, code_verifier: Optional[str] = None, redirect_uri: Optional[str] = None, - resource: Optional[str] = None, + resource: Optional[List[str]] = None, audience: Optional[str] = None, ) -> Oauth2Token: """ @@ -752,7 +809,7 @@ def create_token( PKCE code verifier. Required for public apps. redirect_uri : Optional[str] Redirect URI. Required for `authorization_code` grant type. - resource : Optional[str] + resource : Optional[List[str]] RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. audience : Optional[str] Compatibility alias for a single OAuth2 resource indicator URI. diff --git a/appwrite/services/organization.py b/appwrite/services/organization.py index aa7eed39..0e31be2b 100644 --- a/appwrite/services/organization.py +++ b/appwrite/services/organization.py @@ -6,14 +6,15 @@ from ..models.organization import Organization as OrganizationModel from ..models.app_installation_list import AppInstallationList from ..models.app_installation import AppInstallation -from ..models.key_list import KeyList -from ..enums.organization_key_scopes import OrganizationKeyScopes -from ..models.key import Key from ..models.membership_list import MembershipList from ..models.membership import Membership from ..models.project_list import ProjectList from ..enums.region import Region from ..models.project import Project +from ..models.key_list import KeyList +from ..enums.project_key_scopes import ProjectKeyScopes +from ..models.ephemeral_key import EphemeralKey +from ..models.key import Key T = TypeVar('T') @@ -131,6 +132,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -251,7 +253,7 @@ def get_installation( api_path = '/organization/installations/{installationId}' api_params = {} - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) @@ -294,7 +296,7 @@ def update_installation( api_path = '/organization/installations/{installationId}' api_params = {} - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) if authorization_details is not None: @@ -337,7 +339,7 @@ def delete_installation( api_path = '/organization/installations/{installationId}' api_params = {} - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) @@ -354,23 +356,26 @@ def delete_installation( return response - def list_keys( + def list_memberships( self, queries: Optional[List[str]] = None, + search: Optional[str] = None, total: Optional[bool] = None, - ) -> KeyList: + ) -> MembershipList: """ - Get a list of all API keys from the current organization. + Get a list of all memberships from the current organization. Parameters ---------- queries : Optional[List[str]] - 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: expire, accessedAt, name, scopes + 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 : Optional[str] + Search term to filter your list results. Max length: 256 chars. total : Optional[bool] When set to false, the total count returned will be 0 and will not be calculated. Returns ------- - KeyList + MembershipList API response as a typed Pydantic model Raises @@ -379,10 +384,12 @@ def list_keys( If API request fails """ - api_path = '/organization/keys' + api_path = '/organization/memberships' api_params = {} if queries is not None: api_params['queries'] = self._normalize_value(queries) + if search is not None: + api_params['search'] = self._normalize_value(search) if total is not None: api_params['total'] = self._normalize_value(total) @@ -396,31 +403,37 @@ def list_keys( api_params, ) - return self._parse_response(response, model=KeyList) + return self._parse_response(response, model=MembershipList) - def create_key( + def create_membership( self, - key_id: str, - name: str, - scopes: List[OrganizationKeyScopes], - expire: Optional[str] = None, - ) -> Key: + roles: List[str], + email: Optional[str] = None, + user_id: Optional[str] = None, + phone: Optional[str] = None, + url: Optional[str] = None, + name: Optional[str] = None, + ) -> Membership: """ - Create a new organization API key. + 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 ---------- - key_id : str - 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 : str - Key name. Max length: 128 chars. - scopes : List[OrganizationKeyScopes] - Key scopes list. Maximum of 200 scopes are allowed. - expire : Optional[str] - Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. + roles : List[str] + 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. + email : Optional[str] + Email of the new organization member. + user_id : Optional[str] + ID of the user to be added to the organization. + phone : Optional[str] + Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. + url : Optional[str] + 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 : Optional[str] + Name of the new organization member. Max length: 128 chars. Returns ------- - Key + Membership API response as a typed Pydantic model Raises @@ -429,19 +442,21 @@ def create_key( If API request fails """ - api_path = '/organization/keys' + api_path = '/organization/memberships' api_params = {} - if key_id is None: - raise AppwriteException('Missing required parameter: "key_id"') - if name is None: - raise AppwriteException('Missing required parameter: "name"') - if scopes is None: - raise AppwriteException('Missing required parameter: "scopes"') - api_params['keyId'] = self._normalize_value(key_id) - api_params['name'] = self._normalize_value(name) - api_params['scopes'] = self._normalize_value(scopes) - if expire is not None: - api_params['expire'] = self._normalize_value(expire) + if roles is None: + raise AppwriteException('Missing required parameter: "roles"') + if email is not None: + api_params['email'] = self._normalize_value(email) + if user_id is not None: + api_params['userId'] = self._normalize_value(user_id) + if phone is not None: + api_params['phone'] = self._normalize_value(phone) + api_params['roles'] = self._normalize_value(roles) + if url is not None: + api_params['url'] = self._normalize_value(url) + if name is not None: + api_params['name'] = self._normalize_value(name) response = self.client.call( 'post', @@ -454,22 +469,22 @@ def create_key( api_params, ) - return self._parse_response(response, model=Key) + return self._parse_response(response, model=Membership) - def get_key( + def get_membership( self, - key_id: str, - ) -> Key: + membership_id: str, + ) -> Membership: """ - Get a key by its unique ID. This endpoint returns details about a specific API key in your organization including its scopes. + Get a membership from the current organization by its unique ID. Parameters ---------- - key_id : str - Key unique ID. + membership_id : str + Membership ID. Returns ------- - Key + Membership API response as a typed Pydantic model Raises @@ -478,11 +493,11 @@ def get_key( If API request fails """ - api_path = '/organization/keys/{keyId}' + api_path = '/organization/memberships/{membershipId}' api_params = {} - if key_id is None: - raise AppwriteException('Missing required parameter: "key_id"') - api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) + if membership_id is None or membership_id == '': + raise AppwriteException('Missing required parameter: "membership_id"') + api_path = api_path.replace('{membershipId}', str(self._normalize_value(membership_id))) response = self.client.call( 'get', @@ -494,31 +509,25 @@ def get_key( api_params, ) - return self._parse_response(response, model=Key) + return self._parse_response(response, model=Membership) - def update_key( + def update_membership( self, - key_id: str, - name: str, - scopes: List[OrganizationKeyScopes], - expire: Optional[str] = None, - ) -> Key: + membership_id: str, + roles: List[str], + ) -> Membership: """ - Update a key by its unique ID. Use this endpoint to update the name, scopes, or expiration time of an API key. + Modify the roles of a member in the current organization. Parameters ---------- - key_id : str - Key unique ID. - name : str - Key name. Max length: 128 chars. - scopes : List[OrganizationKeyScopes] - Key scopes list. Maximum of 200 scopes are allowed. - expire : Optional[str] - Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. + membership_id : str + Membership ID. + roles : List[str] + 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. Returns ------- - Key + Membership API response as a typed Pydantic model Raises @@ -527,22 +536,17 @@ def update_key( If API request fails """ - api_path = '/organization/keys/{keyId}' + api_path = '/organization/memberships/{membershipId}' api_params = {} - if key_id is None: - raise AppwriteException('Missing required parameter: "key_id"') - if name is None: - raise AppwriteException('Missing required parameter: "name"') - if scopes is None: - raise AppwriteException('Missing required parameter: "scopes"') - api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) - api_params['name'] = self._normalize_value(name) - api_params['scopes'] = self._normalize_value(scopes) - if expire is not None: - api_params['expire'] = self._normalize_value(expire) + if membership_id is None or membership_id == '': + raise AppwriteException('Missing required parameter: "membership_id"') + if roles is None: + raise AppwriteException('Missing required parameter: "roles"') + api_path = api_path.replace('{membershipId}', str(self._normalize_value(membership_id))) + api_params['roles'] = self._normalize_value(roles) response = self.client.call( - 'put', + 'patch', api_path, { 'X-Appwrite-Project': self.client.get_config('project'), @@ -552,19 +556,19 @@ def update_key( api_params, ) - return self._parse_response(response, model=Key) + return self._parse_response(response, model=Membership) - def delete_key( + def delete_membership( self, - key_id: str, + membership_id: str, ) -> Dict[str, Any]: """ - Delete a key by its unique ID. Once deleted, the key can no longer be used to authenticate API calls. + Remove a member from the current organization. The member is removed whether they accepted the invitation or not; a pending invitation is revoked. Parameters ---------- - key_id : str - Key unique ID. + membership_id : str + Membership ID. Returns ------- Dict[str, Any] @@ -576,11 +580,11 @@ def delete_key( If API request fails """ - api_path = '/organization/keys/{keyId}' + api_path = '/organization/memberships/{membershipId}' api_params = {} - if key_id is None: - raise AppwriteException('Missing required parameter: "key_id"') - api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) + if membership_id is None or membership_id == '': + raise AppwriteException('Missing required parameter: "membership_id"') + api_path = api_path.replace('{membershipId}', str(self._normalize_value(membership_id))) response = self.client.call( 'delete', @@ -588,32 +592,33 @@ def delete_key( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) return response - def list_memberships( + def list_projects( self, queries: Optional[List[str]] = None, search: Optional[str] = None, total: Optional[bool] = None, - ) -> MembershipList: + ) -> ProjectList: """ - Get a list of all memberships from the current organization. + Get a list of all projects. You can use the query params to filter your results. Parameters ---------- queries : Optional[List[str]] - 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 + 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 : Optional[str] Search term to filter your list results. Max length: 256 chars. total : Optional[bool] When set to false, the total count returned will be 0 and will not be calculated. Returns ------- - MembershipList + ProjectList API response as a typed Pydantic model Raises @@ -622,7 +627,7 @@ def list_memberships( If API request fails """ - api_path = '/organization/memberships' + api_path = '/organization/projects' api_params = {} if queries is not None: api_params['queries'] = self._normalize_value(queries) @@ -641,37 +646,28 @@ def list_memberships( api_params, ) - return self._parse_response(response, model=MembershipList) + return self._parse_response(response, model=ProjectList) - def create_membership( + def create_project( self, - roles: List[str], - email: Optional[str] = None, - user_id: Optional[str] = None, - phone: Optional[str] = None, - url: Optional[str] = None, - name: Optional[str] = None, - ) -> Membership: + project_id: str, + name: str, + region: Optional[Region] = None, + ) -> Project: """ - 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. + Create a new project. Parameters ---------- - roles : List[str] - 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. - email : Optional[str] - Email of the new organization member. - user_id : Optional[str] - ID of the user to be added to the organization. - phone : Optional[str] - Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. - url : Optional[str] - 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 : Optional[str] - Name of the new organization member. Max length: 128 chars. + project_id : str + Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars. + name : str + Project name. Max length: 128 chars. + region : Optional[Region] + Project Region. Returns ------- - Membership + Project API response as a typed Pydantic model Raises @@ -680,21 +676,16 @@ def create_membership( If API request fails """ - api_path = '/organization/memberships' + api_path = '/organization/projects' api_params = {} - if roles is None: - raise AppwriteException('Missing required parameter: "roles"') - if email is not None: - api_params['email'] = self._normalize_value(email) - if user_id is not None: - api_params['userId'] = self._normalize_value(user_id) - if phone is not None: - api_params['phone'] = self._normalize_value(phone) - api_params['roles'] = self._normalize_value(roles) - if url is not None: - api_params['url'] = self._normalize_value(url) - if name is not None: - api_params['name'] = self._normalize_value(name) + if project_id is None: + raise AppwriteException('Missing required parameter: "project_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + api_params['projectId'] = self._normalize_value(project_id) + api_params['name'] = self._normalize_value(name) + if region is not None: + api_params['region'] = self._normalize_value(region) response = self.client.call( 'post', @@ -707,22 +698,22 @@ def create_membership( api_params, ) - return self._parse_response(response, model=Membership) + return self._parse_response(response, model=Project) - def get_membership( + def get_project( self, - membership_id: str, - ) -> Membership: + project_id: str, + ) -> Project: """ - Get a membership from the current organization by its unique ID. + Get a project. Parameters ---------- - membership_id : str - Membership ID. + project_id : str + Project unique ID. Returns ------- - Membership + Project API response as a typed Pydantic model Raises @@ -731,11 +722,11 @@ def get_membership( If API request fails """ - api_path = '/organization/memberships/{membershipId}' + api_path = '/organization/projects/{projectId}' api_params = {} - if membership_id is None: - raise AppwriteException('Missing required parameter: "membership_id"') - api_path = api_path.replace('{membershipId}', str(self._normalize_value(membership_id))) + if project_id is None or project_id == '': + raise AppwriteException('Missing required parameter: "project_id"') + api_path = api_path.replace('{projectId}', str(self._normalize_value(project_id))) response = self.client.call( 'get', @@ -747,25 +738,25 @@ def get_membership( api_params, ) - return self._parse_response(response, model=Membership) + return self._parse_response(response, model=Project) - def update_membership( + def update_project( self, - membership_id: str, - roles: List[str], - ) -> Membership: + project_id: str, + name: str, + ) -> Project: """ - Modify the roles of a member in the current organization. + Update a project by its unique ID. Parameters ---------- - membership_id : str - Membership ID. - roles : List[str] - 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. + project_id : str + Project unique ID. + name : str + Project name. Max length: 128 chars. Returns ------- - Membership + Project API response as a typed Pydantic model Raises @@ -774,14 +765,14 @@ def update_membership( If API request fails """ - api_path = '/organization/memberships/{membershipId}' + api_path = '/organization/projects/{projectId}' api_params = {} - if membership_id is None: - raise AppwriteException('Missing required parameter: "membership_id"') - if roles is None: - raise AppwriteException('Missing required parameter: "roles"') - api_path = api_path.replace('{membershipId}', str(self._normalize_value(membership_id))) - api_params['roles'] = self._normalize_value(roles) + if project_id is None or project_id == '': + raise AppwriteException('Missing required parameter: "project_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + api_path = api_path.replace('{projectId}', str(self._normalize_value(project_id))) + api_params['name'] = self._normalize_value(name) response = self.client.call( 'patch', @@ -794,19 +785,19 @@ def update_membership( api_params, ) - return self._parse_response(response, model=Membership) + return self._parse_response(response, model=Project) - def delete_membership( + def delete_project( self, - membership_id: str, + project_id: str, ) -> Dict[str, Any]: """ - Remove a member from the current organization. The member is removed whether they accepted the invitation or not; a pending invitation is revoked. + Delete a project by its unique ID. Parameters ---------- - membership_id : str - Membership ID. + project_id : str + Project unique ID. Returns ------- Dict[str, Any] @@ -818,11 +809,11 @@ def delete_membership( If API request fails """ - api_path = '/organization/memberships/{membershipId}' + api_path = '/organization/projects/{projectId}' api_params = {} - if membership_id is None: - raise AppwriteException('Missing required parameter: "membership_id"') - api_path = api_path.replace('{membershipId}', str(self._normalize_value(membership_id))) + if project_id is None or project_id == '': + raise AppwriteException('Missing required parameter: "project_id"') + api_path = api_path.replace('{projectId}', str(self._normalize_value(project_id))) response = self.client.call( 'delete', @@ -830,32 +821,33 @@ def delete_membership( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) return response - def list_projects( + def list_project_keys( self, + project_id: str, queries: Optional[List[str]] = None, - search: Optional[str] = None, total: Optional[bool] = None, - ) -> ProjectList: + ) -> KeyList: """ - Get a list of all projects. You can use the query params to filter your results. + Get a list of all API keys of a project in your organization. Parameters ---------- + project_id : str + Project unique ID. queries : Optional[List[str]] - 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 : Optional[str] - Search term to filter your list results. Max length: 256 chars. + 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: expire, accessedAt, name, scopes total : Optional[bool] When set to false, the total count returned will be 0 and will not be calculated. Returns ------- - ProjectList + KeyList API response as a typed Pydantic model Raises @@ -864,12 +856,13 @@ def list_projects( If API request fails """ - api_path = '/organization/projects' + api_path = '/organization/projects/{projectId}/keys' api_params = {} + if project_id is None or project_id == '': + raise AppwriteException('Missing required parameter: "project_id"') + api_path = api_path.replace('{projectId}', str(self._normalize_value(project_id))) if queries is not None: api_params['queries'] = self._normalize_value(queries) - if search is not None: - api_params['search'] = self._normalize_value(search) if total is not None: api_params['total'] = self._normalize_value(total) @@ -883,28 +876,30 @@ def list_projects( api_params, ) - return self._parse_response(response, model=ProjectList) + return self._parse_response(response, model=KeyList) - def create_project( + def create_ephemeral_project_key( self, project_id: str, - name: str, - region: Optional[Region] = None, - ) -> Project: + scopes: List[ProjectKeyScopes], + duration: float, + ) -> EphemeralKey: """ - Create a new project. + Create a new ephemeral API key for a project in your organization. It's recommended to have multiple API keys with strict scopes for separate functions within your project. + + You can also create a standard API key if you need a longer-lived key instead. Parameters ---------- project_id : str - Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars. - name : str - Project name. Max length: 128 chars. - region : Optional[Region] - Project Region. + Project unique ID. + scopes : List[ProjectKeyScopes] + Key scopes list. Maximum of 200 scopes are allowed. + duration : float + Time in seconds before ephemeral key expires. Maximum duration is 3600 seconds. Returns ------- - Project + EphemeralKey API response as a typed Pydantic model Raises @@ -913,16 +908,17 @@ def create_project( If API request fails """ - api_path = '/organization/projects' + api_path = '/organization/projects/{projectId}/keys/ephemeral' api_params = {} - if project_id is None: + if project_id is None or project_id == '': raise AppwriteException('Missing required parameter: "project_id"') - if name is None: - raise AppwriteException('Missing required parameter: "name"') - api_params['projectId'] = self._normalize_value(project_id) - api_params['name'] = self._normalize_value(name) - if region is not None: - api_params['region'] = self._normalize_value(region) + if scopes is None: + raise AppwriteException('Missing required parameter: "scopes"') + if duration is None: + raise AppwriteException('Missing required parameter: "duration"') + api_path = api_path.replace('{projectId}', str(self._normalize_value(project_id))) + api_params['scopes'] = self._normalize_value(scopes) + api_params['duration'] = self._normalize_value(duration) response = self.client.call( 'post', @@ -935,22 +931,25 @@ def create_project( api_params, ) - return self._parse_response(response, model=Project) + return self._parse_response(response, model=EphemeralKey) - def get_project( + def get_project_key( self, project_id: str, - ) -> Project: + key_id: str, + ) -> Key: """ - Get a project. + Get a project key by its unique ID. Parameters ---------- project_id : str Project unique ID. + key_id : str + Key ID. Returns ------- - Project + Key API response as a typed Pydantic model Raises @@ -959,40 +958,53 @@ def get_project( If API request fails """ - api_path = '/organization/projects/{projectId}' + api_path = '/organization/projects/{projectId}/keys/{keyId}' api_params = {} - if project_id is None: + if project_id is None or project_id == '': raise AppwriteException('Missing required parameter: "project_id"') + if key_id is None or key_id == '': + raise AppwriteException('Missing required parameter: "key_id"') api_path = api_path.replace('{projectId}', str(self._normalize_value(project_id))) + api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) response = self.client.call( 'get', api_path, { 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', }, api_params, ) - return self._parse_response(response, model=Project) + return self._parse_response(response, model=Key) - def update_project( + def update_project_key( self, project_id: str, + key_id: str, name: str, - ) -> Project: + scopes: List[ProjectKeyScopes], + expire: Optional[str] = None, + ) -> Key: """ - Update a project by its unique ID. + Update a project key by its unique ID. Use this endpoint to update the name, scopes, or expiration time of an API key. Parameters ---------- project_id : str Project unique ID. + key_id : str + Key ID. name : str - Project name. Max length: 128 chars. + Key name. Max length: 128 chars. + scopes : List[ProjectKeyScopes] + Key scopes list. Maximum of 200 scopes are allowed. + expire : Optional[str] + Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. Returns ------- - Project + Key API response as a typed Pydantic model Raises @@ -1001,17 +1013,25 @@ def update_project( If API request fails """ - api_path = '/organization/projects/{projectId}' + api_path = '/organization/projects/{projectId}/keys/{keyId}' api_params = {} - if project_id is None: + if project_id is None or project_id == '': raise AppwriteException('Missing required parameter: "project_id"') + if key_id is None or key_id == '': + raise AppwriteException('Missing required parameter: "key_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') + if scopes is None: + raise AppwriteException('Missing required parameter: "scopes"') api_path = api_path.replace('{projectId}', str(self._normalize_value(project_id))) + api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) api_params['name'] = self._normalize_value(name) + api_params['scopes'] = self._normalize_value(scopes) + if expire is not None: + api_params['expire'] = self._normalize_value(expire) response = self.client.call( - 'patch', + 'put', api_path, { 'X-Appwrite-Project': self.client.get_config('project'), @@ -1021,19 +1041,22 @@ def update_project( api_params, ) - return self._parse_response(response, model=Project) + return self._parse_response(response, model=Key) - def delete_project( + def delete_project_key( self, project_id: str, + key_id: str, ) -> Dict[str, Any]: """ - Delete a project by its unique ID. + Delete a project key by its unique ID. Once deleted, the key can no longer be used to authenticate API calls. Parameters ---------- project_id : str Project unique ID. + key_id : str + Key ID. Returns ------- Dict[str, Any] @@ -1045,11 +1068,14 @@ def delete_project( If API request fails """ - api_path = '/organization/projects/{projectId}' + api_path = '/organization/projects/{projectId}/keys/{keyId}' api_params = {} - if project_id is None: + if project_id is None or project_id == '': raise AppwriteException('Missing required parameter: "project_id"') + if key_id is None or key_id == '': + raise AppwriteException('Missing required parameter: "key_id"') api_path = api_path.replace('{projectId}', str(self._normalize_value(project_id))) + api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) response = self.client.call( 'delete', @@ -1057,6 +1083,7 @@ def delete_project( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) diff --git a/appwrite/services/postgresql.py b/appwrite/services/postgresql.py index 19d1ff74..52d7ed46 100644 --- a/appwrite/services/postgresql.py +++ b/appwrite/services/postgresql.py @@ -117,7 +117,7 @@ def create( storage_autoscaling_threshold_percent : Optional[float] Storage usage percentage (50-95) that triggers automatic expansion. storage_autoscaling_max_gb : Optional[float] - Maximum storage size in GB for autoscaling. 0 means no limit. + Maximum storage size in GB for autoscaling. Defaults to 3 times the specification's storage. 0 means no limit. Returns ------- DedicatedDatabase @@ -181,7 +181,7 @@ def list_specifications( self, ) -> DedicatedDatabaseSpecificationList: """ - 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. + List the dedicated database specifications available on the current plan. Each specification reports its resource limits, its own prices and overage rates, and whether it is enabled for the organization. Returns ------- DedicatedDatabaseSpecificationList @@ -232,7 +232,7 @@ def get( api_path = '/postgresql/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -332,7 +332,7 @@ def update( api_path = '/postgresql/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if name is not None: @@ -415,7 +415,7 @@ def delete( api_path = '/postgresql/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -459,7 +459,7 @@ def list_backups( api_path = '/postgresql/{databaseId}/backups' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -504,7 +504,7 @@ def create_backup( api_path = '/postgresql/{databaseId}/backups' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if type is not None: @@ -550,7 +550,7 @@ def list_backup_policies( api_path = '/postgresql/{databaseId}/backups/policies' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -610,7 +610,7 @@ def create_backup_policy( api_path = '/postgresql/{databaseId}/backups/policies' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if policy_id is None: raise AppwriteException('Missing required parameter: "policy_id"') @@ -670,9 +670,9 @@ def get_backup_policy( api_path = '/postgresql/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -728,9 +728,9 @@ def update_backup_policy( api_path = '/postgresql/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -783,9 +783,9 @@ def delete_backup_policy( api_path = '/postgresql/{databaseId}/backups/policies/{policyId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if policy_id is None: + if policy_id is None or policy_id == '': raise AppwriteException('Missing required parameter: "policy_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{policyId}', str(self._normalize_value(policy_id))) @@ -848,7 +848,7 @@ def update_backup_storage( api_path = '/postgresql/{databaseId}/backups/storage' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if provider is None: raise AppwriteException('Missing required parameter: "provider"') @@ -910,9 +910,9 @@ def get_backup( api_path = '/postgresql/{databaseId}/backups/{backupId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if backup_id is None: + if backup_id is None or backup_id == '': raise AppwriteException('Missing required parameter: "backup_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{backupId}', str(self._normalize_value(backup_id))) @@ -956,9 +956,9 @@ def delete_backup( api_path = '/postgresql/{databaseId}/backups/{backupId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if backup_id is None: + if backup_id is None or backup_id == '': raise AppwriteException('Missing required parameter: "backup_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{backupId}', str(self._normalize_value(backup_id))) @@ -1000,7 +1000,7 @@ def list_branches( api_path = '/postgresql/{databaseId}/branches' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1046,7 +1046,7 @@ def create_branch( api_path = '/postgresql/{databaseId}/branches' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if branch_id is not None: @@ -1094,9 +1094,9 @@ def delete_branch( api_path = '/postgresql/{databaseId}/branches/{branchId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if branch_id is None: + if branch_id is None or branch_id == '': raise AppwriteException('Missing required parameter: "branch_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{branchId}', str(self._normalize_value(branch_id))) @@ -1138,7 +1138,7 @@ def update_credentials( api_path = '/postgresql/{databaseId}/credentials' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1188,7 +1188,7 @@ def create_execution( api_path = '/postgresql/{databaseId}/executions' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if sql is None: raise AppwriteException('Missing required parameter: "sql"') @@ -1236,7 +1236,7 @@ def list_extensions( api_path = '/postgresql/{databaseId}/extensions' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1279,7 +1279,7 @@ def create_extension( api_path = '/postgresql/{databaseId}/extensions' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -1326,9 +1326,9 @@ def delete_extension( api_path = '/postgresql/{databaseId}/extensions/{extensionName}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if extension_name is None: + if extension_name is None or extension_name == '': raise AppwriteException('Missing required parameter: "extension_name"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{extensionName}', str(self._normalize_value(extension_name))) @@ -1373,7 +1373,7 @@ def create_failover( api_path = '/postgresql/{databaseId}/failovers' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if target_replica_id is not None: @@ -1422,7 +1422,7 @@ def update_maintenance( api_path = '/postgresql/{databaseId}/maintenance' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if day is None: raise AppwriteException('Missing required parameter: "day"') @@ -1475,7 +1475,7 @@ def create_migration( api_path = '/postgresql/{databaseId}/migrations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if target_type is None: raise AppwriteException('Missing required parameter: "target_type"') @@ -1530,7 +1530,7 @@ def list_operations( api_path = '/postgresql/{databaseId}/operations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -1576,7 +1576,7 @@ def get_pitr( api_path = '/postgresql/{databaseId}/pitr' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1616,7 +1616,7 @@ def get_pooler( api_path = '/postgresql/{databaseId}/pooler' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1680,7 +1680,7 @@ def update_pooler( api_path = '/postgresql/{databaseId}/pooler' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if mode is not None: @@ -1737,7 +1737,7 @@ def get_replicas( api_path = '/postgresql/{databaseId}/replicas' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1789,7 +1789,7 @@ def list_restorations( api_path = '/postgresql/{databaseId}/restorations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -1849,7 +1849,7 @@ def create_restoration( api_path = '/postgresql/{databaseId}/restorations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if type is not None: @@ -1901,9 +1901,9 @@ def get_restoration( api_path = '/postgresql/{databaseId}/restorations/{restorationId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if restoration_id is None: + if restoration_id is None or restoration_id == '': raise AppwriteException('Missing required parameter: "restoration_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{restorationId}', str(self._normalize_value(restoration_id))) @@ -1944,7 +1944,7 @@ def get_status( api_path = '/postgresql/{databaseId}/status' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1987,7 +1987,7 @@ def create_upgrade( api_path = '/postgresql/{databaseId}/upgrades' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if target_version is None: raise AppwriteException('Missing required parameter: "target_version"') diff --git a/appwrite/services/presences.py b/appwrite/services/presences.py index d4caaa86..7066914a 100644 --- a/appwrite/services/presences.py +++ b/appwrite/services/presences.py @@ -85,7 +85,7 @@ def get( api_path = '/presences/{presenceId}' api_params = {} - if presence_id is None: + if presence_id is None or presence_id == '': raise AppwriteException('Missing required parameter: "presence_id"') api_path = api_path.replace('{presenceId}', str(self._normalize_value(presence_id))) @@ -140,7 +140,7 @@ def upsert( api_path = '/presences/{presenceId}' api_params = {} - if presence_id is None: + if presence_id is None or presence_id == '': raise AppwriteException('Missing required parameter: "presence_id"') if user_id is None: raise AppwriteException('Missing required parameter: "user_id"') @@ -211,7 +211,7 @@ def update( api_path = '/presences/{presenceId}' api_params = {} - if presence_id is None: + if presence_id is None or presence_id == '': raise AppwriteException('Missing required parameter: "presence_id"') if user_id is None: raise AppwriteException('Missing required parameter: "user_id"') @@ -265,7 +265,7 @@ def delete( api_path = '/presences/{presenceId}' api_params = {} - if presence_id is None: + if presence_id is None or presence_id == '': raise AppwriteException('Missing required parameter: "presence_id"') api_path = api_path.replace('{presenceId}', str(self._normalize_value(presence_id))) @@ -275,6 +275,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) diff --git a/appwrite/services/project.py b/appwrite/services/project.py index 848e448c..7b868d6d 100644 --- a/appwrite/services/project.py +++ b/appwrite/services/project.py @@ -15,6 +15,7 @@ from ..models.o_auth2_amazon import OAuth2Amazon from ..models.o_auth2_apple import OAuth2Apple from ..models.o_auth2_appwrite import OAuth2Appwrite +from ..enums.project_o_auth2_auth0_prompt import ProjectOAuth2Auth0Prompt from ..models.o_auth2_auth0 import OAuth2Auth0 from ..models.o_auth2_authentik import OAuth2Authentik from ..models.o_auth2_autodesk import OAuth2Autodesk @@ -23,6 +24,7 @@ from ..models.o_auth2_box import OAuth2Box from ..models.o_auth2_cloudflare import OAuth2Cloudflare from ..models.o_auth2_dailymotion import OAuth2Dailymotion +from ..enums.project_o_auth2_discord_prompt import ProjectOAuth2DiscordPrompt from ..models.o_auth2_discord import OAuth2Discord from ..models.o_auth2_disqus import OAuth2Disqus from ..models.o_auth2_dropbox import OAuth2Dropbox @@ -30,32 +32,41 @@ from ..models.o_auth2_facebook import OAuth2Facebook from ..models.o_auth2_figma import OAuth2Figma from ..models.o_auth2_fusion_auth import OAuth2FusionAuth +from ..enums.project_o_auth2_git_hub_prompt import ProjectOAuth2GitHubPrompt from ..models.o_auth2_github import OAuth2Github from ..models.o_auth2_gitlab import OAuth2Gitlab from ..enums.project_o_auth2_google_prompt import ProjectOAuth2GooglePrompt from ..models.o_auth2_google import OAuth2Google from ..models.o_auth2_hugging_face import OAuth2HuggingFace +from ..enums.project_o_auth2_kakao_prompt import ProjectOAuth2KakaoPrompt +from ..models.o_auth2_kakao import OAuth2Kakao from ..models.o_auth2_keycloak import OAuth2Keycloak from ..models.o_auth2_kick import OAuth2Kick from ..models.o_auth2_linkedin import OAuth2Linkedin +from ..enums.project_o_auth2_microsoft_prompt import ProjectOAuth2MicrosoftPrompt from ..models.o_auth2_microsoft import OAuth2Microsoft from ..models.o_auth2_notion import OAuth2Notion from ..enums.project_o_auth2_oidc_prompt import ProjectOAuth2OidcPrompt from ..models.o_auth2_oidc import OAuth2Oidc +from ..enums.project_o_auth2_okta_prompt import ProjectOAuth2OktaPrompt from ..models.o_auth2_okta import OAuth2Okta from ..models.o_auth2_paypal import OAuth2Paypal from ..models.o_auth2_podio import OAuth2Podio from ..models.o_auth2_resend import OAuth2Resend +from ..enums.project_o_auth2_salesforce_prompt import ProjectOAuth2SalesforcePrompt from ..models.o_auth2_salesforce import OAuth2Salesforce from ..models.o_auth2_slack import OAuth2Slack from ..models.o_auth2_spotify import OAuth2Spotify from ..models.o_auth2_stripe import OAuth2Stripe +from ..models.o_auth2_tik_tok import OAuth2TikTok from ..models.o_auth2_tradeshift import OAuth2Tradeshift from ..models.o_auth2_twitch import OAuth2Twitch +from ..models.o_auth2_webflow import OAuth2Webflow from ..models.o_auth2_word_press import OAuth2WordPress from ..models.o_auth2_x import OAuth2X from ..models.o_auth2_yahoo import OAuth2Yahoo from ..models.o_auth2_yandex import OAuth2Yandex +from ..enums.project_o_auth2_zoho_prompt import ProjectOAuth2ZohoPrompt from ..models.o_auth2_zoho import OAuth2Zoho from ..models.o_auth2_zoom import OAuth2Zoom from ..enums.project_o_auth_provider_id import ProjectOAuthProviderId @@ -71,6 +82,8 @@ from ..models.policy_password_dictionary import PolicyPasswordDictionary from ..models.policy_password_history import PolicyPasswordHistory from ..models.policy_password_personal_data import PolicyPasswordPersonalData +from ..models.policy_password_pwned import PolicyPasswordPwned +from ..models.policy_password_rotation import PolicyPasswordRotation from ..models.policy_session_alert import PolicySessionAlert from ..models.policy_session_duration import PolicySessionDuration from ..models.policy_session_invalidation import PolicySessionInvalidation @@ -82,6 +95,7 @@ from ..models.policy_deny_disposable_email import PolicyDenyDisposableEmail from ..models.policy_deny_free_email import PolicyDenyFreeEmail from ..models.policy_deny_corporate_email import PolicyDenyCorporateEmail +from ..models.policy_passkey import PolicyPasskey from ..enums.project_protocol_id import ProjectProtocolId from ..enums.project_service_id import ProjectServiceId from ..enums.project_smtp_secure import ProjectSMTPSecure @@ -122,6 +136,7 @@ def get( api_path, { 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', }, api_params, ) @@ -153,6 +168,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -170,7 +186,7 @@ def update_auth_method( Parameters ---------- method_id : ProjectAuthMethodId - Auth Method ID. Possible values: email-password,magic-url,email-otp,anonymous,invites,jwt,phone + Auth Method ID. Possible values: email-password,magic-url,email-otp,anonymous,invites,jwt,phone,passkey enabled : bool Auth method status. Returns @@ -323,7 +339,7 @@ def get_key( api_path = '/project/keys/{keyId}' api_params = {} - if key_id is None: + if key_id is None or key_id == '': raise AppwriteException('Missing required parameter: "key_id"') api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) @@ -372,7 +388,7 @@ def update_key( api_path = '/project/keys/{keyId}' api_params = {} - if key_id is None: + if key_id is None or key_id == '': raise AppwriteException('Missing required parameter: "key_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -421,7 +437,7 @@ def delete_key( api_path = '/project/keys/{keyId}' api_params = {} - if key_id is None: + if key_id is None or key_id == '': raise AppwriteException('Missing required parameter: "key_id"') api_path = api_path.replace('{keyId}', str(self._normalize_value(key_id))) @@ -431,6 +447,7 @@ def delete_key( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -593,7 +610,7 @@ def get_mock_phone( api_path = '/project/mock-phones/{number}' api_params = {} - if number is None: + if number is None or number == '': raise AppwriteException('Missing required parameter: "number"') api_path = api_path.replace('{number}', str(self._normalize_value(number))) @@ -636,7 +653,7 @@ def update_mock_phone( api_path = '/project/mock-phones/{number}' api_params = {} - if number is None: + if number is None or number == '': raise AppwriteException('Missing required parameter: "number"') if otp is None: raise AppwriteException('Missing required parameter: "otp"') @@ -680,7 +697,7 @@ def delete_mock_phone( api_path = '/project/mock-phones/{number}' api_params = {} - if number is None: + if number is None or number == '': raise AppwriteException('Missing required parameter: "number"') api_path = api_path.replace('{number}', str(self._normalize_value(number))) @@ -690,6 +707,7 @@ def delete_mock_phone( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -913,7 +931,9 @@ def update_o_auth2_apple( key_id: Optional[str] = None, team_id: Optional[str] = None, p8_file: Optional[str] = None, + native_client_ids: Optional[List[str]] = None, enabled: Optional[bool] = None, + native_enabled: Optional[bool] = None, ) -> OAuth2Apple: """ Update the project OAuth2 Apple configuration. @@ -928,8 +948,12 @@ def update_o_auth2_apple( 'Team ID' of Apple OAuth2 app. For example: D4000000R6 p8_file : Optional[str] Contents of the Apple OAuth2 app .p8 private key file. The secret key wrapped by the PEM markers is 200 characters long. For example: -----BEGIN PRIVATE KEY-----MIGTAg...jy2Xbna-----END PRIVATE KEY----- + native_client_ids : Optional[List[str]] + App bundle IDs accepted as ID token audiences for native Sign in with Apple. For example: com.example.app. Together with the Services ID, these are the only client IDs whose tokens are trusted. Pass an empty array to clear the list. enabled : Optional[bool] - 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. + Browser-based OAuth2 sign-in status. Set to true to enable new session creation through the redirect flow. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. Has no effect on native sign-in, which is controlled by nativeEnabled only. + native_enabled : Optional[bool] + Native Sign in with Apple status. This is the only switch for creating sessions from ID tokens obtained on device and is independent of enabled. Needs a Services ID or at least one native client ID to match tokens against, but no key or team ID: this method verifies a signature rather than redeeming an authorization code. Returns ------- OAuth2Apple @@ -951,8 +975,12 @@ def update_o_auth2_apple( api_params['teamId'] = self._normalize_value(team_id) if p8_file is not None: api_params['p8File'] = self._normalize_value(p8_file) + if native_client_ids is not None: + api_params['nativeClientIds'] = self._normalize_value(native_client_ids) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) + if native_enabled is not None: + api_params['nativeEnabled'] = self._normalize_value(native_enabled) response = self.client.call( 'patch', @@ -1022,6 +1050,7 @@ def update_o_auth2_auth0( client_id: Optional[str] = None, client_secret: Optional[str] = None, endpoint: Optional[str] = None, + prompt: Optional[List[ProjectOAuth2Auth0Prompt]] = None, enabled: Optional[bool] = None, ) -> OAuth2Auth0: """ @@ -1035,6 +1064,8 @@ def update_o_auth2_auth0( 'Client Secret' of Auth0 OAuth2 app. For example: zXz0000-00000000000000000000000000000-00000000000000000000PJafnF endpoint : Optional[str] Domain of Auth0 instance. For example: example.us.auth0.com + prompt : Optional[List[ProjectOAuth2Auth0Prompt]] + Array of Auth0 OAuth2 prompt values. 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. Pass an empty array to use the Auth0 default. enabled : Optional[bool] 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. Returns @@ -1056,6 +1087,8 @@ def update_o_auth2_auth0( api_params['clientSecret'] = self._normalize_value(client_secret) if endpoint is not None: api_params['endpoint'] = self._normalize_value(endpoint) + if prompt is not None: + api_params['prompt'] = self._normalize_value(prompt) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) @@ -1431,6 +1464,7 @@ def update_o_auth2_discord( self, client_id: Optional[str] = None, client_secret: Optional[str] = None, + prompt: Optional[List[ProjectOAuth2DiscordPrompt]] = None, enabled: Optional[bool] = None, ) -> OAuth2Discord: """ @@ -1442,6 +1476,8 @@ def update_o_auth2_discord( 'Client ID' of Discord OAuth2 app. For example: 950722000000343754 client_secret : Optional[str] 'Client Secret' of Discord OAuth2 app. For example: YmPXnM000000000000000000002zFg5D + prompt : Optional[List[ProjectOAuth2DiscordPrompt]] + Array with at most one Discord OAuth2 prompt value. "none" means: skip the authorization screen for users who already authorized the app with the requested scopes. "consent" means: ask users who already authorized the app to approve it again. Pass an empty array to use the Discord default. enabled : Optional[bool] 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. Returns @@ -1461,6 +1497,8 @@ def update_o_auth2_discord( api_params['clientId'] = self._normalize_value(client_id) if client_secret is not None: api_params['clientSecret'] = self._normalize_value(client_secret) + if prompt is not None: + api_params['prompt'] = self._normalize_value(prompt) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) @@ -1786,6 +1824,7 @@ def update_o_auth2_git_hub( self, client_id: Optional[str] = None, client_secret: Optional[str] = None, + prompt: Optional[List[ProjectOAuth2GitHubPrompt]] = None, enabled: Optional[bool] = None, ) -> OAuth2Github: """ @@ -1797,6 +1836,8 @@ def update_o_auth2_git_hub( 'OAuth2 app Client ID, or App ID' of GitHub OAuth2 app. For example: e4d87900000000540733. Example of wrong value: 370006 client_secret : Optional[str] 'Client Secret' of GitHub OAuth2 app. For example: 5e07c00000000000000000000000000000198bcc + prompt : Optional[List[ProjectOAuth2GitHubPrompt]] + Array of GitHub OAuth2 prompt values. "select_account" means: prompt the user to select an account. Pass an empty array to use the GitHub default. enabled : Optional[bool] 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. Returns @@ -1816,6 +1857,8 @@ def update_o_auth2_git_hub( api_params['clientId'] = self._normalize_value(client_id) if client_secret is not None: api_params['clientSecret'] = self._normalize_value(client_secret) + if prompt is not None: + api_params['prompt'] = self._normalize_value(prompt) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) @@ -1892,7 +1935,9 @@ def update_o_auth2_google( client_id: Optional[str] = None, client_secret: Optional[str] = None, prompt: Optional[List[ProjectOAuth2GooglePrompt]] = None, + native_client_ids: Optional[List[str]] = None, enabled: Optional[bool] = None, + native_enabled: Optional[bool] = None, ) -> OAuth2Google: """ Update the project OAuth2 Google configuration. @@ -1905,8 +1950,12 @@ def update_o_auth2_google( 'Client Secret' of Google OAuth2 app. For example: GOCSPX-2k8gsR0000000000000000VNahJj prompt : Optional[List[ProjectOAuth2GooglePrompt]] Array of Google OAuth2 prompt values. If "none" is included, it must be the only element. "none" means: don't display any authentication or consent screens. Must not be specified with other values. "consent" means: prompt the user for consent. "select_account" means: prompt the user to select an account. + native_client_ids : Optional[List[str]] + Additional OAuth2 client IDs accepted as ID token audiences for native sign-in (Android and iOS client IDs). Together with the client ID, which is always accepted, these are the only client IDs whose tokens are trusted. Pass an empty array to clear the list. enabled : Optional[bool] - 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. + Browser-based OAuth2 sign-in status. Set to true to enable new session creation through the redirect flow. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. Has no effect on native sign-in, which is controlled by nativeEnabled only. + native_enabled : Optional[bool] + Native Google sign-in status. This is the only switch for creating sessions from ID tokens obtained on device and is independent of enabled. Needs a client ID or at least one native client ID to match tokens against, but no client secret: this method verifies a signature rather than redeeming an authorization code. Returns ------- OAuth2Google @@ -1926,8 +1975,12 @@ def update_o_auth2_google( api_params['clientSecret'] = self._normalize_value(client_secret) if prompt is not None: api_params['prompt'] = self._normalize_value(prompt) + if native_client_ids is not None: + api_params['nativeClientIds'] = self._normalize_value(native_client_ids) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) + if native_enabled is not None: + api_params['nativeEnabled'] = self._normalize_value(native_enabled) response = self.client.call( 'patch', @@ -1992,6 +2045,61 @@ def update_o_auth2_hugging_face( return self._parse_response(response, model=OAuth2HuggingFace) + def update_o_auth2_kakao( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + prompt: Optional[List[ProjectOAuth2KakaoPrompt]] = None, + enabled: Optional[bool] = None, + ) -> OAuth2Kakao: + """ + Update the project OAuth2 Kakao configuration. + + Parameters + ---------- + client_id : Optional[str] + 'REST API key' of Kakao OAuth2 app. For example: 839ff5000000000000000000013206de + client_secret : Optional[str] + 'Client Secret' of Kakao OAuth2 app. For example: jLNVOK00000000000000000000yJebea. Generate it under Kakao Login > Security and set its status to enabled + prompt : Optional[List[ProjectOAuth2KakaoPrompt]] + Array of Kakao OAuth2 prompt values. 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. "create" means: prompt the user to sign up. "select_account" means: prompt the user to select an account. Pass an empty array to use the Kakao default. + enabled : Optional[bool] + 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. + Returns + ------- + OAuth2Kakao + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/project/oauth2/kakao' + api_params = {} + if client_id is not None: + api_params['clientId'] = self._normalize_value(client_id) + if client_secret is not None: + api_params['clientSecret'] = self._normalize_value(client_secret) + if prompt is not None: + api_params['prompt'] = self._normalize_value(prompt) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=OAuth2Kakao) + def update_o_auth2_keycloak( self, client_id: Optional[str] = None, @@ -2157,6 +2265,7 @@ def update_o_auth2_microsoft( application_id: Optional[str] = None, application_secret: Optional[str] = None, tenant: Optional[str] = None, + prompt: Optional[List[ProjectOAuth2MicrosoftPrompt]] = None, enabled: Optional[bool] = None, ) -> OAuth2Microsoft: """ @@ -2170,6 +2279,8 @@ def update_o_auth2_microsoft( 'Entra ID Application Secret, also known as Client Secret' of Microsoft OAuth2 app. For example: A1bC2dE3fH4iJ5kL6mN7oP8qR9sT0u tenant : Optional[str] Microsoft Entra ID tenant identifier. Use 'common', 'organizations', 'consumers' or a specific tenant ID. For example: common + prompt : Optional[List[ProjectOAuth2MicrosoftPrompt]] + Array of Microsoft OAuth2 prompt values. "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. Pass an empty array to use the Microsoft default. enabled : Optional[bool] 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. Returns @@ -2191,6 +2302,8 @@ def update_o_auth2_microsoft( api_params['applicationSecret'] = self._normalize_value(application_secret) if tenant is not None: api_params['tenant'] = self._normalize_value(tenant) + if prompt is not None: + api_params['prompt'] = self._normalize_value(prompt) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) @@ -2343,6 +2456,7 @@ def update_o_auth2_okta( client_secret: Optional[str] = None, domain: Optional[str] = None, authorization_server_id: Optional[str] = None, + prompt: Optional[List[ProjectOAuth2OktaPrompt]] = None, enabled: Optional[bool] = None, ) -> OAuth2Okta: """ @@ -2358,6 +2472,8 @@ def update_o_auth2_okta( Okta company domain. Required when enabling the provider. For example: trial-6400025.okta.com. Example of wrong value: trial-6400025-admin.okta.com, or https://trial-6400025.okta.com/ authorization_server_id : Optional[str] Custom Authorization Servers. Optional, can be left empty or unconfigured. For example: aus000000000000000h7z + prompt : Optional[List[ProjectOAuth2OktaPrompt]] + Array of Okta OAuth2 prompt values. 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. Pass an empty array to use the Okta default. enabled : Optional[bool] 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. Returns @@ -2381,6 +2497,8 @@ def update_o_auth2_okta( api_params['domain'] = self._normalize_value(domain) if authorization_server_id is not None: api_params['authorizationServerId'] = self._normalize_value(authorization_server_id) + if prompt is not None: + api_params['prompt'] = self._normalize_value(prompt) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) @@ -2601,6 +2719,7 @@ def update_o_auth2_salesforce( self, customer_key: Optional[str] = None, customer_secret: Optional[str] = None, + prompt: Optional[List[ProjectOAuth2SalesforcePrompt]] = None, enabled: Optional[bool] = None, ) -> OAuth2Salesforce: """ @@ -2612,6 +2731,8 @@ def update_o_auth2_salesforce( 'Consumer Key' of Salesforce OAuth2 app. For example: 3MVG9I0000000000000000000000000000000000000000000000000000000000000000000000000C5Aejq customer_secret : Optional[str] 'Consumer Secret' of Salesforce OAuth2 app. For example: 3w000000000000e2 + prompt : Optional[List[ProjectOAuth2SalesforcePrompt]] + Array of Salesforce OAuth2 prompt values. "login" means: prompt the user to re-authenticate. "consent" means: prompt the user for consent. Pass an empty array to use the Salesforce default. enabled : Optional[bool] 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. Returns @@ -2631,6 +2752,8 @@ def update_o_auth2_salesforce( api_params['customerKey'] = self._normalize_value(customer_key) if customer_secret is not None: api_params['customerSecret'] = self._normalize_value(customer_secret) + if prompt is not None: + api_params['prompt'] = self._normalize_value(prompt) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) @@ -2797,6 +2920,56 @@ def update_o_auth2_stripe( return self._parse_response(response, model=OAuth2Stripe) + def update_o_auth2_tik_tok( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + enabled: Optional[bool] = None, + ) -> OAuth2TikTok: + """ + Update the project OAuth2 TikTok configuration. + + Parameters + ---------- + client_id : Optional[str] + 'Client key' of TikTok OAuth2 app. For example: awz000000000tyw0 + client_secret : Optional[str] + 'Client secret' of TikTok OAuth2 app. For example: 6wXewM00000000000000000000yXnite + enabled : Optional[bool] + 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. + Returns + ------- + OAuth2TikTok + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/project/oauth2/tiktok' + api_params = {} + if client_id is not None: + api_params['clientId'] = self._normalize_value(client_id) + if client_secret is not None: + api_params['clientSecret'] = self._normalize_value(client_secret) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=OAuth2TikTok) + def update_o_auth2_tradeshift( self, oauth2_client_id: Optional[str] = None, @@ -2947,6 +3120,56 @@ def update_o_auth2_twitch( return self._parse_response(response, model=OAuth2Twitch) + def update_o_auth2_webflow( + self, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + enabled: Optional[bool] = None, + ) -> OAuth2Webflow: + """ + Update the project OAuth2 Webflow configuration. + + Parameters + ---------- + client_id : Optional[str] + 'Client ID' of Webflow OAuth2 app. For example: 8bb20000000000000000000000000000000000000000000000000000000040dd + client_secret : Optional[str] + 'Client Secret' of Webflow OAuth2 app. For example: 59bf00000000000000000000000000000000000000000000000000000000fe59 + enabled : Optional[bool] + 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. + Returns + ------- + OAuth2Webflow + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/project/oauth2/webflow' + api_params = {} + if client_id is not None: + api_params['clientId'] = self._normalize_value(client_id) + if client_secret is not None: + api_params['clientSecret'] = self._normalize_value(client_secret) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=OAuth2Webflow) + def update_o_auth2_word_press( self, client_id: Optional[str] = None, @@ -3151,6 +3374,7 @@ def update_o_auth2_zoho( self, client_id: Optional[str] = None, client_secret: Optional[str] = None, + prompt: Optional[List[ProjectOAuth2ZohoPrompt]] = None, enabled: Optional[bool] = None, ) -> OAuth2Zoho: """ @@ -3162,6 +3386,8 @@ def update_o_auth2_zoho( 'Client ID' of Zoho OAuth2 app. For example: 1000.83C178000000000000000000RPNX0B client_secret : Optional[str] 'Client Secret' of Zoho OAuth2 app. For example: fb5cac000000000000000000000000000000a68f6e + prompt : Optional[List[ProjectOAuth2ZohoPrompt]] + Array of Zoho OAuth2 prompt values. "consent" means: prompt the user for consent. Pass an empty array to use the Zoho default. enabled : Optional[bool] 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. Returns @@ -3181,6 +3407,8 @@ def update_o_auth2_zoho( api_params['clientId'] = self._normalize_value(client_id) if client_secret is not None: api_params['clientSecret'] = self._normalize_value(client_secret) + if prompt is not None: + api_params['prompt'] = self._normalize_value(prompt) if enabled is not None: api_params['enabled'] = self._normalize_value(enabled) @@ -3266,6 +3494,7 @@ def get_o_auth2_provider( OAuth2Yandex, OAuth2X, OAuth2WordPress, + OAuth2Webflow, OAuth2Twitch, OAuth2Stripe, OAuth2Spotify, @@ -3294,6 +3523,8 @@ def get_o_auth2_provider( OAuth2Okta, OAuth2Kick, OAuth2Microsoft, + OAuth2TikTok, + OAuth2Kakao, ]: """ Get a single OAuth2 provider configuration. Credential fields (client secret, p8 file, key/team IDs) are write-only and always returned empty. @@ -3304,7 +3535,7 @@ def get_o_auth2_provider( OAuth2 provider key. For example: github, google, apple. Returns ------- - Union[OAuth2Github, OAuth2Discord, OAuth2Figma, OAuth2Dropbox, OAuth2Dailymotion, OAuth2Bitbucket, OAuth2Bitly, OAuth2Box, OAuth2Autodesk, OAuth2Google, OAuth2Zoom, OAuth2Zoho, OAuth2Yandex, OAuth2X, OAuth2WordPress, OAuth2Twitch, OAuth2Stripe, OAuth2Spotify, OAuth2Slack, OAuth2Podio, OAuth2Notion, OAuth2Salesforce, OAuth2Yahoo, OAuth2HuggingFace, OAuth2Resend, OAuth2Cloudflare, OAuth2Linkedin, OAuth2Disqus, OAuth2Amazon, OAuth2Etsy, OAuth2Facebook, OAuth2Tradeshift, OAuth2Paypal, OAuth2Gitlab, OAuth2Authentik, OAuth2Auth0, OAuth2FusionAuth, OAuth2Keycloak, OAuth2Oidc, OAuth2Apple, OAuth2Okta, OAuth2Kick, OAuth2Microsoft] + Union[OAuth2Github, OAuth2Discord, OAuth2Figma, OAuth2Dropbox, OAuth2Dailymotion, OAuth2Bitbucket, OAuth2Bitly, OAuth2Box, OAuth2Autodesk, OAuth2Google, OAuth2Zoom, OAuth2Zoho, OAuth2Yandex, OAuth2X, OAuth2WordPress, OAuth2Webflow, OAuth2Twitch, OAuth2Stripe, OAuth2Spotify, OAuth2Slack, OAuth2Podio, OAuth2Notion, OAuth2Salesforce, OAuth2Yahoo, OAuth2HuggingFace, OAuth2Resend, OAuth2Cloudflare, OAuth2Linkedin, OAuth2Disqus, OAuth2Amazon, OAuth2Etsy, OAuth2Facebook, OAuth2Tradeshift, OAuth2Paypal, OAuth2Gitlab, OAuth2Authentik, OAuth2Auth0, OAuth2FusionAuth, OAuth2Keycloak, OAuth2Oidc, OAuth2Apple, OAuth2Okta, OAuth2Kick, OAuth2Microsoft, OAuth2TikTok, OAuth2Kakao] API response as one of the typed response models Raises @@ -3376,6 +3607,9 @@ def get_o_auth2_provider( if response.get('$id') == 'wordpress': return self._parse_response(response, model=OAuth2WordPress) + if response.get('$id') == 'webflow': + return self._parse_response(response, model=OAuth2Webflow) + if response.get('$id') == 'twitch': return self._parse_response(response, model=OAuth2Twitch) @@ -3460,6 +3694,12 @@ def get_o_auth2_provider( if response.get('$id') == 'microsoft': return self._parse_response(response, model=OAuth2Microsoft) + if response.get('$id') == 'tiktok': + return self._parse_response(response, model=OAuth2TikTok) + + if response.get('$id') == 'kakao': + return self._parse_response(response, model=OAuth2Kakao) + raise AppwriteException('Unable to match response to any known model') def list_platforms( @@ -3511,6 +3751,7 @@ def create_android_platform( platform_id: str, name: str, application_id: str, + fingerprints: Optional[List[str]] = None, ) -> PlatformAndroid: """ Create a new Android platform for your project. Use this endpoint to register a new Android platform where your users will run your application which will interact with the Appwrite API. @@ -3523,6 +3764,8 @@ def create_android_platform( Platform name. Max length: 128 chars. application_id : str Android application ID. Max length: 256 chars. + fingerprints : Optional[List[str]] + SHA-256 fingerprints of the certificates your app is signed with, such as "14:6D:E9:...:2B:6A". Passkeys created in the app are accepted when its signature matches one. Find them under App signing in Play Console, or with `./gradlew signingReport`. Returns ------- PlatformAndroid @@ -3545,6 +3788,8 @@ def create_android_platform( api_params['platformId'] = self._normalize_value(platform_id) api_params['name'] = self._normalize_value(name) api_params['applicationId'] = self._normalize_value(application_id) + if fingerprints is not None: + api_params['fingerprints'] = self._normalize_value(fingerprints) response = self.client.call( 'post', @@ -3564,9 +3809,10 @@ def update_android_platform( platform_id: str, name: str, application_id: str, + fingerprints: Optional[List[str]] = None, ) -> PlatformAndroid: """ - Update an Android platform by its unique ID. Use this endpoint to update the platform's name or application ID. + Update an Android platform by its unique ID. Use this endpoint to update the platform's name, application ID or signing certificate fingerprints. Parameters ---------- @@ -3576,6 +3822,8 @@ def update_android_platform( Platform name. Max length: 128 chars. application_id : str Android application ID. Max length: 256 chars. + fingerprints : Optional[List[str]] + SHA-256 fingerprints of the certificates your app is signed with, such as "14:6D:E9:...:2B:6A". Passkeys created in the app are accepted when its signature matches one. Find them under App signing in Play Console, or with `./gradlew signingReport`. Omit to keep the current list, or pass an empty array to clear it. Returns ------- PlatformAndroid @@ -3589,7 +3837,7 @@ def update_android_platform( api_path = '/project/platforms/android/{platformId}' api_params = {} - if platform_id is None: + if platform_id is None or platform_id == '': raise AppwriteException('Missing required parameter: "platform_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -3598,6 +3846,8 @@ def update_android_platform( api_path = api_path.replace('{platformId}', str(self._normalize_value(platform_id))) api_params['name'] = self._normalize_value(name) api_params['applicationId'] = self._normalize_value(application_id) + if fingerprints is not None: + api_params['fingerprints'] = self._normalize_value(fingerprints) response = self.client.call( 'put', @@ -3695,7 +3945,7 @@ def update_apple_platform( api_path = '/project/platforms/apple/{platformId}' api_params = {} - if platform_id is None: + if platform_id is None or platform_id == '': raise AppwriteException('Missing required parameter: "platform_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -3801,7 +4051,7 @@ def update_linux_platform( api_path = '/project/platforms/linux/{platformId}' api_params = {} - if platform_id is None: + if platform_id is None or platform_id == '': raise AppwriteException('Missing required parameter: "platform_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -3907,7 +4157,7 @@ def update_web_platform( api_path = '/project/platforms/web/{platformId}' api_params = {} - if platform_id is None: + if platform_id is None or platform_id == '': raise AppwriteException('Missing required parameter: "platform_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -4013,7 +4263,7 @@ def update_windows_platform( api_path = '/project/platforms/windows/{platformId}' api_params = {} - if platform_id is None: + if platform_id is None or platform_id == '': raise AppwriteException('Missing required parameter: "platform_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -4066,7 +4316,7 @@ def get_platform( api_path = '/project/platforms/{platformId}' api_params = {} - if platform_id is None: + if platform_id is None or platform_id == '': raise AppwriteException('Missing required parameter: "platform_id"') api_path = api_path.replace('{platformId}', str(self._normalize_value(platform_id))) @@ -4123,7 +4373,7 @@ def delete_platform( api_path = '/project/platforms/{platformId}' api_params = {} - if platform_id is None: + if platform_id is None or platform_id == '': raise AppwriteException('Missing required parameter: "platform_id"') api_path = api_path.replace('{platformId}', str(self._normalize_value(platform_id))) @@ -4133,6 +4383,7 @@ def delete_platform( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -4467,6 +4718,47 @@ def update_mfa_factors_policy( return self._parse_response(response, model=ProjectModel) + def update_passkey_policy( + self, + rp_id: str, + ) -> ProjectModel: + """ + Set the relying party ID passkeys are bound to: the domain of your application. Passkeys work on the project's web platforms on that domain or its subdomains, and on the domain itself for Apple apps. A localhost web platform enables passkeys for local development without a relying party ID. The relying party ID cannot change while users have passkeys, and any change invalidates ceremonies in progress. + + Parameters + ---------- + rp_id : str + Relying party ID: the domain of your application, such as `example.com`. Use `localhost` for local development, or an empty string to unset it. + Returns + ------- + ProjectModel + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/project/policies/passkey' + api_params = {} + if rp_id is None: + raise AppwriteException('Missing required parameter: "rp_id"') + api_params['rpId'] = self._normalize_value(rp_id) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=ProjectModel) + def update_password_dictionary_policy( self, enabled: bool, @@ -4590,6 +4882,101 @@ def update_password_personal_data_policy( return self._parse_response(response, model=ProjectModel) + def update_password_pwned_policy( + self, + enabled: Optional[bool] = None, + sessions: Optional[bool] = None, + users: Optional[bool] = None, + ) -> ProjectModel: + """ + Updating this policy allows you to control if passwords are checked against the Have I Been Pwned breach database. When enabled, every password a user signs up, signs in or resets with is checked and the result is recorded on the user as `passwordPwned`. On its own the policy only records. Enable `users` to reject a breached password when a user signs up or sets a new password, and `sessions` to refuse a sign-in with a breached password until it is reset. Only the first five characters of the password hash are ever shared with the service. Options left out keep their current value. + + Parameters + ---------- + enabled : Optional[bool] + Toggle password pwned policy. Set to true to check passwords against known data breaches and record the result on the user, or false to never check. Default is true. On its own this only records; use `users` and `sessions` to block. When changing this policy, existing passwords remain valid. + sessions : Optional[bool] + Whether a sign-in with a breached password is refused until the password is reset. Default is false, which allows the sign-in and only records the result. + users : Optional[bool] + Whether a breached password is rejected when a user signs up or sets a new password. Default is false, which allows the password and only records the result. + Returns + ------- + ProjectModel + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/project/policies/password-pwned' + api_params = {} + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if sessions is not None: + api_params['sessions'] = self._normalize_value(sessions) + if users is not None: + api_params['users'] = self._normalize_value(users) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=ProjectModel) + + def update_password_rotation_policy( + self, + enabled: Optional[bool] = None, + max_age: Optional[float] = None, + ) -> ProjectModel: + """ + Require a password reset when an email/password sign-in uses a password older than the configured maximum age. Options left out keep their current value. + + Parameters + ---------- + enabled : Optional[bool] + Enable password rotation. Disabled by default. + max_age : Optional[float] + Maximum password age in seconds. Minimum allowed value is 86400 seconds (1 day), and maximum is 10 years, which is 315360000 seconds. Defaults to 1 year, which is 31536000 seconds. + Returns + ------- + ProjectModel + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/project/policies/password-rotation' + api_params = {} + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if max_age is not None: + api_params['maxAge'] = self._normalize_value(max_age) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=ProjectModel) + def update_password_strength_policy( self, min: Optional[float] = None, @@ -4861,6 +5248,8 @@ def get_policy( PolicyPasswordHistory, PolicyPasswordStrength, PolicyPasswordPersonalData, + PolicyPasswordPwned, + PolicyPasswordRotation, PolicySessionAlert, PolicySessionDuration, PolicySessionInvalidation, @@ -4872,6 +5261,7 @@ def get_policy( PolicyDenyDisposableEmail, PolicyDenyFreeEmail, PolicyDenyCorporateEmail, + PolicyPasskey, ]: """ Get a policy by its unique ID. This endpoint returns the current configuration for the requested project policy. @@ -4879,10 +5269,10 @@ def get_policy( Parameters ---------- policy_id : ProjectPolicyId - 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. + Policy ID. Can be one of: password-dictionary, password-history, password-strength, password-personal-data, password-pwned, password-rotation, 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, passkey. Returns ------- - Union[PolicyPasswordDictionary, PolicyPasswordHistory, PolicyPasswordStrength, PolicyPasswordPersonalData, PolicySessionAlert, PolicySessionDuration, PolicySessionInvalidation, PolicySessionLimit, PolicyUserLimit, PolicyMembershipPrivacy, PolicyMfaFactors, PolicyDenyAliasedEmail, PolicyDenyDisposableEmail, PolicyDenyFreeEmail, PolicyDenyCorporateEmail] + Union[PolicyPasswordDictionary, PolicyPasswordHistory, PolicyPasswordStrength, PolicyPasswordPersonalData, PolicyPasswordPwned, PolicyPasswordRotation, PolicySessionAlert, PolicySessionDuration, PolicySessionInvalidation, PolicySessionLimit, PolicyUserLimit, PolicyMembershipPrivacy, PolicyMfaFactors, PolicyDenyAliasedEmail, PolicyDenyDisposableEmail, PolicyDenyFreeEmail, PolicyDenyCorporateEmail, PolicyPasskey] API response as one of the typed response models Raises @@ -4921,6 +5311,12 @@ def get_policy( if response.get('$id') == 'password-personal-data': return self._parse_response(response, model=PolicyPasswordPersonalData) + if response.get('$id') == 'password-pwned': + return self._parse_response(response, model=PolicyPasswordPwned) + + if response.get('$id') == 'password-rotation': + return self._parse_response(response, model=PolicyPasswordRotation) + if response.get('$id') == 'session-alert': return self._parse_response(response, model=PolicySessionAlert) @@ -4954,6 +5350,9 @@ def get_policy( if response.get('$id') == 'deny-corporate-email': return self._parse_response(response, model=PolicyDenyCorporateEmail) + if response.get('$id') == 'passkey': + return self._parse_response(response, model=PolicyPasskey) + raise AppwriteException('Unable to match response to any known model') def update_protocol( @@ -5169,6 +5568,7 @@ def create_smtp_test( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -5236,7 +5636,7 @@ def update_email_template( Parameters ---------- template_id : ProjectEmailTemplateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession + Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession, otpVerification, otpRecovery locale : Optional[ProjectEmailTemplateLocale] Custom email template locale. If left empty, the fallback locale (en) will be used. subject : Optional[str] @@ -5306,7 +5706,7 @@ def get_email_template( Parameters ---------- template_id : ProjectEmailTemplateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession + Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession, otpVerification, otpRecovery locale : Optional[ProjectEmailTemplateLocale] Custom email template locale. If left empty, the fallback locale (en) will be used. Returns @@ -5466,7 +5866,7 @@ def get_variable( api_path = '/project/variables/{variableId}' api_params = {} - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) @@ -5515,7 +5915,7 @@ def update_variable( api_path = '/project/variables/{variableId}' api_params = {} - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) if key is not None: @@ -5562,7 +5962,7 @@ def delete_variable( api_path = '/project/variables/{variableId}' api_params = {} - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) @@ -5572,6 +5972,7 @@ def delete_variable( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) diff --git a/appwrite/services/proxy.py b/appwrite/services/proxy.py index 0429a4e9..9f5d012b 100644 --- a/appwrite/services/proxy.py +++ b/appwrite/services/proxy.py @@ -27,6 +27,8 @@ def create_invalidation( Depending on type, the invalidation purges a single cache tag, a single URL path, or all cached content for the domain. + Domains that route to a function do not support cache invalidation. + Parameters ---------- domain : str @@ -356,7 +358,7 @@ def get_rule( api_path = '/proxy/rules/{ruleId}' api_params = {} - if rule_id is None: + if rule_id is None or rule_id == '': raise AppwriteException('Missing required parameter: "rule_id"') api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) @@ -396,7 +398,7 @@ def delete_rule( api_path = '/proxy/rules/{ruleId}' api_params = {} - if rule_id is None: + if rule_id is None or rule_id == '': raise AppwriteException('Missing required parameter: "rule_id"') api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) @@ -406,6 +408,7 @@ def delete_rule( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -436,7 +439,7 @@ def update_rule_status( api_path = '/proxy/rules/{ruleId}/status' api_params = {} - if rule_id is None: + if rule_id is None or rule_id == '': raise AppwriteException('Missing required parameter: "rule_id"') api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) diff --git a/appwrite/services/sites.py b/appwrite/services/sites.py index 36a29462..952e4b27 100644 --- a/appwrite/services/sites.py +++ b/appwrite/services/sites.py @@ -238,9 +238,15 @@ def create( def list_frameworks( self, + total: Optional[bool] = None, ) -> FrameworkList: """ Get a list of all frameworks that are currently available on the server instance. + + Parameters + ---------- + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- FrameworkList @@ -254,6 +260,8 @@ def list_frameworks( api_path = '/sites/frameworks' api_params = {} + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -270,6 +278,7 @@ def list_frameworks( def list_specifications( self, type: Optional[str] = None, + total: Optional[bool] = None, ) -> SpecificationList: """ List allowed site specifications for this instance. @@ -278,6 +287,8 @@ def list_specifications( ---------- type : Optional[str] Specification type to list. Can be one of: runtimes, builds. Defaults to runtimes. + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- SpecificationList @@ -293,6 +304,8 @@ def list_specifications( api_params = {} if type is not None: api_params['type'] = self._normalize_value(type) + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -330,7 +343,7 @@ def get( api_path = '/sites/{siteId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) @@ -439,7 +452,7 @@ def update( api_path = '/sites/{siteId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -528,7 +541,7 @@ def delete( api_path = '/sites/{siteId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) @@ -538,6 +551,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -571,7 +585,7 @@ def update_site_deployment( api_path = '/sites/{siteId}/deployment' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') if deployment_id is None: raise AppwriteException('Missing required parameter: "deployment_id"') @@ -624,7 +638,7 @@ def list_deployments( api_path = '/sites/{siteId}/deployments' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) if queries is not None: @@ -689,7 +703,7 @@ def create_deployment( api_path = '/sites/{siteId}/deployments' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') if code is None: raise AppwriteException('Missing required parameter: "code"') @@ -721,6 +735,7 @@ def create_deployment( param_name, on_progress, upload_id, + method='post', ) return self._parse_response(response, model=Deployment) @@ -752,7 +767,7 @@ def create_duplicate_deployment( api_path = '/sites/{siteId}/deployments/duplicate' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') if deployment_id is None: raise AppwriteException('Missing required parameter: "deployment_id"') @@ -816,7 +831,7 @@ def create_template_deployment( api_path = '/sites/{siteId}/deployments/template' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') if repository is None: raise AppwriteException('Missing required parameter: "repository"') @@ -885,7 +900,7 @@ def create_vcs_deployment( api_path = '/sites/{siteId}/deployments/vcs' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') if type is None: raise AppwriteException('Missing required parameter: "type"') @@ -937,9 +952,9 @@ def get_deployment( api_path = '/sites/{siteId}/deployments/{deploymentId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if deployment_id is None: + if deployment_id is None or deployment_id == '': raise AppwriteException('Missing required parameter: "deployment_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{deploymentId}', str(self._normalize_value(deployment_id))) @@ -983,9 +998,9 @@ def delete_deployment( api_path = '/sites/{siteId}/deployments/{deploymentId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if deployment_id is None: + if deployment_id is None or deployment_id == '': raise AppwriteException('Missing required parameter: "deployment_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{deploymentId}', str(self._normalize_value(deployment_id))) @@ -996,6 +1011,7 @@ def delete_deployment( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1035,9 +1051,9 @@ def get_deployment_download( api_path = '/sites/{siteId}/deployments/{deploymentId}/download' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if deployment_id is None: + if deployment_id is None or deployment_id == '': raise AppwriteException('Missing required parameter: "deployment_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{deploymentId}', str(self._normalize_value(deployment_id))) @@ -1085,9 +1101,9 @@ def update_deployment_status( api_path = '/sites/{siteId}/deployments/{deploymentId}/status' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if deployment_id is None: + if deployment_id is None or deployment_id == '': raise AppwriteException('Missing required parameter: "deployment_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{deploymentId}', str(self._normalize_value(deployment_id))) @@ -1135,7 +1151,7 @@ def list_logs( api_path = '/sites/{siteId}/logs' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) if queries is not None: @@ -1182,9 +1198,9 @@ def get_log( api_path = '/sites/{siteId}/logs/{logId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if log_id is None: + if log_id is None or log_id == '': raise AppwriteException('Missing required parameter: "log_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{logId}', str(self._normalize_value(log_id))) @@ -1228,9 +1244,9 @@ def delete_log( api_path = '/sites/{siteId}/logs/{logId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if log_id is None: + if log_id is None or log_id == '': raise AppwriteException('Missing required parameter: "log_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{logId}', str(self._normalize_value(log_id))) @@ -1278,7 +1294,7 @@ def list_variables( api_path = '/sites/{siteId}/variables' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) if queries is not None: @@ -1334,7 +1350,7 @@ def create_variable( api_path = '/sites/{siteId}/variables' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') if variable_id is None: raise AppwriteException('Missing required parameter: "variable_id"') @@ -1389,9 +1405,9 @@ def get_variable( api_path = '/sites/{siteId}/variables/{variableId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) @@ -1444,9 +1460,9 @@ def update_variable( api_path = '/sites/{siteId}/variables/{variableId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) @@ -1497,9 +1513,9 @@ def delete_variable( api_path = '/sites/{siteId}/variables/{variableId}' api_params = {} - if site_id is None: + if site_id is None or site_id == '': raise AppwriteException('Missing required parameter: "site_id"') - if variable_id is None: + if variable_id is None or variable_id == '': raise AppwriteException('Missing required parameter: "variable_id"') api_path = api_path.replace('{siteId}', str(self._normalize_value(site_id))) api_path = api_path.replace('{variableId}', str(self._normalize_value(variable_id))) @@ -1510,6 +1526,7 @@ def delete_variable( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) diff --git a/appwrite/services/storage.py b/appwrite/services/storage.py index 7e4f647d..a095f6d2 100644 --- a/appwrite/services/storage.py +++ b/appwrite/services/storage.py @@ -183,7 +183,7 @@ def get_bucket( api_path = '/storage/buckets/{bucketId}' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) @@ -253,7 +253,7 @@ def update_bucket( api_path = '/storage/buckets/{bucketId}' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -315,7 +315,7 @@ def delete_bucket( api_path = '/storage/buckets/{bucketId}' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) @@ -325,6 +325,7 @@ def delete_bucket( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -364,7 +365,7 @@ def list_files( api_path = '/storage/buckets/{bucketId}/files' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) if queries is not None: @@ -432,7 +433,7 @@ def create_file( api_path = '/storage/buckets/{bucketId}/files' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') if file_id is None: raise AppwriteException('Missing required parameter: "file_id"') @@ -462,6 +463,7 @@ def create_file( param_name, on_progress, upload_id, + method='post', ) return self._parse_response(response, model=File) @@ -493,9 +495,9 @@ def get_file( api_path = '/storage/buckets/{bucketId}/files/{fileId}' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') - if file_id is None: + if file_id is None or file_id == '': raise AppwriteException('Missing required parameter: "file_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) api_path = api_path.replace('{fileId}', str(self._normalize_value(file_id))) @@ -545,9 +547,9 @@ def update_file( api_path = '/storage/buckets/{bucketId}/files/{fileId}' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') - if file_id is None: + if file_id is None or file_id == '': raise AppwriteException('Missing required parameter: "file_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) api_path = api_path.replace('{fileId}', str(self._normalize_value(file_id))) @@ -596,9 +598,9 @@ def delete_file( api_path = '/storage/buckets/{bucketId}/files/{fileId}' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') - if file_id is None: + if file_id is None or file_id == '': raise AppwriteException('Missing required parameter: "file_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) api_path = api_path.replace('{fileId}', str(self._normalize_value(file_id))) @@ -609,6 +611,7 @@ def delete_file( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -645,9 +648,9 @@ def get_file_download( api_path = '/storage/buckets/{bucketId}/files/{fileId}/download' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') - if file_id is None: + if file_id is None or file_id == '': raise AppwriteException('Missing required parameter: "file_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) api_path = api_path.replace('{fileId}', str(self._normalize_value(file_id))) @@ -697,7 +700,7 @@ def get_file_preview( height : Optional[float] Resize preview image height, Pass an integer between 0 to 4000. gravity : Optional[ImageGravity] - Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right + Image crop gravity. Can be one of auto,center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right quality : Optional[float] Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality. border_width : Optional[float] @@ -729,9 +732,9 @@ def get_file_preview( api_path = '/storage/buckets/{bucketId}/files/{fileId}/preview' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') - if file_id is None: + if file_id is None or file_id == '': raise AppwriteException('Missing required parameter: "file_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) api_path = api_path.replace('{fileId}', str(self._normalize_value(file_id))) @@ -802,9 +805,9 @@ def get_file_view( api_path = '/storage/buckets/{bucketId}/files/{fileId}/view' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') - if file_id is None: + if file_id is None or file_id == '': raise AppwriteException('Missing required parameter: "file_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) api_path = api_path.replace('{fileId}', str(self._normalize_value(file_id))) diff --git a/appwrite/services/tables_db.py b/appwrite/services/tables_db.py index f7e8ed2e..551bc649 100644 --- a/appwrite/services/tables_db.py +++ b/appwrite/services/tables_db.py @@ -172,7 +172,7 @@ def list_specifications( self, ) -> DedicatedDatabaseSpecificationList: """ - 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. + List the dedicated database specifications available on the current plan. Each specification reports its resource limits, its own prices and overage rates, and whether it is enabled for the organization. Returns ------- DedicatedDatabaseSpecificationList @@ -202,6 +202,7 @@ def list_specifications( def list_transactions( self, queries: Optional[List[str]] = None, + total: Optional[bool] = None, ) -> TransactionList: """ List transactions across all databases. @@ -210,6 +211,8 @@ def list_transactions( ---------- queries : Optional[List[str]] Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- TransactionList @@ -225,6 +228,8 @@ def list_transactions( api_params = {} if queries is not None: api_params['queries'] = self._normalize_value(queries) + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -302,7 +307,7 @@ def get_transaction( api_path = '/tablesdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) @@ -348,7 +353,7 @@ def update_transaction( api_path = '/tablesdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) if commit is not None: @@ -393,7 +398,7 @@ def delete_transaction( api_path = '/tablesdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) @@ -403,6 +408,7 @@ def delete_transaction( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -436,7 +442,7 @@ def create_operations( api_path = '/tablesdb/transactions/{transactionId}/operations' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) if operations is not None: @@ -479,7 +485,7 @@ def get( api_path = '/tablesdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -534,7 +540,7 @@ def update( api_path = '/tablesdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if name is not None: @@ -585,7 +591,7 @@ def delete( api_path = '/tablesdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -595,6 +601,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -628,7 +635,7 @@ def create_failover( api_path = '/tablesdb/{databaseId}/failovers' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if target_replica_id is not None: @@ -671,7 +678,7 @@ def list_migrations( api_path = '/tablesdb/{databaseId}/migrations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -717,7 +724,7 @@ def create_migration( api_path = '/tablesdb/{databaseId}/migrations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if specification is None: raise AppwriteException('Missing required parameter: "specification"') @@ -766,9 +773,9 @@ def get_migration( api_path = '/tablesdb/{databaseId}/migrations/{migrationId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if migration_id is None: + if migration_id is None or migration_id == '': raise AppwriteException('Missing required parameter: "migration_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{migrationId}', str(self._normalize_value(migration_id))) @@ -812,9 +819,9 @@ def delete_migration( api_path = '/tablesdb/{databaseId}/migrations/{migrationId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if migration_id is None: + if migration_id is None or migration_id == '': raise AppwriteException('Missing required parameter: "migration_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{migrationId}', str(self._normalize_value(migration_id))) @@ -859,9 +866,9 @@ def create_cutover( api_path = '/tablesdb/{databaseId}/migrations/{migrationId}/cutovers' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if migration_id is None: + if migration_id is None or migration_id == '': raise AppwriteException('Missing required parameter: "migration_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{migrationId}', str(self._normalize_value(migration_id))) @@ -912,7 +919,7 @@ def list_operations( api_path = '/tablesdb/{databaseId}/operations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -958,7 +965,7 @@ def get_replicas( api_path = '/tablesdb/{databaseId}/replicas' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -998,7 +1005,7 @@ def get_status( api_path = '/tablesdb/{databaseId}/status' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -1047,7 +1054,7 @@ def list_tables( api_path = '/tablesdb/{databaseId}/tables' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -1114,7 +1121,7 @@ def create_table( api_path = '/tablesdb/{databaseId}/tables' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if table_id is None: raise AppwriteException('Missing required parameter: "table_id"') @@ -1174,9 +1181,9 @@ def get_table( api_path = '/tablesdb/{databaseId}/tables/{tableId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -1235,9 +1242,9 @@ def update_table( api_path = '/tablesdb/{databaseId}/tables/{tableId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -1292,9 +1299,9 @@ def delete_table( api_path = '/tablesdb/{databaseId}/tables/{tableId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -1305,6 +1312,7 @@ def delete_table( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1344,9 +1352,9 @@ def list_columns( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -1412,9 +1420,9 @@ def create_big_int_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/bigint' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1491,11 +1499,11 @@ def update_big_int_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/bigint/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1563,9 +1571,9 @@ def create_boolean_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/boolean' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1632,11 +1640,11 @@ def update_boolean_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/boolean/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1700,9 +1708,9 @@ def create_datetime_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/datetime' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1769,11 +1777,11 @@ def update_datetime_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/datetime/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1837,9 +1845,9 @@ def create_email_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/email' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1906,11 +1914,11 @@ def update_email_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/email/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -1977,9 +1985,9 @@ def create_enum_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/enum' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2052,11 +2060,11 @@ def update_enum_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/enum/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if elements is None: raise AppwriteException('Missing required parameter: "elements"') @@ -2129,9 +2137,9 @@ def create_float_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/float' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2208,11 +2216,11 @@ def update_float_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/float/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2286,9 +2294,9 @@ def create_integer_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/integer' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2365,11 +2373,11 @@ def update_integer_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/integer/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2437,9 +2445,9 @@ def create_ip_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/ip' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2506,11 +2514,11 @@ def update_ip_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/ip/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2571,9 +2579,9 @@ def create_line_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/line' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2638,11 +2646,11 @@ def update_line_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/line/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2710,9 +2718,9 @@ def create_longtext_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/longtext' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2781,11 +2789,11 @@ def update_longtext_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/longtext/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2852,9 +2860,9 @@ def create_mediumtext_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/mediumtext' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -2923,11 +2931,11 @@ def update_mediumtext_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/mediumtext/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -2988,9 +2996,9 @@ def create_point_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/point' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3055,11 +3063,11 @@ def update_point_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/point/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3121,9 +3129,9 @@ def create_polygon_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/polygon' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3188,11 +3196,11 @@ def update_polygon_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/polygon/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3263,9 +3271,9 @@ def create_relationship_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/relationship' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if related_table_id is None: raise AppwriteException('Missing required parameter: "related_table_id"') @@ -3297,6 +3305,69 @@ def create_relationship_column( return self._parse_response(response, model=ColumnRelationship) + def update_relationship_column( + self, + database_id: str, + table_id: str, + key: str, + on_delete: Optional[RelationMutate] = None, + new_key: Optional[str] = None, + ) -> ColumnRelationship: + """ + Update relationship column. [Learn more about relationship columns](https://appwrite.io/docs/databases-relationships#relationship-columns). + + Parameters + ---------- + database_id : str + Database ID. + table_id : str + Table ID. + key : str + Column Key. + on_delete : Optional[RelationMutate] + Delete constraint. Possible values are: cascade, restrict, setNull. + new_key : Optional[str] + New Column Key. + Returns + ------- + ColumnRelationship + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/relationship/{key}' + api_params = {} + if database_id is None or database_id == '': + raise AppwriteException('Missing required parameter: "database_id"') + if table_id is None or table_id == '': + raise AppwriteException('Missing required parameter: "table_id"') + if key is None or key == '': + raise AppwriteException('Missing required parameter: "key"') + api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) + api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) + api_path = api_path.replace('{key}', str(self._normalize_value(key))) + if on_delete is not None: + api_params['onDelete'] = self._normalize_value(on_delete) + if new_key is not None: + api_params['newKey'] = self._normalize_value(new_key) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=ColumnRelationship) + @deprecated("This API has been deprecated since 1.9.0. Please use `tablesDB.create_text_column` instead.") def create_string_column( self, @@ -3345,9 +3416,9 @@ def create_string_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/string' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3425,11 +3496,11 @@ def update_string_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/string/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3498,9 +3569,9 @@ def create_text_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/text' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3569,11 +3640,11 @@ def update_text_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/text/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3637,9 +3708,9 @@ def create_url_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/url' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3706,11 +3777,11 @@ def update_url_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/url/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3780,9 +3851,9 @@ def create_varchar_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/varchar' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -3857,11 +3928,11 @@ def update_varchar_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/varchar/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') if required is None: raise AppwriteException('Missing required parameter: "required"') @@ -3895,6 +3966,7 @@ def get_column( key: str, ) -> Union[ ColumnBoolean, + ColumnBigint, ColumnInteger, ColumnFloat, ColumnEmail, @@ -3903,6 +3975,13 @@ def get_column( ColumnIp, ColumnDatetime, ColumnRelationship, + ColumnPoint, + ColumnLine, + ColumnPolygon, + ColumnVarchar, + ColumnText, + ColumnMediumtext, + ColumnLongtext, ColumnString, ]: """ @@ -3918,7 +3997,7 @@ def get_column( Column Key. Returns ------- - Union[ColumnBoolean, ColumnInteger, ColumnFloat, ColumnEmail, ColumnEnum, ColumnUrl, ColumnIp, ColumnDatetime, ColumnRelationship, ColumnString] + Union[ColumnBoolean, ColumnBigint, ColumnInteger, ColumnFloat, ColumnEmail, ColumnEnum, ColumnUrl, ColumnIp, ColumnDatetime, ColumnRelationship, ColumnPoint, ColumnLine, ColumnPolygon, ColumnVarchar, ColumnText, ColumnMediumtext, ColumnLongtext, ColumnString] API response as one of the typed response models Raises @@ -3929,11 +4008,11 @@ def get_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -3966,6 +4045,9 @@ def get_column( if response.get('type') == 'boolean': return self._parse_response(response, model=ColumnBoolean) + if response.get('type') == 'bigint': + return self._parse_response(response, model=ColumnBigint) + if response.get('type') == 'integer': return self._parse_response(response, model=ColumnInteger) @@ -3978,6 +4060,27 @@ def get_column( if response.get('type') == 'relationship': return self._parse_response(response, model=ColumnRelationship) + if response.get('type') == 'point': + return self._parse_response(response, model=ColumnPoint) + + if response.get('type') == 'linestring': + return self._parse_response(response, model=ColumnLine) + + if response.get('type') == 'polygon': + return self._parse_response(response, model=ColumnPolygon) + + if response.get('type') == 'varchar': + return self._parse_response(response, model=ColumnVarchar) + + if response.get('type') == 'text': + return self._parse_response(response, model=ColumnText) + + if response.get('type') == 'mediumtext': + return self._parse_response(response, model=ColumnMediumtext) + + if response.get('type') == 'longtext': + return self._parse_response(response, model=ColumnLongtext) + if response.get('type') == 'string': return self._parse_response(response, model=ColumnString) @@ -4013,11 +4116,11 @@ def delete_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4026,68 +4129,6 @@ def delete_column( response = self.client.call( 'delete', api_path, - { - 'X-Appwrite-Project': self.client.get_config('project'), - 'content-type': 'application/json', - }, - api_params, - ) - - return response - - def update_relationship_column( - self, - database_id: str, - table_id: str, - key: str, - on_delete: Optional[RelationMutate] = None, - new_key: Optional[str] = None, - ) -> ColumnRelationship: - """ - Update relationship column. [Learn more about relationship columns](https://appwrite.io/docs/databases-relationships#relationship-columns). - - Parameters - ---------- - database_id : str - Database ID. - table_id : str - Table ID. - key : str - Column Key. - on_delete : Optional[RelationMutate] - Delete constraint. Possible values are: cascade, restrict, setNull. - new_key : Optional[str] - New Column Key. - Returns - ------- - ColumnRelationship - API response as a typed Pydantic model - - Raises - ------ - AppwriteException - If API request fails - """ - - api_path = '/tablesdb/{databaseId}/tables/{tableId}/columns/{key}/relationship' - api_params = {} - if database_id is None: - raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: - raise AppwriteException('Missing required parameter: "table_id"') - if key is None: - raise AppwriteException('Missing required parameter: "key"') - api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) - api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) - api_path = api_path.replace('{key}', str(self._normalize_value(key))) - if on_delete is not None: - api_params['onDelete'] = self._normalize_value(on_delete) - if new_key is not None: - api_params['newKey'] = self._normalize_value(new_key) - - response = self.client.call( - 'patch', - api_path, { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', @@ -4096,7 +4137,7 @@ def update_relationship_column( api_params, ) - return self._parse_response(response, model=ColumnRelationship) + return response def list_indexes( self, @@ -4131,9 +4172,9 @@ def list_indexes( api_path = '/tablesdb/{databaseId}/tables/{tableId}/indexes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4197,9 +4238,9 @@ def create_index( api_path = '/tablesdb/{databaseId}/tables/{tableId}/indexes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -4260,11 +4301,11 @@ def get_index( api_path = '/tablesdb/{databaseId}/tables/{tableId}/indexes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4312,11 +4353,11 @@ def delete_index( api_path = '/tablesdb/{databaseId}/tables/{tableId}/indexes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4328,6 +4369,7 @@ def delete_index( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -4377,9 +4419,9 @@ def list_rows( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4447,9 +4489,9 @@ def create_row( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if row_id is None: raise AppwriteException('Missing required parameter: "row_id"') @@ -4514,9 +4556,9 @@ def create_rows( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if rows is None: raise AppwriteException('Missing required parameter: "rows"') @@ -4576,9 +4618,9 @@ def upsert_rows( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') if rows is None: raise AppwriteException('Missing required parameter: "rows"') @@ -4641,9 +4683,9 @@ def update_rows( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4704,9 +4746,9 @@ def delete_rows( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4768,11 +4810,11 @@ def get_row( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if row_id is None: + if row_id is None or row_id == '': raise AppwriteException('Missing required parameter: "row_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4837,11 +4879,11 @@ def upsert_row( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if row_id is None: + if row_id is None or row_id == '': raise AppwriteException('Missing required parameter: "row_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4909,11 +4951,11 @@ def update_row( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if row_id is None: + if row_id is None or row_id == '': raise AppwriteException('Missing required parameter: "row_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4971,11 +5013,11 @@ def delete_row( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if row_id is None: + if row_id is None or row_id == '': raise AppwriteException('Missing required parameter: "row_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -4989,6 +5031,7 @@ def delete_row( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -5041,13 +5084,13 @@ def decrement_row_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}/{column}/decrement' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if row_id is None: + if row_id is None or row_id == '': raise AppwriteException('Missing required parameter: "row_id"') - if column is None: + if column is None or column == '': raise AppwriteException('Missing required parameter: "column"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) @@ -5119,13 +5162,13 @@ def increment_row_column( api_path = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}/{column}/increment' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if table_id is None: + if table_id is None or table_id == '': raise AppwriteException('Missing required parameter: "table_id"') - if row_id is None: + if row_id is None or row_id == '': raise AppwriteException('Missing required parameter: "row_id"') - if column is None: + if column is None or column == '': raise AppwriteException('Missing required parameter: "column"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{tableId}', str(self._normalize_value(table_id))) diff --git a/appwrite/services/teams.py b/appwrite/services/teams.py index 9df2eb7e..94bc8702 100644 --- a/appwrite/services/teams.py +++ b/appwrite/services/teams.py @@ -89,7 +89,7 @@ def create( name : str Team name. Max length: 128 chars. roles : Optional[List[str]] - Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 32 characters long. + Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. 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. model_type : Type[T], optional Pydantic model class for the user-defined data. Defaults to dict for backward compatibility. @@ -156,7 +156,7 @@ def get( api_path = '/teams/{teamId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) @@ -203,7 +203,7 @@ def update_name( api_path = '/teams/{teamId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -247,7 +247,7 @@ def delete( api_path = '/teams/{teamId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) @@ -257,6 +257,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -293,7 +294,7 @@ def list_installations( api_path = '/teams/{teamId}/installations' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) if queries is not None: @@ -343,7 +344,7 @@ def create_installation( api_path = '/teams/{teamId}/installations' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') if app_id is None: raise AppwriteException('Missing required parameter: "app_id"') @@ -392,9 +393,9 @@ def get_installation( api_path = '/teams/{teamId}/installations/{installationId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) @@ -441,9 +442,9 @@ def update_installation( api_path = '/teams/{teamId}/installations/{installationId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) @@ -490,9 +491,9 @@ def delete_installation( api_path = '/teams/{teamId}/installations/{installationId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') - if installation_id is None: + if installation_id is None or installation_id == '': raise AppwriteException('Missing required parameter: "installation_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) api_path = api_path.replace('{installationId}', str(self._normalize_value(installation_id))) @@ -543,7 +544,7 @@ def list_memberships( api_path = '/teams/{teamId}/memberships' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) if queries is not None: @@ -569,6 +570,7 @@ def create_membership( self, team_id: str, roles: List[str], + membership_id: Optional[str] = None, email: Optional[str] = None, user_id: Optional[str] = None, phone: Optional[str] = None, @@ -590,6 +592,8 @@ def create_membership( Team ID. roles : List[str] Array of strings. Use this param to set the user roles in the team. 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. + membership_id : Optional[str] + Membership 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. email : Optional[str] Email of the new team member. user_id : Optional[str] @@ -613,11 +617,13 @@ def create_membership( api_path = '/teams/{teamId}/memberships' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') if roles is None: raise AppwriteException('Missing required parameter: "roles"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) + if membership_id is not None: + api_params['membershipId'] = self._normalize_value(membership_id) if email is not None: api_params['email'] = self._normalize_value(email) if user_id is not None: @@ -670,9 +676,9 @@ def get_membership( api_path = '/teams/{teamId}/memberships/{membershipId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') - if membership_id is None: + if membership_id is None or membership_id == '': raise AppwriteException('Missing required parameter: "membership_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) api_path = api_path.replace('{membershipId}', str(self._normalize_value(membership_id))) @@ -719,9 +725,9 @@ def update_membership( api_path = '/teams/{teamId}/memberships/{membershipId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') - if membership_id is None: + if membership_id is None or membership_id == '': raise AppwriteException('Missing required parameter: "membership_id"') if roles is None: raise AppwriteException('Missing required parameter: "roles"') @@ -769,9 +775,9 @@ def delete_membership( api_path = '/teams/{teamId}/memberships/{membershipId}' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') - if membership_id is None: + if membership_id is None or membership_id == '': raise AppwriteException('Missing required parameter: "membership_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) api_path = api_path.replace('{membershipId}', str(self._normalize_value(membership_id))) @@ -782,6 +788,7 @@ def delete_membership( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -823,9 +830,9 @@ def update_membership_status( api_path = '/teams/{teamId}/memberships/{membershipId}/status' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') - if membership_id is None: + if membership_id is None or membership_id == '': raise AppwriteException('Missing required parameter: "membership_id"') if user_id is None: raise AppwriteException('Missing required parameter: "user_id"') @@ -877,7 +884,7 @@ def get_prefs( api_path = '/teams/{teamId}/prefs' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') api_path = api_path.replace('{teamId}', str(self._normalize_value(team_id))) @@ -924,7 +931,7 @@ def update_prefs( api_path = '/teams/{teamId}/prefs' api_params = {} - if team_id is None: + if team_id is None or team_id == '': raise AppwriteException('Missing required parameter: "team_id"') if prefs is None: raise AppwriteException('Missing required parameter: "prefs"') diff --git a/appwrite/services/tokens.py b/appwrite/services/tokens.py index d3c9eae4..b3edf492 100644 --- a/appwrite/services/tokens.py +++ b/appwrite/services/tokens.py @@ -45,9 +45,9 @@ def list( api_path = '/tokens/buckets/{bucketId}/files/{fileId}' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') - if file_id is None: + if file_id is None or file_id == '': raise AppwriteException('Missing required parameter: "file_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) api_path = api_path.replace('{fileId}', str(self._normalize_value(file_id))) @@ -98,9 +98,9 @@ def create_file_token( api_path = '/tokens/buckets/{bucketId}/files/{fileId}' api_params = {} - if bucket_id is None: + if bucket_id is None or bucket_id == '': raise AppwriteException('Missing required parameter: "bucket_id"') - if file_id is None: + if file_id is None or file_id == '': raise AppwriteException('Missing required parameter: "file_id"') api_path = api_path.replace('{bucketId}', str(self._normalize_value(bucket_id))) api_path = api_path.replace('{fileId}', str(self._normalize_value(file_id))) @@ -144,7 +144,7 @@ def get( api_path = '/tokens/{tokenId}' api_params = {} - if token_id is None: + if token_id is None or token_id == '': raise AppwriteException('Missing required parameter: "token_id"') api_path = api_path.replace('{tokenId}', str(self._normalize_value(token_id))) @@ -187,7 +187,7 @@ def update( api_path = '/tokens/{tokenId}' api_params = {} - if token_id is None: + if token_id is None or token_id == '': raise AppwriteException('Missing required parameter: "token_id"') api_path = api_path.replace('{tokenId}', str(self._normalize_value(token_id))) if expire is not None: @@ -230,7 +230,7 @@ def delete( api_path = '/tokens/{tokenId}' api_params = {} - if token_id is None: + if token_id is None or token_id == '': raise AppwriteException('Missing required parameter: "token_id"') api_path = api_path.replace('{tokenId}', str(self._normalize_value(token_id))) @@ -240,6 +240,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) diff --git a/appwrite/services/users.py b/appwrite/services/users.py index 1c7ffc67..6e89654b 100644 --- a/appwrite/services/users.py +++ b/appwrite/services/users.py @@ -8,12 +8,13 @@ from ..models.identity_list import IdentityList from ..enums.password_hash import PasswordHash from ..models.jwt import Jwt -from ..models.log_list import LogList from ..models.membership_list import MembershipList from ..enums.authenticator_type import AuthenticatorType from ..models.mfa_challenge_secret import MfaChallengeSecret from ..models.mfa_factors import MfaFactors from ..models.mfa_recovery_codes import MfaRecoveryCodes +from ..models.passkey_list import PasskeyList +from ..models.passkey import Passkey from ..models.preferences import Preferences from ..models.session_list import SessionList from ..models.session import Session @@ -43,7 +44,7 @@ def list( Parameters ---------- queries : Optional[List[str]] - 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 + 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, passwordPwned, labels, impersonator, accessedAt search : Optional[str] Search term to filter your list results. Max length: 256 chars. total : Optional[bool] @@ -345,7 +346,7 @@ def delete_identity( api_path = '/users/identities/{identityId}' api_params = {} - if identity_id is None: + if identity_id is None or identity_id == '': raise AppwriteException('Missing required parameter: "identity_id"') api_path = api_path.replace('{identityId}', str(self._normalize_value(identity_id))) @@ -355,6 +356,7 @@ def delete_identity( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -752,7 +754,7 @@ def get( api_path = '/users/{userId}' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -792,7 +794,7 @@ def delete( api_path = '/users/{userId}' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -802,6 +804,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -839,7 +842,7 @@ def update_email( api_path = '/users/{userId}/email' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if email is None: raise AppwriteException('Missing required parameter: "email"') @@ -866,7 +869,7 @@ def update_impersonator( model_type: Type[T] = dict, ) -> User[T]: """ - Enable or disable whether a user can impersonate other users. When impersonation headers are used, the request runs as the target user for API behavior, while internal audit logs still attribute the action to the original impersonator and store the impersonated target details only in internal audit payload data. + Enable or disable whether a user can impersonate other users. When impersonation headers are used, the request runs as the target user for API behavior, while internal audit logs still attribute the action to the original impersonator and store the impersonated target details only in internal audit payload data. Account endpoints are read-only while impersonating: they report the target's account, and anything that would change it is refused, so an impersonator cannot alter the target's credentials or delete their account. Parameters ---------- @@ -890,7 +893,7 @@ def update_impersonator( api_path = '/users/{userId}/impersonator' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if impersonator is None: raise AppwriteException('Missing required parameter: "impersonator"') @@ -940,7 +943,7 @@ def create_jwt( api_path = '/users/{userId}/jwts' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) if session_id is not None: @@ -994,7 +997,7 @@ def update_labels( api_path = '/users/{userId}/labels' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if labels is None: raise AppwriteException('Missing required parameter: "labels"') @@ -1014,56 +1017,6 @@ def update_labels( return User.with_data(response, model_type) - def list_logs( - self, - user_id: str, - queries: Optional[List[str]] = None, - total: Optional[bool] = None, - ) -> LogList: - """ - Get the user activity logs list by its unique ID. - - Parameters - ---------- - user_id : str - User ID. - queries : Optional[List[str]] - 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 : Optional[bool] - When set to false, the total count returned will be 0 and will not be calculated. - Returns - ------- - LogList - API response as a typed Pydantic model - - Raises - ------ - AppwriteException - If API request fails - """ - - api_path = '/users/{userId}/logs' - api_params = {} - if user_id is None: - raise AppwriteException('Missing required parameter: "user_id"') - api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) - if queries is not None: - api_params['queries'] = self._normalize_value(queries) - if total is not None: - api_params['total'] = self._normalize_value(total) - - response = self.client.call( - 'get', - api_path, - { - 'X-Appwrite-Project': self.client.get_config('project'), - 'accept': 'application/json', - }, - api_params, - ) - - return self._parse_response(response, model=LogList) - def list_memberships( self, user_id: str, @@ -1097,7 +1050,7 @@ def list_memberships( api_path = '/users/{userId}/memberships' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) if queries is not None: @@ -1150,7 +1103,7 @@ def update_mfa( api_path = '/users/{userId}/mfa' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if mfa is None: raise AppwriteException('Missing required parameter: "mfa"') @@ -1197,7 +1150,7 @@ def delete_mfa_authenticator( api_path = '/users/{userId}/mfa/authenticators/{type}' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if type is None: raise AppwriteException('Missing required parameter: "type"') @@ -1210,6 +1163,7 @@ def delete_mfa_authenticator( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1243,9 +1197,9 @@ def get_mfa_challenge( api_path = '/users/{userId}/mfa/challenges/{challengeId}' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') - if challenge_id is None: + if challenge_id is None or challenge_id == '': raise AppwriteException('Missing required parameter: "challenge_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) api_path = api_path.replace('{challengeId}', str(self._normalize_value(challenge_id))) @@ -1286,7 +1240,7 @@ def list_mfa_factors( api_path = '/users/{userId}/mfa/factors' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -1326,7 +1280,7 @@ def get_mfa_recovery_codes( api_path = '/users/{userId}/mfa/recovery-codes' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -1366,7 +1320,7 @@ def update_mfa_recovery_codes( api_path = '/users/{userId}/mfa/recovery-codes' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -1407,7 +1361,7 @@ def create_mfa_recovery_codes( api_path = '/users/{userId}/mfa/recovery-codes' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -1455,7 +1409,7 @@ def update_name( api_path = '/users/{userId}/name' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -1475,6 +1429,202 @@ def update_name( return User.with_data(response, model_type) + def list_passkeys( + self, + user_id: str, + queries: Optional[List[str]] = None, + total: Optional[bool] = None, + ) -> PasskeyList: + """ + Get the list of verified passkeys registered by a user. + + Parameters + ---------- + user_id : str + User ID. + queries : Optional[List[str]] + 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 and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. + Returns + ------- + PasskeyList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/users/{userId}/passkeys' + api_params = {} + if user_id is None or user_id == '': + raise AppwriteException('Missing required parameter: "user_id"') + api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) + if queries is not None: + api_params['queries'] = self._normalize_value(queries) + if total is not None: + api_params['total'] = self._normalize_value(total) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=PasskeyList) + + def get_passkey( + self, + user_id: str, + passkey_id: str, + ) -> Passkey: + """ + Get a verified passkey of a user by its unique ID. + + Parameters + ---------- + user_id : str + User ID. + passkey_id : str + Passkey ID. + Returns + ------- + Passkey + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/users/{userId}/passkeys/{passkeyId}' + api_params = {} + if user_id is None or user_id == '': + raise AppwriteException('Missing required parameter: "user_id"') + if passkey_id is None or passkey_id == '': + raise AppwriteException('Missing required parameter: "passkey_id"') + api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) + api_path = api_path.replace('{passkeyId}', str(self._normalize_value(passkey_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Passkey) + + def update_passkey( + self, + user_id: str, + passkey_id: str, + name: str, + ) -> Passkey: + """ + Rename a passkey of a user. + + Parameters + ---------- + user_id : str + User ID. + passkey_id : str + Passkey ID. + name : str + Passkey name. Max length: 128 chars. + Returns + ------- + Passkey + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/users/{userId}/passkeys/{passkeyId}' + api_params = {} + if user_id is None or user_id == '': + raise AppwriteException('Missing required parameter: "user_id"') + if passkey_id is None or passkey_id == '': + raise AppwriteException('Missing required parameter: "passkey_id"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) + api_path = api_path.replace('{passkeyId}', str(self._normalize_value(passkey_id))) + api_params['name'] = self._normalize_value(name) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=Passkey) + + def delete_passkey( + self, + user_id: str, + passkey_id: str, + ) -> Dict[str, Any]: + """ + Delete a passkey from a user, for example when a device is lost. The passkey can no longer be used to sign in. + + Parameters + ---------- + user_id : str + User ID. + passkey_id : str + Passkey ID. + Returns + ------- + Dict[str, Any] + API response as a dictionary + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/users/{userId}/passkeys/{passkeyId}' + api_params = {} + if user_id is None or user_id == '': + raise AppwriteException('Missing required parameter: "user_id"') + if passkey_id is None or passkey_id == '': + raise AppwriteException('Missing required parameter: "passkey_id"') + api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) + api_path = api_path.replace('{passkeyId}', str(self._normalize_value(passkey_id))) + + response = self.client.call( + 'delete', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return response + def update_password( self, user_id: str, @@ -1506,7 +1656,7 @@ def update_password( api_path = '/users/{userId}/password' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if password is None: raise AppwriteException('Missing required parameter: "password"') @@ -1557,7 +1707,7 @@ def update_phone( api_path = '/users/{userId}/phone' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if number is None: raise AppwriteException('Missing required parameter: "number"') @@ -1605,7 +1755,7 @@ def get_prefs( api_path = '/users/{userId}/prefs' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -1652,7 +1802,7 @@ def update_prefs( api_path = '/users/{userId}/prefs' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if prefs is None: raise AppwriteException('Missing required parameter: "prefs"') @@ -1699,7 +1849,7 @@ def list_sessions( api_path = '/users/{userId}/sessions' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) if total is not None: @@ -1743,7 +1893,7 @@ def create_session( api_path = '/users/{userId}/sessions' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -1784,7 +1934,7 @@ def delete_sessions( api_path = '/users/{userId}/sessions' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) @@ -1794,6 +1944,7 @@ def delete_sessions( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1827,9 +1978,9 @@ def delete_session( api_path = '/users/{userId}/sessions/{sessionId}' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') - if session_id is None: + if session_id is None or session_id == '': raise AppwriteException('Missing required parameter: "session_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) api_path = api_path.replace('{sessionId}', str(self._normalize_value(session_id))) @@ -1840,6 +1991,7 @@ def delete_session( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1877,7 +2029,7 @@ def update_status( api_path = '/users/{userId}/status' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if status is None: raise AppwriteException('Missing required parameter: "status"') @@ -1927,7 +2079,7 @@ def list_targets( api_path = '/users/{userId}/targets' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) if queries is not None: @@ -1986,7 +2138,7 @@ def create_target( api_path = '/users/{userId}/targets' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if target_id is None: raise AppwriteException('Missing required parameter: "target_id"') @@ -2043,9 +2195,9 @@ def get_target( api_path = '/users/{userId}/targets/{targetId}' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') - if target_id is None: + if target_id is None or target_id == '': raise AppwriteException('Missing required parameter: "target_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) api_path = api_path.replace('{targetId}', str(self._normalize_value(target_id))) @@ -2098,9 +2250,9 @@ def update_target( api_path = '/users/{userId}/targets/{targetId}' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') - if target_id is None: + if target_id is None or target_id == '': raise AppwriteException('Missing required parameter: "target_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) api_path = api_path.replace('{targetId}', str(self._normalize_value(target_id))) @@ -2151,9 +2303,9 @@ def delete_target( api_path = '/users/{userId}/targets/{targetId}' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') - if target_id is None: + if target_id is None or target_id == '': raise AppwriteException('Missing required parameter: "target_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) api_path = api_path.replace('{targetId}', str(self._normalize_value(target_id))) @@ -2164,6 +2316,7 @@ def delete_target( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -2200,7 +2353,7 @@ def create_token( api_path = '/users/{userId}/tokens' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') api_path = api_path.replace('{userId}', str(self._normalize_value(user_id))) if length is not None: @@ -2252,7 +2405,7 @@ def update_email_verification( api_path = '/users/{userId}/verification' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if email_verification is None: raise AppwriteException('Missing required parameter: "email_verification"') @@ -2303,7 +2456,7 @@ def update_phone_verification( api_path = '/users/{userId}/verification/phone' api_params = {} - if user_id is None: + if user_id is None or user_id == '': raise AppwriteException('Missing required parameter: "user_id"') if phone_verification is None: raise AppwriteException('Missing required parameter: "phone_verification"') diff --git a/appwrite/services/vectors_db.py b/appwrite/services/vectors_db.py index eede5fa1..1cea0603 100644 --- a/appwrite/services/vectors_db.py +++ b/appwrite/services/vectors_db.py @@ -144,7 +144,7 @@ def list_specifications( self, ) -> DedicatedDatabaseSpecificationList: """ - 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. + List the dedicated database specifications available on the current plan. Each specification reports its resource limits, its own prices and overage rates, and whether it is enabled for the organization. Returns ------- DedicatedDatabaseSpecificationList @@ -174,6 +174,7 @@ def list_specifications( def list_transactions( self, queries: Optional[List[str]] = None, + total: Optional[bool] = None, ) -> TransactionList: """ List transactions across all databases. @@ -182,6 +183,8 @@ def list_transactions( ---------- queries : Optional[List[str]] Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. Returns ------- TransactionList @@ -197,6 +200,8 @@ def list_transactions( api_params = {} if queries is not None: api_params['queries'] = self._normalize_value(queries) + if total is not None: + api_params['total'] = self._normalize_value(total) response = self.client.call( 'get', @@ -274,7 +279,7 @@ def get_transaction( api_path = '/vectorsdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) @@ -320,7 +325,7 @@ def update_transaction( api_path = '/vectorsdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) if commit is not None: @@ -365,7 +370,7 @@ def delete_transaction( api_path = '/vectorsdb/transactions/{transactionId}' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) @@ -375,6 +380,7 @@ def delete_transaction( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -408,7 +414,7 @@ def create_operations( api_path = '/vectorsdb/transactions/{transactionId}/operations' api_params = {} - if transaction_id is None: + if transaction_id is None or transaction_id == '': raise AppwriteException('Missing required parameter: "transaction_id"') api_path = api_path.replace('{transactionId}', str(self._normalize_value(transaction_id))) if operations is not None: @@ -451,7 +457,7 @@ def get( api_path = '/vectorsdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -506,7 +512,7 @@ def update( api_path = '/vectorsdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -558,7 +564,7 @@ def delete( api_path = '/vectorsdb/{databaseId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -568,6 +574,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -607,7 +614,7 @@ def list_collections( api_path = '/vectorsdb/{databaseId}/collections' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if queries is not None: @@ -671,7 +678,7 @@ def create_collection( api_path = '/vectorsdb/{databaseId}/collections' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') if collection_id is None: raise AppwriteException('Missing required parameter: "collection_id"') @@ -730,9 +737,9 @@ def get_collection( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -791,9 +798,9 @@ def update_collection( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -849,9 +856,9 @@ def delete_collection( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -862,6 +869,7 @@ def delete_collection( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -911,9 +919,9 @@ def list_documents( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -981,9 +989,9 @@ def create_document( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if document_id is None: raise AppwriteException('Missing required parameter: "document_id"') @@ -1048,9 +1056,9 @@ def create_documents( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if documents is None: raise AppwriteException('Missing required parameter: "documents"') @@ -1110,9 +1118,9 @@ def upsert_documents( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if documents is None: raise AppwriteException('Missing required parameter: "documents"') @@ -1175,9 +1183,9 @@ def update_documents( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1238,9 +1246,9 @@ def delete_documents( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1305,9 +1313,9 @@ def create_query( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/query' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1373,11 +1381,11 @@ def get_document( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1442,11 +1450,11 @@ def upsert_document( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1514,11 +1522,11 @@ def update_document( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1576,11 +1584,11 @@ def delete_document( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if document_id is None: + if document_id is None or document_id == '': raise AppwriteException('Missing required parameter: "document_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1594,6 +1602,7 @@ def delete_document( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1633,9 +1642,9 @@ def list_indexes( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/indexes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1699,9 +1708,9 @@ def create_index( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/indexes' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') if key is None: raise AppwriteException('Missing required parameter: "key"') @@ -1762,11 +1771,11 @@ def get_index( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/indexes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1814,11 +1823,11 @@ def delete_index( api_path = '/vectorsdb/{databaseId}/collections/{collectionId}/indexes/{key}' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') - if collection_id is None: + if collection_id is None or collection_id == '': raise AppwriteException('Missing required parameter: "collection_id"') - if key is None: + if key is None or key == '': raise AppwriteException('Missing required parameter: "key"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) api_path = api_path.replace('{collectionId}', str(self._normalize_value(collection_id))) @@ -1830,6 +1839,7 @@ def delete_index( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -1863,7 +1873,7 @@ def create_failover( api_path = '/vectorsdb/{databaseId}/failovers' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if target_replica_id is not None: @@ -1915,7 +1925,7 @@ def list_operations( api_path = '/vectorsdb/{databaseId}/operations' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) if status is not None: @@ -1961,7 +1971,7 @@ def get_replicas( api_path = '/vectorsdb/{databaseId}/replicas' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) @@ -2001,7 +2011,7 @@ def get_status( api_path = '/vectorsdb/{databaseId}/status' api_params = {} - if database_id is None: + if database_id is None or database_id == '': raise AppwriteException('Missing required parameter: "database_id"') api_path = api_path.replace('{databaseId}', str(self._normalize_value(database_id))) diff --git a/appwrite/services/waf.py b/appwrite/services/waf.py new file mode 100644 index 00000000..8aaa3ebc --- /dev/null +++ b/appwrite/services/waf.py @@ -0,0 +1,1039 @@ +from ..service import Service +from urllib.parse import quote +from typing import Any, Dict, List, Optional, Union +from ..exception import AppwriteException +from appwrite.utils.deprecated import deprecated +from ..models.waf_rule_list import WafRuleList +from ..models.waf_rule_bypass import WafRuleBypass +from ..models.waf_rule_challenge import WafRuleChallenge +from ..models.waf_rule_deny import WafRuleDeny +from ..models.waf_rule_rate_limit import WafRuleRateLimit +from ..models.waf_rule_redirect import WafRuleRedirect + + +class Waf(Service): + + def __init__(self, client) -> None: + super(Waf, self).__init__(client) + + def list_rules( + self, + queries: Optional[List[str]] = None, + search: Optional[str] = None, + total: Optional[bool] = None, + ) -> WafRuleList: + """ + List WAF rules for the current project. + + Parameters + ---------- + queries : Optional[List[str]] + 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. + search : Optional[str] + Search term to filter your list results. Max length: 256 chars. + total : Optional[bool] + When set to false, the total count returned will be 0 and will not be calculated. + Returns + ------- + WafRuleList + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules' + api_params = {} + if queries is not None: + api_params['queries'] = self._normalize_value(queries) + if search is not None: + api_params['search'] = self._normalize_value(search) + if total is not None: + api_params['total'] = self._normalize_value(total) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleList) + + def create_bypass_rule( + self, + rule_id: str, + resource_type: str, + name: str, + resource_id: Optional[str] = None, + description: Optional[str] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + ) -> WafRuleBypass: + """ + Create a bypass WAF rule. Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. Choose a custom ID or pass `ID.unique()` to generate a unique one. + resource_type : str + Resource type the rule applies to. + name : str + Rule name. + resource_id : Optional[str] + Resource identifier. Leave empty for the API resource type. + description : Optional[str] + Optional description for the rule. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to create the rule in a disabled state. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + Returns + ------- + WafRuleBypass + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/bypass' + api_params = {} + if rule_id is None: + raise AppwriteException('Missing required parameter: "rule_id"') + if resource_type is None: + raise AppwriteException('Missing required parameter: "resource_type"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + api_params['ruleId'] = self._normalize_value(rule_id) + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleBypass) + + def update_bypass_rule( + self, + rule_id: str, + resource_type: Optional[str] = None, + resource_id: Optional[str] = None, + name: Optional[str] = None, + description: Optional[str] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + ) -> WafRuleBypass: + """ + Update a bypass WAF rule. Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. + resource_type : Optional[str] + Resource type the rule applies to. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + name : Optional[str] + Rule name. + description : Optional[str] + Optional description for the rule. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to disable the rule. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + Returns + ------- + WafRuleBypass + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/bypass/{ruleId}' + api_params = {} + if rule_id is None or rule_id == '': + raise AppwriteException('Missing required parameter: "rule_id"') + api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) + if resource_type is not None: + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + if name is not None: + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleBypass) + + def create_challenge_rule( + self, + rule_id: str, + resource_type: str, + name: str, + resource_id: Optional[str] = None, + description: Optional[str] = None, + challenge_type: Optional[str] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + difficulty: Optional[float] = None, + ttl: Optional[float] = None, + ) -> WafRuleChallenge: + """ + Create a challenge WAF rule. Use `difficulty` (1 easiest to 5 hardest) to tune the client-side proof-of-work cost, and `ttl` to control how long, in seconds, a visitor stays cleared after passing the challenge before being challenged again. Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. Choose a custom ID or pass `ID.unique()` to generate a unique one. + resource_type : str + Resource type the rule applies to. + name : str + Rule name. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + description : Optional[str] + Optional description for the rule. + challenge_type : Optional[str] + Challenge type enforced by the rule. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to create the rule in a disabled state. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + difficulty : Optional[float] + Challenge difficulty from 1 (easiest) to 5 (hardest). Higher values demand more client-side proof-of-work. + ttl : Optional[float] + How long, in seconds, a visitor stays cleared after passing the challenge before being challenged again. + Returns + ------- + WafRuleChallenge + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/challenge' + api_params = {} + if rule_id is None: + raise AppwriteException('Missing required parameter: "rule_id"') + if resource_type is None: + raise AppwriteException('Missing required parameter: "resource_type"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + api_params['ruleId'] = self._normalize_value(rule_id) + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + if challenge_type is not None: + api_params['challengeType'] = self._normalize_value(challenge_type) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + if difficulty is not None: + api_params['difficulty'] = self._normalize_value(difficulty) + if ttl is not None: + api_params['ttl'] = self._normalize_value(ttl) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleChallenge) + + def update_challenge_rule( + self, + rule_id: str, + resource_type: Optional[str] = None, + resource_id: Optional[str] = None, + name: Optional[str] = None, + description: Optional[str] = None, + challenge_type: Optional[str] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + difficulty: Optional[float] = None, + ttl: Optional[float] = None, + ) -> WafRuleChallenge: + """ + Update a challenge WAF rule. Use `difficulty` (1 easiest to 5 hardest) to tune the client-side proof-of-work cost, and `ttl` to control how long, in seconds, a visitor stays cleared after passing the challenge before being challenged again. Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. + resource_type : Optional[str] + Resource type the rule applies to. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + name : Optional[str] + Rule name. + description : Optional[str] + Optional description for the rule. + challenge_type : Optional[str] + Challenge type enforced by the rule. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to disable the rule. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + difficulty : Optional[float] + Challenge difficulty from 1 (easiest) to 5 (hardest). Higher values demand more client-side proof-of-work. + ttl : Optional[float] + How long, in seconds, a visitor stays cleared after passing the challenge before being challenged again. + Returns + ------- + WafRuleChallenge + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/challenge/{ruleId}' + api_params = {} + if rule_id is None or rule_id == '': + raise AppwriteException('Missing required parameter: "rule_id"') + api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) + if resource_type is not None: + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + if name is not None: + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + if challenge_type is not None: + api_params['challengeType'] = self._normalize_value(challenge_type) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + if difficulty is not None: + api_params['difficulty'] = self._normalize_value(difficulty) + if ttl is not None: + api_params['ttl'] = self._normalize_value(ttl) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleChallenge) + + def create_deny_rule( + self, + rule_id: str, + resource_type: str, + name: str, + resource_id: Optional[str] = None, + description: Optional[str] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + ) -> WafRuleDeny: + """ + Create a deny WAF rule. Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. Choose a custom ID or pass `ID.unique()` to generate a unique one. + resource_type : str + Resource type the rule applies to. + name : str + Rule name. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + description : Optional[str] + Optional description for the rule. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to create the rule in a disabled state. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + Returns + ------- + WafRuleDeny + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/deny' + api_params = {} + if rule_id is None: + raise AppwriteException('Missing required parameter: "rule_id"') + if resource_type is None: + raise AppwriteException('Missing required parameter: "resource_type"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + api_params['ruleId'] = self._normalize_value(rule_id) + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleDeny) + + def update_deny_rule( + self, + rule_id: str, + resource_type: Optional[str] = None, + resource_id: Optional[str] = None, + name: Optional[str] = None, + description: Optional[str] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + ) -> WafRuleDeny: + """ + Update a deny WAF rule. Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. + resource_type : Optional[str] + Resource type the rule applies to. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + name : Optional[str] + Rule name. + description : Optional[str] + Optional description for the rule. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to disable the rule. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + Returns + ------- + WafRuleDeny + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/deny/{ruleId}' + api_params = {} + if rule_id is None or rule_id == '': + raise AppwriteException('Missing required parameter: "rule_id"') + api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) + if resource_type is not None: + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + if name is not None: + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleDeny) + + def create_rate_limit_rule( + self, + rule_id: str, + resource_type: str, + name: str, + limit: float, + interval: float, + resource_id: Optional[str] = None, + description: Optional[str] = None, + key: Optional[str] = None, + strategy: Optional[str] = None, + max_bucket_size: Optional[float] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + ) -> WafRuleRateLimit: + """ + Create a rate limit WAF rule. Use `key` to choose the counter: `ip` limits per client IP, while `userId` limits per authenticated user (requests without an authenticated user skip `userId` rules). Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. Choose a custom ID or pass `ID.unique()` to generate a unique one. + resource_type : str + Resource type the rule applies to. + name : str + Rule name. + limit : float + Maximum number of matching requests allowed in the configured interval. + interval : float + Interval in seconds used for rate limiting. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + description : Optional[str] + Optional description for the rule. + key : Optional[str] + Rate limit key. Use `ip` to limit per client IP or `userId` to limit per authenticated user. Requests without an authenticated user skip `userId` rules. + strategy : Optional[str] + Rate limit strategy. `fixedWindow` counts requests in discrete intervals, `slidingWindow` weights the previous interval for smoother limiting, and `tokenBucket` refills allowance continuously to permit short bursts. + max_bucket_size : Optional[float] + Maximum number of tokens the bucket can hold for the `tokenBucket` strategy, controlling how large a burst is allowed. The sustained refill rate is `limit / interval`. Defaults to `limit` when omitted. Ignored by other strategies. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to create the rule in a disabled state. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + Returns + ------- + WafRuleRateLimit + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/rate-limit' + api_params = {} + if rule_id is None: + raise AppwriteException('Missing required parameter: "rule_id"') + if resource_type is None: + raise AppwriteException('Missing required parameter: "resource_type"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if limit is None: + raise AppwriteException('Missing required parameter: "limit"') + if interval is None: + raise AppwriteException('Missing required parameter: "interval"') + api_params['ruleId'] = self._normalize_value(rule_id) + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + api_params['limit'] = self._normalize_value(limit) + api_params['interval'] = self._normalize_value(interval) + if key is not None: + api_params['key'] = self._normalize_value(key) + if strategy is not None: + api_params['strategy'] = self._normalize_value(strategy) + if max_bucket_size is not None: + api_params['maxBucketSize'] = self._normalize_value(max_bucket_size) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleRateLimit) + + def update_rate_limit_rule( + self, + rule_id: str, + resource_type: Optional[str] = None, + resource_id: Optional[str] = None, + name: Optional[str] = None, + description: Optional[str] = None, + limit: Optional[float] = None, + interval: Optional[float] = None, + key: Optional[str] = None, + max_bucket_size: Optional[float] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + ) -> WafRuleRateLimit: + """ + Update a rate limit WAF rule. Use `key` to choose the counter: `ip` limits per client IP, while `userId` limits per authenticated user (requests without an authenticated user skip `userId` rules). Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. + resource_type : Optional[str] + Resource type the rule applies to. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + name : Optional[str] + Rule name. + description : Optional[str] + Optional description for the rule. + limit : Optional[float] + Maximum number of matching requests allowed in the configured interval. + interval : Optional[float] + Interval in seconds used for rate limiting. + key : Optional[str] + Rate limit key. Use `ip` to limit per client IP or `userId` to limit per authenticated user. Requests without an authenticated user skip `userId` rules. + max_bucket_size : Optional[float] + Maximum number of tokens the bucket can hold for the `tokenBucket` strategy, controlling how large a burst is allowed. The sustained refill rate is `limit / interval`. Ignored by other strategies. The strategy itself cannot be changed after creation. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to disable the rule. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + Returns + ------- + WafRuleRateLimit + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/rate-limit/{ruleId}' + api_params = {} + if rule_id is None or rule_id == '': + raise AppwriteException('Missing required parameter: "rule_id"') + api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) + if resource_type is not None: + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + if name is not None: + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + if limit is not None: + api_params['limit'] = self._normalize_value(limit) + if interval is not None: + api_params['interval'] = self._normalize_value(interval) + if key is not None: + api_params['key'] = self._normalize_value(key) + if max_bucket_size is not None: + api_params['maxBucketSize'] = self._normalize_value(max_bucket_size) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleRateLimit) + + def create_redirect_rule( + self, + rule_id: str, + resource_type: str, + name: str, + location: str, + status_code: float, + resource_id: Optional[str] = None, + description: Optional[str] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + ) -> WafRuleRedirect: + """ + Create a redirect WAF rule. Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. Choose a custom ID or pass `ID.unique()` to generate a unique one. + resource_type : str + Resource type the rule applies to. + name : str + Rule name. + location : str + Location used for redirect responses. + status_code : float + Integer status code used for redirect responses. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + description : Optional[str] + Optional description for the rule. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to create the rule in a disabled state. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + Returns + ------- + WafRuleRedirect + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/redirect' + api_params = {} + if rule_id is None: + raise AppwriteException('Missing required parameter: "rule_id"') + if resource_type is None: + raise AppwriteException('Missing required parameter: "resource_type"') + if name is None: + raise AppwriteException('Missing required parameter: "name"') + if location is None: + raise AppwriteException('Missing required parameter: "location"') + if status_code is None: + raise AppwriteException('Missing required parameter: "status_code"') + api_params['ruleId'] = self._normalize_value(rule_id) + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + api_params['location'] = self._normalize_value(location) + api_params['statusCode'] = self._normalize_value(status_code) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + + response = self.client.call( + 'post', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleRedirect) + + def update_redirect_rule( + self, + rule_id: str, + resource_type: Optional[str] = None, + resource_id: Optional[str] = None, + name: Optional[str] = None, + description: Optional[str] = None, + location: Optional[str] = None, + status_code: Optional[float] = None, + priority: Optional[float] = None, + enabled: Optional[bool] = None, + conditions: Optional[List[str]] = None, + ) -> WafRuleRedirect: + """ + Update a redirect WAF rule. Conditions can match request attributes including `ip` (plain IPs or CIDR blocks like `10.0.0.0/8`), `method`, `path`, `host`, `country`, `continent`, `headers.`, `query.`, `queryKeys`, `userAgent`, `os`, `osVersion`, `browser`, and `browserVersion`. Conditions on `city` and `state` require the premium Geo DB addon. + + Parameters + ---------- + rule_id : str + Rule ID. + resource_type : Optional[str] + Resource type the rule applies to. + resource_id : Optional[str] + Resource identifier. Required for functions and sites. + name : Optional[str] + Rule name. + description : Optional[str] + Optional description for the rule. + location : Optional[str] + Location used for redirect responses. + status_code : Optional[float] + Integer status code used for redirect responses. + priority : Optional[float] + Evaluation priority. Lower numbers run earlier. + enabled : Optional[bool] + Set to false to disable the rule. + conditions : Optional[List[str]] + Array of condition strings generated using the WAF Condition builder. Maximum of 100 conditions are allowed, each 4096 characters long. + Returns + ------- + WafRuleRedirect + API response as a typed Pydantic model + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/redirect/{ruleId}' + api_params = {} + if rule_id is None or rule_id == '': + raise AppwriteException('Missing required parameter: "rule_id"') + api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) + if resource_type is not None: + api_params['resourceType'] = self._normalize_value(resource_type) + if resource_id is not None: + api_params['resourceId'] = self._normalize_value(resource_id) + if name is not None: + api_params['name'] = self._normalize_value(name) + if description is not None: + api_params['description'] = self._normalize_value(description) + if location is not None: + api_params['location'] = self._normalize_value(location) + if status_code is not None: + api_params['statusCode'] = self._normalize_value(status_code) + if priority is not None: + api_params['priority'] = self._normalize_value(priority) + if enabled is not None: + api_params['enabled'] = self._normalize_value(enabled) + if conditions is not None: + api_params['conditions'] = self._normalize_value(conditions) + + response = self.client.call( + 'patch', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return self._parse_response(response, model=WafRuleRedirect) + + def get_rule( + self, + rule_id: str, + ) -> Union[ + WafRuleBypass, + WafRuleDeny, + WafRuleChallenge, + WafRuleRateLimit, + WafRuleRedirect, + ]: + """ + Get a WAF rule by its ID. + + Parameters + ---------- + rule_id : str + Rule ID. + Returns + ------- + Union[WafRuleBypass, WafRuleDeny, WafRuleChallenge, WafRuleRateLimit, WafRuleRedirect] + API response as one of the typed response models + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/{ruleId}' + api_params = {} + if rule_id is None or rule_id == '': + raise AppwriteException('Missing required parameter: "rule_id"') + api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) + + response = self.client.call( + 'get', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'accept': 'application/json', + }, + api_params, + ) + if not isinstance(response, dict): + raise AppwriteException('Expected object response when hydrating a response model') + + if response.get('action') == 'bypass': + return self._parse_response(response, model=WafRuleBypass) + + if response.get('action') == 'deny': + return self._parse_response(response, model=WafRuleDeny) + + if response.get('action') == 'challenge': + return self._parse_response(response, model=WafRuleChallenge) + + if response.get('action') == 'rateLimit': + return self._parse_response(response, model=WafRuleRateLimit) + + if response.get('action') == 'redirect': + return self._parse_response(response, model=WafRuleRedirect) + + raise AppwriteException('Unable to match response to any known model') + + def delete_rule( + self, + rule_id: str, + ) -> Dict[str, Any]: + """ + Delete a WAF rule. + + Parameters + ---------- + rule_id : str + Rule ID. + Returns + ------- + Dict[str, Any] + API response as a dictionary + + Raises + ------ + AppwriteException + If API request fails + """ + + api_path = '/waf/rules/{ruleId}' + api_params = {} + if rule_id is None or rule_id == '': + raise AppwriteException('Missing required parameter: "rule_id"') + api_path = api_path.replace('{ruleId}', str(self._normalize_value(rule_id))) + + response = self.client.call( + 'delete', + api_path, + { + 'X-Appwrite-Project': self.client.get_config('project'), + 'content-type': 'application/json', + 'accept': 'application/json', + }, + api_params, + ) + + return response diff --git a/appwrite/services/webhooks.py b/appwrite/services/webhooks.py index 16674e2c..6caa4745 100644 --- a/appwrite/services/webhooks.py +++ b/appwrite/services/webhooks.py @@ -86,9 +86,9 @@ def create( tls : Optional[bool] Certificate verification, false for disabled or true for enabled. auth_username : Optional[str] - Webhook HTTP user. Max length: 256 chars. + Webhook HTTP user. Max length: 255 chars. auth_password : Optional[str] - Webhook HTTP password. Max length: 256 chars. + Webhook HTTP password. Max length: 2048 chars. secret : Optional[str] Webhook secret key. If not provided, a new key will be generated automatically. Key must be at least 8 characters long, and at max 256 characters. Returns @@ -164,7 +164,7 @@ def get( api_path = '/webhooks/{webhookId}' api_params = {} - if webhook_id is None: + if webhook_id is None or webhook_id == '': raise AppwriteException('Missing required parameter: "webhook_id"') api_path = api_path.replace('{webhookId}', str(self._normalize_value(webhook_id))) @@ -209,9 +209,9 @@ def update( tls : Optional[bool] Certificate verification, false for disabled or true for enabled. auth_username : Optional[str] - Webhook HTTP user. Max length: 256 chars. + Webhook HTTP user. Max length: 255 chars. auth_password : Optional[str] - Webhook HTTP password. Max length: 256 chars. + Webhook HTTP password. Max length: 2048 chars. Omit to keep the current password; it is cleared when the URL changes or TLS verification is disabled. Returns ------- Webhook @@ -225,7 +225,7 @@ def update( api_path = '/webhooks/{webhookId}' api_params = {} - if webhook_id is None: + if webhook_id is None or webhook_id == '': raise AppwriteException('Missing required parameter: "webhook_id"') if name is None: raise AppwriteException('Missing required parameter: "name"') @@ -283,7 +283,7 @@ def delete( api_path = '/webhooks/{webhookId}' api_params = {} - if webhook_id is None: + if webhook_id is None or webhook_id == '': raise AppwriteException('Missing required parameter: "webhook_id"') api_path = api_path.replace('{webhookId}', str(self._normalize_value(webhook_id))) @@ -293,6 +293,7 @@ def delete( { 'X-Appwrite-Project': self.client.get_config('project'), 'content-type': 'application/json', + 'accept': 'application/json', }, api_params, ) @@ -326,7 +327,7 @@ def update_secret( api_path = '/webhooks/{webhookId}/secret' api_params = {} - if webhook_id is None: + if webhook_id is None or webhook_id == '': raise AppwriteException('Missing required parameter: "webhook_id"') api_path = api_path.replace('{webhookId}', str(self._normalize_value(webhook_id))) if secret is not None: diff --git a/appwrite/topic.py b/appwrite/topic.py new file mode 100644 index 00000000..b8b7c638 --- /dev/null +++ b/appwrite/topic.py @@ -0,0 +1,106 @@ +from types import MethodType + + +def _levels_of(levels): + """ + Validate the levels passed to `path()`: a non-empty list of non-empty strings, none holding + the level separator `/` or the wildcards `+` and `#` (use `any()` and `all()` for those). + """ + if not isinstance(levels, (list, tuple)): + raise TypeError("path() expects an array, e.g. path(['user'])") + if len(levels) == 0: + raise ValueError("path() needs at least one level") + for index, level in enumerate(levels): + if not isinstance(level, str): + kind = "null" if level is None else type(level).__name__ + raise TypeError(f"level at index {index} must be a string, got {kind}") + if level == "": + raise ValueError(f"empty level at index {index}") + if "/" in level: + parts = ", ".join(f"'{part}'" for part in level.split("/")) + raise ValueError(f'"{level}" contains "/", split it: path([{parts}])') + if level == "+": + raise ValueError('"+" is reserved, use any()') + if "+" in level: + raise ValueError(f'"{level}" contains "+", use any() for wildcards') + if level == "#": + raise ValueError('"#" is reserved, use all()') + if "#" in level: + raise ValueError(f'"{level}" contains "#", use all() for wildcards') + return tuple(levels) + + +class _builder: + """ + Bind a Topic method to the instance it is read from, or to an empty topic when it is read + from the class, so `Topic.path([...])` starts a topic and `topic.path([...])` extends one. + """ + + def __init__(self, func): + self.__func__ = func + self.__doc__ = func.__doc__ + + def __get__(self, instance, owner=None): + target = instance if instance is not None else owner(()) + return MethodType(self.__func__, target) + + +class Topic: + """ + Helper to build MQTT topics for `Push`, level by level. + + Topic.path(['user', user_id, 'notification']) # "user/123/notification" + Topic.path(['user']).any().path(['notification']) # "user/+/notification" + Topic.path(['org']).any().path(['logs']).all() # "org/+/logs/#" + + `any()` matches exactly one level and `all()` everything below, at any depth (including the + parent itself). `all()` ends the topic, so it returns a `ResolvedTopic`. + """ + + def __init__(self, levels): + # Internal: build topics with `Topic.path()`, `Topic.any()` and `Topic.all()`. + self._levels = tuple(levels) + + @_builder + def path(self, levels): + """Start a topic with the given levels, or append them, e.g. `Topic.path(['user', user_id])`.""" + return Topic(self._levels + _levels_of(levels)) + + @_builder + def any(self): + """Start a topic with, or append, a single-level wildcard (`+`): matches exactly one level.""" + return Topic(self._levels + ("+",)) + + @_builder + def all(self): + """The multi-level wildcard (`#`) alone, or appended to end the topic.""" + return ResolvedTopic(self._levels + ("#",)) + + def __str__(self): + return "/".join(self._levels) + + def __repr__(self): + return f"Topic({str(self)!r})" + + +class ResolvedTopic: + """A topic ended by `all()`: nothing can be appended after the `#` wildcard.""" + + def __init__(self, levels): + # Internal: created by `Topic.all()`. + self._levels = tuple(levels) + + def path(self, levels): + raise TypeError("nothing can come after all()") + + def any(self): + raise TypeError("nothing can come after all()") + + def all(self): + raise TypeError("nothing can come after all()") + + def __str__(self): + return "/".join(self._levels) + + def __repr__(self): + return f"ResolvedTopic({str(self)!r})" diff --git a/docs/examples/account/create-email-password-session.md b/docs/examples/account/create-email-password-session.md index 292074db..7e016dab 100644 --- a/docs/examples/account/create-email-password-session.md +++ b/docs/examples/account/create-email-password-session.md @@ -12,7 +12,8 @@ account = Account(client) result: Session = account.create_email_password_session( email = 'email@example.com', - password = 'password' + password = 'password', + duration = 60 # optional ) print(result.model_dump()) diff --git a/docs/examples/account/create-email-verification-otp.md b/docs/examples/account/create-email-verification-otp.md new file mode 100644 index 00000000..92de90e8 --- /dev/null +++ b/docs/examples/account/create-email-verification-otp.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import Token + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: Token = account.create_email_verification_otp( + phrase = False # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/create-id-token-session.md b/docs/examples/account/create-id-token-session.md new file mode 100644 index 00000000..b076d40c --- /dev/null +++ b/docs/examples/account/create-id-token-session.md @@ -0,0 +1,24 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import Session +from appwrite.enums.id_token_provider import IdTokenProvider + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: Session = account.create_id_token_session( + provider = IdTokenProvider.APPLE, + id_token = '', + nonce = '', # optional + access_token = '', # optional + access_token_expiry = 0, # optional + name = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/create-mfa-authenticator.md b/docs/examples/account/create-mfa-authenticator.md index 468011b2..745a0314 100644 --- a/docs/examples/account/create-mfa-authenticator.md +++ b/docs/examples/account/create-mfa-authenticator.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.account import Account from appwrite.models import MfaType -from appwrite.enums import AuthenticatorType +from appwrite.enums.authenticator_type import AuthenticatorType client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/account/create-mfa-challenge.md b/docs/examples/account/create-mfa-challenge.md index f31797a4..e26d4e9b 100644 --- a/docs/examples/account/create-mfa-challenge.md +++ b/docs/examples/account/create-mfa-challenge.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.account import Account from appwrite.models import MfaChallenge -from appwrite.enums import AuthenticationFactor +from appwrite.enums.authentication_factor import AuthenticationFactor client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/account/create-o-auth-2-token.md b/docs/examples/account/create-o-auth-2-token.md index cae5a66e..e21fb47d 100644 --- a/docs/examples/account/create-o-auth-2-token.md +++ b/docs/examples/account/create-o-auth-2-token.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.account import Account -from appwrite.enums import OAuthProvider +from appwrite.enums.o_auth_provider import OAuthProvider client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/account/create-passkey-token.md b/docs/examples/account/create-passkey-token.md new file mode 100644 index 00000000..5e33ab57 --- /dev/null +++ b/docs/examples/account/create-passkey-token.md @@ -0,0 +1,16 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import PasskeyChallenge + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: PasskeyChallenge = account.create_passkey_token() + +print(result.model_dump()) +``` diff --git a/docs/examples/account/create-passkey.md b/docs/examples/account/create-passkey.md new file mode 100644 index 00000000..75bc56fd --- /dev/null +++ b/docs/examples/account/create-passkey.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import PasskeyChallenge + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: PasskeyChallenge = account.create_passkey( + passkey_id = '', # optional + name = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/create-recovery-otp.md b/docs/examples/account/create-recovery-otp.md new file mode 100644 index 00000000..02240e31 --- /dev/null +++ b/docs/examples/account/create-recovery-otp.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import Token + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: Token = account.create_recovery_otp( + email = 'email@example.com', + phrase = False # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/delete-mfa-authenticator.md b/docs/examples/account/delete-mfa-authenticator.md index faeccb8b..bc5219a0 100644 --- a/docs/examples/account/delete-mfa-authenticator.md +++ b/docs/examples/account/delete-mfa-authenticator.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.account import Account -from appwrite.enums import AuthenticatorType +from appwrite.enums.authenticator_type import AuthenticatorType client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/account/delete-passkey.md b/docs/examples/account/delete-passkey.md new file mode 100644 index 00000000..c366ed6a --- /dev/null +++ b/docs/examples/account/delete-passkey.md @@ -0,0 +1,15 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result = account.delete_passkey( + passkey_id = '' +) +``` diff --git a/docs/examples/account/delete-sessions.md b/docs/examples/account/delete-sessions.md index 4db5c1ec..ae380854 100644 --- a/docs/examples/account/delete-sessions.md +++ b/docs/examples/account/delete-sessions.md @@ -9,5 +9,7 @@ client.set_session('') # The user session to authenticate with account = Account(client) -result = account.delete_sessions() +result = account.delete_sessions( + current = False # optional +) ``` diff --git a/docs/examples/account/get-passkey.md b/docs/examples/account/get-passkey.md new file mode 100644 index 00000000..018f8467 --- /dev/null +++ b/docs/examples/account/get-passkey.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import Passkey + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: Passkey = account.get_passkey( + passkey_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/list-logs.md b/docs/examples/account/list-passkeys.md similarity index 83% rename from docs/examples/account/list-logs.md rename to docs/examples/account/list-passkeys.md index 3f0a3b55..8c8df029 100644 --- a/docs/examples/account/list-logs.md +++ b/docs/examples/account/list-passkeys.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.account import Account -from appwrite.models import LogList +from appwrite.models import PasskeyList client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint @@ -10,7 +10,7 @@ client.set_session('') # The user session to authenticate with account = Account(client) -result: LogList = account.list_logs( +result: PasskeyList = account.list_passkeys( queries = [], # optional total = False # optional ) diff --git a/docs/examples/account/list-sessions.md b/docs/examples/account/list-sessions.md index d9df7a71..828aad6f 100644 --- a/docs/examples/account/list-sessions.md +++ b/docs/examples/account/list-sessions.md @@ -10,7 +10,9 @@ client.set_session('') # The user session to authenticate with account = Account(client) -result: SessionList = account.list_sessions() +result: SessionList = account.list_sessions( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/account/update-email-verification-otp.md b/docs/examples/account/update-email-verification-otp.md new file mode 100644 index 00000000..b112871f --- /dev/null +++ b/docs/examples/account/update-email-verification-otp.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import Token + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: Token = account.update_email_verification_otp( + user_id = '', + secret = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/update-mfa-authenticator.md b/docs/examples/account/update-mfa-authenticator.md index e7040b0a..60204b9d 100644 --- a/docs/examples/account/update-mfa-authenticator.md +++ b/docs/examples/account/update-mfa-authenticator.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.account import Account from appwrite.models import User -from appwrite.enums import AuthenticatorType +from appwrite.enums.authenticator_type import AuthenticatorType client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/account/update-passkey-token.md b/docs/examples/account/update-passkey-token.md new file mode 100644 index 00000000..21fabcbf --- /dev/null +++ b/docs/examples/account/update-passkey-token.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import TokenSecret + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: TokenSecret = account.update_passkey_token( + challenge_id = '', + credential = {} +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/update-passkey-verification.md b/docs/examples/account/update-passkey-verification.md new file mode 100644 index 00000000..64904203 --- /dev/null +++ b/docs/examples/account/update-passkey-verification.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import Passkey + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: Passkey = account.update_passkey_verification( + passkey_id = '', + credential = {} +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/update-passkey.md b/docs/examples/account/update-passkey.md new file mode 100644 index 00000000..aae42a4b --- /dev/null +++ b/docs/examples/account/update-passkey.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import Passkey + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: Passkey = account.update_passkey( + passkey_id = '', + name = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/account/update-recovery-otp.md b/docs/examples/account/update-recovery-otp.md new file mode 100644 index 00000000..e34e5808 --- /dev/null +++ b/docs/examples/account/update-recovery-otp.md @@ -0,0 +1,20 @@ +```python +from appwrite.client import Client +from appwrite.services.account import Account +from appwrite.models import Token + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +account = Account(client) + +result: Token = account.update_recovery_otp( + user_id = '', + secret = '', + password = 'password' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/avatars/delete-photo.md b/docs/examples/avatars/delete-photo.md new file mode 100644 index 00000000..0851c0c5 --- /dev/null +++ b/docs/examples/avatars/delete-photo.md @@ -0,0 +1,13 @@ +```python +from appwrite.client import Client +from appwrite.services.avatars import Avatars + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +avatars = Avatars(client) + +result = avatars.delete_photo() +``` diff --git a/docs/examples/avatars/get-browser.md b/docs/examples/avatars/get-browser.md index 3c950dbb..622244be 100644 --- a/docs/examples/avatars/get-browser.md +++ b/docs/examples/avatars/get-browser.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.avatars import Avatars -from appwrite.enums import Browser +from appwrite.enums.browser import Browser client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/avatars/get-credit-card.md b/docs/examples/avatars/get-credit-card.md index 8ef04f63..8888b752 100644 --- a/docs/examples/avatars/get-credit-card.md +++ b/docs/examples/avatars/get-credit-card.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.avatars import Avatars -from appwrite.enums import CreditCard +from appwrite.enums.credit_card import CreditCard client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/avatars/get-flag.md b/docs/examples/avatars/get-flag.md index f97b20dd..c8b628d8 100644 --- a/docs/examples/avatars/get-flag.md +++ b/docs/examples/avatars/get-flag.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.avatars import Avatars -from appwrite.enums import Flag +from appwrite.enums.flag import Flag client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/avatars/get-screenshot.md b/docs/examples/avatars/get-screenshot.md index cf7f9a6b..7e39b59b 100644 --- a/docs/examples/avatars/get-screenshot.md +++ b/docs/examples/avatars/get-screenshot.md @@ -1,10 +1,10 @@ ```python from appwrite.client import Client from appwrite.services.avatars import Avatars -from appwrite.enums import BrowserTheme -from appwrite.enums import Timezone -from appwrite.enums import BrowserPermission -from appwrite.enums import ImageFormat +from appwrite.enums.browser_theme import BrowserTheme +from appwrite.enums.timezone import Timezone +from appwrite.enums.browser_permission import BrowserPermission +from appwrite.enums.image_format import ImageFormat client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint @@ -16,8 +16,7 @@ avatars = Avatars(client) result: bytes = avatars.get_screenshot( url = 'https://example.com', headers = { - "Authorization": "Bearer token123", - "X-Custom-Header": "value" + "Accept-Language": "en-US,en;q=0.9" }, # optional viewport_width = 1920, # optional viewport_height = 1080, # optional diff --git a/docs/examples/avatars/update-photo.md b/docs/examples/avatars/update-photo.md new file mode 100644 index 00000000..cdd605a0 --- /dev/null +++ b/docs/examples/avatars/update-photo.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.avatars import Avatars +from appwrite.input_file import InputFile +from appwrite.models import Account + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +avatars = Avatars(client) + +result: Account = avatars.update_photo( + file = InputFile.from_path('file.png') +) + +print(result.model_dump()) +``` diff --git a/docs/examples/backups/create-archive.md b/docs/examples/backups/create-archive.md index 77264469..6d25a93b 100644 --- a/docs/examples/backups/create-archive.md +++ b/docs/examples/backups/create-archive.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.backups import Backups from appwrite.models import BackupArchive -from appwrite.enums import BackupServices +from appwrite.enums.backup_services import BackupServices client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/backups/create-policy.md b/docs/examples/backups/create-policy.md index bf24e87a..a100d80e 100644 --- a/docs/examples/backups/create-policy.md +++ b/docs/examples/backups/create-policy.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.backups import Backups from appwrite.models import BackupPolicy -from appwrite.enums import BackupServices +from appwrite.enums.backup_services import BackupServices client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/backups/create-restoration.md b/docs/examples/backups/create-restoration.md index e2966caa..0c116884 100644 --- a/docs/examples/backups/create-restoration.md +++ b/docs/examples/backups/create-restoration.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.backups import Backups from appwrite.models import BackupRestoration -from appwrite.enums import BackupServices +from appwrite.enums.backup_services import BackupServices client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/databases/create-documents.md b/docs/examples/databases/create-documents.md index a1df96a9..13e7b94f 100644 --- a/docs/examples/databases/create-documents.md +++ b/docs/examples/databases/create-documents.md @@ -13,7 +13,16 @@ databases = Databases(client) result: DocumentList = databases.create_documents( database_id = '', collection_id = '', - documents = [], + documents = [ + { + "$id": "example1", + "username": "walter.obrien", + "email": "walter.obrien@example.com", + "fullName": "Walter O'Brien", + "age": 30, + "isAdmin": false + } + ], transaction_id = '' # optional ) diff --git a/docs/examples/databases/create-index.md b/docs/examples/databases/create-index.md index 71c694f1..8733b72a 100644 --- a/docs/examples/databases/create-index.md +++ b/docs/examples/databases/create-index.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.databases import Databases from appwrite.models import Index -from appwrite.enums import DatabasesIndexType -from appwrite.enums import OrderBy +from appwrite.enums.databases_index_type import DatabasesIndexType +from appwrite.enums.order_by import OrderBy client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint @@ -17,7 +17,7 @@ result: Index = databases.create_index( collection_id = '', key = '', type = DatabasesIndexType.KEY, - attributes = [], + attributes = ["username"], orders = [OrderBy.ASC], # optional lengths = [] # optional ) diff --git a/docs/examples/databases/create-relationship-attribute.md b/docs/examples/databases/create-relationship-attribute.md index 81959496..48821cac 100644 --- a/docs/examples/databases/create-relationship-attribute.md +++ b/docs/examples/databases/create-relationship-attribute.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.databases import Databases from appwrite.models import AttributeRelationship -from appwrite.enums import RelationshipType -from appwrite.enums import RelationMutate +from appwrite.enums.relationship_type import RelationshipType +from appwrite.enums.relation_mutate import RelationMutate client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/databases/delete-documents.md b/docs/examples/databases/delete-documents.md index d410bdef..21a2a214 100644 --- a/docs/examples/databases/delete-documents.md +++ b/docs/examples/databases/delete-documents.md @@ -13,7 +13,7 @@ databases = Databases(client) result: DocumentList = databases.delete_documents( database_id = '', collection_id = '', - queries = [], # optional + queries = ["{\"method\":\"equal\", \"attribute\":\"$id\", \"values\":[\"\"]}"], # optional transaction_id = '' # optional ) diff --git a/docs/examples/databases/get-attribute.md b/docs/examples/databases/get-attribute.md index 880a5872..fdcc23da 100644 --- a/docs/examples/databases/get-attribute.md +++ b/docs/examples/databases/get-attribute.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.databases import Databases from appwrite.models import AttributeBoolean +from appwrite.models import AttributeBigint from appwrite.models import AttributeInteger from appwrite.models import AttributeFloat from appwrite.models import AttributeEmail @@ -10,6 +11,13 @@ from appwrite.models import AttributeUrl from appwrite.models import AttributeIp from appwrite.models import AttributeDatetime from appwrite.models import AttributeRelationship +from appwrite.models import AttributePoint +from appwrite.models import AttributeLine +from appwrite.models import AttributePolygon +from appwrite.models import AttributeVarchar +from appwrite.models import AttributeText +from appwrite.models import AttributeMediumtext +from appwrite.models import AttributeLongtext from appwrite.models import AttributeString from typing import Union @@ -20,7 +28,7 @@ client.set_key('') # Your secret API key databases = Databases(client) -result: Union[AttributeBoolean, AttributeInteger, AttributeFloat, AttributeEmail, AttributeEnum, AttributeUrl, AttributeIp, AttributeDatetime, AttributeRelationship, AttributeString] = databases.get_attribute( +result: Union[AttributeBoolean, AttributeBigint, AttributeInteger, AttributeFloat, AttributeEmail, AttributeEnum, AttributeUrl, AttributeIp, AttributeDatetime, AttributeRelationship, AttributePoint, AttributeLine, AttributePolygon, AttributeVarchar, AttributeText, AttributeMediumtext, AttributeLongtext, AttributeString] = databases.get_attribute( database_id = '', collection_id = '', key = '' diff --git a/docs/examples/databases/list-transactions.md b/docs/examples/databases/list-transactions.md index bd099314..d382cb93 100644 --- a/docs/examples/databases/list-transactions.md +++ b/docs/examples/databases/list-transactions.md @@ -11,7 +11,8 @@ client.set_key('') # Your secret API key databases = Databases(client) result: TransactionList = databases.list_transactions( - queries = [] # optional + queries = [], # optional + total = False # optional ) print(result.model_dump()) diff --git a/docs/examples/databases/update-relationship-attribute.md b/docs/examples/databases/update-relationship-attribute.md index a507aca1..cc328d63 100644 --- a/docs/examples/databases/update-relationship-attribute.md +++ b/docs/examples/databases/update-relationship-attribute.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.databases import Databases from appwrite.models import AttributeRelationship -from appwrite.enums import RelationMutate +from appwrite.enums.relation_mutate import RelationMutate client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/databases/upsert-documents.md b/docs/examples/databases/upsert-documents.md index 5039ccb0..ae28f031 100644 --- a/docs/examples/databases/upsert-documents.md +++ b/docs/examples/databases/upsert-documents.md @@ -13,7 +13,16 @@ databases = Databases(client) result: DocumentList = databases.upsert_documents( database_id = '', collection_id = '', - documents = [], + documents = [ + { + "$id": "example1", + "username": "walter.obrien", + "email": "walter.obrien@example.com", + "fullName": "Walter O'Brien", + "age": 30, + "isAdmin": false + } + ], transaction_id = '' # optional ) diff --git a/docs/examples/documentsdb/create-documents.md b/docs/examples/documentsdb/create-documents.md index 2b15e560..7f470a36 100644 --- a/docs/examples/documentsdb/create-documents.md +++ b/docs/examples/documentsdb/create-documents.md @@ -13,7 +13,16 @@ documents_db = DocumentsDB(client) result: DocumentList = documents_db.create_documents( database_id = '', collection_id = '', - documents = [], + documents = [ + { + "$id": "example1", + "username": "walter.obrien", + "email": "walter.obrien@example.com", + "fullName": "Walter O'Brien", + "age": 30, + "isAdmin": false + } + ], transaction_id = '' # optional ) diff --git a/docs/examples/documentsdb/create-index.md b/docs/examples/documentsdb/create-index.md index 34a36dc8..51eea435 100644 --- a/docs/examples/documentsdb/create-index.md +++ b/docs/examples/documentsdb/create-index.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.documents_db import DocumentsDB from appwrite.models import Index -from appwrite.enums import DocumentsDBIndexType -from appwrite.enums import OrderBy +from appwrite.enums.documents_db_index_type import DocumentsDBIndexType +from appwrite.enums.order_by import OrderBy client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint @@ -17,7 +17,7 @@ result: Index = documents_db.create_index( collection_id = '', key = '', type = DocumentsDBIndexType.KEY, - attributes = [], + attributes = ["username"], orders = [OrderBy.ASC], # optional lengths = [] # optional ) diff --git a/docs/examples/documentsdb/delete-documents.md b/docs/examples/documentsdb/delete-documents.md index 8bc343de..4b127c79 100644 --- a/docs/examples/documentsdb/delete-documents.md +++ b/docs/examples/documentsdb/delete-documents.md @@ -13,7 +13,7 @@ documents_db = DocumentsDB(client) result: DocumentList = documents_db.delete_documents( database_id = '', collection_id = '', - queries = [], # optional + queries = ["{\"method\":\"equal\", \"attribute\":\"$id\", \"values\":[\"\"]}"], # optional transaction_id = '' # optional ) diff --git a/docs/examples/documentsdb/list-transactions.md b/docs/examples/documentsdb/list-transactions.md index 6dc7aae2..7128d9b5 100644 --- a/docs/examples/documentsdb/list-transactions.md +++ b/docs/examples/documentsdb/list-transactions.md @@ -11,7 +11,8 @@ client.set_key('') # Your secret API key documents_db = DocumentsDB(client) result: TransactionList = documents_db.list_transactions( - queries = [] # optional + queries = [], # optional + total = False # optional ) print(result.model_dump()) diff --git a/docs/examples/documentsdb/upsert-documents.md b/docs/examples/documentsdb/upsert-documents.md index d98b227c..f1613df1 100644 --- a/docs/examples/documentsdb/upsert-documents.md +++ b/docs/examples/documentsdb/upsert-documents.md @@ -13,7 +13,16 @@ documents_db = DocumentsDB(client) result: DocumentList = documents_db.upsert_documents( database_id = '', collection_id = '', - documents = [], + documents = [ + { + "$id": "example1", + "username": "walter.obrien", + "email": "walter.obrien@example.com", + "fullName": "Walter O'Brien", + "age": 30, + "isAdmin": false + } + ], transaction_id = '' # optional ) diff --git a/docs/examples/domains/create-preset-google-workspace.md b/docs/examples/domains/create-preset-google-workspace.md new file mode 100644 index 00000000..73c5594e --- /dev/null +++ b/docs/examples/domains/create-preset-google-workspace.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.create_preset_google_workspace( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-preset-i-cloud.md b/docs/examples/domains/create-preset-i-cloud.md new file mode 100644 index 00000000..d9a957aa --- /dev/null +++ b/docs/examples/domains/create-preset-i-cloud.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.create_preset_i_cloud( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-preset-mailgun.md b/docs/examples/domains/create-preset-mailgun.md new file mode 100644 index 00000000..89012267 --- /dev/null +++ b/docs/examples/domains/create-preset-mailgun.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.create_preset_mailgun( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-preset-outlook.md b/docs/examples/domains/create-preset-outlook.md new file mode 100644 index 00000000..b8e0f790 --- /dev/null +++ b/docs/examples/domains/create-preset-outlook.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.create_preset_outlook( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-preset-proton-mail.md b/docs/examples/domains/create-preset-proton-mail.md new file mode 100644 index 00000000..1caf9d5d --- /dev/null +++ b/docs/examples/domains/create-preset-proton-mail.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.create_preset_proton_mail( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-preset-zoho.md b/docs/examples/domains/create-preset-zoho.md new file mode 100644 index 00000000..bc5a7c2a --- /dev/null +++ b/docs/examples/domains/create-preset-zoho.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.create_preset_zoho( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-a.md b/docs/examples/domains/create-record-a.md new file mode 100644 index 00000000..17be375e --- /dev/null +++ b/docs/examples/domains/create-record-a.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_a( + domain_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-aaaa.md b/docs/examples/domains/create-record-aaaa.md new file mode 100644 index 00000000..c02fff65 --- /dev/null +++ b/docs/examples/domains/create-record-aaaa.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_aaaa( + domain_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-alias.md b/docs/examples/domains/create-record-alias.md new file mode 100644 index 00000000..a5c9f167 --- /dev/null +++ b/docs/examples/domains/create-record-alias.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_alias( + domain_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-caa.md b/docs/examples/domains/create-record-caa.md new file mode 100644 index 00000000..5e0ee5d8 --- /dev/null +++ b/docs/examples/domains/create-record-caa.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_caa( + domain_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-cname.md b/docs/examples/domains/create-record-cname.md new file mode 100644 index 00000000..8afe96a2 --- /dev/null +++ b/docs/examples/domains/create-record-cname.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_cname( + domain_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-https.md b/docs/examples/domains/create-record-https.md new file mode 100644 index 00000000..2448b64c --- /dev/null +++ b/docs/examples/domains/create-record-https.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_https( + domain_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-mx.md b/docs/examples/domains/create-record-mx.md new file mode 100644 index 00000000..ef492fe1 --- /dev/null +++ b/docs/examples/domains/create-record-mx.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_mx( + domain_id = '', + name = '', + value = '', + ttl = 1, + priority = 0, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-ns.md b/docs/examples/domains/create-record-ns.md new file mode 100644 index 00000000..bc2e4187 --- /dev/null +++ b/docs/examples/domains/create-record-ns.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_ns( + domain_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-srv.md b/docs/examples/domains/create-record-srv.md new file mode 100644 index 00000000..04071b34 --- /dev/null +++ b/docs/examples/domains/create-record-srv.md @@ -0,0 +1,25 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_srv( + domain_id = '', + name = '', + value = '', + ttl = 1, + priority = 0, + weight = 0, + port = 0, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create-record-txt.md b/docs/examples/domains/create-record-txt.md new file mode 100644 index 00000000..4a66afd0 --- /dev/null +++ b/docs/examples/domains/create-record-txt.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.create_record_txt( + domain_id = '', + name = '', + ttl = 1, + value = '', # optional + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/create.md b/docs/examples/domains/create.md new file mode 100644 index 00000000..01c02414 --- /dev/null +++ b/docs/examples/domains/create.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import Domain + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: Domain = domains.create( + team_id = '', + domain = 'example.com' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/delete-record.md b/docs/examples/domains/delete-record.md new file mode 100644 index 00000000..40b12e83 --- /dev/null +++ b/docs/examples/domains/delete-record.md @@ -0,0 +1,16 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result = domains.delete_record( + domain_id = '', + record_id = '' +) +``` diff --git a/docs/examples/domains/delete.md b/docs/examples/domains/delete.md new file mode 100644 index 00000000..f9cb3c43 --- /dev/null +++ b/docs/examples/domains/delete.md @@ -0,0 +1,15 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result = domains.delete( + domain_id = '' +) +``` diff --git a/docs/examples/domains/get-preset-google-workspace.md b/docs/examples/domains/get-preset-google-workspace.md new file mode 100644 index 00000000..e228af7c --- /dev/null +++ b/docs/examples/domains/get-preset-google-workspace.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.get_preset_google_workspace( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-preset-i-cloud.md b/docs/examples/domains/get-preset-i-cloud.md new file mode 100644 index 00000000..5b0169c2 --- /dev/null +++ b/docs/examples/domains/get-preset-i-cloud.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.get_preset_i_cloud( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-preset-mailgun.md b/docs/examples/domains/get-preset-mailgun.md new file mode 100644 index 00000000..494f42a5 --- /dev/null +++ b/docs/examples/domains/get-preset-mailgun.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.get_preset_mailgun( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-preset-outlook.md b/docs/examples/domains/get-preset-outlook.md new file mode 100644 index 00000000..5daf056d --- /dev/null +++ b/docs/examples/domains/get-preset-outlook.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.get_preset_outlook( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-preset-proton-mail.md b/docs/examples/domains/get-preset-proton-mail.md new file mode 100644 index 00000000..5dff2d5b --- /dev/null +++ b/docs/examples/domains/get-preset-proton-mail.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.get_preset_proton_mail( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-preset-zoho.md b/docs/examples/domains/get-preset-zoho.md new file mode 100644 index 00000000..b9f6e1ab --- /dev/null +++ b/docs/examples/domains/get-preset-zoho.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.get_preset_zoho( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-price.md b/docs/examples/domains/get-price.md new file mode 100644 index 00000000..648998d5 --- /dev/null +++ b/docs/examples/domains/get-price.md @@ -0,0 +1,21 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DomainPrice +from appwrite.enums.domain_registration_type import DomainRegistrationType + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DomainPrice = domains.get_price( + domain = 'example.com', + period_years = None, # optional + registration_type = DomainRegistrationType.NEW # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-record.md b/docs/examples/domains/get-record.md new file mode 100644 index 00000000..e923cd6c --- /dev/null +++ b/docs/examples/domains/get-record.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.get_record( + domain_id = '', + record_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-transfer-status.md b/docs/examples/domains/get-transfer-status.md new file mode 100644 index 00000000..ca10cf7a --- /dev/null +++ b/docs/examples/domains/get-transfer-status.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DomainTransferStatus + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DomainTransferStatus = domains.get_transfer_status( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/get-zone.md b/docs/examples/domains/get-zone.md new file mode 100644 index 00000000..ad17f2dc --- /dev/null +++ b/docs/examples/domains/get-zone.md @@ -0,0 +1,15 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result = domains.get_zone( + domain_id = '' +) +``` diff --git a/docs/examples/domains/get.md b/docs/examples/domains/get.md new file mode 100644 index 00000000..c1d772d4 --- /dev/null +++ b/docs/examples/domains/get.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import Domain + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: Domain = domains.get( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/list-prices.md b/docs/examples/domains/list-prices.md new file mode 100644 index 00000000..ea6907e7 --- /dev/null +++ b/docs/examples/domains/list-prices.md @@ -0,0 +1,21 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DomainPricesList +from appwrite.enums.domain_registration_type import DomainRegistrationType + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DomainPricesList = domains.list_prices( + domains = [], + period_years = None, # optional + registration_type = DomainRegistrationType.NEW # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/list-records.md b/docs/examples/domains/list-records.md new file mode 100644 index 00000000..9d40d255 --- /dev/null +++ b/docs/examples/domains/list-records.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecordsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecordsList = domains.list_records( + domain_id = '', + queries = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/list.md b/docs/examples/domains/list.md new file mode 100644 index 00000000..f0d15a75 --- /dev/null +++ b/docs/examples/domains/list.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DomainsList + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DomainsList = domains.list( + queries = [], # optional + search = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-nameservers.md b/docs/examples/domains/update-nameservers.md new file mode 100644 index 00000000..0e5ed4be --- /dev/null +++ b/docs/examples/domains/update-nameservers.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import Domain + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: Domain = domains.update_nameservers( + domain_id = '', + nameservers = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-a.md b/docs/examples/domains/update-record-a.md new file mode 100644 index 00000000..516e273b --- /dev/null +++ b/docs/examples/domains/update-record-a.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_a( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-aaaa.md b/docs/examples/domains/update-record-aaaa.md new file mode 100644 index 00000000..1d36e41f --- /dev/null +++ b/docs/examples/domains/update-record-aaaa.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_aaaa( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-alias.md b/docs/examples/domains/update-record-alias.md new file mode 100644 index 00000000..9dc96784 --- /dev/null +++ b/docs/examples/domains/update-record-alias.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_alias( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-caa.md b/docs/examples/domains/update-record-caa.md new file mode 100644 index 00000000..e1c74e35 --- /dev/null +++ b/docs/examples/domains/update-record-caa.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_caa( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-cname.md b/docs/examples/domains/update-record-cname.md new file mode 100644 index 00000000..35e12cd6 --- /dev/null +++ b/docs/examples/domains/update-record-cname.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_cname( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-https.md b/docs/examples/domains/update-record-https.md new file mode 100644 index 00000000..c31e963d --- /dev/null +++ b/docs/examples/domains/update-record-https.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_https( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-mx.md b/docs/examples/domains/update-record-mx.md new file mode 100644 index 00000000..bd96398a --- /dev/null +++ b/docs/examples/domains/update-record-mx.md @@ -0,0 +1,24 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_mx( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + priority = 0, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-ns.md b/docs/examples/domains/update-record-ns.md new file mode 100644 index 00000000..3ca42be8 --- /dev/null +++ b/docs/examples/domains/update-record-ns.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_ns( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-srv.md b/docs/examples/domains/update-record-srv.md new file mode 100644 index 00000000..c47f9f2c --- /dev/null +++ b/docs/examples/domains/update-record-srv.md @@ -0,0 +1,26 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_srv( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + priority = 0, + weight = 0, + port = 0, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-record-txt.md b/docs/examples/domains/update-record-txt.md new file mode 100644 index 00000000..b6461701 --- /dev/null +++ b/docs/examples/domains/update-record-txt.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import DnsRecord + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: DnsRecord = domains.update_record_txt( + domain_id = '', + record_id = '', + name = '', + value = '', + ttl = 1, + comment = '' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-team.md b/docs/examples/domains/update-team.md new file mode 100644 index 00000000..3963e778 --- /dev/null +++ b/docs/examples/domains/update-team.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import Domain + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: Domain = domains.update_team( + domain_id = '', + team_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/update-zone.md b/docs/examples/domains/update-zone.md new file mode 100644 index 00000000..89e9011a --- /dev/null +++ b/docs/examples/domains/update-zone.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import Domain + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: Domain = domains.update_zone( + domain_id = '', + content = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/domains/verify-nameservers.md b/docs/examples/domains/verify-nameservers.md new file mode 100644 index 00000000..13caac7f --- /dev/null +++ b/docs/examples/domains/verify-nameservers.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.domains import Domains +from appwrite.models import Domain + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +domains = Domains(client) + +result: Domain = domains.verify_nameservers( + domain_id = '' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/embeddings/create-text-embeddings.md b/docs/examples/embeddings/create-text-embeddings.md index 49d3c258..36da57c3 100644 --- a/docs/examples/embeddings/create-text-embeddings.md +++ b/docs/examples/embeddings/create-text-embeddings.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.embeddings import Embeddings from appwrite.models import EmbeddingList -from appwrite.enums import EmbeddingModel +from appwrite.enums.embedding_model import EmbeddingModel client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint @@ -12,7 +12,7 @@ client.set_key('') # Your secret API key embeddings = Embeddings(client) result: EmbeddingList = embeddings.create_text_embeddings( - texts = [], + texts = ["Appwrite helps developers build applications.", "Find documents with semantic search."], model = EmbeddingModel.NOMIC_EMBED_TEXT # optional ) diff --git a/docs/examples/functions/create-execution.md b/docs/examples/functions/create-execution.md index c88c00ef..a57c0415 100644 --- a/docs/examples/functions/create-execution.md +++ b/docs/examples/functions/create-execution.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.functions import Functions from appwrite.models import Execution -from appwrite.enums import ExecutionMethod +from appwrite.enums.execution_method import ExecutionMethod client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/functions/create-template-deployment.md b/docs/examples/functions/create-template-deployment.md index 19227be6..cd7511d5 100644 --- a/docs/examples/functions/create-template-deployment.md +++ b/docs/examples/functions/create-template-deployment.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.functions import Functions from appwrite.models import Deployment -from appwrite.enums import TemplateReferenceType +from appwrite.enums.template_reference_type import TemplateReferenceType client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/functions/create-vcs-deployment.md b/docs/examples/functions/create-vcs-deployment.md index be644a7c..37a2d604 100644 --- a/docs/examples/functions/create-vcs-deployment.md +++ b/docs/examples/functions/create-vcs-deployment.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.functions import Functions from appwrite.models import Deployment -from appwrite.enums import VCSReferenceType +from appwrite.enums.vcs_reference_type import VCSReferenceType client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/functions/create.md b/docs/examples/functions/create.md index 9f61841b..46652c4a 100644 --- a/docs/examples/functions/create.md +++ b/docs/examples/functions/create.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.functions import Functions from appwrite.models import Function -from appwrite.enums import Runtime -from appwrite.enums import ProjectKeyScopes +from appwrite.enums.runtime import Runtime +from appwrite.enums.project_key_scopes import ProjectKeyScopes client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/functions/get-deployment-download.md b/docs/examples/functions/get-deployment-download.md index 49df861b..186211e8 100644 --- a/docs/examples/functions/get-deployment-download.md +++ b/docs/examples/functions/get-deployment-download.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.functions import Functions -from appwrite.enums import DeploymentDownloadType +from appwrite.enums.deployment_download_type import DeploymentDownloadType client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/functions/list-runtimes.md b/docs/examples/functions/list-runtimes.md index ee75c80e..a33db3ad 100644 --- a/docs/examples/functions/list-runtimes.md +++ b/docs/examples/functions/list-runtimes.md @@ -10,7 +10,9 @@ client.set_key('') # Your secret API key functions = Functions(client) -result: RuntimeList = functions.list_runtimes() +result: RuntimeList = functions.list_runtimes( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/functions/list-specifications.md b/docs/examples/functions/list-specifications.md index 7cf529a9..ff71a1be 100644 --- a/docs/examples/functions/list-specifications.md +++ b/docs/examples/functions/list-specifications.md @@ -11,7 +11,8 @@ client.set_key('') # Your secret API key functions = Functions(client) result: SpecificationList = functions.list_specifications( - type = 'runtimes' # optional + type = 'runtimes', # optional + total = False # optional ) print(result.model_dump()) diff --git a/docs/examples/functions/update.md b/docs/examples/functions/update.md index 4e819331..b07cb5ac 100644 --- a/docs/examples/functions/update.md +++ b/docs/examples/functions/update.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.functions import Functions from appwrite.models import Function -from appwrite.enums import Runtime -from appwrite.enums import ProjectKeyScopes +from appwrite.enums.runtime import Runtime +from appwrite.enums.project_key_scopes import ProjectKeyScopes client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/graphql/mutation.md b/docs/examples/graphql/mutation.md index 26ed1cbe..a7609b1f 100644 --- a/docs/examples/graphql/mutation.md +++ b/docs/examples/graphql/mutation.md @@ -10,6 +10,8 @@ client.set_key('') # Your secret API key graphql = Graphql(client) result = graphql.mutation( - query = {} + query = { + "query": "mutation { accountUpdateName(name: \"Walter\") { name } }" + } ) ``` diff --git a/docs/examples/graphql/query.md b/docs/examples/graphql/query.md index 94142f99..350c47ba 100644 --- a/docs/examples/graphql/query.md +++ b/docs/examples/graphql/query.md @@ -10,6 +10,8 @@ client.set_key('') # Your secret API key graphql = Graphql(client) result = graphql.query( - query = {} + query = { + "query": "query { localeGet { ip } }" + } ) ``` diff --git a/docs/examples/locale/list-codes.md b/docs/examples/locale/list-codes.md index adc29396..66079411 100644 --- a/docs/examples/locale/list-codes.md +++ b/docs/examples/locale/list-codes.md @@ -10,7 +10,9 @@ client.set_session('') # The user session to authenticate with locale = Locale(client) -result: LocaleCodeList = locale.list_codes() +result: LocaleCodeList = locale.list_codes( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/locale/list-continents.md b/docs/examples/locale/list-continents.md index fcf05e6e..cc7c3fd7 100644 --- a/docs/examples/locale/list-continents.md +++ b/docs/examples/locale/list-continents.md @@ -10,7 +10,9 @@ client.set_session('') # The user session to authenticate with locale = Locale(client) -result: ContinentList = locale.list_continents() +result: ContinentList = locale.list_continents( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/locale/list-countries-eu.md b/docs/examples/locale/list-countries-eu.md index 374cc9a3..d7bebd5a 100644 --- a/docs/examples/locale/list-countries-eu.md +++ b/docs/examples/locale/list-countries-eu.md @@ -10,7 +10,9 @@ client.set_session('') # The user session to authenticate with locale = Locale(client) -result: CountryList = locale.list_countries_eu() +result: CountryList = locale.list_countries_eu( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/locale/list-countries-phones.md b/docs/examples/locale/list-countries-phones.md index 8b36a1f9..cf23539b 100644 --- a/docs/examples/locale/list-countries-phones.md +++ b/docs/examples/locale/list-countries-phones.md @@ -10,7 +10,9 @@ client.set_session('') # The user session to authenticate with locale = Locale(client) -result: PhoneList = locale.list_countries_phones() +result: PhoneList = locale.list_countries_phones( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/locale/list-countries.md b/docs/examples/locale/list-countries.md index 5c45a766..73cb699f 100644 --- a/docs/examples/locale/list-countries.md +++ b/docs/examples/locale/list-countries.md @@ -10,7 +10,9 @@ client.set_session('') # The user session to authenticate with locale = Locale(client) -result: CountryList = locale.list_countries() +result: CountryList = locale.list_countries( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/locale/list-currencies.md b/docs/examples/locale/list-currencies.md index 07f061c9..6d4d2628 100644 --- a/docs/examples/locale/list-currencies.md +++ b/docs/examples/locale/list-currencies.md @@ -10,7 +10,9 @@ client.set_session('') # The user session to authenticate with locale = Locale(client) -result: CurrencyList = locale.list_currencies() +result: CurrencyList = locale.list_currencies( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/locale/list-languages.md b/docs/examples/locale/list-languages.md index 3fb0c82c..ea1f75f2 100644 --- a/docs/examples/locale/list-languages.md +++ b/docs/examples/locale/list-languages.md @@ -10,7 +10,9 @@ client.set_session('') # The user session to authenticate with locale = Locale(client) -result: LanguageList = locale.list_languages() +result: LanguageList = locale.list_languages( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/messaging/create-appwrite-provider.md b/docs/examples/messaging/create-appwrite-provider.md new file mode 100644 index 00000000..c17c582e --- /dev/null +++ b/docs/examples/messaging/create-appwrite-provider.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.messaging import Messaging +from appwrite.models import Provider + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +messaging = Messaging(client) + +result: Provider = messaging.create_appwrite_provider( + provider_id = '', + name = '', + enabled = False, # optional + qos = 0, # optional + expiry = 0 # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/messaging/create-email.md b/docs/examples/messaging/create-email.md index a6454e49..32d94594 100644 --- a/docs/examples/messaging/create-email.md +++ b/docs/examples/messaging/create-email.md @@ -20,6 +20,8 @@ result: Message = messaging.create_email( cc = [], # optional bcc = [], # optional attachments = [], # optional + reply_to_email = 'email@example.com', # optional + reply_to_name = '', # optional draft = False, # optional html = False, # optional scheduled_at = '2020-10-15T06:38:00.000+00:00' # optional diff --git a/docs/examples/messaging/create-push.md b/docs/examples/messaging/create-push.md index 155128a0..f4b4ff8c 100644 --- a/docs/examples/messaging/create-push.md +++ b/docs/examples/messaging/create-push.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.messaging import Messaging from appwrite.models import Message -from appwrite.enums import MessagePriority +from appwrite.enums.message_priority import MessagePriority client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint @@ -30,7 +30,8 @@ result: Message = messaging.create_push( scheduled_at = '2020-10-15T06:38:00.000+00:00', # optional content_available = False, # optional critical = False, # optional - priority = MessagePriority.NORMAL # optional + priority = MessagePriority.NORMAL, # optional + channel_id = '' # optional ) print(result.model_dump()) diff --git a/docs/examples/messaging/create-smtp-provider.md b/docs/examples/messaging/create-smtp-provider.md index 9681bc18..98eabeff 100644 --- a/docs/examples/messaging/create-smtp-provider.md +++ b/docs/examples/messaging/create-smtp-provider.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.messaging import Messaging from appwrite.models import Provider -from appwrite.enums import SmtpEncryption +from appwrite.enums.smtp_encryption import SmtpEncryption client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/messaging/create-topic.md b/docs/examples/messaging/create-topic.md index 3a6547eb..93388456 100644 --- a/docs/examples/messaging/create-topic.md +++ b/docs/examples/messaging/create-topic.md @@ -13,7 +13,9 @@ messaging = Messaging(client) result: Topic = messaging.create_topic( topic_id = '', name = '', - subscribe = ["any"] # optional + subscribe = ["any"], # optional + qos = 0, # optional + expiry = 0 # optional ) print(result.model_dump()) diff --git a/docs/examples/messaging/create-twilio-provider.md b/docs/examples/messaging/create-twilio-provider.md index 6a20087d..b0e31595 100644 --- a/docs/examples/messaging/create-twilio-provider.md +++ b/docs/examples/messaging/create-twilio-provider.md @@ -13,7 +13,7 @@ messaging = Messaging(client) result: Provider = messaging.create_twilio_provider( provider_id = '', name = '', - from = '+12065550100', # optional + from = '', # optional account_sid = '', # optional auth_token = '', # optional enabled = False # optional diff --git a/docs/examples/messaging/update-appwrite-provider.md b/docs/examples/messaging/update-appwrite-provider.md new file mode 100644 index 00000000..6b931ab6 --- /dev/null +++ b/docs/examples/messaging/update-appwrite-provider.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.messaging import Messaging +from appwrite.models import Provider + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +messaging = Messaging(client) + +result: Provider = messaging.update_appwrite_provider( + provider_id = '', + name = '', # optional + enabled = False, # optional + qos = 0, # optional + expiry = 0 # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/messaging/update-email.md b/docs/examples/messaging/update-email.md index 94d2d407..b8659ff0 100644 --- a/docs/examples/messaging/update-email.md +++ b/docs/examples/messaging/update-email.md @@ -12,17 +12,19 @@ messaging = Messaging(client) result: Message = messaging.update_email( message_id = '', + subject = '', # optional + content = '', # optional topics = [], # optional users = [], # optional targets = [], # optional - subject = '', # optional - content = '', # optional - draft = False, # optional - html = False, # optional cc = [], # optional bcc = [], # optional - scheduled_at = '2020-10-15T06:38:00.000+00:00', # optional - attachments = [] # optional + attachments = [], # optional + reply_to_email = 'email@example.com', # optional + reply_to_name = '', # optional + draft = False, # optional + html = False, # optional + scheduled_at = '2020-10-15T06:38:00.000+00:00' # optional ) print(result.model_dump()) diff --git a/docs/examples/messaging/update-push.md b/docs/examples/messaging/update-push.md index 0c592d6c..109ad1f7 100644 --- a/docs/examples/messaging/update-push.md +++ b/docs/examples/messaging/update-push.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.messaging import Messaging from appwrite.models import Message -from appwrite.enums import MessagePriority +from appwrite.enums.message_priority import MessagePriority client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint @@ -13,11 +13,11 @@ messaging = Messaging(client) result: Message = messaging.update_push( message_id = '', + title = '', # optional + body = '<BODY>', # optional topics = [], # optional users = [], # optional targets = [], # optional - title = '<TITLE>', # optional - body = '<BODY>', # optional data = {}, # optional action = '<ACTION>', # optional image = '<ID1:ID2>', # optional @@ -30,7 +30,8 @@ result: Message = messaging.update_push( scheduled_at = '2020-10-15T06:38:00.000+00:00', # optional content_available = False, # optional critical = False, # optional - priority = MessagePriority.NORMAL # optional + priority = MessagePriority.NORMAL, # optional + channel_id = '<CHANNEL_ID>' # optional ) print(result.model_dump()) diff --git a/docs/examples/messaging/update-sms.md b/docs/examples/messaging/update-sms.md index 32698978..f499e6ae 100644 --- a/docs/examples/messaging/update-sms.md +++ b/docs/examples/messaging/update-sms.md @@ -12,10 +12,10 @@ messaging = Messaging(client) result: Message = messaging.update_sms( message_id = '<MESSAGE_ID>', + content = '<CONTENT>', # optional topics = [], # optional users = [], # optional targets = [], # optional - content = '<CONTENT>', # optional draft = False, # optional scheduled_at = '2020-10-15T06:38:00.000+00:00' # optional ) diff --git a/docs/examples/messaging/update-smtp-provider.md b/docs/examples/messaging/update-smtp-provider.md index 23294e88..548d72a1 100644 --- a/docs/examples/messaging/update-smtp-provider.md +++ b/docs/examples/messaging/update-smtp-provider.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.messaging import Messaging from appwrite.models import Provider -from appwrite.enums import SmtpEncryption +from appwrite.enums.smtp_encryption import SmtpEncryption client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/messaging/update-topic.md b/docs/examples/messaging/update-topic.md index d7936aa6..4870903a 100644 --- a/docs/examples/messaging/update-topic.md +++ b/docs/examples/messaging/update-topic.md @@ -13,7 +13,9 @@ messaging = Messaging(client) result: Topic = messaging.update_topic( topic_id = '<TOPIC_ID>', name = '<NAME>', # optional - subscribe = ["any"] # optional + subscribe = ["any"], # optional + qos = 0, # optional + expiry = 0 # optional ) print(result.model_dump()) diff --git a/docs/examples/oauth2/approve.md b/docs/examples/oauth2/approve.md index 12bc9c0d..31bb7317 100644 --- a/docs/examples/oauth2/approve.md +++ b/docs/examples/oauth2/approve.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2Approve client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) diff --git a/docs/examples/oauth2/authorize-post.md b/docs/examples/oauth2/authorize-post.md index b6dd6449..8cf274b7 100644 --- a/docs/examples/oauth2/authorize-post.md +++ b/docs/examples/oauth2/authorize-post.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2Authorize client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) @@ -22,7 +22,7 @@ result: Oauth2Authorize = oauth2.authorize_post( prompt = '<PROMPT>', # optional max_age = 0, # optional authorization_details = '<AUTHORIZATION_DETAILS>', # optional - resource = '', # optional + resource = [], # optional audience = '<AUDIENCE>', # optional request_uri = '<REQUEST_URI>' # optional ) diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md index 9d7bb486..32fbf4b2 100644 --- a/docs/examples/oauth2/authorize.md +++ b/docs/examples/oauth2/authorize.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2Authorize client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) @@ -22,7 +22,7 @@ result: Oauth2Authorize = oauth2.authorize( prompt = '<PROMPT>', # optional max_age = 0, # optional authorization_details = '<AUTHORIZATION_DETAILS>', # optional - resource = '', # optional + resource = [], # optional audience = '<AUDIENCE>', # optional request_uri = '<REQUEST_URI>' # optional ) diff --git a/docs/examples/oauth2/create-device-authorization.md b/docs/examples/oauth2/create-device-authorization.md index 0fa3852d..f45ce70c 100644 --- a/docs/examples/oauth2/create-device-authorization.md +++ b/docs/examples/oauth2/create-device-authorization.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2DeviceAuthorization client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) @@ -14,7 +14,7 @@ result: Oauth2DeviceAuthorization = oauth2.create_device_authorization( client_id = '<CLIENT_ID>', # optional scope = '<SCOPE>', # optional authorization_details = '<AUTHORIZATION_DETAILS>', # optional - resource = '', # optional + resource = [], # optional audience = '<AUDIENCE>' # optional ) diff --git a/docs/examples/oauth2/create-grant.md b/docs/examples/oauth2/create-grant.md index 1a87716c..73727320 100644 --- a/docs/examples/oauth2/create-grant.md +++ b/docs/examples/oauth2/create-grant.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2Grant client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) diff --git a/docs/examples/oauth2/create-par.md b/docs/examples/oauth2/create-par.md index 2018794c..32b72a9d 100644 --- a/docs/examples/oauth2/create-par.md +++ b/docs/examples/oauth2/create-par.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2PAR client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) @@ -22,7 +22,7 @@ result: Oauth2PAR = oauth2.create_par( prompt = '<PROMPT>', # optional max_age = 0, # optional authorization_details = '<AUTHORIZATION_DETAILS>', # optional - resource = '', # optional + resource = [], # optional audience = '<AUDIENCE>' # optional ) diff --git a/docs/examples/oauth2/create-token.md b/docs/examples/oauth2/create-token.md index 1d52bbc9..6dd3006b 100644 --- a/docs/examples/oauth2/create-token.md +++ b/docs/examples/oauth2/create-token.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2Token client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) @@ -19,7 +19,7 @@ result: Oauth2Token = oauth2.create_token( client_secret = '<CLIENT_SECRET>', # optional code_verifier = '<CODE_VERIFIER>', # optional redirect_uri = 'https://example.com', # optional - resource = '', # optional + resource = [], # optional audience = '<AUDIENCE>' # optional ) diff --git a/docs/examples/oauth2/get-grant.md b/docs/examples/oauth2/get-grant.md index 51f617f4..77de5ec2 100644 --- a/docs/examples/oauth2/get-grant.md +++ b/docs/examples/oauth2/get-grant.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2Grant client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) diff --git a/docs/examples/oauth2/introspect.md b/docs/examples/oauth2/introspect.md new file mode 100644 index 00000000..bde9da87 --- /dev/null +++ b/docs/examples/oauth2/introspect.md @@ -0,0 +1,21 @@ +```python +from appwrite.client import Client +from appwrite.services.oauth2 import Oauth2 +from appwrite.models import Oauth2Introspection + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +oauth2 = Oauth2(client) + +result: Oauth2Introspection = oauth2.introspect( + token = '<TOKEN>', + token_type_hint = 'access_token', # optional + client_id = '<CLIENT_ID>', # optional + client_secret = '<CLIENT_SECRET>' # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/oauth2/list-organizations.md b/docs/examples/oauth2/list-organizations.md index 42ece3a8..5c429e96 100644 --- a/docs/examples/oauth2/list-organizations.md +++ b/docs/examples/oauth2/list-organizations.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2OrganizationList client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) diff --git a/docs/examples/oauth2/list-projects.md b/docs/examples/oauth2/list-projects.md index 97a58b7b..b6b45f74 100644 --- a/docs/examples/oauth2/list-projects.md +++ b/docs/examples/oauth2/list-projects.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2ProjectList client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) diff --git a/docs/examples/oauth2/reject.md b/docs/examples/oauth2/reject.md index 63f3335f..1979d517 100644 --- a/docs/examples/oauth2/reject.md +++ b/docs/examples/oauth2/reject.md @@ -5,8 +5,8 @@ from appwrite.models import Oauth2Reject client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) diff --git a/docs/examples/oauth2/revoke.md b/docs/examples/oauth2/revoke.md index 70b94f6d..f351c771 100644 --- a/docs/examples/oauth2/revoke.md +++ b/docs/examples/oauth2/revoke.md @@ -4,8 +4,8 @@ from appwrite.services.oauth2 import Oauth2 client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint -client.set_session('') # The user session to authenticate with client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_session('') # The user session to authenticate with oauth2 = Oauth2(client) diff --git a/docs/examples/organization/create-key.md b/docs/examples/organization/create-ephemeral-project-key.md similarity index 58% rename from docs/examples/organization/create-key.md rename to docs/examples/organization/create-ephemeral-project-key.md index 14fee9a7..1762acd3 100644 --- a/docs/examples/organization/create-key.md +++ b/docs/examples/organization/create-ephemeral-project-key.md @@ -1,8 +1,8 @@ ```python from appwrite.client import Client from appwrite.services.organization import Organization -from appwrite.models import Key -from appwrite.enums import OrganizationKeyScopes +from appwrite.models import EphemeralKey +from appwrite.enums.project_key_scopes import ProjectKeyScopes client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -11,11 +11,10 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key organization = Organization(client) -result: Key = organization.create_key( - key_id = '<KEY_ID>', - name = '<NAME>', - scopes = [OrganizationKeyScopes.PROJECTS_READ], - expire = '2020-10-15T06:38:00.000+00:00' # optional +result: EphemeralKey = organization.create_ephemeral_project_key( + project_id = '<PROJECT_ID>', + scopes = [ProjectKeyScopes.USERS_READ], + duration = 600 ) print(result.model_dump()) diff --git a/docs/examples/organization/create-project.md b/docs/examples/organization/create-project.md index da78ecff..6d66e4cc 100644 --- a/docs/examples/organization/create-project.md +++ b/docs/examples/organization/create-project.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.organization import Organization from appwrite.models import Project -from appwrite.enums import Region +from appwrite.enums.region import Region client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/organization/delete-key.md b/docs/examples/organization/delete-project-key.md similarity index 83% rename from docs/examples/organization/delete-key.md rename to docs/examples/organization/delete-project-key.md index 6e48d845..060c6fd4 100644 --- a/docs/examples/organization/delete-key.md +++ b/docs/examples/organization/delete-project-key.md @@ -9,7 +9,8 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key organization = Organization(client) -result = organization.delete_key( +result = organization.delete_project_key( + project_id = '<PROJECT_ID>', key_id = '<KEY_ID>' ) ``` diff --git a/docs/examples/organization/get-key.md b/docs/examples/organization/get-project-key.md similarity index 85% rename from docs/examples/organization/get-key.md rename to docs/examples/organization/get-project-key.md index d60f1190..841e3817 100644 --- a/docs/examples/organization/get-key.md +++ b/docs/examples/organization/get-project-key.md @@ -10,7 +10,8 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key organization = Organization(client) -result: Key = organization.get_key( +result: Key = organization.get_project_key( + project_id = '<PROJECT_ID>', key_id = '<KEY_ID>' ) diff --git a/docs/examples/organization/list-keys.md b/docs/examples/organization/list-project-keys.md similarity index 85% rename from docs/examples/organization/list-keys.md rename to docs/examples/organization/list-project-keys.md index 41634a0e..c09c02cd 100644 --- a/docs/examples/organization/list-keys.md +++ b/docs/examples/organization/list-project-keys.md @@ -10,7 +10,8 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key organization = Organization(client) -result: KeyList = organization.list_keys( +result: KeyList = organization.list_project_keys( + project_id = '<PROJECT_ID>', queries = [], # optional total = False # optional ) diff --git a/docs/examples/organization/update-key.md b/docs/examples/organization/update-project-key.md similarity index 73% rename from docs/examples/organization/update-key.md rename to docs/examples/organization/update-project-key.md index 2c32078b..7f01ddf5 100644 --- a/docs/examples/organization/update-key.md +++ b/docs/examples/organization/update-project-key.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.organization import Organization from appwrite.models import Key -from appwrite.enums import OrganizationKeyScopes +from appwrite.enums.project_key_scopes import ProjectKeyScopes client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -11,10 +11,11 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key organization = Organization(client) -result: Key = organization.update_key( +result: Key = organization.update_project_key( + project_id = '<PROJECT_ID>', key_id = '<KEY_ID>', name = '<NAME>', - scopes = [OrganizationKeyScopes.PROJECTS_READ], + scopes = [ProjectKeyScopes.USERS_READ], expire = '2020-10-15T06:38:00.000+00:00' # optional ) diff --git a/docs/examples/project/create-android-platform.md b/docs/examples/project/create-android-platform.md index 092376e0..60e7f73d 100644 --- a/docs/examples/project/create-android-platform.md +++ b/docs/examples/project/create-android-platform.md @@ -13,7 +13,8 @@ project = Project(client) result: PlatformAndroid = project.create_android_platform( platform_id = '<PLATFORM_ID>', name = '<NAME>', - application_id = '<APPLICATION_ID>' + application_id = '<APPLICATION_ID>', + fingerprints = [] # optional ) print(result.model_dump()) diff --git a/docs/examples/project/create-ephemeral-key.md b/docs/examples/project/create-ephemeral-key.md index 17a48da6..c2b202ad 100644 --- a/docs/examples/project/create-ephemeral-key.md +++ b/docs/examples/project/create-ephemeral-key.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import EphemeralKey -from appwrite.enums import ProjectKeyScopes +from appwrite.enums.project_key_scopes import ProjectKeyScopes client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -12,7 +12,7 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key project = Project(client) result: EphemeralKey = project.create_ephemeral_key( - scopes = [ProjectKeyScopes.PROJECT_READ], + scopes = [ProjectKeyScopes.USERS_READ], duration = 600 ) diff --git a/docs/examples/project/create-smtp-test.md b/docs/examples/project/create-smtp-test.md index 3b39979b..e46cb13e 100644 --- a/docs/examples/project/create-smtp-test.md +++ b/docs/examples/project/create-smtp-test.md @@ -10,6 +10,6 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key project = Project(client) result = project.create_smtp_test( - emails = [] + emails = ["recipient@example.com"] ) ``` diff --git a/docs/examples/project/get-email-template.md b/docs/examples/project/get-email-template.md index 8fedaf74..116cc0ae 100644 --- a/docs/examples/project/get-email-template.md +++ b/docs/examples/project/get-email-template.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import EmailTemplate -from appwrite.enums import ProjectEmailTemplateId -from appwrite.enums import ProjectEmailTemplateLocale +from appwrite.enums.project_email_template_id import ProjectEmailTemplateId +from appwrite.enums.project_email_template_locale import ProjectEmailTemplateLocale client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/project/get-o-auth-2-provider.md b/docs/examples/project/get-o-auth-2-provider.md index e2e8f9e9..55a01469 100644 --- a/docs/examples/project/get-o-auth-2-provider.md +++ b/docs/examples/project/get-o-auth-2-provider.md @@ -16,6 +16,7 @@ from appwrite.models import OAuth2Zoho from appwrite.models import OAuth2Yandex from appwrite.models import OAuth2X from appwrite.models import OAuth2WordPress +from appwrite.models import OAuth2Webflow from appwrite.models import OAuth2Twitch from appwrite.models import OAuth2Stripe from appwrite.models import OAuth2Spotify @@ -44,8 +45,10 @@ from appwrite.models import OAuth2Apple from appwrite.models import OAuth2Okta from appwrite.models import OAuth2Kick from appwrite.models import OAuth2Microsoft +from appwrite.models import OAuth2TikTok +from appwrite.models import OAuth2Kakao from typing import Union -from appwrite.enums import ProjectOAuthProviderId +from appwrite.enums.project_o_auth_provider_id import ProjectOAuthProviderId client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -54,7 +57,7 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key project = Project(client) -result: Union[OAuth2Github, OAuth2Discord, OAuth2Figma, OAuth2Dropbox, OAuth2Dailymotion, OAuth2Bitbucket, OAuth2Bitly, OAuth2Box, OAuth2Autodesk, OAuth2Google, OAuth2Zoom, OAuth2Zoho, OAuth2Yandex, OAuth2X, OAuth2WordPress, OAuth2Twitch, OAuth2Stripe, OAuth2Spotify, OAuth2Slack, OAuth2Podio, OAuth2Notion, OAuth2Salesforce, OAuth2Yahoo, OAuth2HuggingFace, OAuth2Resend, OAuth2Cloudflare, OAuth2Linkedin, OAuth2Disqus, OAuth2Amazon, OAuth2Etsy, OAuth2Facebook, OAuth2Tradeshift, OAuth2Paypal, OAuth2Gitlab, OAuth2Authentik, OAuth2Auth0, OAuth2FusionAuth, OAuth2Keycloak, OAuth2Oidc, OAuth2Apple, OAuth2Okta, OAuth2Kick, OAuth2Microsoft] = project.get_o_auth2_provider( +result: Union[OAuth2Github, OAuth2Discord, OAuth2Figma, OAuth2Dropbox, OAuth2Dailymotion, OAuth2Bitbucket, OAuth2Bitly, OAuth2Box, OAuth2Autodesk, OAuth2Google, OAuth2Zoom, OAuth2Zoho, OAuth2Yandex, OAuth2X, OAuth2WordPress, OAuth2Webflow, OAuth2Twitch, OAuth2Stripe, OAuth2Spotify, OAuth2Slack, OAuth2Podio, OAuth2Notion, OAuth2Salesforce, OAuth2Yahoo, OAuth2HuggingFace, OAuth2Resend, OAuth2Cloudflare, OAuth2Linkedin, OAuth2Disqus, OAuth2Amazon, OAuth2Etsy, OAuth2Facebook, OAuth2Tradeshift, OAuth2Paypal, OAuth2Gitlab, OAuth2Authentik, OAuth2Auth0, OAuth2FusionAuth, OAuth2Keycloak, OAuth2Oidc, OAuth2Apple, OAuth2Okta, OAuth2Kick, OAuth2Microsoft, OAuth2TikTok, OAuth2Kakao] = project.get_o_auth2_provider( provider_id = ProjectOAuthProviderId.AMAZON ) diff --git a/docs/examples/project/get-policy.md b/docs/examples/project/get-policy.md index 16caef14..3e746d52 100644 --- a/docs/examples/project/get-policy.md +++ b/docs/examples/project/get-policy.md @@ -5,6 +5,8 @@ from appwrite.models import PolicyPasswordDictionary from appwrite.models import PolicyPasswordHistory from appwrite.models import PolicyPasswordStrength from appwrite.models import PolicyPasswordPersonalData +from appwrite.models import PolicyPasswordPwned +from appwrite.models import PolicyPasswordRotation from appwrite.models import PolicySessionAlert from appwrite.models import PolicySessionDuration from appwrite.models import PolicySessionInvalidation @@ -16,8 +18,9 @@ from appwrite.models import PolicyDenyAliasedEmail from appwrite.models import PolicyDenyDisposableEmail from appwrite.models import PolicyDenyFreeEmail from appwrite.models import PolicyDenyCorporateEmail +from appwrite.models import PolicyPasskey from typing import Union -from appwrite.enums import ProjectPolicyId +from appwrite.enums.project_policy_id import ProjectPolicyId client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -26,7 +29,7 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key project = Project(client) -result: Union[PolicyPasswordDictionary, PolicyPasswordHistory, PolicyPasswordStrength, PolicyPasswordPersonalData, PolicySessionAlert, PolicySessionDuration, PolicySessionInvalidation, PolicySessionLimit, PolicyUserLimit, PolicyMembershipPrivacy, PolicyMfaFactors, PolicyDenyAliasedEmail, PolicyDenyDisposableEmail, PolicyDenyFreeEmail, PolicyDenyCorporateEmail] = project.get_policy( +result: Union[PolicyPasswordDictionary, PolicyPasswordHistory, PolicyPasswordStrength, PolicyPasswordPersonalData, PolicyPasswordPwned, PolicyPasswordRotation, PolicySessionAlert, PolicySessionDuration, PolicySessionInvalidation, PolicySessionLimit, PolicyUserLimit, PolicyMembershipPrivacy, PolicyMfaFactors, PolicyDenyAliasedEmail, PolicyDenyDisposableEmail, PolicyDenyFreeEmail, PolicyDenyCorporateEmail, PolicyPasskey] = project.get_policy( policy_id = ProjectPolicyId.PASSWORD_DICTIONARY ) diff --git a/docs/examples/project/update-android-platform.md b/docs/examples/project/update-android-platform.md index 1c915ac4..70e179c7 100644 --- a/docs/examples/project/update-android-platform.md +++ b/docs/examples/project/update-android-platform.md @@ -13,7 +13,8 @@ project = Project(client) result: PlatformAndroid = project.update_android_platform( platform_id = '<PLATFORM_ID>', name = '<NAME>', - application_id = '<APPLICATION_ID>' + application_id = '<APPLICATION_ID>', + fingerprints = [] # optional ) print(result.model_dump()) diff --git a/docs/examples/project/update-auth-method.md b/docs/examples/project/update-auth-method.md index d9e4c643..4f562960 100644 --- a/docs/examples/project/update-auth-method.md +++ b/docs/examples/project/update-auth-method.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import Project as ProjectModel -from appwrite.enums import ProjectAuthMethodId +from appwrite.enums.project_auth_method_id import ProjectAuthMethodId client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/project/update-email-template.md b/docs/examples/project/update-email-template.md index d5548fdb..2c679f24 100644 --- a/docs/examples/project/update-email-template.md +++ b/docs/examples/project/update-email-template.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import EmailTemplate -from appwrite.enums import ProjectEmailTemplateId -from appwrite.enums import ProjectEmailTemplateLocale +from appwrite.enums.project_email_template_id import ProjectEmailTemplateId +from appwrite.enums.project_email_template_locale import ProjectEmailTemplateLocale client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/project/update-key.md b/docs/examples/project/update-key.md index e1ecc201..a8aa7ccf 100644 --- a/docs/examples/project/update-key.md +++ b/docs/examples/project/update-key.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import Key -from appwrite.enums import ProjectKeyScopes +from appwrite.enums.project_key_scopes import ProjectKeyScopes client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -14,7 +14,7 @@ project = Project(client) result: Key = project.update_key( key_id = '<KEY_ID>', name = '<NAME>', - scopes = [ProjectKeyScopes.PROJECT_READ], + scopes = [ProjectKeyScopes.USERS_READ], expire = '2020-10-15T06:38:00.000+00:00' # optional ) diff --git a/docs/examples/project/update-labels.md b/docs/examples/project/update-labels.md index 4fedceb1..ed324cad 100644 --- a/docs/examples/project/update-labels.md +++ b/docs/examples/project/update-labels.md @@ -11,7 +11,7 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key project = Project(client) result: ProjectModel = project.update_labels( - labels = [] + labels = ["production"] ) print(result.model_dump()) diff --git a/docs/examples/project/update-o-auth-2-apple.md b/docs/examples/project/update-o-auth-2-apple.md index 2619115e..1e0b8ff7 100644 --- a/docs/examples/project/update-o-auth-2-apple.md +++ b/docs/examples/project/update-o-auth-2-apple.md @@ -15,7 +15,9 @@ result: OAuth2Apple = project.update_o_auth2_apple( key_id = '<KEY_ID>', # optional team_id = '<TEAM_ID>', # optional p8_file = '<P8_FILE>', # optional - enabled = False # optional + native_client_ids = [], # optional + enabled = False, # optional + native_enabled = False # optional ) print(result.model_dump()) diff --git a/docs/examples/project/update-o-auth-2-auth-0.md b/docs/examples/project/update-o-auth-2-auth-0.md index 568bb9bb..f97e4418 100644 --- a/docs/examples/project/update-o-auth-2-auth-0.md +++ b/docs/examples/project/update-o-auth-2-auth-0.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Auth0 +from appwrite.enums.project_o_auth2_auth0_prompt import ProjectOAuth2Auth0Prompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -14,6 +15,7 @@ result: OAuth2Auth0 = project.update_o_auth2_auth0( client_id = '<CLIENT_ID>', # optional client_secret = '<CLIENT_SECRET>', # optional endpoint = '<ENDPOINT>', # optional + prompt = [ProjectOAuth2Auth0Prompt.NONE], # optional enabled = False # optional ) diff --git a/docs/examples/project/update-o-auth-2-discord.md b/docs/examples/project/update-o-auth-2-discord.md index a95cc496..a43cc259 100644 --- a/docs/examples/project/update-o-auth-2-discord.md +++ b/docs/examples/project/update-o-auth-2-discord.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Discord +from appwrite.enums.project_o_auth2_discord_prompt import ProjectOAuth2DiscordPrompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -13,6 +14,7 @@ project = Project(client) result: OAuth2Discord = project.update_o_auth2_discord( client_id = '<CLIENT_ID>', # optional client_secret = '<CLIENT_SECRET>', # optional + prompt = [ProjectOAuth2DiscordPrompt.NONE], # optional enabled = False # optional ) diff --git a/docs/examples/project/update-o-auth-2-git-hub.md b/docs/examples/project/update-o-auth-2-git-hub.md index 36664b85..37c34de9 100644 --- a/docs/examples/project/update-o-auth-2-git-hub.md +++ b/docs/examples/project/update-o-auth-2-git-hub.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Github +from appwrite.enums.project_o_auth2_git_hub_prompt import ProjectOAuth2GitHubPrompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -13,6 +14,7 @@ project = Project(client) result: OAuth2Github = project.update_o_auth2_git_hub( client_id = '<CLIENT_ID>', # optional client_secret = '<CLIENT_SECRET>', # optional + prompt = [ProjectOAuth2GitHubPrompt.SELECT_ACCOUNT], # optional enabled = False # optional ) diff --git a/docs/examples/project/update-o-auth-2-google.md b/docs/examples/project/update-o-auth-2-google.md index b1cc1eca..c970d7bd 100644 --- a/docs/examples/project/update-o-auth-2-google.md +++ b/docs/examples/project/update-o-auth-2-google.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Google -from appwrite.enums import ProjectOAuth2GooglePrompt +from appwrite.enums.project_o_auth2_google_prompt import ProjectOAuth2GooglePrompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -15,7 +15,9 @@ result: OAuth2Google = project.update_o_auth2_google( client_id = '<CLIENT_ID>', # optional client_secret = '<CLIENT_SECRET>', # optional prompt = [ProjectOAuth2GooglePrompt.NONE], # optional - enabled = False # optional + native_client_ids = [], # optional + enabled = False, # optional + native_enabled = False # optional ) print(result.model_dump()) diff --git a/docs/examples/project/update-o-auth-2-kakao.md b/docs/examples/project/update-o-auth-2-kakao.md new file mode 100644 index 00000000..b67c6e49 --- /dev/null +++ b/docs/examples/project/update-o-auth-2-kakao.md @@ -0,0 +1,22 @@ +```python +from appwrite.client import Client +from appwrite.services.project import Project +from appwrite.models import OAuth2Kakao +from appwrite.enums.project_o_auth2_kakao_prompt import ProjectOAuth2KakaoPrompt + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +project = Project(client) + +result: OAuth2Kakao = project.update_o_auth2_kakao( + client_id = '<CLIENT_ID>', # optional + client_secret = '<CLIENT_SECRET>', # optional + prompt = [ProjectOAuth2KakaoPrompt.NONE], # optional + enabled = False # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/project/update-o-auth-2-microsoft.md b/docs/examples/project/update-o-auth-2-microsoft.md index aeeefa9e..14347bc0 100644 --- a/docs/examples/project/update-o-auth-2-microsoft.md +++ b/docs/examples/project/update-o-auth-2-microsoft.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Microsoft +from appwrite.enums.project_o_auth2_microsoft_prompt import ProjectOAuth2MicrosoftPrompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -14,6 +15,7 @@ result: OAuth2Microsoft = project.update_o_auth2_microsoft( application_id = '<APPLICATION_ID>', # optional application_secret = '<APPLICATION_SECRET>', # optional tenant = '<TENANT>', # optional + prompt = [ProjectOAuth2MicrosoftPrompt.NONE], # 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 e2df2e3c..de01460f 100644 --- a/docs/examples/project/update-o-auth-2-oidc.md +++ b/docs/examples/project/update-o-auth-2-oidc.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Oidc -from appwrite.enums import ProjectOAuth2OidcPrompt +from appwrite.enums.project_o_auth2_oidc_prompt import ProjectOAuth2OidcPrompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/project/update-o-auth-2-okta.md b/docs/examples/project/update-o-auth-2-okta.md index 0b4fc532..c3e35736 100644 --- a/docs/examples/project/update-o-auth-2-okta.md +++ b/docs/examples/project/update-o-auth-2-okta.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Okta +from appwrite.enums.project_o_auth2_okta_prompt import ProjectOAuth2OktaPrompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -15,6 +16,7 @@ result: OAuth2Okta = project.update_o_auth2_okta( client_secret = '<CLIENT_SECRET>', # optional domain = 'example.com', # optional authorization_server_id = '<AUTHORIZATION_SERVER_ID>', # optional + prompt = [ProjectOAuth2OktaPrompt.NONE], # optional enabled = False # optional ) diff --git a/docs/examples/project/update-o-auth-2-salesforce.md b/docs/examples/project/update-o-auth-2-salesforce.md index a3cb6377..1cdfdec7 100644 --- a/docs/examples/project/update-o-auth-2-salesforce.md +++ b/docs/examples/project/update-o-auth-2-salesforce.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Salesforce +from appwrite.enums.project_o_auth2_salesforce_prompt import ProjectOAuth2SalesforcePrompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -13,6 +14,7 @@ project = Project(client) result: OAuth2Salesforce = project.update_o_auth2_salesforce( customer_key = '<CUSTOMER_KEY>', # optional customer_secret = '<CUSTOMER_SECRET>', # optional + prompt = [ProjectOAuth2SalesforcePrompt.LOGIN], # optional enabled = False # optional ) diff --git a/docs/examples/project/update-o-auth-2-tik-tok.md b/docs/examples/project/update-o-auth-2-tik-tok.md new file mode 100644 index 00000000..3a7c9cb7 --- /dev/null +++ b/docs/examples/project/update-o-auth-2-tik-tok.md @@ -0,0 +1,20 @@ +```python +from appwrite.client import Client +from appwrite.services.project import Project +from appwrite.models import OAuth2TikTok + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +project = Project(client) + +result: OAuth2TikTok = project.update_o_auth2_tik_tok( + client_id = '<CLIENT_ID>', # optional + client_secret = '<CLIENT_SECRET>', # optional + enabled = False # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/project/update-o-auth-2-webflow.md b/docs/examples/project/update-o-auth-2-webflow.md new file mode 100644 index 00000000..5edfea64 --- /dev/null +++ b/docs/examples/project/update-o-auth-2-webflow.md @@ -0,0 +1,20 @@ +```python +from appwrite.client import Client +from appwrite.services.project import Project +from appwrite.models import OAuth2Webflow + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +project = Project(client) + +result: OAuth2Webflow = project.update_o_auth2_webflow( + client_id = '<CLIENT_ID>', # optional + client_secret = '<CLIENT_SECRET>', # optional + enabled = False # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/project/update-o-auth-2-zoho.md b/docs/examples/project/update-o-auth-2-zoho.md index 069a9645..b42c066f 100644 --- a/docs/examples/project/update-o-auth-2-zoho.md +++ b/docs/examples/project/update-o-auth-2-zoho.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import OAuth2Zoho +from appwrite.enums.project_o_auth2_zoho_prompt import ProjectOAuth2ZohoPrompt client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -13,6 +14,7 @@ project = Project(client) result: OAuth2Zoho = project.update_o_auth2_zoho( client_id = '<CLIENT_ID>', # optional client_secret = '<CLIENT_SECRET>', # optional + prompt = [ProjectOAuth2ZohoPrompt.CONSENT], # optional enabled = False # optional ) diff --git a/docs/examples/project/update-passkey-policy.md b/docs/examples/project/update-passkey-policy.md new file mode 100644 index 00000000..08e2f41b --- /dev/null +++ b/docs/examples/project/update-passkey-policy.md @@ -0,0 +1,18 @@ +```python +from appwrite.client import Client +from appwrite.services.project import Project +from appwrite.models import Project as ProjectModel + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +project = Project(client) + +result: ProjectModel = project.update_passkey_policy( + rp_id = '<RP_ID>' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/project/update-password-pwned-policy.md b/docs/examples/project/update-password-pwned-policy.md new file mode 100644 index 00000000..53d2130c --- /dev/null +++ b/docs/examples/project/update-password-pwned-policy.md @@ -0,0 +1,20 @@ +```python +from appwrite.client import Client +from appwrite.services.project import Project +from appwrite.models import Project as ProjectModel + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +project = Project(client) + +result: ProjectModel = project.update_password_pwned_policy( + enabled = False, # optional + sessions = False, # optional + users = False # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/project/update-password-rotation-policy.md b/docs/examples/project/update-password-rotation-policy.md new file mode 100644 index 00000000..68d69221 --- /dev/null +++ b/docs/examples/project/update-password-rotation-policy.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.project import Project +from appwrite.models import Project as ProjectModel + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +project = Project(client) + +result: ProjectModel = project.update_password_rotation_policy( + enabled = False, # optional + max_age = 86400 # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/project/update-protocol.md b/docs/examples/project/update-protocol.md index db26644d..e3d7afc8 100644 --- a/docs/examples/project/update-protocol.md +++ b/docs/examples/project/update-protocol.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import Project as ProjectModel -from appwrite.enums import ProjectProtocolId +from appwrite.enums.project_protocol_id import ProjectProtocolId client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/project/update-service.md b/docs/examples/project/update-service.md index 17c003c0..61b490a6 100644 --- a/docs/examples/project/update-service.md +++ b/docs/examples/project/update-service.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import Project as ProjectModel -from appwrite.enums import ProjectServiceId +from appwrite.enums.project_service_id import ProjectServiceId client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/project/update-smtp.md b/docs/examples/project/update-smtp.md index 772bafea..ae8b2c9f 100644 --- a/docs/examples/project/update-smtp.md +++ b/docs/examples/project/update-smtp.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.project import Project from appwrite.models import Project as ProjectModel -from appwrite.enums import ProjectSMTPSecure +from appwrite.enums.project_smtp_secure import ProjectSMTPSecure client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/proxy/create-invalidation.md b/docs/examples/proxy/create-invalidation.md index 413beb6f..365de03e 100644 --- a/docs/examples/proxy/create-invalidation.md +++ b/docs/examples/proxy/create-invalidation.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.proxy import Proxy from appwrite.models import ProxyInvalidation -from appwrite.enums import InvalidationType +from appwrite.enums.invalidation_type import InvalidationType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/proxy/create-redirect-rule.md b/docs/examples/proxy/create-redirect-rule.md index 7a44bac0..2b4c1934 100644 --- a/docs/examples/proxy/create-redirect-rule.md +++ b/docs/examples/proxy/create-redirect-rule.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.proxy import Proxy from appwrite.models import ProxyRule -from appwrite.enums import StatusCode -from appwrite.enums import ProxyResourceType +from appwrite.enums.status_code import StatusCode +from appwrite.enums.proxy_resource_type import ProxyResourceType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/sites/create-template-deployment.md b/docs/examples/sites/create-template-deployment.md index f65b153b..7be43234 100644 --- a/docs/examples/sites/create-template-deployment.md +++ b/docs/examples/sites/create-template-deployment.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.sites import Sites from appwrite.models import Deployment -from appwrite.enums import TemplateReferenceType +from appwrite.enums.template_reference_type import TemplateReferenceType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/sites/create-vcs-deployment.md b/docs/examples/sites/create-vcs-deployment.md index 1846cefc..3b97fa75 100644 --- a/docs/examples/sites/create-vcs-deployment.md +++ b/docs/examples/sites/create-vcs-deployment.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.sites import Sites from appwrite.models import Deployment -from appwrite.enums import VCSReferenceType +from appwrite.enums.vcs_reference_type import VCSReferenceType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/sites/create.md b/docs/examples/sites/create.md index 8fd41e72..4d8e03bc 100644 --- a/docs/examples/sites/create.md +++ b/docs/examples/sites/create.md @@ -2,10 +2,10 @@ from appwrite.client import Client from appwrite.services.sites import Sites from appwrite.models import Site -from appwrite.enums import Framework -from appwrite.enums import BuildRuntime -from appwrite.enums import Adapter -from appwrite.enums import ProjectKeyScopes +from appwrite.enums.framework import Framework +from appwrite.enums.build_runtime import BuildRuntime +from appwrite.enums.adapter import Adapter +from appwrite.enums.project_key_scopes import ProjectKeyScopes client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/sites/get-deployment-download.md b/docs/examples/sites/get-deployment-download.md index 7d6ae537..0e9ea18a 100644 --- a/docs/examples/sites/get-deployment-download.md +++ b/docs/examples/sites/get-deployment-download.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.sites import Sites -from appwrite.enums import DeploymentDownloadType +from appwrite.enums.deployment_download_type import DeploymentDownloadType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/sites/list-frameworks.md b/docs/examples/sites/list-frameworks.md index 84996b3f..2edd3b35 100644 --- a/docs/examples/sites/list-frameworks.md +++ b/docs/examples/sites/list-frameworks.md @@ -10,7 +10,9 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key sites = Sites(client) -result: FrameworkList = sites.list_frameworks() +result: FrameworkList = sites.list_frameworks( + total = False # optional +) print(result.model_dump()) ``` diff --git a/docs/examples/sites/list-specifications.md b/docs/examples/sites/list-specifications.md index 2f04ddf4..88c3402b 100644 --- a/docs/examples/sites/list-specifications.md +++ b/docs/examples/sites/list-specifications.md @@ -11,7 +11,8 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key sites = Sites(client) result: SpecificationList = sites.list_specifications( - type = 'runtimes' # optional + type = 'runtimes', # optional + total = False # optional ) print(result.model_dump()) diff --git a/docs/examples/sites/update.md b/docs/examples/sites/update.md index 0065e89f..59ac85ce 100644 --- a/docs/examples/sites/update.md +++ b/docs/examples/sites/update.md @@ -2,10 +2,10 @@ from appwrite.client import Client from appwrite.services.sites import Sites from appwrite.models import Site -from appwrite.enums import Framework -from appwrite.enums import BuildRuntime -from appwrite.enums import Adapter -from appwrite.enums import ProjectKeyScopes +from appwrite.enums.framework import Framework +from appwrite.enums.build_runtime import BuildRuntime +from appwrite.enums.adapter import Adapter +from appwrite.enums.project_key_scopes import ProjectKeyScopes client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/storage/create-bucket.md b/docs/examples/storage/create-bucket.md index 418f8ecb..76ec2f0e 100644 --- a/docs/examples/storage/create-bucket.md +++ b/docs/examples/storage/create-bucket.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.storage import Storage from appwrite.models import Bucket -from appwrite.enums import Compression +from appwrite.enums.compression import Compression from appwrite.permission import Permission from appwrite.role import Role diff --git a/docs/examples/storage/get-file-preview.md b/docs/examples/storage/get-file-preview.md index 373cb941..f5c8c9db 100644 --- a/docs/examples/storage/get-file-preview.md +++ b/docs/examples/storage/get-file-preview.md @@ -1,8 +1,8 @@ ```python from appwrite.client import Client from appwrite.services.storage import Storage -from appwrite.enums import ImageGravity -from appwrite.enums import ImageFormat +from appwrite.enums.image_gravity import ImageGravity +from appwrite.enums.image_format import ImageFormat client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -16,7 +16,7 @@ result: bytes = storage.get_file_preview( file_id = '<FILE_ID>', width = 0, # optional height = 0, # optional - gravity = ImageGravity.CENTER, # optional + gravity = ImageGravity.AUTO, # optional quality = -1, # optional border_width = 0, # optional border_color = 'FFFFFF', # optional diff --git a/docs/examples/storage/update-bucket.md b/docs/examples/storage/update-bucket.md index ecb1ada6..c9222517 100644 --- a/docs/examples/storage/update-bucket.md +++ b/docs/examples/storage/update-bucket.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.storage import Storage from appwrite.models import Bucket -from appwrite.enums import Compression +from appwrite.enums.compression import Compression from appwrite.permission import Permission from appwrite.role import Role diff --git a/docs/examples/tablesdb/create-index.md b/docs/examples/tablesdb/create-index.md index 5de707fe..8ecf506d 100644 --- a/docs/examples/tablesdb/create-index.md +++ b/docs/examples/tablesdb/create-index.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.tables_db import TablesDB from appwrite.models import ColumnIndex -from appwrite.enums import TablesDBIndexType -from appwrite.enums import OrderBy +from appwrite.enums.tables_db_index_type import TablesDBIndexType +from appwrite.enums.order_by import OrderBy client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -17,7 +17,7 @@ result: ColumnIndex = tables_db.create_index( table_id = '<TABLE_ID>', key = '<KEY>', type = TablesDBIndexType.KEY, - columns = [], + columns = ["username"], orders = [OrderBy.ASC], # optional lengths = [] # optional ) diff --git a/docs/examples/tablesdb/create-relationship-column.md b/docs/examples/tablesdb/create-relationship-column.md index ffad0db4..32fc4ba1 100644 --- a/docs/examples/tablesdb/create-relationship-column.md +++ b/docs/examples/tablesdb/create-relationship-column.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.tables_db import TablesDB from appwrite.models import ColumnRelationship -from appwrite.enums import RelationshipType -from appwrite.enums import RelationMutate +from appwrite.enums.relationship_type import RelationshipType +from appwrite.enums.relation_mutate import RelationMutate client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/tablesdb/create-rows.md b/docs/examples/tablesdb/create-rows.md index 9e741fe4..6dc95621 100644 --- a/docs/examples/tablesdb/create-rows.md +++ b/docs/examples/tablesdb/create-rows.md @@ -13,7 +13,16 @@ tables_db = TablesDB(client) result: RowList = tables_db.create_rows( database_id = '<DATABASE_ID>', table_id = '<TABLE_ID>', - rows = [], + rows = [ + { + "$id": "example1", + "username": "walter.obrien", + "email": "walter.obrien@example.com", + "fullName": "Walter O'Brien", + "age": 30, + "isAdmin": false + } + ], transaction_id = '<TRANSACTION_ID>' # optional ) diff --git a/docs/examples/tablesdb/delete-rows.md b/docs/examples/tablesdb/delete-rows.md index 2a3a89ca..9ed0672d 100644 --- a/docs/examples/tablesdb/delete-rows.md +++ b/docs/examples/tablesdb/delete-rows.md @@ -13,7 +13,7 @@ tables_db = TablesDB(client) result: RowList = tables_db.delete_rows( database_id = '<DATABASE_ID>', table_id = '<TABLE_ID>', - queries = [], # optional + queries = ["{\"method\":\"equal\", \"attribute\":\"$id\", \"values\":[\"<ROW_ID>\"]}"], # optional transaction_id = '<TRANSACTION_ID>' # optional ) diff --git a/docs/examples/tablesdb/get-column.md b/docs/examples/tablesdb/get-column.md index 6d2b8255..1a4dd142 100644 --- a/docs/examples/tablesdb/get-column.md +++ b/docs/examples/tablesdb/get-column.md @@ -2,6 +2,7 @@ from appwrite.client import Client from appwrite.services.tables_db import TablesDB from appwrite.models import ColumnBoolean +from appwrite.models import ColumnBigint from appwrite.models import ColumnInteger from appwrite.models import ColumnFloat from appwrite.models import ColumnEmail @@ -10,6 +11,13 @@ from appwrite.models import ColumnUrl from appwrite.models import ColumnIp from appwrite.models import ColumnDatetime from appwrite.models import ColumnRelationship +from appwrite.models import ColumnPoint +from appwrite.models import ColumnLine +from appwrite.models import ColumnPolygon +from appwrite.models import ColumnVarchar +from appwrite.models import ColumnText +from appwrite.models import ColumnMediumtext +from appwrite.models import ColumnLongtext from appwrite.models import ColumnString from typing import Union @@ -20,7 +28,7 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key tables_db = TablesDB(client) -result: Union[ColumnBoolean, ColumnInteger, ColumnFloat, ColumnEmail, ColumnEnum, ColumnUrl, ColumnIp, ColumnDatetime, ColumnRelationship, ColumnString] = tables_db.get_column( +result: Union[ColumnBoolean, ColumnBigint, ColumnInteger, ColumnFloat, ColumnEmail, ColumnEnum, ColumnUrl, ColumnIp, ColumnDatetime, ColumnRelationship, ColumnPoint, ColumnLine, ColumnPolygon, ColumnVarchar, ColumnText, ColumnMediumtext, ColumnLongtext, ColumnString] = tables_db.get_column( database_id = '<DATABASE_ID>', table_id = '<TABLE_ID>', key = '<KEY>' diff --git a/docs/examples/tablesdb/list-transactions.md b/docs/examples/tablesdb/list-transactions.md index b4384e67..ded73360 100644 --- a/docs/examples/tablesdb/list-transactions.md +++ b/docs/examples/tablesdb/list-transactions.md @@ -11,7 +11,8 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key tables_db = TablesDB(client) result: TransactionList = tables_db.list_transactions( - queries = [] # optional + queries = [], # optional + total = False # optional ) print(result.model_dump()) diff --git a/docs/examples/tablesdb/update-relationship-column.md b/docs/examples/tablesdb/update-relationship-column.md index 4932a8a9..67fb6063 100644 --- a/docs/examples/tablesdb/update-relationship-column.md +++ b/docs/examples/tablesdb/update-relationship-column.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.tables_db import TablesDB from appwrite.models import ColumnRelationship -from appwrite.enums import RelationMutate +from appwrite.enums.relation_mutate import RelationMutate client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/tablesdb/upsert-rows.md b/docs/examples/tablesdb/upsert-rows.md index 0b6a754e..673b9a2b 100644 --- a/docs/examples/tablesdb/upsert-rows.md +++ b/docs/examples/tablesdb/upsert-rows.md @@ -13,7 +13,16 @@ tables_db = TablesDB(client) result: RowList = tables_db.upsert_rows( database_id = '<DATABASE_ID>', table_id = '<TABLE_ID>', - rows = [], + rows = [ + { + "$id": "example1", + "username": "walter.obrien", + "email": "walter.obrien@example.com", + "fullName": "Walter O'Brien", + "age": 30, + "isAdmin": false + } + ], transaction_id = '<TRANSACTION_ID>' # optional ) diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md index 313bf5f6..a04ed454 100644 --- a/docs/examples/teams/create-membership.md +++ b/docs/examples/teams/create-membership.md @@ -12,7 +12,8 @@ teams = Teams(client) result: Membership = teams.create_membership( team_id = '<TEAM_ID>', - roles = [], + roles = ["editor"], + membership_id = '<MEMBERSHIP_ID>', # optional email = 'email@example.com', # optional user_id = '<USER_ID>', # optional phone = '+12065550100', # optional diff --git a/docs/examples/teams/update-membership.md b/docs/examples/teams/update-membership.md index 4425ae58..e6db1a04 100644 --- a/docs/examples/teams/update-membership.md +++ b/docs/examples/teams/update-membership.md @@ -13,7 +13,7 @@ teams = Teams(client) result: Membership = teams.update_membership( team_id = '<TEAM_ID>', membership_id = '<MEMBERSHIP_ID>', - roles = [] + roles = ["editor"] ) print(result.model_dump()) diff --git a/docs/examples/users/create-sha-user.md b/docs/examples/users/create-sha-user.md index 9d42300a..9b7ef7d3 100644 --- a/docs/examples/users/create-sha-user.md +++ b/docs/examples/users/create-sha-user.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.users import Users from appwrite.models import User -from appwrite.enums import PasswordHash +from appwrite.enums.password_hash import PasswordHash client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/users/create-target.md b/docs/examples/users/create-target.md index fcfd394a..36ce660f 100644 --- a/docs/examples/users/create-target.md +++ b/docs/examples/users/create-target.md @@ -2,7 +2,7 @@ from appwrite.client import Client from appwrite.services.users import Users from appwrite.models import Target -from appwrite.enums import MessagingProviderType +from appwrite.enums.messaging_provider_type import MessagingProviderType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/users/delete-mfa-authenticator.md b/docs/examples/users/delete-mfa-authenticator.md index 67ab6b78..b7cc38c0 100644 --- a/docs/examples/users/delete-mfa-authenticator.md +++ b/docs/examples/users/delete-mfa-authenticator.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.users import Users -from appwrite.enums import AuthenticatorType +from appwrite.enums.authenticator_type import AuthenticatorType client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint diff --git a/docs/examples/users/delete-passkey.md b/docs/examples/users/delete-passkey.md new file mode 100644 index 00000000..060b39d4 --- /dev/null +++ b/docs/examples/users/delete-passkey.md @@ -0,0 +1,16 @@ +```python +from appwrite.client import Client +from appwrite.services.users import Users + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +users = Users(client) + +result = users.delete_passkey( + user_id = '<USER_ID>', + passkey_id = '<PASSKEY_ID>' +) +``` diff --git a/docs/examples/users/get-passkey.md b/docs/examples/users/get-passkey.md new file mode 100644 index 00000000..c7194bb9 --- /dev/null +++ b/docs/examples/users/get-passkey.md @@ -0,0 +1,19 @@ +```python +from appwrite.client import Client +from appwrite.services.users import Users +from appwrite.models import Passkey + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +users = Users(client) + +result: Passkey = users.get_passkey( + user_id = '<USER_ID>', + passkey_id = '<PASSKEY_ID>' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/users/list-logs.md b/docs/examples/users/list-passkeys.md similarity index 84% rename from docs/examples/users/list-logs.md rename to docs/examples/users/list-passkeys.md index 34d41e75..8853711e 100644 --- a/docs/examples/users/list-logs.md +++ b/docs/examples/users/list-passkeys.md @@ -1,7 +1,7 @@ ```python from appwrite.client import Client from appwrite.services.users import Users -from appwrite.models import LogList +from appwrite.models import PasskeyList client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -10,7 +10,7 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key users = Users(client) -result: LogList = users.list_logs( +result: PasskeyList = users.list_passkeys( user_id = '<USER_ID>', queries = [], # optional total = False # optional diff --git a/docs/examples/users/update-labels.md b/docs/examples/users/update-labels.md index bffba0c1..7d75293f 100644 --- a/docs/examples/users/update-labels.md +++ b/docs/examples/users/update-labels.md @@ -12,7 +12,7 @@ users = Users(client) result: User = users.update_labels( user_id = '<USER_ID>', - labels = [] + labels = ["subscriber"] ) print(result.model_dump()) diff --git a/docs/examples/users/update-passkey.md b/docs/examples/users/update-passkey.md new file mode 100644 index 00000000..e8a2bb1c --- /dev/null +++ b/docs/examples/users/update-passkey.md @@ -0,0 +1,20 @@ +```python +from appwrite.client import Client +from appwrite.services.users import Users +from appwrite.models import Passkey + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +users = Users(client) + +result: Passkey = users.update_passkey( + user_id = '<USER_ID>', + passkey_id = '<PASSKEY_ID>', + name = '<NAME>' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/vectorsdb/create-collection.md b/docs/examples/vectorsdb/create-collection.md index 793aa3f5..6dcdeb24 100644 --- a/docs/examples/vectorsdb/create-collection.md +++ b/docs/examples/vectorsdb/create-collection.md @@ -16,7 +16,7 @@ result: VectorsdbCollection = vectors_db.create_collection( database_id = '<DATABASE_ID>', collection_id = '<COLLECTION_ID>', name = '<NAME>', - dimension = 1, + dimension = 4, permissions = [Permission.read(Role.any())], # optional document_security = False, # optional enabled = False # optional diff --git a/docs/examples/vectorsdb/create-documents.md b/docs/examples/vectorsdb/create-documents.md index b84eea6d..6191c41b 100644 --- a/docs/examples/vectorsdb/create-documents.md +++ b/docs/examples/vectorsdb/create-documents.md @@ -13,7 +13,20 @@ vectors_db = VectorsDB(client) result: DocumentList = vectors_db.create_documents( database_id = '<DATABASE_ID>', collection_id = '<COLLECTION_ID>', - documents = [], + documents = [ + { + "$id": "example1", + "embeddings": [ + 0.12, + -0.55, + 0.88, + 1.02 + ], + "metadata": { + "name": "First document" + } + } + ], transaction_id = '<TRANSACTION_ID>' # optional ) diff --git a/docs/examples/vectorsdb/create-index.md b/docs/examples/vectorsdb/create-index.md index 2f5bf256..71e650a6 100644 --- a/docs/examples/vectorsdb/create-index.md +++ b/docs/examples/vectorsdb/create-index.md @@ -2,8 +2,8 @@ from appwrite.client import Client from appwrite.services.vectors_db import VectorsDB from appwrite.models import Index -from appwrite.enums import VectorsDBIndexType -from appwrite.enums import OrderBy +from appwrite.enums.vectors_db_index_type import VectorsDBIndexType +from appwrite.enums.order_by import OrderBy client = Client() client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint @@ -17,7 +17,7 @@ result: Index = vectors_db.create_index( collection_id = '<COLLECTION_ID>', key = '<KEY>', type = VectorsDBIndexType.HNSW_EUCLIDEAN, - attributes = [], + attributes = ["embeddings"], orders = [OrderBy.ASC], # optional lengths = [] # optional ) diff --git a/docs/examples/vectorsdb/create-operations.md b/docs/examples/vectorsdb/create-operations.md index e19a8936..f4e1026d 100644 --- a/docs/examples/vectorsdb/create-operations.md +++ b/docs/examples/vectorsdb/create-operations.md @@ -19,7 +19,15 @@ result: Transaction = vectors_db.create_operations( "collectionId": "<COLLECTION_ID>", "documentId": "<DOCUMENT_ID>", "data": { - "name": "Walter O'Brien" + "embeddings": [ + 0.12, + -0.55, + 0.88, + 1.02 + ], + "metadata": { + "name": "First document" + } } } ] # optional diff --git a/docs/examples/vectorsdb/delete-documents.md b/docs/examples/vectorsdb/delete-documents.md index f1bee6ee..8a36e763 100644 --- a/docs/examples/vectorsdb/delete-documents.md +++ b/docs/examples/vectorsdb/delete-documents.md @@ -13,7 +13,7 @@ vectors_db = VectorsDB(client) result: DocumentList = vectors_db.delete_documents( database_id = '<DATABASE_ID>', collection_id = '<COLLECTION_ID>', - queries = [], # optional + queries = ["{\"method\":\"equal\", \"attribute\":\"$id\", \"values\":[\"<DOCUMENT_ID>\"]}"], # optional transaction_id = '<TRANSACTION_ID>' # optional ) diff --git a/docs/examples/vectorsdb/list-transactions.md b/docs/examples/vectorsdb/list-transactions.md index d21db012..6ff6cdaa 100644 --- a/docs/examples/vectorsdb/list-transactions.md +++ b/docs/examples/vectorsdb/list-transactions.md @@ -11,7 +11,8 @@ client.set_key('<YOUR_API_KEY>') # Your secret API key vectors_db = VectorsDB(client) result: TransactionList = vectors_db.list_transactions( - queries = [] # optional + queries = [], # optional + total = False # optional ) print(result.model_dump()) diff --git a/docs/examples/vectorsdb/update-collection.md b/docs/examples/vectorsdb/update-collection.md index 3dcf8903..7093c0b2 100644 --- a/docs/examples/vectorsdb/update-collection.md +++ b/docs/examples/vectorsdb/update-collection.md @@ -16,7 +16,7 @@ result: VectorsdbCollection = vectors_db.update_collection( database_id = '<DATABASE_ID>', collection_id = '<COLLECTION_ID>', name = '<NAME>', - dimension = 1, # optional + dimension = 4, # optional permissions = [Permission.read(Role.any())], # optional document_security = False, # optional enabled = False # optional diff --git a/docs/examples/vectorsdb/upsert-documents.md b/docs/examples/vectorsdb/upsert-documents.md index 5eb3d2d1..c89ed2f3 100644 --- a/docs/examples/vectorsdb/upsert-documents.md +++ b/docs/examples/vectorsdb/upsert-documents.md @@ -13,7 +13,20 @@ vectors_db = VectorsDB(client) result: DocumentList = vectors_db.upsert_documents( database_id = '<DATABASE_ID>', collection_id = '<COLLECTION_ID>', - documents = [], + documents = [ + { + "$id": "example1", + "embeddings": [ + 0.12, + -0.55, + 0.88, + 1.02 + ], + "metadata": { + "name": "First document" + } + } + ], transaction_id = '<TRANSACTION_ID>' # optional ) diff --git a/docs/examples/waf/create-bypass-rule.md b/docs/examples/waf/create-bypass-rule.md new file mode 100644 index 00000000..70ed9061 --- /dev/null +++ b/docs/examples/waf/create-bypass-rule.md @@ -0,0 +1,25 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleBypass + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleBypass = waf.create_bypass_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', + name = '<NAME>', + resource_id = '<RESOURCE_ID>', # optional + description = '<DESCRIPTION>', # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/create-challenge-rule.md b/docs/examples/waf/create-challenge-rule.md new file mode 100644 index 00000000..e3d2fea2 --- /dev/null +++ b/docs/examples/waf/create-challenge-rule.md @@ -0,0 +1,28 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleChallenge + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleChallenge = waf.create_challenge_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', + name = '<NAME>', + resource_id = '<RESOURCE_ID>', # optional + description = '<DESCRIPTION>', # optional + challenge_type = 'compute', # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [], # optional + difficulty = 1, # optional + ttl = 900 # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/create-deny-rule.md b/docs/examples/waf/create-deny-rule.md new file mode 100644 index 00000000..a23ae249 --- /dev/null +++ b/docs/examples/waf/create-deny-rule.md @@ -0,0 +1,25 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleDeny + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleDeny = waf.create_deny_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', + name = '<NAME>', + resource_id = '<RESOURCE_ID>', # optional + description = '<DESCRIPTION>', # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/create-rate-limit-rule.md b/docs/examples/waf/create-rate-limit-rule.md new file mode 100644 index 00000000..e76605f8 --- /dev/null +++ b/docs/examples/waf/create-rate-limit-rule.md @@ -0,0 +1,30 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleRateLimit + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleRateLimit = waf.create_rate_limit_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', + name = '<NAME>', + limit = 1, + interval = 1, + resource_id = '<RESOURCE_ID>', # optional + description = '<DESCRIPTION>', # optional + key = 'ip', # optional + strategy = 'fixedWindow', # optional + max_bucket_size = 1, # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/create-redirect-rule.md b/docs/examples/waf/create-redirect-rule.md new file mode 100644 index 00000000..a33a1e6c --- /dev/null +++ b/docs/examples/waf/create-redirect-rule.md @@ -0,0 +1,27 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleRedirect + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleRedirect = waf.create_redirect_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', + name = '<NAME>', + location = '<LOCATION>', + status_code = 300, + resource_id = '<RESOURCE_ID>', # optional + description = '<DESCRIPTION>', # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/delete-rule.md b/docs/examples/waf/delete-rule.md new file mode 100644 index 00000000..a2fbe6d8 --- /dev/null +++ b/docs/examples/waf/delete-rule.md @@ -0,0 +1,15 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result = waf.delete_rule( + rule_id = '<RULE_ID>' +) +``` diff --git a/docs/examples/waf/get-rule.md b/docs/examples/waf/get-rule.md new file mode 100644 index 00000000..3168d309 --- /dev/null +++ b/docs/examples/waf/get-rule.md @@ -0,0 +1,23 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleBypass +from appwrite.models import WafRuleDeny +from appwrite.models import WafRuleChallenge +from appwrite.models import WafRuleRateLimit +from appwrite.models import WafRuleRedirect +from typing import Union + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: Union[WafRuleBypass, WafRuleDeny, WafRuleChallenge, WafRuleRateLimit, WafRuleRedirect] = waf.get_rule( + rule_id = '<RULE_ID>' +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/list-rules.md b/docs/examples/waf/list-rules.md new file mode 100644 index 00000000..d06a509e --- /dev/null +++ b/docs/examples/waf/list-rules.md @@ -0,0 +1,20 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleList + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleList = waf.list_rules( + queries = [], # optional + search = '<SEARCH>', # optional + total = False # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/update-bypass-rule.md b/docs/examples/waf/update-bypass-rule.md new file mode 100644 index 00000000..39ceb7f4 --- /dev/null +++ b/docs/examples/waf/update-bypass-rule.md @@ -0,0 +1,25 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleBypass + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleBypass = waf.update_bypass_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', # optional + resource_id = '<RESOURCE_ID>', # optional + name = '<NAME>', # optional + description = '<DESCRIPTION>', # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/update-challenge-rule.md b/docs/examples/waf/update-challenge-rule.md new file mode 100644 index 00000000..30afcd7f --- /dev/null +++ b/docs/examples/waf/update-challenge-rule.md @@ -0,0 +1,28 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleChallenge + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleChallenge = waf.update_challenge_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', # optional + resource_id = '<RESOURCE_ID>', # optional + name = '<NAME>', # optional + description = '<DESCRIPTION>', # optional + challenge_type = 'compute', # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [], # optional + difficulty = 1, # optional + ttl = 900 # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/update-deny-rule.md b/docs/examples/waf/update-deny-rule.md new file mode 100644 index 00000000..2253e2b7 --- /dev/null +++ b/docs/examples/waf/update-deny-rule.md @@ -0,0 +1,25 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleDeny + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleDeny = waf.update_deny_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', # optional + resource_id = '<RESOURCE_ID>', # optional + name = '<NAME>', # optional + description = '<DESCRIPTION>', # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/update-rate-limit-rule.md b/docs/examples/waf/update-rate-limit-rule.md new file mode 100644 index 00000000..e413cef8 --- /dev/null +++ b/docs/examples/waf/update-rate-limit-rule.md @@ -0,0 +1,29 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleRateLimit + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleRateLimit = waf.update_rate_limit_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', # optional + resource_id = '<RESOURCE_ID>', # optional + name = '<NAME>', # optional + description = '<DESCRIPTION>', # optional + limit = 1, # optional + interval = 1, # optional + key = 'ip', # optional + max_bucket_size = 1, # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/waf/update-redirect-rule.md b/docs/examples/waf/update-redirect-rule.md new file mode 100644 index 00000000..7e294f8c --- /dev/null +++ b/docs/examples/waf/update-redirect-rule.md @@ -0,0 +1,27 @@ +```python +from appwrite.client import Client +from appwrite.services.waf import Waf +from appwrite.models import WafRuleRedirect + +client = Client() +client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('<YOUR_PROJECT_ID>') # Your project ID +client.set_key('<YOUR_API_KEY>') # Your secret API key + +waf = Waf(client) + +result: WafRuleRedirect = waf.update_redirect_rule( + rule_id = '<RULE_ID>', + resource_type = 'api', # optional + resource_id = '<RESOURCE_ID>', # optional + name = '<NAME>', # optional + description = '<DESCRIPTION>', # optional + location = '<LOCATION>', # optional + status_code = 300, # optional + priority = -100000, # optional + enabled = False, # optional + conditions = [] # optional +) + +print(result.model_dump()) +``` diff --git a/docs/examples/webhooks/create.md b/docs/examples/webhooks/create.md index ed957a41..1585ef2b 100644 --- a/docs/examples/webhooks/create.md +++ b/docs/examples/webhooks/create.md @@ -14,7 +14,7 @@ result: Webhook = webhooks.create( webhook_id = '<WEBHOOK_ID>', url = 'https://example.com/webhook', name = '<NAME>', - events = [], + events = ["users.*.create"], enabled = False, # optional tls = False, # optional auth_username = '<AUTH_USERNAME>', # optional diff --git a/docs/examples/webhooks/update.md b/docs/examples/webhooks/update.md index a6d3ac7b..647e8618 100644 --- a/docs/examples/webhooks/update.md +++ b/docs/examples/webhooks/update.md @@ -14,7 +14,7 @@ result: Webhook = webhooks.update( webhook_id = '<WEBHOOK_ID>', name = '<NAME>', url = 'https://example.com/webhook', - events = [], + events = ["users.*.create"], enabled = False, # optional tls = False, # optional auth_username = '<AUTH_USERNAME>', # optional diff --git a/pyproject.toml b/pyproject.toml index e8e2aa0c..f9897243 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "appwrite" -version = "24.2.0" +version = "25.0.0" description = "Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API" readme = "README.md" requires-python = ">=3.9" diff --git a/setup.py b/setup.py index eb5e4ea1..dc433792 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name='appwrite', packages=setuptools.find_packages(), - version='24.2.0', + version='25.0.0', license='BSD-3-Clause', description='Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API', long_description=long_description, @@ -18,7 +18,7 @@ maintainer='Appwrite Team', maintainer_email='team@appwrite.io', url='https://appwrite.io/support', - download_url='https://github.com/appwrite/sdk-for-python/archive/24.2.0.tar.gz', + download_url='https://github.com/appwrite/sdk-for-python/archive/25.0.0.tar.gz', install_requires=[ 'requests', 'pydantic>=2,<3', diff --git a/test/services/test_account.py b/test/services/test_account.py index ee88a7d8..04fb136f 100644 --- a/test/services/test_account.py +++ b/test/services/test_account.py @@ -261,22 +261,6 @@ def test_delete_identity(self, m): ) self.assertEqual(response, data) - @requests_mock.Mocker() - def test_list_logs(self, m): - data = { - "total": 5.0, - "logs": [], - } - headers = {'Content-Type': 'application/json'} - m.request( - requests_mock.ANY, - requests_mock.ANY, - text=json.dumps(data), - headers=headers, - ) - response = self.account.list_logs() - self.assertEqual(response.to_dict(), data) - @requests_mock.Mocker() def test_update_mfa(self, m): data = { @@ -733,6 +717,121 @@ def test_update_name(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_list_passkeys(self, m): + data = { + "total": 5.0, + "passkeys": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.list_passkeys() + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_passkey(self, m): + data = { + "$id": "bb8ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "passkeyId": "5e5ea5c16897e", + "expire": "2020-10-15T06:38:00.000+00:00", + "publicKey": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.create_passkey() + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_passkey(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "My laptop", + "accessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.get_passkey( + '<PASSKEY_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_passkey(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "My laptop", + "accessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.update_passkey( + '<PASSKEY_ID>', + '<NAME>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_delete_passkey(self, m): + data = '' + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.delete_passkey( + '<PASSKEY_ID>', + ) + self.assertEqual(response, data) + + @requests_mock.Mocker() + def test_update_passkey_verification(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "My laptop", + "accessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.update_passkey_verification( + '<PASSKEY_ID>', + {}, + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_update_password(self, m): data = { @@ -890,6 +989,52 @@ def test_update_recovery(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_create_recovery_otp(self, m): + data = { + "$id": "bb8ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "userId": "5e5ea5c168bb8", + "secret": "", + "expire": "2020-10-15T06:38:00.000+00:00", + "phrase": "Golden Fox", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.create_recovery_otp( + 'email@example.com', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_recovery_otp(self, m): + data = { + "$id": "bb8ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "userId": "5e5ea5c168bb8", + "secret": "", + "expire": "2020-10-15T06:38:00.000+00:00", + "phrase": "Golden Fox", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.update_recovery_otp( + '<USER_ID>', + '<SECRET>', + 'password', + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_list_sessions(self, m): data = { @@ -1008,6 +1153,52 @@ def test_create_email_password_session(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_create_id_token_session(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "userId": "5e5bb8c16897e", + "expire": "2020-10-15T06:38:00.000+00:00", + "provider": "email", + "providerUid": "user@example.com", + "providerAccessToken": "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", + "providerAccessTokenExpiry": "2020-10-15T06:38:00.000+00:00", + "providerRefreshToken": "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", + "ip": "127.0.0.1", + "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", + "current": True, + "factors": [], + "secret": "5e5bb8c16897e", + "mfaUpdatedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.create_id_token_session( + 'apple', + '<ID_TOKEN>', + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_update_magic_url_session(self, m): data = { @@ -1342,6 +1533,48 @@ def test_create_o_auth2_token(self, m): ) self.assertEqual(response, data) + @requests_mock.Mocker() + def test_create_passkey_token(self, m): + data = { + "$id": "bb8ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "passkeyId": "5e5ea5c16897e", + "expire": "2020-10-15T06:38:00.000+00:00", + "publicKey": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.create_passkey_token() + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_passkey_token(self, m): + data = { + "$id": "bb8ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "userId": "5e5ea5c168bb8", + "secret": "", + "expire": "2020-10-15T06:38:00.000+00:00", + "phrase": "Golden Fox", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.update_passkey_token( + '<CHALLENGE_ID>', + {}, + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_create_phone_token(self, m): data = { @@ -1455,6 +1688,49 @@ def test_update_verification(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_create_email_verification_otp(self, m): + data = { + "$id": "bb8ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "userId": "5e5ea5c168bb8", + "secret": "", + "expire": "2020-10-15T06:38:00.000+00:00", + "phrase": "Golden Fox", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.create_email_verification_otp() + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_email_verification_otp(self, m): + data = { + "$id": "bb8ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "userId": "5e5ea5c168bb8", + "secret": "", + "expire": "2020-10-15T06:38:00.000+00:00", + "phrase": "Golden Fox", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.account.update_email_verification_otp( + '<USER_ID>', + '<SECRET>', + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_create_phone_verification(self, m): data = { diff --git a/test/services/test_avatars.py b/test/services/test_avatars.py index b6fc5fbb..c54fe183 100644 --- a/test/services/test_avatars.py +++ b/test/services/test_avatars.py @@ -115,6 +115,51 @@ def test_get_photo(self, m): response = self.avatars.get_photo() self.assertEqual(response, data) + @requests_mock.Mocker() + def test_update_photo(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "John Doe", + "registration": "2020-10-15T06:38:00.000+00:00", + "status": True, + "labels": [], + "passwordUpdate": "2020-10-15T06:38:00.000+00:00", + "email": "john@appwrite.io", + "phone": "+4930901820", + "emailVerification": True, + "phoneVerification": True, + "mfa": True, + "prefs": {}, + "targets": [], + "accessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.avatars.update_photo( + InputFile.from_bytes(bytearray(), "example.file"), + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_delete_photo(self, m): + data = '' + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.avatars.delete_photo() + self.assertEqual(response, data) + @requests_mock.Mocker() def test_get_qr(self, m): data = bytearray() diff --git a/test/services/test_backups.py b/test/services/test_backups.py index a2515204..175b3515 100644 --- a/test/services/test_backups.py +++ b/test/services/test_backups.py @@ -37,9 +37,7 @@ def test_create_archive(self, m): "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "policyId": "did8jx6ws45jana098ab7", - "size": 100000.0, "status": "completed", - "startedAt": "2020-10-15T06:38:00.000+00:00", "migrationId": "did8jx6ws45jana098ab7", "services": [], "resources": [], @@ -63,9 +61,7 @@ def test_get_archive(self, m): "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "policyId": "did8jx6ws45jana098ab7", - "size": 100000.0, "status": "completed", - "startedAt": "2020-10-15T06:38:00.000+00:00", "migrationId": "did8jx6ws45jana098ab7", "services": [], "resources": [], @@ -138,7 +134,7 @@ def test_create_policy(self, m): '<POLICY_ID>', [], 1, - '', + 'schedule', ) self.assertEqual(response.to_dict(), data) @@ -218,11 +214,10 @@ def test_create_restoration(self, m): "archiveId": "did8jx6ws45jana098ab7", "policyId": "did8jx6ws45jana098ab7", "status": "completed", - "startedAt": "2020-10-15T06:38:00.000+00:00", "migrationId": "did8jx6ws45jana098ab7", "services": [], "resources": [], - "options": "{databases.database[{oldId, newId, newName}]}", + "options": {}, } headers = {'Content-Type': 'application/json'} m.request( @@ -262,11 +257,10 @@ def test_get_restoration(self, m): "archiveId": "did8jx6ws45jana098ab7", "policyId": "did8jx6ws45jana098ab7", "status": "completed", - "startedAt": "2020-10-15T06:38:00.000+00:00", "migrationId": "did8jx6ws45jana098ab7", "services": [], "resources": [], - "options": "{databases.database[{oldId, newId, newName}]}", + "options": {}, } headers = {'Content-Type': 'application/json'} m.request( diff --git a/test/services/test_documents_db.py b/test/services/test_documents_db.py index 05ffaa0d..fb451c82 100644 --- a/test/services/test_documents_db.py +++ b/test/services/test_documents_db.py @@ -58,12 +58,6 @@ def test_list_specifications(self, m): data = { "specifications": [], "total": 9.0, - "pricing": { - "storageOverageRate": 0.125, - "bandwidthOverageRate": 0.08, - "replicaRate": 1, - "pitrRate": 0.2, - }, } headers = {'Content-Type': 'application/json'} m.request( @@ -748,16 +742,12 @@ def test_create_failover(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -767,6 +757,8 @@ def test_create_failover(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -780,7 +772,7 @@ def test_create_failover(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -851,10 +843,6 @@ def test_get_status(self, m): "engine": "postgresql", "version": "17", "uptime": 86400.0, - "connections": { - "current": 12.0, - "max": 100.0, - }, "syncMode": "async", "syncDegraded": True, "syncAcknowledgements": 1.0, diff --git a/test/services/test_domains.py b/test/services/test_domains.py new file mode 100644 index 00000000..8ae6d3c4 --- /dev/null +++ b/test/services/test_domains.py @@ -0,0 +1,1207 @@ +import json +import requests_mock +import unittest + +from appwrite.client import Client +from appwrite.input_file import InputFile +from appwrite.models import * +from appwrite.services.domains import Domains + + +class DomainsServiceTest(unittest.TestCase): + + def setUp(self): + self.client = Client() + self.domains = Domains(self.client) + + @requests_mock.Mocker() + def test_list(self, m): + data = { + "total": 5.0, + "domains": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.list() + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "domain": "example.com", + "registrar": "appwrite", + "nameservers": "Appwrite", + "expire": "2020-10-15T06:38:00.000+00:00", + "renewal": "2020-10-15T06:38:00.000+00:00", + "autoRenewal": True, + "renewalPrice": 2599.0, + "teamId": "5e5ea5c16897e", + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create( + '<TEAM_ID>', + 'example.com', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_price(self, m): + data = { + "domain": "example.com", + "tld": "com", + "available": True, + "periodYears": 1.0, + "premium": True, + "renewalPeriodYears": 1.0, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_price( + 'example.com', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_list_prices(self, m): + data = { + "total": 5.0, + "prices": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.list_prices( + [], + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "domain": "example.com", + "registrar": "appwrite", + "nameservers": "Appwrite", + "expire": "2020-10-15T06:38:00.000+00:00", + "renewal": "2020-10-15T06:38:00.000+00:00", + "autoRenewal": True, + "renewalPrice": 2599.0, + "teamId": "5e5ea5c16897e", + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_delete(self, m): + data = '' + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.delete( + '<DOMAIN_ID>', + ) + self.assertEqual(response, data) + + @requests_mock.Mocker() + def test_update_nameservers(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "domain": "example.com", + "registrar": "appwrite", + "nameservers": "Appwrite", + "expire": "2020-10-15T06:38:00.000+00:00", + "renewal": "2020-10-15T06:38:00.000+00:00", + "autoRenewal": True, + "renewalPrice": 2599.0, + "teamId": "5e5ea5c16897e", + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_nameservers( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_verify_nameservers(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "domain": "example.com", + "registrar": "appwrite", + "nameservers": "Appwrite", + "expire": "2020-10-15T06:38:00.000+00:00", + "renewal": "2020-10-15T06:38:00.000+00:00", + "autoRenewal": True, + "renewalPrice": 2599.0, + "teamId": "5e5ea5c16897e", + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.verify_nameservers( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_preset_google_workspace(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_preset_google_workspace( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_preset_google_workspace(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_preset_google_workspace( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_preset_i_cloud(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_preset_i_cloud( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_preset_i_cloud(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_preset_i_cloud( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_preset_mailgun(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_preset_mailgun( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_preset_mailgun(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_preset_mailgun( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_preset_outlook(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_preset_outlook( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_preset_outlook(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_preset_outlook( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_preset_proton_mail(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_preset_proton_mail( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_preset_proton_mail(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_preset_proton_mail( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_preset_zoho(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_preset_zoho( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_preset_zoho(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_preset_zoho( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_list_records(self, m): + data = { + "total": 5.0, + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.list_records( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_a(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_a( + '<DOMAIN_ID>', + 'name', + 'value', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_a(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_a( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + 'value', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_aaaa(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_aaaa( + '<DOMAIN_ID>', + 'name', + 'value', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_aaaa(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_aaaa( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + 'value', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_alias(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_alias( + '<DOMAIN_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_alias(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_alias( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_caa(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_caa( + '<DOMAIN_ID>', + 'name', + 'value', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_caa(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_caa( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + 'value', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_cname(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_cname( + '<DOMAIN_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_cname(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_cname( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_https(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_https( + '<DOMAIN_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_https(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_https( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_mx(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_mx( + '<DOMAIN_ID>', + 'name', + '<VALUE>', + 1, + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_mx(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_mx( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + '<VALUE>', + 1, + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_ns(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_ns( + '<DOMAIN_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_ns(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_ns( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_srv(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_srv( + '<DOMAIN_ID>', + 'name', + '<VALUE>', + 1, + 1, + 1, + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_srv(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_srv( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + '<VALUE>', + 1, + 1, + 1, + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_record_txt(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.create_record_txt( + '<DOMAIN_ID>', + 'name', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_record_txt(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_record_txt( + '<DOMAIN_ID>', + '<RECORD_ID>', + 'name', + '<VALUE>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_record(self, m): + data = { + "$id": "5f40a6e10c65e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "type": "A", + "name": "mail", + "value": "192.0.2.1", + "ttl": 86400.0, + "priority": 10.0, + "lock": True, + "weight": 10.0, + "port": 443.0, + "comment": "Mail server record", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_record( + '<DOMAIN_ID>', + '<RECORD_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_delete_record(self, m): + data = '' + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.delete_record( + '<DOMAIN_ID>', + '<RECORD_ID>', + ) + self.assertEqual(response, data) + + @requests_mock.Mocker() + def test_update_team(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "domain": "example.com", + "registrar": "appwrite", + "nameservers": "Appwrite", + "expire": "2020-10-15T06:38:00.000+00:00", + "renewal": "2020-10-15T06:38:00.000+00:00", + "autoRenewal": True, + "renewalPrice": 2599.0, + "teamId": "5e5ea5c16897e", + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_team( + '<DOMAIN_ID>', + '<TEAM_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_transfer_status(self, m): + data = { + "status": "pending_registry", + "reason": "Transfer in progress", + "timestamp": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.get_transfer_status( + '<DOMAIN_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_zone(self, m): + data = '; café zone\nwww 3600 IN A 192.0.2.1\n' + headers = {'Content-Type': 'text/plain; charset=utf-8'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=data, + headers=headers, + ) + response = self.domains.get_zone( + '<DOMAIN_ID>', + ) + self.assertEqual(response, data) + + @requests_mock.Mocker() + def test_update_zone(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "domain": "example.com", + "registrar": "appwrite", + "nameservers": "Appwrite", + "expire": "2020-10-15T06:38:00.000+00:00", + "renewal": "2020-10-15T06:38:00.000+00:00", + "autoRenewal": True, + "renewalPrice": 2599.0, + "teamId": "5e5ea5c16897e", + "dnsRecords": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.domains.update_zone( + '<DOMAIN_ID>', + '<CONTENT>', + ) + self.assertEqual(response.to_dict(), data) diff --git a/test/services/test_functions.py b/test/services/test_functions.py index 16a21555..8cc954e3 100644 --- a/test/services/test_functions.py +++ b/test/services/test_functions.py @@ -631,7 +631,7 @@ def test_create_execution(self, m): "responseHeaders": [], "logs": "", "errors": "", - "duration": 0.4, + "duration": 1.23, } headers = {'Content-Type': 'application/json'} m.request( @@ -665,7 +665,7 @@ def test_get_execution(self, m): "responseHeaders": [], "logs": "", "errors": "", - "duration": 0.4, + "duration": 1.23, } headers = {'Content-Type': 'application/json'} m.request( diff --git a/test/services/test_messaging.py b/test/services/test_messaging.py index ad69b926..03c86ea6 100644 --- a/test/services/test_messaging.py +++ b/test/services/test_messaging.py @@ -415,6 +415,55 @@ def test_update_apns_provider(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_create_appwrite_provider(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Mailgun", + "provider": "mailgun", + "enabled": True, + "type": "sms", + "credentials": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.messaging.create_appwrite_provider( + '<PROVIDER_ID>', + '<NAME>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_appwrite_provider(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Mailgun", + "provider": "mailgun", + "enabled": True, + "type": "sms", + "credentials": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.messaging.update_appwrite_provider( + '<PROVIDER_ID>', + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_create_fcm_provider(self, m): data = { diff --git a/test/services/test_mongo.py b/test/services/test_mongo.py index d66adcb2..c323fb93 100644 --- a/test/services/test_mongo.py +++ b/test/services/test_mongo.py @@ -38,16 +38,12 @@ def test_create(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -57,6 +53,8 @@ def test_create(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -70,7 +68,7 @@ def test_create(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -99,12 +97,6 @@ def test_list_specifications(self, m): data = { "specifications": [], "total": 9.0, - "pricing": { - "storageOverageRate": 0.125, - "bandwidthOverageRate": 0.08, - "replicaRate": 1, - "pitrRate": 0.2, - }, } headers = {'Content-Type': 'application/json'} m.request( @@ -124,16 +116,12 @@ def test_get(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -143,6 +131,8 @@ def test_get(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -156,7 +146,7 @@ def test_get(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -187,16 +177,12 @@ def test_update(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -206,6 +192,8 @@ def test_update(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -219,7 +207,7 @@ def test_update(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -346,7 +334,7 @@ def test_create_backup_policy(self, m): '<DATABASE_ID>', '<POLICY_ID>', '<NAME>', - '', + 'schedule', 1, ) self.assertEqual(response.to_dict(), data) @@ -517,16 +505,12 @@ def test_create_branch(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -536,6 +520,8 @@ def test_create_branch(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -549,7 +535,7 @@ def test_create_branch(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -580,16 +566,12 @@ def test_delete_branch(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -599,6 +581,8 @@ def test_delete_branch(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -612,7 +596,7 @@ def test_delete_branch(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -668,16 +652,12 @@ def test_create_failover(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -687,6 +667,8 @@ def test_create_failover(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -700,7 +682,7 @@ def test_create_failover(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -731,16 +713,12 @@ def test_update_maintenance(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -750,6 +728,8 @@ def test_update_maintenance(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -763,7 +743,7 @@ def test_update_maintenance(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -796,16 +776,12 @@ def test_create_migration(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -815,6 +791,8 @@ def test_create_migration(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -828,7 +806,7 @@ def test_create_migration(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -934,14 +912,9 @@ def test_create_restoration(self, m): "$id": "5e5ea5c16897e", "$createdAt": "2020-10-15T06:38:00.000+00:00", "databaseId": "5e5ea5c16897e", - "sourceDatabaseId": "5e5ea5c16897e", "projectId": "5e5ea5c16897e", - "backupId": "5e5ea5c16897e", "type": "backup", "status": "completed", - "targetTime": "2020-10-15T06:38:00.000+00:00", - "startedAt": "2020-10-15T06:38:00.000+00:00", - "completedAt": "2020-10-15T06:38:00.000+00:00", "error": "", } headers = {'Content-Type': 'application/json'} @@ -962,14 +935,9 @@ def test_get_restoration(self, m): "$id": "5e5ea5c16897e", "$createdAt": "2020-10-15T06:38:00.000+00:00", "databaseId": "5e5ea5c16897e", - "sourceDatabaseId": "5e5ea5c16897e", "projectId": "5e5ea5c16897e", - "backupId": "5e5ea5c16897e", "type": "backup", "status": "completed", - "targetTime": "2020-10-15T06:38:00.000+00:00", - "startedAt": "2020-10-15T06:38:00.000+00:00", - "completedAt": "2020-10-15T06:38:00.000+00:00", "error": "", } headers = {'Content-Type': 'application/json'} @@ -993,10 +961,6 @@ def test_get_status(self, m): "engine": "postgresql", "version": "17", "uptime": 86400.0, - "connections": { - "current": 12.0, - "max": 100.0, - }, "syncMode": "async", "syncDegraded": True, "syncAcknowledgements": 1.0, @@ -1024,16 +988,12 @@ def test_create_upgrade(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -1043,6 +1003,8 @@ def test_create_upgrade(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -1056,7 +1018,7 @@ def test_create_upgrade(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, diff --git a/test/services/test_mysql.py b/test/services/test_mysql.py index 74439293..0c9d361b 100644 --- a/test/services/test_mysql.py +++ b/test/services/test_mysql.py @@ -38,16 +38,12 @@ def test_create(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -57,6 +53,8 @@ def test_create(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -70,7 +68,7 @@ def test_create(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -99,12 +97,6 @@ def test_list_specifications(self, m): data = { "specifications": [], "total": 9.0, - "pricing": { - "storageOverageRate": 0.125, - "bandwidthOverageRate": 0.08, - "replicaRate": 1, - "pitrRate": 0.2, - }, } headers = {'Content-Type': 'application/json'} m.request( @@ -124,16 +116,12 @@ def test_get(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -143,6 +131,8 @@ def test_get(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -156,7 +146,7 @@ def test_get(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -187,16 +177,12 @@ def test_update(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -206,6 +192,8 @@ def test_update(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -219,7 +207,7 @@ def test_update(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -346,7 +334,7 @@ def test_create_backup_policy(self, m): '<DATABASE_ID>', '<POLICY_ID>', '<NAME>', - '', + 'schedule', 1, ) self.assertEqual(response.to_dict(), data) @@ -517,16 +505,12 @@ def test_create_branch(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -536,6 +520,8 @@ def test_create_branch(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -549,7 +535,7 @@ def test_create_branch(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -580,16 +566,12 @@ def test_delete_branch(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -599,6 +581,8 @@ def test_delete_branch(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -612,7 +596,7 @@ def test_delete_branch(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -691,16 +675,12 @@ def test_create_failover(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -710,6 +690,8 @@ def test_create_failover(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -723,7 +705,7 @@ def test_create_failover(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -754,16 +736,12 @@ def test_update_maintenance(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -773,6 +751,8 @@ def test_update_maintenance(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -786,7 +766,7 @@ def test_update_maintenance(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -819,16 +799,12 @@ def test_create_migration(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -838,6 +814,8 @@ def test_create_migration(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -851,7 +829,7 @@ def test_create_migration(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -1009,14 +987,9 @@ def test_create_restoration(self, m): "$id": "5e5ea5c16897e", "$createdAt": "2020-10-15T06:38:00.000+00:00", "databaseId": "5e5ea5c16897e", - "sourceDatabaseId": "5e5ea5c16897e", "projectId": "5e5ea5c16897e", - "backupId": "5e5ea5c16897e", "type": "backup", "status": "completed", - "targetTime": "2020-10-15T06:38:00.000+00:00", - "startedAt": "2020-10-15T06:38:00.000+00:00", - "completedAt": "2020-10-15T06:38:00.000+00:00", "error": "", } headers = {'Content-Type': 'application/json'} @@ -1037,14 +1010,9 @@ def test_get_restoration(self, m): "$id": "5e5ea5c16897e", "$createdAt": "2020-10-15T06:38:00.000+00:00", "databaseId": "5e5ea5c16897e", - "sourceDatabaseId": "5e5ea5c16897e", "projectId": "5e5ea5c16897e", - "backupId": "5e5ea5c16897e", "type": "backup", "status": "completed", - "targetTime": "2020-10-15T06:38:00.000+00:00", - "startedAt": "2020-10-15T06:38:00.000+00:00", - "completedAt": "2020-10-15T06:38:00.000+00:00", "error": "", } headers = {'Content-Type': 'application/json'} @@ -1068,10 +1036,6 @@ def test_get_status(self, m): "engine": "postgresql", "version": "17", "uptime": 86400.0, - "connections": { - "current": 12.0, - "max": 100.0, - }, "syncMode": "async", "syncDegraded": True, "syncAcknowledgements": 1.0, @@ -1099,16 +1063,12 @@ def test_create_upgrade(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -1118,6 +1078,8 @@ def test_create_upgrade(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -1131,7 +1093,7 @@ def test_create_upgrade(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, diff --git a/test/services/test_oauth2.py b/test/services/test_oauth2.py index 5365456d..da2520ee 100644 --- a/test/services/test_oauth2.py +++ b/test/services/test_oauth2.py @@ -68,8 +68,8 @@ def test_create_device_authorization(self, m): data = { "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", + "verification_uri": "https:\/\/appwrite.io\/oauth2\/device", + "verification_uri_complete": "https:\/\/appwrite.io\/oauth2\/device?user_code=ABCD-EFGH", "expires_in": 900.0, "interval": 5.0, } @@ -139,6 +139,23 @@ def test_get_grant(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_introspect(self, m): + data = { + "active": True, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.oauth2.introspect( + '<TOKEN>', + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_list_organizations(self, m): data = { diff --git a/test/services/test_organization.py b/test/services/test_organization.py index 5a7df9dc..b8df68b9 100644 --- a/test/services/test_organization.py +++ b/test/services/test_organization.py @@ -63,72 +63,6 @@ def test_get(self, m): "usageLogs": 30.0, "projectInactivityDays": 7.0, "alertLimit": 80.0, - "usage": { - "bandwidth": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "executions": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "realtime": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "realtimeMessages": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "storage": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "users": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "GBHours": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "imageTransformations": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - }, "addons": {}, "budgetCapEnabled": True, "customSmtp": True, @@ -162,13 +96,6 @@ def test_get(self, m): "databaseComputeCredit": 10, }, "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", - "billingTrialDays": 14.0, - "billingAggregationId": "adbc3de4rddfsd", - "billingInvoiceId": "adbc3de4rddfsd", - "paymentMethodId": "adbc3de4rddfsd", "status": "active", "markedForDeletion": True, "platform": "imagine", @@ -233,72 +160,6 @@ def test_update(self, m): "usageLogs": 30.0, "projectInactivityDays": 7.0, "alertLimit": 80.0, - "usage": { - "bandwidth": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "executions": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "realtime": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "realtimeMessages": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "storage": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "users": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "GBHours": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - "imageTransformations": { - "name": "", - "unit": "GB", - "currency": "USD", - "price": 5, - "value": 25.0, - "invoiceDesc": "", - }, - }, "addons": {}, "budgetCapEnabled": True, "customSmtp": True, @@ -332,13 +193,6 @@ def test_update(self, m): "databaseComputeCredit": 10, }, "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", - "billingTrialDays": 14.0, - "billingAggregationId": "adbc3de4rddfsd", - "billingInvoiceId": "adbc3de4rddfsd", - "paymentMethodId": "adbc3de4rddfsd", "status": "active", "markedForDeletion": True, "platform": "imagine", @@ -475,116 +329,6 @@ def test_delete_installation(self, m): ) self.assertEqual(response, data) - @requests_mock.Mocker() - def test_list_keys(self, m): - data = { - "total": 5.0, - "keys": [], - } - headers = {'Content-Type': 'application/json'} - m.request( - requests_mock.ANY, - requests_mock.ANY, - text=json.dumps(data), - headers=headers, - ) - response = self.organization.list_keys() - self.assertEqual(response.to_dict(), data) - - @requests_mock.Mocker() - def test_create_key(self, m): - data = { - "$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": [], - "secret": "919c2d18fb5d4...a2ae413da83346ad2", - "accessedAt": "2020-10-15T06:38:00.000+00:00", - "sdks": [], - } - headers = {'Content-Type': 'application/json'} - m.request( - requests_mock.ANY, - requests_mock.ANY, - text=json.dumps(data), - headers=headers, - ) - response = self.organization.create_key( - '<KEY_ID>', - '<NAME>', - [], - ) - self.assertEqual(response.to_dict(), data) - - @requests_mock.Mocker() - def test_get_key(self, m): - data = { - "$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": [], - "secret": "919c2d18fb5d4...a2ae413da83346ad2", - "accessedAt": "2020-10-15T06:38:00.000+00:00", - "sdks": [], - } - headers = {'Content-Type': 'application/json'} - m.request( - requests_mock.ANY, - requests_mock.ANY, - text=json.dumps(data), - headers=headers, - ) - response = self.organization.get_key( - '<KEY_ID>', - ) - self.assertEqual(response.to_dict(), data) - - @requests_mock.Mocker() - def test_update_key(self, m): - data = { - "$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": [], - "secret": "919c2d18fb5d4...a2ae413da83346ad2", - "accessedAt": "2020-10-15T06:38:00.000+00:00", - "sdks": [], - } - headers = {'Content-Type': 'application/json'} - m.request( - requests_mock.ANY, - requests_mock.ANY, - text=json.dumps(data), - headers=headers, - ) - response = self.organization.update_key( - '<KEY_ID>', - '<NAME>', - [], - ) - self.assertEqual(response.to_dict(), data) - - @requests_mock.Mocker() - def test_delete_key(self, m): - data = '' - headers = {'Content-Type': 'application/json'} - m.request( - requests_mock.ANY, - requests_mock.ANY, - text=json.dumps(data), - headers=headers, - ) - response = self.organization.delete_key( - '<KEY_ID>', - ) - self.assertEqual(response, data) - @requests_mock.Mocker() def test_list_memberships(self, m): data = { @@ -735,7 +479,6 @@ def test_create_project(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -779,7 +522,6 @@ def test_get_project(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -822,7 +564,6 @@ def test_update_project(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -871,3 +612,118 @@ def test_delete_project(self, m): '<PROJECT_ID>', ) self.assertEqual(response, data) + + @requests_mock.Mocker() + def test_list_project_keys(self, m): + data = { + "total": 5.0, + "keys": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.organization.list_project_keys( + '<PROJECT_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_ephemeral_project_key(self, m): + data = { + "$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": [], + "secret": "919c2d18fb5d4...a2ae413da83346ad2", + "accessedAt": "2020-10-15T06:38:00.000+00:00", + "sdks": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.organization.create_ephemeral_project_key( + '<PROJECT_ID>', + [], + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_project_key(self, m): + data = { + "$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": [], + "secret": "919c2d18fb5d4...a2ae413da83346ad2", + "accessedAt": "2020-10-15T06:38:00.000+00:00", + "sdks": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.organization.get_project_key( + '<PROJECT_ID>', + '<KEY_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_project_key(self, m): + data = { + "$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": [], + "secret": "919c2d18fb5d4...a2ae413da83346ad2", + "accessedAt": "2020-10-15T06:38:00.000+00:00", + "sdks": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.organization.update_project_key( + '<PROJECT_ID>', + '<KEY_ID>', + '<NAME>', + [], + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_delete_project_key(self, m): + data = '' + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.organization.delete_project_key( + '<PROJECT_ID>', + '<KEY_ID>', + ) + self.assertEqual(response, data) diff --git a/test/services/test_postgresql.py b/test/services/test_postgresql.py index 4e6beeef..3625d2c7 100644 --- a/test/services/test_postgresql.py +++ b/test/services/test_postgresql.py @@ -38,16 +38,12 @@ def test_create(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -57,6 +53,8 @@ def test_create(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -70,7 +68,7 @@ def test_create(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -99,12 +97,6 @@ def test_list_specifications(self, m): data = { "specifications": [], "total": 9.0, - "pricing": { - "storageOverageRate": 0.125, - "bandwidthOverageRate": 0.08, - "replicaRate": 1, - "pitrRate": 0.2, - }, } headers = {'Content-Type': 'application/json'} m.request( @@ -124,16 +116,12 @@ def test_get(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -143,6 +131,8 @@ def test_get(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -156,7 +146,7 @@ def test_get(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -187,16 +177,12 @@ def test_update(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -206,6 +192,8 @@ def test_update(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -219,7 +207,7 @@ def test_update(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -346,7 +334,7 @@ def test_create_backup_policy(self, m): '<DATABASE_ID>', '<POLICY_ID>', '<NAME>', - '', + 'schedule', 1, ) self.assertEqual(response.to_dict(), data) @@ -517,16 +505,12 @@ def test_create_branch(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -536,6 +520,8 @@ def test_create_branch(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -549,7 +535,7 @@ def test_create_branch(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -580,16 +566,12 @@ def test_delete_branch(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -599,6 +581,8 @@ def test_delete_branch(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -612,7 +596,7 @@ def test_delete_branch(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -710,16 +694,12 @@ def test_create_extension(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -729,6 +709,8 @@ def test_create_extension(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -742,7 +724,7 @@ def test_create_extension(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -774,16 +756,12 @@ def test_delete_extension(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -793,6 +771,8 @@ def test_delete_extension(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -806,7 +786,7 @@ def test_delete_extension(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -838,16 +818,12 @@ def test_create_failover(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -857,6 +833,8 @@ def test_create_failover(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -870,7 +848,7 @@ def test_create_failover(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -901,16 +879,12 @@ def test_update_maintenance(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -920,6 +894,8 @@ def test_update_maintenance(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -933,7 +909,7 @@ def test_update_maintenance(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -966,16 +942,12 @@ def test_create_migration(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -985,6 +957,8 @@ def test_create_migration(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -998,7 +972,7 @@ def test_create_migration(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -1156,14 +1130,9 @@ def test_create_restoration(self, m): "$id": "5e5ea5c16897e", "$createdAt": "2020-10-15T06:38:00.000+00:00", "databaseId": "5e5ea5c16897e", - "sourceDatabaseId": "5e5ea5c16897e", "projectId": "5e5ea5c16897e", - "backupId": "5e5ea5c16897e", "type": "backup", "status": "completed", - "targetTime": "2020-10-15T06:38:00.000+00:00", - "startedAt": "2020-10-15T06:38:00.000+00:00", - "completedAt": "2020-10-15T06:38:00.000+00:00", "error": "", } headers = {'Content-Type': 'application/json'} @@ -1184,14 +1153,9 @@ def test_get_restoration(self, m): "$id": "5e5ea5c16897e", "$createdAt": "2020-10-15T06:38:00.000+00:00", "databaseId": "5e5ea5c16897e", - "sourceDatabaseId": "5e5ea5c16897e", "projectId": "5e5ea5c16897e", - "backupId": "5e5ea5c16897e", "type": "backup", "status": "completed", - "targetTime": "2020-10-15T06:38:00.000+00:00", - "startedAt": "2020-10-15T06:38:00.000+00:00", - "completedAt": "2020-10-15T06:38:00.000+00:00", "error": "", } headers = {'Content-Type': 'application/json'} @@ -1215,10 +1179,6 @@ def test_get_status(self, m): "engine": "postgresql", "version": "17", "uptime": 86400.0, - "connections": { - "current": 12.0, - "max": 100.0, - }, "syncMode": "async", "syncDegraded": True, "syncAcknowledgements": 1.0, @@ -1246,16 +1206,12 @@ def test_create_upgrade(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -1265,6 +1221,8 @@ def test_create_upgrade(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -1278,7 +1236,7 @@ def test_create_upgrade(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, diff --git a/test/services/test_project.py b/test/services/test_project.py index 09549bf2..931ff6a6 100644 --- a/test/services/test_project.py +++ b/test/services/test_project.py @@ -23,7 +23,6 @@ def test_get(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -77,7 +76,6 @@ def test_update_auth_method(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -230,7 +228,6 @@ def test_update_labels(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -382,7 +379,6 @@ def test_update_o_auth2_server(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -444,6 +440,8 @@ def test_update_o_auth2_apple(self, m): "keyId": "P4000000N8", "teamId": "D4000000R6", "p8File": "-----BEGIN PRIVATE KEY-----MIGTAg...jy2Xbna-----END PRIVATE KEY-----", + "nativeEnabled": True, + "nativeClientIds": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -480,6 +478,7 @@ def test_update_o_auth2_auth0(self, m): "enabled": True, "clientId": "OaOkIA000000000000000000005KLSYq", "clientSecret": "zXz0000-00000000000000000000000000000-00000000000000000000PJafnF", + "prompt": [], "endpoint": "example.us.auth0.com", } headers = {'Content-Type': 'application/json'} @@ -626,6 +625,7 @@ def test_update_o_auth2_discord(self, m): "enabled": True, "clientId": "950722000000343754", "clientSecret": "YmPXnM000000000000000000002zFg5D", + "prompt": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -753,6 +753,7 @@ def test_update_o_auth2_git_hub(self, m): "enabled": True, "clientId": "e4d87900000000540733", "clientSecret": "5e07c00000000000000000000000000000198bcc", + "prompt": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -791,6 +792,8 @@ def test_update_o_auth2_google(self, m): "clientId": "120000000095-92ifjb00000000000000000000g7ijfb.apps.googleusercontent.com", "clientSecret": "GOCSPX-2k8gsR0000000000000000VNahJj", "prompt": [], + "nativeEnabled": True, + "nativeClientIds": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -820,6 +823,25 @@ def test_update_o_auth2_hugging_face(self, m): response = self.project.update_o_auth2_hugging_face() self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_update_o_auth2_kakao(self, m): + data = { + "$id": "github", + "enabled": True, + "clientId": "839ff5000000000000000000013206de", + "clientSecret": "jLNVOK00000000000000000000yJebea", + "prompt": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.project.update_o_auth2_kakao() + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_update_o_auth2_keycloak(self, m): data = { @@ -883,6 +905,7 @@ def test_update_o_auth2_microsoft(self, m): "enabled": True, "applicationId": "00001111-aaaa-2222-bbbb-3333cccc4444", "applicationSecret": "A1bC2dE3fH4iJ5kL6mN7oP8qR9sT0u", + "prompt": [], "tenant": "common", } headers = {'Content-Type': 'application/json'} @@ -920,11 +943,11 @@ def test_update_o_auth2_oidc(self, m): "enabled": True, "clientId": "qibI2x0000000000000000000000000006L2YFoG", "clientSecret": "Ah68ed000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003qpcHV", + "prompt": [], "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", - "prompt": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -943,6 +966,7 @@ def test_update_o_auth2_okta(self, m): "enabled": True, "clientId": "0oa00000000000000698", "clientSecret": "Kiq0000000000000000000000000000000000000-00000000000H2L5-3SJ-vRV", + "prompt": [], "domain": "trial-6400025.okta.com", "authorizationServerId": "aus000000000000000h7z", } @@ -1035,6 +1059,7 @@ def test_update_o_auth2_salesforce(self, m): "enabled": True, "customerKey": "3MVG9I0000000000000000000000000000000000000000000000000000000000000000000000000C5Aejq", "customerSecret": "3w000000000000e2", + "prompt": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -1100,6 +1125,24 @@ def test_update_o_auth2_stripe(self, m): response = self.project.update_o_auth2_stripe() self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_update_o_auth2_tik_tok(self, m): + data = { + "$id": "github", + "enabled": True, + "clientId": "awz000000000tyw0", + "clientSecret": "6wXewM00000000000000000000yXnite", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.project.update_o_auth2_tik_tok() + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_update_o_auth2_tradeshift(self, m): data = { @@ -1154,6 +1197,24 @@ def test_update_o_auth2_twitch(self, m): response = self.project.update_o_auth2_twitch() self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_update_o_auth2_webflow(self, m): + data = { + "$id": "github", + "enabled": True, + "clientId": "8bb20000000000000000000000000000000000000000000000000000000040dd", + "clientSecret": "59bf00000000000000000000000000000000000000000000000000000000fe59", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.project.update_o_auth2_webflow() + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_update_o_auth2_word_press(self, m): data = { @@ -1233,6 +1294,7 @@ def test_update_o_auth2_zoho(self, m): "enabled": True, "clientId": "1000.83C178000000000000000000RPNX0B", "clientSecret": "fb5cac000000000000000000000000000000a68f6e", + "prompt": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -1269,6 +1331,7 @@ def test_get_o_auth2_provider(self, m): "enabled": True, "clientId": "e4d87900000000540733", "clientSecret": "5e07c00000000000000000000000000000198bcc", + "prompt": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -1307,6 +1370,7 @@ def test_create_android_platform(self, m): "name": "My Web App", "type": "web", "applicationId": "com.company.appname", + "fingerprints": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -1331,6 +1395,7 @@ def test_update_android_platform(self, m): "name": "My Web App", "type": "web", "applicationId": "com.company.appname", + "fingerprints": [], } headers = {'Content-Type': 'application/json'} m.request( @@ -1600,7 +1665,6 @@ def test_update_deny_aliased_email_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1643,7 +1707,6 @@ def test_update_deny_corporate_email_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1686,7 +1749,6 @@ def test_update_deny_disposable_email_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1729,7 +1791,6 @@ def test_update_deny_free_email_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1772,7 +1833,6 @@ def test_update_membership_privacy_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1813,7 +1873,6 @@ def test_update_mfa_factors_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1845,6 +1904,48 @@ def test_update_mfa_factors_policy(self, m): response = self.project.update_mfa_factors_policy() self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_update_passkey_policy(self, m): + data = { + "$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", + "smtpEnabled": True, + "smtpSenderName": "John Appwrite", + "smtpSenderEmail": "john@appwrite.io", + "smtpReplyToName": "Support Team", + "smtpReplyToEmail": "support@appwrite.io", + "smtpHost": "mail.appwrite.io", + "smtpPort": 25.0, + "smtpUsername": "emailuser", + "smtpPassword": "smtp-password", + "smtpSecure": "tls", + "pingCount": 1.0, + "pingedAt": "2020-10-15T06:38:00.000+00:00", + "labels": [], + "status": "active", + "onboarding": {}, + "authMethods": [], + "services": [], + "protocols": [], + "blocks": [], + "consoleAccessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.project.update_passkey_policy( + '<RP_ID>', + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_update_password_dictionary_policy(self, m): data = { @@ -1854,7 +1955,6 @@ def test_update_password_dictionary_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1897,7 +1997,6 @@ def test_update_password_history_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1940,7 +2039,6 @@ def test_update_password_personal_data_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -1974,6 +2072,86 @@ def test_update_password_personal_data_policy(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_update_password_pwned_policy(self, m): + data = { + "$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", + "smtpEnabled": True, + "smtpSenderName": "John Appwrite", + "smtpSenderEmail": "john@appwrite.io", + "smtpReplyToName": "Support Team", + "smtpReplyToEmail": "support@appwrite.io", + "smtpHost": "mail.appwrite.io", + "smtpPort": 25.0, + "smtpUsername": "emailuser", + "smtpPassword": "smtp-password", + "smtpSecure": "tls", + "pingCount": 1.0, + "pingedAt": "2020-10-15T06:38:00.000+00:00", + "labels": [], + "status": "active", + "onboarding": {}, + "authMethods": [], + "services": [], + "protocols": [], + "blocks": [], + "consoleAccessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.project.update_password_pwned_policy() + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_password_rotation_policy(self, m): + data = { + "$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", + "smtpEnabled": True, + "smtpSenderName": "John Appwrite", + "smtpSenderEmail": "john@appwrite.io", + "smtpReplyToName": "Support Team", + "smtpReplyToEmail": "support@appwrite.io", + "smtpHost": "mail.appwrite.io", + "smtpPort": 25.0, + "smtpUsername": "emailuser", + "smtpPassword": "smtp-password", + "smtpSecure": "tls", + "pingCount": 1.0, + "pingedAt": "2020-10-15T06:38:00.000+00:00", + "labels": [], + "status": "active", + "onboarding": {}, + "authMethods": [], + "services": [], + "protocols": [], + "blocks": [], + "consoleAccessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.project.update_password_rotation_policy() + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_update_password_strength_policy(self, m): data = { @@ -2003,7 +2181,6 @@ def test_update_session_alert_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -2046,7 +2223,6 @@ def test_update_session_duration_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -2089,7 +2265,6 @@ def test_update_session_invalidation_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -2132,7 +2307,6 @@ def test_update_session_limit_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -2175,7 +2349,6 @@ def test_update_user_limit_policy(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -2236,7 +2409,6 @@ def test_update_protocol(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -2280,7 +2452,6 @@ def test_update_service(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", @@ -2324,7 +2495,6 @@ def test_update_smtp(self, m): "name": "New Project", "teamId": "1592981250", "region": "fra", - "devKeys": [], "smtpEnabled": True, "smtpSenderName": "John Appwrite", "smtpSenderEmail": "john@appwrite.io", diff --git a/test/services/test_sites.py b/test/services/test_sites.py index f8271b9f..d7b7f32c 100644 --- a/test/services/test_sites.py +++ b/test/services/test_sites.py @@ -644,7 +644,7 @@ def test_get_log(self, m): "responseHeaders": [], "logs": "", "errors": "", - "duration": 0.4, + "duration": 1.23, } headers = {'Content-Type': 'application/json'} m.request( diff --git a/test/services/test_tables_db.py b/test/services/test_tables_db.py index 8c5cfa00..b2e71905 100644 --- a/test/services/test_tables_db.py +++ b/test/services/test_tables_db.py @@ -58,12 +58,6 @@ def test_list_specifications(self, m): data = { "specifications": [], "total": 9.0, - "pricing": { - "storageOverageRate": 0.125, - "bandwidthOverageRate": 0.08, - "replicaRate": 1, - "pitrRate": 0.2, - }, } headers = {'Content-Type': 'application/json'} m.request( @@ -259,16 +253,12 @@ def test_create_failover(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -278,6 +268,8 @@ def test_create_failover(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -291,7 +283,7 @@ def test_create_failover(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -498,10 +490,6 @@ def test_get_status(self, m): "engine": "postgresql", "version": "17", "uptime": 86400.0, - "connections": { - "current": 12.0, - "max": 100.0, - }, "syncMode": "async", "syncDegraded": True, "syncAcknowledgements": 1.0, @@ -1392,6 +1380,37 @@ def test_create_relationship_column(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_update_relationship_column(self, m): + data = { + "key": "fullName", + "type": "string", + "status": "available", + "error": "string", + "required": True, + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "relatedTable": "table", + "relationType": "oneToOne|oneToMany|manyToOne|manyToMany", + "twoWay": True, + "twoWayKey": "string", + "onDelete": "restrict|cascade|setNull", + "side": "parent|child", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.tables_db.update_relationship_column( + '<DATABASE_ID>', + '<TABLE_ID>', + '<KEY>', + ) + self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() def test_create_string_column(self, m): data = { @@ -1654,37 +1673,6 @@ def test_delete_column(self, m): ) self.assertEqual(response, data) - @requests_mock.Mocker() - def test_update_relationship_column(self, m): - data = { - "key": "fullName", - "type": "string", - "status": "available", - "error": "string", - "required": True, - "$createdAt": "2020-10-15T06:38:00.000+00:00", - "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "relatedTable": "table", - "relationType": "oneToOne|oneToMany|manyToOne|manyToMany", - "twoWay": True, - "twoWayKey": "string", - "onDelete": "restrict|cascade|setNull", - "side": "parent|child", - } - headers = {'Content-Type': 'application/json'} - m.request( - requests_mock.ANY, - requests_mock.ANY, - text=json.dumps(data), - headers=headers, - ) - response = self.tables_db.update_relationship_column( - '<DATABASE_ID>', - '<TABLE_ID>', - '<KEY>', - ) - self.assertEqual(response.to_dict(), data) - @requests_mock.Mocker() def test_list_indexes(self, m): data = { diff --git a/test/services/test_users.py b/test/services/test_users.py index 22288922..4dad6e4c 100644 --- a/test/services/test_users.py +++ b/test/services/test_users.py @@ -502,24 +502,6 @@ def test_update_labels(self, m): ) self.assertEqual(response.to_dict(), data) - @requests_mock.Mocker() - def test_list_logs(self, m): - data = { - "total": 5.0, - "logs": [], - } - headers = {'Content-Type': 'application/json'} - m.request( - requests_mock.ANY, - requests_mock.ANY, - text=json.dumps(data), - headers=headers, - ) - response = self.users.list_logs( - '<USER_ID>', - ) - self.assertEqual(response.to_dict(), data) - @requests_mock.Mocker() def test_list_memberships(self, m): data = { @@ -835,6 +817,85 @@ def test_update_name(self, m): ) self.assertEqual(response.to_dict(), data) + @requests_mock.Mocker() + def test_list_passkeys(self, m): + data = { + "total": 5.0, + "passkeys": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.users.list_passkeys( + '<USER_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_passkey(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "My laptop", + "accessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.users.get_passkey( + '<USER_ID>', + '<PASSKEY_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_passkey(self, m): + data = { + "$id": "5e5ea5c16897e", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "My laptop", + "accessedAt": "2020-10-15T06:38:00.000+00:00", + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.users.update_passkey( + '<USER_ID>', + '<PASSKEY_ID>', + '<NAME>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_delete_passkey(self, m): + data = '' + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.users.delete_passkey( + '<USER_ID>', + '<PASSKEY_ID>', + ) + self.assertEqual(response, data) + @requests_mock.Mocker() def test_update_password(self, m): data = { diff --git a/test/services/test_vectors_db.py b/test/services/test_vectors_db.py index 17cc1f84..5ed5c005 100644 --- a/test/services/test_vectors_db.py +++ b/test/services/test_vectors_db.py @@ -58,12 +58,6 @@ def test_list_specifications(self, m): data = { "specifications": [], "total": 9.0, - "pricing": { - "storageOverageRate": 0.125, - "bandwidthOverageRate": 0.08, - "replicaRate": 1, - "pitrRate": 0.2, - }, } headers = {'Content-Type': 'application/json'} m.request( @@ -717,16 +711,12 @@ def test_create_failover(self, m): "$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.0, "connectionUser": "appwrite_user", "connectionPassword": "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", - "credentialGeneration": 1.0, "connectionString": "postgresql:\/\/user:pass@db-myproject-mydb.fra.appwrite.center:5432\/postgres?sslmode=require", "ssl": True, "status": "ready", @@ -736,6 +726,8 @@ def test_create_failover(self, m): "cpu": 2000.0, "memory": 4096.0, "storage": 100.0, + "storageStatus": "resizing", + "storageTargetGb": 120.0, "storageClass": "ssd", "storageMaxGb": 100.0, "nodePool": "db-pool-4vcpu-8gb", @@ -749,7 +741,7 @@ def test_create_failover(self, m): "pitrRetentionDays": 14.0, "storageAutoscaling": True, "storageAutoscalingThresholdPercent": 85.0, - "storageAutoscalingMaxGb": 500.0, + "storageAutoscalingMaxGb": 30.0, "maintenanceWindowDay": "sun", "maintenanceWindowHourUtc": 3.0, "metricsEnabled": True, @@ -820,10 +812,6 @@ def test_get_status(self, m): "engine": "postgresql", "version": "17", "uptime": 86400.0, - "connections": { - "current": 12.0, - "max": 100.0, - }, "syncMode": "async", "syncDegraded": True, "syncAcknowledgements": 1.0, diff --git a/test/services/test_waf.py b/test/services/test_waf.py new file mode 100644 index 00000000..8c9e8bec --- /dev/null +++ b/test/services/test_waf.py @@ -0,0 +1,410 @@ +import json +import requests_mock +import unittest + +from appwrite.client import Client +from appwrite.input_file import InputFile +from appwrite.models import * +from appwrite.services.waf import Waf + + +class WafServiceTest(unittest.TestCase): + + def setUp(self): + self.client = Client() + self.waf = Waf(self.client) + + @requests_mock.Mocker() + def test_list_rules(self, m): + data = { + "total": 5.0, + "rules": [], + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.list_rules() + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_bypass_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.create_bypass_rule( + '<RULE_ID>', + 'api', + '<NAME>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_bypass_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.update_bypass_rule( + '<RULE_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_challenge_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + "challengeType": "compute", + "difficulty": 3.0, + "ttl": 1800.0, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.create_challenge_rule( + '<RULE_ID>', + 'api', + '<NAME>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_challenge_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + "challengeType": "compute", + "difficulty": 3.0, + "ttl": 1800.0, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.update_challenge_rule( + '<RULE_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_deny_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.create_deny_rule( + '<RULE_ID>', + 'api', + '<NAME>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_deny_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.update_deny_rule( + '<RULE_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_rate_limit_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + "limit": 1000.0, + "interval": 60.0, + "key": "userId", + "strategy": "slidingWindow", + "maxBucketSize": 200.0, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.create_rate_limit_rule( + '<RULE_ID>', + 'api', + '<NAME>', + 1, + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_rate_limit_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + "limit": 1000.0, + "interval": 60.0, + "key": "userId", + "strategy": "slidingWindow", + "maxBucketSize": 200.0, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.update_rate_limit_rule( + '<RULE_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_create_redirect_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + "location": "\/maintenance", + "statusCode": 301.0, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.create_redirect_rule( + '<RULE_ID>', + 'api', + '<NAME>', + '<LOCATION>', + 1, + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_update_redirect_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + "location": "\/maintenance", + "statusCode": 301.0, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.update_redirect_rule( + '<RULE_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_get_rule(self, m): + data = { + "$id": "wafRule1", + "$createdAt": "2020-10-15T06:38:00.000+00:00", + "$updatedAt": "2020-10-15T06:38:00.000+00:00", + "name": "Block anonymous POST traffic", + "description": "Blocks anonymous POST calls to \/v1\/graphql", + "teamId": "5e5ea5c16897e", + "projectId": "cloudConsole", + "resourceType": "functions", + "resourceId": "functionId", + "action": "deny", + "priority": 100.0, + "enabled": True, + "conditions": [], + "config": {}, + } + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.get_rule( + '<RULE_ID>', + ) + self.assertEqual(response.to_dict(), data) + + @requests_mock.Mocker() + def test_delete_rule(self, m): + data = '' + headers = {'Content-Type': 'application/json'} + m.request( + requests_mock.ANY, + requests_mock.ANY, + text=json.dumps(data), + headers=headers, + ) + response = self.waf.delete_rule( + '<RULE_ID>', + ) + self.assertEqual(response, data) diff --git a/test/test_topic.py b/test/test_topic.py new file mode 100644 index 00000000..1fbe256a --- /dev/null +++ b/test/test_topic.py @@ -0,0 +1,45 @@ +import unittest + +from appwrite.topic import ResolvedTopic, Topic + + +class TestTopicMethods(unittest.TestCase): + + def test_path(self): + self.assertEqual(str(Topic.path(['user'])), 'user') + self.assertEqual(str(Topic.path(['user', 'notification'])), 'user/notification') + self.assertEqual(str(Topic.path(['user']).path(['notification'])), 'user/notification') + + def test_any(self): + self.assertEqual(str(Topic.path(['user']).any().path(['notification'])), 'user/+/notification') + self.assertEqual(str(Topic.path(['chat']).any().any().path(['message'])), 'chat/+/+/message') + self.assertEqual(str(Topic.any().path(['notification'])), '+/notification') + + def test_all(self): + self.assertEqual(str(Topic.path(['org']).any().path(['logs']).all()), 'org/+/logs/#') + self.assertEqual(str(Topic.all()), '#') + self.assertIsInstance(Topic.all(), ResolvedTopic) + + def test_nothing_after_all(self): + with self.assertRaises(TypeError): + Topic.all().any() + + def test_errors(self): + cases = [ + ('user', TypeError), + ([], ValueError), + (['user', 42], TypeError), + (['user', None], TypeError), + (['user', ''], ValueError), + (['user/123'], ValueError), + (['user', '+'], ValueError), + (['user', 'a+b'], ValueError), + (['user', '#'], ValueError), + (['user', 'a#b'], ValueError), + ] + for levels, error in cases: + with self.subTest(levels=levels): + with self.assertRaises(error): + Topic.path(levels) + with self.assertRaises(error): + Topic.any().path(levels)