1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4#[serde(rename_all = "camelCase")]
5pub struct FetchContactsListRequest<'a> {
6 #[serde(rename = "appId")]
7 pub app_id: &'a str,
8}
9
10#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11#[serde(rename_all = "camelCase")]
12pub struct FetchContactsListResponse {
13 pub friends: Vec<String>,
14 pub chatrooms: Vec<String>,
15 pub ghs: Vec<String>,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub struct FetchContactsListCacheRequest<'a> {
21 #[serde(rename = "appId")]
22 pub app_id: &'a str,
23}
24
25pub type FetchContactsListCacheResponse = ();
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28#[serde(rename_all = "camelCase")]
29pub struct SearchContactsRequest<'a> {
30 #[serde(rename = "appId")]
31 pub app_id: &'a str,
32 #[serde(rename = "contactsInfo")]
33 pub contacts_info: &'a str,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, Default)]
37#[serde(rename_all = "camelCase")]
38pub struct SearchContactsResponse {
39 pub v3: String,
40 #[serde(rename = "nickName")]
41 pub nick_name: String,
42 pub sex: i32,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub signature: Option<String>,
45 #[serde(rename = "bigHeadImgUrl")]
46 pub big_head_img_url: String,
47 #[serde(rename = "smallHeadImgUrl")]
48 pub small_head_img_url: String,
49 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub v4: Option<String>,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54#[serde(rename_all = "camelCase")]
55pub struct GetContactBriefInfoRequest<'a> {
56 #[serde(rename = "appId")]
57 pub app_id: &'a str,
58 pub wxids: Vec<&'a str>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, Default)]
62#[serde(rename_all = "camelCase")]
63pub struct ContactBriefInfo {
64 #[serde(rename = "userName")]
65 pub user_name: String,
66 #[serde(rename = "nickName")]
67 pub nick_name: String,
68 #[serde(rename = "pyInitial")]
69 pub py_initial: String,
70 #[serde(rename = "quanPin")]
71 pub quan_pin: String,
72 pub sex: i32,
73 pub remark: String,
74 #[serde(rename = "remarkPyInitial")]
75 pub remark_py_initial: String,
76 #[serde(rename = "remarkQuanPin")]
77 pub remark_quan_pin: String,
78 #[serde(default, skip_serializing_if = "Option::is_none")]
79 pub signature: Option<String>,
80 pub alias: String,
81 #[serde(rename = "snsBgImg", default, skip_serializing_if = "Option::is_none")]
82 pub sns_bg_img: Option<String>,
83 pub country: String,
84 #[serde(rename = "bigHeadImgUrl")]
85 pub big_head_img_url: String,
86 #[serde(rename = "smallHeadImgUrl")]
87 pub small_head_img_url: String,
88 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub description: Option<String>,
90 #[serde(
91 rename = "cardImgUrl",
92 default,
93 skip_serializing_if = "Option::is_none"
94 )]
95 pub card_img_url: Option<String>,
96 #[serde(rename = "labelList")]
97 pub label_list: String,
98 pub province: String,
99 pub city: String,
100 #[serde(
101 rename = "phoneNumList",
102 default,
103 skip_serializing_if = "Option::is_none"
104 )]
105 pub phone_num_list: Option<String>,
106}
107
108pub type GetContactBriefInfoResponse = Vec<ContactBriefInfo>;
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(rename_all = "camelCase")]
112pub struct GetContactDetailInfoRequest<'a> {
113 #[serde(rename = "appId")]
114 pub app_id: &'a str,
115 pub wxids: Vec<&'a str>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, Default)]
119#[serde(rename_all = "camelCase")]
120pub struct ContactDetailInfo {
121 #[serde(rename = "userName")]
122 pub user_name: String,
123 #[serde(rename = "nickName")]
124 pub nick_name: String,
125 #[serde(rename = "pyInitial", default, skip_serializing_if = "Option::is_none")]
126 pub py_initial: Option<String>,
127 #[serde(rename = "quanPin")]
128 pub quan_pin: String,
129 pub sex: i32,
130 #[serde(default, skip_serializing_if = "Option::is_none")]
131 pub remark: Option<String>,
132 #[serde(
133 rename = "remarkPyInitial",
134 default,
135 skip_serializing_if = "Option::is_none"
136 )]
137 pub remark_py_initial: Option<String>,
138 #[serde(
139 rename = "remarkQuanPin",
140 default,
141 skip_serializing_if = "Option::is_none"
142 )]
143 pub remark_quan_pin: Option<String>,
144 pub signature: String,
145 pub alias: String,
146 #[serde(rename = "snsBgImg")]
147 pub sns_bg_img: String,
148 pub country: String,
149 #[serde(rename = "bigHeadImgUrl")]
150 pub big_head_img_url: String,
151 #[serde(rename = "smallHeadImgUrl")]
152 pub small_head_img_url: String,
153 #[serde(default, skip_serializing_if = "Option::is_none")]
154 pub description: Option<String>,
155 #[serde(
156 rename = "cardImgUrl",
157 default,
158 skip_serializing_if = "Option::is_none"
159 )]
160 pub card_img_url: Option<String>,
161 #[serde(rename = "labelList", default, skip_serializing_if = "Option::is_none")]
162 pub label_list: Option<String>,
163 #[serde(default, skip_serializing_if = "Option::is_none")]
164 pub province: Option<String>,
165 #[serde(default, skip_serializing_if = "Option::is_none")]
166 pub city: Option<String>,
167 #[serde(
168 rename = "phoneNumList",
169 default,
170 skip_serializing_if = "Option::is_none"
171 )]
172 pub phone_num_list: Option<String>,
173}
174
175pub type GetContactDetailInfoResponse = Vec<ContactDetailInfo>;
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
178#[serde(rename_all = "camelCase")]
179pub struct GetPhoneAddressListRequest<'a> {
180 #[serde(rename = "appId")]
181 pub app_id: &'a str,
182 #[serde(default, skip_serializing_if = "Option::is_none")]
183 pub phones: Option<Vec<&'a str>>,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize, Default)]
187#[serde(rename_all = "camelCase")]
188pub struct PhoneContact {
189 #[serde(rename = "userName")]
190 pub user_name: String,
191 #[serde(default, skip_serializing_if = "Option::is_none")]
192 pub v4: Option<String>,
193 #[serde(rename = "nickName", default, skip_serializing_if = "Option::is_none")]
194 pub nick_name: Option<String>,
195 pub sex: i32,
196 #[serde(rename = "phoneMd5")]
197 pub phone_md5: String,
198 pub signature: String,
199 #[serde(default, skip_serializing_if = "Option::is_none")]
200 pub alias: Option<String>,
201 pub country: String,
202 #[serde(rename = "bigHeadImgUrl")]
203 pub big_head_img_url: String,
204 #[serde(rename = "smallHeadImgUrl")]
205 pub small_head_img_url: String,
206 pub province: String,
207 pub city: String,
208 #[serde(rename = "personalCard")]
209 pub personal_card: i32,
210}
211
212pub type GetPhoneAddressListResponse = Vec<PhoneContact>;
213
214#[derive(Debug, Clone, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct CheckRelationRequest<'a> {
217 #[serde(rename = "appId")]
218 pub app_id: &'a str,
219 pub wxids: Vec<&'a str>,
220}
221
222#[derive(Debug, Clone, Serialize, Deserialize, Default)]
223#[serde(rename_all = "camelCase")]
224pub struct ContactRelationStatus {
225 pub wxid: String,
226 pub relation: i32,
227}
228
229pub type CheckRelationResponse = Vec<ContactRelationStatus>;
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
236 fn test_fetch_contacts_list_response_default() {
237 let resp = FetchContactsListResponse::default();
238 assert!(resp.friends.is_empty());
239 assert!(resp.chatrooms.is_empty());
240 assert!(resp.ghs.is_empty());
241 }
242
243 #[test]
244 fn test_fetch_contacts_list_response_deserialization() {
245 let json = r#"{
246 "friends": ["wxid1", "wxid2"],
247 "chatrooms": ["room1", "room2"],
248 "ghs": ["gh1"]
249 }"#;
250 let resp: FetchContactsListResponse = serde_json::from_str(json).unwrap();
251 assert_eq!(resp.friends, vec!["wxid1", "wxid2"]);
252 assert_eq!(resp.chatrooms, vec!["room1", "room2"]);
253 assert_eq!(resp.ghs, vec!["gh1"]);
254 }
255
256 #[test]
257 fn test_search_contacts_response_default() {
258 let resp = SearchContactsResponse::default();
259 assert_eq!(resp.v3, "");
260 assert_eq!(resp.nick_name, "");
261 assert_eq!(resp.sex, 0);
262 assert_eq!(resp.signature, None);
263 }
264
265 #[test]
266 fn test_search_contacts_response_deserialization() {
267 let json = r#"{
268 "v3": "test_v3",
269 "nickName": "TestUser",
270 "sex": 1,
271 "signature": "Hello World",
272 "bigHeadImgUrl": "http://example.com/big.jpg",
273 "smallHeadImgUrl": "http://example.com/small.jpg",
274 "v4": "test_v4"
275 }"#;
276 let resp: SearchContactsResponse = serde_json::from_str(json).unwrap();
277 assert_eq!(resp.v3, "test_v3");
278 assert_eq!(resp.nick_name, "TestUser");
279 assert_eq!(resp.sex, 1);
280 assert_eq!(resp.signature, Some("Hello World".to_string()));
281 assert_eq!(resp.big_head_img_url, "http://example.com/big.jpg");
282 assert_eq!(resp.small_head_img_url, "http://example.com/small.jpg");
283 assert_eq!(resp.v4, Some("test_v4".to_string()));
284 }
285
286 #[test]
287 fn test_contact_brief_info_default() {
288 let info = ContactBriefInfo::default();
289 assert_eq!(info.user_name, "");
290 assert_eq!(info.nick_name, "");
291 assert_eq!(info.sex, 0);
292 assert_eq!(info.remark, "");
293 }
294
295 #[test]
296 fn test_contact_brief_info_deserialization() {
297 let json = r#"{
298 "userName": "wxid_test",
299 "nickName": "TestUser",
300 "pyInitial": "TU",
301 "quanPin": "testuser",
302 "sex": 1,
303 "remark": "My Friend",
304 "remarkPyInitial": "MF",
305 "remarkQuanPin": "myfriend",
306 "signature": "Hello",
307 "alias": "test_alias",
308 "country": "CN",
309 "bigHeadImgUrl": "http://example.com/big.jpg",
310 "smallHeadImgUrl": "http://example.com/small.jpg",
311 "labelList": "label1,label2",
312 "province": "Beijing",
313 "city": "Beijing"
314 }"#;
315 let info: ContactBriefInfo = serde_json::from_str(json).unwrap();
316 assert_eq!(info.user_name, "wxid_test");
317 assert_eq!(info.nick_name, "TestUser");
318 assert_eq!(info.py_initial, "TU");
319 assert_eq!(info.sex, 1);
320 assert_eq!(info.remark, "My Friend");
321 assert_eq!(info.alias, "test_alias");
322 assert_eq!(info.country, "CN");
323 assert_eq!(info.province, "Beijing");
324 assert_eq!(info.city, "Beijing");
325 }
326
327 #[test]
328 fn test_contact_detail_info_default() {
329 let info = ContactDetailInfo::default();
330 assert_eq!(info.user_name, "");
331 assert_eq!(info.nick_name, "");
332 assert_eq!(info.sex, 0);
333 assert_eq!(info.signature, "");
334 }
335
336 #[test]
337 fn test_contact_detail_info_deserialization() {
338 let json = r#"{
339 "userName": "wxid_test",
340 "nickName": "TestUser",
341 "quanPin": "testuser",
342 "sex": 1,
343 "signature": "Hello World",
344 "alias": "test_alias",
345 "snsBgImg": "http://example.com/bg.jpg",
346 "country": "CN",
347 "bigHeadImgUrl": "http://example.com/big.jpg",
348 "smallHeadImgUrl": "http://example.com/small.jpg"
349 }"#;
350 let info: ContactDetailInfo = serde_json::from_str(json).unwrap();
351 assert_eq!(info.user_name, "wxid_test");
352 assert_eq!(info.nick_name, "TestUser");
353 assert_eq!(info.quan_pin, "testuser");
354 assert_eq!(info.sex, 1);
355 assert_eq!(info.signature, "Hello World");
356 assert_eq!(info.alias, "test_alias");
357 assert_eq!(info.country, "CN");
358 }
359
360 #[test]
361 fn test_phone_contact_default() {
362 let contact = PhoneContact::default();
363 assert_eq!(contact.user_name, "");
364 assert_eq!(contact.sex, 0);
365 assert_eq!(contact.phone_md5, "");
366 assert_eq!(contact.signature, "");
367 }
368
369 #[test]
370 fn test_phone_contact_deserialization() {
371 let json = r#"{
372 "userName": "wxid_test",
373 "sex": 1,
374 "phoneMd5": "abc123",
375 "signature": "Hello",
376 "country": "CN",
377 "bigHeadImgUrl": "http://example.com/big.jpg",
378 "smallHeadImgUrl": "http://example.com/small.jpg",
379 "province": "Beijing",
380 "city": "Beijing",
381 "personalCard": 1
382 }"#;
383 let contact: PhoneContact = serde_json::from_str(json).unwrap();
384 assert_eq!(contact.user_name, "wxid_test");
385 assert_eq!(contact.sex, 1);
386 assert_eq!(contact.phone_md5, "abc123");
387 assert_eq!(contact.signature, "Hello");
388 assert_eq!(contact.country, "CN");
389 assert_eq!(contact.personal_card, 1);
390 }
391
392 #[test]
393 fn test_contact_relation_status_default() {
394 let status = ContactRelationStatus::default();
395 assert_eq!(status.wxid, "");
396 assert_eq!(status.relation, 0);
397 }
398
399 #[test]
400 fn test_contact_relation_status_deserialization() {
401 let json = r#"{
402 "wxid": "wxid_test",
403 "relation": 1
404 }"#;
405 let status: ContactRelationStatus = serde_json::from_str(json).unwrap();
406 assert_eq!(status.wxid, "wxid_test");
407 assert_eq!(status.relation, 1);
408 }
409
410 #[test]
411 fn test_fetch_contacts_list_request_serialization() {
412 let req = FetchContactsListRequest { app_id: "test_app" };
413 let json = serde_json::to_string(&req).unwrap();
414 assert!(json.contains("test_app"));
415 }
416
417 #[test]
418 fn test_search_contacts_request_serialization() {
419 let req = SearchContactsRequest {
420 app_id: "test_app",
421 contacts_info: "wxid_test",
422 };
423 let json = serde_json::to_string(&req).unwrap();
424 assert!(json.contains("test_app"));
425 assert!(json.contains("wxid_test"));
426 }
427
428 #[test]
429 fn test_get_contact_brief_info_request_serialization() {
430 let req = GetContactBriefInfoRequest {
431 app_id: "test_app",
432 wxids: vec!["wxid1", "wxid2"],
433 };
434 let json = serde_json::to_string(&req).unwrap();
435 assert!(json.contains("test_app"));
436 assert!(json.contains("wxid1"));
437 assert!(json.contains("wxid2"));
438 }
439
440 #[test]
441 fn test_get_phone_address_list_request_serialization() {
442 let req = GetPhoneAddressListRequest {
443 app_id: "test_app",
444 phones: Some(vec!["12345678901", "12345678902"]),
445 };
446 let json = serde_json::to_string(&req).unwrap();
447 assert!(json.contains("test_app"));
448 assert!(json.contains("12345678901"));
449 }
450
451 #[test]
452 fn test_check_relation_request_serialization() {
453 let req = CheckRelationRequest {
454 app_id: "test_app",
455 wxids: vec!["wxid1", "wxid2"],
456 };
457 let json = serde_json::to_string(&req).unwrap();
458 assert!(json.contains("test_app"));
459 assert!(json.contains("wxid1"));
460 }
461}