ruma_client_api/authenticated_media/
get_media_preview.rs

1//! `GET /_matrix/client/*/media/preview_url`
2//!
3//! Get a preview for a URL.
4
5pub mod v1 {
6    //! `/v1/` ([spec])
7    //!
8    //! [spec]: https://spec.matrix.org/latest/client-server-api/#get_matrixclientv1mediapreview_url
9
10    use ruma_common::{
11        MilliSecondsSinceUnixEpoch,
12        api::{auth_scheme::AccessToken, request, response},
13        metadata,
14    };
15    use serde::Serialize;
16    use serde_json::value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value};
17
18    metadata! {
19        method: GET,
20        rate_limited: true,
21        authentication: AccessToken,
22        history: {
23            unstable("org.matrix.msc3916") => "/_matrix/client/unstable/org.matrix.msc3916/media/preview_url",
24            1.11 | stable("org.matrix.msc3916.stable") => "/_matrix/client/v1/media/preview_url",
25        }
26    }
27
28    /// Request type for the `get_media_preview` endpoint.
29    #[request(error = crate::Error)]
30    pub struct Request {
31        /// URL to get a preview of.
32        #[ruma_api(query)]
33        pub url: String,
34
35        /// Preferred point in time (in milliseconds) to return a preview for.
36        #[ruma_api(query)]
37        #[serde(skip_serializing_if = "Option::is_none")]
38        pub ts: Option<MilliSecondsSinceUnixEpoch>,
39    }
40
41    /// Response type for the `get_media_preview` endpoint.
42    #[response(error = crate::Error)]
43    #[derive(Default)]
44    pub struct Response {
45        /// OpenGraph-like data for the URL.
46        ///
47        /// Differences from OpenGraph: the image size in bytes is added to the `matrix:image:size`
48        /// field, and `og:image` returns the MXC URI to the image, if any.
49        #[ruma_api(body)]
50        pub data: Option<Box<RawJsonValue>>,
51    }
52
53    impl Request {
54        /// Creates a new `Request` with the given URL.
55        pub fn new(url: String) -> Self {
56            Self { url, ts: None }
57        }
58    }
59
60    impl Response {
61        /// Creates an empty `Response`.
62        pub fn new() -> Self {
63            Self { data: None }
64        }
65
66        /// Creates a new `Response` with the given OpenGraph data (in a
67        /// `serde_json::value::RawValue`).
68        pub fn from_raw_value(data: Box<RawJsonValue>) -> Self {
69            Self { data: Some(data) }
70        }
71
72        /// Creates a new `Response` with the given OpenGraph data (in any kind of serializable
73        /// object).
74        pub fn from_serialize<T: Serialize>(data: &T) -> serde_json::Result<Self> {
75            Ok(Self { data: Some(to_raw_json_value(data)?) })
76        }
77    }
78
79    #[cfg(test)]
80    mod tests {
81        use assert_matches2::assert_matches;
82        use serde_json::{
83            from_value as from_json_value, json,
84            value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value},
85        };
86
87        // Since BTreeMap<String, Box<RawJsonValue>> deserialization doesn't seem to
88        // work, test that Option<RawJsonValue> works
89        #[test]
90        fn raw_json_deserialize() {
91            type OptRawJson = Option<Box<RawJsonValue>>;
92
93            assert_matches!(from_json_value::<OptRawJson>(json!(null)).unwrap(), None);
94            from_json_value::<OptRawJson>(json!("test")).unwrap().unwrap();
95            from_json_value::<OptRawJson>(json!({ "a": "b" })).unwrap().unwrap();
96        }
97
98        // For completeness sake, make sure serialization works too
99        #[test]
100        fn raw_json_serialize() {
101            to_raw_json_value(&json!(null)).unwrap();
102            to_raw_json_value(&json!("string")).unwrap();
103            to_raw_json_value(&json!({})).unwrap();
104            to_raw_json_value(&json!({ "a": "b" })).unwrap();
105        }
106    }
107}