Skip to main content

babelforce_manager_sdk/resources/
outbound.rs

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