whatsapp_rust/
spam_report.rs

1use crate::client::Client;
2use crate::request::{InfoQuery, IqError};
3use wacore_binary::jid::{Jid, SERVER_JID};
4use wacore_binary::node::NodeContent;
5
6pub use wacore::types::{SpamFlow, SpamReportRequest, SpamReportResult, build_spam_list_node};
7
8impl Client {
9    /// Send a spam report to WhatsApp.
10    ///
11    /// This sends a `spam_list` IQ stanza to report one or more messages as spam.
12    ///
13    /// # Arguments
14    /// * `request` - The spam report request containing message details
15    ///
16    /// # Returns
17    /// * `Ok(SpamReportResult)` - If the report was successfully submitted
18    /// * `Err` - If there was an error sending or processing the report
19    ///
20    /// # Example
21    /// ```rust,ignore
22    /// let result = client.send_spam_report(SpamReportRequest {
23    ///     message_id: "MSG_ID".to_string(),
24    ///     message_timestamp: 1234567890,
25    ///     from_jid: Some(sender_jid),
26    ///     spam_flow: SpamFlow::MessageMenu,
27    ///     ..Default::default()
28    /// }).await?;
29    /// ```
30    pub async fn send_spam_report(
31        &self,
32        request: SpamReportRequest,
33    ) -> Result<SpamReportResult, IqError> {
34        let spam_list_node = build_spam_list_node(&request);
35
36        let server_jid = Jid::new("", SERVER_JID);
37
38        let query = InfoQuery::set(
39            "spam",
40            server_jid,
41            Some(NodeContent::Nodes(vec![spam_list_node])),
42        );
43
44        let response = self.send_iq(query).await?;
45
46        // Extract report_id from response if present
47        let report_id = response
48            .get_optional_child_by_tag(&["report_id"])
49            .and_then(|n| match &n.content {
50                Some(NodeContent::String(s)) => Some(s.clone()),
51                _ => None,
52            });
53
54        Ok(SpamReportResult { report_id })
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61    use wacore_binary::jid::Jid;
62
63    #[test]
64    fn test_spam_flow_as_str() {
65        assert_eq!(SpamFlow::MessageMenu.as_str(), "MessageMenu");
66        assert_eq!(
67            SpamFlow::GroupSpamBannerReport.as_str(),
68            "GroupSpamBannerReport"
69        );
70        assert_eq!(SpamFlow::ContactInfo.as_str(), "ContactInfo");
71    }
72
73    #[test]
74    fn test_build_spam_list_node_basic() {
75        let request = SpamReportRequest {
76            message_id: "TEST123".to_string(),
77            message_timestamp: 1234567890,
78            spam_flow: SpamFlow::MessageMenu,
79            ..Default::default()
80        };
81
82        let node = build_spam_list_node(&request);
83
84        assert_eq!(node.tag, "spam_list");
85        assert_eq!(node.attrs().string("spam_flow"), "MessageMenu");
86
87        let message = node
88            .get_optional_child_by_tag(&["message"])
89            .expect("spam_list node should have message child");
90        assert_eq!(message.attrs().string("id"), "TEST123");
91        assert_eq!(message.attrs().string("t"), "1234567890");
92    }
93
94    #[test]
95    fn test_build_spam_list_node_with_raw_message() {
96        let request = SpamReportRequest {
97            message_id: "TEST456".to_string(),
98            message_timestamp: 1234567890,
99            from_jid: Some(Jid::pn("5511999887766")),
100            spam_flow: SpamFlow::MessageMenu,
101            raw_message: Some(vec![0x01, 0x02, 0x03]),
102            media_type: Some("image".to_string()),
103            ..Default::default()
104        };
105
106        let node = build_spam_list_node(&request);
107        let message = node
108            .get_optional_child_by_tag(&["message"])
109            .expect("spam_list node should have message child");
110        let raw = message
111            .get_optional_child_by_tag(&["raw"])
112            .expect("message node should have raw child");
113
114        assert_eq!(raw.attrs().string("v"), "3");
115        assert_eq!(raw.attrs().string("mediatype"), "image");
116    }
117
118    #[test]
119    fn test_build_spam_list_node_group() {
120        let request = SpamReportRequest {
121            message_id: "TEST789".to_string(),
122            message_timestamp: 1234567890,
123            group_jid: Some(Jid::group("120363025918861132")),
124            group_subject: Some("Test Group".to_string()),
125            participant_jid: Some(Jid::pn("5511999887766")),
126            spam_flow: SpamFlow::GroupInfoReport,
127            ..Default::default()
128        };
129
130        let node = build_spam_list_node(&request);
131
132        assert_eq!(node.attrs().string("spam_flow"), "GroupInfoReport");
133        assert_eq!(node.attrs().string("jid"), "120363025918861132@g.us");
134        assert_eq!(node.attrs().string("subject"), "Test Group");
135    }
136}