Skip to main content

zero_bounce/utility/structures/
generic.rs

1use chrono::NaiveDate;
2use serde::Deserialize;
3
4use crate::utility::structures::custom_deserialize::deserialize_only_date;
5use crate::utility::structures::custom_deserialize::deserialize_stringified_uint;
6
7#[derive(Clone, Debug, Deserialize)]
8pub struct ApiUsage {
9    pub total: u64,
10    pub status_valid: u64,
11    pub status_invalid: u64,
12    pub status_catch_all: u64,
13    pub status_do_not_mail: u64,
14    pub status_spamtrap: u64,
15    pub status_unknown: u64,
16    pub sub_status_toxic: u64,
17    pub sub_status_disposable: u64,
18    pub sub_status_role_based: u64,
19    pub sub_status_possible_trap: u64,
20    pub sub_status_global_suppression: u64,
21    pub sub_status_timeout_exceeded: u64,
22    pub sub_status_mail_server_temporary_error: u64,
23    pub sub_status_mail_server_did_not_respond: u64,
24    pub sub_status_greylisted: u64,
25    pub sub_status_antispam_system: u64,
26    pub sub_status_does_not_accept_mail: u64,
27    pub sub_status_exception_occurred: u64,
28    pub sub_status_failed_syntax_check: u64,
29    pub sub_status_mailbox_not_found: u64,
30    pub sub_status_unroutable_ip_address: u64,
31    pub sub_status_possible_typo: u64,
32    pub sub_status_no_dns_entries: u64,
33    pub sub_status_role_based_catch_all: u64,
34    pub sub_status_accept_all: u64,
35    pub sub_status_mailbox_quota_exceeded: u64,
36    pub sub_status_forcible_disconnect: u64,
37    pub sub_status_failed_smtp_connection: u64,
38    pub sub_status_mx_forward: u64,
39    pub sub_status_alternate: u64,
40    pub sub_status_allowed: u64,
41    pub sub_status_blocked: u64,
42    pub sub_status_gold: u64,
43    pub sub_status_role_based_accept_all: u64,
44
45    #[serde(deserialize_with="deserialize_only_date")]
46    pub start_date: NaiveDate,
47
48    #[serde(deserialize_with="deserialize_only_date")]
49    pub end_date: NaiveDate,
50}
51
52#[derive(Clone, Debug, Deserialize)]
53pub struct ActivityData {
54    pub found: bool,
55
56    #[serde(deserialize_with="deserialize_stringified_uint")]
57    pub active_in_days: Option<u128>,
58}
59
60#[derive(Clone, Debug, Deserialize)]
61pub struct DomainFormats {
62    pub format: String,
63    pub confidence: String,
64}
65
66#[derive(Clone, Debug, Deserialize)]
67pub struct FindEmailResponse {
68    pub email: String,
69    pub domain: String,
70    pub format: String,
71    pub status: String,
72    pub sub_status: String,
73    pub confidence: String,
74    pub did_you_mean: String,
75    pub failure_reason: String,
76    pub other_domain_formats: Vec<DomainFormats>,
77}
78
79/// Response structure for the new find_email_v2 API endpoint.
80/// This structure matches the new API response format which includes
81/// `email_confidence` and `company_name` fields.
82#[derive(Clone, Debug, Deserialize)]
83pub struct FindEmailResponseV2 {
84    pub email: String,
85    #[serde(default)]
86    pub domain: String,
87    #[serde(rename = "email_confidence", default)]
88    pub confidence: String,
89    #[serde(default)]
90    pub company_name: String,
91    #[serde(default)]
92    pub did_you_mean: String,
93    #[serde(default)]
94    pub failure_reason: String,
95}
96
97/// Response structure for the new domain_search_v2 API endpoint.
98/// This structure matches the domain search API response format which includes
99/// `format`, `confidence`, and `other_domain_formats` fields.
100#[derive(Clone, Debug, Deserialize)]
101pub struct DomainSearchResponseV2 {
102    #[serde(default)]
103    pub domain: String,
104    #[serde(default)]
105    pub company_name: String,
106    #[serde(default)]
107    pub format: String,
108    #[serde(default)]
109    pub confidence: String,
110    #[serde(default)]
111    pub did_you_mean: String,
112    #[serde(default)]
113    pub failure_reason: String,
114    #[serde(default)]
115    pub other_domain_formats: Vec<DomainFormats>,
116}
117
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122    use crate::utility::mock_constants::API_USAGE_RESPONSE;
123    use crate::utility::mock_constants::ACTIVITY_DATA_RESPONSE_ACTIVE;
124    use crate::utility::mock_constants::ACTIVITY_DATA_RESPONSE_INACTIVE;
125    use crate::utility::mock_constants::MOCK_FIND_MAIL_INVALID;
126    use crate::utility::mock_constants::MOCK_FIND_MAIL_VALID;
127
128    #[test]
129    fn parse_activity_date_without_amount() {
130        let activity_data_res = serde_json::from_str::<ActivityData>(
131            ACTIVITY_DATA_RESPONSE_INACTIVE
132        );
133        assert!(activity_data_res.is_ok(), "error: {}", activity_data_res.unwrap_err());
134
135        let activity_data = activity_data_res.unwrap();
136        assert_eq!(activity_data.found, false);
137        assert_eq!(activity_data.active_in_days, None);
138    }
139
140    #[test]
141    fn parse_activity_date_with_amount() {
142        let activity_data_res: serde_json::Result<ActivityData> = serde_json::from_str(ACTIVITY_DATA_RESPONSE_ACTIVE);
143        assert!(activity_data_res.is_ok());
144
145        let activity_data = activity_data_res.unwrap();
146        assert_eq!(activity_data.found, true);
147        assert_eq!(activity_data.active_in_days, Some(180));
148    }
149
150    #[test]
151    fn parse_api_usage() {
152        let api_usage: serde_json::Result<ApiUsage> = serde_json::from_str(API_USAGE_RESPONSE);
153        assert!(api_usage.is_ok());
154
155        let api_usage_obj = api_usage.unwrap();
156        let expected_start_date = NaiveDate::from_ymd_opt(2010, 1, 12).unwrap();
157        let expected_end_date = NaiveDate::from_ymd_opt(2030, 12, 1).unwrap();
158        assert_eq!(api_usage_obj.start_date, expected_start_date);
159        assert_eq!(api_usage_obj.end_date, expected_end_date);
160    }
161
162    #[test]
163    fn parse_find_mail_invalid_status() {
164        let find_mail: serde_json::Result<FindEmailResponse> = serde_json::from_str(MOCK_FIND_MAIL_INVALID);
165        assert!(find_mail.is_ok());
166
167        let find_mail_object = find_mail.unwrap();
168        assert_eq!(find_mail_object.email, "");
169        assert_eq!(find_mail_object.other_domain_formats.len(), 0);
170    }
171
172    #[test]
173    fn parse_find_mail_valid_status() {
174        let find_mail: serde_json::Result<FindEmailResponse> = serde_json::from_str(MOCK_FIND_MAIL_VALID);
175        assert!(find_mail.is_ok());
176
177        let find_mail_object = find_mail.unwrap();
178        assert_eq!(find_mail_object.email, "john.doe@example.com");
179        assert_eq!(find_mail_object.other_domain_formats.len(), 2);
180        assert_eq!(find_mail_object.other_domain_formats[0].confidence, "high");
181        assert_eq!(find_mail_object.other_domain_formats[1].confidence, "medium");
182    }
183
184
185}