1use crate::api::BotApi;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::str::FromStr;
10
11#[derive(Debug, Clone, Serialize)]
13pub struct GroupManageEvent {
14 #[serde(skip)]
16 api: BotApi,
17 pub event_id: Option<String>,
19 pub timestamp: Option<u64>,
21 pub group_openid: Option<String>,
23 pub op_member_openid: Option<String>,
25}
26
27impl GroupManageEvent {
28 pub fn new(
36 api: BotApi,
37 event_id: Option<String>,
38 data: &HashMap<String, serde_json::Value>,
39 ) -> Self {
40 Self {
41 api,
42 event_id,
43 timestamp: data.get("timestamp").and_then(|v| v.as_u64()),
44 group_openid: data
45 .get("group_openid")
46 .and_then(|v| v.as_str())
47 .map(String::from),
48 op_member_openid: data
49 .get("op_member_openid")
50 .and_then(|v| v.as_str())
51 .map(String::from),
52 }
53 }
54
55 pub fn api(&self) -> &BotApi {
57 &self.api
58 }
59
60 pub fn formatted_timestamp(&self) -> Option<String> {
62 self.timestamp.map(|ts| {
63 let datetime = chrono::DateTime::from_timestamp(ts as i64, 0).unwrap_or_default();
64 datetime.format("%Y-%m-%d %H:%M:%S").to_string()
65 })
66 }
67}
68
69impl std::fmt::Display for GroupManageEvent {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 write!(
72 f,
73 "GroupManageEvent {{ event_id: {:?}, timestamp: {:?}, group_openid: {:?}, op_member_openid: {:?} }}",
74 self.event_id, self.timestamp, self.group_openid, self.op_member_openid
75 )
76 }
77}
78
79#[derive(Debug, Clone, Serialize)]
81pub struct C2CManageEvent {
82 #[serde(skip)]
84 api: BotApi,
85 pub event_id: Option<String>,
87 pub timestamp: Option<u64>,
89 pub openid: Option<String>,
91 pub nick: Option<String>,
93 pub avatar: Option<String>,
95}
96
97pub type C2CFriendData = C2CManageEvent;
98
99impl C2CManageEvent {
100 pub fn new(
108 api: BotApi,
109 event_id: Option<String>,
110 data: &HashMap<String, serde_json::Value>,
111 ) -> Self {
112 Self {
113 api,
114 event_id,
115 timestamp: data.get("timestamp").and_then(|v| v.as_u64()),
116 openid: data
117 .get("openid")
118 .and_then(|v| v.as_str())
119 .map(String::from),
120 nick: data.get("nick").and_then(|v| v.as_str()).map(String::from),
121 avatar: data
122 .get("avatar")
123 .and_then(|v| v.as_str())
124 .map(String::from),
125 }
126 }
127
128 pub fn api(&self) -> &BotApi {
130 &self.api
131 }
132
133 pub fn formatted_timestamp(&self) -> Option<String> {
135 self.timestamp.map(|ts| {
136 let datetime = chrono::DateTime::from_timestamp(ts as i64, 0).unwrap_or_default();
137 datetime.format("%Y-%m-%d %H:%M:%S").to_string()
138 })
139 }
140}
141
142impl std::fmt::Display for C2CManageEvent {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 write!(
145 f,
146 "C2CManageEvent {{ event_id: {:?}, timestamp: {:?}, openid: {:?}, nick: {:?}, avatar: {:?} }}",
147 self.event_id, self.timestamp, self.openid, self.nick, self.avatar
148 )
149 }
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize, Default)]
154pub struct EnterAioEvent {
155 pub user_openid: Option<String>,
157 pub from_source: Option<String>,
159 #[serde(skip)]
161 pub event_id: Option<String>,
162}
163
164pub type EnterAIO = EnterAioEvent;
165
166impl EnterAioEvent {
167 pub fn new(event_id: Option<String>, data: &serde_json::Value) -> Self {
169 Self {
170 user_openid: data
171 .get("user_openid")
172 .and_then(|v| v.as_str())
173 .map(String::from),
174 from_source: data
175 .get("from_source")
176 .and_then(|v| v.as_str())
177 .map(String::from),
178 event_id,
179 }
180 }
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize, Default)]
185pub struct SubscribeMessageStatusData {
186 pub group_openid: Option<String>,
188 pub openid: Option<String>,
190 #[serde(default)]
192 pub result: Vec<SubscribeMsgTemplateResult>,
193 #[serde(skip)]
195 pub event_id: Option<String>,
196}
197
198impl SubscribeMessageStatusData {
199 pub fn new(event_id: Option<String>, data: &serde_json::Value) -> Self {
201 let mut event = serde_json::from_value::<Self>(data.clone()).unwrap_or_default();
202 event.event_id = event_id;
203 event
204 }
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize, Default)]
209pub struct SubscribeMsgTemplateResult {
210 pub template_id: Option<i32>,
212 pub custom_template_id: Option<String>,
214 pub op: Option<u32>,
216 pub subscribe_id: Option<String>,
218 pub update_ts: Option<u64>,
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
224pub enum ManageEventType {
225 GroupAddRobot,
227 GroupDelRobot,
229 GroupMsgReject,
231 GroupMsgReceive,
233 FriendAdd,
235 FriendDel,
237 C2CMsgReject,
239 C2CMsgReceive,
241}
242
243impl ManageEventType {
244 pub fn as_str(&self) -> &'static str {
246 match self {
247 Self::GroupAddRobot => "group_add_robot",
248 Self::GroupDelRobot => "group_del_robot",
249 Self::GroupMsgReject => "group_msg_reject",
250 Self::GroupMsgReceive => "group_msg_receive",
251 Self::FriendAdd => "friend_add",
252 Self::FriendDel => "friend_del",
253 Self::C2CMsgReject => "c2c_msg_reject",
254 Self::C2CMsgReceive => "c2c_msg_receive",
255 }
256 }
257
258 pub fn is_group_event(&self) -> bool {
260 matches!(
261 self,
262 Self::GroupAddRobot
263 | Self::GroupDelRobot
264 | Self::GroupMsgReject
265 | Self::GroupMsgReceive
266 )
267 }
268
269 pub fn is_c2c_event(&self) -> bool {
271 matches!(
272 self,
273 Self::FriendAdd | Self::FriendDel | Self::C2CMsgReject | Self::C2CMsgReceive
274 )
275 }
276}
277
278impl FromStr for ManageEventType {
279 type Err = ();
280
281 fn from_str(s: &str) -> Result<Self, Self::Err> {
282 match s {
283 "group_add_robot" => Ok(Self::GroupAddRobot),
284 "group_del_robot" => Ok(Self::GroupDelRobot),
285 "group_msg_reject" => Ok(Self::GroupMsgReject),
286 "group_msg_receive" => Ok(Self::GroupMsgReceive),
287 "friend_add" => Ok(Self::FriendAdd),
288 "friend_del" => Ok(Self::FriendDel),
289 "c2c_msg_reject" => Ok(Self::C2CMsgReject),
290 "c2c_msg_receive" => Ok(Self::C2CMsgReceive),
291 _ => Err(()),
292 }
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
301 fn test_manage_event_type_from_str() {
302 assert_eq!(
303 "group_add_robot".parse::<ManageEventType>(),
304 Ok(ManageEventType::GroupAddRobot)
305 );
306 assert_eq!(
307 "friend_add".parse::<ManageEventType>(),
308 Ok(ManageEventType::FriendAdd)
309 );
310 assert_eq!("invalid".parse::<ManageEventType>(), Err(()));
311 }
312
313 #[test]
314 fn test_manage_event_type_as_str() {
315 assert_eq!(ManageEventType::GroupAddRobot.as_str(), "group_add_robot");
316 assert_eq!(ManageEventType::FriendAdd.as_str(), "friend_add");
317 }
318
319 #[test]
320 fn test_is_group_event() {
321 assert!(ManageEventType::GroupAddRobot.is_group_event());
322 assert!(!ManageEventType::FriendAdd.is_group_event());
323 }
324
325 #[test]
326 fn test_is_c2c_event() {
327 assert!(ManageEventType::FriendAdd.is_c2c_event());
328 assert!(!ManageEventType::GroupAddRobot.is_c2c_event());
329 }
330}