use sfr_types as st;
pub use st::FilesUploadResponse;
use crate::{Client, Request};
use reqwest::multipart::Form;
#[derive(Debug)]
pub struct FilesUpload(st::FilesUploadRequest);
const API_CODE: &str = "files.upload";
impl FilesUpload {
async fn request_inner(self, client: &Client) -> Result<FilesUploadResponse, st::Error> {
#[allow(clippy::missing_docs_in_private_items)] const URL: &str = "https://slack.com/api/files.upload";
let form = self
.form()
.await
.map_err(|e| e.stack("failed to create `form`"))?;
tracing::debug!("form = {form:?}");
let response = client
.client()
.post(URL)
.bearer_auth(client.token())
.multipart(form)
.send()
.await
.map_err(|e| st::Error::failed_to_request_by_http(API_CODE, e))?;
tracing::debug!("response = {response:?}");
let body: serde_json::Value = response
.json()
.await
.map_err(|e| st::Error::failed_to_read_json(API_CODE, e))?;
tracing::debug!("body = {body:?}");
body.try_into()
}
async fn form(self) -> Result<Form, st::Error> {
let mut form = Form::new();
if !self.0.channels.is_empty() {
let channels = self.0.channels.join(",");
form = form.text("channels", channels);
}
match self.0.content {
st::FilesUploadRequestContent::Content(content) => {
form = form.text("content", content.clone())
}
st::FilesUploadRequestContent::File(path, filename) => {
let file = tokio::fs::read(path)
.await
.map_err(st::Error::failed_to_read_file_in_files_upload)?;
let part = reqwest::multipart::Part::stream(file).file_name(filename.clone());
form = form.part("file", part);
}
st::FilesUploadRequestContent::FileInMemory(bytes, filename) => {
let part = reqwest::multipart::Part::stream(bytes).file_name(filename.clone());
form = form.part("file", part);
}
}
if let Some(filename) = &self.0.filename {
form = form.text("filename", filename.clone());
}
if let Some(filetype) = &self.0.filetype {
form = form.text("filetype", filetype.clone());
}
if let Some(initial_comment) = &self.0.initial_comment {
form = form.text("initial_comment", initial_comment.clone());
}
if let Some(thread_ts) = &self.0.thread_ts {
form = form.text("thread_ts", thread_ts.clone());
}
if let Some(title) = &self.0.title {
form = form.text("title", title.clone());
}
Ok(form)
}
}
impl From<st::FilesUploadRequest> for FilesUpload {
fn from(inner: st::FilesUploadRequest) -> Self {
Self(inner)
}
}
impl Request for FilesUpload {
type Response = FilesUploadResponse;
async fn request(self, client: &Client) -> Result<Self::Response, st::Error> {
self.request_inner(client).await
}
}