Skip to main content

steam_user/services/
help.rs

1//! Steam Help Request services.
2
3use std::sync::OnceLock;
4
5use scraper::{Html, Selector};
6
7use crate::{client::SteamUser, endpoint::steam_endpoint, error::SteamUserError};
8
9static SEL_HELP_ROW: OnceLock<Selector> = OnceLock::new();
10fn sel_help_row() -> &'static Selector {
11    SEL_HELP_ROW.get_or_init(|| Selector::parse(".help_request_table a.help_request_row").expect("valid CSS selector"))
12}
13
14static SEL_HELP_STATUS: OnceLock<Selector> = OnceLock::new();
15fn sel_help_status() -> &'static Selector {
16    SEL_HELP_STATUS.get_or_init(|| Selector::parse(".status").expect("valid CSS selector"))
17}
18
19static SEL_HELP_TITLE: OnceLock<Selector> = OnceLock::new();
20fn sel_help_title() -> &'static Selector {
21    SEL_HELP_TITLE.get_or_init(|| Selector::parse(".help_request_name").expect("valid CSS selector"))
22}
23
24static SEL_HELP_DATE: OnceLock<Selector> = OnceLock::new();
25fn sel_help_date() -> &'static Selector {
26    SEL_HELP_DATE.get_or_init(|| Selector::parse(".date_created").expect("valid CSS selector"))
27}
28
29static SEL_HELP_PAGE: OnceLock<Selector> = OnceLock::new();
30fn sel_help_page() -> &'static Selector {
31    SEL_HELP_PAGE.get_or_init(|| Selector::parse(".help_request_page").expect("valid CSS selector"))
32}
33
34impl SteamUser {
35    /// Lists active and past Steam support tickets (Help Requests).
36    ///
37    /// Scrapes the Steam Help Requests page at `https://help.steampowered.com/en/wizard/HelpRequests`.
38    ///
39    /// # Returns
40    ///
41    /// Returns a `Vec<HelpRequest>` containing a summary of each support
42    /// ticket.
43    #[steam_endpoint(GET, host = Help, path = "/en/wizard/HelpRequests", kind = Read)]
44    pub async fn get_help_requests(&self) -> Result<Vec<crate::types::HelpRequest>, SteamUserError> {
45        let response = self.get_path("/en/wizard/HelpRequests").send().await?.text().await?;
46
47        let document = Html::parse_document(&response);
48
49        let mut requests = Vec::new();
50
51        for element in document.select(sel_help_row()) {
52            let link = element.value().attr("href").unwrap_or("");
53            // Extract ID from link: .../HelpRequest/HT-XXXX-XXXX-XXXX
54            let id = link.trim_end_matches('/').split('/').next_back().unwrap_or("").to_string();
55
56            let title = element.select(sel_help_title()).next().map(|e| e.text().collect::<String>().trim().to_string()).unwrap_or_default();
57
58            // Status and date are inside columns, but we can search within the row element
59            let status = element.select(sel_help_status()).next().map(|e| e.text().collect::<String>().trim().to_string()).unwrap_or_default();
60
61            let date_created = element.select(sel_help_date()).next().map(|e| e.text().collect::<String>().trim().to_string()).unwrap_or_default();
62
63            requests.push(crate::types::HelpRequest { id, title, date_created, status });
64        }
65
66        Ok(requests)
67    }
68
69    /// Retrieves the detailed conversation for a specific support ticket.
70    ///
71    /// # Arguments
72    ///
73    /// * `id` - The Steam help request ID (e.g., "HT-XXXX-XXXX-XXXX").
74    ///
75    /// # Returns
76    ///
77    /// Returns the raw HTML content of the help request conversation details.
78    #[steam_endpoint(GET, host = Help, path = "/en/wizard/HelpRequest/{id}", kind = Read)]
79    pub async fn get_help_request_detail(&self, id: &str) -> Result<String, SteamUserError> {
80        let response = self.get_path(format!("/en/wizard/HelpRequest/{}", id)).send().await?;
81
82        if !response.status().is_success() {
83            return Err(SteamUserError::Other(format!("Failed to get help request detail: {}", response.status())));
84        }
85
86        let html = response.text().await?;
87        let document = Html::parse_document(&html);
88
89        if let Some(element) = document.select(sel_help_page()).next() {
90            Ok(element.inner_html())
91        } else {
92            // If the element is not found, it might be an error page or a different layout
93            // For now, return empty string or error? JS returns empty if not found logic
94            // implies? JS: const $ = jq.load(result.data); return
95            // $(".help_request_page").html(); If selector finds nothing, jq
96            // returns null/undefined.
97            Ok(String::new())
98        }
99    }
100}