botx_api/api/v4/notification/direct/
models.rs

1use std::collections::HashMap;
2
3use serde::{Serialize, Deserialize};
4use uuid::Uuid;
5
6use crate::api::models::*;
7
8#[derive(Debug, Serialize, Deserialize, Clone)]
9pub struct DirectNotificationResponse {
10    /// Идентификатор отправляемого сообщения (тут или в result, не известно от чего зависит)
11    pub sync_id: Option<Uuid>,
12    pub result: DirectNotificationResult,
13}
14
15#[derive(Debug, Serialize, Deserialize, Clone)]
16pub struct DirectNotificationResult {
17    /// Идентификатор отправляемого сообщения (тут или на уровень выше, не известно от чего зависит)
18    pub sync_id: Option<Uuid>,
19}
20
21#[derive(Debug, Serialize, Deserialize, Clone)]
22#[serde(tag = "reason")]
23pub enum DirectNotificationExpressError {
24    #[serde(rename(serialize = "chat_not_found", deserialize = "chat_not_found"))]
25    ChatNotFound(ChatNotFoundWithEventId),
26    #[serde(rename(serialize = "error_from_messaging_service", deserialize = "error_from_messaging_service"))]
27    ErrorFromMessagingService(ErrorFromMessagingServiceWithEventId),
28    #[serde(rename(serialize = "bot_is_not_a_chat_member", deserialize = "bot_is_not_a_chat_member"))]
29    BotIsNotAChatMember(BotIsNotAChatMember),
30    #[serde(rename(serialize = "stealth_mode_disabled", deserialize = "stealth_mode_disabled"))]
31    StealthModeDisabled(StealthModeDisabled),
32    #[serde(rename(serialize = "event_recipients_list_is_empty", deserialize = "event_recipients_list_is_empty"))]
33    EventRecipientsListIsEmpty(EventRecipientsListIsEmpty),
34    #[serde(rename(serialize = "flow_processing_error", deserialize = "flow_processing_error"))]
35    FlowProcessingError(FlowProcessingError),
36    #[serde(rename(serialize = "unexpected_error", deserialize = "unexpected_error"))]
37    UnexpectedError(UnexpectedError),
38
39    // TODO: добавить десериализацию в HashMap<string, string> когда завезут реализацию
40    #[serde(other)]
41    Other,
42}
43
44#[derive(Debug, Serialize, Deserialize, Clone)]
45pub struct StealthModeDisabled {
46    pub sync_id: Uuid,
47    pub errors: Vec<String>,
48    pub error_data: StealthModeDisabledData,
49}
50
51#[derive(Debug, Serialize, Deserialize, Clone)]
52pub struct StealthModeDisabledData {
53    pub group_chat_id: Uuid,
54    pub bot_id: Uuid,
55    pub error_description: String,
56}
57
58#[derive(Debug, Serialize, Deserialize, Clone)]
59pub struct FlowProcessingError {
60    pub sync_id: Uuid,
61    pub errors: Vec<String>,
62    pub error_data: FlowProcessingErrorData,
63}
64
65#[derive(Debug, Serialize, Deserialize, Clone)]
66pub struct FlowProcessingErrorData {
67    pub error_description: String,
68}
69
70#[derive(Debug, Serialize, Deserialize, Clone)]
71pub struct UnexpectedError {
72    pub sync_id: Uuid,
73    pub errors: Vec<String>,
74    pub error_data: UnexpectedErrorData,
75}
76
77#[derive(Debug, Serialize, Deserialize, Clone)]
78pub struct UnexpectedErrorData {
79    pub error_description: String,
80}
81
82#[derive(Debug, Serialize, Deserialize, Clone)]
83pub struct DirectNotificationExpressErrorData {
84
85    pub bot_id: Option<Uuid>,
86
87    pub group_chat_id: Option<Uuid>,
88
89    /// Ожидается что будет всегда, но на всякий случай сделан опциональным
90    pub error_description: Option<String>,
91
92    pub reason: Option<String>,
93
94    pub recipients_param: Option<Vec<Uuid>>,
95
96    #[serde(flatten)]
97    pub other: HashMap<String, String>,
98}
99
100#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder)]
101#[builder(setter(into, prefix = "with", strip_option))]
102pub struct DirectNotificationRequest {
103    /// идентификатор чата в который придет сообщение
104    pub group_chat_id: Uuid,
105    
106    /// (Default: null) - huid получателей события. По умолчанию все участники чата
107    // #[serde(skip_serializing_if = "Option::is_none")]
108    #[builder(default)]
109    pub recipients: Option<Vec<Uuid>>,
110
111    /// Базовая часть нотификации
112    #[builder(default)]
113    pub notification: EventPayload,
114
115    /// (Default: null) - файл в base64 представление.
116    // #[serde(skip_serializing_if = "Option::is_none")]
117    #[builder(default)]
118    pub file: Option<File>,
119
120    /// опции запроса
121    #[builder(default)]
122    pub opts: PayloadOptions,
123}
124
125#[cfg(test)]
126mod tests {
127    use crate::api::result::{ExpressResult, BotXApiResult, BotXApiError};
128
129    use super::{DirectNotificationResponse, DirectNotificationExpressError};
130
131    #[test]
132    fn deserialize_result_ok()
133    {
134        let res = serde_json::from_str::<ExpressResult<DirectNotificationResponse, DirectNotificationExpressError>>(r#"{
135            "status": "ok",
136            "result": {
137              "sync_id": "f0f105d2-101f-59b0-9e10-e432efce2c36"
138            }
139          }"#).unwrap();
140
141        let res: BotXApiResult<DirectNotificationResponse, DirectNotificationExpressError> = res.into();
142        let res = res.ok().unwrap();
143
144        assert_eq!(res.result.sync_id.unwrap(), uuid::Uuid::parse_str("f0f105d2-101f-59b0-9e10-e432efce2c36").unwrap())
145    }
146
147    #[test]
148    fn deserialize_error_chat_not_found_ok()
149    {
150        let res = serde_json::from_str::<ExpressResult<DirectNotificationResponse, DirectNotificationExpressError>>(r#"{
151            "sync_id": "f0f105d2-101f-59b0-9e10-e432efce2c36",
152            "status": "error",
153            "reason": "chat_not_found",
154            "errors": [],
155            "error_data": {
156              "group_chat_id": "705df263-6bfd-536a-9d51-13524afaab5c",
157              "error_description": "Chat with specified id not found"
158            }
159          }"#).unwrap();
160
161        let res: BotXApiResult<DirectNotificationResponse, DirectNotificationExpressError> = res.into();
162        let err = res.err().unwrap();
163
164        let BotXApiError::ExpressError(err) = err else {
165            panic!("Некорректное десериализация ошибки {:#?}", err);
166        };
167
168        let DirectNotificationExpressError::ChatNotFound(err) = err else {
169            panic!("Некорректное определение типа ошибки");
170        };
171
172        assert_eq!(err.error_data.group_chat_id, uuid::Uuid::parse_str("705df263-6bfd-536a-9d51-13524afaab5c").unwrap())
173    }
174
175    #[test]
176    fn deserialize_error_error_from_messaging_service_ok()
177    {
178        let res = serde_json::from_str::<ExpressResult<DirectNotificationResponse, DirectNotificationExpressError>>(r#"{
179            "sync_id": "f0f105d2-101f-59b0-9e10-e432efce2c36",
180            "status": "error",
181            "reason": "error_from_messaging_service",
182            "errors": [],
183            "error_data": {
184              "group_chat_id": "705df263-6bfd-536a-9d51-13524afaab5c",
185              "reason": "some_error",
186              "error_description": "Messaging service returns error. Check BotX container logs (level :warn or upper) for more info."
187            }
188          }"#).unwrap();
189
190        let res: BotXApiResult<DirectNotificationResponse, DirectNotificationExpressError> = res.into();
191        let err = res.err().unwrap();
192
193        let BotXApiError::ExpressError(err) = err else {
194            panic!("Некорректное десериализация ошибки {:#?}", err);
195        };
196
197        let DirectNotificationExpressError::ErrorFromMessagingService(err) = err else {
198            panic!("Некорректное определение типа ошибки");
199        };
200
201        assert_eq!(err.error_data.group_chat_id, uuid::Uuid::parse_str("705df263-6bfd-536a-9d51-13524afaab5c").unwrap())
202    }
203
204    #[test]
205    fn deserialize_error_bot_is_not_a_chat_member_ok()
206    {
207        let res = serde_json::from_str::<ExpressResult<DirectNotificationResponse, DirectNotificationExpressError>>(r#"{
208            "sync_id": "f0f105d2-101f-59b0-9e10-e432efce2c36",
209            "status": "error",
210            "reason": "bot_is_not_a_chat_member",
211            "errors": [],
212            "error_data": {
213              "group_chat_id": "705df263-6bfd-536a-9d51-13524afaab5c",
214              "bot_id": "b165f00f-3154-412c-7f11-c120164257da",
215              "error_description": "Bot is not a chat member"
216            }
217          }"#).unwrap();
218
219        let res: BotXApiResult<DirectNotificationResponse, DirectNotificationExpressError> = res.into();
220        let err = res.err().unwrap();
221
222        let BotXApiError::ExpressError(err) = err else {
223            panic!("Некорректное десериализация ошибки {:#?}", err);
224        };
225
226        let DirectNotificationExpressError::BotIsNotAChatMember(err) = err else {
227            panic!("Некорректное определение типа ошибки");
228        };
229
230        assert_eq!(err.error_data.group_chat_id, uuid::Uuid::parse_str("705df263-6bfd-536a-9d51-13524afaab5c").unwrap())
231    }
232
233    #[test]
234    fn deserialize_error_stealth_mode_disabled_ok()
235    {
236        let res = serde_json::from_str::<ExpressResult<DirectNotificationResponse, DirectNotificationExpressError>>(r#"{
237            "sync_id": "f0f105d2-101f-59b0-9e10-e432efce2c36",
238            "status": "error",
239            "reason": "stealth_mode_disabled",
240            "errors": [],
241            "error_data": {
242              "group_chat_id": "705df263-6bfd-536a-9d51-13524afaab5c",
243              "bot_id": "b165f00f-3154-412c-7f11-c120164257da",
244              "error_description": "Stealth mode disabled in specified chat"
245            }
246          }"#).unwrap();
247
248        let res: BotXApiResult<DirectNotificationResponse, DirectNotificationExpressError> = res.into();
249        let err = res.err().unwrap();
250
251        let BotXApiError::ExpressError(err) = err else {
252            panic!("Некорректное десериализация ошибки {:#?}", err);
253        };
254
255        let DirectNotificationExpressError::StealthModeDisabled(err) = err else {
256            panic!("Некорректное определение типа ошибки");
257        };
258
259        assert_eq!(err.error_data.group_chat_id, uuid::Uuid::parse_str("705df263-6bfd-536a-9d51-13524afaab5c").unwrap())
260    }
261
262    #[test]
263    fn deserialize_error_event_recipients_list_is_empty_ok()
264    {
265        let res = serde_json::from_str::<ExpressResult<DirectNotificationResponse, DirectNotificationExpressError>>(r#"{
266            "sync_id": "f0f105d2-101f-59b0-9e10-e432efce2c36",
267            "status": "error",
268            "reason": "event_recipients_list_is_empty",
269            "errors": [],
270            "error_data": {
271              "group_chat_id": "705df263-6bfd-536a-9d51-13524afaab5c",
272              "bot_id": "b165f00f-3154-412c-7f11-c120164257da",
273              "recipients_param": ["b165f00f-3154-412c-7f11-c120164257da"],
274              "error_description": "Event recipients list is empty"
275            }
276          }"#).unwrap();
277
278        let res: BotXApiResult<DirectNotificationResponse, DirectNotificationExpressError> = res.into();
279        let err = res.err().unwrap();
280
281        let BotXApiError::ExpressError(err) = err else {
282            panic!("Некорректное десериализация ошибки");
283        };
284
285        let DirectNotificationExpressError::EventRecipientsListIsEmpty(err) = err else {
286            panic!("Некорректное определение типа ошибки {:#?}", err);
287        };
288
289        assert_eq!(err.error_data.bot_id, uuid::Uuid::parse_str("b165f00f-3154-412c-7f11-c120164257da").unwrap())
290    }
291
292    #[test]
293    fn deserialize_error_flow_processing_error_ok()
294    {
295        let res = serde_json::from_str::<ExpressResult<DirectNotificationResponse, DirectNotificationExpressError>>(r#"{
296            "sync_id": "f0f105d2-101f-59b0-9e10-e432efce2c36",
297            "status": "error",
298            "reason": "flow_processing_error",
299            "errors": ["{error1}", "{error2}"],
300            "error_data": {
301              "error_description": "Got error on flow processing. Check BotX container logs (level :info or upper) for more info"
302            }
303          }"#).unwrap();
304
305        let res: BotXApiResult<DirectNotificationResponse, DirectNotificationExpressError> = res.into();
306        let err = res.err().unwrap();
307
308        let BotXApiError::ExpressError(err) = err else {
309            panic!("Некорректное десериализация ошибки {:#?}", err);
310        };
311
312        let DirectNotificationExpressError::FlowProcessingError(err) = err else {
313            panic!("Некорректное определение типа ошибки");
314        };
315
316        assert_eq!(err.error_data.error_description, "Got error on flow processing. Check BotX container logs (level :info or upper) for more info".to_string())
317    }
318
319    #[test]
320    fn deserialize_error_unexpected_error_ok()
321    {
322        let res = serde_json::from_str::<ExpressResult<DirectNotificationResponse, DirectNotificationExpressError>>(r#"{
323            "sync_id": "f0f105d2-101f-59b0-9e10-e432efce2c36",
324            "status": "error",
325            "reason": "unexpected_error",
326            "errors": ["{error1}", "{error2}"],
327            "error_data": {
328              "error_description": "Got unexpected error. Check BotX container logs (level :error or upper) for more info"
329            }
330          }"#).unwrap();
331
332        let res: BotXApiResult<DirectNotificationResponse, DirectNotificationExpressError> = res.into();
333        let err = res.err().unwrap();
334
335        let BotXApiError::ExpressError(err) = err else {
336            panic!("Некорректное десериализация ошибки {:#?}", err);
337        };
338
339        let DirectNotificationExpressError::UnexpectedError(err) = err else {
340            panic!("Некорректное определение типа ошибки");
341        };
342
343        assert_eq!(err.error_data.error_description, "Got unexpected error. Check BotX container logs (level :error or upper) for more info".to_string())
344    }
345}