Skip to main content

babelforce_manager_sdk/resources/
outbound.rs

1use crate::error::{map_manager_err, ManagerError};
2use crate::gen::manager::apis::configuration::Configuration;
3use crate::gen::manager::apis::{call_api, dialer_api, outbound_api as api, reporting_call_api};
4use crate::gen::manager::models;
5use crate::http::collect_all;
6use crate::retry::{with_retry, RetryPolicy};
7use crate::token::SharedCfg;
8
9/// Outbound lists & leads — `/api/v2/outbound/lists`.
10pub struct OutboundResource {
11    pub(crate) cfg: SharedCfg<Configuration>,
12    pub(crate) retry: RetryPolicy,
13}
14
15impl OutboundResource {
16    /// List the outbound lists.
17    pub async fn lists(&self) -> Result<Vec<models::OutboundList>, ManagerError> {
18        let cfg = self.cfg.get().await?;
19        let cfg = cfg.as_ref();
20        let resp = with_retry(&self.retry, true, || api::list_outbound_lists(cfg))
21            .await
22            .map_err(map_manager_err)?;
23        Ok(resp.items)
24    }
25
26    /// Create an outbound list.
27    pub async fn create_list(
28        &self,
29        body: models::CreateOutboundListRequest,
30    ) -> Result<models::OutboundListItemResponse, ManagerError> {
31        let cfg = self.cfg.get().await?;
32        let cfg = cfg.as_ref();
33        with_retry(&self.retry, false, || {
34            api::create_outbound_list(cfg, Some(body.clone()))
35        })
36        .await
37        .map_err(map_manager_err)
38    }
39
40    /// Clear all leads from an outbound list; returns the updated list.
41    pub async fn clear_list(
42        &self,
43        id: &str,
44    ) -> Result<models::OutboundListItemResponse, ManagerError> {
45        let cfg = self.cfg.get().await?;
46        let cfg = cfg.as_ref();
47        with_retry(&self.retry, false, || api::clear_outbound_list(cfg, id))
48            .await
49            .map_err(map_manager_err)
50    }
51
52    /// Add a lead to an outbound list.
53    pub async fn add_lead(
54        &self,
55        list_id: &str,
56        body: models::AddOutboundLeadRequest,
57    ) -> Result<models::OutboundLeadItemResponse, ManagerError> {
58        let cfg = self.cfg.get().await?;
59        let cfg = cfg.as_ref();
60        with_retry(&self.retry, false, || {
61            api::add_outbound_lead(cfg, list_id, Some(body.clone()))
62        })
63        .await
64        .map_err(map_manager_err)
65    }
66
67    /// Update a lead on an outbound list.
68    pub async fn update_lead(
69        &self,
70        list_id: &str,
71        lead_id: &str,
72        body: models::AddOutboundLeadRequest,
73    ) -> Result<models::OutboundLeadItemResponse, ManagerError> {
74        let cfg = self.cfg.get().await?;
75        let cfg = cfg.as_ref();
76        with_retry(&self.retry, false, || {
77            dialer_api::update_outbound_lead(cfg, list_id, lead_id, Some(body.clone()))
78        })
79        .await
80        .map_err(map_manager_err)
81    }
82
83    /// Delete a lead from an outbound list.
84    pub async fn delete_lead(&self, list_id: &str, lead_id: &str) -> Result<(), ManagerError> {
85        let cfg = self.cfg.get().await?;
86        let cfg = cfg.as_ref();
87        with_retry(&self.retry, false, || {
88            dialer_api::delete_outbound_lead(cfg, list_id, lead_id)
89        })
90        .await
91        .map_err(map_manager_err)?;
92        Ok(())
93    }
94
95    /// Place an outbound call on behalf of an agent.
96    pub async fn create_agent_call(
97        &self,
98        id: &str,
99        body: models::AgentOutboundCallRequest,
100    ) -> Result<models::CallItemResponse, ManagerError> {
101        let cfg = self.cfg.get().await?;
102        let cfg = cfg.as_ref();
103        with_retry(&self.retry, false, || {
104            call_api::create_agent_outbound_call(cfg, id, body.clone())
105        })
106        .await
107        .map_err(map_manager_err)
108    }
109
110    /// The simple outbound call report, collecting every call across pages.
111    pub async fn simple_reporting(&self) -> Result<Vec<models::ReportingCall>, ManagerError> {
112        let cfg = self.cfg.get().await?;
113        let cfg = cfg.as_ref();
114        collect_all(&self.retry, map_manager_err, |page| async move {
115            let r = reporting_call_api::list_outbound_simple_reporting_calls(cfg, Some(page), None)
116                .await?;
117            Ok((
118                r.items,
119                r.pagination.pages.unwrap_or(1),
120                r.pagination.current.unwrap_or(1),
121            ))
122        })
123        .await
124    }
125
126    /// List outbound dial attempts, collecting every attempt across pages.
127    pub async fn attempts(&self) -> Result<Vec<models::CallAttempt>, ManagerError> {
128        let cfg = self.cfg.get().await?;
129        let cfg = cfg.as_ref();
130        collect_all(&self.retry, map_manager_err, |page| async move {
131            let r =
132                api::list_outbound_attempts(cfg, Some(page), None, None, None, None, None).await?;
133            Ok((
134                r.items,
135                r.pagination.pages.unwrap_or(1),
136                r.pagination.current.unwrap_or(1),
137            ))
138        })
139        .await
140    }
141
142    /// List outbound leads, collecting every lead across pages.
143    pub async fn leads(&self) -> Result<Vec<models::Lead>, ManagerError> {
144        let cfg = self.cfg.get().await?;
145        let cfg = cfg.as_ref();
146        collect_all(&self.retry, map_manager_err, |page| async move {
147            let r = api::list_outbound_leads(cfg, Some(page), None, None, None).await?;
148            Ok((
149                r.items,
150                r.pagination.pages.unwrap_or(1),
151                r.pagination.current.unwrap_or(1),
152            ))
153        })
154        .await
155    }
156
157    /// List processed outbound leads, collecting every lead across pages.
158    pub async fn processed_leads(&self) -> Result<Vec<models::Lead>, ManagerError> {
159        let cfg = self.cfg.get().await?;
160        let cfg = cfg.as_ref();
161        collect_all(&self.retry, map_manager_err, |page| async move {
162            let r = api::list_processed_outbound_leads(cfg, Some(page), None).await?;
163            Ok((
164                r.items,
165                r.pagination.pages.unwrap_or(1),
166                r.pagination.current.unwrap_or(1),
167            ))
168        })
169        .await
170    }
171
172    /// Get a single outbound list.
173    pub async fn get_list(&self, id: &str) -> Result<models::LeadListItemResponse, ManagerError> {
174        let cfg = self.cfg.get().await?;
175        let cfg = cfg.as_ref();
176        with_retry(&self.retry, true, || api::get_outbound_list(cfg, id))
177            .await
178            .map_err(map_manager_err)
179    }
180
181    /// Update an outbound list.
182    pub async fn update_list(
183        &self,
184        id: &str,
185        body: models::CreateListRequest,
186    ) -> Result<models::LeadListItemResponse, ManagerError> {
187        let cfg = self.cfg.get().await?;
188        let cfg = cfg.as_ref();
189        with_retry(&self.retry, false, || {
190            api::update_outbound_list(cfg, id, body.clone())
191        })
192        .await
193        .map_err(map_manager_err)
194    }
195
196    /// Delete an outbound list.
197    pub async fn delete_list(&self, id: &str) -> Result<(), ManagerError> {
198        let cfg = self.cfg.get().await?;
199        let cfg = cfg.as_ref();
200        with_retry(&self.retry, false, || api::delete_outbound_list(cfg, id))
201            .await
202            .map_err(map_manager_err)?;
203        Ok(())
204    }
205
206    /// Bulk-delete leads from an outbound list.
207    pub async fn bulk_delete_leads(
208        &self,
209        id: &str,
210        body: models::LeadBulkDeleteRequest,
211    ) -> Result<models::DefaultV2MessageResponse, ManagerError> {
212        let cfg = self.cfg.get().await?;
213        let cfg = cfg.as_ref();
214        with_retry(&self.retry, false, || {
215            api::bulk_delete_outbound_leads(cfg, id, body.clone())
216        })
217        .await
218        .map_err(map_manager_err)
219    }
220
221    /// Bulk-delete leads from an outbound list (alternate endpoint).
222    pub async fn bulk_delete_leads_alt(
223        &self,
224        id: &str,
225        body: models::LeadBulkDeleteRequest,
226    ) -> Result<models::DefaultV2MessageResponse, ManagerError> {
227        let cfg = self.cfg.get().await?;
228        let cfg = cfg.as_ref();
229        with_retry(&self.retry, false, || {
230            api::bulk_delete_outbound_leads_alt(cfg, id, body.clone())
231        })
232        .await
233        .map_err(map_manager_err)
234    }
235
236    /// Get a single lead from an outbound list.
237    pub async fn get_lead(
238        &self,
239        list_id: &str,
240        lead_id: &str,
241    ) -> Result<models::LeadItemResponse, ManagerError> {
242        let cfg = self.cfg.get().await?;
243        let cfg = cfg.as_ref();
244        with_retry(&self.retry, true, || {
245            api::get_lead_in_list(cfg, list_id, lead_id)
246        })
247        .await
248        .map_err(map_manager_err)
249    }
250
251    /// List the leads in an outbound list, optionally filtered by dial status and format.
252    pub async fn list_leads(
253        &self,
254        list_id: &str,
255        status: Option<models::DialStatus>,
256        format: Option<&str>,
257    ) -> Result<models::PaginatedLeadResponse, ManagerError> {
258        let cfg = self.cfg.get().await?;
259        let cfg = cfg.as_ref();
260        with_retry(&self.retry, true, || {
261            api::list_leads_in_list(cfg, list_id, status, format)
262        })
263        .await
264        .map_err(map_manager_err)
265    }
266
267    /// Upload leads to an outbound list from a CSV file.
268    pub async fn upload_leads(
269        &self,
270        id: &str,
271        file: std::path::PathBuf,
272        mapping: Option<&str>,
273        separator: Option<&str>,
274        clear: Option<bool>,
275    ) -> Result<models::LeadUploadResponse, ManagerError> {
276        let cfg = self.cfg.get().await?;
277        let cfg = cfg.as_ref();
278        with_retry(&self.retry, false, || {
279            api::upload_outbound_leads(cfg, id, file.clone(), mapping, separator, clear)
280        })
281        .await
282        .map_err(map_manager_err)
283    }
284
285    /// Upload leads to an outbound list from in-memory CSV bytes — the same multipart request as
286    /// [`upload_leads`](Self::upload_leads) without a file on disk (lead CSVs carry PII; callers
287    /// holding the content in memory shouldn't have to write it out to upload it).
288    pub async fn upload_leads_bytes(
289        &self,
290        id: &str,
291        file_name: &str,
292        csv: Vec<u8>,
293        mapping: Option<&str>,
294        separator: Option<&str>,
295        clear: Option<bool>,
296    ) -> Result<models::LeadUploadResponse, ManagerError> {
297        let cfg = self.cfg.get().await?;
298        let cfg = cfg.as_ref();
299        let uri = format!(
300            "{}/api/v2/outbound/lists/{id}/leads/upload",
301            cfg.base_path,
302            id = crate::gen::manager::apis::urlencode(id)
303        );
304        with_retry(&self.retry, false, || {
305            let uri = uri.clone();
306            let csv = csv.clone();
307            async move {
308                let mut req = cfg.client.request(reqwest::Method::POST, &uri);
309                if let Some(ref user_agent) = cfg.user_agent {
310                    req = req.header(reqwest::header::USER_AGENT, user_agent.clone());
311                }
312                if let Some(ref token) = cfg.oauth_access_token {
313                    req = req.bearer_auth(token.to_owned());
314                }
315                let mut form = reqwest::multipart::Form::new().part(
316                    "file",
317                    reqwest::multipart::Part::bytes(csv).file_name(file_name.to_string()),
318                );
319                if let Some(v) = mapping {
320                    form = form.text("mapping", v.to_string());
321                }
322                if let Some(v) = separator {
323                    form = form.text("separator", v.to_string());
324                }
325                if let Some(v) = clear {
326                    form = form.text("clear", v.to_string());
327                }
328                let resp = req
329                    .multipart(form)
330                    .send()
331                    .await
332                    .map_err(|e| ManagerError::Network(e.to_string()))?;
333                let status = resp.status();
334                let body = resp
335                    .text()
336                    .await
337                    .map_err(|e| ManagerError::Network(e.to_string()))?;
338                if !status.is_success() {
339                    return Err(ManagerError::from_response(status.as_u16(), body));
340                }
341                serde_json::from_str(&body).map_err(|e| ManagerError::Decode(e.to_string()))
342            }
343        })
344        .await
345    }
346}