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}