flickr_api/
upload_photo.rs1use crate::*;
2use reqwest::multipart::{Form, Part};
3use tokio::fs::read;
4
5#[derive(Debug, Serialize, Deserialize, PartialEq)]
6#[serde(rename = "rsp")]
7struct UploadXMLAnswer {
8 stat: String,
9
10 #[serde(flatten)]
11 content: UploadXMLPayload,
12}
13
14#[derive(Debug, Serialize, Deserialize, PartialEq)]
15enum UploadXMLPayload {
16 #[serde(rename = "photoid")]
17 PhotoId {
18 #[serde(rename = "$value")]
19 value: String,
20 },
21
22 #[serde(rename = "err")]
23 Err { code: String, msg: String },
24}
25
26impl UploadXMLAnswer {
27 fn to_result(self) -> Result<String, FlickrError> {
28 match self.content {
29 UploadXMLPayload::PhotoId { value } => Ok(value),
30 UploadXMLPayload::Err { code, msg } => Err(FlickrError {
31 stat: self.stat,
32 code: code.parse().unwrap_or(0),
33 message: msg,
34 }),
35 }
36 }
37}
38
39impl PhotoRequestBuilder {
40 pub async fn upload_from_path(&self, path: &std::path::Path) -> Result<String, Box<dyn Error>> {
42 self.upload(
43 &read(path).await?,
44 Some(String::from(
45 path.file_name()
46 .and_then(|f| f.to_str())
47 .unwrap_or("unknown"),
48 )),
49 )
50 .await
51 }
52
53 pub async fn upload(
55 &self,
56 photo: &[u8],
57 filename: Option<String>,
58 ) -> Result<String, Box<dyn Error>> {
59 let mut params = vec![];
60 oauth::build_request(
61 oauth::RequestTarget::Post(URL_UPLOAD),
62 &mut params,
63 &self.handle.key,
64 self.handle.token.as_ref(),
65 );
66
67 let photo_part =
69 Part::bytes(Vec::from(photo)).file_name(filename.unwrap_or("unknown".to_string()));
70
71 let form = params
72 .into_iter()
73 .fold(Form::new(), |form, (k, v)| form.text(k, v))
74 .part("photo", photo_part);
75
76 let request = self
77 .handle
78 .client
79 .post(URL_UPLOAD)
80 .multipart(form)
81 .send()
82 .await?;
83
84 let text = request.text().await?;
85
86 log::trace!("Upload response: {:?}", text);
87
88 let id = serde_xml_rs::from_str::<UploadXMLAnswer>(&text)?.to_result()?;
89
90 Ok(id)
91 }
92}
93
94#[test]
95fn test_upload_answer_error() {
96 let anwser = r#"<?xml version="1.0" encoding="utf-8" ?><rsp stat="fail"><err code="5" msg="Filetype was not recognised"/></rsp>"#;
97
98 let answer = serde_xml_rs::from_str::<UploadXMLAnswer>(anwser).unwrap();
99
100 assert_eq!(
101 answer,
102 UploadXMLAnswer {
103 stat: "fail".to_string(),
104 content: UploadXMLPayload::Err {
105 code: "5".to_string(),
106 msg: "Filetype was not recognised".to_string()
107 }
108 }
109 );
110}
111
112#[test]
113fn test_upload_answer_ok() {
114 let anwser = r#"<?xml version="1.0" encoding="utf-8" ?><rsp stat="ok"><photoid>54026462270</photoid></rsp>"#;
115
116 let answer = serde_xml_rs::from_str::<UploadXMLAnswer>(anwser).unwrap();
117
118 assert_eq!(
119 answer,
120 UploadXMLAnswer {
121 stat: "ok".to_string(),
122 content: UploadXMLPayload::PhotoId {
123 value: "54026462270".to_string()
124 }
125 }
126 );
127}