Skip to main content

zulip_api/message/upload_file/
response.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{field_access, impl_default, impl_display, Error, Result};
4
5/// Represents the response to a `Upload File` API request.
6#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
7pub struct Response {
8    #[serde(skip_serializing_if = "Option::is_none")]
9    uri: Option<String>,
10    #[serde(skip_serializing_if = "Option::is_none")]
11    url: Option<String>,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    filename: Option<String>,
14}
15
16field_access! {
17    Response {
18        uri: option_cow_deref { str, String },
19        url: option_cow_deref { str, String },
20        filename: option_cow_deref { str, String },
21    }
22}
23
24impl Response {
25    /// Gets the realm ID  from the file URL.
26    pub fn realm_id(&self) -> Result<u64> {
27        self.url
28            .as_deref()
29            .and_then(|url| url.strip_prefix("/user_uploads/"))
30            .ok_or(Error::io_other("invalid upload URL"))
31            .and_then(|url| {
32                url.chars()
33                    .take_while(|c| c.is_ascii_digit())
34                    .collect::<String>()
35                    .parse::<u64>()
36                    .map_err(Error::from)
37            })
38    }
39
40    /// Gets the upload file path from the file URL.
41    pub fn filename_path(&self) -> Result<String> {
42        self.url
43            .as_deref()
44            .and_then(|url| url.strip_prefix("/user_uploads/"))
45            .ok_or(Error::io_other("invalid upload URL"))
46            .map(|url| {
47                url.chars()
48                    .skip_while(|c| c.is_ascii_digit() || c.is_ascii_hexdigit())
49                    .skip_while(|c| c == &'/')
50                    .collect::<String>()
51            })
52    }
53}
54
55impl Response {
56    /// Creates a new [Response].
57    pub const fn new() -> Self {
58        Self {
59            uri: None,
60            url: None,
61            filename: None,
62        }
63    }
64}
65
66impl_default!(Response);
67impl_display!(Response);
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_success_upload_file_response() {
75        let uri = "/test/uri";
76        let uri_json = serde_json::to_string(&uri).unwrap();
77
78        let url = "/test/url";
79        let url_json = serde_json::to_string(&url).unwrap();
80
81        let filename = "/test/filename";
82        let filename_json = serde_json::to_string(&filename).unwrap();
83
84        let response = Response::new()
85            .with_uri(uri)
86            .with_url(url)
87            .with_filename(filename);
88
89        let response_json =
90            format!(r#"{{"uri":{uri_json},"url":{url_json},"filename":{filename_json}}}"#);
91
92        assert_eq!(serde_json::to_string(&response).unwrap(), response_json);
93        assert_eq!(
94            serde_json::from_str::<Response>(&response_json).unwrap(),
95            response
96        );
97
98        assert_eq!(response.uri(), Some(uri));
99        assert_eq!(response.url(), Some(url));
100        assert_eq!(response.filename(), Some(filename));
101    }
102}