1use crate::Error;
4use log::debug;
5use serde::Serialize;
6
7pub mod dav;
9pub mod file;
11pub mod models;
13pub mod session;
15pub mod share;
17pub mod site;
19pub mod uri;
21pub mod user;
23pub mod workflow;
25
26#[derive(Debug, Clone)]
28pub struct ApiV4Client {
29 pub base_url: String,
31 pub http_client: reqwest::Client,
33 pub token: Option<String>,
35 pub refresh_token: Option<String>,
37}
38
39impl ApiV4Client {
40 pub fn new(base_url: &str) -> Self {
42 crate::ensure_tls_crypto_provider();
43
44 Self {
45 base_url: base_url.to_string(),
46 http_client: reqwest::Client::new(),
47 token: None,
48 refresh_token: None,
49 }
50 }
51
52 pub fn set_token(&mut self, token: String) {
54 self.token = Some(token);
55 }
56
57 pub fn clear_token(&mut self) {
59 self.token = None;
60 self.refresh_token = None;
61 }
62
63 pub fn set_refresh_token(&mut self, token: String) {
65 self.refresh_token = Some(token);
66 }
67
68 pub fn get_refresh_token(&self) -> Option<&str> {
70 self.refresh_token.as_deref()
71 }
72
73 fn get_url(&self, endpoint: &str) -> String {
75 format!(
76 "{}/api/v4/{}",
77 self.base_url.trim_end_matches('/'),
78 endpoint.trim_start_matches('/')
79 )
80 }
81
82 pub async fn get<T>(&self, endpoint: &str) -> Result<T, Error>
84 where
85 T: serde::de::DeserializeOwned + std::fmt::Debug,
86 {
87 let url = self.get_url(endpoint);
88 let mut request = self.http_client.get(&url);
89
90 if let Some(token) = &self.token {
91 request = request.bearer_auth(token);
92 }
93 debug!("GET URL: {}", url);
94
95 let response = request.send().await?;
96 let status = response.status();
97
98 if !status.is_success() {
100 let raw_text = response.text().await?;
101 if let Ok(api_response) =
103 serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
104 && api_response.code != 0
105 {
106 return Err(Error::Api {
107 code: api_response.code,
108 message: api_response.msg,
109 });
110 }
111 return Err(Error::Api {
113 code: status.as_u16() as i32,
114 message: raw_text.trim().to_string(),
115 });
116 }
117
118 let raw_text = response.text().await?;
120
121 if let Ok(base) = serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
123 && base.code == 401
124 {
125 return Err(Error::Unauthorized(base.msg));
126 }
127
128 match serde_json::from_str::<T>(&raw_text) {
129 Ok(json) => {
130 debug!("Response status: {}, JSON: {:?}", status, json);
131 Ok(json)
132 }
133 Err(e) => {
134 debug!("JSON parse error: {}, raw response: {}", e, raw_text);
135 Err(Error::Json(e))
136 }
137 }
138 }
139
140 pub async fn post<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
142 where
143 T: serde::de::DeserializeOwned + std::fmt::Debug,
144 {
145 let url = self.get_url(endpoint);
146 let mut request = self.http_client.post(&url).json(body);
147
148 if let Some(token) = &self.token {
149 request = request.bearer_auth(token);
150 }
151
152 debug!("POST URL: {}", url);
153
154 if let Ok(json_str) = serde_json::to_string(body) {
156 debug!("Request body: {}", json_str);
157 }
158
159 let response = request.send().await?;
160 let status = response.status();
161
162 if !status.is_success() {
164 let raw_text = response.text().await?;
165 if let Ok(api_response) =
166 serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
167 && api_response.code != 0
168 {
169 return Err(Error::Api {
170 code: api_response.code,
171 message: api_response.msg,
172 });
173 }
174 return Err(Error::Api {
175 code: status.as_u16() as i32,
176 message: raw_text.trim().to_string(),
177 });
178 }
179
180 let raw_text = response.text().await?;
181
182 if let Ok(base) = serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
183 && base.code == 401
184 {
185 return Err(Error::Unauthorized(base.msg));
186 }
187
188 match serde_json::from_str::<T>(&raw_text) {
189 Ok(json) => {
190 debug!("Response status: {}, JSON: {:?}", status, json);
191 Ok(json)
192 }
193 Err(e) => {
194 debug!("JSON parse error: {}, raw response: {}", e, raw_text);
195 Err(Error::Json(e))
196 }
197 }
198 }
199
200 pub async fn put<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
202 where
203 T: serde::de::DeserializeOwned + std::fmt::Debug,
204 {
205 let url = self.get_url(endpoint);
206 let mut request = self.http_client.put(&url).json(body);
207
208 if let Some(token) = &self.token {
209 request = request.bearer_auth(token);
210 }
211 debug!("PUT URL: {}", url);
212
213 let response = request.send().await?;
214 let status = response.status();
215
216 if !status.is_success() {
218 let raw_text = response.text().await?;
219 if let Ok(api_response) =
220 serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
221 && api_response.code != 0
222 {
223 return Err(Error::Api {
224 code: api_response.code,
225 message: api_response.msg,
226 });
227 }
228 return Err(Error::Api {
229 code: status.as_u16() as i32,
230 message: raw_text.trim().to_string(),
231 });
232 }
233
234 let raw_text = response.text().await?;
235
236 match serde_json::from_str::<T>(&raw_text) {
237 Ok(json) => {
238 debug!("Response status: {}, JSON: {:?}", status, json);
239 Ok(json)
240 }
241 Err(e) => {
242 debug!("JSON parse error: {}, raw response: {}", e, raw_text);
243 Err(Error::Json(e))
244 }
245 }
246 }
247
248 pub async fn patch<T>(&self, endpoint: &str, body: &impl Serialize) -> Result<T, Error>
249 where
250 T: serde::de::DeserializeOwned + std::fmt::Debug,
251 {
252 let url = self.get_url(endpoint);
253 let mut request = self.http_client.patch(&url).json(body);
254
255 if let Some(token) = &self.token {
256 request = request.bearer_auth(token);
257 }
258 debug!("PATCH URL: {}", url);
259
260 let response = request.send().await?;
261 let status = response.status();
262
263 if !status.is_success() {
265 let raw_text = response.text().await?;
266 if let Ok(api_response) =
267 serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
268 && api_response.code != 0
269 {
270 return Err(Error::Api {
271 code: api_response.code,
272 message: api_response.msg,
273 });
274 }
275 return Err(Error::Api {
276 code: status.as_u16() as i32,
277 message: raw_text.trim().to_string(),
278 });
279 }
280
281 let raw_text = response.text().await?;
282
283 match serde_json::from_str::<T>(&raw_text) {
284 Ok(json) => {
285 debug!("Response status: {}, JSON: {:?}", status, json);
286 Ok(json)
287 }
288 Err(e) => {
289 debug!("JSON parse error: {}, raw response: {}", e, raw_text);
290 Err(Error::Json(e))
291 }
292 }
293 }
294
295 pub async fn delete<T>(&self, endpoint: &str) -> Result<T, Error>
297 where
298 T: serde::de::DeserializeOwned + std::fmt::Debug,
299 {
300 let url = self.get_url(endpoint);
301 let mut request = self.http_client.delete(&url);
302
303 if let Some(token) = &self.token {
304 request = request.bearer_auth(token);
305 }
306 debug!("DELETE URL: {}", url);
307
308 let response = request.send().await?;
309 let status = response.status();
310
311 if !status.is_success() {
313 let raw_text = response.text().await?;
314 if let Ok(api_response) =
315 serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
316 && api_response.code != 0
317 {
318 return Err(Error::Api {
319 code: api_response.code,
320 message: api_response.msg,
321 });
322 }
323 return Err(Error::Api {
324 code: status.as_u16() as i32,
325 message: raw_text.trim().to_string(),
326 });
327 }
328
329 let raw_text = response.text().await?;
330
331 if let Ok(base) = serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
332 && base.code == 401
333 {
334 return Err(Error::Unauthorized(base.msg));
335 }
336
337 match serde_json::from_str::<T>(&raw_text) {
338 Ok(json) => {
339 debug!("Response status: {}, JSON: {:?}", status, json);
340 Ok(json)
341 }
342 Err(e) => {
343 debug!("JSON parse error: {}, raw response: {}", e, raw_text);
344 Err(Error::Json(e))
345 }
346 }
347 }
348
349 pub async fn delete_with_body<T>(
351 &self,
352 endpoint: &str,
353 body: &impl Serialize,
354 ) -> Result<T, Error>
355 where
356 T: serde::de::DeserializeOwned + std::fmt::Debug,
357 {
358 let url = self.get_url(endpoint);
359 let mut request = self.http_client.delete(&url).json(body);
360
361 if let Some(token) = &self.token {
362 request = request.bearer_auth(token);
363 }
364 debug!("DELETE URL: {} with body", url);
365
366 let response = request.send().await?;
367 let status = response.status();
368
369 if !status.is_success() {
371 let raw_text = response.text().await?;
372 if let Ok(api_response) =
373 serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
374 && api_response.code != 0
375 {
376 return Err(Error::Api {
377 code: api_response.code,
378 message: api_response.msg,
379 });
380 }
381 return Err(Error::Api {
382 code: status.as_u16() as i32,
383 message: raw_text.trim().to_string(),
384 });
385 }
386
387 let raw_text = response.text().await?;
388
389 if let Ok(base) = serde_json::from_str::<crate::ApiResponse<serde_json::Value>>(&raw_text)
390 && base.code == 401
391 {
392 return Err(Error::Unauthorized(base.msg));
393 }
394
395 match serde_json::from_str::<T>(&raw_text) {
396 Ok(json) => {
397 debug!("Response status: {}, JSON: {:?}", status, json);
398 Ok(json)
399 }
400 Err(e) => {
401 debug!("JSON parse error: {}, raw response: {}", e, raw_text);
402 Err(Error::Json(e))
403 }
404 }
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use super::ApiV4Client;
411
412 #[test]
413 fn clear_token_removes_refresh_token() {
414 let mut client = ApiV4Client::new("https://example.com");
415 client.set_token("access_token".to_string());
416 client.set_refresh_token("refresh_token".to_string());
417
418 client.clear_token();
419
420 assert!(client.token.is_none());
421 assert!(client.get_refresh_token().is_none());
422 }
423}