diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aa800b..f94f3fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.8.0] - TBD +## [0.9.0] - TBD ### Added - Initial release of Appwrite Rust SDK @@ -29,12 +29,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Databases service with 71 methods - Functions service with 26 methods - Graphql service with 2 methods -- Health service with 24 methods +- Health service with 25 methods - Locale service with 8 methods -- Messaging service with 56 methods +- Messaging service with 58 methods - Organization service with 10 methods - Presences service with 5 methods -- Project service with 98 methods +- Project service with 100 methods - Proxy service with 8 methods - Advisor service with 5 methods - Sites service with 25 methods @@ -334,6 +334,8 @@ The GraphQL API allows you to query and mutate your Appwrite server using GraphQ The Health service allows you to both validate and monitor your Appwrite server's health. - `get()` - Check the Appwrite HTTP server is up and responsive. - `get_antivirus()` - Check the Appwrite Antivirus server is up and connection is successful. +- `get_audits_db()` - Check the database that backs the audit and activity store. When the connection is reachable the endpoint returns a passing status with its response time. + - `get_cache()` - Check the Appwrite in-memory cache servers are up and connection is successful. - `get_certificate()` - Get the SSL certificate for a domain - `get_console_pausing()` - Get console pausing health status. Monitors projects approaching the pause threshold to detect potential issues with console access tracking. @@ -410,6 +412,8 @@ The Messaging service allows you to send messages to any provider type (SMTP, pu - `update_resend_provider()` - Update a Resend provider by its unique ID. - `create_sendgrid_provider()` - Create a new Sendgrid provider. - `update_sendgrid_provider()` - Update a Sendgrid provider by its unique ID. +- `create_ses_provider()` - Create a new Amazon SES provider. +- `update_ses_provider()` - Update an Amazon SES provider by its unique ID. - `create_smtp_provider()` - Create a new SMTP provider. - `create_smtp_provider()` - Create a new SMTP provider. - `update_smtp_provider()` - Update a SMTP provider by its unique ID. @@ -489,6 +493,7 @@ You can also create a standard API key if you need a longer-lived key instead. - `update_mock_phone()` - Update a mock phone by its unique number. Use this endpoint to update the mock phone's OTP. - `delete_mock_phone()` - Delete a mock phone by its unique number. This endpoint removes the mock phone and its OTP configuration from the project. - `list_o_auth2_providers()` - Get a list of all OAuth2 providers supported by the server, along with the project's configuration for each. Credential fields are write-only and always returned empty. +- `update_o_auth2_server()` - Update the OAuth2 server (OIDC provider) configuration. - `update_o_auth2_amazon()` - Update the project OAuth2 Amazon configuration. - `update_o_auth2_apple()` - Update the project OAuth2 Apple configuration. - `update_o_auth2_auth0()` - Update the project OAuth2 Auth0 configuration. @@ -555,6 +560,7 @@ You can also create a standard API key if you need a longer-lived key instead. Keep in mind, while password history policy is disabled, the history is not being stored. Enabling the policy will not have any history on existing users, and it will only start to collect and enforce the policy on password changes since the policy is enabled. - `update_password_personal_data_policy()` - Updating this policy allows you to control if password strength is checked against personal data. When enabled, and user sets or changes their password, the password must not contain user ID, name, email or phone number. +- `update_password_strength_policy()` - Update the password strength requirements for users in the project. - `update_session_alert_policy()` - Updating this policy allows you to control if email alert is sent upon session creation. When enabled, and user signs into their account, they will be sent an email notification. There is an exception, the first session after a new sign up does not trigger an alert, even if the policy is enabled. - `update_session_duration_policy()` - Update maximum duration how long sessions created within a project should stay active for. - `update_session_invalidation_policy()` - Updating this policy allows you to control if existing sessions should be invalidated when a password of a user is changed. When enabled, and user changes their password, they will be logged out of all their devices. @@ -1046,6 +1052,7 @@ If you want to generate a token for a custom authentication flow, use the [POST - `OAuth2ProviderList` - OAuth2 Providers List - `PolicyPasswordDictionary` - Policy Password Dictionary - `PolicyPasswordHistory` - Policy Password History +- `PolicyPasswordStrength` - Policy Password Strength - `PolicyPasswordPersonalData` - Policy Password Personal Data - `PolicySessionAlert` - Policy Session Alert - `PolicySessionDuration` - Policy Session Duration @@ -1119,4 +1126,4 @@ If you want to generate a token for a custom authentication flow, use the [POST - File upload examples - Query builder documentation -[0.8.0]: https://github.com/appwrite/sdk-for-rust/releases/tag/0.8.0 +[0.9.0]: https://github.com/appwrite/sdk-for-rust/releases/tag/0.9.0 diff --git a/Cargo.toml b/Cargo.toml index 7aab120..05e1ddc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "appwrite" -version = "0.8.0" +version = "0.9.0" edition = "2021" rust-version = "1.83" authors = ["appwrite"] diff --git a/README.md b/README.md index a734535..e2c4e17 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -appwrite = "0.8.0" +appwrite = "0.9.0" tokio = { version = "1.48", features = ["full"] } ``` diff --git a/docs/examples/account/update-password.md b/docs/examples/account/update-password.md index c6c4d5c..d42b4bc 100644 --- a/docs/examples/account/update-password.md +++ b/docs/examples/account/update-password.md @@ -13,7 +13,7 @@ async fn main() -> Result<(), Box> { let result = account.update_password( "", - Some("password") // optional + Some("") // optional ).await?; let _ = result; diff --git a/docs/examples/health/get-audits-db.md b/docs/examples/health/get-audits-db.md new file mode 100644 index 0000000..a83d6aa --- /dev/null +++ b/docs/examples/health/get-audits-db.md @@ -0,0 +1,20 @@ +```rust +use appwrite::Client; +use appwrite::services::Health; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new(); + client.set_endpoint("https://.cloud.appwrite.io/v1"); // Your API Endpoint + client.set_project(""); // Your project ID + client.set_key(""); // Your secret API key + + let health = Health::new(&client); + + let result = health.get_audits_db().await?; + + let _ = result; + + Ok(()) +} +``` diff --git a/docs/examples/messaging/create-ses-provider.md b/docs/examples/messaging/create-ses-provider.md new file mode 100644 index 0000000..f5d8344 --- /dev/null +++ b/docs/examples/messaging/create-ses-provider.md @@ -0,0 +1,31 @@ +```rust +use appwrite::Client; +use appwrite::services::Messaging; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new(); + client.set_endpoint("https://.cloud.appwrite.io/v1"); // Your API Endpoint + client.set_project(""); // Your project ID + client.set_key(""); // Your secret API key + + let messaging = Messaging::new(&client); + + let result = messaging.create_ses_provider( + "", + "", + Some(""), // optional + Some(""), // optional + Some(""), // optional + Some(""), // optional + Some("email@example.com"), // optional + Some(""), // optional + Some("email@example.com"), // optional + Some(false) // optional + ).await?; + + let _ = result; + + Ok(()) +} +``` diff --git a/docs/examples/messaging/update-ses-provider.md b/docs/examples/messaging/update-ses-provider.md new file mode 100644 index 0000000..c7b44d0 --- /dev/null +++ b/docs/examples/messaging/update-ses-provider.md @@ -0,0 +1,31 @@ +```rust +use appwrite::Client; +use appwrite::services::Messaging; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new(); + client.set_endpoint("https://.cloud.appwrite.io/v1"); // Your API Endpoint + client.set_project(""); // Your project ID + client.set_key(""); // Your secret API key + + let messaging = Messaging::new(&client); + + let result = messaging.update_ses_provider( + "", + Some(""), // optional + Some(false), // optional + Some(""), // optional + Some(""), // optional + Some(""), // optional + Some(""), // optional + Some("email@example.com"), // optional + Some(""), // optional + Some("") // optional + ).await?; + + let _ = result; + + Ok(()) +} +``` diff --git a/docs/examples/project/update-o-auth-2-server.md b/docs/examples/project/update-o-auth-2-server.md new file mode 100644 index 0000000..3bc49b0 --- /dev/null +++ b/docs/examples/project/update-o-auth-2-server.md @@ -0,0 +1,29 @@ +```rust +use appwrite::Client; +use appwrite::services::Project; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new(); + client.set_endpoint("https://.cloud.appwrite.io/v1"); // Your API Endpoint + client.set_project(""); // Your project ID + client.set_key(""); // Your secret API key + + let project = Project::new(&client); + + let result = project.update_o_auth2_server( + false, + "https://example.com", + Some(vec![]), // optional + Some(60), // optional + Some(60), // optional + Some(60), // optional + Some(60), // optional + Some(false) // optional + ).await?; + + let _ = result; + + Ok(()) +} +``` diff --git a/docs/examples/project/update-password-strength-policy.md b/docs/examples/project/update-password-strength-policy.md new file mode 100644 index 0000000..dc1b128 --- /dev/null +++ b/docs/examples/project/update-password-strength-policy.md @@ -0,0 +1,26 @@ +```rust +use appwrite::Client; +use appwrite::services::Project; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new(); + client.set_endpoint("https://.cloud.appwrite.io/v1"); // Your API Endpoint + client.set_project(""); // Your project ID + client.set_key(""); // Your secret API key + + let project = Project::new(&client); + + let result = project.update_password_strength_policy( + Some(8), // optional + Some(false), // optional + Some(false), // optional + Some(false), // optional + Some(false) // optional + ).await?; + + let _ = result; + + Ok(()) +} +``` diff --git a/src/client.rs b/src/client.rs index 77eaf5a..85a248e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -92,11 +92,11 @@ impl Client { pub fn new() -> Self { let mut headers = HeaderMap::new(); headers.insert("X-Appwrite-Response-Format", "1.9.5".parse().unwrap()); - headers.insert("user-agent", format!("AppwriteRustSDK/0.8.0 ({}; {})", std::env::consts::OS, std::env::consts::ARCH).parse().unwrap()); + headers.insert("user-agent", format!("AppwriteRustSDK/0.9.0 ({}; {})", std::env::consts::OS, std::env::consts::ARCH).parse().unwrap()); headers.insert("x-sdk-name", "Rust".parse().unwrap()); headers.insert("x-sdk-platform", "server".parse().unwrap()); headers.insert("x-sdk-language", "rust".parse().unwrap()); - headers.insert("x-sdk-version", "0.8.0".parse().unwrap()); + headers.insert("x-sdk-version", "0.9.0".parse().unwrap()); let config = Config { endpoint: "https://cloud.appwrite.io/v1".to_string(), diff --git a/src/enums/project_key_scopes.rs b/src/enums/project_key_scopes.rs index 2720842..5b4de75 100644 --- a/src/enums/project_key_scopes.rs +++ b/src/enums/project_key_scopes.rs @@ -189,6 +189,10 @@ pub enum ProjectKeyScopes { DomainsWrite, #[serde(rename = "events.read")] EventsRead, + #[serde(rename = "apps.read")] + AppsRead, + #[serde(rename = "apps.write")] + AppsWrite, #[serde(rename = "usage.read")] UsageRead, } @@ -290,6 +294,8 @@ impl ProjectKeyScopes { ProjectKeyScopes::DomainsRead => "domains.read", ProjectKeyScopes::DomainsWrite => "domains.write", ProjectKeyScopes::EventsRead => "events.read", + ProjectKeyScopes::AppsRead => "apps.read", + ProjectKeyScopes::AppsWrite => "apps.write", ProjectKeyScopes::UsageRead => "usage.read", } } diff --git a/src/enums/project_policy_id.rs b/src/enums/project_policy_id.rs index 47ad570..10079e0 100644 --- a/src/enums/project_policy_id.rs +++ b/src/enums/project_policy_id.rs @@ -7,6 +7,8 @@ pub enum ProjectPolicyId { PasswordDictionary, #[serde(rename = "password-history")] PasswordHistory, + #[serde(rename = "password-strength")] + PasswordStrength, #[serde(rename = "password-personal-data")] PasswordPersonalData, #[serde(rename = "session-alert")] @@ -35,6 +37,7 @@ impl ProjectPolicyId { match self { ProjectPolicyId::PasswordDictionary => "password-dictionary", ProjectPolicyId::PasswordHistory => "password-history", + ProjectPolicyId::PasswordStrength => "password-strength", ProjectPolicyId::PasswordPersonalData => "password-personal-data", ProjectPolicyId::SessionAlert => "session-alert", ProjectPolicyId::SessionDuration => "session-duration", diff --git a/src/lib.rs b/src/lib.rs index 79181e4..695053a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ //! //! ```toml //! [dependencies] -//! appwrite = "0.8.0" +//! appwrite = "0.9.0" //! ``` //! //! ## Usage @@ -51,7 +51,7 @@ pub use input_file::InputFile; pub type Result = std::result::Result; /// SDK version -pub const VERSION: &str = "0.8.0"; +pub const VERSION: &str = "0.9.0"; /// SDK name pub const SDK_NAME: &str = "Rust"; diff --git a/src/models/mod.rs b/src/models/mod.rs index 7f3e408..6cf848b 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -346,6 +346,8 @@ pub mod policy_password_dictionary; pub use policy_password_dictionary::PolicyPasswordDictionary; pub mod policy_password_history; pub use policy_password_history::PolicyPasswordHistory; +pub mod policy_password_strength; +pub use policy_password_strength::PolicyPasswordStrength; pub mod policy_password_personal_data; pub use policy_password_personal_data::PolicyPasswordPersonalData; pub mod policy_session_alert; @@ -643,6 +645,7 @@ impl Model for OAuth2Microsoft {} impl Model for OAuth2ProviderList {} impl Model for PolicyPasswordDictionary {} impl Model for PolicyPasswordHistory {} +impl Model for PolicyPasswordStrength {} impl Model for PolicyPasswordPersonalData {} impl Model for PolicySessionAlert {} impl Model for PolicySessionDuration {} diff --git a/src/models/policy_password_strength.rs b/src/models/policy_password_strength.rs new file mode 100644 index 0000000..bbdb10b --- /dev/null +++ b/src/models/policy_password_strength.rs @@ -0,0 +1,86 @@ +//! PolicyPasswordStrength model for Appwrite SDK + +use serde::{Deserialize, Serialize}; + +/// Policy Password Strength +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(test, derive(Default))] +pub struct PolicyPasswordStrength { + /// Policy ID. + #[serde(rename = "$id")] + pub id: String, + /// Minimum password length required for user passwords. + #[serde(rename = "min")] + pub min: i64, + /// Whether passwords must include at least one uppercase letter. + #[serde(rename = "uppercase")] + pub uppercase: bool, + /// Whether passwords must include at least one lowercase letter. + #[serde(rename = "lowercase")] + pub lowercase: bool, + /// Whether passwords must include at least one number. + #[serde(rename = "number")] + pub number: bool, + /// Whether passwords must include at least one symbol. + #[serde(rename = "symbols")] + pub symbols: bool, +} + +impl PolicyPasswordStrength { + /// Get id + pub fn id(&self) -> &String { + &self.id + } + + /// Get min + pub fn min(&self) -> &i64 { + &self.min + } + + /// Get uppercase + pub fn uppercase(&self) -> &bool { + &self.uppercase + } + + /// Get lowercase + pub fn lowercase(&self) -> &bool { + &self.lowercase + } + + /// Get number + pub fn number(&self) -> &bool { + &self.number + } + + /// Get symbols + pub fn symbols(&self) -> &bool { + &self.symbols + } + +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_policy_password_strength_creation() { + let _model = ::default(); + let _ = _model.id(); + let _ = _model.min(); + let _ = _model.uppercase(); + let _ = _model.lowercase(); + let _ = _model.number(); + let _ = _model.symbols(); + } + + #[test] + fn test_policy_password_strength_serialization() { + let model = ::default(); + let json = serde_json::to_string(&model); + assert!(json.is_ok()); + + let deserialized: Result = serde_json::from_str(&json.unwrap()); + assert!(deserialized.is_ok()); + } +} diff --git a/src/models/project.rs b/src/models/project.rs index 88ad1a5..72f36c4 100644 --- a/src/models/project.rs +++ b/src/models/project.rs @@ -21,6 +21,9 @@ pub struct Project { /// Project team ID. #[serde(rename = "teamId")] pub team_id: String, + /// Project region + #[serde(rename = "region")] + pub region: String, /// Deprecated since 1.9.5: List of dev keys. #[serde(rename = "devKeys")] pub dev_keys: Vec, @@ -76,13 +79,6 @@ pub struct Project { /// List of protocols. #[serde(rename = "protocols")] pub protocols: Vec, - /// Project region - #[serde(rename = "region")] - pub region: String, - /// Billing limits reached - #[serde(rename = "billingLimits")] - #[serde(skip_serializing_if = "Option::is_none")] - pub billing_limits: Option, /// Project blocks information #[serde(rename = "blocks")] pub blocks: Vec, @@ -90,6 +86,41 @@ pub struct Project { /// projectInactivityDays to determine if project is paused. #[serde(rename = "consoleAccessedAt")] pub console_accessed_at: String, + /// Billing limits reached + #[serde(rename = "billingLimits")] + #[serde(skip_serializing_if = "Option::is_none")] + pub billing_limits: Option, + /// OAuth2 server status + #[serde(rename = "oAuth2ServerEnabled")] + pub o_auth2_server_enabled: bool, + /// OAuth2 server authorization URL + #[serde(rename = "oAuth2ServerAuthorizationUrl")] + pub o_auth2_server_authorization_url: String, + /// OAuth2 server allowed scopes + #[serde(rename = "oAuth2ServerScopes")] + pub o_auth2_server_scopes: Vec, + /// OAuth2 server access token duration in seconds for confidential clients + #[serde(rename = "oAuth2ServerAccessTokenDuration")] + pub o_auth2_server_access_token_duration: i64, + /// OAuth2 server refresh token duration in seconds for confidential clients + #[serde(rename = "oAuth2ServerRefreshTokenDuration")] + pub o_auth2_server_refresh_token_duration: i64, + /// OAuth2 server access token duration in seconds for public clients (SPAs, + /// mobile, native) + #[serde(rename = "oAuth2ServerPublicAccessTokenDuration")] + pub o_auth2_server_public_access_token_duration: i64, + /// OAuth2 server refresh token duration in seconds for public clients (SPAs, + /// mobile, native) + #[serde(rename = "oAuth2ServerPublicRefreshTokenDuration")] + pub o_auth2_server_public_refresh_token_duration: i64, + /// When enabled, PKCE is required for confidential clients (server-side flows + /// using client_secret). PKCE is always required for public clients regardless + /// of this setting. + #[serde(rename = "oAuth2ServerConfidentialPkce")] + pub o_auth2_server_confidential_pkce: bool, + /// OAuth2 server discovery URL + #[serde(rename = "oAuth2ServerDiscoveryUrl")] + pub o_auth2_server_discovery_url: String, } impl Project { @@ -118,6 +149,11 @@ impl Project { &self.team_id } + /// Get region + pub fn region(&self) -> &String { + &self.region + } + /// Get dev_keys pub fn dev_keys(&self) -> &Vec { &self.dev_keys @@ -208,9 +244,14 @@ impl Project { &self.protocols } - /// Get region - pub fn region(&self) -> &String { - &self.region + /// Get blocks + pub fn blocks(&self) -> &Vec { + &self.blocks + } + + /// Get console_accessed_at + pub fn console_accessed_at(&self) -> &String { + &self.console_accessed_at } /// Set billing_limits @@ -224,14 +265,49 @@ impl Project { self.billing_limits.as_ref() } - /// Get blocks - pub fn blocks(&self) -> &Vec { - &self.blocks + /// Get o_auth2_server_enabled + pub fn o_auth2_server_enabled(&self) -> &bool { + &self.o_auth2_server_enabled } - /// Get console_accessed_at - pub fn console_accessed_at(&self) -> &String { - &self.console_accessed_at + /// Get o_auth2_server_authorization_url + pub fn o_auth2_server_authorization_url(&self) -> &String { + &self.o_auth2_server_authorization_url + } + + /// Get o_auth2_server_scopes + pub fn o_auth2_server_scopes(&self) -> &Vec { + &self.o_auth2_server_scopes + } + + /// Get o_auth2_server_access_token_duration + pub fn o_auth2_server_access_token_duration(&self) -> &i64 { + &self.o_auth2_server_access_token_duration + } + + /// Get o_auth2_server_refresh_token_duration + pub fn o_auth2_server_refresh_token_duration(&self) -> &i64 { + &self.o_auth2_server_refresh_token_duration + } + + /// Get o_auth2_server_public_access_token_duration + pub fn o_auth2_server_public_access_token_duration(&self) -> &i64 { + &self.o_auth2_server_public_access_token_duration + } + + /// Get o_auth2_server_public_refresh_token_duration + pub fn o_auth2_server_public_refresh_token_duration(&self) -> &i64 { + &self.o_auth2_server_public_refresh_token_duration + } + + /// Get o_auth2_server_confidential_pkce + pub fn o_auth2_server_confidential_pkce(&self) -> &bool { + &self.o_auth2_server_confidential_pkce + } + + /// Get o_auth2_server_discovery_url + pub fn o_auth2_server_discovery_url(&self) -> &String { + &self.o_auth2_server_discovery_url } } @@ -248,6 +324,7 @@ mod tests { let _ = _model.updated_at(); let _ = _model.name(); let _ = _model.team_id(); + let _ = _model.region(); let _ = _model.dev_keys(); let _ = _model.smtp_enabled(); let _ = _model.smtp_sender_name(); @@ -266,9 +343,17 @@ mod tests { let _ = _model.auth_methods(); let _ = _model.services(); let _ = _model.protocols(); - let _ = _model.region(); let _ = _model.blocks(); let _ = _model.console_accessed_at(); + let _ = _model.o_auth2_server_enabled(); + let _ = _model.o_auth2_server_authorization_url(); + let _ = _model.o_auth2_server_scopes(); + let _ = _model.o_auth2_server_access_token_duration(); + let _ = _model.o_auth2_server_refresh_token_duration(); + let _ = _model.o_auth2_server_public_access_token_duration(); + let _ = _model.o_auth2_server_public_refresh_token_duration(); + let _ = _model.o_auth2_server_confidential_pkce(); + let _ = _model.o_auth2_server_discovery_url(); } #[test] diff --git a/src/services/health.rs b/src/services/health.rs index 1d8b590..87ea2f6 100644 --- a/src/services/health.rs +++ b/src/services/health.rs @@ -44,6 +44,19 @@ impl Health { self.client.call(Method::GET, &path, None, Some(params)).await } + /// Check the database that backs the audit and activity store. When the + /// connection is reachable the endpoint returns a passing status with its + /// response time. + pub async fn get_audits_db( + &self, + ) -> crate::error::Result { + let params = HashMap::new(); + + let path = "/health/audits-db".to_string(); + + self.client.call(Method::GET, &path, None, Some(params)).await + } + /// Check the Appwrite in-memory cache servers are up and connection is /// successful. pub async fn get_cache( diff --git a/src/services/messaging.rs b/src/services/messaging.rs index b59ad60..6c297d7 100644 --- a/src/services/messaging.rs +++ b/src/services/messaging.rs @@ -982,6 +982,107 @@ impl Messaging { self.client.call(Method::PATCH, &path, Some(api_headers), Some(params)).await } + /// Create a new Amazon SES provider. + #[allow(clippy::too_many_arguments)] + pub async fn create_ses_provider( + &self, + provider_id: impl Into, + name: impl Into, + access_key: Option<&str>, + secret_key: Option<&str>, + region: Option<&str>, + from_name: Option<&str>, + from_email: Option<&str>, + reply_to_name: Option<&str>, + reply_to_email: Option<&str>, + enabled: Option, + ) -> crate::error::Result { + let mut params = HashMap::new(); + params.insert("providerId".to_string(), json!(provider_id.into())); + params.insert("name".to_string(), json!(name.into())); + if let Some(value) = access_key { + params.insert("accessKey".to_string(), json!(value)); + } + if let Some(value) = secret_key { + params.insert("secretKey".to_string(), json!(value)); + } + if let Some(value) = region { + params.insert("region".to_string(), json!(value)); + } + if let Some(value) = from_name { + params.insert("fromName".to_string(), json!(value)); + } + if let Some(value) = from_email { + params.insert("fromEmail".to_string(), json!(value)); + } + if let Some(value) = reply_to_name { + params.insert("replyToName".to_string(), json!(value)); + } + if let Some(value) = reply_to_email { + params.insert("replyToEmail".to_string(), json!(value)); + } + if let Some(value) = enabled { + params.insert("enabled".to_string(), json!(value)); + } + let mut api_headers = HashMap::new(); + api_headers.insert("content-type".to_string(), "application/json".to_string()); + + let path = "/messaging/providers/ses".to_string(); + + self.client.call(Method::POST, &path, Some(api_headers), Some(params)).await + } + + /// Update an Amazon SES provider by its unique ID. + #[allow(clippy::too_many_arguments)] + pub async fn update_ses_provider( + &self, + provider_id: impl Into, + name: Option<&str>, + enabled: Option, + access_key: Option<&str>, + secret_key: Option<&str>, + region: Option<&str>, + from_name: Option<&str>, + from_email: Option<&str>, + reply_to_name: Option<&str>, + reply_to_email: Option<&str>, + ) -> crate::error::Result { + let mut params = HashMap::new(); + if let Some(value) = name { + params.insert("name".to_string(), json!(value)); + } + if let Some(value) = enabled { + params.insert("enabled".to_string(), json!(value)); + } + if let Some(value) = access_key { + params.insert("accessKey".to_string(), json!(value)); + } + if let Some(value) = secret_key { + params.insert("secretKey".to_string(), json!(value)); + } + if let Some(value) = region { + params.insert("region".to_string(), json!(value)); + } + if let Some(value) = from_name { + params.insert("fromName".to_string(), json!(value)); + } + if let Some(value) = from_email { + params.insert("fromEmail".to_string(), json!(value)); + } + if let Some(value) = reply_to_name { + params.insert("replyToName".to_string(), json!(value)); + } + if let Some(value) = reply_to_email { + params.insert("replyToEmail".to_string(), json!(value)); + } + let mut api_headers = HashMap::new(); + api_headers.insert("content-type".to_string(), "application/json".to_string()); + + let path = "/messaging/providers/ses/{providerId}".to_string().replace("{providerId}", &provider_id.into().to_string()); + + self.client.call(Method::PATCH, &path, Some(api_headers), Some(params)).await + } + /// Create a new SMTP provider. #[allow(clippy::too_many_arguments)] pub async fn create_smtp_provider( diff --git a/src/services/project.rs b/src/services/project.rs index 193f7c3..fa95c98 100644 --- a/src/services/project.rs +++ b/src/services/project.rs @@ -300,6 +300,48 @@ impl Project { self.client.call(Method::GET, &path, None, Some(params)).await } + /// Update the OAuth2 server (OIDC provider) configuration. + #[allow(clippy::too_many_arguments)] + pub async fn update_o_auth2_server( + &self, + enabled: bool, + authorization_url: impl Into, + scopes: Option>, + access_token_duration: Option, + refresh_token_duration: Option, + public_access_token_duration: Option, + public_refresh_token_duration: Option, + confidential_pkce: Option, + ) -> crate::error::Result { + let mut params = HashMap::new(); + params.insert("enabled".to_string(), json!(enabled)); + params.insert("authorizationUrl".to_string(), json!(authorization_url.into())); + if let Some(value) = scopes { + params.insert("scopes".to_string(), json!(value.into_iter().map(|s| s.into()).collect::>())); + } + if let Some(value) = access_token_duration { + params.insert("accessTokenDuration".to_string(), json!(value)); + } + if let Some(value) = refresh_token_duration { + params.insert("refreshTokenDuration".to_string(), json!(value)); + } + if let Some(value) = public_access_token_duration { + params.insert("publicAccessTokenDuration".to_string(), json!(value)); + } + if let Some(value) = public_refresh_token_duration { + params.insert("publicRefreshTokenDuration".to_string(), json!(value)); + } + if let Some(value) = confidential_pkce { + params.insert("confidentialPkce".to_string(), json!(value)); + } + let mut api_headers = HashMap::new(); + api_headers.insert("content-type".to_string(), "application/json".to_string()); + + let path = "/project/oauth2-server".to_string(); + + self.client.call(Method::PUT, &path, Some(api_headers), Some(params)).await + } + /// Update the project OAuth2 Amazon configuration. pub async fn update_o_auth2_amazon( &self, @@ -1838,6 +1880,39 @@ impl Project { self.client.call(Method::PATCH, &path, Some(api_headers), Some(params)).await } + /// Update the password strength requirements for users in the project. + pub async fn update_password_strength_policy( + &self, + min: Option, + uppercase: Option, + lowercase: Option, + number: Option, + symbols: Option, + ) -> crate::error::Result { + let mut params = HashMap::new(); + if let Some(value) = min { + params.insert("min".to_string(), json!(value)); + } + if let Some(value) = uppercase { + params.insert("uppercase".to_string(), json!(value)); + } + if let Some(value) = lowercase { + params.insert("lowercase".to_string(), json!(value)); + } + if let Some(value) = number { + params.insert("number".to_string(), json!(value)); + } + if let Some(value) = symbols { + params.insert("symbols".to_string(), json!(value)); + } + let mut api_headers = HashMap::new(); + api_headers.insert("content-type".to_string(), "application/json".to_string()); + + let path = "/project/policies/password-strength".to_string(); + + self.client.call(Method::PATCH, &path, Some(api_headers), Some(params)).await + } + /// Updating this policy allows you to control if email alert is sent upon /// session creation. When enabled, and user signs into their account, they /// will be sent an email notification. There is an exception, the first