cloudreve_api/api/v4/
mod.rs

1//! API v4 implementation
2
3use crate::Error;
4use log::debug;
5use serde::Serialize;
6
7/// WebDAV account management methods for v4 API
8pub mod dav;
9/// File management methods for v4 API
10pub mod file;
11/// Common data models for v4 API
12pub mod models;
13/// Session management methods for v4 API
14pub mod session;
15/// Share management methods for v4 API
16pub mod share;
17/// Site-related methods for v4 API
18pub mod site;
19/// URI handling utilities for v4 API
20pub mod uri;
21/// User management methods for v4 API
22pub mod user;
23/// Workflow management methods for v4 API
24pub mod workflow;
25
26/// API v4 client structure
27#[derive(Debug, Clone)]
28pub struct ApiV4Client {
29    /// Base URL for the Cloudreve instance
30    pub base_url: String,
31    /// HTTP client for making requests
32    pub http_client: reqwest::Client,
33    /// Authentication token
34    pub token: Option<String>,
35}
36
37impl ApiV4Client {
38    /// Creates a new API v4 client
39    pub fn new(base_url: &str) -> Self {
40        Self {
41            base_url: base_url.to_string(),
42            http_client: reqwest::Client::new(),
43            token: None,
44        }
45    }
46
47    /// Sets the authentication token
48    pub fn set_token(&mut self, token: String) {
49        self.token = Some(token);
50    }
51
52    /// Gets the full URL for an endpoint with /api/v4 prefix
53    fn get_url(&self, endpoint: &str) -> String {
54        format!(
55            "{}/api/v4/{}",
56            self.base_url.trim_end_matches('/'),
57            endpoint.trim_start_matches('/')
58        )
59    }
60
61    /// Makes a GET request to the API
62    pub async fn get<T>(&self, endpoint: &str) -> Result<T, Error>
63    where
64        T: serde::de::DeserializeOwned + std::fmt::Debug,
65    {
66        let url = self.get_url(endpoint);
67        let mut request = self.http_client.get(&url);
68
69        if let Some(token) = &self.token {
70            request = request.bearer_auth(token);
71        }
72        debug!("GET URL: {}", url);
73
74        let response = request.send().await?;
75        let status = response.status();
76
77        // Check for error status codes first
78        if !status.is_success() {
79            let raw_text = response.text().await?;
80            // Try to parse as API error response
81            if let Ok(api_response) =
82                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
83                && api_response.code != 0
84            {
85                return Err(Error::Api {
86                    code: api_response.code,
87                    message: api_response.msg,
88                });
89            }
90            // If not a standard API response, return error with status code
91            return Err(Error::Api {
92                code: status.as_u16() as i32,
93                message: raw_text.trim().to_string(),
94            });
95        }
96
97        // Get raw response text for better error reporting
98        let raw_text = response.text().await?;
99
100        match serde_json::from_str::<T>(&raw_text) {
101            Ok(json) => {
102                debug!("Response status: {}, JSON: {:?}", status, json);
103                Ok(json)
104            }
105            Err(e) => {
106                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
107                Err(Error::Json(e))
108            }
109        }
110    }
111
112    /// Makes a POST request to the API
113    pub async fn post<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
114    where
115        T: serde::de::DeserializeOwned + std::fmt::Debug,
116    {
117        let url = self.get_url(endpoint);
118        let mut request = self.http_client.post(&url).json(body);
119
120        if let Some(token) = &self.token {
121            request = request.bearer_auth(token);
122        }
123
124        debug!("POST URL: {}", url);
125
126        let response = request.send().await?;
127        let status = response.status();
128
129        // Check for error status codes first
130        if !status.is_success() {
131            let raw_text = response.text().await?;
132            if let Ok(api_response) =
133                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
134                && api_response.code != 0
135            {
136                return Err(Error::Api {
137                    code: api_response.code,
138                    message: api_response.msg,
139                });
140            }
141            return Err(Error::Api {
142                code: status.as_u16() as i32,
143                message: raw_text.trim().to_string(),
144            });
145        }
146
147        let raw_text = response.text().await?;
148
149        match serde_json::from_str::<T>(&raw_text) {
150            Ok(json) => {
151                debug!("Response status: {}, JSON: {:?}", status, json);
152                Ok(json)
153            }
154            Err(e) => {
155                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
156                Err(Error::Json(e))
157            }
158        }
159    }
160
161    /// Makes a PUT request to the API
162    pub async fn put<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
163    where
164        T: serde::de::DeserializeOwned + std::fmt::Debug,
165    {
166        let url = self.get_url(endpoint);
167        let mut request = self.http_client.put(&url).json(body);
168
169        if let Some(token) = &self.token {
170            request = request.bearer_auth(token);
171        }
172        debug!("PUT URL: {}", url);
173
174        let response = request.send().await?;
175        let status = response.status();
176
177        // Check for error status codes first
178        if !status.is_success() {
179            let raw_text = response.text().await?;
180            if let Ok(api_response) =
181                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
182                && api_response.code != 0
183            {
184                return Err(Error::Api {
185                    code: api_response.code,
186                    message: api_response.msg,
187                });
188            }
189            return Err(Error::Api {
190                code: status.as_u16() as i32,
191                message: raw_text.trim().to_string(),
192            });
193        }
194
195        let raw_text = response.text().await?;
196
197        match serde_json::from_str::<T>(&raw_text) {
198            Ok(json) => {
199                debug!("Response status: {}, JSON: {:?}", status, json);
200                Ok(json)
201            }
202            Err(e) => {
203                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
204                Err(Error::Json(e))
205            }
206        }
207    }
208
209    pub async fn patch<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
210    where
211        T: serde::de::DeserializeOwned + std::fmt::Debug,
212    {
213        let url = self.get_url(endpoint);
214        let mut request = self.http_client.patch(&url).json(body);
215
216        if let Some(token) = &self.token {
217            request = request.bearer_auth(token);
218        }
219        debug!("PATCH URL: {}", url);
220
221        let response = request.send().await?;
222        let status = response.status();
223
224        // Check for error status codes first
225        if !status.is_success() {
226            let raw_text = response.text().await?;
227            if let Ok(api_response) =
228                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
229                && api_response.code != 0
230            {
231                return Err(Error::Api {
232                    code: api_response.code,
233                    message: api_response.msg,
234                });
235            }
236            return Err(Error::Api {
237                code: status.as_u16() as i32,
238                message: raw_text.trim().to_string(),
239            });
240        }
241
242        let raw_text = response.text().await?;
243
244        match serde_json::from_str::<T>(&raw_text) {
245            Ok(json) => {
246                debug!("Response status: {}, JSON: {:?}", status, json);
247                Ok(json)
248            }
249            Err(e) => {
250                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
251                Err(Error::Json(e))
252            }
253        }
254    }
255
256    /// Makes a DELETE request to the API
257    pub async fn delete<T>(&self, endpoint: &str) -> Result<T, Error>
258    where
259        T: serde::de::DeserializeOwned + std::fmt::Debug,
260    {
261        let url = self.get_url(endpoint);
262        let mut request = self.http_client.delete(&url);
263
264        if let Some(token) = &self.token {
265            request = request.bearer_auth(token);
266        }
267        debug!("DELETE URL: {}", url);
268
269        let response = request.send().await?;
270        let status = response.status();
271
272        // Check for error status codes first
273        if !status.is_success() {
274            let raw_text = response.text().await?;
275            if let Ok(api_response) =
276                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
277                && api_response.code != 0
278            {
279                return Err(Error::Api {
280                    code: api_response.code,
281                    message: api_response.msg,
282                });
283            }
284            return Err(Error::Api {
285                code: status.as_u16() as i32,
286                message: raw_text.trim().to_string(),
287            });
288        }
289
290        let raw_text = response.text().await?;
291
292        match serde_json::from_str::<T>(&raw_text) {
293            Ok(json) => {
294                debug!("Response status: {}, JSON: {:?}", status, json);
295                Ok(json)
296            }
297            Err(e) => {
298                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
299                Err(Error::Json(e))
300            }
301        }
302    }
303}