gewe_http/message/
send.rs

1use crate::client::GeweHttpClient;
2use gewe_core::{
3    GeweError, PostAppMsgRequest, PostAppMsgResponse, PostEmojiRequest, PostEmojiResponse,
4    PostFileRequest, PostFileResponse, PostImageRequest, PostImageResponse, PostLinkRequest,
5    PostLinkResponse, PostMiniAppRequest, PostMiniAppResponse, PostNameCardRequest,
6    PostNameCardResponse, PostVideoRequest, PostVideoResponse, PostVoiceRequest, PostVoiceResponse,
7    SendTextRequest, SendTextResponse,
8};
9use tracing::instrument;
10
11impl GeweHttpClient {
12    #[instrument(skip(self))]
13    pub async fn send_text(
14        &self,
15        app_id: &str,
16        to_wxid: &str,
17        content: &str,
18        ats: Option<&str>,
19    ) -> Result<SendTextResponse, GeweError> {
20        let body = SendTextRequest {
21            app_id,
22            to_wxid,
23            content,
24            ats,
25        };
26        let env = self
27            .post_api::<_, SendTextResponse>("gewe/v2/api/message/postText", &body)
28            .await?;
29        env.data.ok_or(GeweError::MissingData)
30    }
31
32    #[instrument(skip(self))]
33    pub async fn send_image(
34        &self,
35        app_id: &str,
36        to_wxid: &str,
37        img_url: &str,
38    ) -> Result<PostImageResponse, GeweError> {
39        let body = PostImageRequest {
40            app_id,
41            to_wxid,
42            img_url,
43        };
44        let env = self
45            .post_api::<_, PostImageResponse>("gewe/v2/api/message/postImage", &body)
46            .await?;
47        env.data.ok_or(GeweError::MissingData)
48    }
49
50    #[instrument(skip(self))]
51    pub async fn send_voice(
52        &self,
53        app_id: &str,
54        to_wxid: &str,
55        voice_url: &str,
56        voice_duration: i64,
57    ) -> Result<PostVoiceResponse, GeweError> {
58        let body = PostVoiceRequest {
59            app_id,
60            to_wxid,
61            voice_url,
62            voice_duration,
63        };
64        let env = self
65            .post_api::<_, PostVoiceResponse>("gewe/v2/api/message/postVoice", &body)
66            .await?;
67        env.data.ok_or(GeweError::MissingData)
68    }
69
70    #[instrument(skip(self))]
71    pub async fn send_video(
72        &self,
73        app_id: &str,
74        to_wxid: &str,
75        video_url: &str,
76        thumb_url: &str,
77        video_duration: i64,
78    ) -> Result<PostVideoResponse, GeweError> {
79        let body = PostVideoRequest {
80            app_id,
81            to_wxid,
82            video_url,
83            thumb_url,
84            video_duration,
85        };
86        let env = self
87            .post_api::<_, PostVideoResponse>("gewe/v2/api/message/postVideo", &body)
88            .await?;
89        env.data.ok_or(GeweError::MissingData)
90    }
91
92    #[instrument(skip(self))]
93    pub async fn send_file(
94        &self,
95        app_id: &str,
96        to_wxid: &str,
97        file_url: &str,
98        file_name: &str,
99    ) -> Result<PostFileResponse, GeweError> {
100        let body = PostFileRequest {
101            app_id,
102            to_wxid,
103            file_url,
104            file_name,
105        };
106        let env = self
107            .post_api::<_, PostFileResponse>("gewe/v2/api/message/postFile", &body)
108            .await?;
109        env.data.ok_or(GeweError::MissingData)
110    }
111
112    #[instrument(skip(self))]
113    pub async fn send_link(
114        &self,
115        app_id: &str,
116        to_wxid: &str,
117        title: &str,
118        desc: &str,
119        link_url: &str,
120        thumb_url: &str,
121    ) -> Result<PostLinkResponse, GeweError> {
122        let body = PostLinkRequest {
123            app_id,
124            to_wxid,
125            title,
126            desc,
127            link_url,
128            thumb_url,
129        };
130        let env = self
131            .post_api::<_, PostLinkResponse>("gewe/v2/api/message/postLink", &body)
132            .await?;
133        env.data.ok_or(GeweError::MissingData)
134    }
135
136    #[instrument(skip(self))]
137    pub async fn send_emoji(
138        &self,
139        app_id: &str,
140        to_wxid: &str,
141        emoji_md5: &str,
142        emoji_size: i64,
143    ) -> Result<PostEmojiResponse, GeweError> {
144        let body = PostEmojiRequest {
145            app_id,
146            to_wxid,
147            emoji_md5,
148            emoji_size,
149        };
150        let env = self
151            .post_api::<_, PostEmojiResponse>("gewe/v2/api/message/postEmoji", &body)
152            .await?;
153        env.data.ok_or(GeweError::MissingData)
154    }
155
156    #[instrument(skip(self))]
157    pub async fn send_app_msg(
158        &self,
159        app_id: &str,
160        to_wxid: &str,
161        appmsg: &str,
162    ) -> Result<PostAppMsgResponse, GeweError> {
163        let body = PostAppMsgRequest {
164            app_id,
165            to_wxid,
166            appmsg,
167        };
168        let env = self
169            .post_api::<_, PostAppMsgResponse>("gewe/v2/api/message/postAppMsg", &body)
170            .await?;
171        env.data.ok_or(GeweError::MissingData)
172    }
173
174    #[allow(clippy::too_many_arguments)]
175    #[instrument(skip(self))]
176    pub async fn send_mini_app(
177        &self,
178        app_id: &str,
179        to_wxid: &str,
180        mini_app_id: &str,
181        display_name: &str,
182        page_path: &str,
183        cover_img_url: &str,
184        title: &str,
185        user_name: &str,
186    ) -> Result<PostMiniAppResponse, GeweError> {
187        let body = PostMiniAppRequest {
188            app_id,
189            to_wxid,
190            mini_app_id,
191            display_name,
192            page_path,
193            cover_img_url,
194            title,
195            user_name,
196        };
197        let env = self
198            .post_api::<_, PostMiniAppResponse>("gewe/v2/api/message/postMiniApp", &body)
199            .await?;
200        env.data.ok_or(GeweError::MissingData)
201    }
202
203    #[instrument(skip(self))]
204    pub async fn send_name_card(
205        &self,
206        app_id: &str,
207        to_wxid: &str,
208        nick_name: &str,
209        name_card_wxid: &str,
210    ) -> Result<PostNameCardResponse, GeweError> {
211        let body = PostNameCardRequest {
212            app_id,
213            to_wxid,
214            nick_name,
215            name_card_wxid,
216        };
217        let env = self
218            .post_api::<_, PostNameCardResponse>("gewe/v2/api/message/postNameCard", &body)
219            .await?;
220        env.data.ok_or(GeweError::MissingData)
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    #[test]
229    fn test_send_text_request_serialization() {
230        let req = SendTextRequest {
231            app_id: "test_app",
232            to_wxid: "recipient_wxid",
233            content: "Hello World",
234            ats: Some("@wxid1,@wxid2"),
235        };
236        let json = serde_json::to_string(&req).expect("Failed to serialize");
237        assert!(json.contains("appId"));
238        assert!(json.contains("toWxid"));
239        assert!(json.contains("Hello World"));
240    }
241
242    #[test]
243    fn test_send_text_without_ats() {
244        let req = SendTextRequest {
245            app_id: "test_app",
246            to_wxid: "recipient_wxid",
247            content: "Hello",
248            ats: None,
249        };
250        let json = serde_json::to_string(&req).expect("Failed to serialize");
251        assert!(json.contains("appId"));
252        assert!(json.contains("Hello"));
253    }
254
255    #[test]
256    fn test_post_image_request_serialization() {
257        let req = PostImageRequest {
258            app_id: "test_app",
259            to_wxid: "recipient_wxid",
260            img_url: "https://example.com/image.jpg",
261        };
262        let json = serde_json::to_string(&req).expect("Failed to serialize");
263        assert!(json.contains("appId"));
264        assert!(json.contains("imgUrl"));
265        assert!(json.contains("https://example.com/image.jpg"));
266    }
267
268    #[test]
269    fn test_post_voice_request_serialization() {
270        let req = PostVoiceRequest {
271            app_id: "test_app",
272            to_wxid: "recipient_wxid",
273            voice_url: "https://example.com/voice.mp3",
274            voice_duration: 30000,
275        };
276        let json = serde_json::to_string(&req).expect("Failed to serialize");
277        assert!(json.contains("appId"));
278        assert!(json.contains("voiceUrl"));
279        assert!(json.contains("30000"));
280    }
281
282    #[test]
283    fn test_post_video_request_serialization() {
284        let req = PostVideoRequest {
285            app_id: "test_app",
286            to_wxid: "recipient_wxid",
287            video_url: "https://example.com/video.mp4",
288            thumb_url: "https://example.com/thumb.jpg",
289            video_duration: 60000,
290        };
291        let json = serde_json::to_string(&req).expect("Failed to serialize");
292        assert!(json.contains("videoUrl"));
293        assert!(json.contains("thumbUrl"));
294        assert!(json.contains("60000"));
295    }
296
297    #[test]
298    fn test_post_file_request_serialization() {
299        let req = PostFileRequest {
300            app_id: "test_app",
301            to_wxid: "recipient_wxid",
302            file_url: "https://example.com/file.pdf",
303            file_name: "document.pdf",
304        };
305        let json = serde_json::to_string(&req).expect("Failed to serialize");
306        assert!(json.contains("fileUrl"));
307        assert!(json.contains("fileName"));
308        assert!(json.contains("document.pdf"));
309    }
310
311    #[test]
312    fn test_post_link_request_serialization() {
313        let req = PostLinkRequest {
314            app_id: "test_app",
315            to_wxid: "recipient_wxid",
316            title: "Link Title",
317            desc: "Link Description",
318            link_url: "https://example.com",
319            thumb_url: "https://example.com/thumb.jpg",
320        };
321        let json = serde_json::to_string(&req).expect("Failed to serialize");
322        assert!(json.contains("Link Title"));
323        assert!(json.contains("Link Description"));
324        assert!(json.contains("linkUrl"));
325    }
326
327    #[test]
328    fn test_post_emoji_request_serialization() {
329        let req = PostEmojiRequest {
330            app_id: "test_app",
331            to_wxid: "recipient_wxid",
332            emoji_md5: "abc123def456",
333            emoji_size: 102400,
334        };
335        let json = serde_json::to_string(&req).expect("Failed to serialize");
336        assert!(json.contains("emojiMd5"));
337        assert!(json.contains("abc123def456"));
338        assert!(json.contains("102400"));
339    }
340
341    #[test]
342    fn test_post_app_msg_request_serialization() {
343        let req = PostAppMsgRequest {
344            app_id: "test_app",
345            to_wxid: "recipient_wxid",
346            appmsg: "<xml>app message</xml>",
347        };
348        let json = serde_json::to_string(&req).expect("Failed to serialize");
349        assert!(json.contains("appmsg"));
350        assert!(json.contains("<xml>app message</xml>"));
351    }
352
353    #[test]
354    fn test_post_mini_app_request_serialization() {
355        let req = PostMiniAppRequest {
356            app_id: "test_app",
357            to_wxid: "recipient_wxid",
358            mini_app_id: "mini_app_123",
359            display_name: "Mini App",
360            page_path: "pages/index",
361            cover_img_url: "https://example.com/cover.jpg",
362            title: "App Title",
363            user_name: "gh_123456",
364        };
365        let json = serde_json::to_string(&req).expect("Failed to serialize");
366        assert!(json.contains("miniAppId"));
367        assert!(json.contains("displayName"));
368        assert!(json.contains("pagePath"));
369        assert!(json.contains("Mini App"));
370    }
371
372    #[test]
373    fn test_post_name_card_request_serialization() {
374        let req = PostNameCardRequest {
375            app_id: "test_app",
376            to_wxid: "recipient_wxid",
377            nick_name: "John Doe",
378            name_card_wxid: "card_wxid_123",
379        };
380        let json = serde_json::to_string(&req).expect("Failed to serialize");
381        assert!(json.contains("nickName"));
382        assert!(json.contains("John Doe"));
383        assert!(json.contains("nameCardWxid"));
384    }
385
386    #[test]
387    fn test_send_text_with_unicode() {
388        let req = SendTextRequest {
389            app_id: "测试应用",
390            to_wxid: "收件人",
391            content: "你好世界",
392            ats: None,
393        };
394        let json = serde_json::to_string(&req).expect("Failed to serialize");
395        assert!(json.contains("测试应用"));
396        assert!(json.contains("你好世界"));
397    }
398}