open_lark/service/im/v2/
models.rs

1use serde::{Deserialize, Serialize};
2
3/// 消息流卡片状态
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5pub enum FeedCardStatus {
6    /// 激活状态
7    #[serde(rename = "active")]
8    Active,
9    /// 失效状态
10    #[serde(rename = "inactive")]
11    Inactive,
12}
13
14/// 用户ID类型
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16pub enum UserIdType {
17    /// 用户ID
18    #[serde(rename = "user_id")]
19    UserId,
20    /// union_id
21    #[serde(rename = "union_id")]
22    UnionId,
23    /// open_id
24    #[serde(rename = "open_id")]
25    OpenId,
26}
27
28impl UserIdType {
29    pub fn as_str(&self) -> &'static str {
30        match self {
31            UserIdType::UserId => "user_id",
32            UserIdType::UnionId => "union_id",
33            UserIdType::OpenId => "open_id",
34        }
35    }
36}
37
38/// 消息流卡片信息
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct FeedCard {
41    /// 卡片ID
42    pub card_id: String,
43    /// 卡片标题
44    pub title: Option<String>,
45    /// 卡片内容
46    pub content: Option<String>,
47    /// 卡片状态
48    pub status: Option<FeedCardStatus>,
49    /// 创建时间
50    pub create_time: Option<String>,
51    /// 更新时间
52    pub update_time: Option<String>,
53}
54
55/// 按钮信息
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct ButtonInfo {
58    /// 按钮ID
59    pub button_id: String,
60    /// 按钮文本
61    pub text: String,
62    /// 按钮类型
63    pub button_type: Option<String>,
64    /// 按钮行为
65    pub action: Option<String>,
66}
67
68/// 即时提醒配置
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct TimelyNotification {
71    /// 提醒类型
72    pub notification_type: String,
73    /// 提醒消息
74    pub message: String,
75    /// 目标用户
76    pub target_users: Vec<String>,
77}
78
79#[cfg(test)]
80#[allow(unused_variables, unused_unsafe)]
81mod tests {
82    use super::*;
83    use serde_json;
84
85    #[test]
86    fn test_feed_card_status_serialization() {
87        let active = FeedCardStatus::Active;
88        let inactive = FeedCardStatus::Inactive;
89
90        let active_json = serde_json::to_string(&active).unwrap();
91        let inactive_json = serde_json::to_string(&inactive).unwrap();
92
93        assert_eq!(active_json, "\"active\"");
94        assert_eq!(inactive_json, "\"inactive\"");
95    }
96
97    #[test]
98    fn test_feed_card_status_deserialization() {
99        let active_result: FeedCardStatus = serde_json::from_str("\"active\"").unwrap();
100        let inactive_result: FeedCardStatus = serde_json::from_str("\"inactive\"").unwrap();
101
102        assert_eq!(active_result, FeedCardStatus::Active);
103        assert_eq!(inactive_result, FeedCardStatus::Inactive);
104    }
105
106    #[test]
107    fn test_feed_card_status_clone_and_debug() {
108        let status = FeedCardStatus::Active;
109        let cloned_status = status.clone();
110
111        assert_eq!(status, cloned_status);
112        assert!(format!("{:?}", status).contains("Active"));
113    }
114
115    #[test]
116    fn test_user_id_type_as_str() {
117        assert_eq!(UserIdType::UserId.as_str(), "user_id");
118        assert_eq!(UserIdType::UnionId.as_str(), "union_id");
119        assert_eq!(UserIdType::OpenId.as_str(), "open_id");
120    }
121
122    #[test]
123    fn test_user_id_type_serialization() {
124        let user_id = UserIdType::UserId;
125        let union_id = UserIdType::UnionId;
126        let open_id = UserIdType::OpenId;
127
128        let user_id_json = serde_json::to_string(&user_id).unwrap();
129        let union_id_json = serde_json::to_string(&union_id).unwrap();
130        let open_id_json = serde_json::to_string(&open_id).unwrap();
131
132        assert_eq!(user_id_json, "\"user_id\"");
133        assert_eq!(union_id_json, "\"union_id\"");
134        assert_eq!(open_id_json, "\"open_id\"");
135    }
136
137    #[test]
138    fn test_user_id_type_deserialization() {
139        let user_id_result: UserIdType = serde_json::from_str("\"user_id\"").unwrap();
140        let union_id_result: UserIdType = serde_json::from_str("\"union_id\"").unwrap();
141        let open_id_result: UserIdType = serde_json::from_str("\"open_id\"").unwrap();
142
143        assert_eq!(user_id_result, UserIdType::UserId);
144        assert_eq!(union_id_result, UserIdType::UnionId);
145        assert_eq!(open_id_result, UserIdType::OpenId);
146    }
147
148    #[test]
149    fn test_user_id_type_clone_debug_and_partial_eq() {
150        let id_type = UserIdType::UserId;
151        let cloned_type = id_type.clone();
152
153        assert_eq!(id_type, cloned_type);
154        assert!(format!("{:?}", id_type).contains("UserId"));
155        assert_ne!(UserIdType::UserId, UserIdType::UnionId);
156    }
157
158    #[test]
159    fn test_feed_card_serialization() {
160        let feed_card = FeedCard {
161            card_id: "card123".to_string(),
162            title: Some("Test Card".to_string()),
163            content: Some("Test Content".to_string()),
164            status: Some(FeedCardStatus::Active),
165            create_time: Some("2023-01-01T00:00:00Z".to_string()),
166            update_time: Some("2023-01-02T00:00:00Z".to_string()),
167        };
168
169        let json = serde_json::to_string(&feed_card).unwrap();
170        assert!(json.contains("card123"));
171        assert!(json.contains("Test Card"));
172        assert!(json.contains("Test Content"));
173        assert!(json.contains("active"));
174    }
175
176    #[test]
177    fn test_feed_card_deserialization() {
178        let json = r#"{
179            "card_id": "card123",
180            "title": "Test Card",
181            "content": "Test Content",
182            "status": "active",
183            "create_time": "2023-01-01T00:00:00Z",
184            "update_time": "2023-01-02T00:00:00Z"
185        }"#;
186
187        let feed_card: FeedCard = serde_json::from_str(json).unwrap();
188        assert_eq!(feed_card.card_id, "card123");
189        assert_eq!(feed_card.title, Some("Test Card".to_string()));
190        assert_eq!(feed_card.content, Some("Test Content".to_string()));
191        assert_eq!(feed_card.status, Some(FeedCardStatus::Active));
192        assert_eq!(
193            feed_card.create_time,
194            Some("2023-01-01T00:00:00Z".to_string())
195        );
196        assert_eq!(
197            feed_card.update_time,
198            Some("2023-01-02T00:00:00Z".to_string())
199        );
200    }
201
202    #[test]
203    fn test_feed_card_with_none_values() {
204        let feed_card = FeedCard {
205            card_id: "card456".to_string(),
206            title: None,
207            content: None,
208            status: None,
209            create_time: None,
210            update_time: None,
211        };
212
213        let json = serde_json::to_string(&feed_card).unwrap();
214        let deserialized: FeedCard = serde_json::from_str(&json).unwrap();
215
216        assert_eq!(deserialized.card_id, "card456");
217        assert_eq!(deserialized.title, None);
218        assert_eq!(deserialized.content, None);
219        assert_eq!(deserialized.status, None);
220        assert_eq!(deserialized.create_time, None);
221        assert_eq!(deserialized.update_time, None);
222    }
223
224    #[test]
225    fn test_feed_card_clone_and_debug() {
226        let feed_card = FeedCard {
227            card_id: "card789".to_string(),
228            title: Some("Clone Test".to_string()),
229            content: Some("Clone Content".to_string()),
230            status: Some(FeedCardStatus::Inactive),
231            create_time: Some("2023-01-03T00:00:00Z".to_string()),
232            update_time: Some("2023-01-04T00:00:00Z".to_string()),
233        };
234
235        let cloned_card = feed_card.clone();
236        assert_eq!(feed_card.card_id, cloned_card.card_id);
237        assert_eq!(feed_card.title, cloned_card.title);
238        assert_eq!(feed_card.status, cloned_card.status);
239
240        let debug_output = format!("{:?}", feed_card);
241        assert!(debug_output.contains("card789"));
242        assert!(debug_output.contains("Clone Test"));
243    }
244
245    #[test]
246    fn test_button_info_serialization() {
247        let button = ButtonInfo {
248            button_id: "btn123".to_string(),
249            text: "Click Me".to_string(),
250            button_type: Some("primary".to_string()),
251            action: Some("submit".to_string()),
252        };
253
254        let json = serde_json::to_string(&button).unwrap();
255        assert!(json.contains("btn123"));
256        assert!(json.contains("Click Me"));
257        assert!(json.contains("primary"));
258        assert!(json.contains("submit"));
259    }
260
261    #[test]
262    fn test_button_info_deserialization() {
263        let json = r#"{
264            "button_id": "btn456",
265            "text": "Submit",
266            "button_type": "secondary",
267            "action": "cancel"
268        }"#;
269
270        let button: ButtonInfo = serde_json::from_str(json).unwrap();
271        assert_eq!(button.button_id, "btn456");
272        assert_eq!(button.text, "Submit");
273        assert_eq!(button.button_type, Some("secondary".to_string()));
274        assert_eq!(button.action, Some("cancel".to_string()));
275    }
276
277    #[test]
278    fn test_button_info_with_none_values() {
279        let button = ButtonInfo {
280            button_id: "btn789".to_string(),
281            text: "Basic Button".to_string(),
282            button_type: None,
283            action: None,
284        };
285
286        let json = serde_json::to_string(&button).unwrap();
287        let deserialized: ButtonInfo = serde_json::from_str(&json).unwrap();
288
289        assert_eq!(deserialized.button_id, "btn789");
290        assert_eq!(deserialized.text, "Basic Button");
291        assert_eq!(deserialized.button_type, None);
292        assert_eq!(deserialized.action, None);
293    }
294
295    #[test]
296    fn test_button_info_clone_and_debug() {
297        let button = ButtonInfo {
298            button_id: "btn_clone".to_string(),
299            text: "Clone Test".to_string(),
300            button_type: Some("test".to_string()),
301            action: Some("test_action".to_string()),
302        };
303
304        let cloned_button = button.clone();
305        assert_eq!(button.button_id, cloned_button.button_id);
306        assert_eq!(button.text, cloned_button.text);
307        assert_eq!(button.button_type, cloned_button.button_type);
308        assert_eq!(button.action, cloned_button.action);
309
310        let debug_output = format!("{:?}", button);
311        assert!(debug_output.contains("btn_clone"));
312        assert!(debug_output.contains("Clone Test"));
313    }
314
315    #[test]
316    fn test_timely_notification_serialization() {
317        let notification = TimelyNotification {
318            notification_type: "urgent".to_string(),
319            message: "Important notification".to_string(),
320            target_users: vec!["user1".to_string(), "user2".to_string()],
321        };
322
323        let json = serde_json::to_string(&notification).unwrap();
324        assert!(json.contains("urgent"));
325        assert!(json.contains("Important notification"));
326        assert!(json.contains("user1"));
327        assert!(json.contains("user2"));
328    }
329
330    #[test]
331    fn test_timely_notification_deserialization() {
332        let json = r#"{
333            "notification_type": "reminder",
334            "message": "Meeting in 5 minutes",
335            "target_users": ["alice", "bob", "charlie"]
336        }"#;
337
338        let notification: TimelyNotification = serde_json::from_str(json).unwrap();
339        assert_eq!(notification.notification_type, "reminder");
340        assert_eq!(notification.message, "Meeting in 5 minutes");
341        assert_eq!(notification.target_users, vec!["alice", "bob", "charlie"]);
342    }
343
344    #[test]
345    fn test_timely_notification_with_empty_users() {
346        let notification = TimelyNotification {
347            notification_type: "info".to_string(),
348            message: "System maintenance".to_string(),
349            target_users: vec![],
350        };
351
352        let json = serde_json::to_string(&notification).unwrap();
353        let deserialized: TimelyNotification = serde_json::from_str(&json).unwrap();
354
355        assert_eq!(deserialized.notification_type, "info");
356        assert_eq!(deserialized.message, "System maintenance");
357        assert!(deserialized.target_users.is_empty());
358    }
359
360    #[test]
361    fn test_timely_notification_clone_and_debug() {
362        let notification = TimelyNotification {
363            notification_type: "test".to_string(),
364            message: "Test message".to_string(),
365            target_users: vec!["test_user".to_string()],
366        };
367
368        let cloned_notification = notification.clone();
369        assert_eq!(
370            notification.notification_type,
371            cloned_notification.notification_type
372        );
373        assert_eq!(notification.message, cloned_notification.message);
374        assert_eq!(notification.target_users, cloned_notification.target_users);
375
376        let debug_output = format!("{:?}", notification);
377        assert!(debug_output.contains("test"));
378        assert!(debug_output.contains("Test message"));
379        assert!(debug_output.contains("test_user"));
380    }
381
382    #[test]
383    fn test_timely_notification_with_unicode() {
384        let notification = TimelyNotification {
385            notification_type: "提醒".to_string(),
386            message: "会议将在5分钟后开始".to_string(),
387            target_users: vec!["张三".to_string(), "李四".to_string()],
388        };
389
390        let json = serde_json::to_string(&notification).unwrap();
391        let deserialized: TimelyNotification = serde_json::from_str(&json).unwrap();
392
393        assert_eq!(deserialized.notification_type, "提醒");
394        assert_eq!(deserialized.message, "会议将在5分钟后开始");
395        assert_eq!(deserialized.target_users, vec!["张三", "李四"]);
396    }
397
398    #[test]
399    fn test_complex_feed_card_status_combinations() {
400        let test_cases = vec![
401            (FeedCardStatus::Active, "active"),
402            (FeedCardStatus::Inactive, "inactive"),
403        ];
404
405        for (status, expected_str) in test_cases {
406            let json = serde_json::to_string(&status).unwrap();
407            assert_eq!(json, format!("\"{}\"", expected_str));
408
409            let deserialized: FeedCardStatus = serde_json::from_str(&json).unwrap();
410            assert_eq!(deserialized, status);
411        }
412    }
413
414    #[test]
415    fn test_all_user_id_types() {
416        let types = vec![UserIdType::UserId, UserIdType::UnionId, UserIdType::OpenId];
417
418        for user_type in types {
419            let json = serde_json::to_string(&user_type).unwrap();
420            let deserialized: UserIdType = serde_json::from_str(&json).unwrap();
421            assert_eq!(deserialized, user_type);
422
423            // Test as_str method
424            let str_value = user_type.as_str();
425            assert!(!str_value.is_empty());
426            assert!(str_value.contains("_id") || str_value == "open_id");
427        }
428    }
429}