files_sdk/sharing/
requests.rs

1//! Request (File Request) operations
2//!
3//! Requests are files that should be uploaded by a specific user or group.
4//! They can be manually created/managed or automatically managed by automations.
5
6use crate::{FilesClient, PaginationInfo, Result};
7use serde::{Deserialize, Serialize};
8use serde_json::json;
9
10/// A Request entity (File Request)
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct RequestEntity {
13    /// Request ID
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub id: Option<i64>,
16
17    /// Folder path
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub path: Option<String>,
20
21    /// Source filename (if applicable)
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub source: Option<String>,
24
25    /// Destination filename
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub destination: Option<String>,
28
29    /// ID of automation that created this request
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub automation_id: Option<i64>,
32
33    /// User making the request (if applicable)
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub user_display_name: Option<String>,
36}
37
38/// Handler for request operations
39pub struct RequestHandler {
40    client: FilesClient,
41}
42
43impl RequestHandler {
44    /// Create a new request handler
45    pub fn new(client: FilesClient) -> Self {
46        Self { client }
47    }
48
49    /// List requests
50    ///
51    /// # Arguments
52    /// * `cursor` - Pagination cursor
53    /// * `per_page` - Results per page (max 10,000)
54    /// * `path` - Filter by path
55    /// * `mine` - Only show requests for current user
56    ///
57    /// # Returns
58    /// Tuple of (requests, pagination_info)
59    ///
60    /// # Example
61    /// ```no_run
62    /// use files_sdk::{FilesClient, RequestHandler};
63    ///
64    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
65    /// let client = FilesClient::builder().api_key("key").build()?;
66    /// let handler = RequestHandler::new(client);
67    /// let (requests, pagination) = handler.list(None, None, None, None).await?;
68    /// # Ok(())
69    /// # }
70    /// ```
71    pub async fn list(
72        &self,
73        cursor: Option<&str>,
74        per_page: Option<i64>,
75        path: Option<&str>,
76        mine: Option<bool>,
77    ) -> Result<(Vec<RequestEntity>, PaginationInfo)> {
78        let mut params = vec![];
79        if let Some(c) = cursor {
80            params.push(("cursor", c.to_string()));
81        }
82        if let Some(pp) = per_page {
83            params.push(("per_page", pp.to_string()));
84        }
85        if let Some(p) = path {
86            params.push(("path", p.to_string()));
87        }
88        if let Some(m) = mine {
89            params.push(("mine", m.to_string()));
90        }
91
92        let query = if params.is_empty() {
93            String::new()
94        } else {
95            format!(
96                "?{}",
97                params
98                    .iter()
99                    .map(|(k, v)| format!("{}={}", k, v))
100                    .collect::<Vec<_>>()
101                    .join("&")
102            )
103        };
104
105        let response = self.client.get_raw(&format!("/requests{}", query)).await?;
106        let requests: Vec<RequestEntity> = serde_json::from_value(response)?;
107
108        let pagination = PaginationInfo {
109            cursor_next: None,
110            cursor_prev: None,
111        };
112
113        Ok((requests, pagination))
114    }
115
116    /// List requests for a specific folder path
117    ///
118    /// # Arguments
119    /// * `path` - Folder path
120    /// * `cursor` - Pagination cursor
121    /// * `per_page` - Results per page
122    ///
123    /// # Returns
124    /// Tuple of (requests, pagination_info)
125    pub async fn list_for_folder(
126        &self,
127        path: &str,
128        cursor: Option<&str>,
129        per_page: Option<i64>,
130    ) -> Result<(Vec<RequestEntity>, PaginationInfo)> {
131        let mut params = vec![];
132        if let Some(c) = cursor {
133            params.push(("cursor", c.to_string()));
134        }
135        if let Some(pp) = per_page {
136            params.push(("per_page", pp.to_string()));
137        }
138
139        let query = if params.is_empty() {
140            String::new()
141        } else {
142            format!(
143                "?{}",
144                params
145                    .iter()
146                    .map(|(k, v)| format!("{}={}", k, v))
147                    .collect::<Vec<_>>()
148                    .join("&")
149            )
150        };
151
152        let response = self
153            .client
154            .get_raw(&format!("/requests/folders/{}{}", path, query))
155            .await?;
156        let requests: Vec<RequestEntity> = serde_json::from_value(response)?;
157
158        let pagination = PaginationInfo {
159            cursor_next: None,
160            cursor_prev: None,
161        };
162
163        Ok((requests, pagination))
164    }
165
166    /// Create a new request
167    ///
168    /// # Arguments
169    /// * `path` - Folder path where file should be uploaded (required)
170    /// * `destination` - Destination filename without extension (required)
171    /// * `user_ids` - Comma-separated list of user IDs to request from
172    /// * `group_ids` - Comma-separated list of group IDs to request from
173    ///
174    /// # Returns
175    /// The created request
176    ///
177    /// # Example
178    /// ```no_run
179    /// use files_sdk::{FilesClient, RequestHandler};
180    ///
181    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
182    /// let client = FilesClient::builder().api_key("key").build()?;
183    /// let handler = RequestHandler::new(client);
184    /// let request = handler.create(
185    ///     "/uploads",
186    ///     "monthly_report",
187    ///     Some("123,456"),
188    ///     None
189    /// ).await?;
190    /// # Ok(())
191    /// # }
192    /// ```
193    pub async fn create(
194        &self,
195        path: &str,
196        destination: &str,
197        user_ids: Option<&str>,
198        group_ids: Option<&str>,
199    ) -> Result<RequestEntity> {
200        let mut body = json!({
201            "path": path,
202            "destination": destination,
203        });
204
205        if let Some(uids) = user_ids {
206            body["user_ids"] = json!(uids);
207        }
208        if let Some(gids) = group_ids {
209            body["group_ids"] = json!(gids);
210        }
211
212        let response = self.client.post_raw("/requests", body).await?;
213        Ok(serde_json::from_value(response)?)
214    }
215
216    /// Delete a request
217    ///
218    /// # Arguments
219    /// * `id` - Request ID
220    ///
221    /// # Example
222    /// ```no_run
223    /// use files_sdk::{FilesClient, RequestHandler};
224    ///
225    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
226    /// let client = FilesClient::builder().api_key("key").build()?;
227    /// let handler = RequestHandler::new(client);
228    /// handler.delete(123).await?;
229    /// # Ok(())
230    /// # }
231    /// ```
232    pub async fn delete(&self, id: i64) -> Result<()> {
233        self.client.delete_raw(&format!("/requests/{}", id)).await?;
234        Ok(())
235    }
236}
237
238#[cfg(test)]
239mod tests {
240    use super::*;
241
242    #[test]
243    fn test_handler_creation() {
244        let client = FilesClient::builder().api_key("test-key").build().unwrap();
245        let _handler = RequestHandler::new(client);
246    }
247}