Skip to main content

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    /// Clears the authentication token
53    pub fn clear_token(&mut self) {
54        self.token = None;
55    }
56
57    /// Gets the full URL for an endpoint with /api/v4 prefix
58    fn get_url(&self, endpoint: &str) -> String {
59        format!(
60            "{}/api/v4/{}",
61            self.base_url.trim_end_matches('/'),
62            endpoint.trim_start_matches('/')
63        )
64    }
65
66    /// Makes a GET request to the API
67    pub async fn get<T>(&self, endpoint: &str) -> Result<T, Error>
68    where
69        T: serde::de::DeserializeOwned + std::fmt::Debug,
70    {
71        let url = self.get_url(endpoint);
72        let mut request = self.http_client.get(&url);
73
74        if let Some(token) = &self.token {
75            request = request.bearer_auth(token);
76        }
77        debug!("GET URL: {}", url);
78
79        let response = request.send().await?;
80        let status = response.status();
81
82        // Check for error status codes first
83        if !status.is_success() {
84            let raw_text = response.text().await?;
85            // Try to parse as API error response
86            if let Ok(api_response) =
87                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
88                && api_response.code != 0
89            {
90                return Err(Error::Api {
91                    code: api_response.code,
92                    message: api_response.msg,
93                });
94            }
95            // If not a standard API response, return error with status code
96            return Err(Error::Api {
97                code: status.as_u16() as i32,
98                message: raw_text.trim().to_string(),
99            });
100        }
101
102        // Get raw response text for better error reporting
103        let raw_text = response.text().await?;
104
105        match serde_json::from_str::<T>(&raw_text) {
106            Ok(json) => {
107                debug!("Response status: {}, JSON: {:?}", status, json);
108                Ok(json)
109            }
110            Err(e) => {
111                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
112                Err(Error::Json(e))
113            }
114        }
115    }
116
117    /// Makes a POST request to the API
118    pub async fn post<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
119    where
120        T: serde::de::DeserializeOwned + std::fmt::Debug,
121    {
122        let url = self.get_url(endpoint);
123        let mut request = self.http_client.post(&url).json(body);
124
125        if let Some(token) = &self.token {
126            request = request.bearer_auth(token);
127        }
128
129        debug!("POST URL: {}", url);
130
131        // Log the request body for debugging
132        if let Ok(json_str) = serde_json::to_string(body) {
133            debug!("Request body: {}", json_str);
134        }
135
136        let response = request.send().await?;
137        let status = response.status();
138
139        // Check for error status codes first
140        if !status.is_success() {
141            let raw_text = response.text().await?;
142            if let Ok(api_response) =
143                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
144                && api_response.code != 0
145            {
146                return Err(Error::Api {
147                    code: api_response.code,
148                    message: api_response.msg,
149                });
150            }
151            return Err(Error::Api {
152                code: status.as_u16() as i32,
153                message: raw_text.trim().to_string(),
154            });
155        }
156
157        let raw_text = response.text().await?;
158
159        match serde_json::from_str::<T>(&raw_text) {
160            Ok(json) => {
161                debug!("Response status: {}, JSON: {:?}", status, json);
162                Ok(json)
163            }
164            Err(e) => {
165                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
166                Err(Error::Json(e))
167            }
168        }
169    }
170
171    /// Makes a PUT request to the API
172    pub async fn put<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
173    where
174        T: serde::de::DeserializeOwned + std::fmt::Debug,
175    {
176        let url = self.get_url(endpoint);
177        let mut request = self.http_client.put(&url).json(body);
178
179        if let Some(token) = &self.token {
180            request = request.bearer_auth(token);
181        }
182        debug!("PUT URL: {}", url);
183
184        let response = request.send().await?;
185        let status = response.status();
186
187        // Check for error status codes first
188        if !status.is_success() {
189            let raw_text = response.text().await?;
190            if let Ok(api_response) =
191                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
192                && api_response.code != 0
193            {
194                return Err(Error::Api {
195                    code: api_response.code,
196                    message: api_response.msg,
197                });
198            }
199            return Err(Error::Api {
200                code: status.as_u16() as i32,
201                message: raw_text.trim().to_string(),
202            });
203        }
204
205        let raw_text = response.text().await?;
206
207        match serde_json::from_str::<T>(&raw_text) {
208            Ok(json) => {
209                debug!("Response status: {}, JSON: {:?}", status, json);
210                Ok(json)
211            }
212            Err(e) => {
213                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
214                Err(Error::Json(e))
215            }
216        }
217    }
218
219    pub async fn patch<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
220    where
221        T: serde::de::DeserializeOwned + std::fmt::Debug,
222    {
223        let url = self.get_url(endpoint);
224        let mut request = self.http_client.patch(&url).json(body);
225
226        if let Some(token) = &self.token {
227            request = request.bearer_auth(token);
228        }
229        debug!("PATCH URL: {}", url);
230
231        let response = request.send().await?;
232        let status = response.status();
233
234        // Check for error status codes first
235        if !status.is_success() {
236            let raw_text = response.text().await?;
237            if let Ok(api_response) =
238                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
239                && api_response.code != 0
240            {
241                return Err(Error::Api {
242                    code: api_response.code,
243                    message: api_response.msg,
244                });
245            }
246            return Err(Error::Api {
247                code: status.as_u16() as i32,
248                message: raw_text.trim().to_string(),
249            });
250        }
251
252        let raw_text = response.text().await?;
253
254        match serde_json::from_str::<T>(&raw_text) {
255            Ok(json) => {
256                debug!("Response status: {}, JSON: {:?}", status, json);
257                Ok(json)
258            }
259            Err(e) => {
260                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
261                Err(Error::Json(e))
262            }
263        }
264    }
265
266    /// Makes a DELETE request to the API
267    pub async fn delete<T>(&self, endpoint: &str) -> Result<T, Error>
268    where
269        T: serde::de::DeserializeOwned + std::fmt::Debug,
270    {
271        let url = self.get_url(endpoint);
272        let mut request = self.http_client.delete(&url);
273
274        if let Some(token) = &self.token {
275            request = request.bearer_auth(token);
276        }
277        debug!("DELETE URL: {}", url);
278
279        let response = request.send().await?;
280        let status = response.status();
281
282        // Check for error status codes first
283        if !status.is_success() {
284            let raw_text = response.text().await?;
285            if let Ok(api_response) =
286                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
287                && api_response.code != 0
288            {
289                return Err(Error::Api {
290                    code: api_response.code,
291                    message: api_response.msg,
292                });
293            }
294            return Err(Error::Api {
295                code: status.as_u16() as i32,
296                message: raw_text.trim().to_string(),
297            });
298        }
299
300        let raw_text = response.text().await?;
301
302        match serde_json::from_str::<T>(&raw_text) {
303            Ok(json) => {
304                debug!("Response status: {}, JSON: {:?}", status, json);
305                Ok(json)
306            }
307            Err(e) => {
308                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
309                Err(Error::Json(e))
310            }
311        }
312    }
313
314    /// Makes a DELETE request with JSON body to the API
315    pub async fn delete_with_body<T>(
316        &self,
317        endpoint: &str,
318        body: &impl Serialize,
319    ) -> Result<T, Error>
320    where
321        T: serde::de::DeserializeOwned + std::fmt::Debug,
322    {
323        let url = self.get_url(endpoint);
324        let mut request = self.http_client.delete(&url).json(body);
325
326        if let Some(token) = &self.token {
327            request = request.bearer_auth(token);
328        }
329        debug!("DELETE URL: {} with body", url);
330
331        let response = request.send().await?;
332        let status = response.status();
333
334        // Check for error status codes first
335        if !status.is_success() {
336            let raw_text = response.text().await?;
337            if let Ok(api_response) =
338                serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
339                && api_response.code != 0
340            {
341                return Err(Error::Api {
342                    code: api_response.code,
343                    message: api_response.msg,
344                });
345            }
346            return Err(Error::Api {
347                code: status.as_u16() as i32,
348                message: raw_text.trim().to_string(),
349            });
350        }
351
352        let raw_text = response.text().await?;
353
354        match serde_json::from_str::<T>(&raw_text) {
355            Ok(json) => {
356                debug!("Response status: {}, JSON: {:?}", status, json);
357                Ok(json)
358            }
359            Err(e) => {
360                debug!("JSON parse error: {}, raw response: {}", e, raw_text);
361                Err(Error::Json(e))
362            }
363        }
364    }
365}