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((r.items, r.pagination.pages, r.pagination.current))
118        })
119        .await
120    }
121
122    /// List outbound dial attempts, collecting every attempt across pages.
123    pub async fn attempts(&self) -> Result<Vec<models::CallAttempt>, ManagerError> {
124        let cfg = self.cfg.get().await?;
125        let cfg = cfg.as_ref();
126        collect_all(&self.retry, map_manager_err, |page| async move {
127            let r =
128                api::list_outbound_attempts(cfg, Some(page), None, None, None, None, None).await?;
129            Ok((r.items, r.pagination.pages, r.pagination.current))
130        })
131        .await
132    }
133
134    /// List outbound leads, collecting every lead across pages.
135    pub async fn leads(&self) -> Result<Vec<models::Lead>, ManagerError> {
136        let cfg = self.cfg.get().await?;
137        let cfg = cfg.as_ref();
138        collect_all(&self.retry, map_manager_err, |page| async move {
139            let r = api::list_outbound_leads(cfg, Some(page), None, None, None).await?;
140            Ok((r.items, r.pagination.pages, r.pagination.current))
141        })
142        .await
143    }
144
145    /// List processed outbound leads, collecting every lead across pages.
146    pub async fn processed_leads(&self) -> Result<Vec<models::Lead>, ManagerError> {
147        let cfg = self.cfg.get().await?;
148        let cfg = cfg.as_ref();
149        collect_all(&self.retry, map_manager_err, |page| async move {
150            let r = api::list_processed_outbound_leads(cfg, Some(page), None).await?;
151            Ok((r.items, r.pagination.pages, r.pagination.current))
152        })
153        .await
154    }
155
156    /// Get a single outbound list.
157    pub async fn get_list(&self, id: &str) -> Result<models::LeadListItemResponse, ManagerError> {
158        let cfg = self.cfg.get().await?;
159        let cfg = cfg.as_ref();
160        with_retry(&self.retry, true, || api::get_outbound_list(cfg, id))
161            .await
162            .map_err(map_manager_err)
163    }
164
165    /// Update an outbound list.
166    pub async fn update_list(
167        &self,
168        id: &str,
169        body: models::CreateListRequest,
170    ) -> Result<models::LeadListItemResponse, ManagerError> {
171        let cfg = self.cfg.get().await?;
172        let cfg = cfg.as_ref();
173        with_retry(&self.retry, false, || {
174            api::update_outbound_list(cfg, id, body.clone())
175        })
176        .await
177        .map_err(map_manager_err)
178    }
179
180    /// Delete an outbound list.
181    pub async fn delete_list(&self, id: &str) -> Result<(), ManagerError> {
182        let cfg = self.cfg.get().await?;
183        let cfg = cfg.as_ref();
184        with_retry(&self.retry, false, || api::delete_outbound_list(cfg, id))
185            .await
186            .map_err(map_manager_err)?;
187        Ok(())
188    }
189
190    /// Bulk-delete leads from an outbound list.
191    pub async fn bulk_delete_leads(
192        &self,
193        id: &str,
194        body: models::LeadBulkDeleteRequest,
195    ) -> Result<models::DefaultV2MessageResponse, ManagerError> {
196        let cfg = self.cfg.get().await?;
197        let cfg = cfg.as_ref();
198        with_retry(&self.retry, false, || {
199            api::bulk_delete_outbound_leads(cfg, id, body.clone())
200        })
201        .await
202        .map_err(map_manager_err)
203    }
204
205    /// Bulk-delete leads from an outbound list (alternate endpoint).
206    pub async fn bulk_delete_leads_alt(
207        &self,
208        id: &str,
209        body: models::LeadBulkDeleteRequest,
210    ) -> Result<models::DefaultV2MessageResponse, ManagerError> {
211        let cfg = self.cfg.get().await?;
212        let cfg = cfg.as_ref();
213        with_retry(&self.retry, false, || {
214            api::bulk_delete_outbound_leads_alt(cfg, id, body.clone())
215        })
216        .await
217        .map_err(map_manager_err)
218    }
219
220    /// Get a single lead from an outbound list.
221    pub async fn get_lead(
222        &self,
223        list_id: &str,
224        lead_id: &str,
225    ) -> Result<models::LeadItemResponse, ManagerError> {
226        let cfg = self.cfg.get().await?;
227        let cfg = cfg.as_ref();
228        with_retry(&self.retry, true, || {
229            api::get_lead_in_list(cfg, list_id, lead_id)
230        })
231        .await
232        .map_err(map_manager_err)
233    }
234
235    /// List the leads in an outbound list, optionally filtered by dial status and format.
236    pub async fn list_leads(
237        &self,
238        list_id: &str,
239        status: Option<models::DialStatus>,
240        format: Option<&str>,
241    ) -> Result<models::PaginatedLeadResponse, ManagerError> {
242        let cfg = self.cfg.get().await?;
243        let cfg = cfg.as_ref();
244        with_retry(&self.retry, true, || {
245            api::list_leads_in_list(cfg, list_id, status, format)
246        })
247        .await
248        .map_err(map_manager_err)
249    }
250
251    /// Upload leads to an outbound list from a CSV file.
252    pub async fn upload_leads(
253        &self,
254        id: &str,
255        file: std::path::PathBuf,
256        mapping: Option<&str>,
257        separator: Option<&str>,
258        clear: Option<bool>,
259    ) -> Result<models::LeadUploadResponse, ManagerError> {
260        let cfg = self.cfg.get().await?;
261        let cfg = cfg.as_ref();
262        with_retry(&self.retry, false, || {
263            api::upload_outbound_leads(cfg, id, file.clone(), mapping, separator, clear)
264        })
265        .await
266        .map_err(map_manager_err)
267    }
268
269    /// Upload leads to an outbound list from in-memory CSV bytes — the same multipart request as
270    /// [`upload_leads`](Self::upload_leads) without a file on disk (lead CSVs carry PII; callers
271    /// holding the content in memory shouldn't have to write it out to upload it).
272    pub async fn upload_leads_bytes(
273        &self,
274        id: &str,
275        file_name: &str,
276        csv: Vec<u8>,
277        mapping: Option<&str>,
278        separator: Option<&str>,
279        clear: Option<bool>,
280    ) -> Result<models::LeadUploadResponse, ManagerError> {
281        let cfg = self.cfg.get().await?;
282        let cfg = cfg.as_ref();
283        let uri = format!(
284            "{}/api/v2/outbound/lists/{id}/leads/upload",
285            cfg.base_path,
286            id = crate::gen::manager::apis::urlencode(id)
287        );
288        with_retry(&self.retry, false, || {
289            let uri = uri.clone();
290            let csv = csv.clone();
291            async move {
292                let mut req = cfg.client.request(reqwest::Method::POST, &uri);
293                if let Some(ref user_agent) = cfg.user_agent {
294                    req = req.header(reqwest::header::USER_AGENT, user_agent.clone());
295                }
296                if let Some(ref token) = cfg.oauth_access_token {
297                    req = req.bearer_auth(token.to_owned());
298                }
299                let mut form = reqwest::multipart::Form::new().part(
300                    "file",
301                    reqwest::multipart::Part::bytes(csv).file_name(file_name.to_string()),
302                );
303                if let Some(v) = mapping {
304                    form = form.text("mapping", v.to_string());
305                }
306                if let Some(v) = separator {
307                    form = form.text("separator", v.to_string());
308                }
309                if let Some(v) = clear {
310                    form = form.text("clear", v.to_string());
311                }
312                let resp = req
313                    .multipart(form)
314                    .send()
315                    .await
316                    .map_err(|e| ManagerError::Network(e.to_string()))?;
317                let status = resp.status();
318                let body = resp
319                    .text()
320                    .await
321                    .map_err(|e| ManagerError::Network(e.to_string()))?;
322                if !status.is_success() {
323                    return Err(ManagerError::from_response(status.as_u16(), body));
324                }
325                serde_json::from_str(&body).map_err(|e| ManagerError::Decode(e.to_string()))
326            }
327        })
328        .await
329    }
330}