Skip to main content

onspring/endpoints/
files.rs

1use reqwest::Method;
2
3use crate::client::OnspringClient;
4use crate::error::Result;
5use crate::models::{CreatedWithIdResponse, FileInfo, FileResponse, SaveFileRequest};
6
7impl OnspringClient {
8  /// Gets a file's metadata information.
9  pub async fn get_file_info(
10    &self,
11    record_id: i32,
12    field_id: i32,
13    file_id: i32,
14  ) -> Result<FileInfo> {
15    let path = format!(
16      "/Files/recordId/{}/fieldId/{}/fileId/{}",
17      record_id, field_id, file_id
18    );
19    self
20      .request(Method::GET, &path, &[], Option::<&()>::None)
21      .await
22  }
23
24  /// Downloads a file's content.
25  pub async fn get_file(
26    &self,
27    record_id: i32,
28    field_id: i32,
29    file_id: i32,
30  ) -> Result<FileResponse> {
31    let path = format!(
32      "/Files/recordId/{}/fieldId/{}/fileId/{}/file",
33      record_id, field_id, file_id
34    );
35    let (_status, headers, data) = self.request_bytes(Method::GET, &path, &[]).await?;
36
37    let content_type = headers
38      .get("content-type")
39      .and_then(|v| v.to_str().ok())
40      .map(String::from);
41
42    let file_name = headers
43      .get("content-disposition")
44      .and_then(|v| v.to_str().ok())
45      .and_then(|v| {
46        v.split("filename=")
47          .nth(1)
48          .map(|s| s.trim_matches('"').to_string())
49      });
50
51    Ok(FileResponse {
52      content_type,
53      file_name,
54      data,
55    })
56  }
57
58  /// Uploads a file attachment.
59  pub async fn upload_file(&self, request: SaveFileRequest) -> Result<CreatedWithIdResponse> {
60    let file_part = reqwest::multipart::Part::bytes(request.file_data)
61      .file_name(request.file_name)
62      .mime_str(&request.content_type)
63      .map_err(|e| crate::error::OnspringError::InvalidArgument(e.to_string()))?;
64
65    let mut form = reqwest::multipart::Form::new()
66      .text("RecordId", request.record_id.to_string())
67      .text("FieldId", request.field_id.to_string())
68      .part("File", file_part);
69
70    if let Some(notes) = request.notes {
71      form = form.text("Notes", notes);
72    }
73    if let Some(date) = request.modified_date {
74      form = form.text("ModifiedDate", date.to_rfc3339());
75    }
76
77    self.request_multipart("/Files", form).await
78  }
79
80  /// Deletes a file attachment.
81  pub async fn delete_file(&self, record_id: i32, field_id: i32, file_id: i32) -> Result<()> {
82    let path = format!(
83      "/Files/recordId/{}/fieldId/{}/fileId/{}",
84      record_id, field_id, file_id
85    );
86    self
87      .request_no_content(Method::DELETE, &path, &[], Option::<&()>::None)
88      .await
89  }
90}