steam-user 0.1.0

Steam User web client for Rust - HTTP-based Steam Community interactions
Documentation
//! Privacy settings management services.

use crate::{
    client::SteamUser,
    endpoint::steam_endpoint,
    error::SteamUserError,
    types::{PrivacySettings, PrivacyState},
};

impl SteamUser {
    /// Retrieves the current privacy settings for the authenticated user
    /// profile.
    #[steam_endpoint(GET, host = Community, path = "/profiles/{steam_id}/edit/settings", kind = Read)]
    pub async fn get_privacy_settings(&self) -> Result<PrivacySettings, SteamUserError> {
        let response = self.my_profile_get("edit/settings").await?;
        let document = scraper::Html::parse_document(&response);
        let selector = scraper::Selector::parse("#profile_edit_config").map_err(|e| SteamUserError::Other(format!("Failed to parse selector: {:?}", e)))?;

        let element = document.select(&selector).next().ok_or_else(|| SteamUserError::Other("Could not find #profile_edit_config element".to_string()))?;

        let data_json = element.value().attr("data-profile-edit").ok_or_else(|| SteamUserError::Other("data-profile-edit attribute missing".to_string()))?;

        let json: serde_json::Value = serde_json::from_str(data_json)?;

        PrivacySettings::from_steam_json(&json).ok_or_else(|| SteamUserError::MalformedResponse("Failed to parse privacy settings from JSON".into()))
    }

    /// Updates the privacy settings for the authenticated user profile.
    ///
    /// If partial settings are provided, the current settings are fetched and
    /// merged to avoid overwriting unspecified fields.
    #[steam_endpoint(POST, host = Community, path = "/profiles/{steam_id}/ajaxsetprivacy/", kind = Write)]
    pub async fn set_privacy_settings(&self, settings: PrivacySettings) -> Result<PrivacySettings, SteamUserError> {
        let mut final_settings = settings.clone();

        // Check if we need to fetch existing settings to fill in the blanks
        // (matching JS behavior: if any field is missing, fetch all)
        let is_partial = settings.profile.is_none() || settings.comments.is_none() || settings.inventory.is_none() || settings.inventory_gifts.is_none() || settings.game_details.is_none() || settings.playtime.is_none() || settings.friends_list.is_none();

        if is_partial {
            let existing = self.get_privacy_settings().await?;
            let mut merged = existing;
            merged.merge(settings);
            final_settings = merged;
        }

        let privacy_json = final_settings.to_steam_format();
        let privacy_str = privacy_json.to_string();
        let comment_perm = final_settings.comments.unwrap_or(0).to_string();

        let form = [("Privacy", privacy_str.as_str()), ("eCommentPermission", comment_perm.as_str())];

        let body = self.my_profile_post("ajaxsetprivacy/", &form).await?;
        let result_json: serde_json::Value = serde_json::from_str(&body)?;

        PrivacySettings::from_steam_json(&result_json).ok_or_else(|| SteamUserError::MalformedResponse("Failed to parse updated privacy settings".into()))
    }

    /// Sets all privacy-related settings to the specified level (Public,
    /// Friends Only, or Private).
    // delegates to `set_privacy_settings` — no #[steam_endpoint]
    #[tracing::instrument(skip(self))]
    pub async fn set_all_privacy(&self, level: PrivacyState) -> Result<PrivacySettings, SteamUserError> {
        let settings = PrivacySettings {
            profile: Some(level),
            comments: Some(match level {
                PrivacyState::Public => 1,
                PrivacyState::FriendsOnly => 0,
                PrivacyState::Private => 2,
            }),
            inventory: Some(level),
            inventory_gifts: Some(level),
            game_details: Some(level),
            playtime: Some(level),
            friends_list: Some(level),
        };
        self.set_privacy_settings(settings).await
    }
}