Skip to main content

steam_user/services/
privacy.rs

1//! Privacy settings management services.
2
3use crate::{
4    client::SteamUser,
5    endpoint::steam_endpoint,
6    error::SteamUserError,
7    types::{PrivacySettings, PrivacyState},
8};
9
10impl SteamUser {
11    /// Retrieves the current privacy settings for the authenticated user
12    /// profile.
13    #[steam_endpoint(GET, host = Community, path = "/profiles/{steam_id}/edit/settings", kind = Read)]
14    pub async fn get_privacy_settings(&self) -> Result<PrivacySettings, SteamUserError> {
15        let response = self.my_profile_get("edit/settings").await?;
16        let document = scraper::Html::parse_document(&response);
17        let selector = scraper::Selector::parse("#profile_edit_config").map_err(|e| SteamUserError::Other(format!("Failed to parse selector: {:?}", e)))?;
18
19        let element = document.select(&selector).next().ok_or_else(|| SteamUserError::Other("Could not find #profile_edit_config element".to_string()))?;
20
21        let data_json = element.value().attr("data-profile-edit").ok_or_else(|| SteamUserError::Other("data-profile-edit attribute missing".to_string()))?;
22
23        let json: serde_json::Value = serde_json::from_str(data_json)?;
24
25        PrivacySettings::from_steam_json(&json).ok_or_else(|| SteamUserError::MalformedResponse("Failed to parse privacy settings from JSON".into()))
26    }
27
28    /// Updates the privacy settings for the authenticated user profile.
29    ///
30    /// If partial settings are provided, the current settings are fetched and
31    /// merged to avoid overwriting unspecified fields.
32    #[steam_endpoint(POST, host = Community, path = "/profiles/{steam_id}/ajaxsetprivacy/", kind = Write)]
33    pub async fn set_privacy_settings(&self, settings: PrivacySettings) -> Result<PrivacySettings, SteamUserError> {
34        let mut final_settings = settings.clone();
35
36        // Check if we need to fetch existing settings to fill in the blanks
37        // (matching JS behavior: if any field is missing, fetch all)
38        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();
39
40        if is_partial {
41            let existing = self.get_privacy_settings().await?;
42            let mut merged = existing;
43            merged.merge(settings);
44            final_settings = merged;
45        }
46
47        let privacy_json = final_settings.to_steam_format();
48        let privacy_str = privacy_json.to_string();
49        let comment_perm = final_settings.comments.unwrap_or(0).to_string();
50
51        let form = [("Privacy", privacy_str.as_str()), ("eCommentPermission", comment_perm.as_str())];
52
53        let body = self.my_profile_post("ajaxsetprivacy/", &form).await?;
54        let result_json: serde_json::Value = serde_json::from_str(&body)?;
55
56        PrivacySettings::from_steam_json(&result_json).ok_or_else(|| SteamUserError::MalformedResponse("Failed to parse updated privacy settings".into()))
57    }
58
59    /// Sets all privacy-related settings to the specified level (Public,
60    /// Friends Only, or Private).
61    // delegates to `set_privacy_settings` — no #[steam_endpoint]
62    #[tracing::instrument(skip(self))]
63    pub async fn set_all_privacy(&self, level: PrivacyState) -> Result<PrivacySettings, SteamUserError> {
64        let settings = PrivacySettings {
65            profile: Some(level),
66            comments: Some(match level {
67                PrivacyState::Public => 1,
68                PrivacyState::FriendsOnly => 0,
69                PrivacyState::Private => 2,
70            }),
71            inventory: Some(level),
72            inventory_gifts: Some(level),
73            game_details: Some(level),
74            playtime: Some(level),
75            friends_list: Some(level),
76        };
77        self.set_privacy_settings(settings).await
78    }
79}