Skip to main content

zulip_api/message/
attachment.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{field_access, impl_default, impl_display};
4
5/// Represents metadata for a attachment in a Zulip message.
6#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
7pub struct Attachment {
8    #[serde(skip_serializing_if = "Option::is_none")]
9    id: Option<u64>,
10    #[serde(skip_serializing_if = "Option::is_none")]
11    name: Option<String>,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    path_id: Option<String>,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    size: Option<u64>,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    create_time: Option<u64>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    messages: Option<Vec<AttachmentMessage>>,
20}
21
22impl Attachment {
23    /// Creates a new [Attachment].
24    pub const fn new() -> Self {
25        Self {
26            id: None,
27            name: None,
28            path_id: None,
29            size: None,
30            create_time: None,
31            messages: None,
32        }
33    }
34}
35
36field_access! {
37    Attachment {
38        /// The unique ID for the attachment.
39        id: option { u64 },
40        /// Size of the file in bytes.
41        size: option { u64 },
42        /// Time when the attachment was uploaded as a UNIX timestamp
43        /// multiplied by 1000 (matching the format of getTime() in JavaScript).
44        ///
45        /// **Changes**: Changed in Zulip 3.0 (feature level 22). This field was
46        /// previously a floating point number.
47        create_time: option { u64 },
48    }
49}
50
51field_access! {
52    Attachment {
53        /// Name of the uploaded file.
54        name: option_cow_deref { str, String },
55        /// A representation of the path of the file within the
56        /// repository of user-uploaded files. If the `path_id` of a
57        /// file is `{realm_id}/ab/cdef/temp_file.py`, its URL will be:
58        /// `{server_url}/user_uploads/{realm_id}/ab/cdef/temp_file.py`.
59        path_id: option_cow_deref { str, String },
60        /// Contains basic details on any Zulip messages that have been
61        /// sent referencing this [uploaded file](/api/upload-file).
62        /// This includes messages sent by any user in the Zulip
63        /// organization who sent a message containing a link to the
64        /// uploaded file.
65        messages: option_cow_deref { [AttachmentMessage], Vec<AttachmentMessage> },
66    }
67}
68
69impl_default!(Attachment);
70impl_display!(Attachment);
71
72/// Represents metadata for a attachment message in a Zulip message.
73#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
74pub struct AttachmentMessage {
75    #[serde(skip_serializing_if = "Option::is_none")]
76    date_sent: Option<u64>,
77    #[serde(skip_serializing_if = "Option::is_none")]
78    id: Option<u64>,
79}
80
81impl AttachmentMessage {
82    /// Creates a new [AttachmentMessage].
83    pub const fn new() -> Self {
84        Self {
85            date_sent: None,
86            id: None,
87        }
88    }
89}
90
91field_access! {
92    AttachmentMessage {
93        date_sent: option { u64 },
94        id: option { u64 },
95    }
96}
97
98impl_default!(AttachmentMessage);
99impl_display!(AttachmentMessage);
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn test_attachment() {
107        let id = 1;
108        let id_json = serde_json::to_string(&id).unwrap();
109
110        let name = "name";
111        let name_json = serde_json::to_string(&name).unwrap();
112
113        let path_id = "path_id";
114        let path_id_json = serde_json::to_string(&path_id).unwrap();
115
116        let size = 2;
117        let size_json = serde_json::to_string(&size).unwrap();
118
119        let create_time = 3;
120        let create_time_json = serde_json::to_string(&create_time).unwrap();
121
122        let msg_date_sent = 4;
123        let msg_id = 5;
124
125        let detached_msg = AttachmentMessage::new()
126            .with_date_sent(msg_date_sent)
127            .with_id(msg_id);
128
129        let messages = vec![detached_msg];
130        let messages_json = serde_json::to_string(&messages).unwrap();
131
132        let detached = Attachment::new()
133            .with_id(id)
134            .with_name(name)
135            .with_path_id(path_id)
136            .with_size(size)
137            .with_create_time(create_time)
138            .with_messages(messages.as_slice());
139
140        let detached_json = format!(
141            r#"{{"id":{id_json},"name":{name_json},"path_id":{path_id_json},"size":{size_json},"create_time":{create_time_json},"messages":{messages_json}}}"#
142        );
143
144        assert_eq!(detached.id(), Some(id));
145        assert_eq!(detached.name(), Some(name));
146        assert_eq!(detached.path_id(), Some(path_id));
147        assert_eq!(detached.size(), Some(size));
148        assert_eq!(detached.create_time(), Some(create_time));
149        assert_eq!(detached.messages(), Some(messages.as_slice()));
150
151        assert_eq!(serde_json::to_string(&detached).unwrap(), detached_json);
152        assert_eq!(
153            serde_json::from_str::<Attachment>(&detached_json).unwrap(),
154            detached
155        );
156    }
157
158    #[test]
159    fn test_attachment_message() {
160        let date_sent = 1;
161        let date_sent_json = serde_json::to_string(&date_sent).unwrap();
162
163        let id = 2;
164        let id_json = serde_json::to_string(&id).unwrap();
165
166        let detached = AttachmentMessage::new()
167            .with_date_sent(date_sent)
168            .with_id(id);
169
170        let detached_json = format!(r#"{{"date_sent":{date_sent_json},"id":{id_json}}}"#);
171
172        assert_eq!(detached.date_sent(), Some(date_sent));
173        assert_eq!(detached.id(), Some(id));
174
175        assert_eq!(serde_json::to_string(&detached).unwrap(), detached_json);
176        assert_eq!(
177            serde_json::from_str::<AttachmentMessage>(&detached_json).unwrap(),
178            detached
179        );
180    }
181}